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 gdk_error_trap_push ();
285 XFixesChangeSaveSet (GDK_DISPLAY_XDISPLAY (display),
286 GDK_WINDOW_XWINDOW (socket->plug_window),
287 SetModeInsert, SaveSetRoot, SaveSetUnmap);
288 gdk_error_trap_pop_ignored ();
290 _gtk_xembed_send_message (socket->plug_window,
291 XEMBED_EMBEDDED_NOTIFY, 0,
292 GDK_WINDOW_XWINDOW (gtk_widget_get_window (GTK_WIDGET (socket))),
293 socket->xembed_version);
297 xembed_get_info (GdkWindow *window,
298 unsigned long *version,
299 unsigned long *flags)
301 GdkDisplay *display = gdk_window_get_display (window);
302 Atom xembed_info_atom = gdk_x11_get_xatom_by_name_for_display (display, "_XEMBED_INFO");
305 unsigned long nitems, bytes_after;
307 unsigned long *data_long;
310 gdk_error_trap_push ();
311 status = XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display),
312 GDK_WINDOW_XWINDOW (window),
315 xembed_info_atom, &type, &format,
316 &nitems, &bytes_after, &data);
317 gdk_error_trap_pop_ignored ();
319 if (status != Success)
320 return FALSE; /* Window vanished? */
322 if (type == None) /* No info property */
325 if (type != xembed_info_atom)
327 g_warning ("_XEMBED_INFO property has wrong type\n");
333 g_warning ("_XEMBED_INFO too short\n");
338 data_long = (unsigned long *)data;
340 *version = data_long[0];
342 *flags = data_long[1] & XEMBED_MAPPED;
349 _gtk_socket_windowing_embed_get_focus_wrapped (void)
351 return _gtk_xembed_get_focus_wrapped ();
355 _gtk_socket_windowing_embed_set_focus_wrapped (void)
357 _gtk_xembed_set_focus_wrapped ();
361 handle_xembed_message (GtkSocket *socket,
362 XEmbedMessageType message,
368 GTK_NOTE (PLUGSOCKET,
369 g_message ("GtkSocket: %s received", _gtk_xembed_message_name (message)));
373 case XEMBED_EMBEDDED_NOTIFY:
374 case XEMBED_WINDOW_ACTIVATE:
375 case XEMBED_WINDOW_DEACTIVATE:
376 case XEMBED_MODALITY_ON:
377 case XEMBED_MODALITY_OFF:
378 case XEMBED_FOCUS_IN:
379 case XEMBED_FOCUS_OUT:
380 g_warning ("GtkSocket: Invalid _XEMBED message %s received", _gtk_xembed_message_name (message));
383 case XEMBED_REQUEST_FOCUS:
384 _gtk_socket_claim_focus (socket, TRUE);
387 case XEMBED_FOCUS_NEXT:
388 case XEMBED_FOCUS_PREV:
389 _gtk_socket_advance_toplevel_focus (socket,
390 (message == XEMBED_FOCUS_NEXT ?
391 GTK_DIR_TAB_FORWARD : GTK_DIR_TAB_BACKWARD));
394 case XEMBED_GTK_GRAB_KEY:
395 _gtk_socket_add_grabbed_key (socket, data1, data2);
397 case XEMBED_GTK_UNGRAB_KEY:
398 _gtk_socket_remove_grabbed_key (socket, data1, data2);
401 case XEMBED_GRAB_KEY:
402 case XEMBED_UNGRAB_KEY:
406 GTK_NOTE (PLUGSOCKET,
407 g_message ("GtkSocket: Ignoring unknown _XEMBED message of type %d", message));
413 _gtk_socket_windowing_filter_func (GdkXEvent *gdk_xevent,
422 GdkFilterReturn return_val;
424 socket = GTK_SOCKET (data);
426 return_val = GDK_FILTER_CONTINUE;
428 if (socket->plug_widget)
431 widget = GTK_WIDGET (socket);
432 xevent = (XEvent *)gdk_xevent;
433 display = gtk_widget_get_display (widget);
435 switch (xevent->type)
438 if (xevent->xclient.message_type == gdk_x11_get_xatom_by_name_for_display (display, "_XEMBED"))
440 _gtk_xembed_push_message (xevent);
441 handle_xembed_message (socket,
442 xevent->xclient.data.l[1],
443 xevent->xclient.data.l[2],
444 xevent->xclient.data.l[3],
445 xevent->xclient.data.l[4],
446 xevent->xclient.data.l[0]);
447 _gtk_xembed_pop_message ();
449 return_val = GDK_FILTER_REMOVE;
455 XCreateWindowEvent *xcwe = &xevent->xcreatewindow;
457 if (!socket->plug_window)
459 _gtk_socket_add_window (socket, xcwe->window, FALSE);
461 if (socket->plug_window)
463 GTK_NOTE (PLUGSOCKET, g_message ("GtkSocket - window created"));
467 return_val = GDK_FILTER_REMOVE;
472 case ConfigureRequest:
474 XConfigureRequestEvent *xcre = &xevent->xconfigurerequest;
476 if (!socket->plug_window)
477 _gtk_socket_add_window (socket, xcre->window, FALSE);
479 if (socket->plug_window)
481 GtkSocketPrivate *private = _gtk_socket_get_private (socket);
483 if (xcre->value_mask & (CWWidth | CWHeight))
485 GTK_NOTE (PLUGSOCKET,
486 g_message ("GtkSocket - configure request: %d %d",
487 socket->request_width,
488 socket->request_height));
490 private->resize_count++;
491 gtk_widget_queue_resize (widget);
493 else if (xcre->value_mask & (CWX | CWY))
495 _gtk_socket_windowing_send_configure_event (socket);
497 /* Ignore stacking requests. */
499 return_val = GDK_FILTER_REMOVE;
506 XDestroyWindowEvent *xdwe = &xevent->xdestroywindow;
508 /* Note that we get destroy notifies both from SubstructureNotify on
509 * our window and StructureNotify on socket->plug_window
511 if (socket->plug_window && (xdwe->window == GDK_WINDOW_XWINDOW (socket->plug_window)))
515 GTK_NOTE (PLUGSOCKET, g_message ("GtkSocket - destroy notify"));
517 gdk_window_destroy_notify (socket->plug_window);
518 _gtk_socket_end_embedding (socket);
520 g_object_ref (widget);
521 g_signal_emit_by_name (widget, "plug-removed", &result);
523 gtk_widget_destroy (widget);
524 g_object_unref (widget);
526 return_val = GDK_FILTER_REMOVE;
532 if (xevent->xfocus.mode == EMBEDDED_APP_WANTS_FOCUS)
534 _gtk_socket_claim_focus (socket, TRUE);
536 return_val = GDK_FILTER_REMOVE;
539 return_val = GDK_FILTER_REMOVE;
542 if (!socket->plug_window)
544 _gtk_socket_add_window (socket, xevent->xmaprequest.window, FALSE);
547 if (socket->plug_window)
549 GTK_NOTE (PLUGSOCKET, g_message ("GtkSocket - Map Request"));
551 _gtk_socket_handle_map_request (socket);
552 return_val = GDK_FILTER_REMOVE;
556 if (socket->plug_window &&
557 xevent->xproperty.window == GDK_WINDOW_XWINDOW (socket->plug_window))
559 GdkDragProtocol protocol;
561 if (xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "WM_NORMAL_HINTS"))
563 GTK_NOTE (PLUGSOCKET, g_message ("GtkSocket - received PropertyNotify for plug's WM_NORMAL_HINTS"));
564 socket->have_size = FALSE;
565 gtk_widget_queue_resize (widget);
566 return_val = GDK_FILTER_REMOVE;
568 else if ((xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "XdndAware")) ||
569 (xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_RECEIVER_INFO")))
571 gdk_error_trap_push ();
572 if (gdk_drag_get_protocol_for_display (display,
573 xevent->xproperty.window,
575 gtk_drag_dest_set_proxy (GTK_WIDGET (socket),
579 gdk_error_trap_pop_ignored ();
580 return_val = GDK_FILTER_REMOVE;
582 else if (xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "_XEMBED_INFO"))
586 if (xembed_get_info (socket->plug_window, NULL, &flags))
588 gboolean was_mapped = socket->is_mapped;
589 gboolean is_mapped = (flags & XEMBED_MAPPED) != 0;
591 if (was_mapped != is_mapped)
594 _gtk_socket_handle_map_request (socket);
597 gdk_error_trap_push ();
598 gdk_window_show (socket->plug_window);
599 gdk_error_trap_pop_ignored ();
601 _gtk_socket_unmap_notify (socket);
605 return_val = GDK_FILTER_REMOVE;
612 XReparentEvent *xre = &xevent->xreparent;
614 window = gtk_widget_get_window (widget);
616 GTK_NOTE (PLUGSOCKET, g_message ("GtkSocket - ReparentNotify received"));
617 if (!socket->plug_window &&
618 xre->parent == GDK_WINDOW_XWINDOW (window))
620 _gtk_socket_add_window (socket, xre->window, FALSE);
622 if (socket->plug_window)
624 GTK_NOTE (PLUGSOCKET, g_message ("GtkSocket - window reparented"));
627 return_val = GDK_FILTER_REMOVE;
631 if (socket->plug_window &&
632 xre->window == GDK_WINDOW_XWINDOW (socket->plug_window) &&
633 xre->parent != GDK_WINDOW_XWINDOW (window))
637 _gtk_socket_end_embedding (socket);
639 g_object_ref (widget);
640 g_signal_emit_by_name (widget, "plug-removed", &result);
642 gtk_widget_destroy (widget);
643 g_object_unref (widget);
645 return_val = GDK_FILTER_REMOVE;
652 if (socket->plug_window &&
653 xevent->xunmap.window == GDK_WINDOW_XWINDOW (socket->plug_window))
655 GTK_NOTE (PLUGSOCKET, g_message ("GtkSocket - Unmap notify"));
657 _gtk_socket_unmap_notify (socket);
658 return_val = GDK_FILTER_REMOVE;