]> Pileus Git - ~andy/gtk/blob - gtk/gtkwin32embedwidget.c
945bd841633d5bf2e3a063238189edf54a58397e
[~andy/gtk] / gtk / gtkwin32embedwidget.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free
16  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18
19 /*
20  * Modified by the GTK+ Team and others 1997-2006.  See the AUTHORS
21  * file for a list of people on the GTK+ Team.  See the ChangeLog
22  * files for a list of changes.  These files are distributed with
23  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
24  */
25
26 #include "config.h"
27
28 #include "gtkmain.h"
29 #include "gtkmarshalers.h"
30 #include "gtksizerequest.h"
31 #include "gtkwin32embedwidget.h"
32 #include "gtkintl.h"
33 #include "gtkprivate.h"
34 #include "gtkwindowprivate.h"
35 #include "gtkwidgetprivate.h"
36 #include "gtkcontainerprivate.h"
37
38
39 static void            gtk_win32_embed_widget_realize               (GtkWidget        *widget);
40 static void            gtk_win32_embed_widget_unrealize             (GtkWidget        *widget);
41 static void            gtk_win32_embed_widget_show                  (GtkWidget        *widget);
42 static void            gtk_win32_embed_widget_hide                  (GtkWidget        *widget);
43 static void            gtk_win32_embed_widget_map                   (GtkWidget        *widget);
44 static void            gtk_win32_embed_widget_unmap                 (GtkWidget        *widget);
45 static void            gtk_win32_embed_widget_size_allocate         (GtkWidget        *widget,
46                                                                      GtkAllocation    *allocation);
47 static void            gtk_win32_embed_widget_set_focus             (GtkWindow        *window,
48                                                                      GtkWidget        *focus);
49 static gboolean        gtk_win32_embed_widget_focus                 (GtkWidget        *widget,
50                                                                      GtkDirectionType  direction);
51 static void            gtk_win32_embed_widget_check_resize          (GtkContainer     *container);
52
53 static GtkBinClass *bin_class = NULL;
54
55 G_DEFINE_TYPE (GtkWin32EmbedWidget, gtk_win32_embed_widget, GTK_TYPE_WINDOW)
56
57 static void
58 gtk_win32_embed_widget_class_init (GtkWin32EmbedWidgetClass *class)
59 {
60   GtkWidgetClass *widget_class = (GtkWidgetClass *)class;
61   GtkWindowClass *window_class = (GtkWindowClass *)class;
62   GtkContainerClass *container_class = (GtkContainerClass *)class;
63
64   bin_class = g_type_class_peek (GTK_TYPE_BIN);
65
66   widget_class->realize = gtk_win32_embed_widget_realize;
67   widget_class->unrealize = gtk_win32_embed_widget_unrealize;
68
69   widget_class->show = gtk_win32_embed_widget_show;
70   widget_class->hide = gtk_win32_embed_widget_hide;
71   widget_class->map = gtk_win32_embed_widget_map;
72   widget_class->unmap = gtk_win32_embed_widget_unmap;
73   widget_class->size_allocate = gtk_win32_embed_widget_size_allocate;
74
75   widget_class->focus = gtk_win32_embed_widget_focus;
76   
77   container_class->check_resize = gtk_win32_embed_widget_check_resize;
78
79   window_class->set_focus = gtk_win32_embed_widget_set_focus;
80 }
81
82 static void
83 gtk_win32_embed_widget_init (GtkWin32EmbedWidget *embed_widget)
84 {
85   GtkWindow *window;
86
87   window = GTK_WINDOW (embed_widget);
88
89   _gtk_widget_set_is_toplevel (GTK_WIDGET (embed_widget), TRUE);
90   gtk_container_set_resize_mode (GTK_CONTAINER (embed_widget), GTK_RESIZE_QUEUE);
91 }
92
93 GtkWidget*
94 _gtk_win32_embed_widget_new (HWND parent)
95 {
96   GtkWin32EmbedWidget *embed_widget;
97
98   embed_widget = g_object_new (GTK_TYPE_WIN32_EMBED_WIDGET, NULL);
99   
100   embed_widget->parent_window =
101     gdk_win32_window_lookup_for_display (gdk_display_get_default (),
102                                          parent);
103   
104   if (!embed_widget->parent_window)
105     embed_widget->parent_window =
106       gdk_win32_window_foreign_new_for_display (gdk_display_get_default (),
107                                           parent);
108   
109   return GTK_WIDGET (embed_widget);
110 }
111
112 BOOL
113 _gtk_win32_embed_widget_dialog_procedure (GtkWin32EmbedWidget *embed_widget,
114                                           HWND wnd, UINT message, WPARAM wparam, LPARAM lparam)
115 {
116   GtkAllocation allocation;
117   GtkWidget *widget = GTK_WIDGET (embed_widget);
118   
119  if (message == WM_SIZE)
120    {
121      allocation.width = LOWORD(lparam);
122      allocation.height = HIWORD(lparam);
123      gtk_widget_set_allocation (widget, &allocation);
124
125      gtk_widget_queue_resize (widget);
126    }
127         
128  return 0;
129 }
130
131 static void
132 gtk_win32_embed_widget_unrealize (GtkWidget *widget)
133 {
134   GtkWin32EmbedWidget *embed_widget = GTK_WIN32_EMBED_WIDGET (widget);
135
136   embed_widget->old_window_procedure = NULL;
137   
138   if (embed_widget->parent_window != NULL)
139     {
140       gdk_window_set_user_data (embed_widget->parent_window, NULL);
141       g_object_unref (embed_widget->parent_window);
142       embed_widget->parent_window = NULL;
143     }
144
145   GTK_WIDGET_CLASS (gtk_win32_embed_widget_parent_class)->unrealize (widget);
146 }
147
148 static LRESULT CALLBACK
149 gtk_win32_embed_widget_window_process (HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
150 {
151   GdkWindow *window;
152   GtkWin32EmbedWidget *embed_widget;
153   gpointer user_data;
154
155   window = gdk_win32_window_lookup_for_display (gdk_display_get_default (), hwnd);
156   if (window == NULL) {
157     g_warning ("No such window!");
158     return 0;
159   }
160   gdk_window_get_user_data (window, &user_data);
161   embed_widget = GTK_WIN32_EMBED_WIDGET (user_data);
162
163   if (msg == WM_GETDLGCODE) {
164     return DLGC_WANTALLKEYS;
165   }
166
167   if (embed_widget && embed_widget->old_window_procedure)
168     return CallWindowProc(embed_widget->old_window_procedure,
169                           hwnd, msg, wparam, lparam);
170   else
171     return 0;
172 }
173
174 static void
175 gtk_win32_embed_widget_realize (GtkWidget *widget)
176 {
177   GtkWindow *window = GTK_WINDOW (widget);
178   GtkWin32EmbedWidget *embed_widget = GTK_WIN32_EMBED_WIDGET (widget);
179   GtkAllocation allocation;
180   GdkWindow *gdk_window;
181   GdkWindowAttr attributes;
182   gint attributes_mask;
183   LONG_PTR styles;
184
185   gtk_widget_get_allocation (widget, &allocation);
186
187   /* ensure widget tree is properly size allocated */
188   if (allocation.x == -1 && allocation.y == -1 &&
189       allocation.width == 1 && allocation.height == 1)
190     {
191       GtkRequisition requisition;
192       GtkAllocation allocation = { 0, 0, 200, 200 };
193
194       gtk_widget_get_preferred_size (widget, &requisition, NULL);
195       if (requisition.width || requisition.height)
196         {
197           /* non-empty window */
198           allocation.width = requisition.width;
199           allocation.height = requisition.height;
200         }
201       gtk_widget_size_allocate (widget, &allocation);
202       
203       _gtk_container_queue_resize (GTK_CONTAINER (widget));
204
205       g_return_if_fail (!gtk_widget_get_realized (widget));
206     }
207
208   gtk_widget_set_realized (widget, TRUE);
209
210   gtk_widget_get_allocation (widget, &allocation);
211
212   attributes.window_type = GDK_WINDOW_CHILD;
213   attributes.title = gtk_window_get_title (window);
214   _gtk_window_get_wmclass (window, &attributes.wmclass_name, &attributes.wmclass_class);
215   attributes.width = allocation.width;
216   attributes.height = allocation.height;
217   attributes.wclass = GDK_INPUT_OUTPUT;
218
219   /* this isn't right - we should match our parent's visual/colormap.
220    * though that will require handling "foreign" colormaps */
221   attributes.visual = gtk_widget_get_visual (widget);
222   attributes.event_mask = gtk_widget_get_events (widget);
223   attributes.event_mask |= (GDK_EXPOSURE_MASK |
224                             GDK_KEY_PRESS_MASK |
225                             GDK_KEY_RELEASE_MASK |
226                             GDK_ENTER_NOTIFY_MASK |
227                             GDK_LEAVE_NOTIFY_MASK |
228                             GDK_STRUCTURE_MASK |
229                             GDK_FOCUS_CHANGE_MASK);
230
231   attributes_mask = GDK_WA_VISUAL;
232   attributes_mask |= (gtk_window_get_title (window) ? GDK_WA_TITLE : 0);
233   attributes_mask |= (attributes.wmclass_name ? GDK_WA_WMCLASS : 0);
234
235   gdk_window = gdk_window_new (embed_widget->parent_window,
236                                &attributes, attributes_mask);
237   gtk_widget_set_window (widget, gdk_window);
238   gdk_window_set_user_data (gdk_window, window);
239
240   embed_widget->old_window_procedure = (gpointer)
241     SetWindowLongPtrW(GDK_WINDOW_HWND (gdk_window),
242                       GWLP_WNDPROC,
243                       (LONG_PTR)gtk_win32_embed_widget_window_process);
244
245   /* Enable tab to focus the widget */
246   styles = GetWindowLongPtr(GDK_WINDOW_HWND (gdk_window), GWL_STYLE);
247   SetWindowLongPtrW(GDK_WINDOW_HWND (gdk_window), GWL_STYLE, styles | WS_TABSTOP);
248
249   gtk_style_context_set_background (gtk_widget_get_style_context (widget),
250                                     gdk_window);
251 }
252
253 static void
254 gtk_win32_embed_widget_show (GtkWidget *widget)
255 {
256   gtk_widget_set_visible (widget, TRUE);
257   
258   gtk_widget_realize (widget);
259   gtk_container_check_resize (GTK_CONTAINER (widget));
260   gtk_widget_map (widget);
261 }
262
263 static void
264 gtk_win32_embed_widget_hide (GtkWidget *widget)
265 {
266   gtk_widget_set_visible (widget, FALSE);
267   gtk_widget_unmap (widget);
268 }
269
270 static void
271 gtk_win32_embed_widget_map (GtkWidget *widget)
272 {
273   GtkBin    *bin = GTK_BIN (widget);
274   GtkWidget *child;
275
276   gtk_widget_set_mapped (widget, TRUE);
277
278   child = gtk_bin_get_child (bin);
279   if (child &&
280       gtk_widget_get_visible (child) &&
281       !gtk_widget_get_mapped (child))
282     gtk_widget_map (child);
283
284   gdk_window_show (gtk_widget_get_window (widget));
285 }
286
287 static void
288 gtk_win32_embed_widget_unmap (GtkWidget *widget)
289 {
290   gtk_widget_set_mapped (widget, FALSE);
291   gdk_window_hide (gtk_widget_get_window (widget));
292 }
293
294 static void
295 gtk_win32_embed_widget_size_allocate (GtkWidget     *widget,
296                                       GtkAllocation *allocation)
297 {
298   GtkBin    *bin = GTK_BIN (widget);
299   GtkWidget *child;
300   
301   gtk_widget_set_allocation (widget, allocation);
302   
303   if (gtk_widget_get_realized (widget))
304     gdk_window_move_resize (gtk_widget_get_window (widget),
305                             allocation->x, allocation->y,
306                             allocation->width, allocation->height);
307
308   child = gtk_bin_get_child (bin);
309   if (child && gtk_widget_get_visible (child))
310     {
311       GtkAllocation child_allocation;
312       
313       child_allocation.x = gtk_container_get_border_width (GTK_CONTAINER (widget));
314       child_allocation.y = child_allocation.x;
315       child_allocation.width =
316         MAX (1, (gint)allocation->width - child_allocation.x * 2);
317       child_allocation.height =
318         MAX (1, (gint)allocation->height - child_allocation.y * 2);
319       
320       gtk_widget_size_allocate (child, &child_allocation);
321     }
322 }
323
324 static void
325 gtk_win32_embed_widget_check_resize (GtkContainer *container)
326 {
327   GTK_CONTAINER_CLASS (bin_class)->check_resize (container);
328 }
329
330 static gboolean
331 gtk_win32_embed_widget_focus (GtkWidget        *widget,
332                               GtkDirectionType  direction)
333 {
334   GtkBin *bin = GTK_BIN (widget);
335   GtkWin32EmbedWidget *embed_widget = GTK_WIN32_EMBED_WIDGET (widget);
336   GtkWindow *window = GTK_WINDOW (widget);
337   GtkContainer *container = GTK_CONTAINER (widget);
338   GtkWidget *old_focus_child = gtk_container_get_focus_child (container);
339   GtkWidget *parent;
340   GtkWidget *child;
341
342   /* We override GtkWindow's behavior, since we don't want wrapping here.
343    */
344   if (old_focus_child)
345     {
346       if (gtk_widget_child_focus (old_focus_child, direction))
347         return TRUE;
348
349       if (gtk_window_get_focus (window))
350         {
351           /* Wrapped off the end, clear the focus setting for the toplevel */
352           parent = gtk_widget_get_parent (gtk_window_get_focus (window));
353           while (parent)
354             {
355               gtk_container_set_focus_child (GTK_CONTAINER (parent), NULL);
356               parent = gtk_widget_get_parent (GTK_WIDGET (parent));
357             }
358           
359           gtk_window_set_focus (GTK_WINDOW (container), NULL);
360         }
361     }
362   else
363     {
364       /* Try to focus the first widget in the window */
365       child = gtk_bin_get_child (bin);
366       if (child && gtk_widget_child_focus (child, direction))
367         return TRUE;
368     }
369
370   if (!gtk_container_get_focus_child (GTK_CONTAINER (window)))
371     {
372       int backwards = FALSE;
373
374       if (direction == GTK_DIR_TAB_BACKWARD ||
375           direction == GTK_DIR_LEFT)
376         backwards = TRUE;
377       
378       PostMessage(GDK_WINDOW_HWND (embed_widget->parent_window),
379                                    WM_NEXTDLGCTL,
380                                    backwards, 0);
381     }
382
383   return FALSE;
384 }
385
386 static void
387 gtk_win32_embed_widget_set_focus (GtkWindow *window,
388                                   GtkWidget *focus)
389 {
390   GTK_WINDOW_CLASS (gtk_win32_embed_widget_parent_class)->set_focus (window, focus);
391
392   gdk_window_focus (gtk_widget_get_window (GTK_WIDGET(window)), 0);
393 }