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"
44 #include <X11/extensions/Xfixes.h>
47 #include "gtkxembed.h"
49 static gboolean xembed_get_info (GdkWindow *gdk_window,
50 unsigned long *version,
51 unsigned long *flags);
54 #define EMBEDDED_APP_WANTS_FOCUS NotifyNormal+20
57 _gtk_socket_windowing_get_id (GtkSocket *socket)
59 return GDK_WINDOW_XWINDOW (GTK_WIDGET (socket)->window);
63 _gtk_socket_windowing_realize_window (GtkSocket *socket)
65 GdkWindow *window = GTK_WIDGET (socket)->window;
66 XWindowAttributes xattrs;
68 XGetWindowAttributes (GDK_WINDOW_XDISPLAY (window),
69 GDK_WINDOW_XWINDOW (window),
72 /* Sooooo, it turns out that mozilla, as per the gtk2xt code selects
73 for input on the socket with a mask of 0x0fffff (for god knows why)
74 which includes ButtonPressMask causing a BadAccess if someone else
75 also selects for this. As per the client-side windows merge we always
76 normally selects for button press so we can emulate it on client
77 side children that selects for button press. However, we don't need
78 this for GtkSocket, so we unselect it here, fixing the crashes in
80 XSelectInput (GDK_WINDOW_XDISPLAY (window),
81 GDK_WINDOW_XWINDOW (window),
82 (xattrs.your_event_mask & ~ButtonPressMask) |
83 SubstructureNotifyMask | SubstructureRedirectMask);
87 _gtk_socket_windowing_end_embedding_toplevel (GtkSocket *socket)
89 gtk_window_remove_embedded_xid (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (socket))),
90 GDK_WINDOW_XWINDOW (socket->plug_window));
94 _gtk_socket_windowing_size_request (GtkSocket *socket)
99 gdk_error_trap_push ();
101 socket->request_width = 1;
102 socket->request_height = 1;
104 if (XGetWMNormalHints (GDK_WINDOW_XDISPLAY (socket->plug_window),
105 GDK_WINDOW_XWINDOW (socket->plug_window),
108 if (hints.flags & PMinSize)
110 socket->request_width = MAX (hints.min_width, 1);
111 socket->request_height = MAX (hints.min_height, 1);
113 else if (hints.flags & PBaseSize)
115 socket->request_width = MAX (hints.base_width, 1);
116 socket->request_height = MAX (hints.base_height, 1);
119 socket->have_size = TRUE;
121 gdk_error_trap_pop ();
125 _gtk_socket_windowing_send_key_event (GtkSocket *socket,
127 gboolean mask_key_presses)
130 GdkScreen *screen = gdk_drawable_get_screen (socket->plug_window);
132 memset (&xkey, 0, sizeof (xkey));
133 xkey.type = (gdk_event->type == GDK_KEY_PRESS) ? KeyPress : KeyRelease;
134 xkey.window = GDK_WINDOW_XWINDOW (socket->plug_window);
135 xkey.root = GDK_WINDOW_XWINDOW (gdk_screen_get_root_window (screen));
136 xkey.subwindow = None;
137 xkey.time = gdk_event->key.time;
142 xkey.state = gdk_event->key.state;
143 xkey.keycode = gdk_event->key.hardware_keycode;
144 xkey.same_screen = True;/* FIXME ? */
146 gdk_error_trap_push ();
147 XSendEvent (GDK_WINDOW_XDISPLAY (socket->plug_window),
148 GDK_WINDOW_XWINDOW (socket->plug_window),
150 (mask_key_presses ? KeyPressMask : NoEventMask),
152 gdk_display_sync (gdk_screen_get_display (screen));
153 gdk_error_trap_pop ();
157 _gtk_socket_windowing_focus_change (GtkSocket *socket,
161 _gtk_xembed_send_focus_message (socket->plug_window,
162 XEMBED_FOCUS_IN, XEMBED_FOCUS_CURRENT);
164 _gtk_xembed_send_message (socket->plug_window,
165 XEMBED_FOCUS_OUT, 0, 0, 0);
169 _gtk_socket_windowing_update_active (GtkSocket *socket,
172 _gtk_xembed_send_message (socket->plug_window,
173 active ? XEMBED_WINDOW_ACTIVATE : XEMBED_WINDOW_DEACTIVATE,
178 _gtk_socket_windowing_update_modality (GtkSocket *socket,
181 _gtk_xembed_send_message (socket->plug_window,
182 modality ? XEMBED_MODALITY_ON : XEMBED_MODALITY_OFF,
187 _gtk_socket_windowing_focus (GtkSocket *socket,
188 GtkDirectionType direction)
196 case GTK_DIR_TAB_BACKWARD:
197 detail = XEMBED_FOCUS_LAST;
201 case GTK_DIR_TAB_FORWARD:
202 detail = XEMBED_FOCUS_FIRST;
206 _gtk_xembed_send_focus_message (socket->plug_window, XEMBED_FOCUS_IN, detail);
210 _gtk_socket_windowing_send_configure_event (GtkSocket *socket)
212 XConfigureEvent xconfigure;
215 g_return_if_fail (socket->plug_window != NULL);
217 memset (&xconfigure, 0, sizeof (xconfigure));
218 xconfigure.type = ConfigureNotify;
220 xconfigure.event = GDK_WINDOW_XWINDOW (socket->plug_window);
221 xconfigure.window = GDK_WINDOW_XWINDOW (socket->plug_window);
223 /* The ICCCM says that synthetic events should have root relative
224 * coordinates. We still aren't really ICCCM compliant, since
225 * we don't send events when the real toplevel is moved.
227 gdk_error_trap_push ();
228 gdk_window_get_origin (socket->plug_window, &x, &y);
229 gdk_error_trap_pop ();
233 xconfigure.width = GTK_WIDGET(socket)->allocation.width;
234 xconfigure.height = GTK_WIDGET(socket)->allocation.height;
236 xconfigure.border_width = 0;
237 xconfigure.above = None;
238 xconfigure.override_redirect = False;
240 gdk_error_trap_push ();
241 XSendEvent (GDK_WINDOW_XDISPLAY (socket->plug_window),
242 GDK_WINDOW_XWINDOW (socket->plug_window),
243 False, NoEventMask, (XEvent *)&xconfigure);
244 gdk_display_sync (gtk_widget_get_display (GTK_WIDGET (socket)));
245 gdk_error_trap_pop ();
249 _gtk_socket_windowing_select_plug_window_input (GtkSocket *socket)
251 XSelectInput (GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (GTK_WIDGET (socket))),
252 GDK_WINDOW_XWINDOW (socket->plug_window),
253 StructureNotifyMask | PropertyChangeMask);
257 _gtk_socket_windowing_embed_get_info (GtkSocket *socket)
259 unsigned long version;
262 socket->xembed_version = -1;
263 if (xembed_get_info (socket->plug_window, &version, &flags))
265 socket->xembed_version = MIN (GTK_XEMBED_PROTOCOL_VERSION, version);
266 socket->is_mapped = (flags & XEMBED_MAPPED) != 0;
270 /* FIXME, we should probably actually check the state before we started */
271 socket->is_mapped = TRUE;
276 _gtk_socket_windowing_embed_notify (GtkSocket *socket)
279 GdkDisplay *display = gtk_widget_get_display (GTK_WIDGET (socket));
281 XFixesChangeSaveSet (GDK_DISPLAY_XDISPLAY (display),
282 GDK_WINDOW_XWINDOW (socket->plug_window),
283 SetModeInsert, SaveSetRoot, SaveSetUnmap);
285 _gtk_xembed_send_message (socket->plug_window,
286 XEMBED_EMBEDDED_NOTIFY, 0,
287 GDK_WINDOW_XWINDOW (GTK_WIDGET (socket)->window),
288 socket->xembed_version);
292 xembed_get_info (GdkWindow *window,
293 unsigned long *version,
294 unsigned long *flags)
296 GdkDisplay *display = gdk_drawable_get_display (window);
297 Atom xembed_info_atom = gdk_x11_get_xatom_by_name_for_display (display, "_XEMBED_INFO");
300 unsigned long nitems, bytes_after;
302 unsigned long *data_long;
305 gdk_error_trap_push();
306 status = XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display),
307 GDK_WINDOW_XWINDOW (window),
310 xembed_info_atom, &type, &format,
311 &nitems, &bytes_after, &data);
312 gdk_error_trap_pop();
314 if (status != Success)
315 return FALSE; /* Window vanished? */
317 if (type == None) /* No info property */
320 if (type != xembed_info_atom)
322 g_warning ("_XEMBED_INFO property has wrong type\n");
328 g_warning ("_XEMBED_INFO too short\n");
333 data_long = (unsigned long *)data;
335 *version = data_long[0];
337 *flags = data_long[1] & XEMBED_MAPPED;
344 _gtk_socket_windowing_embed_get_focus_wrapped (void)
346 return _gtk_xembed_get_focus_wrapped ();
350 _gtk_socket_windowing_embed_set_focus_wrapped (void)
352 _gtk_xembed_set_focus_wrapped ();
356 handle_xembed_message (GtkSocket *socket,
357 XEmbedMessageType message,
363 GTK_NOTE (PLUGSOCKET,
364 g_message ("GtkSocket: %s received", _gtk_xembed_message_name (message)));
368 case XEMBED_EMBEDDED_NOTIFY:
369 case XEMBED_WINDOW_ACTIVATE:
370 case XEMBED_WINDOW_DEACTIVATE:
371 case XEMBED_MODALITY_ON:
372 case XEMBED_MODALITY_OFF:
373 case XEMBED_FOCUS_IN:
374 case XEMBED_FOCUS_OUT:
375 g_warning ("GtkSocket: Invalid _XEMBED message %s received", _gtk_xembed_message_name (message));
378 case XEMBED_REQUEST_FOCUS:
379 _gtk_socket_claim_focus (socket, TRUE);
382 case XEMBED_FOCUS_NEXT:
383 case XEMBED_FOCUS_PREV:
384 _gtk_socket_advance_toplevel_focus (socket,
385 (message == XEMBED_FOCUS_NEXT ?
386 GTK_DIR_TAB_FORWARD : GTK_DIR_TAB_BACKWARD));
389 case XEMBED_GTK_GRAB_KEY:
390 _gtk_socket_add_grabbed_key (socket, data1, data2);
392 case XEMBED_GTK_UNGRAB_KEY:
393 _gtk_socket_remove_grabbed_key (socket, data1, data2);
396 case XEMBED_GRAB_KEY:
397 case XEMBED_UNGRAB_KEY:
401 GTK_NOTE (PLUGSOCKET,
402 g_message ("GtkSocket: Ignoring unknown _XEMBED message of type %d", message));
408 _gtk_socket_windowing_filter_func (GdkXEvent *gdk_xevent,
417 GdkFilterReturn return_val;
419 socket = GTK_SOCKET (data);
421 return_val = GDK_FILTER_CONTINUE;
423 if (socket->plug_widget)
426 widget = GTK_WIDGET (socket);
427 xevent = (XEvent *)gdk_xevent;
428 display = gtk_widget_get_display (widget);
430 switch (xevent->type)
433 if (xevent->xclient.message_type == gdk_x11_get_xatom_by_name_for_display (display, "_XEMBED"))
435 _gtk_xembed_push_message (xevent);
436 handle_xembed_message (socket,
437 xevent->xclient.data.l[1],
438 xevent->xclient.data.l[2],
439 xevent->xclient.data.l[3],
440 xevent->xclient.data.l[4],
441 xevent->xclient.data.l[0]);
442 _gtk_xembed_pop_message ();
444 return_val = GDK_FILTER_REMOVE;
450 XCreateWindowEvent *xcwe = &xevent->xcreatewindow;
452 if (!socket->plug_window)
454 _gtk_socket_add_window (socket, xcwe->window, FALSE);
456 if (socket->plug_window)
458 GTK_NOTE (PLUGSOCKET, g_message ("GtkSocket - window created"));
462 return_val = GDK_FILTER_REMOVE;
467 case ConfigureRequest:
469 XConfigureRequestEvent *xcre = &xevent->xconfigurerequest;
471 if (!socket->plug_window)
472 _gtk_socket_add_window (socket, xcre->window, FALSE);
474 if (socket->plug_window)
476 GtkSocketPrivate *private = _gtk_socket_get_private (socket);
478 if (xcre->value_mask & (CWWidth | CWHeight))
480 GTK_NOTE (PLUGSOCKET,
481 g_message ("GtkSocket - configure request: %d %d",
482 socket->request_width,
483 socket->request_height));
485 private->resize_count++;
486 gtk_widget_queue_resize (widget);
488 else if (xcre->value_mask & (CWX | CWY))
490 _gtk_socket_windowing_send_configure_event (socket);
492 /* Ignore stacking requests. */
494 return_val = GDK_FILTER_REMOVE;
501 XDestroyWindowEvent *xdwe = &xevent->xdestroywindow;
503 /* Note that we get destroy notifies both from SubstructureNotify on
504 * our window and StructureNotify on socket->plug_window
506 if (socket->plug_window && (xdwe->window == GDK_WINDOW_XWINDOW (socket->plug_window)))
510 GTK_NOTE (PLUGSOCKET, g_message ("GtkSocket - destroy notify"));
512 gdk_window_destroy_notify (socket->plug_window);
513 _gtk_socket_end_embedding (socket);
515 g_object_ref (widget);
516 g_signal_emit_by_name (widget, "plug-removed", &result);
518 gtk_widget_destroy (widget);
519 g_object_unref (widget);
521 return_val = GDK_FILTER_REMOVE;
527 if (xevent->xfocus.mode == EMBEDDED_APP_WANTS_FOCUS)
529 _gtk_socket_claim_focus (socket, TRUE);
531 return_val = GDK_FILTER_REMOVE;
534 return_val = GDK_FILTER_REMOVE;
537 if (!socket->plug_window)
539 _gtk_socket_add_window (socket, xevent->xmaprequest.window, FALSE);
542 if (socket->plug_window)
544 GTK_NOTE (PLUGSOCKET, g_message ("GtkSocket - Map Request"));
546 _gtk_socket_handle_map_request (socket);
547 return_val = GDK_FILTER_REMOVE;
551 if (socket->plug_window &&
552 xevent->xproperty.window == GDK_WINDOW_XWINDOW (socket->plug_window))
554 GdkDragProtocol protocol;
556 if (xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "WM_NORMAL_HINTS"))
558 GTK_NOTE (PLUGSOCKET, g_message ("GtkSocket - received PropertyNotify for plug's WM_NORMAL_HINTS"));
559 socket->have_size = FALSE;
560 gtk_widget_queue_resize (widget);
561 return_val = GDK_FILTER_REMOVE;
563 else if ((xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "XdndAware")) ||
564 (xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_RECEIVER_INFO")))
566 gdk_error_trap_push ();
567 if (gdk_drag_get_protocol_for_display (display,
568 xevent->xproperty.window,
570 gtk_drag_dest_set_proxy (GTK_WIDGET (socket),
574 gdk_display_sync (display);
575 gdk_error_trap_pop ();
576 return_val = GDK_FILTER_REMOVE;
578 else if (xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "_XEMBED_INFO"))
582 if (xembed_get_info (socket->plug_window, NULL, &flags))
584 gboolean was_mapped = socket->is_mapped;
585 gboolean is_mapped = (flags & XEMBED_MAPPED) != 0;
587 if (was_mapped != is_mapped)
590 _gtk_socket_handle_map_request (socket);
593 gdk_error_trap_push ();
594 gdk_window_show (socket->plug_window);
596 gdk_error_trap_pop ();
598 _gtk_socket_unmap_notify (socket);
602 return_val = GDK_FILTER_REMOVE;
608 XReparentEvent *xre = &xevent->xreparent;
610 GTK_NOTE (PLUGSOCKET, g_message ("GtkSocket - ReparentNotify received"));
611 if (!socket->plug_window && xre->parent == GDK_WINDOW_XWINDOW (widget->window))
613 _gtk_socket_add_window (socket, xre->window, FALSE);
615 if (socket->plug_window)
617 GTK_NOTE (PLUGSOCKET, g_message ("GtkSocket - window reparented"));
620 return_val = GDK_FILTER_REMOVE;
624 if (socket->plug_window && xre->window == GDK_WINDOW_XWINDOW (socket->plug_window) && xre->parent != GDK_WINDOW_XWINDOW (widget->window))
628 _gtk_socket_end_embedding (socket);
630 g_object_ref (widget);
631 g_signal_emit_by_name (widget, "plug-removed", &result);
633 gtk_widget_destroy (widget);
634 g_object_unref (widget);
636 return_val = GDK_FILTER_REMOVE;
643 if (socket->plug_window &&
644 xevent->xunmap.window == GDK_WINDOW_XWINDOW (socket->plug_window))
646 GTK_NOTE (PLUGSOCKET, g_message ("GtkSocket - Unmap notify"));
648 _gtk_socket_unmap_notify (socket);
649 return_val = GDK_FILTER_REMOVE;