]> Pileus Git - ~andy/gtk/blob - gtk/gtkplug-win32.c
Revert name change
[~andy/gtk] / gtk / gtkplug-win32.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  * Copyright (C) 2005 Novell, Inc.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free
17  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  */
19
20 /* By Tor Lillqvist <tml@novell.com> 2005 */
21
22 /*
23  * Modified by the GTK+ Team and others 1997-2005.  See the AUTHORS
24  * file for a list of people on the GTK+ Team.  See the ChangeLog
25  * files for a list of changes.  These files are distributed with
26  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
27  */
28
29 #include "gtkmarshalers.h"
30 #include "gtkplug.h"
31 #include "gtkplugprivate.h"
32
33 #include "win32/gdkwin32.h"
34
35 #include "gtkwin32embed.h"
36 #include "gtkalias.h"
37
38 #if defined(_MSC_VER) && (WINVER < 0x0500)
39 #ifndef GA_PARENT
40 #define GA_PARENT 1
41 #endif
42 WINUSERAPI HWND WINAPI GetAncestor(HWND,UINT);
43 #endif
44
45 GdkNativeWindow
46 _gtk_plug_windowing_get_id (GtkPlug *plug)
47 {
48   return (GdkNativeWindow) GDK_WINDOW_HWND (GTK_WIDGET (plug)->window);
49 }
50
51 void
52 _gtk_plug_windowing_realize_toplevel (GtkPlug *plug)
53 {
54   if (plug->socket_window)
55     {
56       _gtk_win32_embed_send (plug->socket_window,
57                              GTK_WIN32_EMBED_PARENT_NOTIFY,
58                              (int) GDK_WINDOW_HWND (GTK_WIDGET (plug)->window),
59                              GTK_WIN32_EMBED_PROTOCOL_VERSION);
60       _gtk_win32_embed_send (plug->socket_window,
61                              GTK_WIN32_EMBED_EVENT_PLUG_MAPPED, 0, 0);
62     }
63 }
64
65 void
66 _gtk_plug_windowing_map_toplevel (GtkPlug *plug)
67 {
68   if (plug->socket_window)
69     _gtk_win32_embed_send (plug->socket_window,
70                            GTK_WIN32_EMBED_EVENT_PLUG_MAPPED,
71                            1, 0);
72 }
73
74 void
75 _gtk_plug_windowing_unmap_toplevel (GtkPlug *plug)
76 {
77   if (plug->socket_window)
78     _gtk_win32_embed_send (plug->socket_window,
79                            GTK_WIN32_EMBED_EVENT_PLUG_MAPPED,
80                            0, 0);
81 }
82
83 void
84 _gtk_plug_windowing_set_focus (GtkPlug *plug)
85 {
86   if (plug->socket_window)
87     _gtk_win32_embed_send (plug->socket_window,
88                            GTK_WIN32_EMBED_REQUEST_FOCUS,
89                            0, 0);
90 }
91
92 void
93 _gtk_plug_windowing_add_grabbed_key (GtkPlug        *plug,
94                                      guint           accelerator_key,
95                                      GdkModifierType accelerator_mods)
96 {
97   if (plug->socket_window)
98     _gtk_win32_embed_send (plug->socket_window,
99                            GTK_WIN32_EMBED_GRAB_KEY,
100                            accelerator_key, accelerator_mods);
101 }
102
103 void
104 _gtk_plug_windowing_remove_grabbed_key (GtkPlug        *plug,
105                                         guint           accelerator_key,
106                                         GdkModifierType accelerator_mods)
107 {
108   if (plug->socket_window)
109     _gtk_win32_embed_send (plug->socket_window,
110                            GTK_WIN32_EMBED_UNGRAB_KEY,
111                            accelerator_key, accelerator_mods);
112 }
113
114 void
115 _gtk_plug_windowing_focus_to_parent (GtkPlug         *plug,
116                                      GtkDirectionType direction)
117 {
118   GtkWin32EmbedMessageType message = GTK_WIN32_EMBED_FOCUS_PREV;
119   
120   switch (direction)
121     {
122     case GTK_DIR_UP:
123     case GTK_DIR_LEFT:
124     case GTK_DIR_TAB_BACKWARD:
125       message = GTK_WIN32_EMBED_FOCUS_PREV;
126       break;
127     case GTK_DIR_DOWN:
128     case GTK_DIR_RIGHT:
129     case GTK_DIR_TAB_FORWARD:
130       message = GTK_WIN32_EMBED_FOCUS_NEXT;
131       break;
132     }
133   
134   _gtk_win32_embed_send_focus_message (plug->socket_window, message, 0);
135 }
136
137 GdkFilterReturn
138 _gtk_plug_windowing_filter_func (GdkXEvent *gdk_xevent,
139                                  GdkEvent  *event,
140                                  gpointer   data)
141 {
142   GtkPlug *plug = GTK_PLUG (data);
143   MSG *msg = (MSG *) gdk_xevent;
144   GdkFilterReturn return_val = GDK_FILTER_CONTINUE;
145
146   switch (msg->message)
147     {
148       /* What message should we look for to notice the reparenting?
149        * Maybe WM_WINDOWPOSCHANGED will work? This is handled in the
150        * X11 implementation by handling ReparentNotify. Handle this
151        * only for cross-process embedding, otherwise we get odd
152        * crashes in testsocket.
153        */
154     case WM_WINDOWPOSCHANGED:
155       if (!plug->same_app)
156         {
157           HWND parent = GetAncestor (msg->hwnd, GA_PARENT);
158           gboolean was_embedded = plug->socket_window != NULL;
159           GdkScreen *screen = gdk_drawable_get_screen (event->any.window);
160           GdkDisplay *display = gdk_screen_get_display (screen);
161
162           GTK_NOTE (PLUGSOCKET, g_printerr ("WM_WINDOWPOSCHANGED: hwnd=%p GA_PARENT=%p socket_window=%p\n", msg->hwnd, parent, plug->socket_window));
163           g_object_ref (plug);
164           if (was_embedded)
165             {
166               /* End of embedding protocol for previous socket */
167               if (parent != GDK_WINDOW_HWND (plug->socket_window))
168                 {
169                   GtkWidget *widget = GTK_WIDGET (plug);
170
171                   GTK_NOTE (PLUGSOCKET, g_printerr ("was_embedded, current parent != socket_window\n"));
172                   gdk_window_set_user_data (plug->socket_window, NULL);
173                   g_object_unref (plug->socket_window);
174                   plug->socket_window = NULL;
175
176                   /* Emit a delete window, as if the user attempted to
177                    * close the toplevel. Only do this if we are being
178                    * reparented to the desktop window. Moving from one
179                    * embedder to another should be invisible to the app.
180                    */
181                   if (parent == GetDesktopWindow ())
182                     {
183                       GTK_NOTE (PLUGSOCKET, g_printerr ("current parent is root window\n"));
184                       _gtk_plug_send_delete_event (widget);
185                       return_val = GDK_FILTER_REMOVE;
186                     }
187                 }
188               else
189                 {
190                   GTK_NOTE (PLUGSOCKET, g_printerr ("still same parent\n"));
191                   goto done;
192                 }
193             }
194
195           if (parent != GetDesktopWindow ())
196             {
197               /* Start of embedding protocol */
198
199               GTK_NOTE (PLUGSOCKET, g_printerr ("start of embedding\n"));
200               plug->socket_window = gdk_window_lookup_for_display (display, (GdkNativeWindow) parent);
201               if (plug->socket_window)
202                 {
203                   gpointer user_data = NULL;
204
205                   GTK_NOTE (PLUGSOCKET, g_printerr ("already had socket_window\n"));
206                   gdk_window_get_user_data (plug->socket_window, &user_data);
207
208                   if (user_data)
209                     {
210                       g_warning (G_STRLOC "Plug reparented unexpectedly into window in the same process");
211                       plug->socket_window = NULL;
212                       break;
213                     }
214
215                   g_object_ref (plug->socket_window);
216                 }
217               else
218                 {
219                   plug->socket_window = gdk_window_foreign_new_for_display (display, (GdkNativeWindow) parent);
220                   if (!plug->socket_window) /* Already gone */
221                     break;
222                 }
223
224               _gtk_plug_add_all_grabbed_keys (plug);
225
226               if (!was_embedded)
227                 g_signal_emit_by_name (plug, "embedded");
228             }
229         done:
230           g_object_unref (plug);
231         }
232       break;
233
234     case WM_SIZE:
235       if (!plug->same_app && plug->socket_window)
236         {
237           _gtk_win32_embed_send (plug->socket_window,
238                                  GTK_WIN32_EMBED_PLUG_RESIZED,
239                                  0, 0);
240         }
241       break;
242
243     default:
244       if (msg->message == _gtk_win32_embed_message_type (GTK_WIN32_EMBED_WINDOW_ACTIVATE))
245         {
246           GTK_NOTE (PLUGSOCKET, g_printerr ("GtkPlug: WINDOW_ACTIVATE received\n"));
247           _gtk_win32_embed_push_message (msg);
248           _gtk_window_set_is_active (GTK_WINDOW (plug), TRUE);
249           _gtk_win32_embed_pop_message ();
250           return_val = GDK_FILTER_REMOVE;
251         }
252       else if (msg->message == _gtk_win32_embed_message_type (GTK_WIN32_EMBED_WINDOW_DEACTIVATE))
253         {
254           GTK_NOTE (PLUGSOCKET, g_printerr ("GtkPlug: WINDOW_DEACTIVATE received\n"));
255           _gtk_win32_embed_push_message (msg);
256           _gtk_window_set_is_active (GTK_WINDOW (plug), FALSE);
257           _gtk_win32_embed_pop_message ();
258           return_val = GDK_FILTER_REMOVE;
259         }
260       else if (msg->message == _gtk_win32_embed_message_type (GTK_WIN32_EMBED_FOCUS_IN))
261         {
262           GTK_NOTE (PLUGSOCKET, g_printerr ("GtkPlug: FOCUS_IN received\n"));
263           _gtk_win32_embed_push_message (msg);
264           _gtk_window_set_has_toplevel_focus (GTK_WINDOW (plug), TRUE);
265           switch (msg->wParam)
266             {
267             case GTK_WIN32_EMBED_FOCUS_CURRENT:
268               break;
269             case GTK_WIN32_EMBED_FOCUS_FIRST:
270               _gtk_plug_focus_first_last (plug, GTK_DIR_TAB_FORWARD);
271               break;
272             case GTK_WIN32_EMBED_FOCUS_LAST:
273               _gtk_plug_focus_first_last (plug, GTK_DIR_TAB_BACKWARD);
274               break;
275             }
276           _gtk_win32_embed_pop_message ();
277           return_val = GDK_FILTER_REMOVE;
278         }
279       else if (msg->message == _gtk_win32_embed_message_type (GTK_WIN32_EMBED_FOCUS_OUT))
280         {
281           GTK_NOTE (PLUGSOCKET, g_printerr ("GtkPlug: FOCUS_OUT received\n"));
282           _gtk_win32_embed_push_message (msg);
283           _gtk_window_set_has_toplevel_focus (GTK_WINDOW (plug), FALSE);
284           _gtk_win32_embed_pop_message ();
285           return_val = GDK_FILTER_REMOVE;
286         }
287       else if (msg->message == _gtk_win32_embed_message_type (GTK_WIN32_EMBED_MODALITY_ON))
288         {
289           GTK_NOTE (PLUGSOCKET, g_printerr ("GtkPlug: MODALITY_ON received\n"));
290           _gtk_win32_embed_push_message (msg);
291           _gtk_plug_handle_modality_on (plug);
292           _gtk_win32_embed_pop_message ();
293           return_val = GDK_FILTER_REMOVE;
294         }
295       else if (msg->message == _gtk_win32_embed_message_type (GTK_WIN32_EMBED_MODALITY_OFF))
296         {
297           GTK_NOTE (PLUGSOCKET, g_printerr ("GtkPlug: MODALITY_OFF received\n"));
298           _gtk_win32_embed_push_message (msg);
299           _gtk_plug_handle_modality_off (plug);
300           _gtk_win32_embed_pop_message ();
301           return_val = GDK_FILTER_REMOVE;
302         }
303       break;
304     }
305
306   return return_val;
307 }