From: jstebbins <jstebbins.hb@gmail.com>
Date: Thu, 16 Apr 2009 01:46:08 +0000 (+0000)
Subject: LinGui: merge gtk mingw cross compiling support
X-Git-Tag: 0.9.4~630
X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=abbb574581cf09d09605e5acc2eef96c2fba1657;p=handbrake

LinGui: merge gtk mingw cross compiling support


git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@2332 b64f7644-9d1e-0410-96f1-a4d463321fa5
---

diff --git a/gtk/configure.ac b/gtk/configure.ac
index c7e0ad695..7f3ca5ff9 100644
--- a/gtk/configure.ac
+++ b/gtk/configure.ac
@@ -45,6 +45,10 @@ else
 	AC_SUBST(HB_DIR, '$(top_srcdir)/'"..")
 fi
 
+AC_ARG_ENABLE(gst,
+	AS_HELP_STRING([--enable-gst], [enable gstreamer on Win32]),
+	w32_gst=yes, w32_gst=no)
+
 # overwrite global variable (used for Makefile generation)
 AC_SUBST(GLOBALCXXFLAGS, $CXXFLAGS )
 AC_SUBST(GLOBALLDFLAGS, $LDFLAGS )
@@ -60,23 +64,35 @@ AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE,"$GETTEXT_PACKAGE", [GETTEXT package name])
 AM_GLIB_GNU_GETTEXT
 IT_PROG_INTLTOOL([0.35.0])
 
-
-
 AM_PROG_LIBTOOL
 
+case $host in
+  *-*-mingw*)
+    if test "x$w32_gst" = "xyes" ; then
+		GHB_PACKAGES="gtk+-2.0 >= 2.8 gthread-2.0 gstreamer-0.10 gstreamer-interfaces-0.10 gstreamer-video-0.10 gstreamer-pbutils-0.10 gio-2.0 hal hal-storage libgtkhtml-3.14"
+	else
+        GHB_PACKAGES="gtk+-2.0 >= 2.8 gthread-2.0 gio-2.0"
+	fi
+	mingw_flag=yes
+    ;;
+  *)
+	GHB_PACKAGES="gtk+-2.0 >= 2.8 gthread-2.0 gstreamer-0.10 gstreamer-interfaces-0.10 gstreamer-video-0.10 gstreamer-pbutils-0.10 gio-2.0 hal hal-storage libgtkhtml-3.14 libnotify"
+	mingw_flag=no
+    ;;
+esac
+
+if test "x$w32_gst" = "xyes" -o  "x$mingw_flag" != "xyes" ; then
+	CXXFLAGS="$CXXFLAGS -D_ENABLE_GST"
+	CFLAGS="$CFLAGS -D_ENABLE_GST"
+fi
 
+AM_CONDITIONAL([MINGW], [test "x$mingw_flag" = "xyes"])
 
-PKG_CHECK_MODULES(GHBTOOLS, [glib-2.0 gobject-2.0 gdk-pixbuf-2.0])
-AC_SUBST(GHBTOOLS_CFLAGS)
-AC_SUBST(GHBTOOLS_LIBS)
+PKG_CHECK_MODULES(GHB, [$GHB_PACKAGES])
 
-PKG_CHECK_MODULES(GHB, [gtk+-2.0 >= 2.8 gthread-2.0 gstreamer-0.10 gstreamer-interfaces-0.10 gstreamer-video-0.10 gstreamer-pbutils-0.10 gio-2.0 hal hal-storage libgtkhtml-3.14 libnotify ])
 AC_SUBST(GHB_CFLAGS)
 AC_SUBST(GHB_LIBS)
 
-
-
-
 AC_OUTPUT([
 Makefile
 src/Makefile
diff --git a/gtk/module.defs b/gtk/module.defs
index 7550a82ae..8c1648d61 100644
--- a/gtk/module.defs
+++ b/gtk/module.defs
@@ -11,3 +11,59 @@ GTK.CONFIGURE.stamp = $(GTK.build/).stamp.configure
 GTK.out += $(GTK.CONFIGURE.stamp)
 
 BUILD.out += $(GTK.out)
+
+###############################################################################
+
+ifeq (1-mingw,$(BUILD.cross)-$(BUILD.system))
+    GTK.GCC.D += PTW32_STATIC_LIB
+endif
+
+
+###############################################################################
+###############################################################################
+$(eval $(call import.MODULE.defs,HGTK,hgtk))
+$(eval $(call import.GCC,HGTK))
+
+HGTK.GCC.gcc = gcc
+HGTK.GCC.args.extra = $(shell pkg-config --cflags glib-2.0)
+HGTK.GCC.args.extra += $(shell pkg-config --cflags gdk-pixbuf-2.0)
+HGTK.GCC.args.extra += $(shell pkg-config --libs glib-2.0)
+HGTK.GCC.args.extra += $(shell pkg-config --libs gdk-pixbuf-2.0)
+
+HGTK.src/ = $(SRC/)gtk/src/
+HGTK.build/ = $(BUILD/)gtk/src/
+
+HGTKCOMMON.c = \
+	$(HGTK.src/)plist.c \
+	$(HGTK.src/)values.c
+
+HGTKCOMMON.c.o = $(patsubst $(SRC/)%.c,$(BUILD/)%-native.o,$(HGTKCOMMON.c))
+
+CREATE_RES.c = \
+	$(HGTK.src/)create_resources.c \
+	$(HGTK.src/)icon_tools.c
+
+CREATE_RES.c.o = $(patsubst $(SRC/)%.c,$(BUILD/)%-native.o,$(CREATE_RES.c))
+CREATE_RES.exe = $(HGTK.build/)create_resources
+
+WIDGETDEPS.c = \
+	$(HGTK.src/)widgetdeps.c
+
+WIDGETDEPS.c.o = $(patsubst $(SRC/)%.c,$(BUILD/)%-native.o,$(WIDGETDEPS.c))
+WIDGETDEPS.exe = $(HGTK.build/)widgetdeps
+
+QUOTESTRING.c = \
+	$(HGTK.src/)quotestring.c
+
+QUOTESTRING.c.o = $(patsubst $(SRC/)%.c,$(BUILD/)%-native.o,$(QUOTESTRING.c))
+QUOTESTRING.exe = $(HGTK.build/)quotestring
+
+HGTK.out += $(HGTKCOMMON.c.o)
+HGTK.out += $(CREATE_RES.exe)
+HGTK.out += $(CREATE_RES.c.o)
+HGTK.out += $(WIDGETDEPS.exe)
+HGTK.out += $(WIDGETDEPS.c.o)
+HGTK.out += $(QUOTESTRING.exe)
+HGTK.out += $(QUOTESTRING.c.o)
+
+BUILD.out += $(HGTK.out)
diff --git a/gtk/module.rules b/gtk/module.rules
index 3fd03e189..ddf9bccca 100644
--- a/gtk/module.rules
+++ b/gtk/module.rules
@@ -1,10 +1,10 @@
 $(eval $(call import.MODULE.rules,GTK))
 
-build: gtk.build
+build: hgtk.build gtk.build
 install: gtk.install
 uninstall: gtk.uninstall
-clean: gtk.clean
-xclean: gtk.xclean
+clean: hgtk.clean gtk.clean
+xclean: hgtk.clean gtk.xclean
 
 gtk.configure: $(GTK.CONFIGURE.stamp)
 
@@ -12,12 +12,22 @@ $(GTK.CONFIGURE.stamp): | $(dir $(GTK.CONFIGURE.stamp))
 $(GTK.CONFIGURE.stamp): $(GTK.src/)Makefile.am
 $(GTK.CONFIGURE.stamp): $(GTK.src/)configure.ac $(GTK.src/)src/Makefile.am
 	set -e; cd $(GTK.src/); NOCONFIGURE=1 ./autogen.sh
+ifeq (1-mingw,$(BUILD.cross)-$(BUILD.system))
 	set -e; cd $(GTK.build/); $(call fn.ABSOLUTE,$(GTK.src/))configure \
-		PKG_CONFIG_DIR=$(BUILD/)contrib/lib/pkgconfig \
-	    CFLAGS="$(call fn.ARGS,GTK.GCC,.g .O)" \
+		--host=$(BUILD.spec) \
+		PKG_CONFIG_PATH=$(BUILD/)contrib/lib/pkgconfig \
+	    CFLAGS="$(call fn.ARGS,GTK.GCC,.g .O *D ?extra)" \
+	    LDFLAGS="$(call fn.ARGS,GTK.GCC,?strip .g .O) " \
+	    --prefix=$(PREFIX) \
+	    --with-hb=$(call fn.ABSOLUTE,$(BUILD/))
+else
+	set -e; cd $(GTK.build/); $(call fn.ABSOLUTE,$(GTK.src/))configure \
+		PKG_CONFIG_PATH=$(BUILD/)contrib/lib/pkgconfig \
+	    CFLAGS="$(call fn.ARGS,GTK.GCC,.g .O ?extra)" \
 	    LDFLAGS="$(call fn.ARGS,GTK.GCC,?strip .g .O)" \
 	    --prefix=$(PREFIX) \
 	    --with-hb=$(call fn.ABSOLUTE,$(BUILD/))
+endif
 	$(TOUCH.exe) $@
 
 gtk.build: | $(GTK.build/)
@@ -37,3 +47,40 @@ gtk.xclean:
 	$(MAKE) -C $(GTK.build/) distclean
 	$(RM.exe) -f $(GTK.out)
 	$(RM.exe) -fr $(GTK.build/)
+
+###############################################################################
+###############################################################################
+$(eval $(call import.MODULE.rules,HGTK))
+
+hgtk.build: $(CREATE_RES.exe) $(WIDGETDEPS.exe) $(QUOTESTRING.exe)
+
+$(CREATE_RES.exe): | $(dir $(CREATE_RES.exe))
+$(CREATE_RES.exe): $(CREATE_RES.c.o) $(HGTKCOMMON.c.o)
+	$(call HGTK.GCC.EXE,$@,$^)
+
+$(HGTKCOMMON.c.o): | $(dir $(HGTKCOMMON.c.o))
+$(HGTKCOMMON.c.o): $(BUILD/)%-native.o: $(SRC/)%.c
+	$(call HGTK.GCC.C_O,$@,$<)
+
+$(CREATE_RES.c.o): | $(dir $(CREATE_RES.c.o))
+$(CREATE_RES.c.o): $(BUILD/)%-native.o: $(SRC/)%.c
+	$(call HGTK.GCC.C_O,$@,$<)
+
+$(WIDGETDEPS.exe): | $(dir $(WIDGETDEPS.exe))
+$(WIDGETDEPS.exe): $(WIDGETDEPS.c.o) $(HGTKCOMMON.c.o)
+	$(call HGTK.GCC.EXE,$@,$^)
+
+$(WIDGETDEPS.c.o): | $(dir $(WIDGETDEPS.c.o))
+$(WIDGETDEPS.c.o): $(BUILD/)%-native.o: $(SRC/)%.c
+	$(call HGTK.GCC.C_O,$@,$<)
+
+$(QUOTESTRING.c.o): | $(dir $(QUOTESTRING.c.o))
+$(QUOTESTRING.c.o): $(BUILD/)%-native.o: $(SRC/)%.c
+	$(call HGTK.GCC.C_O,$@,$<)
+
+$(QUOTESTRING.exe): | $(dir $(QUOTESTRING.exe))
+$(QUOTESTRING.exe): $(QUOTESTRING.c.o)
+	$(call HGTK.GCC.EXE,$@,$^)
+
+hgtk.clean:
+	$(RM.exe) -f $(HGTK.out)
diff --git a/gtk/src/Makefile.am b/gtk/src/Makefile.am
index 8abcc6f97..b6e6f528b 100644
--- a/gtk/src/Makefile.am
+++ b/gtk/src/Makefile.am
@@ -1,30 +1,18 @@
 ## Process this file with automake to produce Makefile.in
 
-HB_LIBS=\
-	-lhb \
-	-la52 \
-	-lmkv \
-	-lavformat \
-	-lavcodec \
-	-lavutil \
-	-ldca \
-	-ldvdread \
-	-lfaac \
-	-lmp3lame \
-	-lmpeg2 \
-	-lvorbis \
-	-lvorbisenc \
-	-logg \
-	-lsamplerate \
-	-lx264 \
-	-lxvidcore \
-	-lmp4v2 \
-	-lswscale \
-	-ltheora \
-	-lfaad \
-	-lz \
-	-lbz2 \
-	-lpthread
+if MINGW
+HB_LIBS= \
+	-lhb -la52 -lmkv -lavformat -lavcodec -lavutil -ldca -ldvdread \
+	-lfaac -lmp3lame -lmpeg2 -lvorbis -lvorbisenc -logg -lsamplerate \
+	-lx264 -lxvidcore -lmp4v2 -lswscale -ltheora -lfaad -lz \
+	-lbz2 -liberty -lpthreadGC2
+else
+HB_LIBS= \
+	-lhb -la52 -lmkv -lavformat -lavcodec -lavutil -ldca -ldvdread \
+	-lfaac -lmp3lame -lmpeg2 -lvorbis -lvorbisenc -logg -lsamplerate \
+	-lx264 -lxvidcore -lmp4v2 -lswscale -ltheora -lfaad -lz \
+	-lbz2 -liberty -lpthread
+endif
 
 icons =	\
 	hb-icon.128.png 
@@ -66,13 +54,9 @@ AM_CPPFLAGS = \
 	-DPACKAGE_DATA_DIR=\""$(datadir)"\" \
 	$(GHB_CFLAGS)
 
-AM_CFLAGS =\
-	 -Wall\
-	 -g
+AM_CFLAGS = -Wall -g
 
 bin_PROGRAMS = ghb 
-noinst_PROGRAMS = makewidgetdeps quotestring create_resources preset_xlat \
-	resource_data.h resources.plist widget.deps widget_reverse.deps
 
 # Dummy file, not built.  Forces g++ linking
 nodist_EXTRA_ghb_SOURCES = dummy.cpp
@@ -117,54 +101,26 @@ ghb_SOURCES = \
 	marshalers.c \
 	marshalers.h
 
+if MINGW
+ghb_LDFLAGS = \
+	-mwindows -Wl,--export-dynamic -Wl,--exclude-libs,ALL
+else
 ghb_LDFLAGS = \
 	-Wl,--export-dynamic -Wl,--exclude-libs,ALL
+endif
 
 ghb_LDADD = $(HB_LIBS) $(GHB_LIBS)
 
 ghb_DEPENDENCIES = $(HB_DIR)/libhb/libhb.a
 
-makewidgetdeps_SOURCES = \
-	plist.c \
-	plist.h \
-	values.c \
-	values.h \
-	makedeps.c 
-
-makewidgetdeps_LDADD = $(GHBTOOLS_LIBS)
-
-create_resources_SOURCES = \
-	create_resources.c \
-	plist.c \
-	plist.h \
-	values.c \
-	values.h \
-	icon_tools.c \
-	icon_tools.h
-
-create_resources_LDADD = $(GHBTOOLS_LIBS)
-
-preset_xlat_SOURCES = \
-	preset_xlat.c \
-	plist.c \
-	plist.h \
-	values.c \
-	values.h
-
-preset_xlat_LDADD = $(GHBTOOLS_LIBS)
-
-quotestring_SOURCES = quotestring.c
-
-dumbell: preset_xlat
-
 resources.o: resource_data.h
 
 resource_data.h: quotestring resources.plist
 	./quotestring resources.plist resource_data.h
 
-widget_reverse.deps: makewidgetdeps
-widget.deps: makewidgetdeps
-	./makewidgetdeps
+widget_reverse.deps: widgetdeps
+widget.deps: widgetdeps
+	./widgetdeps
 
 resources.plist: create_resources resources.list $(icons_dep) internal_defaults.xml standard_presets.xml ghb.ui widget.deps widget_reverse.deps
 	./create_resources -I$(srcdir) $(srcdir)/resources.list resources.plist
diff --git a/gtk/src/audiohandler.c b/gtk/src/audiohandler.c
index 1ffbf8df5..adfc79b07 100644
--- a/gtk/src/audiohandler.c
+++ b/gtk/src/audiohandler.c
@@ -281,7 +281,7 @@ audio_list_refresh_selected(signal_user_data_t *ud)
 	}
 }
 
