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
memset (&xkey, 0, sizeof (xkey));
127
xkey.type = (gdk_event->type == GDK_KEY_PRESS) ? KeyPress : KeyRelease;
128
xkey.window = GDK_WINDOW_XWINDOW (socket->plug_window);
129
xkey.root = GDK_WINDOW_XWINDOW (gdk_screen_get_root_window (screen));
130
xkey.subwindow = None;
131
xkey.time = gdk_event->key.time;
136
xkey.state = gdk_event->key.state;
137
xkey.keycode = gdk_event->key.hardware_keycode;
138
xkey.same_screen = True;/* FIXME ? */
140
gdk_error_trap_push ();
141
XSendEvent (GDK_WINDOW_XDISPLAY (socket->plug_window),
142
GDK_WINDOW_XWINDOW (socket->plug_window),
144
(mask_key_presses ? KeyPressMask : NoEventMask),
146
gdk_display_sync (gdk_screen_get_display (screen));
147
gdk_error_trap_pop ();
151
_gtk_socket_windowing_focus_change (GtkSocket *socket,
155
_gtk_xembed_send_focus_message (socket->plug_window,
156
XEMBED_FOCUS_IN, XEMBED_FOCUS_CURRENT);
158
_gtk_xembed_send_message (socket->plug_window,
159
XEMBED_FOCUS_OUT, 0, 0, 0);
163
_gtk_socket_windowing_update_active (GtkSocket *socket,
166
_gtk_xembed_send_message (socket->plug_window,
167
active ? XEMBED_WINDOW_ACTIVATE : XEMBED_WINDOW_DEACTIVATE,
172
_gtk_socket_windowing_update_modality (GtkSocket *socket,
175
_gtk_xembed_send_message (socket->plug_window,
176
modality ? XEMBED_MODALITY_ON : XEMBED_MODALITY_OFF,
181
_gtk_socket_windowing_focus (GtkSocket *socket,
182
GtkDirectionType direction)
190
case GTK_DIR_TAB_BACKWARD:
191
detail = XEMBED_FOCUS_LAST;
195
case GTK_DIR_TAB_FORWARD:
196
detail = XEMBED_FOCUS_FIRST;
200
_gtk_xembed_send_focus_message (socket->plug_window, XEMBED_FOCUS_IN, detail);
204
_gtk_socket_windowing_send_configure_event (GtkSocket *socket)
206
XConfigureEvent xconfigure;
209
g_return_if_fail (socket->plug_window != NULL);
211
memset (&xconfigure, 0, sizeof (xconfigure));
212
xconfigure.type = ConfigureNotify;
214
xconfigure.event = GDK_WINDOW_XWINDOW (socket->plug_window);
215
xconfigure.window = GDK_WINDOW_XWINDOW (socket->plug_window);
217
/* The ICCCM says that synthetic events should have root relative
218
* coordinates. We still aren't really ICCCM compliant, since
219
* we don't send events when the real toplevel is moved.
221
gdk_error_trap_push ();
222
gdk_window_get_origin (socket->plug_window, &x, &y);
223
gdk_error_trap_pop ();
227
xconfigure.width = GTK_WIDGET(socket)->allocation.width;
228
xconfigure.height = GTK_WIDGET(socket)->allocation.height;
230
xconfigure.border_width = 0;
231
xconfigure.above = None;
232
xconfigure.override_redirect = False;
234
gdk_error_trap_push ();
235
XSendEvent (GDK_WINDOW_XDISPLAY (socket->plug_window),
236
GDK_WINDOW_XWINDOW (socket->plug_window),
237
False, NoEventMask, (XEvent *)&xconfigure);
238
gdk_display_sync (gtk_widget_get_display (GTK_WIDGET (socket)));
239
gdk_error_trap_pop ();
243
_gtk_socket_windowing_select_plug_window_input (GtkSocket *socket)
245
XSelectInput (GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (GTK_WIDGET (socket))),
246
GDK_WINDOW_XWINDOW (socket->plug_window),
247
StructureNotifyMask | PropertyChangeMask);
251
_gtk_socket_windowing_embed_get_info (GtkSocket *socket)
253
unsigned long version;
256
socket->xembed_version = -1;
257
if (xembed_get_info (socket->plug_window, &version, &flags))
259
socket->xembed_version = MIN (GTK_XEMBED_PROTOCOL_VERSION, version);
260
socket->is_mapped = (flags & XEMBED_MAPPED) != 0;
264
/* FIXME, we should probably actually check the state before we started */
265
socket->is_mapped = TRUE;
270
_gtk_socket_windowing_embed_notify (GtkSocket *socket)
273
GdkDisplay *display = gtk_widget_get_display (GTK_WIDGET (socket));
275
XFixesChangeSaveSet (GDK_DISPLAY_XDISPLAY (display),
276
GDK_WINDOW_XWINDOW (socket->plug_window),
277
SetModeInsert, SaveSetRoot, SaveSetUnmap);
279
_gtk_xembed_send_message (socket->plug_window,
280
XEMBED_EMBEDDED_NOTIFY, 0,
281
GDK_WINDOW_XWINDOW (GTK_WIDGET (socket)->window),
282
socket->xembed_version);
286
xembed_get_info (GdkWindow *window,
287
unsigned long *version,
288
unsigned long *flags)
290
GdkDisplay *display = gdk_drawable_get_display (window);
291
Atom xembed_info_atom = gdk_x11_get_xatom_by_name_for_display (display, "_XEMBED_INFO");
294
unsigned long nitems, bytes_after;
296
unsigned long *data_long;
299
gdk_error_trap_push();
300
status = XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display),
301
GDK_WINDOW_XWINDOW (window),
304
xembed_info_atom, &type, &format,
305
&nitems, &bytes_after, &data);
306
gdk_error_trap_pop();
308
if (status != Success)
309
return FALSE; /* Window vanished? */
311
if (type == None) /* No info property */
314
if (type != xembed_info_atom)
316
g_warning ("_XEMBED_INFO property has wrong type\n");
322
g_warning ("_XEMBED_INFO too short\n");
327
data_long = (unsigned long *)data;
329
*version = data_long[0];
331
*flags = data_long[1] & XEMBED_MAPPED;
338
_gtk_socket_windowing_embed_get_focus_wrapped (void)
340
return _gtk_xembed_get_focus_wrapped ();
344
_gtk_socket_windowing_embed_set_focus_wrapped (void)
346
_gtk_xembed_set_focus_wrapped ();
350
handle_xembed_message (GtkSocket *socket,
351
XEmbedMessageType message,
357
GTK_NOTE (PLUGSOCKET,
358
g_message ("GtkSocket: %s received", _gtk_xembed_message_name (message)));
362
case XEMBED_EMBEDDED_NOTIFY:
363
case XEMBED_WINDOW_ACTIVATE:
364
case XEMBED_WINDOW_DEACTIVATE:
365
case XEMBED_MODALITY_ON:
366
case XEMBED_MODALITY_OFF:
367
case XEMBED_FOCUS_IN:
368
case XEMBED_FOCUS_OUT:
369
g_warning ("GtkSocket: Invalid _XEMBED message %s received", _gtk_xembed_message_name (message));
372
case XEMBED_REQUEST_FOCUS:
373
_gtk_socket_claim_focus (socket, TRUE);
376
case XEMBED_FOCUS_NEXT:
377
case XEMBED_FOCUS_PREV:
378
_gtk_socket_advance_toplevel_focus (socket,
379
(message == XEMBED_FOCUS_NEXT ?
380
GTK_DIR_TAB_FORWARD : GTK_DIR_TAB_BACKWARD));
383
case XEMBED_GTK_GRAB_KEY:
384
_gtk_socket_add_grabbed_key (socket, data1, data2);
386
case XEMBED_GTK_UNGRAB_KEY:
387
_gtk_socket_remove_grabbed_key (socket, data1, data2);
390
case XEMBED_GRAB_KEY:
391
case XEMBED_UNGRAB_KEY:
395
GTK_NOTE (PLUGSOCKET,
396
g_message ("GtkSocket: Ignoring unknown _XEMBED message of type %d", message));
402
_gtk_socket_windowing_filter_func (GdkXEvent *gdk_xevent,
411
GdkFilterReturn return_val;
413
socket = GTK_SOCKET (data);
415
return_val = GDK_FILTER_CONTINUE;
417
if (socket->plug_widget)
420
widget = GTK_WIDGET (socket);
421
xevent = (XEvent *)gdk_xevent;
422
display = gtk_widget_get_display (widget);
424
switch (xevent->type)
427
if (xevent->xclient.message_type == gdk_x11_get_xatom_by_name_for_display (display, "_XEMBED"))
429
_gtk_xembed_push_message (xevent);
430
handle_xembed_message (socket,
431
xevent->xclient.data.l[1],
432
xevent->xclient.data.l[2],
433
xevent->xclient.data.l[3],
434
xevent->xclient.data.l[4],
435
xevent->xclient.data.l[0]);
436
_gtk_xembed_pop_message ();
438
return_val = GDK_FILTER_REMOVE;
444
XCreateWindowEvent *xcwe = &xevent->xcreatewindow;
446
if (!socket->plug_window)
448
_gtk_socket_add_window (socket, xcwe->window, FALSE);
450
if (socket->plug_window)
452
GTK_NOTE (PLUGSOCKET, g_message ("GtkSocket - window created"));
456
return_val = GDK_FILTER_REMOVE;
461
case ConfigureRequest:
463
XConfigureRequestEvent *xcre = &xevent->xconfigurerequest;
465
if (!socket->plug_window)
466
_gtk_socket_add_window (socket, xcre->window, FALSE);
468
if (socket->plug_window)
470
GtkSocketPrivate *private = _gtk_socket_get_private (socket);
472
if (xcre->value_mask & (CWWidth | CWHeight))
474
GTK_NOTE (PLUGSOCKET,
475
g_message ("GtkSocket - configure request: %d %d",
476
socket->request_width,
477
socket->request_height));
479
private->resize_count++;
480
gtk_widget_queue_resize (widget);
482
else if (xcre->value_mask & (CWX | CWY))
484
_gtk_socket_windowing_send_configure_event (socket);
486
/* Ignore stacking requests. */
488
return_val = GDK_FILTER_REMOVE;
495
XDestroyWindowEvent *xdwe = &xevent->xdestroywindow;
497
/* Note that we get destroy notifies both from SubstructureNotify on
498
* our window and StructureNotify on socket->plug_window
500
if (socket->plug_window && (xdwe->window == GDK_WINDOW_XWINDOW (socket->plug_window)))
504
GTK_NOTE (PLUGSOCKET, g_message ("GtkSocket - destroy notify"));
506
gdk_window_destroy_notify (socket->plug_window);
507
_gtk_socket_end_embedding (socket);
509
g_object_ref (widget);
510
g_signal_emit_by_name (widget, "plug_removed", &result);
512
gtk_widget_destroy (widget);
513
g_object_unref (widget);
515
return_val = GDK_FILTER_REMOVE;
521
if (xevent->xfocus.mode == EMBEDDED_APP_WANTS_FOCUS)
523
_gtk_socket_claim_focus (socket, TRUE);
525
return_val = GDK_FILTER_REMOVE;
528
return_val = GDK_FILTER_REMOVE;
531
if (!socket->plug_window)
533
_gtk_socket_add_window (socket, xevent->xmaprequest.window, FALSE);
536
if (socket->plug_window)
538
GTK_NOTE (PLUGSOCKET, g_message ("GtkSocket - Map Request"));
540
_gtk_socket_handle_map_request (socket);
541
return_val = GDK_FILTER_REMOVE;
545
if (socket->plug_window &&
546
xevent->xproperty.window == GDK_WINDOW_XWINDOW (socket->plug_window))
548
GdkDragProtocol protocol;
550
if (xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "WM_NORMAL_HINTS"))
552
GTK_NOTE (PLUGSOCKET, g_message ("GtkSocket - received PropertyNotify for plug's WM_NORMAL_HINTS"));
553
socket->have_size = FALSE;
554
gtk_widget_queue_resize (widget);
555
return_val = GDK_FILTER_REMOVE;
557
else if ((xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "XdndAware")) ||
558
(xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_RECEIVER_INFO")))
560
gdk_error_trap_push ();
561
if (gdk_drag_get_protocol_for_display (display,
562
xevent->xproperty.window,
564
gtk_drag_dest_set_proxy (GTK_WIDGET (socket),
568
gdk_display_sync (display);
569
gdk_error_trap_pop ();
570
return_val = GDK_FILTER_REMOVE;
572
else if (xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "_XEMBED_INFO"))
576
if (xembed_get_info (socket->plug_window, NULL, &flags))
578
gboolean was_mapped = socket->is_mapped;
579
gboolean is_mapped = (flags & XEMBED_MAPPED) != 0;
581
if (was_mapped != is_mapped)
584
_gtk_socket_handle_map_request (socket);
587
gdk_error_trap_push ();
588
gdk_window_show (socket->plug_window);
590
gdk_error_trap_pop ();
592
_gtk_socket_unmap_notify (socket);
596
return_val = GDK_FILTER_REMOVE;
602
XReparentEvent *xre = &xevent->xreparent;
604
GTK_NOTE (PLUGSOCKET, g_message ("GtkPlug: ReparentNotify received\n"));
605
if (!socket->plug_window && xre->parent == GDK_WINDOW_XWINDOW (widget->window))
607
_gtk_socket_add_window (socket, xre->window, FALSE);
609
if (socket->plug_window)
611
GTK_NOTE (PLUGSOCKET, g_message ("GtkSocket - window reparented"));
614
return_val = GDK_FILTER_REMOVE;
620
if (socket->plug_window &&
621
xevent->xunmap.window == GDK_WINDOW_XWINDOW (socket->plug_window))
623
GTK_NOTE (PLUGSOCKET, g_message ("GtkSocket - Unmap notify"));
625
_gtk_socket_unmap_notify (socket);
626
return_val = GDK_FILTER_REMOVE;