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 Library 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 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library 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-1999. 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/.
28 #include "gdkconfig.h"
30 #if defined (GDK_WINDOWING_X11)
32 #elif defined (GDK_WINDOWING_WIN32)
33 #include "win32/gdkwin32.h"
34 #elif defined(GDK_WINDOWING_FB)
35 #include "linux-fb/gdkfb.h"
38 #include "gdk/gdkkeysyms.h"
39 #include "gtkwindow.h"
40 #include "gtksignal.h"
41 #include "gtksocket.h"
44 #ifdef GDK_WINDOWING_X11
46 /* Forward declararations */
48 static void gtk_socket_class_init (GtkSocketClass *klass);
49 static void gtk_socket_init (GtkSocket *socket);
50 static void gtk_socket_realize (GtkWidget *widget);
51 static void gtk_socket_unrealize (GtkWidget *widget);
52 static void gtk_socket_size_request (GtkWidget *widget,
53 GtkRequisition *requisition);
54 static void gtk_socket_size_allocate (GtkWidget *widget,
55 GtkAllocation *allocation);
56 static gint gtk_socket_focus_in_event (GtkWidget *widget,
57 GdkEventFocus *event);
58 static void gtk_socket_claim_focus (GtkSocket *socket);
59 static gint gtk_socket_focus_out_event (GtkWidget *widget,
60 GdkEventFocus *event);
61 static void gtk_socket_send_configure_event (GtkSocket *socket);
62 static gint gtk_socket_focus (GtkContainer *container,
63 GtkDirectionType direction);
64 static GdkFilterReturn gtk_socket_filter_func (GdkXEvent *gdk_xevent,
69 #define EMBEDDED_APP_WANTS_FOCUS NotifyNormal+20
73 static GtkWidgetClass *parent_class = NULL;
76 gtk_socket_get_type (void)
78 static GtkType socket_type = 0;
82 static const GTypeInfo socket_info =
84 sizeof (GtkSocketClass),
86 NULL, /* base_finalize */
87 (GClassInitFunc) gtk_socket_class_init,
88 NULL, /* class_finalize */
89 NULL, /* class_data */
92 (GInstanceInitFunc) gtk_socket_init,
95 socket_type = g_type_register_static (GTK_TYPE_CONTAINER, "GtkSocket", &socket_info);
102 gtk_socket_class_init (GtkSocketClass *class)
104 GtkObjectClass *object_class;
105 GtkWidgetClass *widget_class;
106 GtkContainerClass *container_class;
108 object_class = (GtkObjectClass*) class;
109 widget_class = (GtkWidgetClass*) class;
110 container_class = (GtkContainerClass*) class;
112 parent_class = gtk_type_class (GTK_TYPE_CONTAINER);
114 widget_class->realize = gtk_socket_realize;
115 widget_class->unrealize = gtk_socket_unrealize;
116 widget_class->size_request = gtk_socket_size_request;
117 widget_class->size_allocate = gtk_socket_size_allocate;
118 widget_class->focus_in_event = gtk_socket_focus_in_event;
119 widget_class->focus_out_event = gtk_socket_focus_out_event;
121 container_class->focus = gtk_socket_focus;
125 gtk_socket_init (GtkSocket *socket)
127 socket->request_width = 0;
128 socket->request_height = 0;
129 socket->current_width = 0;
130 socket->current_height = 0;
132 socket->plug_window = NULL;
133 socket->same_app = FALSE;
134 socket->focus_in = FALSE;
135 socket->have_size = FALSE;
136 socket->need_map = FALSE;
140 gtk_socket_new (void)
144 socket = gtk_type_new (GTK_TYPE_SOCKET);
146 return GTK_WIDGET (socket);
150 gtk_socket_steal (GtkSocket *socket, GdkNativeWindow id)
154 widget = GTK_WIDGET (socket);
156 socket->plug_window = gdk_window_lookup (id);
158 gdk_error_trap_push ();
160 if (socket->plug_window && socket->plug_window->user_data)
163 GtkWidget *child_widget;
165 child_widget = GTK_WIDGET (socket->plug_window->user_data);
168 g_warning("Stealing from same app not yet implemented");
170 socket->same_app = TRUE;
174 socket->plug_window = gdk_window_foreign_new (id);
175 if (!socket->plug_window) /* was deleted before we could get it */
177 gdk_error_trap_pop ();
181 socket->same_app = FALSE;
182 socket->have_size = FALSE;
184 XSelectInput (GDK_DISPLAY (),
185 GDK_WINDOW_XWINDOW(socket->plug_window),
186 StructureNotifyMask | PropertyChangeMask);
188 gtk_widget_queue_resize (widget);
191 gdk_window_hide (socket->plug_window);
192 gdk_window_reparent (socket->plug_window, widget->window, 0, 0);
195 gdk_error_trap_pop ();
197 socket->need_map = TRUE;
201 gtk_socket_realize (GtkWidget *widget)
204 GdkWindowAttr attributes;
205 gint attributes_mask;
206 XWindowAttributes xattrs;
208 g_return_if_fail (widget != NULL);
209 g_return_if_fail (GTK_IS_SOCKET (widget));
211 socket = GTK_SOCKET (widget);
212 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
214 attributes.window_type = GDK_WINDOW_CHILD;
215 attributes.x = widget->allocation.x;
216 attributes.y = widget->allocation.y;
217 attributes.width = widget->allocation.width;
218 attributes.height = widget->allocation.height;
219 attributes.wclass = GDK_INPUT_OUTPUT;
220 attributes.visual = gtk_widget_get_visual (widget);
221 attributes.colormap = gtk_widget_get_colormap (widget);
222 attributes.event_mask = GDK_FOCUS_CHANGE_MASK;
224 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
226 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
227 &attributes, attributes_mask);
228 gdk_window_set_user_data (widget->window, socket);
230 widget->style = gtk_style_attach (widget->style, widget->window);
231 gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
233 XGetWindowAttributes (GDK_DISPLAY (),
234 GDK_WINDOW_XWINDOW (widget->window),
237 XSelectInput (GDK_DISPLAY (),
238 GDK_WINDOW_XWINDOW(widget->window),
239 xattrs.your_event_mask |
240 SubstructureNotifyMask | SubstructureRedirectMask);
242 gdk_window_add_filter (widget->window, gtk_socket_filter_func, widget);
244 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
246 /* We sync here so that we make sure that if the XID for
247 * our window is passed to another application, SubstructureRedirectMask
248 * will be set by the time the other app creates its window.
254 gtk_socket_unrealize (GtkWidget *widget)
258 g_return_if_fail (widget != NULL);
259 g_return_if_fail (GTK_IS_SOCKET (widget));
261 socket = GTK_SOCKET (widget);
263 if (socket->plug_window)
265 GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (socket));
266 if (toplevel && GTK_IS_WINDOW (toplevel))
267 gtk_window_remove_embedded_xid (GTK_WINDOW (toplevel),
268 GDK_WINDOW_XWINDOW (socket->plug_window));
271 if (GTK_WIDGET_CLASS (parent_class)->unrealize)
272 (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
276 gtk_socket_size_request (GtkWidget *widget,
277 GtkRequisition *requisition)
281 g_return_if_fail (widget != NULL);
282 g_return_if_fail (GTK_IS_SOCKET (widget));
283 g_return_if_fail (requisition != NULL);
285 socket = GTK_SOCKET (widget);
287 if (!socket->have_size && socket->plug_window)
292 gdk_error_trap_push ();
294 if (XGetWMNormalHints (GDK_DISPLAY(),
295 GDK_WINDOW_XWINDOW (socket->plug_window),
298 /* This is obsolete, according the X docs, but many programs
300 if (hints.flags & (PSize | USSize))
302 socket->request_width = hints.width;
303 socket->request_height = hints.height;
305 else if (hints.flags & PMinSize)
307 socket->request_width = hints.min_width;
308 socket->request_height = hints.min_height;
310 else if (hints.flags & PBaseSize)
312 socket->request_width = hints.base_width;
313 socket->request_height = hints.base_height;
316 socket->have_size = TRUE; /* don't check again? */
318 gdk_error_trap_pop ();
321 requisition->width = MAX (socket->request_width, 1);
322 requisition->height = MAX (socket->request_height, 1);
326 gtk_socket_size_allocate (GtkWidget *widget,
327 GtkAllocation *allocation)
331 g_return_if_fail (widget != NULL);
332 g_return_if_fail (GTK_IS_SOCKET (widget));
333 g_return_if_fail (allocation != NULL);
335 socket = GTK_SOCKET (widget);
337 widget->allocation = *allocation;
338 if (GTK_WIDGET_REALIZED (widget))
340 gdk_window_move_resize (widget->window,
341 allocation->x, allocation->y,
342 allocation->width, allocation->height);
344 if (socket->plug_window)
346 gdk_error_trap_push ();
348 if (!socket->need_map &&
349 (allocation->width == socket->current_width) &&
350 (allocation->height == socket->current_height))
352 gtk_socket_send_configure_event (socket);
354 g_message ("GtkSocket - allocated no change: %d %d",
355 allocation->width, allocation->height));
359 gdk_window_move_resize (socket->plug_window,
361 allocation->width, allocation->height);
363 g_message ("GtkSocket - allocated: %d %d",
364 allocation->width, allocation->height));
365 socket->current_width = allocation->width;
366 socket->current_height = allocation->height;
369 if (socket->need_map)
371 gdk_window_show (socket->plug_window);
372 socket->need_map = FALSE;
376 gdk_error_trap_pop ();
382 gtk_socket_focus_in_event (GtkWidget *widget, GdkEventFocus *event)
385 g_return_val_if_fail (GTK_IS_SOCKET (widget), FALSE);
386 socket = GTK_SOCKET (widget);
388 if (socket->focus_in && socket->plug_window)
390 gdk_error_trap_push ();
391 XSetInputFocus (GDK_DISPLAY (),
392 GDK_WINDOW_XWINDOW (socket->plug_window),
393 RevertToParent, GDK_CURRENT_TIME);
395 gdk_error_trap_pop ();
402 gtk_socket_focus_out_event (GtkWidget *widget, GdkEventFocus *event)
407 g_return_val_if_fail (GTK_IS_SOCKET (widget), FALSE);
408 socket = GTK_SOCKET (widget);
410 toplevel = gtk_widget_get_ancestor (widget, GTK_TYPE_WINDOW);
414 XSetInputFocus (GDK_DISPLAY (),
415 GDK_WINDOW_XWINDOW (toplevel->window),
416 RevertToParent, CurrentTime); /* FIXME? */
419 socket->focus_in = FALSE;
425 gtk_socket_claim_focus (GtkSocket *socket)
428 socket->focus_in = TRUE;
430 /* Oh, the trickery... */
432 GTK_WIDGET_SET_FLAGS (socket, GTK_CAN_FOCUS);
433 gtk_widget_grab_focus (GTK_WIDGET (socket));
434 GTK_WIDGET_UNSET_FLAGS (socket, GTK_CAN_FOCUS);
436 /* FIXME: we might grab the focus even if we don't have
437 * it as an app... (and see _focus_in ()) */
438 if (socket->plug_window)
440 gdk_error_trap_push ();
441 XSetInputFocus (GDK_DISPLAY (),
442 GDK_WINDOW_XWINDOW (socket->plug_window),
443 RevertToParent, GDK_CURRENT_TIME);
445 gdk_error_trap_pop ();
450 gtk_socket_focus (GtkContainer *container, GtkDirectionType direction)
454 g_return_val_if_fail (GTK_IS_SOCKET (container), FALSE);
456 socket = GTK_SOCKET (container);
458 if (!socket->focus_in && socket->plug_window)
462 gtk_socket_claim_focus (socket);
464 xevent.xkey.type = KeyPress;
465 xevent.xkey.display = GDK_DISPLAY ();
466 xevent.xkey.window = GDK_WINDOW_XWINDOW (socket->plug_window);
467 xevent.xkey.root = GDK_ROOT_WINDOW (); /* FIXME */
468 xevent.xkey.time = GDK_CURRENT_TIME; /* FIXME */
469 /* FIXME, the following might cause big problems for
473 xevent.xkey.x_root = 0;
474 xevent.xkey.y_root = 0;
475 xevent.xkey.state = 0;
476 xevent.xkey.same_screen = TRUE; /* FIXME ? */
481 xevent.xkey.keycode = XKeysymToKeycode(GDK_DISPLAY(), GDK_Up);
484 xevent.xkey.keycode = XKeysymToKeycode(GDK_DISPLAY(), GDK_Down);
487 xevent.xkey.keycode = XKeysymToKeycode(GDK_DISPLAY(), GDK_Left);
490 xevent.xkey.keycode = XKeysymToKeycode(GDK_DISPLAY(), GDK_Right);
492 case GTK_DIR_TAB_FORWARD:
493 xevent.xkey.keycode = XKeysymToKeycode(GDK_DISPLAY(), GDK_Tab);
495 case GTK_DIR_TAB_BACKWARD:
496 xevent.xkey.keycode = XKeysymToKeycode(GDK_DISPLAY(), GDK_Tab);
497 xevent.xkey.state = ShiftMask;
502 gdk_error_trap_push ();
503 XSendEvent (gdk_display,
504 GDK_WINDOW_XWINDOW (socket->plug_window),
505 False, NoEventMask, &xevent);
507 gdk_error_trap_pop ();
518 gtk_socket_send_configure_event (GtkSocket *socket)
522 g_return_if_fail (socket->plug_window != NULL);
524 event.xconfigure.type = ConfigureNotify;
525 event.xconfigure.display = gdk_display;
527 event.xconfigure.event = GDK_WINDOW_XWINDOW (socket->plug_window);
528 event.xconfigure.window = GDK_WINDOW_XWINDOW (socket->plug_window);
530 event.xconfigure.x = 0;
531 event.xconfigure.y = 0;
532 event.xconfigure.width = GTK_WIDGET(socket)->allocation.width;
533 event.xconfigure.height = GTK_WIDGET(socket)->allocation.height;
535 event.xconfigure.border_width = 0;
536 event.xconfigure.above = None;
537 event.xconfigure.override_redirect = False;
539 gdk_error_trap_push ();
540 XSendEvent (gdk_display,
541 GDK_WINDOW_XWINDOW (socket->plug_window),
542 False, NoEventMask, &event);
544 gdk_error_trap_pop ();
548 gtk_socket_add_window (GtkSocket *socket, GdkNativeWindow xid)
550 socket->plug_window = gdk_window_lookup (xid);
551 socket->same_app = TRUE;
553 if (!socket->plug_window)
556 GdkDragProtocol protocol;
558 socket->plug_window = gdk_window_foreign_new (xid);
559 if (!socket->plug_window) /* Already gone */
562 socket->same_app = FALSE;
564 gdk_error_trap_push ();
565 XSelectInput (GDK_DISPLAY (),
566 GDK_WINDOW_XWINDOW(socket->plug_window),
567 StructureNotifyMask | PropertyChangeMask);
569 if (gdk_drag_get_protocol (xid, &protocol))
570 gtk_drag_dest_set_proxy (GTK_WIDGET (socket), socket->plug_window,
573 gdk_error_trap_pop ();
575 gdk_window_add_filter (socket->plug_window,
576 gtk_socket_filter_func, socket);
578 /* Add a pointer to the socket on our toplevel window */
580 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (socket));
581 if (toplevel && GTK_IS_WINDOW (toplevel))
583 gtk_window_add_embedded_xid (GTK_WINDOW (toplevel), xid);
588 static GdkFilterReturn
589 gtk_socket_filter_func (GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data)
595 GdkFilterReturn return_val;
597 socket = GTK_SOCKET (data);
598 widget = GTK_WIDGET (socket);
599 xevent = (XEvent *)gdk_xevent;
601 return_val = GDK_FILTER_CONTINUE;
603 switch (xevent->type)
607 XCreateWindowEvent *xcwe = &xevent->xcreatewindow;
609 if (!socket->plug_window)
611 gtk_socket_add_window (socket, xcwe->window);
613 gdk_error_trap_push ();
614 gdk_window_move_resize(socket->plug_window,
616 widget->allocation.width,
617 widget->allocation.height);
619 gdk_error_trap_pop ();
621 socket->request_width = xcwe->width;
622 socket->request_height = xcwe->height;
623 socket->have_size = TRUE;
626 g_message ("GtkSocket - window created with size: %d %d",
627 socket->request_width,
628 socket->request_height));
630 gtk_widget_queue_resize (widget);
633 return_val = GDK_FILTER_REMOVE;
638 case ConfigureRequest:
640 XConfigureRequestEvent *xcre = &xevent->xconfigurerequest;
642 if (!socket->plug_window)
643 gtk_socket_add_window (socket, xcre->window);
645 if (xcre->window == GDK_WINDOW_XWINDOW (socket->plug_window))
647 if (xcre->value_mask & (CWWidth | CWHeight))
649 socket->request_width = xcre->width;
650 socket->request_height = xcre->height;
651 socket->have_size = TRUE;
654 g_message ("GtkSocket - configure request: %d %d",
655 socket->request_width,
656 socket->request_height));
658 gtk_widget_queue_resize (widget);
660 else if (xcre->value_mask & (CWX | CWY))
662 gtk_socket_send_configure_event (socket);
664 /* Ignore stacking requests. */
666 return_val = GDK_FILTER_REMOVE;
673 XDestroyWindowEvent *xdwe = &xevent->xdestroywindow;
675 if (socket->plug_window &&
676 (xdwe->window == GDK_WINDOW_XWINDOW (socket->plug_window)))
681 g_message ("GtkSocket - destroy notify"));
683 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (socket));
684 if (toplevel && GTK_IS_WINDOW (toplevel))
685 gtk_window_remove_embedded_xid (GTK_WINDOW (toplevel), xdwe->window);
686 gdk_window_destroy_notify (socket->plug_window);
687 gtk_widget_destroy (widget);
689 socket->plug_window = NULL;
691 return_val = GDK_FILTER_REMOVE;
697 if (xevent->xfocus.mode == EMBEDDED_APP_WANTS_FOCUS)
699 gtk_socket_claim_focus (socket);
701 else if (xevent->xfocus.detail == NotifyInferior)
705 toplevel = gtk_widget_get_ancestor (widget, GTK_TYPE_WINDOW);
709 XSetInputFocus (GDK_DISPLAY (),
710 GDK_WINDOW_XWINDOW (toplevel->window),
711 RevertToParent, CurrentTime); /* FIXME? */
715 return_val = GDK_FILTER_REMOVE;
718 return_val = GDK_FILTER_REMOVE;
721 if (!socket->plug_window)
722 gtk_socket_add_window (socket, xevent->xmaprequest.window);
724 if (xevent->xmaprequest.window ==
725 GDK_WINDOW_XWINDOW (socket->plug_window))
728 g_message ("GtkSocket - Map Request"));
730 gdk_error_trap_push ();
731 gdk_window_show (socket->plug_window);
733 gdk_error_trap_pop ();
735 return_val = GDK_FILTER_REMOVE;
739 if (xevent->xproperty.window ==
740 GDK_WINDOW_XWINDOW (socket->plug_window))
742 GdkDragProtocol protocol;
744 if ((xevent->xproperty.atom == gdk_atom_intern ("XdndAware", FALSE)) ||
745 (xevent->xproperty.atom == gdk_atom_intern ("_MOTIF_DRAG_RECEIVER_INFO", FALSE)))
747 gdk_error_trap_push ();
748 if (gdk_drag_get_protocol (xevent->xproperty.window, &protocol))
749 gtk_drag_dest_set_proxy (GTK_WIDGET (socket),
753 gdk_error_trap_pop ();
755 return_val = GDK_FILTER_REMOVE;
765 gtk_socket_get_type (void)
767 g_error ("GtkSocket not implemented");
774 g_error ("GtkSocket not implemented");
779 gtk_socket_steal (GtkSocket *socket, GdkNativeWindow id)
781 g_error ("GtkSocket not implemented");
784 #endif /* GDK_WINDOWING */