-void
+G_MODULE_EXPORT void
 audio_codec_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
 {
 	static gint prev_acodec = 0;
@@ -337,7 +337,7 @@ audio_codec_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
 	ghb_live_reset(ud);
 }
 
-void
+G_MODULE_EXPORT void
 audio_track_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
 {
 	GValue *asettings;
@@ -359,7 +359,7 @@ audio_track_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
 	ghb_live_reset(ud);
 }
 
-void
+G_MODULE_EXPORT void
 audio_mix_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
 {
 	GValue *asettings;
@@ -376,7 +376,7 @@ audio_mix_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
 	ghb_live_reset(ud);
 }
 
-void
+G_MODULE_EXPORT void
 audio_widget_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
 {
 	GValue *asettings;
@@ -392,7 +392,7 @@ audio_widget_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
 	ghb_live_reset(ud);
 }
 
-void
+G_MODULE_EXPORT void
 drc_widget_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
 {
 	GValue *asettings;
@@ -418,7 +418,7 @@ drc_widget_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
 // the selection is updated automaitcally when the title
 // changes.  I don't want the preset selection changed as
 // would happen for regular settings.
-void
+G_MODULE_EXPORT void
 subtitle_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
 {
 	const gchar *name = gtk_widget_get_name(widget);
@@ -508,7 +508,7 @@ add_to_audio_list(signal_user_data_t *ud, GValue *settings)
 	g_free(s_mix);
 }
 
-void
+G_MODULE_EXPORT void
 audio_list_selection_changed_cb(GtkTreeSelection *selection, signal_user_data_t *ud)
 {
 	GtkTreeModel *store;
@@ -545,7 +545,7 @@ audio_list_selection_changed_cb(GtkTreeSelection *selection, signal_user_data_t
 	}
 }
 
-void
+G_MODULE_EXPORT void
 audio_add_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
 {
 	// Add the current audio settings to the list.
@@ -588,7 +588,7 @@ audio_add_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
 	}
 }
 
-void
+G_MODULE_EXPORT void
 audio_remove_clicked_cb(GtkWidget *widget, signal_user_data_t *ud)
 {
 	GtkTreeView *treeview;
diff --git a/gtk/src/callbacks.c b/gtk/src/callbacks.c
index 166b8c684..42f7b6a09 100644
--- a/gtk/src/callbacks.c
+++ b/gtk/src/callbacks.c
@@ -16,20 +16,29 @@
 #endif
 
 #include <string.h>
-#include <poll.h>
 #include <fcntl.h>
 #include <sys/stat.h>
+
+#if !defined(_WIN32)
+#include <poll.h>
+#include <libhal-storage.h>
+#include <dbus/dbus-glib.h>
+#include <dbus/dbus-glib-lowlevel.h>
+
 #include <netinet/in.h>
 #include <netdb.h>
-#include <libhal-storage.h>
-#include <gtk/gtk.h>
 #include <gtkhtml/gtkhtml.h>
+#include <libnotify/notify.h>
+#else
+#define WINVER 0x0500
+#include <winsock2.h>
+#include <dbt.h>
+#endif
+
+#include <gtk/gtk.h>
 #include <gdk/gdkkeysyms.h>
 #include <glib/gstdio.h>
-#include <dbus/dbus-glib.h>
-#include <dbus/dbus-glib-lowlevel.h>
 #include <gio/gio.h>
-#include <libnotify/notify.h>
 
 #include "hb.h"
 #include "callbacks.h"
@@ -260,7 +269,7 @@ ghb_check_all_depencencies(signal_user_data_t *ud)
 	}
 }
 
-void
+G_MODULE_EXPORT void
 on_quit1_activate(GtkMenuItem *quit, signal_user_data_t *ud)
 {
 	gint state = ghb_get_queue_state();
@@ -412,29 +421,110 @@ get_file_label(const gchar *filename)
 	return base;
 }
 
