Commit 0d02cc82 authored by LRN's avatar LRN

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
parent 31d08bd8
......@@ -1894,6 +1894,7 @@ gtk/Makefile
gtk/makefile.msc
gtk/gtkversion.h
gtk/gtk-win32.rc
gtk/libgtk3.manifest
gtk/inspector/Makefile
gtk/native/Makefile
util/Makefile
......
......@@ -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 \
......
......@@ -28,3 +28,4 @@ VS_VERSION_INFO VERSIONINFO
VALUE "Translation", 0x409, 1200
END
END
ISOLATIONAWARE_MANIFEST_RESOURCE_ID RT_MANIFEST libgtk3.manifest
......@@ -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;
......
......@@ -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__ */
......@@ -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)
{
......
<?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>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment