summaryrefslogtreecommitdiff
path: root/gtk
diff options
context:
space:
mode:
authorAlexander Larsson <alexl@redhat.com>2006-05-22 17:19:10 +0000
committerAlexander Larsson <alexl@src.gnome.org>2006-05-22 17:19:10 +0000
commitd2cb6c6eb21a1aa341c9555d5950a1b1da66a05a (patch)
treed3662d2f49fa74394e54fae3b1596ee26a2ca658 /gtk
parentfb3eeb868689df25cc8fa56ed8471f1b880bb1c1 (diff)
downloadgtk+-d2cb6c6eb21a1aa341c9555d5950a1b1da66a05a.tar.gz
Make sure grab-notify is emitted on toplevels as well as child widgets.
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.
Diffstat (limited to 'gtk')
-rw-r--r--gtk/Makefile.am6
-rw-r--r--gtk/gtkmain.c3
-rw-r--r--gtk/gtkmarshalers.list1
-rw-r--r--gtk/gtkprintoperation-private.h3
-rw-r--r--gtk/gtkprintoperation-win32.c151
-rw-r--r--gtk/gtkprintoperation.c87
-rw-r--r--gtk/gtkprintoperation.h4
-rw-r--r--gtk/gtkwin32embedwidget.c394
-rw-r--r--gtk/gtkwin32embedwidget.h75
9 files changed, 705 insertions, 19 deletions
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 <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
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 <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__ */