summaryrefslogtreecommitdiff
path: root/gtk
diff options
context:
space:
mode:
authorРуслан Ижбулатов <lrn1986@gmail.com>2014-07-29 08:18:32 +0000
committerРуслан Ижбулатов <lrn1986@gmail.com>2014-08-05 06:41:31 +0000
commit0d02cc8203e1a43506c0e81f392492aedadb6fa3 (patch)
treebd52cdc4add8c43b7aad0017ba54ed432b50ea2a /gtk
parent31d08bd85e312ba05b7890b403c8a50cfdf52c4f (diff)
downloadgtk+-0d02cc8203e1a43506c0e81f392492aedadb6fa3.tar.gz
Make sure native W32 print dialog uses visual styles
For that to happen the libgtk3 is embedded with a manifest that requests common controls library 6.x, and GTK lazily calls InitCommonControlsEx() to initialize those. Then this manifest is used to temporarily override the process activation contest when loading comdlg32 (which contains the code for the print dialog), ensuring that it too depends on common controls 6.x, even if the application that uses GTK does not. https://bugzilla.gnome.org/show_bug.cgi?id=733773
Diffstat (limited to 'gtk')
-rw-r--r--gtk/Makefile.am3
-rw-r--r--gtk/gtk-win32.rc.in1
-rw-r--r--gtk/gtkprintoperation-win32.c19
-rw-r--r--gtk/gtkprivate.h4
-rw-r--r--gtk/gtkwin32.c90
-rw-r--r--gtk/libgtk3.manifest.in21
6 files changed, 137 insertions, 1 deletions
diff --git a/gtk/Makefile.am b/gtk/Makefile.am
index 2f74d2e862..5c31084a7a 100644
--- a/gtk/Makefile.am
+++ b/gtk/Makefile.am
@@ -90,7 +90,7 @@ gtk_win32_symbols = -export-symbols $(srcdir)/gtk.def
gtk_win32_res = gtk-win32-res.o
gtk_win32_res_ldflag = -Wl,gtk-win32-res.o
-gtk-win32-res.o : gtk-win32.rc
+gtk-win32-res.o : gtk-win32.rc libgtk3.manifest
$(WINDRES) gtk-win32.rc $@
gtk.def: libgtk-3.la
@@ -1726,6 +1726,7 @@ EXTRA_DIST += \
$(adwaita_sources) \
$(win32_theme_sources) \
$(gsettings_SCHEMAS) \
+ libgtk3.manifest.in \
gtk-win32.rc.in \
gtkwin32embed.h \
gtkwin32embedwidget.h \
diff --git a/gtk/gtk-win32.rc.in b/gtk/gtk-win32.rc.in
index 4a42d5a666..dc9464a2c1 100644
--- a/gtk/gtk-win32.rc.in
+++ b/gtk/gtk-win32.rc.in
@@ -28,3 +28,4 @@ VS_VERSION_INFO VERSIONINFO
VALUE "Translation", 0x409, 1200
END
END
+ISOLATIONAWARE_MANIFEST_RESOURCE_ID RT_MANIFEST libgtk3.manifest
diff --git a/gtk/gtkprintoperation-win32.c b/gtk/gtkprintoperation-win32.c
index e59eb9f675..3ac6bc47bf 100644
--- a/gtk/gtkprintoperation-win32.c
+++ b/gtk/gtkprintoperation-win32.c
@@ -1657,6 +1657,25 @@ gtk_print_operation_run_with_dialog (GtkPrintOperation *op,
GtkPrintOperationPrivate *priv;
IPrintDialogCallback *callback;
HPROPSHEETPAGE prop_page;
+ static volatile gsize common_controls_initialized = 0;
+
+ if (g_once_init_enter (&common_controls_initialized))
+ {
+ BOOL initialized;
+ INITCOMMONCONTROLSEX icc;
+
+ memset (&icc, 0, sizeof (icc));
+ icc.dwSize = sizeof (icc);
+ icc.dwICC = ICC_WIN95_CLASSES;
+
+ initialized = InitCommonControlsEx (&icc);
+ if (!initialized)
+ g_warning ("Failed to InitCommonControlsEx: %lu\n", GetLastError ());
+
+ _gtk_load_dll_with_libgtk3_manifest ("comdlg32.dll");
+
+ g_once_init_leave (&common_controls_initialized, initialized ? 1 : 0);
+ }
*do_print = FALSE;
diff --git a/gtk/gtkprivate.h b/gtk/gtkprivate.h
index a07f7292ba..5fe7d88eae 100644
--- a/gtk/gtkprivate.h
+++ b/gtk/gtkprivate.h
@@ -91,6 +91,10 @@ gboolean _gtk_propagate_captured_event (GtkWidget *widget,
GdkEvent *event,
GtkWidget *topmost);
+#ifdef G_OS_WIN32
+void _gtk_load_dll_with_libgtk3_manifest (const char *dllname);
+#endif
+
G_END_DECLS
#endif /* __GTK_PRIVATE_H__ */
diff --git a/gtk/gtkwin32.c b/gtk/gtkwin32.c
index e8bd7ef133..c33659e278 100644
--- a/gtk/gtkwin32.c
+++ b/gtk/gtkwin32.c
@@ -30,8 +30,15 @@
#define STRICT
#include <windows.h>
+#include <commctrl.h>
#undef STRICT
+/* In practice, resulting DLL will have manifest resource under index 2.
+ * Fall back to that value if we can't find resource index programmatically.
+ */
+#define EMPIRIC_MANIFEST_RESOURCE_INDEX 2
+
+
static HMODULE gtk_dll;
BOOL WINAPI
@@ -49,6 +56,89 @@ DllMain (HINSTANCE hinstDLL,
return TRUE;
}
+static BOOL CALLBACK
+find_first_manifest (HMODULE module_handle,
+ LPCSTR resource_type,
+ LPSTR resource_name,
+ LONG_PTR user_data)
+{
+ LPSTR *result_name = (LPSTR *) user_data;
+
+ if (resource_type == RT_MANIFEST)
+ {
+ if (IS_INTRESOURCE (resource_name))
+ *result_name = resource_name;
+ else
+ *result_name = g_strdup (resource_name);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/**
+ * Grabs the first manifest it finds in libgtk3 (which is expected to be the
+ * common-controls-6.0.0.0 manifest we embedded to enable visual styles),
+ * uses it to create a process-default activation context, activates that
+ * context, loads up the library passed in @dllname, then deactivates and
+ * releases the context.
+ *
+ * In practice this is used to force system DLLs (like comdlg32) to be
+ * loaded as if the application had the same manifest as libgtk3
+ * (otherwise libgtk3 manifest only affests libgtk3 itself).
+ * This way application does not need to have a manifest or to link
+ * against comctl32.
+ *
+ * Note that loaded library handle leaks, so only use this function in
+ * g_once_init_enter (leaking once is OK, Windows will clean up after us).
+ */
+void
+_gtk_load_dll_with_libgtk3_manifest (const gchar *dll_name)
+{
+ HANDLE activation_ctx_handle;
+ ACTCTXA activation_ctx_descriptor;
+ ULONG_PTR activation_cookie;
+ LPSTR resource_name;
+ BOOL activated;
+
+ resource_name = NULL;
+ EnumResourceNames (gtk_dll, RT_MANIFEST, find_first_manifest,
+ (LONG_PTR) &resource_name);
+
+ if (resource_name == NULL)
+ resource_name = MAKEINTRESOURCEA (EMPIRIC_MANIFEST_RESOURCE_INDEX);
+
+ memset (&activation_ctx_descriptor, 0, sizeof (activation_ctx_descriptor));
+ activation_ctx_descriptor.cbSize = sizeof (activation_ctx_descriptor);
+ activation_ctx_descriptor.dwFlags = ACTCTX_FLAG_RESOURCE_NAME_VALID |
+ ACTCTX_FLAG_HMODULE_VALID |
+ ACTCTX_FLAG_SET_PROCESS_DEFAULT;
+ activation_ctx_descriptor.hModule = gtk_dll;
+ activation_ctx_descriptor.lpResourceName = resource_name;
+ activation_ctx_handle = CreateActCtx (&activation_ctx_descriptor);
+
+ if (activation_ctx_handle == INVALID_HANDLE_VALUE)
+ g_warning ("Failed to CreateActCtx for module %p, resource %p: %lu\n",
+ gtk_dll, resource_name, GetLastError ());
+ else
+ {
+ activation_cookie = 0;
+ activated = ActivateActCtx (activation_ctx_handle, &activation_cookie);
+
+ if (!activated)
+ g_warning ("Failed to ActivateActCtx: %lu\n", GetLastError ());
+
+ LoadLibraryA (dll_name);
+
+ if (activated && !DeactivateActCtx (0, activation_cookie))
+ g_warning ("Failed to DeactivateActCtx: %lu\n", GetLastError ());
+
+ ReleaseActCtx (activation_ctx_handle);
+ }
+
+ if (!IS_INTRESOURCE (resource_name))
+ g_free (resource_name);
+}
+
const gchar *
_gtk_get_libdir (void)
{
diff --git a/gtk/libgtk3.manifest.in b/gtk/libgtk3.manifest.in
new file mode 100644
index 0000000000..6e1677eb1f
--- /dev/null
+++ b/gtk/libgtk3.manifest.in
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+ <assemblyIdentity
+ version="1.0.0.0"
+ processorArchitecture="@EXE_MANIFEST_ARCHITECTURE@"
+ name="libgtk3"
+ type="win32"
+ />
+ <dependency>
+ <dependentAssembly>
+ <assemblyIdentity
+ type="win32"
+ name="Microsoft.Windows.Common-Controls"
+ version="6.0.0.0"
+ processorArchitecture="@EXE_MANIFEST_ARCHITECTURE@"
+ publicKeyToken="6595b64144ccf1df"
+ language="*"
+ />
+ </dependentAssembly>
+ </dependency>
+</assembly>