+static gchar*
+get_drive_name(const gchar *drive)
+{
+	gchar *result;
+#if defined(_WIN32)
+	gchar vname[51], fsname[51];
+	if (GetVolumeInformation(drive, vname, 50, NULL, NULL, NULL, fsname, 51))
+	{
+		result = g_strdup_printf("%s (%s)", vname, drive);
+	}
+	else
+	{
+		result = g_strdup_printf("%s", drive);
+	}
+#else
+	result = g_strdup_printf("%s", drive);
+#endif
+	return result;
+}
+
+static gchar*
+resolve_drive_name(gchar *filename)
+{
+#if defined(_WIN32)
+	if (filename[1] == ':')
+	{
+		gchar drive[4];
+		gchar *name;
+		gint dtype;
+
+		g_strlcpy(drive, filename, 4);
+		dtype = GetDriveType(drive);
+		if (dtype == DRIVE_CDROM)
+		{
+			gchar vname[51], fsname[51];
+			GetVolumeInformation(drive, vname, 50, NULL, 
+								NULL, NULL, fsname, 50);
+			name = g_strdup(vname);
+			return name;
+		}
+	}
+	return NULL;
+#else
+	return NULL;
+#endif
+}
+
 static gboolean
 update_source_label(signal_user_data_t *ud, const gchar *source)
 {
 	gchar *label = NULL;
 	gint len;
 	gchar **path;
+	gchar *start;
 	gchar *filename = g_strdup(source);
 	
 	len = strlen(filename);
-	if (filename[len-1] == '/') filename[len-1] = 0;
+	if (filename[len-1] == G_DIR_SEPARATOR) filename[len-1] = 0;
 	if (g_file_test(filename, G_FILE_TEST_IS_DIR))
 	{
-		path = g_strsplit(filename, "/", -1);
-		len = g_strv_length (path);
-		if ((len > 1) && (strcmp("VIDEO_TS", path[len-1]) == 0))
+		// Skip dos drive letters
+		start = strchr(filename, ':');
+		label = resolve_drive_name(filename);
+		if (label != NULL)
 		{
-			label = g_strdup(path[len-2]);
+			if (uppers_and_unders(label))
+			{
+				camel_convert(label);
+			}
 		}
 		else
 		{
-			label = g_strdup(path[len-1]);
+			if (start != NULL)
+				start++;
+			else
+				start = filename;
+			
+			path = g_strsplit(start, G_DIR_SEPARATOR_S, -1);
+			len = g_strv_length (path);
+			if ((len > 1) && (strcmp("VIDEO_TS", path[len-1]) == 0))
+			{
+				label = g_strdup(path[len-2]);
+				if (uppers_and_unders(label))
+				{
+					camel_convert(label);
+				}
+			}
+			else if (len > 0)
+			{
+				if (path[len-1][0] != 0)
+				{
+					label = g_strdup(path[len-1]);
+					if (uppers_and_unders(label))
+					{
+						camel_convert(label);
+					}
+				}
+				else
+					label = g_strdup("new_video");
+			}
+			else
+				label = g_strdup("new_video");
+			g_strfreev (path);
 		}
-		g_strfreev (path);
 	}
 	else
 	{
@@ -472,7 +562,7 @@ update_source_label(signal_user_data_t *ud, const gchar *source)
 	return TRUE;
 }
 
-void
+G_MODULE_EXPORT void
 chooser_file_selected_cb(GtkFileChooser *dialog, signal_user_data_t *ud)
 {
 	const gchar *name = gtk_file_chooser_get_filename (dialog);
@@ -503,7 +593,7 @@ chooser_file_selected_cb(GtkFileChooser *dialog, signal_user_data_t *ud)
 		gtk_combo_box_set_active (combo, 0);
 }
 
-void
+G_MODULE_EXPORT void
 dvd_device_changed_cb(GtkComboBox *combo, signal_user_data_t *ud)
 {
 	GtkWidget *dialog;
@@ -522,7 +612,7 @@ dvd_device_changed_cb(GtkComboBox *combo, signal_user_data_t *ud)
 	}
 }
 
-void
+G_MODULE_EXPORT void
 source_type_changed_cb(GtkToggleButton *toggle, signal_user_data_t *ud)
 {
 	gchar *folder;
@@ -715,19 +805,19 @@ do_source_dialog(GtkButton *button, gboolean single, signal_user_data_t *ud)
 	g_free(sourcename);
 }
 
-void
+G_MODULE_EXPORT void
 source_button_clicked_cb(GtkButton *button, signal_user_data_t *ud)
 {
 	do_source_dialog(button, FALSE, ud);
 }
 
-void
+G_MODULE_EXPORT void
 single_title_source_cb(GtkButton *button, signal_user_data_t *ud)
 {
 	do_source_dialog(button, TRUE, ud);
 }
 
-void
+G_MODULE_EXPORT void
 dvd_source_activate_cb(GtkAction *action, signal_user_data_t *ud)
 {
 	const gchar *filename;
@@ -803,7 +893,7 @@ destination_select_title(GtkEntry *entry)
 	}
 	for (start = end; start >= 0; start--)
 	{
-		if (dest[start] == '/')
+		if (dest[start] == G_DIR_SEPARATOR)
 		{
 			start++;
 			break;
@@ -816,7 +906,7 @@ destination_select_title(GtkEntry *entry)
 	}
 }
 
-gboolean
+G_MODULE_EXPORT gboolean
 destination_grab_cb(
 	GtkEntry *entry, 
 	signal_user_data_t *ud)
@@ -827,7 +917,7 @@ destination_grab_cb(
 
 static gboolean update_default_destination = FALSE;
 
-void
+G_MODULE_EXPORT void
 dest_dir_set_cb(GtkFileChooserButton *dest_chooser, signal_user_data_t *ud)
 {
 	gchar *dest_file, *dest_dir, *dest;
@@ -836,7 +926,7 @@ dest_dir_set_cb(GtkFileChooserButton *dest_chooser, signal_user_data_t *ud)
 	ghb_widget_to_setting(ud->settings, (GtkWidget*)dest_chooser);
 	dest_file = ghb_settings_get_string(ud->settings, "dest_file");
 	dest_dir = ghb_settings_get_string(ud->settings, "dest_dir");
-	dest = g_strdup_printf("%s/%s", dest_dir, dest_file);
+	dest = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s", dest_dir, dest_file);
 	ghb_settings_set_string(ud->settings, "destination", dest);
 	g_free(dest_file);
 	g_free(dest_dir);
@@ -844,7 +934,7 @@ dest_dir_set_cb(GtkFileChooserButton *dest_chooser, signal_user_data_t *ud)
 	update_default_destination = TRUE;
 }
 
-void
+G_MODULE_EXPORT void
 dest_file_changed_cb(GtkEntry *entry, signal_user_data_t *ud)
 {
 	gchar *dest_file, *dest_dir, *dest;
@@ -856,7 +946,7 @@ dest_file_changed_cb(GtkEntry *entry, signal_user_data_t *ud)
 	// update on the timer.
 	dest_file = ghb_settings_get_string(ud->settings, "dest_file");
 	dest_dir = ghb_settings_get_string(ud->settings, "dest_dir");
-	dest = g_strdup_printf("%s/%s", dest_dir, dest_file);
+	dest = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s", dest_dir, dest_file);
 	ghb_settings_set_string(ud->settings, "destination", dest);
 	g_free(dest_file);
 	g_free(dest_dir);
@@ -864,7 +954,7 @@ dest_file_changed_cb(GtkEntry *entry, signal_user_data_t *ud)
 	update_default_destination = TRUE;
 }
 
-void
+G_MODULE_EXPORT void
 destination_browse_clicked_cb(GtkButton *button, signal_user_data_t *ud)
 {
 	GtkWidget *dialog;
@@ -904,7 +994,7 @@ destination_browse_clicked_cb(GtkButton *button, signal_user_data_t *ud)
 	gtk_widget_destroy(dialog);
 }
 
-gboolean
+G_MODULE_EXPORT gboolean
 window_destroy_event_cb(GtkWidget *widget, GdkEvent *event, signal_user_data_t *ud)
 {
 	g_debug("window_destroy_event_cb ()");
@@ -914,7 +1004,7 @@ window_destroy_event_cb(GtkWidget *widget, GdkEvent *event, signal_user_data_t *
 	return FALSE;
 }
 
-gboolean
+G_MODULE_EXPORT gboolean
 window_delete_event_cb(GtkWidget *widget, GdkEvent *event, signal_user_data_t *ud)
 {
 	gint state = ghb_get_queue_state();
@@ -942,7 +1032,7 @@ update_acodec_combo(signal_user_data_t *ud)
 	ghb_grey_combo_options (ud->builder);
 }
 
-void
+G_MODULE_EXPORT void
 container_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
 {
 	const GValue *audio_list;
@@ -1087,7 +1177,7 @@ show_title_info(signal_user_data_t *ud, ghb_title_info_t *tinfo)
 
 static gboolean update_preview = FALSE;
 
-void
+G_MODULE_EXPORT void
 title_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
 {
 	ghb_title_info_t tinfo;
@@ -1133,7 +1223,7 @@ title_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
 	}
 }
 
-void
+G_MODULE_EXPORT void
 setting_widget_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
 {
 	ghb_widget_to_setting(ud->settings, widget);
@@ -1142,7 +1232,7 @@ setting_widget_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
 	ghb_live_reset(ud);
 }
 
-void
+G_MODULE_EXPORT void
 vquality_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
 {
 	ghb_widget_to_setting(ud->settings, widget);
@@ -1166,7 +1256,7 @@ vquality_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
 	gtk_range_set_value(GTK_RANGE(widget), val);
 }
 
-void
+G_MODULE_EXPORT void
 http_opt_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
 {
 	ghb_widget_to_setting(ud->settings, widget);
@@ -1177,7 +1267,7 @@ http_opt_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
 	ghb_grey_combo_options (ud->builder);
 }
 
-void
+G_MODULE_EXPORT void
 vcodec_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
 {
 	gdouble vqmin, vqmax, step, page;
@@ -1196,7 +1286,7 @@ vcodec_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
 	gtk_range_set_inverted (GTK_RANGE(qp), inverted);
 }
 
-void
+G_MODULE_EXPORT void
 target_size_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
 {
 	const gchar *name = gtk_widget_get_name(widget);
@@ -1214,7 +1304,7 @@ target_size_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
 	}
 }
 
-void
+G_MODULE_EXPORT void
 start_chapter_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
 {
 	gint start, end;
@@ -1233,7 +1323,7 @@ start_chapter_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
 	}
 }
 
-void
+G_MODULE_EXPORT void
 end_chapter_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
 {
 	gint start, end;
@@ -1252,7 +1342,7 @@ end_chapter_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
 	}
 }
 
-void
+G_MODULE_EXPORT void
 scale_width_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
 {
 	g_debug("scale_width_changed_cb ()");
@@ -1272,7 +1362,7 @@ scale_width_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
 	ghb_live_reset(ud);
 }
 
-void
+G_MODULE_EXPORT void
 scale_height_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
 {
 	g_debug("scale_height_changed_cb ()");
@@ -1292,7 +1382,7 @@ scale_height_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
 	ghb_live_reset(ud);
 }
 
-void
+G_MODULE_EXPORT void
 crop_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
 {
 	gint titleindex, crop[4];
@@ -1331,7 +1421,7 @@ crop_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
 	ghb_live_reset(ud);
 }
 
-void
+G_MODULE_EXPORT void
 display_width_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
 {
 	g_debug("scale_changed_cb ()");
@@ -1425,7 +1515,7 @@ scale_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
 	gtk_label_set_text (GTK_LABEL(widget), text);
 }
 
-void
+G_MODULE_EXPORT void
 generic_entry_changed_cb(GtkEntry *entry, signal_user_data_t *ud)
 {
 	// Normally (due to user input) I only want to process the entry
@@ -1442,7 +1532,7 @@ generic_entry_changed_cb(GtkEntry *entry, signal_user_data_t *ud)
 	}
 }
 
-void
+G_MODULE_EXPORT void
 prefs_dialog_cb(GtkWidget *xwidget, signal_user_data_t *ud)
 {
 	GtkWidget *dialog;
@@ -2007,7 +2097,7 @@ ghb_backend_events(signal_user_data_t *ud)
 	}
 }
 
-gboolean
+G_MODULE_EXPORT gboolean
 ghb_timer_cb(gpointer data)
 {
 	signal_user_data_t *ud = (signal_user_data_t*)data;
@@ -2038,7 +2128,7 @@ ghb_timer_cb(gpointer data)
 	return TRUE;
 }
 
-gboolean
+G_MODULE_EXPORT gboolean
 ghb_log_cb(GIOChannel *source, GIOCondition cond, gpointer data)
 {
 	gchar *text = NULL;
@@ -2092,13 +2182,25 @@ ghb_log_cb(GIOChannel *source, GIOCondition cond, gpointer data)
 			gtk_text_view_scroll_mark_onscreen(textview, mark);
 			gtk_text_buffer_delete_mark(buffer, mark);
 		}
