1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
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.
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.
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.
19 /* By Owen Taylor <otaylor@gtk.org> 98/4/4 */
22 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
23 * file for a list of people on the GTK+ Team. See the ChangeLog
24 * files for a list of changes. These files are distributed with
25 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
31 #include "gdk/gdkkeysyms.h"
33 #include "gtkmarshalers.h"
34 #include "gtkwindow.h"
36 #include "gtkprivate.h"
37 #include "gtksocket.h"
38 #include "gtksocketprivate.h"
45 #include <X11/extensions/Xfixes.h>
48 #include "gtkxembed.h"
50 static gboolean xembed_get_info (GdkWindow *gdk_window,
51 unsigned long *version,
52 unsigned long *flags);
55 #define EMBEDDED_APP_WANTS_FOCUS NotifyNormal+20
58 _gtk_socket_windowing_get_id (GtkSocket *socket)
60 return GDK_WINDOW_XWINDOW (gtk_widget_get_window (GTK_WIDGET (socket)));
64 _gtk_socket_windowing_realize_window (GtkSocket *socket)
67 XWindowAttributes xattrs;
69 window = gtk_widget_get_window (GTK_WIDGET (socket));
71 XGetWindowAttributes (GDK_WINDOW_XDISPLAY (window),
72 GDK_WINDOW_XWINDOW (window),
75 /* Sooooo, it turns out that mozilla, as per the gtk2xt code selects
76 for input on the socket with a mask of 0x0fffff (for god knows why)
77 which includes ButtonPressMask causing a BadAccess if someone else
78 also selects for this. As per the client-side windows merge we always
79 normally selects for button press so we can emulate it on client
80 side children that selects for button press. However, we don't need
81 this for GtkSocket, so we unselect it here, fixing the crashes in
83 XSelectInput (GDK_WINDOW_XDISPLAY (window),
84 GDK_WINDOW_XWINDOW (window),
85 (xattrs.your_event_mask & ~ButtonPressMask) |
86 SubstructureNotifyMask | SubstructureRedirectMask);
90 _gtk_socket_windowing_end_embedding_toplevel (GtkSocket *socket)
92 gtk_window_remove_embedded_xid (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (socket))),
93 GDK_WINDOW_XWINDOW (socket->plug_window));
97 _gtk_socket_windowing_size_request (GtkSocket *socket)
102 gdk_error_trap_push ();
104 socket->request_width = 1;
105 socket->request_height = 1;
107 if (XGetWMNormalHints (GDK_WINDOW_XDISPLAY (socket->plug_window),
108 GDK_WINDOW_XWINDOW (socket->plug_window),
111 if (hints.flags & PMinSize)
113 socket->request_width = MAX (hints.min_width, 1);
114 socket->request_height = MAX (hints.min_height, 1);
116 else if (hints.flags & PBaseSize)
118 socket->request_width = MAX (hints.base_width, 1);
119 socket->request_height = MAX (hints.base_height, 1);
122 socket->have_size = TRUE;
124 gdk_error_trap_pop_ignored ();
128 _gtk_socket_windowing_send_key_event (GtkSocket *socket,
130 gboolean mask_key_presses)
133 GdkScreen *screen = gdk_window_get_screen (socket->plug_window);
135 memset (&xkey, 0, sizeof (xkey));
136 xkey.type = (gdk_event->type == GDK_KEY_PRESS) ? KeyPress : KeyRelease;
137 xkey.window = GDK_WINDOW_XWINDOW (socket->plug_window);
138 xkey.root = GDK_WINDOW_XWINDOW (gdk_screen_get_root_window (screen));
139 xkey.subwindow = None;
140 xkey.time = gdk_event->key.time;
145 xkey.state = gdk_event->key.state;
146 xkey.keycode = gdk_event->key.hardware_keycode;
147 xkey.same_screen = True;/* FIXME ? */
149 gdk_error_trap_push ();
150 XSendEvent (GDK_WINDOW_XDISPLAY (socket->plug_window),
151 GDK_WINDOW_XWINDOW (socket->plug_window),
153 (mask_key_presses ? KeyPressMask : NoEventMask),
155 gdk_error_trap_pop_ignored ();
159 _gtk_socket_windowing_focus_change (GtkSocket *socket,
163 _gtk_xembed_send_focus_message (socket->plug_window,
164 XEMBED_FOCUS_IN, XEMBED_FOCUS_CURRENT);
166 _gtk_xembed_send_message (socket->plug_window,
167 XEMBED_FOCUS_OUT, 0, 0, 0);
171 _gtk_socket_windowing_update_active (GtkSocket *socket,
174 _gtk_xembed_send_message (socket->plug_window,
175 active ? XEMBED_WINDOW_ACTIVATE : XEMBED_WINDOW_DEACTIVATE,
180 _gtk_socket_windowing_update_modality (GtkSocket *socket,
183 _gtk_xembed_send_message (socket->plug_window,
184 modality ? XEMBED_MODALITY_ON : XEMBED_MODALITY_OFF,
189 _gtk_socket_windowing_focus (GtkSocket *socket,
190 GtkDirectionType direction)
198 case GTK_DIR_TAB_BACKWARD:
199 detail = XEMBED_FOCUS_LAST;
203 case GTK_DIR_TAB_FORWARD:
204 detail = XEMBED_FOCUS_FIRST;
208 _gtk_xembed_send_focus_message (socket->plug_window, XEMBED_FOCUS_IN, detail);
212 _gtk_socket_windowing_send_configure_event (GtkSocket *socket)
214 GtkAllocation allocation;
215 XConfigureEvent xconfigure;
218 g_return_if_fail (socket->plug_window != NULL);
220 memset (&xconfigure, 0, sizeof (xconfigure));
221 xconfigure.type = ConfigureNotify;
223 xconfigure.event = GDK_WINDOW_XWINDOW (socket->plug_window);
224 xconfigure.window = GDK_WINDOW_XWINDOW (socket->plug_window);
226 /* The ICCCM says that synthetic events should have root relative
227 * coordinates. We still aren't really ICCCM compliant, since
228 * we don't send events when the real toplevel is moved.
230 gdk_error_trap_push ();
231 gdk_window_get_origin (socket->plug_window, &x, &y);
232 gdk_error_trap_pop_ignored ();
234 gtk_widget_get_allocation (GTK_WIDGET(socket), &allocation);
237 xconfigure.width = allocation.width;
238 xconfigure.height = allocation.height;
240 xconfigure.border_width = 0;
241 xconfigure.above = None;
242 xconfigure.override_redirect = False;
244 gdk_error_trap_push ();
245 XSendEvent (GDK_WINDOW_XDISPLAY (socket->plug_window),
246 GDK_WINDOW_XWINDOW (socket->plug_window),
247 False, NoEventMask, (XEvent *)&xconfigure);
248 gdk_error_trap_pop_ignored ();
252 _gtk_socket_windowing_select_plug_window_input (GtkSocket *socket)
254 XSelectInput (GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (GTK_WIDGET (socket))),
255 GDK_WINDOW_XWINDOW (socket->plug_window),
256 StructureNotifyMask | PropertyChangeMask);
260 _gtk_socket_windowing_embed_get_info (GtkSocket *socket)
262 unsigned long version;
265 socket->xembed_version = -1;
266 if (xembed_get_info (socket->plug_window, &version, &flags))
268 socket->xembed_version = MIN (GTK_XEMBED_PROTOCOL_VERSION, version);
269 socket->is_mapped = (flags & XEMBED_MAPPED) != 0;
273 /* FIXME, we should probably actually check the state before we started */
274 socket->is_mapped = TRUE;
279 _gtk_socket_windowing_embed_notify (GtkSocket *socket)
282 GdkDisplay *display = gtk_widget_get_display (GTK_WIDGET (socket));
284 XFixesChangeSaveSet (GDK_DISPLAY_XDISPLAY (display),
285 GDK_WINDOW_XWINDOW (socket->plug_window),
286 SetModeInsert, SaveSetRoot, SaveSetUnmap);
288 _gtk_xembed_send_message (socket->plug_window,
289 XEMBED_EMBEDDED_NOTIFY, 0,
290 GDK_WINDOW_XWINDOW (gtk_widget_get_window (GTK_WIDGET (socket))),
291 socket->xembed_version);
295 xembed_get_info (GdkWindow *window,
296 unsigned long *version,
297 unsigned long *flags)
299 GdkDisplay *display = gdk_window_get_display (window);
300 Atom xembed_info_atom = gdk_x11_get_xatom_by_name_for_display (display, "_XEMBED_INFO");
303 unsigned long nitems, bytes_after;
305 unsigned long *data_long;
308 gdk_error_trap_push ();
309 status = XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display),
310 GDK_WINDOW_XWINDOW (window),
313 xembed_info_atom, &type, &format,
314 &nitems, &bytes_after, &data);
315 gdk_error_trap_pop_ignored ();
317 if (status != Success)
318 return FALSE; /* Window vanished? */
320 if (type == None) /* No info property */
323 if (type != xembed_info_atom)
325 g_warning ("_XEMBED_INFO property has wrong type\n");
331 g_warning ("_XEMBED_INFO too short\n");
336 data_long = (unsigned long *)data;
338 *version = data_long[0];
340 *flags = data_long[1] & XEMBED_MAPPED;
347 _gtk_socket_windowing_embed_get_focus_wrapped (void)
349 return _gtk_xembed_get_focus_wrapped ();
353 _gtk_socket_windowing_embed_set_focus_wrapped (void)
355 _gtk_xembed_set_focus_wrapped ();
359 handle_xembed_message (GtkSocket *socket,
360 XEmbedMessageType message,
366 GTK_NOTE (PLUGSOCKET,
367 g_message ("GtkSocket: %s received", _gtk_xembed_message_name (message)));
371 case XEMBED_EMBEDDED_NOTIFY:
372 case XEMBED_WINDOW_ACTIVATE:
373 case XEMBED_WINDOW_DEACTIVATE:
374 case XEMBED_MODALITY_ON:
375 case XEMBED_MODALITY_OFF:
376 case XEMBED_FOCUS_IN:
377 case XEMBED_FOCUS_OUT:
378 g_warning ("GtkSocket: Invalid _XEMBED message %s received", _gtk_xembed_message_name (message));
381 case XEMBED_REQUEST_FOCUS:
382 _gtk_socket_claim_focus (socket, TRUE);
385 case XEMBED_FOCUS_NEXT:
386 case XEMBED_FOCUS_PREV:
387 _gtk_socket_advance_toplevel_focus (socket,
388 (message == XEMBED_FOCUS_NEXT ?
389 GTK_DIR_TAB_FORWARD : GTK_DIR_TAB_BACKWARD));
392 case XEMBED_GTK_GRAB_KEY:
393 _gtk_socket_add_grabbed_key (socket, data1, data2);
395 case XEMBED_GTK_UNGRAB_KEY:
396 _gtk_socket_remove_grabbed_key (socket, data1, data2);
399 case XEMBED_GRAB_KEY:
400 case XEMBED_UNGRAB_KEY:
404 GTK_NOTE (PLUGSOCKET,
405 g_message ("GtkSocket: Ignoring unknown _XEMBED message of type %d", message));
411 _gtk_socket_windowing_filter_func (GdkXEvent *gdk_xevent,
420 GdkFilterReturn return_val;
422 socket = GTK_SOCKET (data);
424 return_val = GDK_FILTER_CONTINUE;
426 if (socket->plug_widget)
429 widget = GTK_WIDGET (socket);
430 xevent = (XEvent *)gdk_xevent;
431 display = gtk_widget_get_display (widget);
433 switch (xevent->type)
436 if (xevent->xclient.message_type == gdk_x11_get_xatom_by_name_for_display (display, "_XEMBED"))
438 _gtk_xembed_push_message (xevent);
439 handle_xembed_message (socket,
440 xevent->xclient.data.l[1],
441 xevent->xclient.data.l[2],
442 xevent->xclient.data.l[3],
443 xevent->xclient.data.l[4],
444 xevent->xclient.data.l[0]);
445 _gtk_xembed_pop_message ();
447 return_val = GDK_FILTER_REMOVE;
453 XCreateWindowEvent *xcwe = &xevent->xcreatewindow;
455 if (!socket->plug_window)
457 _gtk_socket_add_window (socket, xcwe->window, FALSE);
459 if (socket->plug_window)
461 GTK_NOTE (PLUGSOCKET, g_message ("GtkSocket - window created"));
465 return_val = GDK_FILTER_REMOVE;
470 case ConfigureRequest:
472 XConfigureRequestEvent *xcre = &xevent->xconfigurerequest;
474 if (!socket->plug_window)
475 _gtk_socket_add_window (socket, xcre->window, FALSE);
477 if (socket->plug_window)
479 GtkSocketPrivate *private = _gtk_socket_get_private (socket);
481 if (xcre->value_mask & (CWWidth | CWHeight))
483 GTK_NOTE (PLUGSOCKET,
484 g_message ("GtkSocket - configure request: %d %d",
485 socket->request_width,
486 socket->request_height));
488 private->resize_count++;
489 gtk_widget_queue_resize (widget);
491 else if (xcre->value_mask & (CWX | CWY))
493 _gtk_socket_windowing_send_configure_event (socket);
495 /* Ignore stacking requests. */
497 return_val = GDK_FILTER_REMOVE;
504 XDestroyWindowEvent *xdwe = &xevent->xdestroywindow;
506 /* Note that we get destroy notifies both from SubstructureNotify on
507 * our window and StructureNotify on socket->plug_window
509 if (socket->plug_window && (xdwe->window == GDK_WINDOW_XWINDOW (socket->plug_window)))
513 GTK_NOTE (PLUGSOCKET, g_message ("GtkSocket - destroy notify"));
515 gdk_window_destroy_notify (socket->plug_window);
516 _gtk_socket_end_embedding (socket);
518 g_object_ref (widget);
519 g_signal_emit_by_name (widget, "plug-removed", &result);
521 gtk_widget_destroy (widget);
522 g_object_unref (widget);
524 return_val = GDK_FILTER_REMOVE;
530 if (xevent->xfocus.mode == EMBEDDED_APP_WANTS_FOCUS)
532 _gtk_socket_claim_focus (socket, TRUE);
534 return_val = GDK_FILTER_REMOVE;
537 return_val = GDK_FILTER_REMOVE;
540 if (!socket->plug_window)
542 _gtk_socket_add_window (socket, xevent->xmaprequest.window, FALSE);
545 if (socket->plug_window)
547 GTK_NOTE (PLUGSOCKET, g_message ("GtkSocket - Map Request"));
549 _gtk_socket_handle_map_request (socket);
550 return_val = GDK_FILTER_REMOVE;
554 if (socket->plug_window &&
555 xevent->xproperty.window == GDK_WINDOW_XWINDOW (socket->plug_window))
557 GdkDragProtocol protocol;
559 if (xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "WM_NORMAL_HINTS"))
561 GTK_NOTE (PLUGSOCKET, g_message ("GtkSocket - received PropertyNotify for plug's WM_NORMAL_HINTS"));
562 socket->have_size = FALSE;
563 gtk_widget_queue_resize (widget);
564 return_val = GDK_FILTER_REMOVE;
566 else if ((xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "XdndAware")) ||
567 (xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_RECEIVER_INFO")))
569 gdk_error_trap_push ();
570 if (gdk_drag_get_protocol_for_display (display,
571 xevent->xproperty.window,
573 gtk_drag_dest_set_proxy (GTK_WIDGET (socket),
577 gdk_error_trap_pop_ignored ();
578 return_val = GDK_FILTER_REMOVE;
580 else if (xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "_XEMBED_INFO"))
584 if (xembed_get_info (socket->plug_window, NULL, &flags))
586 gboolean was_mapped = socket->is_mapped;
587 gboolean is_mapped = (flags & XEMBED_MAPPED) != 0;
589 if (was_mapped != is_mapped)
592 _gtk_socket_handle_map_request (socket);
595 gdk_error_trap_push ();
596 gdk_window_show (socket->plug_window);
597 gdk_error_trap_pop_ignored ();
599 _gtk_socket_unmap_notify (socket);
603 return_val = GDK_FILTER_REMOVE;
610 XReparentEvent *xre = &xevent->xreparent;
612 window = gtk_widget_get_window (widget);
614 GTK_NOTE (PLUGSOCKET, g_message ("GtkSocket - ReparentNotify received"));
615 if (!socket->plug_window &&
616 xre->parent == GDK_WINDOW_XWINDOW (window))
618 _gtk_socket_add_window (socket, xre->window, FALSE);
620 if (socket->plug_window)
622 GTK_NOTE (PLUGSOCKET, g_message ("GtkSocket - window reparented"));
625 return_val = GDK_FILTER_REMOVE;
629 if (socket->plug_window &&
630 xre->window == GDK_WINDOW_XWINDOW (socket->plug_window) &&
631 xre->parent != GDK_WINDOW_XWINDOW (window))
635 _gtk_socket_end_embedding (socket);
637 g_object_ref (widget);
638 g_signal_emit_by_name (widget, "plug-removed", &result);
640 gtk_widget_destroy (widget);
641 g_object_unref (widget);
643 return_val = GDK_FILTER_REMOVE;
650 if (socket->plug_window &&
651 xevent->xunmap.window == GDK_WINDOW_XWINDOW (socket->plug_window))
653 GTK_NOTE (PLUGSOCKET, g_message ("GtkSocket - Unmap notify"));
655 _gtk_socket_unmap_notify (socket);
656 return_val = GDK_FILTER_REMOVE;