]> Pileus Git - ~andy/gtk/blob - gtk/gtkplug-win32.c
Updated Bulgarian translation
[~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
37 #if defined(_MSC_VER) && (WINVER < 0x0500)
38 #ifndef GA_PARENT
39 #define GA_PARENT 1
40 #endif
41 WINUSERAPI HWND WINAPI GetAncestor(HWND,UINT);
42 #endif
43
44 GdkNativeWindow
45 _gtk_plug_windowing_get_id (GtkPlug *plug)
46 {
47   return (GdkNativeWindow) GDK_WINDOW_HWND (GTK_WIDGET (plug)->window);
48 }
49
50 void
51 _gtk_plug_windowing_realize_toplevel (GtkPlug *plug)
52 {
53   if (plug->socket_window)
54     {
55       _gtk_win32_embed_send (plug->socket_window,
56                              GTK_WIN32_EMBED_PARENT_NOTIFY,
57                              (WPARAM) GDK_WINDOW_HWND (GTK_WIDGET (plug)->window),
58                              GTK_WIN32_EMBED_PROTOCOL_VERSION);
59       _gtk_win32_embed_send (plug->socket_window,
60                              GTK_WIN32_EMBED_EVENT_PLUG_MAPPED, 0, 0);
61     }
62 }
63
64 void
65 _gtk_plug_windowing_map_toplevel (GtkPlug *plug)
66 {
67   if (plug->socket_window)
68     _gtk_win32_embed_send (plug->socket_window,
69                            GTK_WIN32_EMBED_EVENT_PLUG_MAPPED,
70                            1, 0);
71 }
72
73 void
74 _gtk_plug_windowing_unmap_toplevel (GtkPlug *plug)
75 {
76   if (plug->socket_window)
77     _gtk_win32_embed_send (plug->socket_window,
78                            GTK_WIN32_EMBED_EVENT_PLUG_MAPPED,
79                            0, 0);
80 }
81
82 void
83 _gtk_plug_windowing_set_focus (GtkPlug *plug)
84 {
85   if (plug->socket_window)
86     _gtk_win32_embed_send (plug->socket_window,
87                            GTK_WIN32_EMBED_REQUEST_FOCUS,
88                            0, 0);
89 }
90
91 void
92 _gtk_plug_windowing_add_grabbed_key (GtkPlug        *plug,
93                                      guint           accelerator_key,
94                                      GdkModifierType accelerator_mods)
95 {
96   if (plug->socket_window)
97     _gtk_win32_embed_send (plug->socket_window,
98                            GTK_WIN32_EMBED_GRAB_KEY,
99                            accelerator_key, accelerator_mods);
100 }
101
102 void
103 _gtk_plug_windowing_remove_grabbed_key (GtkPlug        *plug,
104                                         guint           accelerator_key,
105                                         GdkModifierType accelerator_mods)
106 {
107   if (plug->socket_window)
108     _gtk_win32_embed_send (plug->socket_window,
109                            GTK_WIN32_EMBED_UNGRAB_KEY,
110                            accelerator_key, accelerator_mods);
111 }
112
113 void
114 _gtk_plug_windowing_focus_to_parent (GtkPlug         *plug,
115                                      GtkDirectionType direction)
116 {
117   GtkWin32EmbedMessageType message = GTK_WIN32_EMBED_FOCUS_PREV;
118   
119   switch (direction)
120     {
121     case GTK_DIR_UP:
122     case GTK_DIR_LEFT:
123     case GTK_DIR_TAB_BACKWARD:
124       message = GTK_WIN32_EMBED_FOCUS_PREV;
125       break;
126     case GTK_DIR_DOWN:
127     case GTK_DIR_RIGHT:
128     case GTK_DIR_TAB_FORWARD:
129       message = GTK_WIN32_EMBED_FOCUS_NEXT;
130       break;
131     }
132   
133   _gtk_win32_embed_send_focus_message (plug->socket_window, message, 0);
134 }
135
136 GdkFilterReturn
137 _gtk_plug_windowing_filter_func (GdkXEvent *gdk_xevent,
138                                  GdkEvent  *event,
139                                  gpointer   data)
140 {
141   GtkPlug *plug = GTK_PLUG (data);
142   MSG *msg = (MSG *) gdk_xevent;
143   GdkFilterReturn return_val = GDK_FILTER_CONTINUE;
144
145   switch (msg->message)
146     {
147       /* What message should we look for to notice the reparenting?
148        * Maybe WM_WINDOWPOSCHANGED will work? This is handled in the
149        * X11 implementation by handling ReparentNotify. Handle this
150        * only for cross-process embedding, otherwise we get odd
151        * crashes in testsocket.
152        */
153     case WM_WINDOWPOSCHANGED:
154       if (!plug->same_app)
155         {
156           HWND parent = GetAncestor (msg->hwnd, GA_PARENT);
157           gboolean was_embedded = plug->socket_window != NULL;
158           GdkScreen *screen = gdk_drawable_get_screen (event->any.window);
159           GdkDisplay *display = gdk_screen_get_display (screen);
160
161           GTK_NOTE (PLUGSOCKET, g_printerr ("WM_WINDOWPOSCHANGED: hwnd=%p GA_PARENT=%p socket_window=%p\n", msg->hwnd, parent, plug->socket_window));
162           g_object_ref (plug);
163           if (was_embedded)
164             {
165               /* End of embedding protocol for previous socket */
166               if (parent != GDK_WINDOW_HWND (plug->socket_window))
167                 {
168                   GtkWidget *widget = GTK_WIDGET (plug);
169
170                   GTK_NOTE (PLUGSOCKET, g_printerr ("was_embedded, current parent != socket_window\n"));
171                   gdk_window_set_user_data (plug->socket_window, NULL);
172                   g_object_unref (plug->socket_window);
173                   plug->socket_window = NULL;
174
175                   /* Emit a delete window, as if the user attempted to
176                    * close the toplevel. Only do this if we are being
177                    * reparented to the desktop window. Moving from one
178                    * embedder to another should be invisible to the app.
179                    */
180                   if (parent == GetDesktopWindow ())
181                     {
182                       GTK_NOTE (PLUGSOCKET, g_printerr ("current parent is root window\n"));
183                       _gtk_plug_send_delete_event (widget);
184                       return_val = GDK_FILTER_REMOVE;
185                     }
186                 }
187               else
188                 {
189                   GTK_NOTE (PLUGSOCKET, g_printerr ("still same parent\n"));
190                   goto done;
191                 }
192             }
193
194           if (parent != GetDesktopWindow ())
195             {
196               /* Start of embedding protocol */
197
198               GTK_NOTE (PLUGSOCKET, g_printerr ("start of embedding\n"));
199               plug->socket_window = gdk_window_lookup_for_display (display, (GdkNativeWindow) parent);
200               if (plug->socket_window)
201                 {
202                   gpointer user_data = NULL;
203
204                   GTK_NOTE (PLUGSOCKET, g_printerr ("already had socket_window\n"));
205                   gdk_window_get_user_data (plug->socket_window, &user_data);
206
207                   if (user_data)
208                     {
209                       g_warning (G_STRLOC "Plug reparented unexpectedly into window in the same process");
210                       plug->socket_window = NULL;
211                       break;
212                     }
213
214                   g_object_ref (plug->socket_window);
215                 }
216               else
217                 {
218                   plug->socket_window = gdk_window_foreign_new_for_display (display, (GdkNativeWindow) parent);
219                   if (!plug->socket_window) /* Already gone */
220                     break;
221                 }
222
223               _gtk_plug_add_all_grabbed_keys (plug);
224
225               if (!was_embedded)
226                 g_signal_emit_by_name (plug, "embedded");
227             }
228         done:
229           g_object_unref (plug);
230         }
231       break;
232
233     case WM_SIZE:
234       if (!plug->same_app && plug->socket_window)
235         {
236           _gtk_win32_embed_send (plug->socket_window,
237                                  GTK_WIN32_EMBED_PLUG_RESIZED,
238                                  0, 0);
239         }
240       break;
241
242     default:
243       if (msg->message == _gtk_win32_embed_message_type (GTK_WIN32_EMBED_WINDOW_ACTIVATE))
244         {
245           GTK_NOTE (PLUGSOCKET, g_printerr ("GtkPlug: WINDOW_ACTIVATE received\n"));
246           _gtk_win32_embed_push_message (msg);
247           _gtk_window_set_is_active (GTK_WINDOW (plug), TRUE);
248           _gtk_win32_embed_pop_message ();
249           return_val = GDK_FILTER_REMOVE;
250         }
251       else if (msg->message == _gtk_win32_embed_message_type (GTK_WIN32_EMBED_WINDOW_DEACTIVATE))
252         {
253           GTK_NOTE (PLUGSOCKET, g_printerr ("GtkPlug: WINDOW_DEACTIVATE received\n"));
254           _gtk_win32_embed_push_message (msg);
255           _gtk_window_set_is_active (GTK_WINDOW (plug), FALSE);
256           _gtk_win32_embed_pop_message ();
257           return_val = GDK_FILTER_REMOVE;
258         }
259       else if (msg->message == _gtk_win32_embed_message_type (GTK_WIN32_EMBED_FOCUS_IN))
260         {
261           GTK_NOTE (PLUGSOCKET, g_printerr ("GtkPlug: FOCUS_IN received\n"));
262           _gtk_win32_embed_push_message (msg);
263           _gtk_window_set_has_toplevel_focus (GTK_WINDOW (plug), TRUE);
264           switch (msg->wParam)
265             {
266             case GTK_WIN32_EMBED_FOCUS_CURRENT:
267               break;
268             case GTK_WIN32_EMBED_FOCUS_FIRST:
269               _gtk_plug_focus_first_last (plug, GTK_DIR_TAB_FORWARD);
270               break;
271             case GTK_WIN32_EMBED_FOCUS_LAST:
272               _gtk_plug_focus_first_last (plug, GTK_DIR_TAB_BACKWARD);
273               break;
274             }
275           _gtk_win32_embed_pop_message ();
276           return_val = GDK_FILTER_REMOVE;
277         }
278       else if (msg->message == _gtk_win32_embed_message_type (GTK_WIN32_EMBED_FOCUS_OUT))
279         {
280           GTK_NOTE (PLUGSOCKET, g_printerr ("GtkPlug: FOCUS_OUT received\n"));
281           _gtk_win32_embed_push_message (msg);
282           _gtk_window_set_has_toplevel_focus (GTK_WINDOW (plug), FALSE);
283           _gtk_win32_embed_pop_message ();
284           return_val = GDK_FILTER_REMOVE;
285         }
286       else if (msg->message == _gtk_win32_embed_message_type (GTK_WIN32_EMBED_MODALITY_ON))
287         {
288           GTK_NOTE (PLUGSOCKET, g_printerr ("GtkPlug: MODALITY_ON received\n"));
289           _gtk_win32_embed_push_message (msg);
290           _gtk_plug_handle_modality_on (plug);
291           _gtk_win32_embed_pop_message ();
292           return_val = GDK_FILTER_REMOVE;
293         }
294       else if (msg->message == _gtk_win32_embed_message_type (GTK_WIN32_EMBED_MODALITY_OFF))
295         {
296           GTK_NOTE (PLUGSOCKET, g_printerr ("GtkPlug: MODALITY_OFF received\n"));
297           _gtk_win32_embed_push_message (msg);
298           _gtk_plug_handle_modality_off (plug);
299           _gtk_win32_embed_pop_message ();
300           return_val = GDK_FILTER_REMOVE;
301         }
302       break;
303     }
304
305   return return_val;
306 }