From 1650b4b205191609b5e79393ca07257fa6aa8bca Mon Sep 17 00:00:00 2001 From: Luca Bacci Date: Mon, 15 Nov 2021 11:51:43 +0100 Subject: [PATCH] Win32: Fix print dialog custom widget measurement --- gtk/gtkprintoperation-win32.c | 144 +++++++++++++++++++++++++--------- gtk/gtkwin32embedwidget.c | 1 + 2 files changed, 110 insertions(+), 35 deletions(-) diff --git a/gtk/gtkprintoperation-win32.c b/gtk/gtkprintoperation-win32.c index b3f9a21cb2..abd4f7de95 100644 --- a/gtk/gtkprintoperation-win32.c +++ b/gtk/gtkprintoperation-win32.c @@ -47,6 +47,29 @@ #include "gtkwin32embedwidget.h" #include "gtkprivate.h" +#include +typedef struct { + WORD dlgVer; + WORD signature; + DWORD helpID; + DWORD exStyle; + DWORD style; + WORD cDlgItems; + short x; + short y; + short cx; + short cy; + short menu; + short windowClass; + WCHAR title; + WORD pointsize; + WORD weight; + BYTE italic; + BYTE charset; + WCHAR typeface[LF_FACESIZE]; +} DLGTEMPLATEEX; +#include + #define MAX_PAGE_RANGES 20 #define STATUS_POLLING_TIME 2000 @@ -1461,7 +1484,12 @@ pageDlgProc (HWND wnd, UINT message, WPARAM wparam, LPARAM lparam) } else { - op = GTK_PRINT_OPERATION (GetWindowLongPtrW (wnd, GWLP_USERDATA)); + gpointer user_data = GetWindowLongPtrW (wnd, GWLP_USERDATA); + + if (!user_data) + return FALSE; + + op = GTK_PRINT_OPERATION (user_data); op_win32 = op->priv->platform_data; return _gtk_win32_embed_widget_dialog_procedure (GTK_WIN32_EMBED_WIDGET (op_win32->embed_widget), @@ -1471,43 +1499,83 @@ pageDlgProc (HWND wnd, UINT message, WPARAM wparam, LPARAM lparam) return FALSE; } -static HPROPSHEETPAGE -create_application_page (GtkPrintOperation *op) +static INT_PTR CALLBACK +measure_dialog_procedure (HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) { - HPROPSHEETPAGE hpage; - PROPSHEETPAGEW page; - DLGTEMPLATE *template; + return FALSE; +} + +static HPROPSHEETPAGE +create_application_page (GtkPrintOperation *op, + HWND hwndOwner, + int scale) +{ + const LONG DBU_DEFAULT = GetDialogBaseUnits (); + int dbu_x = LOWORD (DBU_DEFAULT); + int dbu_y = HIWORD (DBU_DEFAULT); + HWND measure_dialog = NULL; HGLOBAL htemplate; - LONG base_units; - WORD baseunitX, baseunitY; - WORD *array; + DLGTEMPLATEEX *template; + PROPSHEETPAGEW page; + HPROPSHEETPAGE hpage; GtkRequisition requisition; - const char *tab_label; + const char *tab_label = NULL; + + /* Widget must be visible to measure its size */ + gtk_widget_show (op->priv->custom_widget); + gtk_widget_get_preferred_size (op->priv->custom_widget, &requisition, NULL); + + htemplate = GlobalAlloc (GMEM_MOVEABLE | GMEM_ZEROINIT, sizeof (DLGTEMPLATEEX)); + template = GlobalLock (htemplate); + template->dlgVer = 1; + template->signature = 0xFFFF; + template->helpID = 0; + template->exStyle = 0; + template->style = DS_SHELLFONT; + template->cDlgItems = 0; + template->x = 0; + template->y = 0; + template->cx = 10; + template->cy = 10; + template->menu = 0; + template->windowClass = 0; + template->title = 0; + template->pointsize = 8; + template->weight = FW_NORMAL; + template->italic = FALSE; + template->charset = DEFAULT_CHARSET; + wcscpy_s (template->typeface, LF_FACESIZE, L"MS Shell Dlg"); + + /* Create an invisible dialog to measure dialog base units */ + measure_dialog = CreateDialogIndirectW (NULL, template, hwndOwner, measure_dialog_procedure); + if (!measure_dialog) + g_warning ("CreateDialogIndirectW failed"); + else + { + RECT rect; + + SetRect (&rect, 0, 0, 4, 8); + if (!MapDialogRect (measure_dialog, &rect)) + g_warning ("MapDialogRect failed"); + else + { + dbu_x = rect.right - rect.left; + dbu_y = rect.bottom - rect.top; + } + + DestroyWindow (measure_dialog); + measure_dialog = NULL; + } /* Make the template the size of the custom widget size request */ - gtk_widget_get_preferred_size (op->priv->custom_widget, - &requisition, NULL); + template->exStyle |= WS_EX_CONTROLPARENT; + template->style |= WS_CHILD | DS_CONTROL; + template->cx = (requisition.width * scale * 4.0) / dbu_x + 1; + template->cy = (requisition.height * scale * 8.0) / dbu_y + 1; - base_units = GetDialogBaseUnits (); - baseunitX = LOWORD (base_units); - baseunitY = HIWORD (base_units); - - htemplate = GlobalAlloc (GMEM_MOVEABLE, - sizeof (DLGTEMPLATE) + sizeof (WORD) * 3); - template = GlobalLock (htemplate); - template->style = WS_CHILDWINDOW | DS_CONTROL; - template->dwExtendedStyle = WS_EX_CONTROLPARENT; - template->cdit = 0; - template->x = MulDiv (0, 4, baseunitX); - template->y = MulDiv (0, 8, baseunitY); - template->cx = MulDiv (requisition.width, 4, baseunitX); - template->cy = MulDiv (requisition.height, 8, baseunitY); - - array = (WORD *) (template+1); - *array++ = 0; /* menu */ - *array++ = 0; /* class */ - *array++ = 0; /* title */ - memset (&page, 0, sizeof (page)); page.dwSize = sizeof (page); page.dwFlags = PSP_DLGINDIRECT | PSP_USETITLE | PSP_PREMATURE; @@ -1731,6 +1799,7 @@ gtk_print_operation_run_with_dialog (GtkPrintOperation *op, GtkPrintOperationPrivate *priv; IPrintDialogCallback *callback; HPROPSHEETPAGE prop_page; + int scale = 1; static volatile gsize common_controls_initialized = 0; if (g_once_init_enter (&common_controls_initialized)) @@ -1762,10 +1831,15 @@ gtk_print_operation_run_with_dialog (GtkPrintOperation *op, if (parent == NULL) { invisible = gtk_invisible_new (); + parentHWnd = get_parent_hwnd (invisible); + scale = gtk_widget_get_scale_factor (invisible); + } + else + { + parentHWnd = get_parent_hwnd (GTK_WIDGET (parent)); + scale = gtk_widget_get_scale_factor (GTK_WIDGET (parent)); } - else - parentHWnd = get_parent_hwnd (GTK_WIDGET (parent)); printdlgex = (LPPRINTDLGEXW)GlobalAlloc (GPTR, sizeof (PRINTDLGEXW)); if (!printdlgex) @@ -1817,7 +1891,7 @@ gtk_print_operation_run_with_dialog (GtkPrintOperation *op, g_signal_emit_by_name (op, "create-custom-widget", &op->priv->custom_widget); if (op->priv->custom_widget) { - prop_page = create_application_page (op); + prop_page = create_application_page (op, parentHWnd, scale); printdlgex->nPropertyPages = 1; printdlgex->lphPropertyPages = &prop_page; } else { diff --git a/gtk/gtkwin32embedwidget.c b/gtk/gtkwin32embedwidget.c index c4e6aff897..619a459c94 100644 --- a/gtk/gtkwin32embedwidget.c +++ b/gtk/gtkwin32embedwidget.c @@ -85,6 +85,7 @@ gtk_win32_embed_widget_init (GtkWin32EmbedWidget *embed_widget) G_GNUC_BEGIN_IGNORE_DEPRECATIONS; gtk_container_set_resize_mode (GTK_CONTAINER (embed_widget), GTK_RESIZE_QUEUE); G_GNUC_END_IGNORE_DEPRECATIONS; + gtk_window_set_decorated (GTK_WINDOW (embed_widget), FALSE); } GtkWidget*