+#if defined(_WIN32)
+		gsize one = 1;
+		text[length-1] = '\r';
+#endif
 		g_io_channel_write_chars (ud->activity_log, text, 
 								length, &length, NULL);
+#if defined(_WIN32)
+		g_io_channel_write_chars (ud->activity_log, "\n", 
+								one, &one, NULL);
+#endif
 		g_io_channel_flush(ud->activity_log, NULL);
 		if (ud->job_activity_log)
 		{
 			g_io_channel_write_chars (ud->job_activity_log, text, 
 									length, &length, NULL);
+#if defined(_WIN32)
+			g_io_channel_write_chars (ud->activity_log, "\n", 
+									one, &one, NULL);
+#endif
 			g_io_channel_flush(ud->job_activity_log, NULL);
 		}
 		g_free(text);
@@ -2133,7 +2235,7 @@ set_visible(GtkWidget *widget, gboolean visible)
 	}
 }
 
-void
+G_MODULE_EXPORT void
 show_activity_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
 {
 	GtkWidget *widget = GHB_WIDGET (ud->builder, "activity_window");
@@ -2141,7 +2243,7 @@ show_activity_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
 						GTK_TOGGLE_TOOL_BUTTON(xwidget)));
 }
 
-void
+G_MODULE_EXPORT void
 show_activity_menu_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
 {
 	GtkWidget *widget = GHB_WIDGET (ud->builder, "activity_window");
@@ -2150,7 +2252,7 @@ show_activity_menu_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
 	gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(widget), TRUE);
 }
 
-gboolean
+G_MODULE_EXPORT gboolean
 activity_window_delete_cb(GtkWidget *xwidget, GdkEvent *event, signal_user_data_t *ud)
 {
 	set_visible(xwidget, FALSE);
@@ -2212,7 +2314,7 @@ about_web_hook(GtkAboutDialog *about, const gchar *link, gpointer data)
 	browse_url(link);
 }
 
-void
+G_MODULE_EXPORT void
 about_activate_cb(GtkWidget *xwidget, signal_user_data_t *ud)
 {
 	GtkWidget *widget = GHB_WIDGET (ud->builder, "hb_about");
@@ -2229,19 +2331,19 @@ about_activate_cb(GtkWidget *xwidget, signal_user_data_t *ud)
 	gtk_widget_show (widget);
 }
 
-void
+G_MODULE_EXPORT void
 guide_activate_cb(GtkWidget *xwidget, signal_user_data_t *ud)
 {
 	browse_url("http://trac.handbrake.fr/wiki/HandBrakeGuide");
 }
 
-void
+G_MODULE_EXPORT void
 hb_about_response_cb(GtkWidget *widget, gint response, signal_user_data_t *ud)
 {
 	gtk_widget_hide (widget);
 }
 
-void
+G_MODULE_EXPORT void
 show_queue_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
 {
 	GtkWidget *widget = GHB_WIDGET (ud->builder, "queue_window");
@@ -2249,7 +2351,7 @@ show_queue_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
 						GTK_TOGGLE_TOOL_BUTTON(xwidget)));
 }
 
-void
+G_MODULE_EXPORT void
 show_queue_menu_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
 {
 	GtkWidget *widget = GHB_WIDGET (ud->builder, "queue_window");
@@ -2258,7 +2360,7 @@ show_queue_menu_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
 	gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(widget), TRUE);
 }
 
