diff --git a/ChangeLog b/ChangeLog index ae807c5cd8..8df66687e9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,27 @@ +2006-05-22 Alexander Larsson + + * gtk/gtkmain.c: + Make sure grab-notify is emitted on toplevels as well as + child widgets. + + * gtk/Makefile.am: + * gtk/gtkwin32embedwidget.[ch] + Add new widget used for win32 port to embed gtk+ + widgets in windows dialog. + + * gtk/gtkmarshalers.list: + Add POINTER:VOID + + * gtk/gtkprintoperation-private.h: + * gtk/gtkprintoperation.[ch]: + Generic support for custom widgets in print dialog. + + * gtk/gtkprintoperation-win32.c: + Implement custom widget support for win32. + + * tests/print-editor.c: + Allow setting of font using custom widgets in the print dialog. + 2006-05-22 Behdad Esfahbod Rollback the following changes, to fix it the proper way in Pango: diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10 index ae807c5cd8..8df66687e9 100644 --- a/ChangeLog.pre-2-10 +++ b/ChangeLog.pre-2-10 @@ -1,3 +1,27 @@ +2006-05-22 Alexander Larsson + + * gtk/gtkmain.c: + Make sure grab-notify is emitted on toplevels as well as + child widgets. + + * gtk/Makefile.am: + * gtk/gtkwin32embedwidget.[ch] + Add new widget used for win32 port to embed gtk+ + widgets in windows dialog. + + * gtk/gtkmarshalers.list: + Add POINTER:VOID + + * gtk/gtkprintoperation-private.h: + * gtk/gtkprintoperation.[ch]: + Generic support for custom widgets in print dialog. + + * gtk/gtkprintoperation-win32.c: + Implement custom widget support for win32. + + * tests/print-editor.c: + Allow setting of font using custom widgets in the print dialog. + 2006-05-22 Behdad Esfahbod Rollback the following changes, to fix it the proper way in Pango: diff --git a/gtk/Makefile.am b/gtk/Makefile.am index 77f4ada015..d04a1cf666 100644 --- a/gtk/Makefile.am +++ b/gtk/Makefile.am @@ -623,8 +623,8 @@ gtk_c_sources += \ gtktrayicon-x11.c else if USE_WIN32 -gtk_private_h_sources += gtkwin32embed.h -gtk_c_sources += gtkplug-win32.c gtksocket-win32.c gtkwin32embed.c +gtk_private_h_sources += gtkwin32embed.h gtkwin32embedwidget.h +gtk_c_sources += gtkplug-win32.c gtksocket-win32.c gtkwin32embed.c gtkwin32embedwidget.c else gtk_c_sources += gtkplug-stub.c gtksocket-stub.c endif @@ -778,7 +778,7 @@ libgtk_directfb_2_0_la_LDFLAGS = $(libtool_opts) libgtk_x11_2_0_la_LIBADD = $(libadd) libgtk_linux_fb_2_0_la_LIBADD = $(libadd) -libgtk_win32_2_0_la_LIBADD = $(libadd) -lole32 -lgdi32 -lcomdlg32 -lwinspool +libgtk_win32_2_0_la_LIBADD = $(libadd) -lole32 -lgdi32 -lcomdlg32 -lwinspool -lcomctl32 libgtk_win32_2_0_la_DEPENDENCIES = $(gtk_def) $(gtk_win32_res) libgtk_quartz_2_0_la_LIBADD = $(libadd) libgtk_directfb_2_0_la_LIBADD = $(libadd) diff --git a/gtk/gtkmain.c b/gtk/gtkmain.c index 5fcdb00c7c..a511ae7115 100644 --- a/gtk/gtkmain.c +++ b/gtk/gtkmain.c @@ -1560,8 +1560,7 @@ gtk_grab_notify (GtkWindowGroup *group, info.is_grabbed = FALSE; if (group == gtk_window_get_group (toplevel)) - gtk_container_foreach (GTK_CONTAINER (toplevel), - gtk_grab_notify_foreach, &info); + gtk_grab_notify_foreach (GTK_WIDGET (toplevel), &info); g_object_unref (toplevel); } diff --git a/gtk/gtkmarshalers.list b/gtk/gtkmarshalers.list index 7b98c4ddbe..88511709e5 100644 --- a/gtk/gtkmarshalers.list +++ b/gtk/gtkmarshalers.list @@ -52,6 +52,7 @@ NONE:INT,BOOL NONE:INT,INT NONE:NONE NONE:STRING,INT,POINTER +POINTER:VOID STRING:DOUBLE VOID:DOUBLE VOID:BOOLEAN diff --git a/gtk/gtkprintoperation-private.h b/gtk/gtkprintoperation-private.h index 333bcfcc3d..d1c6a7f812 100644 --- a/gtk/gtkprintoperation-private.h +++ b/gtk/gtkprintoperation-private.h @@ -57,7 +57,8 @@ struct _GtkPrintOperationPrivate guint manual_orientation : 1; double manual_scale; GtkPageSet manual_page_set; - + GtkWidget *custom_widget; + gpointer platform_data; GDestroyNotify free_platform_data; diff --git a/gtk/gtkprintoperation-win32.c b/gtk/gtkprintoperation-win32.c index b6392600de..bf342c6f80 100644 --- a/gtk/gtkprintoperation-win32.c +++ b/gtk/gtkprintoperation-win32.c @@ -33,7 +33,11 @@ #include "gtkprint-win32.h" #include "gtkintl.h" #include "gtkinvisible.h" +#include "gtkplug.h" +#include "gtkstock.h" #include "gtkalias.h" +#include "gtk.h" +#include "gtkwin32embedwidget.h" #define MAX_PAGE_RANGES 20 #define STATUS_POLLING_TIME 2000 @@ -53,6 +57,8 @@ typedef struct { HANDLE printerHandle; int job_id; guint timeout_id; + + GtkWidget *embed_widget; } GtkPrintOperationWin32; static void win32_poll_status (GtkPrintOperation *op); @@ -593,7 +599,6 @@ get_parent_hwnd (GtkWidget *widget) return gdk_win32_drawable_get_handle (widget->window); } - static void devnames_to_settings (GtkPrintSettings *settings, HANDLE hDevNames) @@ -1267,6 +1272,126 @@ print_callback_new (void) return &callback->iPrintDialogCallback; } +static void +plug_grab_notify (GtkWidget *widget, + gboolean was_grabbed, + GtkPrintOperation *op) +{ + EnableWindow(GetAncestor (GDK_WINDOW_HWND (widget->window), GA_ROOT), + was_grabbed); +} + + +static BOOL CALLBACK +pageDlgProc (HWND wnd, UINT message, WPARAM wparam, LPARAM lparam) +{ + GtkPrintOperation *op; + GtkPrintOperationWin32 *op_win32; + + if (message == WM_INITDIALOG) + { + PROPSHEETPAGEW *page = (PROPSHEETPAGEW *)lparam; + GtkWidget *plug; + + op = GTK_PRINT_OPERATION ((gpointer)page->lParam); + op_win32 = op->priv->platform_data; + + SetWindowLongPtrW(wnd, GWLP_USERDATA, (LONG_PTR)op); + + plug = _gtk_win32_embed_widget_new ((GdkNativeWindow) wnd); + op_win32->embed_widget = plug; + gtk_container_add (GTK_CONTAINER (plug), op->priv->custom_widget); + gtk_widget_show (op->priv->custom_widget); + gtk_widget_show (plug); + gdk_window_focus (plug->window, GDK_CURRENT_TIME); + + /* This dialog is modal, so we grab the embed widget */ + gtk_grab_add (plug); + + /* When we lose the grab we need to disable the print dialog */ + g_signal_connect (plug, "grab-notify", G_CALLBACK (plug_grab_notify), op); + return FALSE; + } + else if (message == WM_DESTROY) + { + op = GTK_PRINT_OPERATION (GetWindowLongPtrW(wnd, GWLP_USERDATA)); + op_win32 = op->priv->platform_data; + + g_signal_emit_by_name (op, "custom-widget-apply", op->priv->custom_widget); + gtk_widget_destroy (op_win32->embed_widget); + op_win32->embed_widget = NULL; + op->priv->custom_widget = NULL; + } + else + { + op = GTK_PRINT_OPERATION (GetWindowLongPtrW(wnd, GWLP_USERDATA)); + op_win32 = op->priv->platform_data; + + return _gtk_win32_embed_widget_dialog_procedure (GTK_WIN32_EMBED_WIDGET (op_win32->embed_widget), + wnd, message, wparam, lparam); + } + + return FALSE; +} + +static HPROPSHEETPAGE +create_application_page (GtkPrintOperation *op) +{ + HPROPSHEETPAGE hpage; + PROPSHEETPAGEW page; + DLGTEMPLATE *template; + HGLOBAL htemplate; + LONG base_units; + WORD baseunitX, baseunitY; + WORD *array; + GtkRequisition requisition; + const char *app_name; + + /* Make the template the size of the custom widget size request */ + gtk_widget_size_request (op->priv->custom_widget, &requisition); + + 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; + page.hInstance = GetModuleHandle (NULL); + page.pResource = template; + app_name = g_get_application_name (); + if (app_name == NULL) + app_name = "Application"; + page.pszTitle = g_utf8_to_utf16 (app_name, + -1, NULL, NULL, NULL); + page.pfnDlgProc = pageDlgProc; + page.pfnCallback = NULL; + page.lParam = (LPARAM) op; + hpage = CreatePropertySheetPageW(&page); + + GlobalUnlock (htemplate); + + /* TODO: We're leaking htemplate here... */ + + return hpage; +} + GtkPrintOperationResult _gtk_print_operation_platform_backend_run_dialog (GtkPrintOperation *op, GtkWindow *parent, @@ -1281,9 +1406,14 @@ _gtk_print_operation_platform_backend_run_dialog (GtkPrintOperation *op, GtkPrintOperationResult result; GtkPrintOperationWin32 *op_win32; IPrintDialogCallback *callback; + HPROPSHEETPAGE prop_page; *do_print = FALSE; + op_win32 = g_new0 (GtkPrintOperationWin32, 1); + op->priv->platform_data = op_win32; + op->priv->free_platform_data = (GDestroyNotify) op_win32_free; + if (parent == NULL) { invisible = gtk_invisible_new (); @@ -1338,8 +1468,18 @@ _gtk_print_operation_platform_backend_run_dialog (GtkPrintOperation *op, printdlgex->hInstance = 0; printdlgex->lpPrintTemplateName = NULL; printdlgex->lpCallback = NULL; - printdlgex->nPropertyPages = 0; - printdlgex->lphPropertyPages = NULL; + + g_signal_emit_by_name (op, "create-custom-widget", + &op->priv->custom_widget); + if (op->priv->custom_widget) { + prop_page = create_application_page (op); + printdlgex->nPropertyPages = 1; + printdlgex->lphPropertyPages = &prop_page; + } else { + printdlgex->nPropertyPages = 0; + printdlgex->lphPropertyPages = NULL; + } + printdlgex->nStartPage = START_PAGE_GENERAL; printdlgex->dwResultAction = 0; @@ -1348,7 +1488,7 @@ _gtk_print_operation_platform_backend_run_dialog (GtkPrintOperation *op, callback = print_callback_new (); printdlgex->lpCallback = (IUnknown *)callback; got_gdk_events_message = RegisterWindowMessage ("GDK_WIN32_GOT_EVENTS"); - + hResult = PrintDlgExW(printdlgex); IUnknown_Release ((IUnknown *)callback); gdk_win32_set_modal_dialog_libgtk_only (NULL); @@ -1426,9 +1566,6 @@ _gtk_print_operation_platform_backend_run_dialog (GtkPrintOperation *op, goto out; } - op_win32 = g_new (GtkPrintOperationWin32, 1); - op->priv->platform_data = op_win32; - op->priv->free_platform_data = (GDestroyNotify) op_win32_free; op_win32->hdc = printdlgex->hDC; op_win32->devmode = printdlgex->hDevMode; op_win32->devnames = printdlgex->hDevNames; diff --git a/gtk/gtkprintoperation.c b/gtk/gtkprintoperation.c index 977a72d544..2f55456036 100644 --- a/gtk/gtkprintoperation.c +++ b/gtk/gtkprintoperation.c @@ -36,6 +36,8 @@ enum { DRAW_PAGE, END_PRINT, STATUS_CHANGED, + CREATE_CUSTOM_WIDGET, + CUSTOM_WIDGET_APPLY, LAST_SIGNAL }; @@ -230,6 +232,29 @@ gtk_print_operation_get_property (GObject *object, } } +static GtkWidget * +gtk_print_operation_create_custom_widget (GtkPrintOperation *operation) +{ + return NULL; +} + +static gboolean +custom_widget_accumulator (GSignalInvocationHint *ihint, + GValue *return_accu, + const GValue *handler_return, + gpointer dummy) +{ + gboolean continue_emission; + GtkWidget *widget; + + widget = g_value_get_pointer (handler_return); + if (widget != NULL) + g_value_set_pointer (return_accu, widget); + continue_emission = (widget == NULL); + + return continue_emission; +} + static void gtk_print_operation_class_init (GtkPrintOperationClass *class) { @@ -238,6 +263,8 @@ gtk_print_operation_class_init (GtkPrintOperationClass *class) gobject_class->set_property = gtk_print_operation_set_property; gobject_class->get_property = gtk_print_operation_get_property; gobject_class->finalize = gtk_print_operation_finalize; + + class->create_custom_widget = gtk_print_operation_create_custom_widget; g_type_class_add_private (gobject_class, sizeof (GtkPrintOperationPrivate)); @@ -384,12 +411,60 @@ gtk_print_operation_class_init (GtkPrintOperationClass *class) */ signals[STATUS_CHANGED] = g_signal_new (I_("status-changed"), - G_TYPE_FROM_CLASS (class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GtkPrintOperationClass, status_changed), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); + G_TYPE_FROM_CLASS (class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GtkPrintOperationClass, status_changed), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + + /** + * GtkPrintOperation::get-custom-widget: + * @operation: the #GtkPrintOperation on which the signal was emitted + * + * Gets emitted when displaying the print dialog. If you return a + * widget in a handler for this signal it will be added to a custom + * tab in the print dialog. You typically return a container widget + * with multiple widgets in it. + * + * The print dialog owns the returned widget, and its lifetime + * isn't controlled by the app. However, the widget is guaranteed + * to stay around until the custom-widget-apply signal is emitted + * on the operation. Then you can read out any information you need + * from the widgets. + * + * Since: 2.10 + */ + signals[CREATE_CUSTOM_WIDGET] = + g_signal_new (I_("create-custom-widget"), + G_TYPE_FROM_CLASS (class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GtkPrintOperationClass, create_custom_widget), + custom_widget_accumulator, NULL, + _gtk_marshal_POINTER__VOID, + G_TYPE_POINTER, 0); + + /** + * GtkPrintOperation::custom-widget-apply: + * @operation: the #GtkPrintOperation on which the signal was emitted + * @widget: the custom widget added in create-custom-widget + * + * This signal gets emitted right before begin-print if you added + * a custom widget in the create-custom-widget handler. When you get + * this signal you should read the information from the custom widgets, + * as the widgets are not guaraneed to be around at a later time. + * + * Since: 2.10 + */ + signals[CUSTOM_WIDGET_APPLY] = + g_signal_new (I_("custom-widget-apply"), + G_TYPE_FROM_CLASS (class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GtkPrintOperationClass, custom_widget_apply), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, GTK_TYPE_WIDGET); /** * GtkPrintOperation:default-page-setup: diff --git a/gtk/gtkprintoperation.h b/gtk/gtkprintoperation.h index e60ec5bc92..58baf74561 100644 --- a/gtk/gtkprintoperation.h +++ b/gtk/gtkprintoperation.h @@ -80,6 +80,10 @@ struct _GtkPrintOperationClass void (*end_print) (GtkPrintOperation *operation, GtkPrintContext *context); void (*status_changed) (GtkPrintOperation *operation); + + GtkWidget *(*create_custom_widget) (GtkPrintOperation *operation); + void (*custom_widget_apply) (GtkPrintOperation *operation, + GtkWidget *widget); /* Padding for future expansion */ void (*_gtk_reserved1) (void); diff --git a/gtk/gtkwin32embedwidget.c b/gtk/gtkwin32embedwidget.c new file mode 100644 index 0000000000..ac43aaa917 --- /dev/null +++ b/gtk/gtkwin32embedwidget.c @@ -0,0 +1,394 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* + * Modified by the GTK+ Team and others 1997-2006. See the AUTHORS + * file for a list of people on the GTK+ Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + */ + +#include + +#include "gtkmain.h" +#include "gtkmarshalers.h" +#include "gtkwin32embedwidget.h" +#include "gtkintl.h" +#include "gtkprivate.h" + +#include "gtkalias.h" + +static void gtk_win32_embed_widget_realize (GtkWidget *widget); +static void gtk_win32_embed_widget_unrealize (GtkWidget *widget); +static void gtk_win32_embed_widget_show (GtkWidget *widget); +static void gtk_win32_embed_widget_hide (GtkWidget *widget); +static void gtk_win32_embed_widget_map (GtkWidget *widget); +static void gtk_win32_embed_widget_unmap (GtkWidget *widget); +static void gtk_win32_embed_widget_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static void gtk_win32_embed_widget_set_focus (GtkWindow *window, + GtkWidget *focus); +static gboolean gtk_win32_embed_widget_focus (GtkWidget *widget, + GtkDirectionType direction); +static void gtk_win32_embed_widget_check_resize (GtkContainer *container); + +static GtkBinClass *bin_class = NULL; + +G_DEFINE_TYPE (GtkWin32EmbedWidget, gtk_win32_embed_widget, GTK_TYPE_WINDOW) + +static void +gtk_win32_embed_widget_class_init (GtkWin32EmbedWidgetClass *class) +{ + GtkWidgetClass *widget_class = (GtkWidgetClass *)class; + GtkWindowClass *window_class = (GtkWindowClass *)class; + GtkContainerClass *container_class = (GtkContainerClass *)class; + + bin_class = g_type_class_peek (GTK_TYPE_BIN); + + widget_class->realize = gtk_win32_embed_widget_realize; + widget_class->unrealize = gtk_win32_embed_widget_unrealize; + + widget_class->show = gtk_win32_embed_widget_show; + widget_class->hide = gtk_win32_embed_widget_hide; + widget_class->map = gtk_win32_embed_widget_map; + widget_class->unmap = gtk_win32_embed_widget_unmap; + widget_class->size_allocate = gtk_win32_embed_widget_size_allocate; + + widget_class->focus = gtk_win32_embed_widget_focus; + + container_class->check_resize = gtk_win32_embed_widget_check_resize; + + window_class->set_focus = gtk_win32_embed_widget_set_focus; +} + +static void +gtk_win32_embed_widget_init (GtkWin32EmbedWidget *embed_widget) +{ + GtkWindow *window; + + window = GTK_WINDOW (embed_widget); + + window->type = GTK_WINDOW_TOPLEVEL; + + GTK_WIDGET_SET_FLAGS (embed_widget, GTK_TOPLEVEL); + gtk_container_set_resize_mode (GTK_CONTAINER (embed_widget), GTK_RESIZE_QUEUE); +} + +GtkWidget* +_gtk_win32_embed_widget_new (GdkNativeWindow parent_id) +{ + GtkWin32EmbedWidget *embed_widget; + + embed_widget = g_object_new (GTK_TYPE_WIN32_EMBED_WIDGET, NULL); + + embed_widget->parent_window = + gdk_window_lookup_for_display (gdk_display_get_default (), + parent_id); + + if (!embed_widget->parent_window) + embed_widget->parent_window = + gdk_window_foreign_new_for_display (gdk_display_get_default (), + parent_id); + + return GTK_WIDGET (embed_widget); +} + +BOOL +_gtk_win32_embed_widget_dialog_procedure (GtkWin32EmbedWidget *embed_widget, + HWND wnd, UINT message, WPARAM wparam, LPARAM lparam) +{ + GtkWidget *widget = GTK_WIDGET (embed_widget); + + if (message == WM_SIZE) + { + widget->allocation.width = LOWORD(lparam); + widget->allocation.height = HIWORD(lparam); + + gtk_widget_queue_resize (widget); + } + + return 0; +} + +static void +gtk_win32_embed_widget_unrealize (GtkWidget *widget) +{ + GtkWin32EmbedWidget *embed_widget; + + g_return_if_fail (GTK_IS_WIN32_EMBED_WIDGET (widget)); + + embed_widget = GTK_WIN32_EMBED_WIDGET (widget); + + embed_widget->old_window_procedure = NULL; + + if (embed_widget->parent_window != NULL) + { + gdk_window_set_user_data (embed_widget->parent_window, NULL); + g_object_unref (embed_widget->parent_window); + embed_widget->parent_window = NULL; + } + + if (GTK_WIDGET_CLASS (gtk_win32_embed_widget_parent_class)->unrealize) + (* GTK_WIDGET_CLASS (gtk_win32_embed_widget_parent_class)->unrealize) (widget); +} + +static LRESULT CALLBACK +gtk_win32_embed_widget_window_process (HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) +{ + GdkWindow *window; + GtkWin32EmbedWidget *embed_widget; + gpointer user_data; + + window = gdk_window_lookup ((GdkNativeWindow)hwnd); + if (window == NULL) { + g_warning ("No such window!"); + return 0; + } + gdk_window_get_user_data (window, &user_data); + embed_widget = GTK_WIN32_EMBED_WIDGET (user_data); + + if (msg == WM_GETDLGCODE) { + return DLGC_WANTALLKEYS; + } + + if (embed_widget && embed_widget->old_window_procedure) + return CallWindowProc(embed_widget->old_window_procedure, + hwnd, msg, wparam, lparam); + else + return 0; +} + +static void +gtk_win32_embed_widget_realize (GtkWidget *widget) +{ + GtkWindow *window; + GtkWin32EmbedWidget *embed_widget; + GdkWindowAttr attributes; + gint attributes_mask; + LONG_PTR styles; + + g_return_if_fail (GTK_IS_WIN32_EMBED_WIDGET (widget)); + + window = GTK_WINDOW (widget); + embed_widget = GTK_WIN32_EMBED_WIDGET (widget); + + /* ensure widget tree is properly size allocated */ + if (widget->allocation.x == -1 && + widget->allocation.y == -1 && + widget->allocation.width == 1 && + widget->allocation.height == 1) + { + GtkRequisition requisition; + GtkAllocation allocation = { 0, 0, 200, 200 }; + + gtk_widget_size_request (widget, &requisition); + if (requisition.width || requisition.height) + { + /* non-empty window */ + allocation.width = requisition.width; + allocation.height = requisition.height; + } + gtk_widget_size_allocate (widget, &allocation); + + _gtk_container_queue_resize (GTK_CONTAINER (widget)); + + g_return_if_fail (!GTK_WIDGET_REALIZED (widget)); + } + + GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); + + attributes.window_type = GDK_WINDOW_CHILD; + attributes.title = window->title; + attributes.wmclass_name = window->wmclass_name; + attributes.wmclass_class = window->wmclass_class; + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; + attributes.wclass = GDK_INPUT_OUTPUT; + + /* this isn't right - we should match our parent's visual/colormap. + * though that will require handling "foreign" colormaps */ + attributes.visual = gtk_widget_get_visual (widget); + attributes.colormap = gtk_widget_get_colormap (widget); + attributes.event_mask = gtk_widget_get_events (widget); + attributes.event_mask |= (GDK_EXPOSURE_MASK | + GDK_KEY_PRESS_MASK | + GDK_KEY_RELEASE_MASK | + GDK_ENTER_NOTIFY_MASK | + GDK_LEAVE_NOTIFY_MASK | + GDK_STRUCTURE_MASK | + GDK_FOCUS_CHANGE_MASK); + + attributes_mask = GDK_WA_VISUAL | GDK_WA_COLORMAP; + attributes_mask |= (window->title ? GDK_WA_TITLE : 0); + attributes_mask |= (window->wmclass_name ? GDK_WA_WMCLASS : 0); + + widget->window = gdk_window_new (embed_widget->parent_window, + &attributes, attributes_mask); + + gdk_window_set_user_data (widget->window, window); + + embed_widget->old_window_procedure = (gpointer) + SetWindowLongPtrW(GDK_WINDOW_HWND (widget->window), + GWLP_WNDPROC, + (LONG_PTR)gtk_win32_embed_widget_window_process); + + /* Enable tab to focus the widget */ + styles = GetWindowLongPtr(GDK_WINDOW_HWND (widget->window), GWL_STYLE); + SetWindowLongPtrW(GDK_WINDOW_HWND (widget->window), GWL_STYLE, styles | WS_TABSTOP); + + widget->style = gtk_style_attach (widget->style, widget->window); + gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL); +} + +static void +gtk_win32_embed_widget_show (GtkWidget *widget) +{ + GTK_WIDGET_SET_FLAGS (widget, GTK_VISIBLE); + + gtk_widget_realize (widget); + gtk_container_check_resize (GTK_CONTAINER (widget)); + gtk_widget_map (widget); +} + +static void +gtk_win32_embed_widget_hide (GtkWidget *widget) +{ + GTK_WIDGET_UNSET_FLAGS (widget, GTK_VISIBLE); + gtk_widget_unmap (widget); +} + +static void +gtk_win32_embed_widget_map (GtkWidget *widget) +{ + GtkBin *bin = GTK_BIN (widget); + + GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED); + + if (bin->child && + GTK_WIDGET_VISIBLE (bin->child) && + !GTK_WIDGET_MAPPED (bin->child)) + gtk_widget_map (bin->child); + + gdk_window_show (widget->window); +} + +static void +gtk_win32_embed_widget_unmap (GtkWidget *widget) +{ + GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED); + gdk_window_hide (widget->window); +} + +static void +gtk_win32_embed_widget_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkBin *bin = GTK_BIN (widget); + + widget->allocation = *allocation; + + if (GTK_WIDGET_REALIZED (widget)) + gdk_window_move_resize (widget->window, + allocation->x, allocation->y, + allocation->width, allocation->height); + + if (bin->child && GTK_WIDGET_VISIBLE (bin->child)) + { + GtkAllocation child_allocation; + + child_allocation.x = child_allocation.y = GTK_CONTAINER (widget)->border_width; + child_allocation.width = + MAX (1, (gint)allocation->width - child_allocation.x * 2); + child_allocation.height = + MAX (1, (gint)allocation->height - child_allocation.y * 2); + + gtk_widget_size_allocate (bin->child, &child_allocation); + } +} + +static void +gtk_win32_embed_widget_check_resize (GtkContainer *container) +{ + GTK_CONTAINER_CLASS (bin_class)->check_resize (container); +} + +static gboolean +gtk_win32_embed_widget_focus (GtkWidget *widget, + GtkDirectionType direction) +{ + GtkBin *bin = GTK_BIN (widget); + GtkWin32EmbedWidget *embed_widget = GTK_WIN32_EMBED_WIDGET (widget); + GtkWindow *window = GTK_WINDOW (widget); + GtkContainer *container = GTK_CONTAINER (widget); + GtkWidget *old_focus_child = container->focus_child; + GtkWidget *parent; + + /* We override GtkWindow's behavior, since we don't want wrapping here. + */ + if (old_focus_child) + { + if (gtk_widget_child_focus (old_focus_child, direction)) + return TRUE; + + if (window->focus_widget) + { + /* Wrapped off the end, clear the focus setting for the toplevel */ + parent = window->focus_widget->parent; + while (parent) + { + gtk_container_set_focus_child (GTK_CONTAINER (parent), NULL); + parent = GTK_WIDGET (parent)->parent; + } + + gtk_window_set_focus (GTK_WINDOW (container), NULL); + } + } + else + { + /* Try to focus the first widget in the window */ + if (bin->child && gtk_widget_child_focus (bin->child, direction)) + return TRUE; + } + + if (!GTK_CONTAINER (window)->focus_child) + { + int backwards = FALSE; + + if (direction == GTK_DIR_TAB_BACKWARD || + direction == GTK_DIR_LEFT) + backwards = TRUE; + + PostMessage(GDK_WINDOW_HWND (embed_widget->parent_window), + WM_NEXTDLGCTL, + backwards, 0); + } + + return FALSE; +} + +static void +gtk_win32_embed_widget_set_focus (GtkWindow *window, + GtkWidget *focus) +{ + GTK_WINDOW_CLASS (gtk_win32_embed_widget_parent_class)->set_focus (window, focus); + + gdk_window_focus (GTK_WIDGET(window)->window, 0); +} + +#define __GTK_WIN32_EMBED_WIDGET_C__ +#include "gtkaliasdef.c" diff --git a/gtk/gtkwin32embedwidget.h b/gtk/gtkwin32embedwidget.h new file mode 100644 index 0000000000..87d6d233e2 --- /dev/null +++ b/gtk/gtkwin32embedwidget.h @@ -0,0 +1,75 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* + * Modified by the GTK+ Team and others 1997-2006. See the AUTHORS + * file for a list of people on the GTK+ Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + */ + +#ifndef __GTK_WIN32_EMBED_WIDGET_H__ +#define __GTK_WIN32_EMBED_WIDGET_H__ + +#include +#include +#include "win32/gdkwin32.h" + +G_BEGIN_DECLS + +#define GTK_TYPE_WIN32_EMBED_WIDGET (gtk_win32_embed_widget_get_type ()) +#define GTK_WIN32_EMBED_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_WIN32_EMBED_WIDGET, GtkWin32EmbedWidget)) +#define GTK_WIN32_EMBED_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_WIN32_EMBED_WIDGET, GtkWin32EmbedWidgetClass)) +#define GTK_IS_WIN32_EMBED_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_WIN32_EMBED_WIDGET)) +#define GTK_IS_WIN32_EMBED_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_WIN32_EMBED_WIDGET)) +#define GTK_WIN32_EMBED_WIDGET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_WIN32_EMBED_WIDGET, GtkWin32EmbedWidgetClass)) + + +typedef struct _GtkWin32EmbedWidget GtkWin32EmbedWidget; +typedef struct _GtkWin32EmbedWidgetClass GtkWin32EmbedWidgetClass; + + +struct _GtkWin32EmbedWidget +{ + GtkWindow window; + + GdkWindow *parent_window; + gpointer old_window_procedure; +}; + +struct _GtkWin32EmbedWidgetClass +{ + GtkWindowClass parent_class; + + /* Padding for future expansion */ + void (*_gtk_reserved1) (void); + void (*_gtk_reserved2) (void); + void (*_gtk_reserved3) (void); + void (*_gtk_reserved4) (void); +}; + + +GType gtk_win32_embed_widget_get_type (void) G_GNUC_CONST; +GtkWidget* _gtk_win32_embed_widget_new (GdkNativeWindow parent_id); +BOOL _gtk_win32_embed_widget_dialog_procedure (GtkWin32EmbedWidget *embed_widget, + HWND wnd, UINT message, WPARAM wparam, LPARAM lparam); + + +G_END_DECLS + +#endif /* __GTK_WIN32_EMBED_WIDGET_H__ */ diff --git a/tests/print-editor.c b/tests/print-editor.c index f3a4b0e419..8775b1079b 100644 --- a/tests/print-editor.c +++ b/tests/print-editor.c @@ -245,6 +245,8 @@ typedef struct { char *text; PangoLayout *layout; GList *page_breaks; + GtkWidget *font_button; + char *font; } PrintData; static void @@ -265,7 +267,7 @@ begin_print (GtkPrintOperation *operation, print_data->layout = gtk_print_context_create_layout (context); - desc = pango_font_description_from_string ("Sans 12"); + desc = pango_font_description_from_string (print_data->font); pango_layout_set_font_description (print_data->layout, desc); pango_font_description_free (desc); @@ -391,6 +393,42 @@ status_changed_cb (GtkPrintOperation *op, update_statusbar (); } +static GtkWidget * +create_custom_widget (GtkPrintOperation *operation, + PrintData *data) +{ + GtkWidget *vbox, *hbox, *font, *label; + + vbox = gtk_vbox_new (FALSE, 0); + gtk_container_set_border_width (GTK_CONTAINER (vbox), 12); + + hbox = gtk_hbox_new (FALSE, 8); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); + gtk_widget_show (hbox); + + label = gtk_label_new ("Font:"); + gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); + gtk_widget_show (label); + + font = gtk_font_button_new_with_font (data->font); + gtk_box_pack_start (GTK_BOX (hbox), font, FALSE, FALSE, 0); + gtk_widget_show (font); + data->font_button = font; + + return vbox; +} + +static void +custom_widget_apply (GtkPrintOperation *operation, + GtkWidget *widget, + PrintData *data) +{ + const char *selected_font; + selected_font = gtk_font_button_get_font_name (GTK_FONT_BUTTON (data->font_button)); + g_free (data->font); + data->font = g_strdup (selected_font); +} + static void do_print (GtkAction *action) { @@ -401,6 +439,7 @@ do_print (GtkAction *action) GError *error; print_data.text = get_text (); + print_data.font = g_strdup ("Sans 12"); print = gtk_print_operation_new (); @@ -414,7 +453,9 @@ do_print (GtkAction *action) g_signal_connect (print, "begin_print", G_CALLBACK (begin_print), &print_data); g_signal_connect (print, "draw_page", G_CALLBACK (draw_page), &print_data); - + g_signal_connect (print, "create_custom_widget", G_CALLBACK (create_custom_widget), &print_data); + g_signal_connect (print, "custom_widget_apply", G_CALLBACK (custom_widget_apply), &print_data); + error = NULL; res = gtk_print_operation_run (print, GTK_WINDOW (main_window), &error); @@ -447,8 +488,10 @@ do_print (GtkAction *action) g_signal_connect (print, "status_changed", G_CALLBACK (status_changed_cb), NULL); } - + g_object_unref (print); + g_free (print_data.text); + g_free (print_data.font); } static void @@ -671,6 +714,7 @@ create_window (void) int main (int argc, char **argv) { + g_set_application_name ("Print editor"); gtk_init (&argc, &argv); create_window ();