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/.
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)
153 gpointer user_data = NULL;
155 widget = GTK_WIDGET (socket);
157 socket->plug_window = gdk_window_lookup (id);
159 gdk_error_trap_push ();
161 if (socket->plug_window)
162 gdk_window_get_user_data (socket->plug_window,
168 GtkWidget *child_widget;
170 child_widget = GTK_WIDGET (socket->plug_window->user_data);
173 g_warning("Stealing from same app not yet implemented");
175 socket->same_app = TRUE;
179 socket->plug_window = gdk_window_foreign_new (id);
180 if (!socket->plug_window) /* was deleted before we could get it */
182 gdk_error_trap_pop ();
186 socket->same_app = FALSE;
187 socket->have_size = FALSE;
189 XSelectInput (GDK_DISPLAY (),
190 GDK_WINDOW_XWINDOW(socket->plug_window),
191 StructureNotifyMask | PropertyChangeMask);
193 gtk_widget_queue_resize (widget);
196 gdk_window_hide (socket->plug_window);
197 gdk_window_reparent (socket->plug_window, widget->window, 0, 0);
200 gdk_error_trap_pop ();
202 socket->need_map = TRUE;
206 gtk_socket_realize (GtkWidget *widget)
209 GdkWindowAttr attributes;
210 gint attributes_mask;
211 XWindowAttributes xattrs;
213 g_return_if_fail (widget != NULL);
214 g_return_if_fail (GTK_IS_SOCKET (widget));
216 socket = GTK_SOCKET (widget);
217 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
219 attributes.window_type = GDK_WINDOW_CHILD;
220 attributes.x = widget->allocation.x;
221 attributes.y = widget->allocation.y;
222 attributes.width = widget->allocation.width;
223 attributes.height = widget->allocation.height;
224 attributes.wclass = GDK_INPUT_OUTPUT;
225 attributes.visual = gtk_widget_get_visual (widget);
226 attributes.colormap = gtk_widget_get_colormap (widget);
227 attributes.event_mask = GDK_FOCUS_CHANGE_MASK;
229 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
231 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
232 &attributes, attributes_mask);
233 gdk_window_set_user_data (widget->window, socket);
235 widget->style = gtk_style_attach (widget->style, widget->window);
236 gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
238 XGetWindowAttributes (GDK_DISPLAY (),
239 GDK_WINDOW_XWINDOW (widget->window),
242 XSelectInput (GDK_DISPLAY (),
243 GDK_WINDOW_XWINDOW(widget->window),
244 xattrs.your_event_mask |
245 SubstructureNotifyMask | SubstructureRedirectMask);
247 gdk_window_add_filter (widget->window, gtk_socket_filter_func, widget);
249 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
251 /* We sync here so that we make sure that if the XID for
252 * our window is passed to another application, SubstructureRedirectMask
253 * will be set by the time the other app creates its window.
259 gtk_socket_unrealize (GtkWidget *widget)
263 g_return_if_fail (widget != NULL);
264 g_return_if_fail (GTK_IS_SOCKET (widget));
266 socket = GTK_SOCKET (widget);
268 if (socket->plug_window)
270 GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (socket));
271 if (toplevel && GTK_IS_WINDOW (toplevel))
272 gtk_window_remove_embedded_xid (GTK_WINDOW (toplevel),
273 GDK_WINDOW_XWINDOW (socket->plug_window));
276 if (GTK_WIDGET_CLASS (parent_class)->unrealize)
277 (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
281 gtk_socket_size_request (GtkWidget *widget,
282 GtkRequisition *requisition)
286 g_return_if_fail (widget != NULL);
287 g_return_if_fail (GTK_IS_SOCKET (widget));
288 g_return_if_fail (requisition != NULL);
290 socket = GTK_SOCKET (widget);
292 if (!socket->have_size && socket->plug_window)
297 gdk_error_trap_push ();
299 if (XGetWMNormalHints (GDK_DISPLAY(),
300 GDK_WINDOW_XWINDOW (socket->plug_window),
303 /* This is obsolete, according the X docs, but many programs
305 if (hints.flags & (PSize | USSize))
307 socket->request_width = hints.width;
308 socket->request_height = hints.height;
310 else if (hints.flags & PMinSize)
312 socket->request_width = hints.min_width;
313 socket->request_height = hints.min_height;
315 else if (hints.flags & PBaseSize)
317 socket->request_width = hints.base_width;
318 socket->request_height = hints.base_height;
321 socket->have_size = TRUE; /* don't check again? */
323 gdk_error_trap_pop ();
326 requisition->width = MAX (socket->request_width, 1);
327 requisition->height = MAX (socket->request_height, 1);
331 gtk_socket_size_allocate (GtkWidget *widget,
332 GtkAllocation *allocation)
336 g_return_if_fail (widget != NULL);
337 g_return_if_fail (GTK_IS_SOCKET (widget));
338 g_return_if_fail (allocation != NULL);
340 socket = GTK_SOCKET (widget);
342 widget->allocation = *allocation;
343 if (GTK_WIDGET_REALIZED (widget))
345 gdk_window_move_resize (widget->window,
346 allocation->x, allocation->y,
347 allocation->width, allocation->height);
349 if (socket->plug_window)
351 gdk_error_trap_push ();
353 if (!socket->need_map &&
354 (allocation->width == socket->current_width) &&
355 (allocation->height == socket->current_height))
357 gtk_socket_send_configure_event (socket);
359 g_message ("GtkSocket - allocated no change: %d %d",
360 allocation->width, allocation->height));
364 gdk_window_move_resize (socket->plug_window,
366 allocation->width, allocation->height);
368 g_message ("GtkSocket - allocated: %d %d",
369 allocation->width, allocation->height));
370 socket->current_width = allocation->width;
371 socket->current_height = allocation->height;
374 if (socket->need_map)
376 gdk_window_show (socket->plug_window);
377 socket->need_map = FALSE;
381 gdk_error_trap_pop ();
387 gtk_socket_focus_in_event (GtkWidget *widget, GdkEventFocus *event)
390 g_return_val_if_fail (GTK_IS_SOCKET (widget), FALSE);
391 socket = GTK_SOCKET (widget);
393 if (socket->focus_in && socket->plug_window)
395 gdk_error_trap_push ();
396 XSetInputFocus (GDK_DISPLAY (),
397 GDK_WINDOW_XWINDOW (socket->plug_window),
398 RevertToParent, GDK_CURRENT_TIME);
400 gdk_error_trap_pop ();
407 gtk_socket_focus_out_event (GtkWidget *widget, GdkEventFocus *event)
412 g_return_val_if_fail (GTK_IS_SOCKET (widget), FALSE);
413 socket = GTK_SOCKET (widget);
415 toplevel = gtk_widget_get_ancestor (widget, GTK_TYPE_WINDOW);
419 XSetInputFocus (GDK_DISPLAY (),
420 GDK_WINDOW_XWINDOW (toplevel->window),
421 RevertToParent, CurrentTime); /* FIXME? */
424 socket->focus_in = FALSE;
430 gtk_socket_claim_focus (GtkSocket *socket)
433 socket->focus_in = TRUE;
435 /* Oh, the trickery... */
437 GTK_WIDGET_SET_FLAGS (socket, GTK_CAN_FOCUS);
438 gtk_widget_grab_focus (GTK_WIDGET (socket));
439 GTK_WIDGET_UNSET_FLAGS (socket, GTK_CAN_FOCUS);
441 /* FIXME: we might grab the focus even if we don't have
442 * it as an app... (and see _focus_in ()) */
443 if (socket->plug_window)
445 gdk_error_trap_push ();
446 XSetInputFocus (GDK_DISPLAY (),
447 GDK_WINDOW_XWINDOW (socket->plug_window),
448 RevertToParent, GDK_CURRENT_TIME);
450 gdk_error_trap_pop ();
455 gtk_socket_focus (GtkContainer *container, GtkDirectionType direction)
459 g_return_val_if_fail (GTK_IS_SOCKET (container), FALSE);
461 socket = GTK_SOCKET (container);
463 if (!socket->focus_in && socket->plug_window)
467 gtk_socket_claim_focus (socket);
469 xevent.xkey.type = KeyPress;
470 xevent.xkey.display = GDK_DISPLAY ();
471 xevent.xkey.window = GDK_WINDOW_XWINDOW (socket->plug_window);
472 xevent.xkey.root = GDK_ROOT_WINDOW (); /* FIXME */
473 xevent.xkey.time = GDK_CURRENT_TIME; /* FIXME */
474 /* FIXME, the following might cause big problems for
478 xevent.xkey.x_root = 0;
479 xevent.xkey.y_root = 0;
480 xevent.xkey.state = 0;
481 xevent.xkey.same_screen = TRUE; /* FIXME ? */
486 xevent.xkey.keycode = XKeysymToKeycode(GDK_DISPLAY(), GDK_Up);
489 xevent.xkey.keycode = XKeysymToKeycode(GDK_DISPLAY(), GDK_Down);
492 xevent.xkey.keycode = XKeysymToKeycode(GDK_DISPLAY(), GDK_Left);
495 xevent.xkey.keycode = XKeysymToKeycode(GDK_DISPLAY(), GDK_Right);
497 case GTK_DIR_TAB_FORWARD:
498 xevent.xkey.keycode = XKeysymToKeycode(GDK_DISPLAY(), GDK_Tab);
500 case GTK_DIR_TAB_BACKWARD:
501 xevent.xkey.keycode = XKeysymToKeycode(GDK_DISPLAY(), GDK_Tab);
502 xevent.xkey.state = ShiftMask;
507 gdk_error_trap_push ();
508 XSendEvent (gdk_display,
509 GDK_WINDOW_XWINDOW (socket->plug_window),
510 False, NoEventMask, &xevent);
512 gdk_error_trap_pop ();
523 gtk_socket_send_configure_event (GtkSocket *socket)
527 g_return_if_fail (socket->plug_window != NULL);
529 event.xconfigure.type = ConfigureNotify;
530 event.xconfigure.display = gdk_display;
532 event.xconfigure.event = GDK_WINDOW_XWINDOW (socket->plug_window);
533 event.xconfigure.window = GDK_WINDOW_XWINDOW (socket->plug_window);
535 event.xconfigure.x = 0;
536 event.xconfigure.y = 0;
537 event.xconfigure.width = GTK_WIDGET(socket)->allocation.width;
538 event.xconfigure.height = GTK_WIDGET(socket)->allocation.height;
540 event.xconfigure.border_width = 0;
541 event.xconfigure.above = None;
542 event.xconfigure.override_redirect = False;
544 gdk_error_trap_push ();
545 XSendEvent (gdk_display,
546 GDK_WINDOW_XWINDOW (socket->plug_window),
547 False, NoEventMask, &event);
549 gdk_error_trap_pop ();
553 gtk_socket_add_window (GtkSocket *socket, GdkNativeWindow xid)
555 socket->plug_window = gdk_window_lookup (xid);
556 socket->same_app = TRUE;
558 if (!socket->plug_window)
561 GdkDragProtocol protocol;
563 socket->plug_window = gdk_window_foreign_new (xid);
564 if (!socket->plug_window) /* Already gone */
567 socket->same_app = FALSE;
569 gdk_error_trap_push ();
570 XSelectInput (GDK_DISPLAY (),
571 GDK_WINDOW_XWINDOW(socket->plug_window),
572 StructureNotifyMask | PropertyChangeMask);
574 if (gdk_drag_get_protocol (xid, &protocol))
575 gtk_drag_dest_set_proxy (GTK_WIDGET (socket), socket->plug_window,
578 gdk_error_trap_pop ();
580 gdk_window_add_filter (socket->plug_window,
581 gtk_socket_filter_func, socket);
583 /* Add a pointer to the socket on our toplevel window */
585 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (socket));
586 if (toplevel && GTK_IS_WINDOW (toplevel))
588 gtk_window_add_embedded_xid (GTK_WINDOW (toplevel), xid);
593 static GdkFilterReturn
594 gtk_socket_filter_func (GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data)
600 GdkFilterReturn return_val;
602 socket = GTK_SOCKET (data);
603 widget = GTK_WIDGET (socket);
604 xevent = (XEvent *)gdk_xevent;
606 return_val = GDK_FILTER_CONTINUE;
608 switch (xevent->type)
612 XCreateWindowEvent *xcwe = &xevent->xcreatewindow;
614 if (!socket->plug_window)
616 gtk_socket_add_window (socket, xcwe->window);
618 gdk_error_trap_push ();
619 gdk_window_move_resize(socket->plug_window,
621 widget->allocation.width,
622 widget->allocation.height);
624 gdk_error_trap_pop ();
626 socket->request_width = xcwe->width;
627 socket->request_height = xcwe->height;
628 socket->have_size = TRUE;
631 g_message ("GtkSocket - window created with size: %d %d",
632 socket->request_width,
633 socket->request_height));
635 gtk_widget_queue_resize (widget);
638 return_val = GDK_FILTER_REMOVE;
643 case ConfigureRequest:
645 XConfigureRequestEvent *xcre = &xevent->xconfigurerequest;
647 if (!socket->plug_window)
648 gtk_socket_add_window (socket, xcre->window);
650 if (xcre->window == GDK_WINDOW_XWINDOW (socket->plug_window))
652 if (xcre->value_mask & (CWWidth | CWHeight))
654 socket->request_width = xcre->width;
655 socket->request_height = xcre->height;
656 socket->have_size = TRUE;
659 g_message ("GtkSocket - configure request: %d %d",
660 socket->request_width,
661 socket->request_height));
663 gtk_widget_queue_resize (widget);
665 else if (xcre->value_mask & (CWX | CWY))
667 gtk_socket_send_configure_event (socket);
669 /* Ignore stacking requests. */
671 return_val = GDK_FILTER_REMOVE;
678 XDestroyWindowEvent *xdwe = &xevent->xdestroywindow;
680 if (socket->plug_window &&
681 (xdwe->window == GDK_WINDOW_XWINDOW (socket->plug_window)))
686 g_message ("GtkSocket - destroy notify"));
688 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (socket));
689 if (toplevel && GTK_IS_WINDOW (toplevel))
690 gtk_window_remove_embedded_xid (GTK_WINDOW (toplevel), xdwe->window);
691 gdk_window_destroy_notify (socket->plug_window);
692 gtk_widget_destroy (widget);
694 socket->plug_window = NULL;
696 return_val = GDK_FILTER_REMOVE;
702 if (xevent->xfocus.mode == EMBEDDED_APP_WANTS_FOCUS)
704 gtk_socket_claim_focus (socket);
706 else if (xevent->xfocus.detail == NotifyInferior)
710 toplevel = gtk_widget_get_ancestor (widget, GTK_TYPE_WINDOW);
714 XSetInputFocus (GDK_DISPLAY (),
715 GDK_WINDOW_XWINDOW (toplevel->window),
716 RevertToParent, CurrentTime); /* FIXME? */
720 return_val = GDK_FILTER_REMOVE;
723 return_val = GDK_FILTER_REMOVE;
726 if (!socket->plug_window)
727 gtk_socket_add_window (socket, xevent->xmaprequest.window);
729 if (xevent->xmaprequest.window ==
730 GDK_WINDOW_XWINDOW (socket->plug_window))
733 g_message ("GtkSocket - Map Request"));
735 gdk_error_trap_push ();
736 gdk_window_show (socket->plug_window);
738 gdk_error_trap_pop ();
740 return_val = GDK_FILTER_REMOVE;
744 if (xevent->xproperty.window ==
745 GDK_WINDOW_XWINDOW (socket->plug_window))
747 GdkDragProtocol protocol;
749 if ((xevent->xproperty.atom == gdk_atom_intern ("XdndAware", FALSE)) ||
750 (xevent->xproperty.atom == gdk_atom_intern ("_MOTIF_DRAG_RECEIVER_INFO", FALSE)))
752 gdk_error_trap_push ();
753 if (gdk_drag_get_protocol (xevent->xproperty.window, &protocol))
754 gtk_drag_dest_set_proxy (GTK_WIDGET (socket),
758 gdk_error_trap_pop ();
760 return_val = GDK_FILTER_REMOVE;
770 gtk_socket_get_type (void)
772 g_error ("GtkSocket not implemented");
779 g_error ("GtkSocket not implemented");
784 gtk_socket_steal (GtkSocket *socket, GdkNativeWindow id)
786 g_error ("GtkSocket not implemented");
789 #endif /* GDK_WINDOWING */