-gboolean
+G_MODULE_EXPORT gboolean
 queue_window_delete_cb(GtkWidget *xwidget, GdkEvent *event, signal_user_data_t *ud)
 {
 	set_visible(xwidget, FALSE);
@@ -2267,7 +2369,7 @@ queue_window_delete_cb(GtkWidget *xwidget, GdkEvent *event, signal_user_data_t *
 	return TRUE;
 }
 
-void
+G_MODULE_EXPORT void
 show_presets_toggled_cb(GtkWidget *action, signal_user_data_t *ud)
 {
 	GtkWidget *widget;
@@ -2369,7 +2471,7 @@ update_chapter_list(signal_user_data_t *ud)
 
 static gint chapter_edit_key = 0;
 
-gboolean
+G_MODULE_EXPORT gboolean
 chapter_keypress_cb(
 	GhbCellRendererText *cell,
 	GdkEventKey *event,
@@ -2379,7 +2481,7 @@ chapter_keypress_cb(
 	return FALSE;
 }
 
-void
+G_MODULE_EXPORT void
 chapter_edited_cb(
 	GhbCellRendererText *cell, 
 	gchar *path, 
@@ -2458,7 +2560,7 @@ chapter_edited_cb(
 	gtk_tree_path_free (treepath);
 }
 
-void
+G_MODULE_EXPORT void
 chapter_list_selection_changed_cb(GtkTreeSelection *selection, signal_user_data_t *ud)
 {
 	g_debug("chapter_list_selection_changed_cb ()");
@@ -2479,7 +2581,6 @@ debug_log_handler(const gchar *domain, GLogLevelFlags flags, const gchar *msg, g
 void
 warn_log_handler(const gchar *domain, GLogLevelFlags flags, const gchar *msg, gpointer data)
 {
-	printf("mywarning\n");
 	printf("%s: %s\n", domain, msg);
 }
 
@@ -2512,7 +2613,7 @@ ghb_hbfd(signal_user_data_t *ud, gboolean hbfd)
 
 }
 
-void
+G_MODULE_EXPORT void
 hbfd_toggled_cb(GtkWidget *widget, signal_user_data_t *ud)
 {
 	g_debug("hbfd_toggled_cb");
@@ -2522,7 +2623,7 @@ hbfd_toggled_cb(GtkWidget *widget, signal_user_data_t *ud)
 	ghb_pref_save(ud->settings, "hbfd");
 }
 
-void
+G_MODULE_EXPORT void
 pref_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
 {
 	g_debug("pref_changed_cb");
@@ -2532,7 +2633,7 @@ pref_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
 	ghb_pref_save(ud->settings, name);
 }
 
-void
+G_MODULE_EXPORT void
 vqual_granularity_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
 {
 	g_debug("vqual_granularity_changed_cb");
@@ -2551,7 +2652,7 @@ vqual_granularity_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
 	gtk_range_set_increments (GTK_RANGE(qp), step, page);
 }
 
-void
+G_MODULE_EXPORT void
 tweaks_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
 {
 	g_debug("tweaks_changed_cb");
@@ -2560,7 +2661,7 @@ tweaks_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
 	ghb_pref_save(ud->settings, name);
 }
 
-void
+G_MODULE_EXPORT void
 hbfd_feature_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
 {
 	g_debug("hbfd_feature_changed_cb");
@@ -2594,20 +2695,30 @@ ghb_file_menu_add_dvd(signal_user_data_t *ud)
 	link = drives = dvd_device_list();
 	while (link != NULL)
 	{
-		gchar *name = (gchar*)link->data;
+		GtkAction *action;
+		gchar *drive = (gchar*)link->data;
+		gchar *name = get_drive_name(drive);
+		
+		action = gtk_action_group_get_action(agroup, drive);
+		if (action != NULL)
+		{
+			gtk_action_group_remove_action(agroup, action);
+			g_object_unref(G_OBJECT(action));
+		}
 		// Create action for this drive
-		GtkAction *action = gtk_action_new(name, name,
+		action = gtk_action_new(drive, name,
 			"Scan this DVD source", "gtk-cdrom");
 		// Add action to action group
-		gtk_action_group_add_action_with_accel(agroup, action, "");
+		gtk_action_group_add_action_with_accel(agroup, action, NULL);
 		// Add to ui manager
 		gtk_ui_manager_add_ui(ui, merge_id, 
-			"ui/menubar1/menuitem1/quit1", name, name,
+			"ui/menubar1/menuitem1/quit1", drive, drive,
 			GTK_UI_MANAGER_AUTO, TRUE);
 		// Connect signal to action (menu item)
 		g_signal_connect(action, "activate", 
 			(GCallback)dvd_source_activate_cb, ud);
 		g_free(name);
+		g_free(drive);
 		link = link->next;
 	}
 	g_list_free(drives);
@@ -2623,9 +2734,33 @@ gboolean ghb_is_cd(GDrive *gd);
 static GList*
 dvd_device_list()
 {
+	GList *dvd_devices = NULL;
+
+#if defined(_WIN32)
+	gint ii, drives;
+	gchar drive[5];
+
+	strcpy(drive, "A:" G_DIR_SEPARATOR_S);
+	drives = GetLogicalDrives();
+	for (ii = 0; ii < 26; ii++)
+	{
+		if (drives & 0x01)
+		{
+			guint dtype;
+
+			drive[0] = 'A' + ii;
+			dtype = GetDriveType(drive);
+			if (dtype == DRIVE_CDROM)
+			{
+				dvd_devices = g_list_append(dvd_devices, 
+						(gpointer)g_strdup(drive));
+			}
+		}
+		drives >>= 1;
+	}
+#else
 	GVolumeMonitor *gvm;
 	GList *drives, *link;
-	GList *dvd_devices = NULL;
 	
 	gvm = g_volume_monitor_get ();
 	drives = g_volume_monitor_get_connected_drives (gvm);
@@ -2645,14 +2780,19 @@ dvd_device_list()
 		link = link->next;
 	}
 	g_list_free(drives);
+#endif
+
 	return dvd_devices;
 }
 
+#if !defined(_WIN32)
 static LibHalContext *hal_ctx;
+#endif
 
 gboolean
 ghb_is_cd(GDrive *gd)
 {
+#if !defined(_WIN32)
 	gchar *device;
 	LibHalDrive *halDrive;
 	LibHalDriveType dtype;
@@ -2663,9 +2803,120 @@ ghb_is_cd(GDrive *gd)
 	libhal_drive_free(halDrive);
 	g_free(device);
 	return (dtype == LIBHAL_DRIVE_TYPE_CDROM);
+#else
+	return FALSE;
+#endif
+}
+
+#if defined(_WIN32)
+static void
+handle_media_change(const gchar *device, gboolean insert, signal_user_data_t *ud)
+{
+	guint dtype;
+	static gint ins_count = 0;
+	static gint rem_count = 0;
+
+	// DVD insertion detected.  Scan it.
+	dtype = GetDriveType(device);
+	if (dtype != DRIVE_CDROM)
+		return;
+	if (insert)
+	{
+		rem_count = 0;
+		ins_count++;
+		if (ins_count == 2)
+		{
+			ghb_file_menu_add_dvd(ud);
+			if (ud->current_dvd_device != NULL &&
+				strcmp(device, ud->current_dvd_device) == 0)
+			{
+				GtkProgressBar *progress;
+				progress = GTK_PROGRESS_BAR(GHB_WIDGET (ud->builder, "progressbar"));
+				gtk_progress_bar_set_text (progress, "Scanning ...");
+				gtk_progress_bar_set_fraction (progress, 0);
+ 				update_source_label(ud, device);
+				ghb_hb_cleanup(TRUE);
+				prune_logs(ud);
+				gint preview_count;
+				preview_count = ghb_settings_get_int(ud->settings, "preview_count");
+				ghb_backend_scan(device, 0, preview_count);
+			}
+		}
+	}
+	else
+	{
+		ins_count = 0;
+		rem_count++;
+		if (rem_count == 2)
+		{
+			ghb_file_menu_add_dvd(ud);
+			if (ud->current_dvd_device != NULL &&
+				strcmp(device, ud->current_dvd_device) == 0)
+			{
+				ghb_hb_cleanup(TRUE);
+				prune_logs(ud);
+				ghb_backend_scan("/dev/null", 0, 1);
+			}
+		}
+	}
+}
+
+static gchar
+FindDriveFromMask(ULONG unitmask)
+{
+	gchar cc;
+	for (cc = 0; cc < 26; cc++)
+	{
+		if (unitmask & 0x01)
+			return 'A' + cc;
+		unitmask >>= 1;
+	}
+	return 0;
 }
 
 void
+wm_drive_changed(MSG *msg, signal_user_data_t *ud)
+{
+	PDEV_BROADCAST_HDR bch = (PDEV_BROADCAST_HDR)msg->lParam;
+	gchar drive[4];
+
+	g_strlcpy(drive, "A:" G_DIR_SEPARATOR_S, 4);
+	switch (msg->wParam)
+	{
+		case DBT_DEVICEARRIVAL:
+		{
+			if (bch->dbch_devicetype == DBT_DEVTYP_VOLUME)
+			{
+				PDEV_BROADCAST_VOLUME bcv = (PDEV_BROADCAST_VOLUME)bch;
+
+				if (bcv->dbcv_flags & DBTF_MEDIA)
+				{
+					drive[0] = FindDriveFromMask(bcv->dbcv_unitmask);
+					handle_media_change(drive, TRUE, ud);
+				}
+			}
+		} break;
+
+		case DBT_DEVICEREMOVECOMPLETE:
+		{
+			if (bch->dbch_devicetype == DBT_DEVTYP_VOLUME)
+			{
+				PDEV_BROADCAST_VOLUME bcv = (PDEV_BROADCAST_VOLUME)bch;
+
+				if (bcv->dbcv_flags & DBTF_MEDIA)
+				{
+					drive[0] = FindDriveFromMask(bcv->dbcv_unitmask);
+					handle_media_change(drive, FALSE, ud);
+				}
+			}
+		} break;
+		default: ;
+	}
+}
+
+#else
+
+G_MODULE_EXPORT void
 drive_changed_cb(GVolumeMonitor *gvm, GDrive *gd, signal_user_data_t *ud)
 {
 	gchar *device;
@@ -2706,8 +2957,9 @@ drive_changed_cb(GVolumeMonitor *gvm, GDrive *gd, signal_user_data_t *ud)
 	}
 	g_free(device);
 }
+#endif
 
-
+#if !defined(_WIN32)
 static void
 dbus_init (void)
 {
@@ -2719,10 +2971,12 @@ dbus_init (void)
 #define GPM_DBUS_INHIBIT_INTERFACE	"org.freedesktop.PowerManagement.Inhibit" 
 static gboolean gpm_inhibited = FALSE;
 static guint gpm_cookie = -1;
+#endif
 
 void
 ghb_inhibit_gpm()
 {
+#if !defined(_WIN32)
 	DBusGConnection *conn;
 	DBusGProxy	*proxy;
 	GError *error = NULL;
@@ -2770,11 +3024,13 @@ ghb_inhibit_gpm()
 	gpm_inhibited = TRUE;
 	g_object_unref(G_OBJECT(proxy));
 	dbus_g_connection_unref(conn);
+#endif
 }
 
 void
 ghb_uninhibit_gpm()
 {
+#if !defined(_WIN32)
 	DBusGConnection *conn;
 	DBusGProxy	*proxy;
 	GError *error = NULL;
@@ -2818,11 +3074,13 @@ ghb_uninhibit_gpm()
 	gpm_inhibited = FALSE;
 	dbus_g_connection_unref(conn);
 	g_object_unref(G_OBJECT(proxy));
+#endif
 }
 
 void
 ghb_hal_init()
 {
+#if !defined(_WIN32)
 	DBusGConnection *gconn;
 	DBusConnection *conn;
 	GError *gerror = NULL;
@@ -2873,9 +3131,10 @@ ghb_hal_init()
 
 	libhal_free_string_array (devices);
 	dbus_g_connection_unref(gconn);
+#endif
 }
 
-gboolean 
+G_MODULE_EXPORT gboolean 
 tweak_setting_cb(
 	GtkWidget *widget, 
 	GdkEventButton *event, 
@@ -2937,7 +3196,7 @@ tweak_setting_cb(
 	return ret;
 }
 
-gboolean 
+G_MODULE_EXPORT gboolean 
 easter_egg_cb(
 	GtkWidget *widget, 
 	GdkEventButton *event, 
@@ -2963,7 +3222,7 @@ easter_egg_cb(
 	return FALSE;
 }
 
-gchar*
+G_MODULE_EXPORT gchar*
 format_deblock_cb(GtkScale *scale, gdouble val, signal_user_data_t *ud)
 {
 	if (val < 5.0)
@@ -2976,7 +3235,7 @@ format_deblock_cb(GtkScale *scale, gdouble val, signal_user_data_t *ud)
 	}
 }
 
-gchar*
+G_MODULE_EXPORT gchar*
 format_drc_cb(GtkScale *scale, gdouble val, signal_user_data_t *ud)
 {
 	if (val <= 0.0)
@@ -2989,7 +3248,7 @@ format_drc_cb(GtkScale *scale, gdouble val, signal_user_data_t *ud)
 	}
 }
 
-gchar*
+G_MODULE_EXPORT gchar*
 format_vquality_cb(GtkScale *scale, gdouble val, signal_user_data_t *ud)
 {
 	gdouble percent;
@@ -3029,11 +3288,13 @@ format_vquality_cb(GtkScale *scale, gdouble val, signal_user_data_t *ud)
 	return g_strdup_printf("QP: %.1f / %.1f%%", val, percent);
 }
 
-static void
+#if !defined(_WIN32)
+G_MODULE_EXPORT void
 html_link_cb(GtkHTML *html, const gchar *url, signal_user_data_t *ud)
 {
 	browse_url(url);
 }
+#endif
 
 static gpointer check_stable_update(signal_user_data_t *ud);
 static gboolean stable_update_lock = FALSE;
@@ -3042,7 +3303,10 @@ static void
 process_appcast(signal_user_data_t *ud)
 {
 	gchar *description = NULL, *build = NULL, *version = NULL, *msg;
-	GtkWidget *html, *window, *dialog, *label;
+#if !defined(_WIN32)
+	GtkWidget *html, *window;
+#endif
+	GtkWidget *dialog, *label;
 	gint	response, ibuild = 0, skip;
 
 	if (ud->appcast == NULL || ud->appcast_len < 15 || 
@@ -3067,17 +3331,21 @@ process_appcast(signal_user_data_t *ud)
 			version, build, hb_get_version(NULL), hb_get_build(NULL));
 	label = GHB_WIDGET(ud->builder, "update_message");
 	gtk_label_set_text(GTK_LABEL(label), msg);
+#if !defined(_WIN32)
 	html = gtk_html_new_from_string(description, -1);
 	g_signal_connect(html, "link_clicked", G_CALLBACK(html_link_cb), ud);
 	window = GHB_WIDGET(ud->builder, "update_scroll");
 	gtk_container_add(GTK_CONTAINER(window), html);
 	// Show it
-	dialog = GHB_WIDGET(ud->builder, "update_dialog");
 	gtk_widget_set_size_request(html, 420, 240);
 	gtk_widget_show(html);
+#endif
+	dialog = GHB_WIDGET(ud->builder, "update_dialog");
 	response = gtk_dialog_run(GTK_DIALOG(dialog));
 	gtk_widget_hide(dialog);
+#if !defined(_WIN32)
 	gtk_widget_destroy(html);
+#endif
 	if (response == GTK_RESPONSE_OK)
 	{
 		// Skip
@@ -3107,7 +3375,7 @@ ghb_net_close(GIOChannel *ioc)
 	g_io_channel_unref(ioc);
 }
 
-gboolean
+G_MODULE_EXPORT gboolean
 ghb_net_recv_cb(GIOChannel *ioc, GIOCondition cond, gpointer data)
 {
 	gchar buf[2048];
@@ -3230,7 +3498,7 @@ check_stable_update(signal_user_data_t *ud)
 	return NULL;
 }
 
-void
+G_MODULE_EXPORT void
 status_activate_cb(GtkStatusIcon *si, signal_user_data_t *ud)
 {
 	GtkWindow *window;
@@ -3239,20 +3507,24 @@ status_activate_cb(GtkStatusIcon *si, signal_user_data_t *ud)
 	gtk_window_present(window);
 }
 
-static void
+#if !defined(_WIN32)
+G_MODULE_EXPORT void
 notify_closed_cb(NotifyNotification *notification, signal_user_data_t *ud)
 {
 	g_object_unref(G_OBJECT(notification));
 }
+#endif
 
 void
 ghb_notify_done(signal_user_data_t *ud)
 {
-	NotifyNotification *notification;
 	GtkStatusIcon *si;
 
 	si = GTK_STATUS_ICON(GHB_OBJECT(ud->builder, "hb_status"));
 	gtk_status_icon_set_from_icon_name(si, "hb-status-empty");
+
+#if !defined(_WIN32)
+	NotifyNotification *notification;
 	notification = notify_notification_new(
 		"Encode Complete",
 		"Put down that cocktail, Your HandBrake queue is done!",
@@ -3261,4 +3533,5 @@ ghb_notify_done(signal_user_data_t *ud)
 	notify_notification_attach_to_status_icon(notification, si);
 	g_signal_connect(notification, "closed", (GCallback)notify_closed_cb, ud);
 	notify_notification_show(notification, NULL);
+#endif
 }
diff --git a/gtk/src/callbacks.h b/gtk/src/callbacks.h
index 2c17e50e2..f438ba534 100644
--- a/gtk/src/callbacks.h
+++ b/gtk/src/callbacks.h
@@ -25,6 +25,10 @@
 #if !defined(_CALLBACKS_H_)
 #define _CALLBACKS_H_
 
+#if defined(_WIN32)
+#include <windows.h>
+#endif
+
 #include <gtk/gtk.h>
 #include "settings.h"
 
@@ -52,6 +56,9 @@ void ghb_log(gchar *log, ...);
 gpointer ghb_check_update(signal_user_data_t *ud);
 void ghb_uninhibit_gpm(void);
 void ghb_inhibit_gpm(void);
+#if defined(_WIN32)
+void wm_drive_changed(MSG *msg, signal_user_data_t *ud);
+#endif
 
 #endif // _CALLBACKS_H_
 
diff --git a/gtk/src/ghb-dvd.c b/gtk/src/ghb-dvd.c
index c20b8fa3e..1d3422caf 100644
--- a/gtk/src/ghb-dvd.c
+++ b/gtk/src/ghb-dvd.c
@@ -37,6 +37,10 @@
  *	Free Software Foundation version 2 of the License.
  */
 
+#if defined(_WIN32)
+#include <windows.h>
+#endif
+
 #include <glib.h>
 #include <gio/gio.h>
 
@@ -315,7 +319,6 @@ ghb_dvd_volname(const gchar *device)
 }
 #endif
 
-#if defined(__linux__)
 gchar*
 ghb_resolve_symlink(const gchar *name)
 {
@@ -359,12 +362,11 @@ ghb_resolve_symlink(const gchar *name)
 	g_object_unref(gfile);
 	return file;
 }
-#endif
 
 void
 ghb_dvd_set_current(const gchar *name, signal_user_data_t *ud)
 {
-#if defined(__linux__)
+#if !defined(_WIN32)
 	GFile *gfile;
 	GFileInfo *info;
 	gchar *resolved = ghb_resolve_symlink(name);
@@ -395,11 +397,19 @@ ghb_dvd_set_current(const gchar *name, signal_user_data_t *ud)
 	}
 	g_object_unref(gfile);
 #else
+	gchar drive[4];
+	guint dtype;
+
 	if (ud->current_dvd_device != NULL)
 	{
 		g_free(ud->current_dvd_device);
 		ud->current_dvd_device = NULL;
 	}
-	ud->current_dvd_device = g_strdup(name);;
+	g_strlcpy(drive, name, 4);
+	dtype = GetDriveType(drive);
+	if (dtype == DRIVE_CDROM)
+	{
+		ud->current_dvd_device = g_strdup(name);
+	}
 #endif
 }
diff --git a/gtk/src/hb-backend.c b/gtk/src/hb-backend.c
index 50125767f..eae2f1f2b 100644
--- a/gtk/src/hb-backend.c
+++ b/gtk/src/hb-backend.c
@@ -1977,9 +1977,9 @@ ghb_update_ui_combo_box(GtkBuilder *builder, const gchar *name, gint user_data,
 	gint signal_id;
 	gint handler_id = 0;
 
-	g_debug("ghb_update_ui_combo_box() %s\n", name);
 	if (name != NULL)
 	{		
+		g_debug("ghb_update_ui_combo_box() %s\n", name);
 		// Clearing a combo box causes a rash of "changed" events, even when
 		// the active item is -1 (inactive).  To control things, I'm disabling
 		// the event till things are settled down.
@@ -3457,7 +3457,7 @@ add_job(hb_handle_t *h, GValue *js, gint unique_id, gint titleindex)
 		job->deinterlace = 0;
     job->grayscale   = ghb_settings_get_boolean(js, "VideoGrayScale");
 
-	job->anamorphic.mode = ghb_settings_get_boolean(js, "PicturePAR");
+	job->anamorphic.mode = ghb_settings_combo_int(js, "PicturePAR");
 	job->anamorphic.modulus = ghb_settings_combo_int(js, "PictureAlignment");
 
 	/* Add selected filters */
diff --git a/gtk/src/main.c b/gtk/src/main.c
index 76097cbe3..e67b3db13 100644
--- a/gtk/src/main.c
+++ b/gtk/src/main.c
@@ -33,10 +33,19 @@
 #include <config.h>
 
 #include <gtk/gtk.h>
+
+#if !defined(_WIN32)
 #include <gst/gst.h>
+#include <libnotify/notify.h>
+#else
+#include <windows.h>
+#include <io.h>
+//#include <pthread/pthread.h>
+#define pipe(phandles)	_pipe (phandles, 4096, _O_BINARY)
+#endif
+
 #include <glib/gstdio.h>
 #include <gio/gio.h>
-#include <libnotify/notify.h>
 #include "hb.h"
 #include "renderer_button.h"
 #include "hb-backend.h"
@@ -76,7 +85,6 @@
 #endif
 
 
-
 #define BUILDER_NAME "ghb"
 
 GtkBuilder*
@@ -193,9 +201,9 @@ change_font(GtkWidget *widget, gpointer data)
     //gtk_container_foreach((GtkContainer*)window, change_font, "sans 20");
 #endif
 
-extern void chapter_list_selection_changed_cb(void);
-extern void chapter_edited_cb(void);
-extern void chapter_keypress_cb(void);
+extern G_MODULE_EXPORT void chapter_list_selection_changed_cb(void);
+extern G_MODULE_EXPORT void chapter_edited_cb(void);
+extern G_MODULE_EXPORT void chapter_keypress_cb(void);
 
 // Create and bind the tree model to the tree view for the chapter list
 // Also, connect up the signal that lets us know the selection has changed
@@ -236,11 +244,11 @@ bind_chapter_tree_model (signal_user_data_t *ud)
 }
 
 
-extern void queue_list_selection_changed_cb(void);
-extern void queue_remove_clicked_cb(void);
-extern void queue_list_size_allocate_cb(void);
-extern void queue_drag_cb(void);
-extern void queue_drag_motion_cb(void);
+extern G_MODULE_EXPORT void queue_list_selection_changed_cb(void);
+extern G_MODULE_EXPORT void queue_remove_clicked_cb(void);
+extern G_MODULE_EXPORT void queue_list_size_allocate_cb(void);
+extern G_MODULE_EXPORT void queue_drag_cb(void);
+extern G_MODULE_EXPORT void queue_drag_motion_cb(void);
 
 // Create and bind the tree model to the tree view for the queue list
 // Also, connect up the signal that lets us know the selection has changed
@@ -304,7 +312,7 @@ bind_queue_tree_model (signal_user_data_t *ud)
 	gtk_widget_hide (widget);
 }
 
-extern void audio_list_selection_changed_cb(void);
+extern G_MODULE_EXPORT void audio_list_selection_changed_cb(void);
 
 // Create and bind the tree model to the tree view for the audio track list
 // Also, connect up the signal that lets us know the selection has changed
@@ -369,9 +377,9 @@ bind_audio_tree_model (signal_user_data_t *ud)
 	g_debug("Done\n");
 }
 
-extern void presets_list_selection_changed_cb(void);
-extern void presets_drag_cb(void);
-extern void presets_drag_motion_cb(void);
+extern G_MODULE_EXPORT void presets_list_selection_changed_cb(void);
+extern G_MODULE_EXPORT void presets_drag_cb(void);
+extern G_MODULE_EXPORT void presets_drag_motion_cb(void);
 extern void presets_row_expanded_cb(void);
 
 // Create and bind the tree model to the tree view for the preset list
@@ -444,8 +452,12 @@ IoRedirect(signal_user_data_t *ud)
 	g_free(config);
 	// Set encoding to raw.
 	g_io_channel_set_encoding (ud->activity_log, NULL, NULL);
+#if !defined(_WIN32)
 	stderr->_fileno = pfd[1];
-	stdin->_fileno = pfd[0];
+#else
+	stderr->_file = pfd[1];
+#endif
+	setvbuf(stderr, NULL, _IONBF, 0);
 	channel = g_io_channel_unix_new (pfd[0]);
 	// I was getting an this error:
 	// "Invalid byte sequence in conversion input"
@@ -472,31 +484,47 @@ static GOptionEntry entries[] =
 	{ NULL }
 };
 
-#if defined(__linux__)
-void drive_changed_cb(GVolumeMonitor *gvm, GDrive *gd, signal_user_data_t *ud);
+G_MODULE_EXPORT void drive_changed_cb(GVolumeMonitor *gvm, GDrive *gd, signal_user_data_t *ud);
 //void drive_disconnected_cb(GnomeVFSVolumeMonitor *gvm, GnomeVFSDrive *gd, signal_user_data_t *ud);
 
+#if defined(_WIN32)
+G_MODULE_EXPORT GdkFilterReturn
+win_message_cb(GdkXEvent *wmevent, GdkEvent *event, gpointer data)
+{
+	signal_user_data_t *ud = (signal_user_data_t*)data;
+	MSG *msg = (MSG*)wmevent;
+
+	if (msg->message == WM_DEVICECHANGE)
+	{
+		wm_drive_changed(wmevent, ud);
+	}
+	return GDK_FILTER_CONTINUE;
+}
+#endif
+
 void
 watch_volumes(signal_user_data_t *ud)
 {
+#if !defined(_WIN32)
 	GVolumeMonitor *gvm;
 	gvm = g_volume_monitor_get ();
 
 	g_signal_connect(gvm, "drive-changed", (GCallback)drive_changed_cb, ud);
-	//g_signal_connect(gvm, "drive-connected", (GCallback)drive_connected_cb, ud);
-}
 #else
-void
-watch_volumes(signal_user_data_t *ud)
-{
-}
+	GdkWindow *window;
+	GtkWidget *widget;
+
+	widget = GHB_WIDGET (ud->builder, "hb_window");
+	window = gtk_widget_get_parent_window(widget);
+	gdk_window_add_filter(window, win_message_cb, ud);
 #endif
+}
 
 // Hack to avoid a segfault in libavcodec
 extern int mm_flags;
 int mm_support();
 
-void x264_entry_changed_cb(GtkWidget *widget, signal_user_data_t *ud);
+G_MODULE_EXPORT void x264_entry_changed_cb(GtkWidget *widget, signal_user_data_t *ud);
 void preview_window_expose_cb(void);
 
 // Some style definitions for the preview window and hud
@@ -543,24 +571,33 @@ main (int argc, char *argv[])
 	textdomain (GETTEXT_PACKAGE);
 #endif
 
+#ifdef PTW32_STATIC_LIB
+	pthread_win32_process_attach_np();
+	pthread_win32_thread_attach_np();
+#endif
+
 	if (!g_thread_supported())
 		g_thread_init(NULL);
 	context = g_option_context_new ("- Rip and encode DVD or MPEG file");
 	g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE);
 	g_option_context_add_group (context, gtk_get_option_group (TRUE));
+#if !defined(_WIN32)
 	g_option_context_add_group (context, gst_init_get_option_group ());
+#endif
 	g_option_context_parse (context, &argc, &argv, &error);
 	g_option_context_free(context);
 	
 	gtk_set_locale ();
 	gtk_init (&argc, &argv);
 	gtk_rc_parse_string(hud_rcstyle);
+#if !defined(_WIN32)
 	notify_init("HandBrake");
+#endif
 	ghb_register_transforms();
 	ghb_resource_init();
 	ghb_load_icons();
 
-#if defined(__linux__)
+#if !defined(_WIN32)
 	ghb_hal_init();
 #endif
 
@@ -570,9 +607,9 @@ main (int argc, char *argv[])
 	g_log_set_handler ("Gtk", G_LOG_LEVEL_WARNING, warn_log_handler, ud);
 	//g_log_set_handler ("Gtk", G_LOG_LEVEL_CRITICAL, warn_log_handler, ud);
 	ud->settings = ghb_settings_new();
+	ud->builder = create_builder_or_die (BUILDER_NAME);
 	// Enable events that alert us to media change events
 	watch_volumes (ud);
-	ud->builder = create_builder_or_die (BUILDER_NAME);
 
 	//GtkWidget *widget = GHB_WIDGET(ud->builder, "PictureDetelecineCustom");
 	//gtk_entry_set_inner_border(widget, 2);
@@ -687,8 +724,13 @@ main (int argc, char *argv[])
 	ghb_value_free(ud->settings);
 	g_io_channel_unref(ud->activity_log);
 	ghb_settings_close();
+#if !defined(_WIN32)
 	notify_uninit();
+#endif
 	g_free(ud);
+#ifdef PTW32_STATIC_LIB
+	pthread_win32_thread_detach_np();
+	pthread_win32_process_detach_np();
+#endif
 	return 0;
 }
-
diff --git a/gtk/src/presets.c b/gtk/src/presets.c
index 2a07291f5..1c5869d4c 100644
--- a/gtk/src/presets.c
+++ b/gtk/src/presets.c
@@ -1033,7 +1033,7 @@ ghb_get_user_config_dir(gchar *subdir)
 		gchar **split;
 		gint ii;
 
-		split = g_strsplit(subdir, "/", -1);
+		split = g_strsplit(subdir, G_DIR_SEPARATOR_S, -1);
 		for (ii = 0; split[ii] != NULL; ii++)
 		{
 			gchar *tmp;
@@ -1328,6 +1328,34 @@ ghb_settings_close()
 		ghb_value_free(prefsPlist);
 }
 
+#if defined(_WIN32)
+gchar*
+FindFirstCDROM(void)
+{
+	gint ii, drives;
+	gchar drive[5];
+
+	strcpy(drive, "A:" G_DIR_SEPARATOR_S);
+	drives = GetLogicalDrives();
+	for (ii = 0; ii < 26; ii++)
+	{
+		if (drives & 0x01)
+		{
+			guint dtype;
+
+			drive[0] = 'A' + ii;
+			dtype = GetDriveType(drive);
+			if (dtype == DRIVE_CDROM)
+			{
+				return g_strdup(drive);
+			}
+		}
+		drives >>= 1;
+	}
+	return NULL;
+}
+#endif
+
 void
 ghb_prefs_load(signal_user_data_t *ud)
 {
@@ -1363,6 +1391,18 @@ ghb_prefs_load(signal_user_data_t *ud)
 		}
 		ghb_dict_insert(dict, 
 			g_strdup("destination_dir"), ghb_value_dup(ghb_string_value(dir)));
+#if defined(_WIN32)
+		gchar *source;
+
+		source = FindFirstCDROM();
+		if (source == NULL)
+		{
+			source = g_strdup("C:" G_DIR_SEPARATOR_S);
+		}
+		ghb_dict_insert(dict, g_strdup("default_source"), 
+						ghb_value_dup(ghb_string_value(source)));
+		g_free(source);
+#endif
 		store_prefs();
     }
 	// Read legacy default_preset preference and update accordingly
