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"
34 #include "gtkmarshalers.h"
35 #include "gtkwindow.h"
37 #include "gtkprivate.h"
38 #include "gtksocket.h"
39 #include "gtksocketprivate.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 XSelectInput (GDK_WINDOW_XDISPLAY (window),
75 GDK_WINDOW_XWINDOW (window),
76 xattrs.your_event_mask |
77 SubstructureNotifyMask | SubstructureRedirectMask);
81 _gtk_socket_windowing_end_embedding_toplevel (GtkSocket *socket)
83 gtk_window_remove_embedded_xid (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (socket))),
84 GDK_WINDOW_XWINDOW (socket->plug_window));
88 _gtk_socket_windowing_size_request (GtkSocket *socket)
93 gdk_error_trap_push ();
95 socket->request_width = 1;
96 socket->request_height = 1;
98 if (XGetWMNormalHints (GDK_WINDOW_XDISPLAY (socket->plug_window),
99 GDK_WINDOW_XWINDOW (socket->plug_window),
102 if (hints.flags & PMinSize)
104 socket->request_width = MAX (hints.min_width, 1);
105 socket->request_height = MAX (hints.min_height, 1);
107 else if (hints.flags & PBaseSize)
109 socket->request_width = MAX (hints.base_width, 1);
110 socket->request_height = MAX (hints.base_height, 1);
113 socket->have_size = TRUE;
115 gdk_error_trap_pop ();
119 _gtk_socket_windowing_send_key_event (GtkSocket *socket,
121 gboolean mask_key_presses)
124 GdkScreen *screen = gdk_drawable_get_screen (socket->plug_window);
126 xevent.xkey.type = (gdk_event->type == GDK_KEY_PRESS) ? KeyPress : KeyRelease;
127 xevent.xkey.window = GDK_WINDOW_XWINDOW (socket->plug_window);
128 xevent.xkey.root = GDK_WINDOW_XWINDOW (gdk_screen_get_root_window (screen));
129 xevent.xkey.subwindow = None;
130 xevent.xkey.time = gdk_event->key.time;
133 xevent.xkey.x_root = 0;
134 xevent.xkey.y_root = 0;
135 xevent.xkey.state = gdk_event->key.state;
136 xevent.xkey.keycode = gdk_event->key.hardware_keycode;
137 xevent.xkey.same_screen = True;/* FIXME ? */
139 gdk_error_trap_push ();
140 XSendEvent (GDK_WINDOW_XDISPLAY (socket->plug_window),
141 GDK_WINDOW_XWINDOW (socket->plug_window),
143 (mask_key_presses ? KeyPressMask : NoEventMask),
145 gdk_display_sync (gdk_screen_get_display (screen));
146 gdk_error_trap_pop ();
150 _gtk_socket_windowing_focus_change (GtkSocket *socket,
154 _gtk_xembed_send_focus_message (socket->plug_window,
155 XEMBED_FOCUS_IN, XEMBED_FOCUS_CURRENT);
157 _gtk_xembed_send_message (socket->plug_window,
158 XEMBED_FOCUS_OUT, 0, 0, 0);
162 _gtk_socket_windowing_update_active (GtkSocket *socket,
165 _gtk_xembed_send_message (socket->plug_window,
166 active ? XEMBED_WINDOW_ACTIVATE : XEMBED_WINDOW_DEACTIVATE,
171 _gtk_socket_windowing_update_modality (GtkSocket *socket,
174 _gtk_xembed_send_message (socket->plug_window,
175 modality ? XEMBED_MODALITY_ON : XEMBED_MODALITY_OFF,
180 _gtk_socket_windowing_focus (GtkSocket *socket,
181 GtkDirectionType direction)
189 case GTK_DIR_TAB_BACKWARD:
190 detail = XEMBED_FOCUS_LAST;
194 case GTK_DIR_TAB_FORWARD:
195 detail = XEMBED_FOCUS_FIRST;
199 _gtk_xembed_send_focus_message (socket->plug_window, XEMBED_FOCUS_IN, detail);
203 _gtk_socket_windowing_send_configure_event (GtkSocket *socket)
208 g_return_if_fail (socket->plug_window != NULL);
210 event.xconfigure.type = ConfigureNotify;
212 event.xconfigure.event = GDK_WINDOW_XWINDOW (socket->plug_window);
213 event.xconfigure.window = GDK_WINDOW_XWINDOW (socket->plug_window);
215 /* The ICCCM says that synthetic events should have root relative
216 * coordinates. We still aren't really ICCCM compliant, since
217 * we don't send events when the real toplevel is moved.
219 gdk_error_trap_push ();
220 gdk_window_get_origin (socket->plug_window, &x, &y);
221 gdk_error_trap_pop ();
223 event.xconfigure.x = x;
224 event.xconfigure.y = y;
225 event.xconfigure.width = GTK_WIDGET(socket)->allocation.width;
226 event.xconfigure.height = GTK_WIDGET(socket)->allocation.height;
228 event.xconfigure.border_width = 0;
229 event.xconfigure.above = None;
230 event.xconfigure.override_redirect = False;
232 gdk_error_trap_push ();
233 XSendEvent (GDK_WINDOW_XDISPLAY (socket->plug_window),
234 GDK_WINDOW_XWINDOW (socket->plug_window),
235 False, NoEventMask, &event);
236 gdk_display_sync (gtk_widget_get_display (GTK_WIDGET (socket)));
237 gdk_error_trap_pop ();
241 _gtk_socket_windowing_select_plug_window_input (GtkSocket *socket)
243 XSelectInput (GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (GTK_WIDGET (socket))),
244 GDK_WINDOW_XWINDOW (socket->plug_window),
245 StructureNotifyMask | PropertyChangeMask);
249 _gtk_socket_windowing_embed_get_info (GtkSocket *socket)
251 unsigned long version;
254 socket->xembed_version = -1;
255 if (xembed_get_info (socket->plug_window, &version, &flags))
257 socket->xembed_version = MIN (GTK_XEMBED_PROTOCOL_VERSION, version);
258 socket->is_mapped = (flags & XEMBED_MAPPED) != 0;
262 /* FIXME, we should probably actually check the state before we started */
263 socket->is_mapped = TRUE;
268 _gtk_socket_windowing_embed_notify (GtkSocket *socket)
271 GdkDisplay *display = gtk_widget_get_display (GTK_WIDGET (socket));
273 XFixesChangeSaveSet (GDK_DISPLAY_XDISPLAY (display),
274 GDK_WINDOW_XWINDOW (socket->plug_window),
275 SetModeInsert, SaveSetRoot, SaveSetUnmap);
277 _gtk_xembed_send_message (socket->plug_window,
278 XEMBED_EMBEDDED_NOTIFY, 0,
279 GDK_WINDOW_XWINDOW (GTK_WIDGET (socket)->window),
280 socket->xembed_version);
284 xembed_get_info (GdkWindow *window,
285 unsigned long *version,
286 unsigned long *flags)
288 GdkDisplay *display = gdk_drawable_get_display (window);
289 Atom xembed_info_atom = gdk_x11_get_xatom_by_name_for_display (display, "_XEMBED_INFO");
292 unsigned long nitems, bytes_after;
294 unsigned long *data_long;
297 gdk_error_trap_push();
298 status = XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display),
299 GDK_WINDOW_XWINDOW (window),
302 xembed_info_atom, &type, &format,
303 &nitems, &bytes_after, &data);
304 gdk_error_trap_pop();
306 if (status != Success)
307 return FALSE; /* Window vanished? */
309 if (type == None) /* No info property */
312 if (type != xembed_info_atom)
314 g_warning ("_XEMBED_INFO property has wrong type\n");
320 g_warning ("_XEMBED_INFO too short\n");
325 data_long = (unsigned long *)data;
327 *version = data_long[0];
329 *flags = data_long[1] & XEMBED_MAPPED;
336 _gtk_socket_windowing_embed_get_focus_wrapped (void)
338 return _gtk_xembed_get_focus_wrapped ();
342 _gtk_socket_windowing_embed_set_focus_wrapped (void)
344 _gtk_xembed_set_focus_wrapped ();
348 handle_xembed_message (GtkSocket *socket,
349 XEmbedMessageType message,
355 GTK_NOTE (PLUGSOCKET,
356 g_message ("GtkSocket: %s received", _gtk_xembed_message_name (message)));
360 case XEMBED_EMBEDDED_NOTIFY:
361 case XEMBED_WINDOW_ACTIVATE:
362 case XEMBED_WINDOW_DEACTIVATE:
363 case XEMBED_MODALITY_ON:
364 case XEMBED_MODALITY_OFF:
365 case XEMBED_FOCUS_IN:
366 case XEMBED_FOCUS_OUT:
367 g_warning ("GtkSocket: Invalid _XEMBED message %s received", _gtk_xembed_message_name (message));
370 case XEMBED_REQUEST_FOCUS:
371 _gtk_socket_claim_focus (socket, TRUE);
374 case XEMBED_FOCUS_NEXT:
375 case XEMBED_FOCUS_PREV:
376 _gtk_socket_advance_toplevel_focus (socket,
377 (message == XEMBED_FOCUS_NEXT ?
378 GTK_DIR_TAB_FORWARD : GTK_DIR_TAB_BACKWARD));
381 case XEMBED_GTK_GRAB_KEY:
382 _gtk_socket_add_grabbed_key (socket, data1, data2);
384 case XEMBED_GTK_UNGRAB_KEY:
385 _gtk_socket_remove_grabbed_key (socket, data1, data2);
388 case XEMBED_GRAB_KEY:
389 case XEMBED_UNGRAB_KEY:
393 GTK_NOTE (PLUGSOCKET,
394 g_message ("GtkSocket: Ignoring unknown _XEMBED message of type %d", message));
400 _gtk_socket_windowing_filter_func (GdkXEvent *gdk_xevent,
409 GdkFilterReturn return_val;
411 socket = GTK_SOCKET (data);
413 return_val = GDK_FILTER_CONTINUE;
415 if (socket->plug_widget)
418 widget = GTK_WIDGET (socket);
419 xevent = (XEvent *)gdk_xevent;
420 display = gtk_widget_get_display (widget);
422 switch (xevent->type)
425 if (xevent->xclient.message_type == gdk_x11_get_xatom_by_name_for_display (display, "_XEMBED"))
427 _gtk_xembed_push_message (xevent);
428 handle_xembed_message (socket,
429 xevent->xclient.data.l[1],
430 xevent->xclient.data.l[2],
431 xevent->xclient.data.l[3],
432 xevent->xclient.data.l[4],
433 xevent->xclient.data.l[0]);
434 _gtk_xembed_pop_message ();
436 return_val = GDK_FILTER_REMOVE;
442 XCreateWindowEvent *xcwe = &xevent->xcreatewindow;
444 if (!socket->plug_window)
446 _gtk_socket_add_window (socket, xcwe->window, FALSE);
448 if (socket->plug_window)
450 GTK_NOTE (PLUGSOCKET, g_message ("GtkSocket - window created"));
454 return_val = GDK_FILTER_REMOVE;
459 case ConfigureRequest:
461 XConfigureRequestEvent *xcre = &xevent->xconfigurerequest;
463 if (!socket->plug_window)
464 _gtk_socket_add_window (socket, xcre->window, FALSE);
466 if (socket->plug_window)
468 GtkSocketPrivate *private = _gtk_socket_get_private (socket);
470 if (xcre->value_mask & (CWWidth | CWHeight))
472 GTK_NOTE (PLUGSOCKET,
473 g_message ("GtkSocket - configure request: %d %d",
474 socket->request_width,
475 socket->request_height));
477 private->resize_count++;
478 gtk_widget_queue_resize (widget);
480 else if (xcre->value_mask & (CWX | CWY))
482 _gtk_socket_windowing_send_configure_event (socket);
484 /* Ignore stacking requests. */
486 return_val = GDK_FILTER_REMOVE;
493 XDestroyWindowEvent *xdwe = &xevent->xdestroywindow;
495 /* Note that we get destroy notifies both from SubstructureNotify on
496 * our window and StructureNotify on socket->plug_window
498 if (socket->plug_window && (xdwe->window == GDK_WINDOW_XWINDOW (socket->plug_window)))
502 GTK_NOTE (PLUGSOCKET, g_message ("GtkSocket - destroy notify"));
504 gdk_window_destroy_notify (socket->plug_window);
505 _gtk_socket_end_embedding (socket);
507 g_object_ref (widget);
508 g_signal_emit_by_name (widget, "plug_removed", &result);
510 gtk_widget_destroy (widget);
511 g_object_unref (widget);
513 return_val = GDK_FILTER_REMOVE;
519 if (xevent->xfocus.mode == EMBEDDED_APP_WANTS_FOCUS)
521 _gtk_socket_claim_focus (socket, TRUE);
523 return_val = GDK_FILTER_REMOVE;
526 return_val = GDK_FILTER_REMOVE;
529 if (!socket->plug_window)
531 _gtk_socket_add_window (socket, xevent->xmaprequest.window, FALSE);
534 if (socket->plug_window)
536 GTK_NOTE (PLUGSOCKET, g_message ("GtkSocket - Map Request"));
538 _gtk_socket_handle_map_request (socket);
539 return_val = GDK_FILTER_REMOVE;
543 if (socket->plug_window &&
544 xevent->xproperty.window == GDK_WINDOW_XWINDOW (socket->plug_window))
546 GdkDragProtocol protocol;
548 if (xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "WM_NORMAL_HINTS"))
550 GTK_NOTE (PLUGSOCKET, g_message ("GtkSocket - received PropertyNotify for plug's WM_NORMAL_HINTS"));
551 socket->have_size = FALSE;
552 gtk_widget_queue_resize (widget);
553 return_val = GDK_FILTER_REMOVE;
555 else if ((xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "XdndAware")) ||
556 (xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_RECEIVER_INFO")))
558 gdk_error_trap_push ();
559 if (gdk_drag_get_protocol_for_display (display,
560 xevent->xproperty.window,
562 gtk_drag_dest_set_proxy (GTK_WIDGET (socket),
566 gdk_display_sync (display);
567 gdk_error_trap_pop ();
568 return_val = GDK_FILTER_REMOVE;
570 else if (xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "_XEMBED_INFO"))
574 if (xembed_get_info (socket->plug_window, NULL, &flags))
576 gboolean was_mapped = socket->is_mapped;
577 gboolean is_mapped = (flags & XEMBED_MAPPED) != 0;
579 if (was_mapped != is_mapped)
582 _gtk_socket_handle_map_request (socket);
585 gdk_error_trap_push ();
586 gdk_window_show (socket->plug_window);
588 gdk_error_trap_pop ();
590 _gtk_socket_unmap_notify (socket);
594 return_val = GDK_FILTER_REMOVE;
600 XReparentEvent *xre = &xevent->xreparent;
602 GTK_NOTE (PLUGSOCKET, g_message ("GtkPlug: ReparentNotify received\n"));
603 if (!socket->plug_window && xre->parent == GDK_WINDOW_XWINDOW (widget->window))
605 _gtk_socket_add_window (socket, xre->window, FALSE);
607 if (socket->plug_window)
609 GTK_NOTE (PLUGSOCKET, g_message ("GtkSocket - window reparented"));
612 return_val = GDK_FILTER_REMOVE;
618 if (socket->plug_window &&
619 xevent->xunmap.window == GDK_WINDOW_XWINDOW (socket->plug_window))
621 GTK_NOTE (PLUGSOCKET, g_message ("GtkSocket - Unmap notify"));
623 _gtk_socket_unmap_notify (socket);
624 return_val = GDK_FILTER_REMOVE;