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"
42 #include "gdk/x11/gdkx.h"
43 #include "gdk/gdkprivate.h"
46 #include <X11/extensions/Xfixes.h>
49 #include "gtkxembed.h"
51 static gboolean xembed_get_info (GdkWindow *gdk_window,
52 unsigned long *version,
53 unsigned long *flags);
56 #define EMBEDDED_APP_WANTS_FOCUS NotifyNormal+20
59 _gtk_socket_windowing_get_id (GtkSocket *socket)
61 return GDK_WINDOW_XID (gtk_widget_get_window (GTK_WIDGET (socket)));
65 _gtk_socket_windowing_realize_window (GtkSocket *socket)
68 XWindowAttributes xattrs;
70 window = gtk_widget_get_window (GTK_WIDGET (socket));
72 XGetWindowAttributes (GDK_WINDOW_XDISPLAY (window),
73 GDK_WINDOW_XID (window),
76 /* Sooooo, it turns out that mozilla, as per the gtk2xt code selects
77 for input on the socket with a mask of 0x0fffff (for god knows why)
78 which includes ButtonPressMask causing a BadAccess if someone else
79 also selects for this. As per the client-side windows merge we always
80 normally selects for button press so we can emulate it on client
81 side children that selects for button press. However, we don't need
82 this for GtkSocket, so we unselect it here, fixing the crashes in
84 XSelectInput (GDK_WINDOW_XDISPLAY (window),
85 GDK_WINDOW_XID (window),
86 (xattrs.your_event_mask & ~ButtonPressMask) |
87 SubstructureNotifyMask | SubstructureRedirectMask);
91 _gtk_socket_windowing_end_embedding_toplevel (GtkSocket *socket)
93 gtk_window_remove_embedded_xid (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (socket))),
94 GDK_WINDOW_XID (socket->plug_window));
98 _gtk_socket_windowing_size_request (GtkSocket *socket)
103 gdk_error_trap_push ();
105 socket->request_width = 1;
106 socket->request_height = 1;
108 if (XGetWMNormalHints (GDK_WINDOW_XDISPLAY (socket->plug_window),
109 GDK_WINDOW_XID (socket->plug_window),
112 if (hints.flags & PMinSize)
114 socket->request_width = MAX (hints.min_width, 1);
115 socket->request_height = MAX (hints.min_height, 1);
117 else if (hints.flags & PBaseSize)
119 socket->request_width = MAX (hints.base_width, 1);
120 socket->request_height = MAX (hints.base_height, 1);
123 socket->have_size = TRUE;
125 gdk_error_trap_pop_ignored ();
129 _gtk_socket_windowing_send_key_event (GtkSocket *socket,
131 gboolean mask_key_presses)
134 GdkScreen *screen = gdk_window_get_screen (socket->plug_window);
136 memset (&xkey, 0, sizeof (xkey));
137 xkey.type = (gdk_event->type == GDK_KEY_PRESS) ? KeyPress : KeyRelease;
138 xkey.window = GDK_WINDOW_XID (socket->plug_window);
139 xkey.root = GDK_WINDOW_XID (gdk_screen_get_root_window (screen));
140 xkey.subwindow = None;
141 xkey.time = gdk_event->key.time;
146 xkey.state = gdk_event->key.state;
147 xkey.keycode = gdk_event->key.hardware_keycode;
148 xkey.same_screen = True;/* FIXME ? */
150 gdk_error_trap_push ();
151 XSendEvent (GDK_WINDOW_XDISPLAY (socket->plug_window),
152 GDK_WINDOW_XID (socket->plug_window),
154 (mask_key_presses ? KeyPressMask : NoEventMask),
156 gdk_error_trap_pop_ignored ();
160 _gtk_socket_windowing_focus_change (GtkSocket *socket,
164 _gtk_xembed_send_focus_message (socket->plug_window,
165 XEMBED_FOCUS_IN, XEMBED_FOCUS_CURRENT);
167 _gtk_xembed_send_message (socket->plug_window,
168 XEMBED_FOCUS_OUT, 0, 0, 0);
172 _gtk_socket_windowing_update_active (GtkSocket *socket,
175 _gtk_xembed_send_message (socket->plug_window,
176 active ? XEMBED_WINDOW_ACTIVATE : XEMBED_WINDOW_DEACTIVATE,
181 _gtk_socket_windowing_update_modality (GtkSocket *socket,
184 _gtk_xembed_send_message (socket->plug_window,
185 modality ? XEMBED_MODALITY_ON : XEMBED_MODALITY_OFF,
190 _gtk_socket_windowing_focus (GtkSocket *socket,
191 GtkDirectionType direction)
199 case GTK_DIR_TAB_BACKWARD:
200 detail = XEMBED_FOCUS_LAST;
204 case GTK_DIR_TAB_FORWARD:
205 detail = XEMBED_FOCUS_FIRST;
209 _gtk_xembed_send_focus_message (socket->plug_window, XEMBED_FOCUS_IN, detail);
213 _gtk_socket_windowing_send_configure_event (GtkSocket *socket)
215 GtkAllocation allocation;
216 XConfigureEvent xconfigure;
219 g_return_if_fail (socket->plug_window != NULL);
221 memset (&xconfigure, 0, sizeof (xconfigure));
222 xconfigure.type = ConfigureNotify;
224 xconfigure.event = GDK_WINDOW_XID (socket->plug_window);
225 xconfigure.window = GDK_WINDOW_XID (socket->plug_window);
227 /* The ICCCM says that synthetic events should have root relative
228 * coordinates. We still aren't really ICCCM compliant, since
229 * we don't send events when the real toplevel is moved.
231 gdk_error_trap_push ();
232 gdk_window_get_origin (socket->plug_window, &x, &y);
233 gdk_error_trap_pop_ignored ();
235 gtk_widget_get_allocation (GTK_WIDGET(socket), &allocation);
238 xconfigure.width = allocation.width;
239 xconfigure.height = allocation.height;
241 xconfigure.border_width = 0;
242 xconfigure.above = None;
243 xconfigure.override_redirect = False;
245 gdk_error_trap_push ();
246 XSendEvent (GDK_WINDOW_XDISPLAY (socket->plug_window),
247 GDK_WINDOW_XID (socket->plug_window),
248 False, NoEventMask, (XEvent *)&xconfigure);
249 gdk_error_trap_pop_ignored ();
253 _gtk_socket_windowing_select_plug_window_input (GtkSocket *socket)
255 XSelectInput (GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (GTK_WIDGET (socket))),
256 GDK_WINDOW_XID (socket->plug_window),
257 StructureNotifyMask | PropertyChangeMask);
261 _gtk_socket_windowing_embed_get_info (GtkSocket *socket)
263 unsigned long version;
266 socket->xembed_version = -1;
267 if (xembed_get_info (socket->plug_window, &version, &flags))
269 socket->xembed_version = MIN (GTK_XEMBED_PROTOCOL_VERSION, version);
270 socket->is_mapped = (flags & XEMBED_MAPPED) != 0;
274 /* FIXME, we should probably actually check the state before we started */
275 socket->is_mapped = TRUE;
280 _gtk_socket_windowing_embed_notify (GtkSocket *socket)
283 GdkDisplay *display = gtk_widget_get_display (GTK_WIDGET (socket));
285 gdk_error_trap_push ();
286 XFixesChangeSaveSet (GDK_DISPLAY_XDISPLAY (display),
287 GDK_WINDOW_XID (socket->plug_window),
288 SetModeInsert, SaveSetRoot, SaveSetUnmap);
289 gdk_error_trap_pop_ignored ();
291 _gtk_xembed_send_message (socket->plug_window,
292 XEMBED_EMBEDDED_NOTIFY, 0,
293 GDK_WINDOW_XID (gtk_widget_get_window (GTK_WIDGET (socket))),
294 socket->xembed_version);
298 xembed_get_info (GdkWindow *window,
299 unsigned long *version,
300 unsigned long *flags)
302 GdkDisplay *display = gdk_window_get_display (window);
303 Atom xembed_info_atom = gdk_x11_get_xatom_by_name_for_display (display, "_XEMBED_INFO");
306 unsigned long nitems, bytes_after;
308 unsigned long *data_long;
311 gdk_error_trap_push ();
312 status = XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display),
313 GDK_WINDOW_XID (window),
316 xembed_info_atom, &type, &format,
317 &nitems, &bytes_after, &data);
318 gdk_error_trap_pop_ignored ();
320 if (status != Success)
321 return FALSE; /* Window vanished? */
323 if (type == None) /* No info property */
326 if (type != xembed_info_atom)
328 g_warning ("_XEMBED_INFO property has wrong type\n");
334 g_warning ("_XEMBED_INFO too short\n");
339 data_long = (unsigned long *)data;
341 *version = data_long[0];
343 *flags = data_long[1] & XEMBED_MAPPED;
350 _gtk_socket_windowing_embed_get_focus_wrapped (void)
352 return _gtk_xembed_get_focus_wrapped ();
356 _gtk_socket_windowing_embed_set_focus_wrapped (void)
358 _gtk_xembed_set_focus_wrapped ();
362 handle_xembed_message (GtkSocket *socket,
363 XEmbedMessageType message,
369 GTK_NOTE (PLUGSOCKET,
370 g_message ("GtkSocket: %s received", _gtk_xembed_message_name (message)));
374 case XEMBED_EMBEDDED_NOTIFY:
375 case XEMBED_WINDOW_ACTIVATE:
376 case XEMBED_WINDOW_DEACTIVATE:
377 case XEMBED_MODALITY_ON:
378 case XEMBED_MODALITY_OFF:
379 case XEMBED_FOCUS_IN:
380 case XEMBED_FOCUS_OUT:
381 g_warning ("GtkSocket: Invalid _XEMBED message %s received", _gtk_xembed_message_name (message));
384 case XEMBED_REQUEST_FOCUS:
385 _gtk_socket_claim_focus (socket, TRUE);
388 case XEMBED_FOCUS_NEXT:
389 case XEMBED_FOCUS_PREV:
390 _gtk_socket_advance_toplevel_focus (socket,
391 (message == XEMBED_FOCUS_NEXT ?
392 GTK_DIR_TAB_FORWARD : GTK_DIR_TAB_BACKWARD));
395 case XEMBED_GTK_GRAB_KEY:
396 _gtk_socket_add_grabbed_key (socket, data1, data2);
398 case XEMBED_GTK_UNGRAB_KEY:
399 _gtk_socket_remove_grabbed_key (socket, data1, data2);
402 case XEMBED_GRAB_KEY:
403 case XEMBED_UNGRAB_KEY:
407 GTK_NOTE (PLUGSOCKET,
408 g_message ("GtkSocket: Ignoring unknown _XEMBED message of type %d", message));
414 _gtk_socket_windowing_filter_func (GdkXEvent *gdk_xevent,
423 GdkFilterReturn return_val;
425 socket = GTK_SOCKET (data);
427 return_val = GDK_FILTER_CONTINUE;
429 if (socket->plug_widget)
432 widget = GTK_WIDGET (socket);
433 xevent = (XEvent *)gdk_xevent;
434 display = gtk_widget_get_display (widget);
436 switch (xevent->type)
439 if (xevent->xclient.message_type == gdk_x11_get_xatom_by_name_for_display (display, "_XEMBED"))
441 _gtk_xembed_push_message (xevent);
442 handle_xembed_message (socket,
443 xevent->xclient.data.l[1],
444 xevent->xclient.data.l[2],
445 xevent->xclient.data.l[3],
446 xevent->xclient.data.l[4],
447 xevent->xclient.data.l[0]);
448 _gtk_xembed_pop_message ();
450 return_val = GDK_FILTER_REMOVE;
456 XCreateWindowEvent *xcwe = &xevent->xcreatewindow;
458 if (!socket->plug_window)
460 _gtk_socket_add_window (socket, xcwe->window, FALSE);
462 if (socket->plug_window)
464 GTK_NOTE (PLUGSOCKET, g_message ("GtkSocket - window created"));
468 return_val = GDK_FILTER_REMOVE;
473 case ConfigureRequest:
475 XConfigureRequestEvent *xcre = &xevent->xconfigurerequest;
477 if (!socket->plug_window)
478 _gtk_socket_add_window (socket, xcre->window, FALSE);
480 if (socket->plug_window)
482 GtkSocketPrivate *private = _gtk_socket_get_private (socket);
484 if (xcre->value_mask & (CWWidth | CWHeight))
486 GTK_NOTE (PLUGSOCKET,
487 g_message ("GtkSocket - configure request: %d %d",
488 socket->request_width,
489 socket->request_height));
491 private->resize_count++;
492 gtk_widget_queue_resize (widget);
494 else if (xcre->value_mask & (CWX | CWY))
496 _gtk_socket_windowing_send_configure_event (socket);
498 /* Ignore stacking requests. */
500 return_val = GDK_FILTER_REMOVE;
507 XDestroyWindowEvent *xdwe = &xevent->xdestroywindow;
509 /* Note that we get destroy notifies both from SubstructureNotify on
510 * our window and StructureNotify on socket->plug_window
512 if (socket->plug_window && (xdwe->window == GDK_WINDOW_XID (socket->plug_window)))
516 GTK_NOTE (PLUGSOCKET, g_message ("GtkSocket - destroy notify"));
518 gdk_window_destroy_notify (socket->plug_window);
519 _gtk_socket_end_embedding (socket);
521 g_object_ref (widget);
522 g_signal_emit_by_name (widget, "plug-removed", &result);
524 gtk_widget_destroy (widget);
525 g_object_unref (widget);
527 return_val = GDK_FILTER_REMOVE;
533 if (xevent->xfocus.mode == EMBEDDED_APP_WANTS_FOCUS)
535 _gtk_socket_claim_focus (socket, TRUE);
537 return_val = GDK_FILTER_REMOVE;
540 return_val = GDK_FILTER_REMOVE;
543 if (!socket->plug_window)
545 _gtk_socket_add_window (socket, xevent->xmaprequest.window, FALSE);
548 if (socket->plug_window)
550 GTK_NOTE (PLUGSOCKET, g_message ("GtkSocket - Map Request"));
552 _gtk_socket_handle_map_request (socket);
553 return_val = GDK_FILTER_REMOVE;
557 if (socket->plug_window &&
558 xevent->xproperty.window == GDK_WINDOW_XID (socket->plug_window))
560 GdkDragProtocol protocol;
562 if (xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "WM_NORMAL_HINTS"))
564 GTK_NOTE (PLUGSOCKET, g_message ("GtkSocket - received PropertyNotify for plug's WM_NORMAL_HINTS"));
565 socket->have_size = FALSE;
566 gtk_widget_queue_resize (widget);
567 return_val = GDK_FILTER_REMOVE;
569 else if ((xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "XdndAware")) ||
570 (xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_RECEIVER_INFO")))
572 gdk_error_trap_push ();
573 if (gdk_drag_get_protocol_for_display (display,
574 xevent->xproperty.window,
576 gtk_drag_dest_set_proxy (GTK_WIDGET (socket),
580 gdk_error_trap_pop_ignored ();
581 return_val = GDK_FILTER_REMOVE;
583 else if (xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "_XEMBED_INFO"))
587 if (xembed_get_info (socket->plug_window, NULL, &flags))
589 gboolean was_mapped = socket->is_mapped;
590 gboolean is_mapped = (flags & XEMBED_MAPPED) != 0;
592 if (was_mapped != is_mapped)
595 _gtk_socket_handle_map_request (socket);
598 gdk_error_trap_push ();
599 gdk_window_show (socket->plug_window);
600 gdk_error_trap_pop_ignored ();
602 _gtk_socket_unmap_notify (socket);
606 return_val = GDK_FILTER_REMOVE;
613 XReparentEvent *xre = &xevent->xreparent;
615 window = gtk_widget_get_window (widget);
617 GTK_NOTE (PLUGSOCKET, g_message ("GtkSocket - ReparentNotify received"));
618 if (!socket->plug_window &&
619 xre->parent == GDK_WINDOW_XID (window))
621 _gtk_socket_add_window (socket, xre->window, FALSE);
623 if (socket->plug_window)
625 GTK_NOTE (PLUGSOCKET, g_message ("GtkSocket - window reparented"));
628 return_val = GDK_FILTER_REMOVE;
632 if (socket->plug_window &&
633 xre->window == GDK_WINDOW_XID (socket->plug_window) &&
634 xre->parent != GDK_WINDOW_XID (window))
638 _gtk_socket_end_embedding (socket);
640 g_object_ref (widget);
641 g_signal_emit_by_name (widget, "plug-removed", &result);
643 gtk_widget_destroy (widget);
644 g_object_unref (widget);
646 return_val = GDK_FILTER_REMOVE;
653 if (socket->plug_window &&
654 xevent->xunmap.window == GDK_WINDOW_XID (socket->plug_window))
656 GTK_NOTE (PLUGSOCKET, g_message ("GtkSocket - Unmap notify"));
658 _gtk_socket_unmap_notify (socket);
659 return_val = GDK_FILTER_REMOVE;