]> Pileus Git - ~andy/gtk/commitdiff
Make sure grab-notify is emitted on toplevels as well as child widgets.
authorAlexander Larsson <alexl@redhat.com>
Mon, 22 May 2006 17:19:10 +0000 (17:19 +0000)
committerAlexander Larsson <alexl@src.gnome.org>
Mon, 22 May 2006 17:19:10 +0000 (17:19 +0000)
2006-05-22  Alexander Larsson  <alexl@redhat.com>

* 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.

12 files changed:
ChangeLog
ChangeLog.pre-2-10
gtk/Makefile.am
gtk/gtkmain.c
gtk/gtkmarshalers.list
gtk/gtkprintoperation-private.h
gtk/gtkprintoperation-win32.c
gtk/gtkprintoperation.c
gtk/gtkprintoperation.h
gtk/gtkwin32embedwidget.c [new file with mode: 0644]
gtk/gtkwin32embedwidget.h [new file with mode: 0644]
tests/print-editor.c

index ae807c5cd85470400315975efc4f965e24314018..8df66687e9b5cbb393e55028b515a7bc63a3bf18 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,27 @@
+2006-05-22  Alexander Larsson  <alexl@redhat.com>
+
+       * 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  <behdad@gnome.org>
 
        Rollback the following changes, to fix it the proper way in Pango:
index ae807c5cd85470400315975efc4f965e24314018..8df66687e9b5cbb393e55028b515a7bc63a3bf18 100644 (file)
@@ -1,3 +1,27 @@
+2006-05-22  Alexander Larsson  <alexl@redhat.com>
+
+       * 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  <behdad@gnome.org>
 
        Rollback the following changes, to fix it the proper way in Pango:
index 77f4ada0157b70accea7ef5da0540a83f03f8fe5..d04a1cf666a832a0887560d7f1858599ec8a44eb 100644 (file)
@@ -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)
index 5fcdb00c7cbf987dfbc396f8aada88a511c06a04..a511ae71154bd8d65402bb39b2518c56e9b177f3 100644 (file)
@@ -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);
     }
 
index 7b98c4ddbecdcbcb41dbe566b7c548e03e935f48..88511709e56dc87bd4694cba269477eb7cb38e9b 100644 (file)
@@ -52,6 +52,7 @@ NONE:INT,BOOL
 NONE:INT,INT
 NONE:NONE
 NONE:STRING,INT,POINTER
+POINTER:VOID
 STRING:DOUBLE
 VOID:DOUBLE
 VOID:BOOLEAN
index 333bcfcc3d7b76b2abe657c3e7956696a7d9ee2a..d1c6a7f81280d343e235944d210a1d1f2e11e35f 100644 (file)
@@ -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;
 
index b6392600de70f422fd1bd611a5580a7a38026911..bf342c6f80ec662f827b7da58cb13d952f07dc5e 100644 (file)
 #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;
index 977a72d5449c3b1f87fd8fde858187eb0c5d21a3..2f55456036ad341ccdfbc4b51e513186cd7aebfe 100644 (file)
@@ -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:
index e60ec5bc92cb8c410899dc011e7f8e98604d649a..58baf745612c15c6e9b3807893d85c137bd17952 100644 (file)
@@ -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 (file)
index 0000000..ac43aaa
--- /dev/null
@@ -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 <config.h>
+
+#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 (file)
index 0000000..87d6d23
--- /dev/null
@@ -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 <gdk/gdk.h>
+#include <gtk/gtkwindow.h>
+#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__ */
index f3a4b0e41977bd4bc9d63f6b9bada5912036d6ec..8775b1079b166afc93c3580bbfa51054bf2de455 100644 (file)
@@ -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 ();