@@ -2837,7 +2877,7 @@ enforce_preset_type(signal_user_data_t *ud, const GValue *path)
 	}
 }
 
-void
+G_MODULE_EXPORT void
 presets_save_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
 {
 	GtkWidget *dialog;
@@ -2906,13 +2946,13 @@ presets_save_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
 	}
 }
 
-void
+G_MODULE_EXPORT void
 preset_type_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
 {
 	ghb_widget_to_setting(ud->settings, widget);
 }
 
-void
+G_MODULE_EXPORT void
 preset_name_changed_cb(GtkWidget *entry, signal_user_data_t *ud)
 {
 	gchar *name;
@@ -2928,7 +2968,7 @@ preset_name_changed_cb(GtkWidget *entry, signal_user_data_t *ud)
 	ghb_value_free(dest);
 }
 
-void
+G_MODULE_EXPORT void
 presets_restore_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
 {
 	GValue *preset;
@@ -2942,7 +2982,7 @@ presets_restore_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
 	ghb_select_preset(ud->builder, preset);
 }
 
-void
+G_MODULE_EXPORT void
 presets_remove_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
 {
 	GtkTreeView *treeview;
@@ -3011,7 +3051,7 @@ presets_remove_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
 }
 
 // controls where valid drop locations are
-gboolean
+G_MODULE_EXPORT gboolean
 presets_drag_motion_cb(
 	GtkTreeView *tv,
 	GdkDragContext *ctx,
@@ -3102,7 +3142,7 @@ presets_drag_motion_cb(
 	return TRUE;
 }
 
-void 
+G_MODULE_EXPORT void 
 presets_drag_cb(
 	GtkTreeView *dstwidget, 
 	GdkDragContext *dc, 
@@ -3347,7 +3387,7 @@ preset_update_title_deps(signal_user_data_t *ud, ghb_title_info_t *tinfo)
 	}
 }
 
