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 <X11/Xatom.h>
45 #include <X11/extensions/Xfixes.h>
48 #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_XWINDOW (GTK_WIDGET (socket)->window);
65 _gtk_socket_windowing_realize_window (GtkSocket *socket)
67 GdkWindow *window = GTK_WIDGET (socket)->window;
68 XWindowAttributes xattrs;
70 XGetWindowAttributes (GDK_WINDOW_XDISPLAY (window),
71 GDK_WINDOW_XWINDOW (window),
74 /* Sooooo, it turns out that mozilla, as per the gtk2xt code selects
75 for input on the socket with a mask of 0x0fffff (for god knows why)
76 which includes ButtonPressMask causing a BadAccess if someone else
77 also selects for this. As per the client-side windows merge we always
78 normally selects for button press so we can emulate it on client
79 side children that selects for button press. However, we don't need
80 this for GtkSocket, so we unselect it here, fixing the crashes in
82 XSelectInput (GDK_WINDOW_XDISPLAY (window),
83 GDK_WINDOW_XWINDOW (window),
84 (xattrs.your_event_mask & ~ButtonPressMask) |
85 SubstructureNotifyMask | SubstructureRedirectMask);
89 _gtk_socket_windowing_end_embedding_toplevel (GtkSocket *socket)
91 gtk_window_remove_embedded_xid (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (socket))),
92 GDK_WINDOW_XWINDOW (socket->plug_window));
96 _gtk_socket_windowing_size_request (GtkSocket *socket)
101 gdk_error_trap_push ();
103 socket->request_width = 1;
104 socket->request_height = 1;
106 if (XGetWMNormalHints (GDK_WINDOW_XDISPLAY (socket->plug_window),
107 GDK_WINDOW_XWINDOW (socket->plug_window),
110 if (hints.flags & PMinSize)
112 socket->request_width = MAX (hints.min_width, 1);
113 socket->request_height = MAX (hints.min_height, 1);
115 else if (hints.flags & PBaseSize)
117 socket->request_width = MAX (hints.base_width, 1);
118 socket->request_height = MAX (hints.base_height, 1);
121 socket->have_size = TRUE;
123 gdk_error_trap_pop ();
127 _gtk_socket_windowing_get_natural_size (GtkSocket *socket)
129 GtkSocketPrivate *priv;
135 unsigned long nitems, bytes_after;
139 priv = _gtk_socket_get_private (socket);
141 priv->natural_width = 1;
142 priv->natural_height = 1;
144 if (GTK_WIDGET_MAPPED (socket))
146 display = gdk_drawable_get_display (socket->plug_window);
147 property = gdk_x11_get_xatom_by_name_for_display (display, "_GTK_NATURAL_SIZE");
149 gdk_error_trap_push ();
150 status = XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display),
151 GDK_WINDOW_XWINDOW (socket->plug_window),
152 property, 0, 2, False, XA_CARDINAL,
153 &type, &format, &nitems, &bytes_after,
155 gdk_error_trap_pop ();
157 priv->have_natural_size = TRUE;
159 if (Success != status || !type)
162 if (type != XA_CARDINAL)
164 g_warning ("_GTK_NATURAL_SIZE property has wrong type: %d\n", (int)type);
170 g_warning ("_GTK_NATURAL_SIZE too short\n");
175 data_long = (gint32*) data;
176 priv->natural_width = MAX (1, data_long[0]);
177 priv->natural_height = MAX (1, data_long[1]);
184 _gtk_socket_windowing_send_key_event (GtkSocket *socket,
186 gboolean mask_key_presses)
189 GdkScreen *screen = gdk_drawable_get_screen (socket->plug_window);
191 memset (&xkey, 0, sizeof (xkey));
192 xkey.type = (gdk_event->type == GDK_KEY_PRESS) ? KeyPress : KeyRelease;
193 xkey.window = GDK_WINDOW_XWINDOW (socket->plug_window);
194 xkey.root = GDK_WINDOW_XWINDOW (gdk_screen_get_root_window (screen));
195 xkey.subwindow = None;
196 xkey.time = gdk_event->key.time;
201 xkey.state = gdk_event->key.state;
202 xkey.keycode = gdk_event->key.hardware_keycode;
203 xkey.same_screen = True;/* FIXME ? */
205 gdk_error_trap_push ();
206 XSendEvent (GDK_WINDOW_XDISPLAY (socket->plug_window),
207 GDK_WINDOW_XWINDOW (socket->plug_window),
209 (mask_key_presses ? KeyPressMask : NoEventMask),
211 gdk_display_sync (gdk_screen_get_display (screen));
212 gdk_error_trap_pop ();
216 _gtk_socket_windowing_focus_change (GtkSocket *socket,
220 _gtk_xembed_send_focus_message (socket->plug_window,
221 XEMBED_FOCUS_IN, XEMBED_FOCUS_CURRENT);
223 _gtk_xembed_send_message (socket->plug_window,
224 XEMBED_FOCUS_OUT, 0, 0, 0);
228 _gtk_socket_windowing_update_active (GtkSocket *socket,
231 _gtk_xembed_send_message (socket->plug_window,
232 active ? XEMBED_WINDOW_ACTIVATE : XEMBED_WINDOW_DEACTIVATE,
237 _gtk_socket_windowing_update_modality (GtkSocket *socket,
240 _gtk_xembed_send_message (socket->plug_window,
241 modality ? XEMBED_MODALITY_ON : XEMBED_MODALITY_OFF,
246 _gtk_socket_windowing_focus (GtkSocket *socket,
247 GtkDirectionType direction)
255 case GTK_DIR_TAB_BACKWARD:
256 detail = XEMBED_FOCUS_LAST;
260 case GTK_DIR_TAB_FORWARD:
261 detail = XEMBED_FOCUS_FIRST;
265 _gtk_xembed_send_focus_message (socket->plug_window, XEMBED_FOCUS_IN, detail);
269 _gtk_socket_windowing_send_configure_event (GtkSocket *socket)
271 XConfigureEvent xconfigure;
274 g_return_if_fail (socket->plug_window != NULL);
276 memset (&xconfigure, 0, sizeof (xconfigure));
277 xconfigure.type = ConfigureNotify;
279 xconfigure.event = GDK_WINDOW_XWINDOW (socket->plug_window);
280 xconfigure.window = GDK_WINDOW_XWINDOW (socket->plug_window);
282 /* The ICCCM says that synthetic events should have root relative
283 * coordinates. We still aren't really ICCCM compliant, since
284 * we don't send events when the real toplevel is moved.
286 gdk_error_trap_push ();
287 gdk_window_get_origin (socket->plug_window, &x, &y);
288 gdk_error_trap_pop ();
292 xconfigure.width = GTK_WIDGET(socket)->allocation.width;
293 xconfigure.height = GTK_WIDGET(socket)->allocation.height;
295 xconfigure.border_width = 0;
296 xconfigure.above = None;
297 xconfigure.override_redirect = False;
299 gdk_error_trap_push ();
300 XSendEvent (GDK_WINDOW_XDISPLAY (socket->plug_window),
301 GDK_WINDOW_XWINDOW (socket->plug_window),
302 False, NoEventMask, (XEvent *)&xconfigure);
303 gdk_display_sync (gtk_widget_get_display (GTK_WIDGET (socket)));
304 gdk_error_trap_pop ();
308 _gtk_socket_windowing_select_plug_window_input (GtkSocket *socket)
310 XSelectInput (GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (GTK_WIDGET (socket))),
311 GDK_WINDOW_XWINDOW (socket->plug_window),
312 StructureNotifyMask | PropertyChangeMask);
316 _gtk_socket_windowing_embed_get_info (GtkSocket *socket)
318 unsigned long version;
321 socket->xembed_version = -1;
322 if (xembed_get_info (socket->plug_window, &version, &flags))
324 socket->xembed_version = MIN (GTK_XEMBED_PROTOCOL_VERSION, version);
325 socket->is_mapped = (flags & XEMBED_MAPPED) != 0;
329 /* FIXME, we should probably actually check the state before we started */
330 socket->is_mapped = TRUE;
335 _gtk_socket_windowing_embed_notify (GtkSocket *socket)
338 GdkDisplay *display = gtk_widget_get_display (GTK_WIDGET (socket));
340 XFixesChangeSaveSet (GDK_DISPLAY_XDISPLAY (display),
341 GDK_WINDOW_XWINDOW (socket->plug_window),
342 SetModeInsert, SaveSetRoot, SaveSetUnmap);
344 _gtk_xembed_send_message (socket->plug_window,
345 XEMBED_EMBEDDED_NOTIFY, 0,
346 GDK_WINDOW_XWINDOW (GTK_WIDGET (socket)->window),
347 socket->xembed_version);
351 xembed_get_info (GdkWindow *window,
352 unsigned long *version,
353 unsigned long *flags)
355 GdkDisplay *display = gdk_drawable_get_display (window);
356 Atom xembed_info_atom = gdk_x11_get_xatom_by_name_for_display (display, "_XEMBED_INFO");
359 unsigned long nitems, bytes_after;
361 unsigned long *data_long;
364 gdk_error_trap_push();
365 status = XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display),
366 GDK_WINDOW_XWINDOW (window),
369 xembed_info_atom, &type, &format,
370 &nitems, &bytes_after, &data);
371 gdk_error_trap_pop();
373 if (status != Success)
374 return FALSE; /* Window vanished? */
376 if (type == None) /* No info property */
379 if (type != xembed_info_atom)
381 g_warning ("_XEMBED_INFO property has wrong type\n");
387 g_warning ("_XEMBED_INFO too short\n");
392 data_long = (unsigned long *)data;
394 *version = data_long[0];
396 *flags = data_long[1] & XEMBED_MAPPED;
403 _gtk_socket_windowing_embed_get_focus_wrapped (void)
405 return _gtk_xembed_get_focus_wrapped ();
409 _gtk_socket_windowing_embed_set_focus_wrapped (void)
411 _gtk_xembed_set_focus_wrapped ();
415 handle_xembed_message (GtkSocket *socket,
416 XEmbedMessageType message,
422 GTK_NOTE (PLUGSOCKET,
423 g_message ("GtkSocket: %s received", _gtk_xembed_message_name (message)));
427 case XEMBED_EMBEDDED_NOTIFY:
428 case XEMBED_WINDOW_ACTIVATE:
429 case XEMBED_WINDOW_DEACTIVATE:
430 case XEMBED_MODALITY_ON:
431 case XEMBED_MODALITY_OFF:
432 case XEMBED_FOCUS_IN:
433 case XEMBED_FOCUS_OUT:
434 g_warning ("GtkSocket: Invalid _XEMBED message %s received", _gtk_xembed_message_name (message));
437 case XEMBED_REQUEST_FOCUS:
438 _gtk_socket_claim_focus (socket, TRUE);
441 case XEMBED_FOCUS_NEXT:
442 case XEMBED_FOCUS_PREV:
443 _gtk_socket_advance_toplevel_focus (socket,
444 (message == XEMBED_FOCUS_NEXT ?
445 GTK_DIR_TAB_FORWARD : GTK_DIR_TAB_BACKWARD));
448 case XEMBED_GTK_GRAB_KEY:
449 _gtk_socket_add_grabbed_key (socket, data1, data2);
451 case XEMBED_GTK_UNGRAB_KEY:
452 _gtk_socket_remove_grabbed_key (socket, data1, data2);
455 case XEMBED_GRAB_KEY:
456 case XEMBED_UNGRAB_KEY:
460 GTK_NOTE (PLUGSOCKET,
461 g_message ("GtkSocket: Ignoring unknown _XEMBED message of type %d", message));
467 _gtk_socket_windowing_filter_func (GdkXEvent *gdk_xevent,
476 GdkFilterReturn return_val;
478 socket = GTK_SOCKET (data);
480 return_val = GDK_FILTER_CONTINUE;
482 if (socket->plug_widget)
485 widget = GTK_WIDGET (socket);
486 xevent = (XEvent *)gdk_xevent;
487 display = gtk_widget_get_display (widget);
489 switch (xevent->type)
492 if (xevent->xclient.message_type == gdk_x11_get_xatom_by_name_for_display (display, "_XEMBED"))
494 _gtk_xembed_push_message (xevent);
495 handle_xembed_message (socket,
496 xevent->xclient.data.l[1],
497 xevent->xclient.data.l[2],
498 xevent->xclient.data.l[3],
499 xevent->xclient.data.l[4],
500 xevent->xclient.data.l[0]);
501 _gtk_xembed_pop_message ();
503 return_val = GDK_FILTER_REMOVE;
509 XCreateWindowEvent *xcwe = &xevent->xcreatewindow;
511 if (!socket->plug_window)
513 _gtk_socket_add_window (socket, xcwe->window, FALSE);
515 if (socket->plug_window)
517 GTK_NOTE (PLUGSOCKET, g_message ("GtkSocket - window created"));
521 return_val = GDK_FILTER_REMOVE;
526 case ConfigureRequest:
528 XConfigureRequestEvent *xcre = &xevent->xconfigurerequest;
530 if (!socket->plug_window)
531 _gtk_socket_add_window (socket, xcre->window, FALSE);
533 if (socket->plug_window)
535 GtkSocketPrivate *private = _gtk_socket_get_private (socket);
537 if (xcre->value_mask & (CWWidth | CWHeight))
539 GTK_NOTE (PLUGSOCKET,
540 g_message ("GtkSocket - configure request: %d %d",
541 socket->request_width,
542 socket->request_height));
544 private->resize_count++;
545 gtk_widget_queue_resize (widget);
547 else if (xcre->value_mask & (CWX | CWY))
549 _gtk_socket_windowing_send_configure_event (socket);
551 /* Ignore stacking requests. */
553 return_val = GDK_FILTER_REMOVE;
560 XDestroyWindowEvent *xdwe = &xevent->xdestroywindow;
562 /* Note that we get destroy notifies both from SubstructureNotify on
563 * our window and StructureNotify on socket->plug_window
565 if (socket->plug_window && (xdwe->window == GDK_WINDOW_XWINDOW (socket->plug_window)))
569 GTK_NOTE (PLUGSOCKET, g_message ("GtkSocket - destroy notify"));
571 gdk_window_destroy_notify (socket->plug_window);
572 _gtk_socket_end_embedding (socket);
574 g_object_ref (widget);
575 g_signal_emit_by_name (widget, "plug-removed", &result);
577 gtk_widget_destroy (widget);
578 g_object_unref (widget);
580 return_val = GDK_FILTER_REMOVE;
586 if (xevent->xfocus.mode == EMBEDDED_APP_WANTS_FOCUS)
588 _gtk_socket_claim_focus (socket, TRUE);
590 return_val = GDK_FILTER_REMOVE;
593 return_val = GDK_FILTER_REMOVE;
596 if (!socket->plug_window)
598 _gtk_socket_add_window (socket, xevent->xmaprequest.window, FALSE);
601 if (socket->plug_window)
603 GTK_NOTE (PLUGSOCKET, g_message ("GtkSocket - Map Request"));
605 _gtk_socket_handle_map_request (socket);
606 return_val = GDK_FILTER_REMOVE;
610 if (socket->plug_window &&
611 xevent->xproperty.window == GDK_WINDOW_XWINDOW (socket->plug_window))
613 GdkDragProtocol protocol;
615 if (xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "WM_NORMAL_HINTS"))
617 GTK_NOTE (PLUGSOCKET, g_message ("GtkSocket - received PropertyNotify for plug's WM_NORMAL_HINTS"));
618 socket->have_size = FALSE;
619 gtk_widget_queue_resize (widget);
620 return_val = GDK_FILTER_REMOVE;
622 else if ((xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "XdndAware")) ||
623 (xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_RECEIVER_INFO")))
625 gdk_error_trap_push ();
626 if (gdk_drag_get_protocol_for_display (display,
627 xevent->xproperty.window,
629 gtk_drag_dest_set_proxy (GTK_WIDGET (socket),
633 gdk_display_sync (display);
634 gdk_error_trap_pop ();
635 return_val = GDK_FILTER_REMOVE;
637 else if (xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "_XEMBED_INFO"))
641 if (xembed_get_info (socket->plug_window, NULL, &flags))
643 gboolean was_mapped = socket->is_mapped;
644 gboolean is_mapped = (flags & XEMBED_MAPPED) != 0;
646 if (was_mapped != is_mapped)
649 _gtk_socket_handle_map_request (socket);
652 gdk_error_trap_push ();
653 gdk_window_show (socket->plug_window);
655 gdk_error_trap_pop ();
657 _gtk_socket_unmap_notify (socket);
661 return_val = GDK_FILTER_REMOVE;
663 else if (xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "_GTK_NATURAL_SIZE"))
665 _gtk_socket_windowing_get_natural_size (socket);
671 XReparentEvent *xre = &xevent->xreparent;
673 GTK_NOTE (PLUGSOCKET, g_message ("GtkSocket - ReparentNotify received"));
674 if (!socket->plug_window && xre->parent == GDK_WINDOW_XWINDOW (widget->window))
676 _gtk_socket_add_window (socket, xre->window, FALSE);
678 if (socket->plug_window)
680 GTK_NOTE (PLUGSOCKET, g_message ("GtkSocket - window reparented"));
683 return_val = GDK_FILTER_REMOVE;
687 if (socket->plug_window && xre->window == GDK_WINDOW_XWINDOW (socket->plug_window) && xre->parent != GDK_WINDOW_XWINDOW (widget->window))
691 _gtk_socket_end_embedding (socket);
693 g_object_ref (widget);
694 g_signal_emit_by_name (widget, "plug-removed", &result);
696 gtk_widget_destroy (widget);
697 g_object_unref (widget);
699 return_val = GDK_FILTER_REMOVE;
706 if (socket->plug_window &&
707 xevent->xunmap.window == GDK_WINDOW_XWINDOW (socket->plug_window))
709 GTK_NOTE (PLUGSOCKET, g_message ("GtkSocket - Unmap notify"));
711 _gtk_socket_unmap_notify (socket);
712 return_val = GDK_FILTER_REMOVE;