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"
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 (socket)->window);
64 _gtk_socket_windowing_realize_window (GtkSocket *socket)
66 GdkWindow *window = GTK_WIDGET (socket)->window;
67 XWindowAttributes xattrs;
69 XGetWindowAttributes (GDK_WINDOW_XDISPLAY (window),
70 GDK_WINDOW_XWINDOW (window),
73 XSelectInput (GDK_WINDOW_XDISPLAY (window),
74 GDK_WINDOW_XWINDOW (window),
75 xattrs.your_event_mask |
76 SubstructureNotifyMask | SubstructureRedirectMask);
80 _gtk_socket_windowing_end_embedding_toplevel (GtkSocket *socket)
82 gtk_window_remove_embedded_xid (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (socket))),
83 GDK_WINDOW_XWINDOW (socket->plug_window));
87 _gtk_socket_windowing_size_request (GtkSocket *socket)
92 gdk_error_trap_push ();
94 socket->request_width = 1;
95 socket->request_height = 1;
97 if (XGetWMNormalHints (GDK_WINDOW_XDISPLAY (socket->plug_window),
98 GDK_WINDOW_XWINDOW (socket->plug_window),
101 if (hints.flags & PMinSize)
103 socket->request_width = MAX (hints.min_width, 1);
104 socket->request_height = MAX (hints.min_height, 1);
106 else if (hints.flags & PBaseSize)
108 socket->request_width = MAX (hints.base_width, 1);
109 socket->request_height = MAX (hints.base_height, 1);
112 socket->have_size = TRUE;
114 gdk_error_trap_pop ();
118 _gtk_socket_windowing_send_key_event (GtkSocket *socket,
120 gboolean mask_key_presses)
123 GdkScreen *screen = gdk_drawable_get_screen (socket->plug_window);
125 xevent.xkey.type = (gdk_event->type == GDK_KEY_PRESS) ? KeyPress : KeyRelease;
126 xevent.xkey.window = GDK_WINDOW_XWINDOW (socket->plug_window);
127 xevent.xkey.root = GDK_WINDOW_XWINDOW (gdk_screen_get_root_window (screen));
128 xevent.xkey.subwindow = None;
129 xevent.xkey.time = gdk_event->key.time;
132 xevent.xkey.x_root = 0;
133 xevent.xkey.y_root = 0;
134 xevent.xkey.state = gdk_event->key.state;
135 xevent.xkey.keycode = gdk_event->key.hardware_keycode;
136 xevent.xkey.same_screen = True;/* FIXME ? */
138 gdk_error_trap_push ();
139 XSendEvent (GDK_WINDOW_XDISPLAY (socket->plug_window),
140 GDK_WINDOW_XWINDOW (socket->plug_window),
142 (mask_key_presses ? KeyPressMask : NoEventMask),
144 gdk_display_sync (gdk_screen_get_display (screen));
145 gdk_error_trap_pop ();
149 _gtk_socket_windowing_focus_change (GtkSocket *socket,
153 _gtk_xembed_send_focus_message (socket->plug_window,
154 XEMBED_FOCUS_IN, XEMBED_FOCUS_CURRENT);
156 _gtk_xembed_send_message (socket->plug_window,
157 XEMBED_FOCUS_OUT, 0, 0, 0);
161 _gtk_socket_windowing_update_active (GtkSocket *socket,
164 _gtk_xembed_send_message (socket->plug_window,
165 active ? XEMBED_WINDOW_ACTIVATE : XEMBED_WINDOW_DEACTIVATE,
170 _gtk_socket_windowing_update_modality (GtkSocket *socket,
173 _gtk_xembed_send_message (socket->plug_window,
174 modality ? XEMBED_MODALITY_ON : XEMBED_MODALITY_OFF,
179 _gtk_socket_windowing_focus (GtkSocket *socket,
180 GtkDirectionType direction)
188 case GTK_DIR_TAB_BACKWARD:
189 detail = XEMBED_FOCUS_LAST;
193 case GTK_DIR_TAB_FORWARD:
194 detail = XEMBED_FOCUS_FIRST;
198 _gtk_xembed_send_focus_message (socket->plug_window, XEMBED_FOCUS_IN, detail);
202 _gtk_socket_windowing_send_configure_event (GtkSocket *socket)
207 g_return_if_fail (socket->plug_window != NULL);
209 event.xconfigure.type = ConfigureNotify;
211 event.xconfigure.event = GDK_WINDOW_XWINDOW (socket->plug_window);
212 event.xconfigure.window = GDK_WINDOW_XWINDOW (socket->plug_window);
214 /* The ICCCM says that synthetic events should have root relative
215 * coordinates. We still aren't really ICCCM compliant, since
216 * we don't send events when the real toplevel is moved.
218 gdk_error_trap_push ();
219 gdk_window_get_origin (socket->plug_window, &x, &y);
220 gdk_error_trap_pop ();
222 event.xconfigure.x = x;
223 event.xconfigure.y = y;
224 event.xconfigure.width = GTK_WIDGET(socket)->allocation.width;
225 event.xconfigure.height = GTK_WIDGET(socket)->allocation.height;
227 event.xconfigure.border_width = 0;
228 event.xconfigure.above = None;
229 event.xconfigure.override_redirect = False;
231 gdk_error_trap_push ();
232 XSendEvent (GDK_WINDOW_XDISPLAY (socket->plug_window),
233 GDK_WINDOW_XWINDOW (socket->plug_window),
234 False, NoEventMask, &event);
235 gdk_display_sync (gtk_widget_get_display (GTK_WIDGET (socket)));
236 gdk_error_trap_pop ();
240 _gtk_socket_windowing_select_plug_window_input (GtkSocket *socket)
242 XSelectInput (GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (GTK_WIDGET (socket))),
243 GDK_WINDOW_XWINDOW (socket->plug_window),
244 StructureNotifyMask | PropertyChangeMask);
248 _gtk_socket_windowing_embed_get_info (GtkSocket *socket)
250 unsigned long version;
253 socket->xembed_version = -1;
254 if (xembed_get_info (socket->plug_window, &version, &flags))
256 socket->xembed_version = MIN (GTK_XEMBED_PROTOCOL_VERSION, version);
257 socket->is_mapped = (flags & XEMBED_MAPPED) != 0;
261 /* FIXME, we should probably actually check the state before we started */
262 socket->is_mapped = TRUE;
267 _gtk_socket_windowing_embed_notify (GtkSocket *socket)
270 GdkDisplay *display = gtk_widget_get_display (GTK_WIDGET (socket));
272 XFixesChangeSaveSet (GDK_DISPLAY_XDISPLAY (display),
273 GDK_WINDOW_XWINDOW (socket->plug_window),
274 SetModeInsert, SaveSetRoot, SaveSetUnmap);
276 _gtk_xembed_send_message (socket->plug_window,
277 XEMBED_EMBEDDED_NOTIFY, 0,
278 GDK_WINDOW_XWINDOW (GTK_WIDGET (socket)->window),
279 socket->xembed_version);
283 xembed_get_info (GdkWindow *window,
284 unsigned long *version,
285 unsigned long *flags)
287 GdkDisplay *display = gdk_drawable_get_display (window);
288 Atom xembed_info_atom = gdk_x11_get_xatom_by_name_for_display (display, "_XEMBED_INFO");
291 unsigned long nitems, bytes_after;
293 unsigned long *data_long;
296 gdk_error_trap_push();
297 status = XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display),
298 GDK_WINDOW_XWINDOW (window),
301 xembed_info_atom, &type, &format,
302 &nitems, &bytes_after, &data);
303 gdk_error_trap_pop();
305 if (status != Success)
306 return FALSE; /* Window vanished? */
308 if (type == None) /* No info property */
311 if (type != xembed_info_atom)
313 g_warning ("_XEMBED_INFO property has wrong type\n");
319 g_warning ("_XEMBED_INFO too short\n");
324 data_long = (unsigned long *)data;
326 *version = data_long[0];
328 *flags = data_long[1] & XEMBED_MAPPED;
335 _gtk_socket_windowing_embed_get_focus_wrapped (void)
337 return _gtk_xembed_get_focus_wrapped ();
341 _gtk_socket_windowing_embed_set_focus_wrapped (void)
343 _gtk_xembed_set_focus_wrapped ();
347 handle_xembed_message (GtkSocket *socket,
348 XEmbedMessageType message,
354 GTK_NOTE (PLUGSOCKET,
355 g_message ("GtkSocket: %s received", _gtk_xembed_message_name (message)));
359 case XEMBED_EMBEDDED_NOTIFY:
360 case XEMBED_WINDOW_ACTIVATE:
361 case XEMBED_WINDOW_DEACTIVATE:
362 case XEMBED_MODALITY_ON:
363 case XEMBED_MODALITY_OFF:
364 case XEMBED_FOCUS_IN:
365 case XEMBED_FOCUS_OUT:
366 g_warning ("GtkSocket: Invalid _XEMBED message %s received", _gtk_xembed_message_name (message));
369 case XEMBED_REQUEST_FOCUS:
370 _gtk_socket_claim_focus (socket, TRUE);
373 case XEMBED_FOCUS_NEXT:
374 case XEMBED_FOCUS_PREV:
375 _gtk_socket_advance_toplevel_focus (socket,
376 (message == XEMBED_FOCUS_NEXT ?
377 GTK_DIR_TAB_FORWARD : GTK_DIR_TAB_BACKWARD));
380 case XEMBED_GTK_GRAB_KEY:
381 _gtk_socket_add_grabbed_key (socket, data1, data2);
383 case XEMBED_GTK_UNGRAB_KEY:
384 _gtk_socket_remove_grabbed_key (socket, data1, data2);
387 case XEMBED_GRAB_KEY:
388 case XEMBED_UNGRAB_KEY:
392 GTK_NOTE (PLUGSOCKET,
393 g_message ("GtkSocket: Ignoring unknown _XEMBED message of type %d", message));
399 _gtk_socket_windowing_filter_func (GdkXEvent *gdk_xevent,
408 GdkFilterReturn return_val;
410 socket = GTK_SOCKET (data);
412 return_val = GDK_FILTER_CONTINUE;
414 if (socket->plug_widget)
417 widget = GTK_WIDGET (socket);
418 xevent = (XEvent *)gdk_xevent;
419 display = gtk_widget_get_display (widget);
421 switch (xevent->type)
424 if (xevent->xclient.message_type == gdk_x11_get_xatom_by_name_for_display (display, "_XEMBED"))
426 _gtk_xembed_push_message (xevent);
427 handle_xembed_message (socket,
428 xevent->xclient.data.l[1],
429 xevent->xclient.data.l[2],
430 xevent->xclient.data.l[3],
431 xevent->xclient.data.l[4],
432 xevent->xclient.data.l[0]);
433 _gtk_xembed_pop_message ();
435 return_val = GDK_FILTER_REMOVE;
441 XCreateWindowEvent *xcwe = &xevent->xcreatewindow;
443 if (!socket->plug_window)
445 _gtk_socket_add_window (socket, xcwe->window, FALSE);
447 if (socket->plug_window)
449 GTK_NOTE (PLUGSOCKET, g_message ("GtkSocket - window created"));
453 return_val = GDK_FILTER_REMOVE;
458 case ConfigureRequest:
460 XConfigureRequestEvent *xcre = &xevent->xconfigurerequest;
462 if (!socket->plug_window)
463 _gtk_socket_add_window (socket, xcre->window, FALSE);
465 if (socket->plug_window)
467 GtkSocketPrivate *private = _gtk_socket_get_private (socket);
469 if (xcre->value_mask & (CWWidth | CWHeight))
471 GTK_NOTE (PLUGSOCKET,
472 g_message ("GtkSocket - configure request: %d %d",
473 socket->request_width,
474 socket->request_height));
476 private->resize_count++;
477 gtk_widget_queue_resize (widget);
479 else if (xcre->value_mask & (CWX | CWY))
481 _gtk_socket_windowing_send_configure_event (socket);
483 /* Ignore stacking requests. */
485 return_val = GDK_FILTER_REMOVE;
492 XDestroyWindowEvent *xdwe = &xevent->xdestroywindow;
494 /* Note that we get destroy notifies both from SubstructureNotify on
495 * our window and StructureNotify on socket->plug_window
497 if (socket->plug_window && (xdwe->window == GDK_WINDOW_XWINDOW (socket->plug_window)))
501 GTK_NOTE (PLUGSOCKET, g_message ("GtkSocket - destroy notify"));
503 gdk_window_destroy_notify (socket->plug_window);
504 _gtk_socket_end_embedding (socket);
506 g_object_ref (widget);
507 g_signal_emit_by_name (widget, "plug_removed", &result);
509 gtk_widget_destroy (widget);
510 g_object_unref (widget);
512 return_val = GDK_FILTER_REMOVE;
518 if (xevent->xfocus.mode == EMBEDDED_APP_WANTS_FOCUS)
520 _gtk_socket_claim_focus (socket, TRUE);
522 return_val = GDK_FILTER_REMOVE;
525 return_val = GDK_FILTER_REMOVE;
528 if (!socket->plug_window)
530 _gtk_socket_add_window (socket, xevent->xmaprequest.window, FALSE);
533 if (socket->plug_window)
535 GTK_NOTE (PLUGSOCKET, g_message ("GtkSocket - Map Request"));
537 _gtk_socket_handle_map_request (socket);
538 return_val = GDK_FILTER_REMOVE;
542 if (socket->plug_window &&
543 xevent->xproperty.window == GDK_WINDOW_XWINDOW (socket->plug_window))
545 GdkDragProtocol protocol;
547 if (xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "WM_NORMAL_HINTS"))
549 GTK_NOTE (PLUGSOCKET, g_message ("GtkSocket - received PropertyNotify for plug's WM_NORMAL_HINTS"));
550 socket->have_size = FALSE;
551 gtk_widget_queue_resize (widget);
552 return_val = GDK_FILTER_REMOVE;
554 else if ((xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "XdndAware")) ||
555 (xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_RECEIVER_INFO")))
557 gdk_error_trap_push ();
558 if (gdk_drag_get_protocol_for_display (display,
559 xevent->xproperty.window,
561 gtk_drag_dest_set_proxy (GTK_WIDGET (socket),
565 gdk_display_sync (display);
566 gdk_error_trap_pop ();
567 return_val = GDK_FILTER_REMOVE;
569 else if (xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "_XEMBED_INFO"))
573 if (xembed_get_info (socket->plug_window, NULL, &flags))
575 gboolean was_mapped = socket->is_mapped;
576 gboolean is_mapped = (flags & XEMBED_MAPPED) != 0;
578 if (was_mapped != is_mapped)
581 _gtk_socket_handle_map_request (socket);
584 gdk_error_trap_push ();
585 gdk_window_show (socket->plug_window);
587 gdk_error_trap_pop ();
589 _gtk_socket_unmap_notify (socket);
593 return_val = GDK_FILTER_REMOVE;
599 XReparentEvent *xre = &xevent->xreparent;
601 GTK_NOTE (PLUGSOCKET, g_message ("GtkPlug: ReparentNotify received\n"));
602 if (!socket->plug_window && xre->parent == GDK_WINDOW_XWINDOW (widget->window))
604 _gtk_socket_add_window (socket, xre->window, FALSE);
606 if (socket->plug_window)
608 GTK_NOTE (PLUGSOCKET, g_message ("GtkSocket - window reparented"));
611 return_val = GDK_FILTER_REMOVE;
617 if (socket->plug_window &&
618 xevent->xunmap.window == GDK_WINDOW_XWINDOW (socket->plug_window))
620 GTK_NOTE (PLUGSOCKET, g_message ("GtkSocket - Unmap notify"));
622 _gtk_socket_unmap_notify (socket);
623 return_val = GDK_FILTER_REMOVE;