-void
+G_MODULE_EXPORT void
 presets_list_selection_changed_cb(GtkTreeSelection *selection, signal_user_data_t *ud)
 {
 	GtkTreeModel *store;
@@ -3445,7 +3485,7 @@ ghb_clear_presets_selection(signal_user_data_t *ud)
 	ghb_settings_set_boolean(ud->settings, "preset_modified", TRUE);
 }
 
-void
+G_MODULE_EXPORT void
 presets_frame_size_allocate_cb(GtkWidget *widget, GtkAllocation *allocation, signal_user_data_t *ud)
 {
 	GtkTreeView *treeview;
@@ -3465,7 +3505,7 @@ presets_frame_size_allocate_cb(GtkWidget *widget, GtkAllocation *allocation, sig
 	}
 }
 
-void
+G_MODULE_EXPORT void
 presets_default_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
 {
 	GValue *preset;
diff --git a/gtk/src/preview.c b/gtk/src/preview.c
index 6164270de..ef5f8c738 100644
--- a/gtk/src/preview.c
+++ b/gtk/src/preview.c
@@ -16,11 +16,18 @@
 #include <glib/gstdio.h>
 #include <glib-object.h>
 #include <gtk/gtk.h>
+
+#if !defined(_WIN32)
 #include <gdk/gdkx.h>
+#endif
+
+#if defined(_ENABLE_GST)
 #include <gst/gst.h>
 #include <gst/interfaces/xoverlay.h>
 #include <gst/video/video.h>
 #include <gst/pbutils/missing-plugins.h>
+#endif
+
 #include "settings.h"
 #include "presets.h"
 #include "callbacks.h"
@@ -34,7 +41,10 @@
 
 struct preview_s
 {
+#if defined(_ENABLE_GST)
 	GstElement *play;
+	gulong xid;
+#endif
 	gint64 len;
 	gint64 pos;
 	gboolean seek_lock;
@@ -42,7 +52,6 @@ struct preview_s
 	gint width;
 	gint height;
 	GtkWidget *view;
-	gulong xid;
 	GdkPixbuf *pix;
 	gint button_width;
 	gint button_height;
@@ -55,15 +64,19 @@ struct preview_s
 	gchar *current;
 };
 
-static gboolean live_preview_cb(GstBus *bus, GstMessage *msg, gpointer data);
+#if defined(_ENABLE_GST)
+G_MODULE_EXPORT gboolean live_preview_cb(GstBus *bus, GstMessage *msg, gpointer data);
 static GstBusSyncReply create_window(GstBus *bus, GstMessage *msg, 
 				gpointer data);
-gboolean preview_expose_cb(GtkWidget *widget, GdkEventExpose *event, 
+#endif
+
+G_MODULE_EXPORT gboolean preview_expose_cb(GtkWidget *widget, GdkEventExpose *event, 
 				signal_user_data_t *ud);
 
 void
 ghb_screen_par(signal_user_data_t *ud, gint *par_n, gint *par_d)
 {
+#if defined(_ENABLE_GST)
 	GValue disp_par = {0,};
 	GstElement *xover;
 	GObjectClass *klass;
@@ -91,6 +104,10 @@ ghb_screen_par(signal_user_data_t *ud, gint *par_n, gint *par_d)
 	*par_n = gst_value_get_fraction_numerator(&disp_par);
 	*par_d = gst_value_get_fraction_denominator(&disp_par);
 	g_value_unset(&disp_par);
+#else
+	*par_n = 1;
+	*par_d = 1;
+#endif
 }
 
 void
@@ -111,20 +128,22 @@ ghb_par_scale(signal_user_data_t *ud, gint *width, gint *height, gint par_n, gin
 void
 ghb_preview_init(signal_user_data_t *ud)
 {
-	GstBus *bus;
-	GstElement *xover;
-
 	ud->preview = g_malloc0(sizeof(preview_t));
 	ud->preview->view = GHB_WIDGET(ud->builder, "preview_image");
 	gtk_widget_realize(ud->preview->view);
 	g_signal_connect(G_OBJECT(ud->preview->view), "expose_event",
 					G_CALLBACK(preview_expose_cb), ud);
-	ud->preview->xid = GDK_DRAWABLE_XID(ud->preview->view->window);
 
-	ud->preview->play = gst_element_factory_make("playbin", "play");
 	ud->preview->pause = TRUE;
 	ud->preview->encode_frame = -1;
 	ud->preview->live_id = -1;
+
+#if defined(_ENABLE_GST)
+	GstBus *bus;
+	GstElement *xover;
+
+	ud->preview->xid = GDK_DRAWABLE_XID(ud->preview->view->window);
+	ud->preview->play = gst_element_factory_make("playbin", "play");
 	//xover = gst_element_factory_make("xvimagesink", "xover");
 	//xover = gst_element_factory_make("ximagesink", "xover");
 	xover = gst_element_factory_make("gconfvideosink", "xover");
@@ -135,6 +154,12 @@ ghb_preview_init(signal_user_data_t *ud)
 	gst_bus_add_watch(bus, live_preview_cb, ud);
 	gst_bus_set_sync_handler(bus, create_window, ud->preview);
 	gst_object_unref(bus);
+#else
+	GtkWidget *widget = GHB_WIDGET(ud->builder, "live_preview_box");
+	gtk_widget_hide (widget);
+	widget = GHB_WIDGET(ud->builder, "live_preview_duration_box");
+	gtk_widget_hide (widget);
+#endif
 }
 
 void
@@ -147,6 +172,7 @@ ghb_preview_cleanup(signal_user_data_t *ud)
 	}
 }
 
+#if defined(_ENABLE_GST)
 static GstBusSyncReply
 create_window(GstBus *bus, GstMessage *msg, gpointer data)
 {
@@ -307,7 +333,7 @@ update_stream_info(signal_user_data_t *ud)
 	g_list_free(vstreams);
 }
 
-static gboolean
+G_MODULE_EXPORT gboolean
 live_preview_cb(GstBus *bus, GstMessage *msg, gpointer data)
 {
 	signal_user_data_t *ud = (signal_user_data_t*)data;
@@ -409,6 +435,7 @@ live_preview_pause(signal_user_data_t *ud)
 	gst_element_set_state(ud->preview->play, GST_STATE_PAUSED);
 	ud->preview->pause = TRUE;
 }
+#endif
 
 void
 live_preview_stop(signal_user_data_t *ud)
@@ -418,7 +445,9 @@ live_preview_stop(signal_user_data_t *ud)
 
 	img = GTK_IMAGE(GHB_WIDGET(ud->builder, "live_preview_play_image"));
 	gtk_image_set_from_stock(img, "gtk-media-play", GTK_ICON_SIZE_BUTTON);
+#if defined(_ENABLE_GST)
 	gst_element_set_state(ud->preview->play, GST_STATE_NULL);
+#endif
 	ud->preview->pause = TRUE;
 	ud->preview->state = PREVIEW_STATE_IMAGE;
 
@@ -452,7 +481,7 @@ ghb_live_reset(signal_user_data_t *ud)
 
 extern void hb_get_tempory_directory(hb_handle_t *h, char path[512]);
 
-void
+G_MODULE_EXPORT void
 live_preview_start_cb(GtkWidget *xwidget, signal_user_data_t *ud)
 {
 	gchar *tmp_dir;
@@ -468,10 +497,12 @@ live_preview_start_cb(GtkWidget *xwidget, signal_user_data_t *ud)
 	if (ud->preview->encoded[frame] &&
 		g_file_test(name, G_FILE_TEST_IS_REGULAR))
 	{
+#if defined(_ENABLE_GST)
 		if (ud->preview->pause)
 			live_preview_start(ud);
 		else
 			live_preview_pause(ud);
+#endif
 	}
 	else
 	{
@@ -502,7 +533,9 @@ ghb_live_encode_done(signal_user_data_t *ud, gboolean success)
 		gtk_progress_bar_set_text(GTK_PROGRESS_BAR(prog), "Done");
 		gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR(prog), 1);
 		ud->preview->encoded[ud->preview->encode_frame] = TRUE;
+#if defined(_ENABLE_GST)
 		live_preview_start(ud);
+#endif
 		widget = GHB_WIDGET(ud->builder, "live_progress_box");
 		gtk_widget_hide (widget);
 		widget = GHB_WIDGET(ud->builder, "live_preview_progress");
@@ -516,7 +549,8 @@ ghb_live_encode_done(signal_user_data_t *ud, gboolean success)
 	}
 }
 
-static gboolean
+#if defined(_ENABLE_GST)
+G_MODULE_EXPORT gboolean
 unlock_progress_cb(signal_user_data_t *ud)
 {
 	ud->preview->progress_lock = FALSE;
@@ -524,10 +558,12 @@ unlock_progress_cb(signal_user_data_t *ud)
 	// so that it is not called again
 	return FALSE;
 }
+#endif
 
 void
 ghb_live_preview_progress(signal_user_data_t *ud)
 {
+#if defined(_ENABLE_GST)
 	GstFormat fmt = GST_FORMAT_TIME;
 	gint64 len = -1, pos = -1;
 
@@ -559,9 +595,11 @@ ghb_live_preview_progress(signal_user_data_t *ud)
 		gtk_range_set_value(progress, percent);
 	}
 	g_idle_add((GSourceFunc)unlock_progress_cb, ud);
+#endif
 }
 
-static gboolean
+#if defined(_ENABLE_GST)
+G_MODULE_EXPORT gboolean
 unlock_seek_cb(signal_user_data_t *ud)
 {
 	ud->preview->seek_lock = FALSE;
@@ -569,10 +607,12 @@ unlock_seek_cb(signal_user_data_t *ud)
 	// so that it is not called again
 	return FALSE;
 }
+#endif
 
-void
+G_MODULE_EXPORT void
 live_preview_seek_cb(GtkWidget *widget, signal_user_data_t *ud)
 {
+#if defined(_ENABLE_GST)
 	gdouble dval;
 	gint64 pos;
 
@@ -587,6 +627,7 @@ live_preview_seek_cb(GtkWidget *widget, signal_user_data_t *ud)
 		GST_SEEK_TYPE_SET, pos,
 		GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
 	g_idle_add((GSourceFunc)unlock_seek_cb, ud);
+#endif
 }
 
 void
@@ -666,7 +707,8 @@ ghb_set_preview_image(signal_user_data_t *ud)
 	}
 }
 
-static gboolean
+#if defined(_ENABLE_GST)
+G_MODULE_EXPORT gboolean
 delayed_expose_cb(signal_user_data_t *ud)
 {
 	GstElement *vsink;
@@ -683,13 +725,15 @@ delayed_expose_cb(signal_user_data_t *ud)
 	// so that it is not called again
 	return FALSE;
 }
+#endif
 
-gboolean
+G_MODULE_EXPORT gboolean
 preview_expose_cb(
 	GtkWidget *widget, 
 	GdkEventExpose *event, 
 	signal_user_data_t *ud)
 {
+#if defined(_ENABLE_GST)
 	if (ud->preview->state == PREVIEW_STATE_LIVE)
 	{
 		if (GST_STATE(ud->preview->play) >= GST_STATE_PAUSED)
@@ -712,6 +756,7 @@ preview_expose_cb(
 		}
 		return TRUE;
 	}
+#endif
 
 	if (ud->preview->pix != NULL)
 	{
@@ -722,7 +767,7 @@ preview_expose_cb(
 	return TRUE;
 }
 
-void
+G_MODULE_EXPORT void
 preview_button_size_allocate_cb(GtkWidget *widget, GtkAllocation *allocation, signal_user_data_t *ud)
 {
 	g_debug("allocate %d x %d", allocation->width, allocation->height);
@@ -919,7 +964,7 @@ preview_frame_value_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
 	ghb_set_preview_image(ud);
 }
 
-gboolean
+G_MODULE_EXPORT gboolean
 preview_window_delete_cb(
 	GtkWidget *widget, 
 	GdkEvent *event, 
@@ -967,7 +1012,7 @@ settings_window_delete_cb(
 	return TRUE;
 }
 
-void
+G_MODULE_EXPORT void
 preview_duration_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
 {
 	g_debug("preview_duration_changed_cb ()");
diff --git a/gtk/src/queuehandler.c b/gtk/src/queuehandler.c
index f01f543b6..aed2b0790 100644
--- a/gtk/src/queuehandler.c
+++ b/gtk/src/queuehandler.c
@@ -23,7 +23,7 @@
 #include "presets.h"
 #include "ghb-dvd.h"
 
-void
+G_MODULE_EXPORT void
 queue_list_selection_changed_cb(GtkTreeSelection *selection, signal_user_data_t *ud)
 {
 	GtkTreeModel *store;
@@ -674,14 +674,14 @@ queue_add(signal_user_data_t *ud)
 	return TRUE;
 }
 
-void
+G_MODULE_EXPORT void
 queue_add_clicked_cb(GtkWidget *widget, signal_user_data_t *ud)
 {
 	g_debug("queue_add_clicked_cb ()");
 	queue_add(ud);
 }
 
-void
+G_MODULE_EXPORT void
 queue_remove_clicked_cb(GtkWidget *widget, gchar *path, signal_user_data_t *ud)
 {
 	GtkTreeView *treeview;
@@ -761,7 +761,7 @@ find_last_finished(GValue *queue)
 // handler from expanding rows if you hover over them while
 // dragging.
 // Also controls where valid drop locations are
-gboolean
+G_MODULE_EXPORT gboolean
 queue_drag_motion_cb(
 	GtkTreeView *tv,
 	GdkDragContext *ctx,
@@ -839,7 +839,7 @@ queue_drag_motion_cb(
 	return TRUE;
 }
 
-void 
+G_MODULE_EXPORT void 
 queue_drag_cb(
 	GtkTreeView *dstwidget, 
 	GdkDragContext *dc, 
@@ -973,7 +973,7 @@ ghb_queue_buttons_grey(signal_user_data_t *ud, gboolean working)
 	gtk_action_set_sensitive (action, working);
 }
 
-void
+G_MODULE_EXPORT void
 queue_list_size_allocate_cb(GtkWidget *widget, GtkAllocation *allocation, GtkCellRenderer *cell)
 {
 	GtkTreeViewColumn *column;
@@ -988,7 +988,7 @@ queue_list_size_allocate_cb(GtkWidget *widget, GtkAllocation *allocation, GtkCel
 		g_object_set(cell, "wrap-width", width-70, NULL);
 }
 
-void
+G_MODULE_EXPORT void
 queue_start_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
 {
 	GValue *js;
@@ -1024,14 +1024,14 @@ queue_start_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
 	}
 }
 
-void
+G_MODULE_EXPORT void
 queue_stop_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
 {
 	ud->cancel_encode = TRUE;
 	ghb_cancel_encode(NULL);
 }
 
-void
+G_MODULE_EXPORT void
 queue_pause_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
 {
 	ghb_pause_queue();
@@ -1107,7 +1107,7 @@ ghb_reload_queue(signal_user_data_t *ud)
 	return FALSE;
 }
 
-gboolean 
+G_MODULE_EXPORT gboolean 
 queue_key_press_cb(
 	GtkWidget *widget, 
 	GdkEventKey *event,
@@ -1170,7 +1170,7 @@ queue_key_press_cb(
 
 GValue *ghb_queue_edit_settings = NULL;
 
-void
+G_MODULE_EXPORT void
 queue_edit_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
 {
 	GtkTreeView *treeview;
diff --git a/gtk/src/values.c b/gtk/src/values.c
index a2096e008..17319a582 100644
--- a/gtk/src/values.c
+++ b/gtk/src/values.c
@@ -15,6 +15,7 @@
 #include <glib.h>
 #include <glib-object.h>
 #include <string.h>
+#include <inttypes.h>
 #include "values.h"
 
 static void dict_delete_key(gpointer data);
@@ -96,7 +97,7 @@ debug_show_value(GValue *gval)
 	}
 	else if (tp == G_TYPE_INT64)
 	{
-		g_message("Type %s value %ld", "int64", g_value_get_int64(gval));
+		g_message("Type %s value %" PRId64, "int64", g_value_get_int64(gval));
 	}
 	else if (tp == G_TYPE_DOUBLE)
 	{
diff --git a/gtk/src/makedeps.c b/gtk/src/widgetdeps.c
similarity index 100%
rename from gtk/src/makedeps.c
rename to gtk/src/widgetdeps.c
diff --git a/gtk/src/x264handler.c b/gtk/src/x264handler.c
index 20ec56e5f..ff2338f19 100644
--- a/gtk/src/x264handler.c
+++ b/gtk/src/x264handler.c
@@ -26,7 +26,7 @@ static gchar* sanitize_x264opts(signal_user_data_t *ud, const gchar *options);
 // Flag needed to prevent x264 options processing from chasing its tail
 static gboolean ignore_options_update = FALSE;
 
-void
+G_MODULE_EXPORT void
 x264_widget_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
 {
 	ghb_widget_to_setting(ud->settings, widget);
@@ -40,7 +40,7 @@ x264_widget_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
 	ghb_clear_presets_selection(ud);
 }
 
-void
+G_MODULE_EXPORT void
 x264_me_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
 {
 	gint me;
@@ -68,7 +68,7 @@ x264_me_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
 	}
 }
 
-void
+G_MODULE_EXPORT void
 x264_entry_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
 {
 	g_debug("x264_entry_changed_cb ()");
@@ -96,7 +96,7 @@ x264_entry_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
 	}
 }
 
-gboolean
+G_MODULE_EXPORT gboolean
 x264_focus_out_cb(GtkWidget *widget, GdkEventFocus *event, 
 	signal_user_data_t *ud)
 {