gtksocket.c 45.1 KB
Newer Older
Cody Russell's avatar
Cody Russell committed
1
/* GTK - The GIMP Toolkit
2 3 4
 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
 *
 * This library is free software; you can redistribute it and/or
5
 * modify it under the terms of the GNU Lesser General Public
6 7 8 9 10 11
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
 * Lesser General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU Lesser General Public
Javier Jardón's avatar
Javier Jardón committed
15
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.Free
16 17 18 19
 */

/* By Owen Taylor <otaylor@gtk.org>              98/4/4 */

20
/*
21
 * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
22 23 24 25 26
 * file for a list of people on the GTK+ Team.  See the ChangeLog
 * files for a list of changes.  These files are distributed with
 * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
 */

27
#include "config.h"
28

29
#include "gtksocketprivate.h"
30

31 32
#include <string.h>

33
#include "gtkmarshalers.h"
34
#include "gtksizerequest.h"
35
#include "gtkplug.h"
36
#include "gtkprivate.h"
37
#include "gtkdnd.h"
38
#include "gtkdebug.h"
39
#include "gtkintl.h"
40
#include "gtkmain.h"
41
#include "gtkwidgetprivate.h"
42

43
#include <gdk/gdkx.h>
44 45 46 47 48 49 50
#include <gdk/gdkprivate.h>

#ifdef HAVE_XFIXES
#include <X11/extensions/Xfixes.h>
#endif

#include "gtkxembed.h"
51

52

53 54 55 56
/**
 * SECTION:gtksocket
 * @Short_description: Container for widgets from other processes
 * @Title: GtkSocket
57
 * @include: gtk/gtkx.h
58 59
 * @See_also: #GtkPlug, <ulink url="http://www.freedesktop.org/Standards/xembed-spec">XEmbed</ulink>
 *
60 61 62 63 64 65
 * Together with #GtkPlug, #GtkSocket provides the ability to embed
 * widgets from one process into another process in a fashion that
 * is transparent to the user. One process creates a #GtkSocket widget
 * and passes that widget's window ID to the other process, which then
 * creates a #GtkPlug with that window ID. Any widgets contained in the
 * #GtkPlug then will appear inside the first application's window.
66
 *
67 68 69
 * The socket's window ID is obtained by using gtk_socket_get_id().
 * Before using this function, the socket must have been realized,
 * and for hence, have been added to its parent.
70 71 72
 *
 * <example>
 * <title>Obtaining the window ID of a socket.</title>
73
 * |[<!-- language="C" -->
74 75 76 77
 * GtkWidget *socket = gtk_socket_new (<!-- -->);
 * gtk_widget_show (socket);
 * gtk_container_add (GTK_CONTAINER (parent), socket);
 *
78
 * /&ast; The following call is only necessary if one of
79
 *  * the ancestors of the socket is not yet visible.
80
 *  &ast;/
81 82 83
 * gtk_widget_realize (socket);
 * g_print ("The ID of the sockets window is %#x\n",
 *          gtk_socket_get_id (socket));
84
 * ]|
85 86 87
 * </example>
 *
 * Note that if you pass the window ID of the socket to another
88 89 90 91 92 93 94
 * process that will create a plug in the socket, you must make
 * sure that the socket widget is not destroyed until that plug
 * is created. Violating this rule will cause unpredictable
 * consequences, the most likely consequence being that the plug
 * will appear as a separate toplevel window. You can check if
 * the plug has been created by using gtk_socket_get_plug_window().
 * If it returns a non-%NULL value, then the plug has been
95 96
 * successfully created inside of the socket.
 *
97 98 99 100 101
 * When GTK+ is notified that the embedded window has been destroyed,
 * then it will destroy the socket as well. You should always,
 * therefore, be prepared for your sockets to be destroyed at any
 * time when the main event loop is running. To prevent this from
 * happening, you can connect to the #GtkSocket::plug-removed signal.
102 103 104
 *
 * The communication between a #GtkSocket and a #GtkPlug follows the
 * <ulink url="http://www.freedesktop.org/Standards/xembed-spec">XEmbed</ulink>
105 106 107 108
 * protocol. This protocol has also been implemented in other toolkits,
 * e.g. <application>Qt</application>, allowing the same level of
 * integration when embedding a <application>Qt</application> widget
 * in GTK or vice versa.
109
 *
110 111 112
 * The #GtkPlug and #GtkSocket widgets are only available when GTK+
 * is compiled for the X11 platform and %GDK_WINDOWING_X11 is defined.
 * They can only be used on a #GdkX11Display. To use #GtkPlug and
113
 * #GtkSocket, you need to include the `gtk/gtkx.h`
114
 * header.
115 116
 */

117 118
/* Forward declararations */

119
static void     gtk_socket_finalize             (GObject          *object);
120 121
static void     gtk_socket_notify               (GObject          *object,
						 GParamSpec       *pspec);
122 123
static void     gtk_socket_realize              (GtkWidget        *widget);
static void     gtk_socket_unrealize            (GtkWidget        *widget);
124 125 126 127 128 129
static void     gtk_socket_get_preferred_width  (GtkWidget        *widget,
                                                 gint             *minimum,
                                                 gint             *natural);
static void     gtk_socket_get_preferred_height (GtkWidget        *widget,
                                                 gint             *minimum,
                                                 gint             *natural);
130 131 132 133 134 135
static void     gtk_socket_size_allocate        (GtkWidget        *widget,
						 GtkAllocation    *allocation);
static void     gtk_socket_hierarchy_changed    (GtkWidget        *widget,
						 GtkWidget        *old_toplevel);
static void     gtk_socket_grab_notify          (GtkWidget        *widget,
						 gboolean          was_grabbed);
136
static gboolean gtk_socket_key_event            (GtkWidget        *widget,
137 138 139 140 141 142 143 144 145
						 GdkEventKey      *event);
static gboolean gtk_socket_focus                (GtkWidget        *widget,
						 GtkDirectionType  direction);
static void     gtk_socket_remove               (GtkContainer     *container,
						 GtkWidget        *widget);
static void     gtk_socket_forall               (GtkContainer     *container,
						 gboolean          include_internals,
						 GtkCallback       callback,
						 gpointer          callback_data);
146
static void     gtk_socket_add_window           (GtkSocket        *socket,
147
                                                 Window            xid,
148 149 150 151 152 153 154 155 156 157 158
                                                 gboolean          need_reparent);
static GdkFilterReturn gtk_socket_filter_func   (GdkXEvent        *gdk_xevent,
                                                 GdkEvent         *event,
                                                 gpointer          data);

static gboolean xembed_get_info                 (GdkWindow        *gdk_window,
                                                 unsigned long    *version,
                                                 unsigned long    *flags);

/* From Tk */
#define EMBEDDED_APP_WANTS_FOCUS NotifyNormal+20
159 160


161 162
/* Local data */

163 164 165 166 167 168
typedef struct
{
  guint			 accel_key;
  GdkModifierType	 accel_mods;
} GrabbedKey;

169 170 171 172 173 174 175 176
enum {
  PLUG_ADDED,
  PLUG_REMOVED,
  LAST_SIGNAL
}; 

static guint socket_signals[LAST_SIGNAL] = { 0 };

177
G_DEFINE_TYPE_WITH_PRIVATE (GtkSocket, gtk_socket, GTK_TYPE_CONTAINER)
178

179 180 181 182
static void
gtk_socket_finalize (GObject *object)
{
  GtkSocket *socket = GTK_SOCKET (object);
183 184 185
  GtkSocketPrivate *priv = socket->priv;

  g_object_unref (priv->accel_group);
186

Matthias Clasen's avatar
Matthias Clasen committed
187
  G_OBJECT_CLASS (gtk_socket_parent_class)->finalize (object);
188 189
}

190 191 192 193 194
static void
gtk_socket_class_init (GtkSocketClass *class)
{
  GtkWidgetClass *widget_class;
  GtkContainerClass *container_class;
195
  GObjectClass *gobject_class;
196

197
  gobject_class = (GObjectClass *) class;
198 199 200
  widget_class = (GtkWidgetClass*) class;
  container_class = (GtkContainerClass*) class;

201
  gobject_class->finalize = gtk_socket_finalize;
202
  gobject_class->notify = gtk_socket_notify;
203

204 205
  widget_class->realize = gtk_socket_realize;
  widget_class->unrealize = gtk_socket_unrealize;
206 207
  widget_class->get_preferred_width = gtk_socket_get_preferred_width;
  widget_class->get_preferred_height = gtk_socket_get_preferred_height;
208
  widget_class->size_allocate = gtk_socket_size_allocate;
209 210
  widget_class->hierarchy_changed = gtk_socket_hierarchy_changed;
  widget_class->grab_notify = gtk_socket_grab_notify;
211 212
  widget_class->key_press_event = gtk_socket_key_event;
  widget_class->key_release_event = gtk_socket_key_event;
213
  widget_class->focus = gtk_socket_focus;
214

215
  /* We don't want to show_all the in-process plug, if any.
216 217
   */
  widget_class->show_all = gtk_widget_show;
218

219 220
  container_class->remove = gtk_socket_remove;
  container_class->forall = gtk_socket_forall;
221

Matthias Clasen's avatar
Matthias Clasen committed
222 223 224 225 226 227 228
  /**
   * GtkSocket::plug-added:
   * @socket_: the object which received the signal
   *
   * This signal is emitted when a client is successfully
   * added to the socket. 
   */
229
  socket_signals[PLUG_ADDED] =
230
    g_signal_new (I_("plug-added"),
231 232 233 234
		  G_OBJECT_CLASS_TYPE (class),
		  G_SIGNAL_RUN_LAST,
		  G_STRUCT_OFFSET (GtkSocketClass, plug_added),
		  NULL, NULL,
235
		  _gtk_marshal_VOID__VOID,
Manish Singh's avatar
Manish Singh committed
236
		  G_TYPE_NONE, 0);
Matthias Clasen's avatar
Matthias Clasen committed
237 238 239 240 241 242 243 244 245 246 247

  /**
   * GtkSocket::plug-removed:
   * @socket_: the object which received the signal
   *
   * This signal is emitted when a client is removed from the socket. 
   * The default action is to destroy the #GtkSocket widget, so if you 
   * want to reuse it you must add a signal handler that returns %TRUE. 
   *
   * Return value: %TRUE to stop other handlers from being invoked.
   */
248
  socket_signals[PLUG_REMOVED] =
249
    g_signal_new (I_("plug-removed"),
250 251 252 253
		  G_OBJECT_CLASS_TYPE (class),
		  G_SIGNAL_RUN_LAST,
		  G_STRUCT_OFFSET (GtkSocketClass, plug_removed),
                  _gtk_boolean_handled_accumulator, NULL,
254
		  _gtk_marshal_BOOLEAN__VOID,
255
		  G_TYPE_BOOLEAN, 0);
256 257 258 259 260
}

static void
gtk_socket_init (GtkSocket *socket)
{
261 262
  GtkSocketPrivate *priv;

263
  priv = gtk_socket_get_instance_private (socket);
264
  socket->priv = priv;
265

266 267 268 269 270 271 272 273 274 275 276 277 278 279
  priv->request_width = 0;
  priv->request_height = 0;
  priv->current_width = 0;
  priv->current_height = 0;

  priv->plug_window = NULL;
  priv->plug_widget = NULL;
  priv->focus_in = FALSE;
  priv->have_size = FALSE;
  priv->need_map = FALSE;
  priv->active = FALSE;

  priv->accel_group = gtk_accel_group_new ();
  g_object_set_data (G_OBJECT (priv->accel_group), I_("gtk-socket"), socket);
280 281
}

282 283 284 285 286 287 288
/**
 * gtk_socket_new:
 * 
 * Create a new empty #GtkSocket.
 * 
 * Return value:  the new #GtkSocket.
 **/
289
GtkWidget*
Tim Janik's avatar
Tim Janik committed
290
gtk_socket_new (void)
291 292 293
{
  GtkSocket *socket;

294
  socket = g_object_new (GTK_TYPE_SOCKET, NULL);
295 296 297 298

  return GTK_WIDGET (socket);
}

299 300
/**
 * gtk_socket_add_id:
301
 * @socket_: a #GtkSocket
302
 * @window: the Window of a client participating in the XEMBED protocol.
303 304 305 306 307
 *
 * Adds an XEMBED client, such as a #GtkPlug, to the #GtkSocket.  The
 * client may be in the same process or in a different process. 
 * 
 * To embed a #GtkPlug in a #GtkSocket, you can either create the
308 309
 * #GtkPlug with <literal>gtk_plug_new (0)</literal>, call 
 * gtk_plug_get_id() to get the window ID of the plug, and then pass that to the
310 311 312 313 314 315 316 317
 * gtk_socket_add_id(), or you can call gtk_socket_get_id() to get the
 * window ID for the socket, and call gtk_plug_new() passing in that
 * ID.
 *
 * The #GtkSocket must have already be added into a toplevel window
 *  before you can make this call.
 **/
void           
318
gtk_socket_add_id (GtkSocket      *socket,
319
		   Window          window)
320 321
{
  g_return_if_fail (GTK_IS_SOCKET (socket));
322
  g_return_if_fail (_gtk_widget_get_anchored (GTK_WIDGET (socket)));
323

324
  if (!gtk_widget_get_realized (GTK_WIDGET (socket)))
325 326
    gtk_widget_realize (GTK_WIDGET (socket));

327
  gtk_socket_add_window (socket, window, TRUE);
328 329 330 331
}

/**
 * gtk_socket_get_id:
332
 * @socket_: a #GtkSocket.
333 334 335
 * 
 * Gets the window ID of a #GtkSocket widget, which can then
 * be used to create a client embedded inside the socket, for
336
 * instance with gtk_plug_new(). 
Matthias Clasen's avatar
Matthias Clasen committed
337 338 339
 *
 * The #GtkSocket must have already be added into a toplevel window 
 * before you can make this call.
340 341 342
 * 
 * Return value: the window ID for the socket
 **/
343
Window
344 345 346
gtk_socket_get_id (GtkSocket *socket)
{
  g_return_val_if_fail (GTK_IS_SOCKET (socket), 0);
347
  g_return_val_if_fail (_gtk_widget_get_anchored (GTK_WIDGET (socket)), 0);
348

349
  if (!gtk_widget_get_realized (GTK_WIDGET (socket)))
350 351
    gtk_widget_realize (GTK_WIDGET (socket));

352
  return GDK_WINDOW_XID (gtk_widget_get_window (GTK_WIDGET (socket)));
353 354
}

Tim Janik's avatar
Tim Janik committed
355 356 357 358 359 360 361
/**
 * gtk_socket_get_plug_window:
 * @socket_: a #GtkSocket.
 *
 * Retrieves the window of the plug. Use this to check if the plug has
 * been created inside of the socket.
 *
362
 * Return value: (transfer none): the window of the plug if available, or %NULL
Tim Janik's avatar
Tim Janik committed
363
 *
364
 * Since:  2.14
Tim Janik's avatar
Tim Janik committed
365 366 367 368 369 370
 **/
GdkWindow*
gtk_socket_get_plug_window (GtkSocket *socket)
{
  g_return_val_if_fail (GTK_IS_SOCKET (socket), NULL);

371
  return socket->priv->plug_window;
Tim Janik's avatar
Tim Janik committed
372 373
}

374 375 376
static void
gtk_socket_realize (GtkWidget *widget)
{
377 378
  GtkAllocation allocation;
  GdkWindow *window;
379
  GdkWindowAttr attributes;
380
  XWindowAttributes xattrs;
381 382
  gint attributes_mask;

383
  gtk_widget_set_realized (widget, TRUE);
384

385 386
  gtk_widget_get_allocation (widget, &allocation);

387
  attributes.window_type = GDK_WINDOW_CHILD;
388 389 390 391
  attributes.x = allocation.x;
  attributes.y = allocation.y;
  attributes.width = allocation.width;
  attributes.height = allocation.height;
392 393 394 395
  attributes.wclass = GDK_INPUT_OUTPUT;
  attributes.visual = gtk_widget_get_visual (widget);
  attributes.event_mask = GDK_FOCUS_CHANGE_MASK;

396
  attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
397

398 399 400
  window = gdk_window_new (gtk_widget_get_parent_window (widget),
                           &attributes, attributes_mask);
  gtk_widget_set_window (widget, window);
401
  gtk_widget_register_window (widget, window);
402

403 404
  gtk_style_context_set_background (gtk_widget_get_style_context (widget),
                                    window);
405

406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421
  XGetWindowAttributes (GDK_WINDOW_XDISPLAY (window),
			GDK_WINDOW_XID (window),
			&xattrs);

  /* Sooooo, it turns out that mozilla, as per the gtk2xt code selects
     for input on the socket with a mask of 0x0fffff (for god knows why)
     which includes ButtonPressMask causing a BadAccess if someone else
     also selects for this. As per the client-side windows merge we always
     normally selects for button press so we can emulate it on client
     side children that selects for button press. However, we don't need
     this for GtkSocket, so we unselect it here, fixing the crashes in
     firefox. */
  XSelectInput (GDK_WINDOW_XDISPLAY (window),
		GDK_WINDOW_XID (window), 
		(xattrs.your_event_mask & ~ButtonPressMask) |
		SubstructureNotifyMask | SubstructureRedirectMask);
422

423
  gdk_window_add_filter (window,
424
			 gtk_socket_filter_func,
425
			 widget);
426 427 428 429 430

  /* We sync here so that we make sure that if the XID for
   * our window is passed to another application, SubstructureRedirectMask
   * will be set by the time the other app creates its window.
   */
431
  gdk_display_sync (gtk_widget_get_display (widget));
432 433
}

434
/**
435
 * gtk_socket_end_embedding:
436 437 438 439
 * @socket: a #GtkSocket
 *
 * Called to end the embedding of a plug in the socket.
 */
440 441
static void
gtk_socket_end_embedding (GtkSocket *socket)
442
{
443
  GtkSocketPrivate *private = socket->priv;
444

445 446 447 448
  g_object_unref (private->plug_window);
  private->plug_window = NULL;
  private->current_width = 0;
  private->current_height = 0;
449
  private->resize_count = 0;
450

451
  gtk_accel_group_disconnect (private->accel_group, NULL);
452 453
}

454 455 456
static void
gtk_socket_unrealize (GtkWidget *widget)
{
457
  GtkSocket *socket = GTK_SOCKET (widget);
458
  GtkSocketPrivate *private = socket->priv;
459

460
  gtk_widget_set_realized (widget, FALSE);
461

462
  if (private->plug_widget)
463
    {
464
      _gtk_plug_remove_from_socket (GTK_PLUG (private->plug_widget), socket);
465
    }
466
  else if (private->plug_window)
467
    {
468
      gtk_socket_end_embedding (socket);
469 470
    }

471
  GTK_WIDGET_CLASS (gtk_socket_parent_class)->unrealize (widget);
472
}
473

474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505
static void
gtk_socket_size_request (GtkSocket *socket)
{
  GtkSocketPrivate *private = socket->priv;
  XSizeHints hints;
  long supplied;
	  
  gdk_error_trap_push ();

  private->request_width = 1;
  private->request_height = 1;
	  
  if (XGetWMNormalHints (GDK_WINDOW_XDISPLAY (private->plug_window),
			 GDK_WINDOW_XID (private->plug_window),
			 &hints, &supplied))
    {
      if (hints.flags & PMinSize)
	{
	  private->request_width = MAX (hints.min_width, 1);
	  private->request_height = MAX (hints.min_height, 1);
	}
      else if (hints.flags & PBaseSize)
	{
	  private->request_width = MAX (hints.base_width, 1);
	  private->request_height = MAX (hints.base_height, 1);
	}
    }
  private->have_size = TRUE;
  
  gdk_error_trap_pop_ignored ();
}

506
static void
507 508 509
gtk_socket_get_preferred_width (GtkWidget *widget,
                                gint      *minimum,
                                gint      *natural)
510
{
511
  GtkSocket *socket = GTK_SOCKET (widget);
512
  GtkSocketPrivate *private = socket->priv;
513

514
  if (private->plug_widget)
515
    {
516
      gtk_widget_get_preferred_width (private->plug_widget, minimum, natural);
517 518 519
    }
  else
    {
520
      if (private->is_mapped && !private->have_size && private->plug_window)
521
        gtk_socket_size_request (socket);
522

523 524
      if (private->is_mapped && private->have_size)
        *minimum = *natural = MAX (private->request_width, 1);
525
      else
526 527 528 529 530 531 532 533 534 535
        *minimum = *natural = 1;
    }
}

static void
gtk_socket_get_preferred_height (GtkWidget *widget,
                                 gint      *minimum,
                                 gint      *natural)
{
  GtkSocket *socket = GTK_SOCKET (widget);
536
  GtkSocketPrivate *private = socket->priv;
537

538
  if (private->plug_widget)
539
    {
540
      gtk_widget_get_preferred_height (private->plug_widget, minimum, natural);
541 542 543
    }
  else
    {
544
      if (private->is_mapped && !private->have_size && private->plug_window)
545
        gtk_socket_size_request (socket);
546

547 548
      if (private->is_mapped && private->have_size)
        *minimum = *natural = MAX (private->request_height, 1);
549 550
      else
        *minimum = *natural = 1;
551 552 553
    }
}

554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593
static void
gtk_socket_send_configure_event (GtkSocket *socket)
{
  GtkAllocation allocation;
  XConfigureEvent xconfigure;
  gint x, y;

  g_return_if_fail (socket->priv->plug_window != NULL);

  memset (&xconfigure, 0, sizeof (xconfigure));
  xconfigure.type = ConfigureNotify;

  xconfigure.event = GDK_WINDOW_XID (socket->priv->plug_window);
  xconfigure.window = GDK_WINDOW_XID (socket->priv->plug_window);

  /* The ICCCM says that synthetic events should have root relative
   * coordinates. We still aren't really ICCCM compliant, since
   * we don't send events when the real toplevel is moved.
   */
  gdk_error_trap_push ();
  gdk_window_get_origin (socket->priv->plug_window, &x, &y);
  gdk_error_trap_pop_ignored ();

  gtk_widget_get_allocation (GTK_WIDGET(socket), &allocation);
  xconfigure.x = x;
  xconfigure.y = y;
  xconfigure.width = allocation.width;
  xconfigure.height = allocation.height;

  xconfigure.border_width = 0;
  xconfigure.above = None;
  xconfigure.override_redirect = False;

  gdk_error_trap_push ();
  XSendEvent (GDK_WINDOW_XDISPLAY (socket->priv->plug_window),
	      GDK_WINDOW_XID (socket->priv->plug_window),
	      False, NoEventMask, (XEvent *)&xconfigure);
  gdk_error_trap_pop_ignored ();
}

594 595 596 597
static void
gtk_socket_size_allocate (GtkWidget     *widget,
			  GtkAllocation *allocation)
{
598
  GtkSocket *socket = GTK_SOCKET (widget);
599
  GtkSocketPrivate *private = socket->priv;
600

601
  gtk_widget_set_allocation (widget, allocation);
602
  if (gtk_widget_get_realized (widget))
603
    {
604
      gdk_window_move_resize (gtk_widget_get_window (widget),
605 606 607
			      allocation->x, allocation->y,
			      allocation->width, allocation->height);

608
      if (private->plug_widget)
609 610 611 612 613 614 615 616
	{
	  GtkAllocation child_allocation;

	  child_allocation.x = 0;
	  child_allocation.y = 0;
	  child_allocation.width = allocation->width;
	  child_allocation.height = allocation->height;

617
	  gtk_widget_size_allocate (private->plug_widget, &child_allocation);
618
	}
619
      else if (private->plug_window)
620
	{
621
	  gdk_error_trap_push ();
622 623 624

	  if (allocation->width != private->current_width ||
	      allocation->height != private->current_height)
625
	    {
626
	      gdk_window_move_resize (private->plug_window,
627 628
				      0, 0,
				      allocation->width, allocation->height);
629 630 631
	      if (private->resize_count)
		private->resize_count--;
	      
632 633 634
	      GTK_NOTE (PLUGSOCKET,
			g_message ("GtkSocket - allocated: %d %d",
				   allocation->width, allocation->height));
635 636
	      private->current_width = allocation->width;
	      private->current_height = allocation->height;
637 638
	    }

639
	  if (private->need_map)
640
	    {
641 642
	      gdk_window_show (private->plug_window);
	      private->need_map = FALSE;
643 644
	    }

645 646
	  while (private->resize_count)
 	    {
647
 	      gtk_socket_send_configure_event (socket);
648
 	      private->resize_count--;
649 650 651
 	      GTK_NOTE (PLUGSOCKET,
			g_message ("GtkSocket - sending synthetic configure: %d %d",
				   allocation->width, allocation->height));
652
 	    }
653

654
	  gdk_error_trap_pop_ignored ();
655 656 657 658
	}
    }
}

659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689
static void
gtk_socket_send_key_event (GtkSocket *socket,
			   GdkEvent  *gdk_event,
			   gboolean   mask_key_presses)
{
  XKeyEvent xkey;
  GdkScreen *screen = gdk_window_get_screen (socket->priv->plug_window);

  memset (&xkey, 0, sizeof (xkey));
  xkey.type = (gdk_event->type == GDK_KEY_PRESS) ? KeyPress : KeyRelease;
  xkey.window = GDK_WINDOW_XID (socket->priv->plug_window);
  xkey.root = GDK_WINDOW_XID (gdk_screen_get_root_window (screen));
  xkey.subwindow = None;
  xkey.time = gdk_event->key.time;
  xkey.x = 0;
  xkey.y = 0;
  xkey.x_root = 0;
  xkey.y_root = 0;
  xkey.state = gdk_event->key.state;
  xkey.keycode = gdk_event->key.hardware_keycode;
  xkey.same_screen = True;/* FIXME ? */

  gdk_error_trap_push ();
  XSendEvent (GDK_WINDOW_XDISPLAY (socket->priv->plug_window),
	      GDK_WINDOW_XID (socket->priv->plug_window),
	      False,
	      (mask_key_presses ? KeyPressMask : NoEventMask),
	      (XEvent *)&xkey);
  gdk_error_trap_pop_ignored ();
}

690 691 692 693 694 695
static gboolean
activate_key (GtkAccelGroup  *accel_group,
	      GObject        *acceleratable,
	      guint           accel_key,
	      GdkModifierType accel_mods,
	      GrabbedKey     *grabbed_key)
696
{
697
  GdkEvent *gdk_event = gtk_get_current_event ();
698
  
699
  GtkSocket *socket = g_object_get_data (G_OBJECT (accel_group), "gtk-socket");
700
  gboolean retval = FALSE;
701

702
  if (gdk_event && gdk_event->type == GDK_KEY_PRESS && socket->priv->plug_window)
703
    {
704
      gtk_socket_send_key_event (socket, gdk_event, FALSE);
705
      retval = TRUE;
706 707 708 709
    }

  if (gdk_event)
    gdk_event_free (gdk_event);
710 711

  return retval;
712 713 714
}

static gboolean
715 716 717
find_accel_key (GtkAccelKey *key,
		GClosure    *closure,
		gpointer     data)
718
{
719 720 721 722
  GrabbedKey *grabbed_key = data;
  
  return (key->accel_key == grabbed_key->accel_key &&
	  key->accel_mods == grabbed_key->accel_mods);
723 724
}

725
/**
726
 * gtk_socket_add_grabbed_key:
727 728 729 730 731 732 733
 * @socket: a #GtkSocket
 * @keyval: a key
 * @modifiers: modifiers for the key
 *
 * Called from the GtkSocket platform-specific backend when the
 * corresponding plug has told the socket to grab a key.
 */
734 735 736 737
static void
gtk_socket_add_grabbed_key (GtkSocket       *socket,
			    guint            keyval,
			    GdkModifierType  modifiers)
738
{
739 740
  GClosure *closure;
  GrabbedKey *grabbed_key;
741

742 743 744 745
  grabbed_key = g_new (GrabbedKey, 1);
  
  grabbed_key->accel_key = keyval;
  grabbed_key->accel_mods = modifiers;
746

747
  if (gtk_accel_group_find (socket->priv->accel_group,
748 749 750 751 752 753 754
			    find_accel_key,
			    &grabbed_key))
    {
      g_warning ("GtkSocket: request to add already present grabbed key %u,%#x\n",
		 keyval, modifiers);
      g_free (grabbed_key);
      return;
755 756
    }

757
  closure = g_cclosure_new (G_CALLBACK (activate_key), grabbed_key, (GClosureNotify)g_free);
758

759
  gtk_accel_group_connect (socket->priv->accel_group, keyval, modifiers, GTK_ACCEL_LOCKED,
760
			   closure);
761 762
}

763
/**
764
 * gtk_socket_remove_grabbed_key:
765 766 767 768 769 770 771
 * @socket: a #GtkSocket
 * @keyval: a key
 * @modifiers: modifiers for the key
 *
 * Called from the GtkSocket backend when the corresponding plug has
 * told the socket to remove a key grab.
 */
772 773 774 775
static void
gtk_socket_remove_grabbed_key (GtkSocket      *socket,
			       guint           keyval,
			       GdkModifierType modifiers)
776
{
777
  if (!gtk_accel_group_disconnect_key (socket->priv->accel_group, keyval, modifiers))
778 779
    g_warning ("GtkSocket: request to remove non-present grabbed key %u,%#x\n",
	       keyval, modifiers);
780 781
}

782 783
static void
socket_update_focus_in (GtkSocket *socket)
784
{
785
  GtkSocketPrivate *private = socket->priv;
786 787
  gboolean focus_in = FALSE;

788
  if (private->plug_window)
789 790
    {
      GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (socket));
791

792
      if (gtk_widget_is_toplevel (toplevel) &&
793
	  gtk_window_has_toplevel_focus (GTK_WINDOW (toplevel)) &&
794 795 796 797
	  gtk_widget_is_focus (GTK_WIDGET (socket)))
	focus_in = TRUE;
    }

798
  if (focus_in != private->focus_in)
799
    {
800
      private->focus_in = focus_in;
801

802 803 804 805 806 807
      if (focus_in)
        _gtk_xembed_send_focus_message (private->plug_window,
                                        XEMBED_FOCUS_IN, XEMBED_FOCUS_CURRENT);
      else
        _gtk_xembed_send_message (private->plug_window,
                                  XEMBED_FOCUS_OUT, 0, 0, 0);
808
    }
809 810
}

811 812
static void
socket_update_active (GtkSocket *socket)
813
{
814
  GtkSocketPrivate *private = socket->priv;
815
  gboolean active = FALSE;
816

817
  if (private->plug_window)
818 819
    {
      GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (socket));
820

821
      if (gtk_widget_is_toplevel (toplevel) &&
822
	  gtk_window_is_active  (GTK_WINDOW (toplevel)))
823 824 825
	active = TRUE;
    }

826
  if (active != private->active)
827
    {
828
      private->active = active;
829

830 831 832
      _gtk_xembed_send_message (private->plug_window,
                                active ? XEMBED_WINDOW_ACTIVATE : XEMBED_WINDOW_DEACTIVATE,
                                0, 0, 0);
833
    }
834 835 836
}

static void
837 838
gtk_socket_hierarchy_changed (GtkWidget *widget,
			      GtkWidget *old_toplevel)
839 840
{
  GtkSocket *socket = GTK_SOCKET (widget);
841
  GtkSocketPrivate *private = socket->priv;
842 843 844 845 846
  GtkWidget *toplevel = gtk_widget_get_toplevel (widget);

  if (toplevel && !GTK_IS_WINDOW (toplevel))
    toplevel = NULL;

847
  if (toplevel != private->toplevel)
848
    {
849
      if (private->toplevel)
850
	{
851 852
	  gtk_window_remove_accel_group (GTK_WINDOW (private->toplevel), private->accel_group);
	  g_signal_handlers_disconnect_by_func (private->toplevel,
Manish Singh's avatar
Manish Singh committed
853 854
						socket_update_focus_in,
						socket);
855
	  g_signal_handlers_disconnect_by_func (private->toplevel,
Manish Singh's avatar
Manish Singh committed
856 857
						socket_update_active,
						socket);
858 859
	}

860
      private->toplevel = toplevel;
861 862 863

      if (toplevel)
	{
864 865
	  gtk_window_add_accel_group (GTK_WINDOW (private->toplevel), private->accel_group);
	  g_signal_connect_swapped (private->toplevel, "notify::has-toplevel-focus",
866
				    G_CALLBACK (socket_update_focus_in), socket);
867
	  g_signal_connect_swapped (private->toplevel, "notify::is-active",
868
				    G_CALLBACK (socket_update_active), socket);
869
	}
870 871 872

      socket_update_focus_in (socket);
      socket_update_active (socket);
873 874 875 876 877 878 879
    }
}

static void
gtk_socket_grab_notify (GtkWidget *widget,
			gboolean   was_grabbed)
{
880 881
  GtkSocket *socket = GTK_SOCKET (widget);

882
  if (!socket->priv->same_app)
883 884 885
    _gtk_xembed_send_message (socket->priv->plug_window,
                              was_grabbed ? XEMBED_MODALITY_OFF : XEMBED_MODALITY_ON,
                              0, 0, 0);
886 887 888
}

static gboolean
889 890
gtk_socket_key_event (GtkWidget   *widget,
                      GdkEventKey *event)
891 892
{
  GtkSocket *socket = GTK_SOCKET (widget);
893
  GtkSocketPrivate *private = socket->priv;
894
  
895
  if (gtk_widget_has_focus (widget) && private->plug_window && !private->plug_widget)
896
    {
897
      gtk_socket_send_key_event (socket, (GdkEvent *) event, FALSE);
898

899 900 901 902 903 904
      return TRUE;
    }
  else
    return FALSE;
}

905 906 907
static void
gtk_socket_notify (GObject    *object,
		   GParamSpec *pspec)
908
{
909 910
  if (strcmp (pspec->name, "is-focus") == 0)
    socket_update_focus_in (GTK_SOCKET (object));
911 912 913

  if (G_OBJECT_CLASS (gtk_socket_parent_class)->notify)
    G_OBJECT_CLASS (gtk_socket_parent_class)->notify (object, pspec);
914 915
}

916
/**
917
 * gtk_socket_claim_focus:
918 919 920 921 922
 * @socket: a #GtkSocket
 * @send_event: huh?
 *
 * Claims focus for the socket. XXX send_event?
 */
923 924 925
static void
gtk_socket_claim_focus (GtkSocket *socket,
			gboolean   send_event)
926
{
927
  GtkWidget *widget = GTK_WIDGET (socket);
928
  GtkSocketPrivate *private = socket->priv;
929

930
  if (!send_event)
931
    private->focus_in = TRUE;	/* Otherwise, our notify handler will send FOCUS_IN  */
932 933 934
      
  /* Oh, the trickery... */
  
935 936 937
  gtk_widget_set_can_focus (widget, TRUE);
  gtk_widget_grab_focus (widget);
  gtk_widget_set_can_focus (widget, FALSE);
938 939
}

940
static gboolean
941 942
gtk_socket_focus (GtkWidget       *widget,
		  GtkDirectionType direction)
943
{
944
  GtkSocket *socket = GTK_SOCKET (widget);
945
  GtkSocketPrivate *private = socket->priv;
946

947 948
  if (private->plug_widget)
    return gtk_widget_child_focus (private->plug_widget, direction);
949

950
  if (!gtk_widget_is_focus (widget))
951
    {
952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969
      gint detail = -1;

      switch (direction)
        {
        case GTK_DIR_UP:
        case GTK_DIR_LEFT:
        case GTK_DIR_TAB_BACKWARD:
          detail = XEMBED_FOCUS_LAST;
          break;
        case GTK_DIR_DOWN:
        case GTK_DIR_RIGHT:
        case GTK_DIR_TAB_FORWARD:
          detail = XEMBED_FOCUS_FIRST;
          break;
        }
      
      _gtk_xembed_send_focus_message (private->plug_window, XEMBED_FOCUS_IN, detail);
      gtk_socket_claim_focus (socket, FALSE);
970 971 972 973 974
 
      return TRUE;
    }
  else
    return FALSE;
975 976
}

977 978 979 980 981
static void
gtk_socket_remove (GtkContainer *container,
		   GtkWidget    *child)
{
  GtkSocket *socket = GTK_SOCKET (container);
982
  GtkSocketPrivate *private = socket->priv;
983

984
  g_return_if_fail (child == private->plug_widget);
985

986
  _gtk_plug_remove_from_socket (GTK_PLUG (private->plug_widget), socket);
987 988 989 990 991 992 993 994 995
}

static void
gtk_socket_forall (GtkContainer *container,
		   gboolean      include_internals,
		   GtkCallback   callback,
		   gpointer      callback_data)
{
  GtkSocket *socket = GTK_SOCKET (container);
996
  GtkSocketPrivate *private = socket->priv;
997

998 999
  if (private->plug_widget)
    (* callback) (private->plug_widget, callback_data);
1000 1001
}

1002
/**
1003
 * gtk_socket_add_window:
1004 1005 1006
 * @socket: a #GtkSocket
 * @xid: the native identifier for a window
 * @need_reparent: whether the socket's plug's window needs to be
1007
 *                 reparented to the socket
1008 1009 1010
 *
 * Adds a window to a GtkSocket.
 */
1011 1012
static void
gtk_socket_add_window (GtkSocket       *socket,
1013
		       Window           xid,
1014
		       gboolean         need_reparent)
1015
{
1016
  GtkWidget *widget = GTK_WIDGET (socket);
1017
  GdkDisplay *display = gtk_widget_get_display (widget);
1018
  gpointer user_data = NULL;
1019
  GtkSocketPrivate *private = socket->priv;
1020 1021
  unsigned long version;
  unsigned long flags;
1022

1023
  if (GDK_IS_X11_DISPLAY (display))
1024 1025 1026
    private->plug_window = gdk_x11_window_lookup_for_display (display, xid);
  else
    private->plug_window = NULL;
1027

1028
  if (private->plug_window)
1029
    {
1030 1031
      g_object_ref (private->plug_window);
      gdk_window_get_user_data (private->plug_window, &user_data);
1032 1033
    }

1034
  if (user_data) /* A widget's window in this process */
1035 1036 1037 1038
    {
      GtkWidget *child_widget = user_data;

      if (!GTK_IS_PLUG (child_widget))
1039 1040 1041 1042 1043 1044 1045
        {
          g_warning (G_STRLOC ": Can't add non-GtkPlug to GtkSocket");
          private->plug_window = NULL;
          gdk_error_trap_pop_ignored ();

          return;
        }
1046 1047 1048

      _gtk_plug_add_to_socket (GTK_PLUG (child_widget), socket);
    }
1049
  else  /* A foreign window */
1050 1051
    {
      GdkDragProtocol protocol;
1052 1053

      gdk_error_trap_push ();
1054

1055
      if (!private->plug_window)
1056
        {
1057
          if (GDK_IS_X11_DISPLAY (display))
1058 1059 1060 1061 1062 1063 1064 1065
            private->plug_window = gdk_x11_window_foreign_new_for_display (display, xid);
          if (!private->plug_window) /* was deleted before we could get it */
            {
              gdk_error_trap_pop_ignored ();
              return;
            }
        }

1066 1067 1068
      XSelectInput (GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (GTK_WIDGET (socket))),
                    GDK_WINDOW_XID (private->plug_window),
                    StructureNotifyMask | PropertyChangeMask);
1069

1070 1071
      if (gdk_error_trap_pop ())
	{
1072 1073
	  g_object_unref (private->plug_window);
	  private->plug_window = NULL;
1074 1075 1076 1077 1078 1079 1080 1081 1082
	  return;
	}
      
      /* OK, we now will reliably get destroy notification on socket->plug_window */

      gdk_error_trap_push ();

      if (need_reparent)
	{
1083 1084
	  gdk_window_hide (private->plug_window); /* Shouldn't actually be necessary for XEMBED, but just in case */
	  gdk_window_reparent (private->plug_window,
1085 1086
                               gtk_widget_get_window (widget),
                               0, 0);
1087 1088
	}

1089
      private->have_size = FALSE;
1090

1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101
      private->xembed_version = -1;
      if (xembed_get_info (private->plug_window, &version, &flags))
        {
          private->xembed_version = MIN (GTK_XEMBED_PROTOCOL_VERSION, version);
          private->is_mapped = (flags & XEMBED_MAPPED) != 0;
        }
      else
        {
          /* FIXME, we should probably actually check the state before we started */
          private->is_mapped = TRUE;
        }
1102

1103
      private->need_map = private->is_mapped;
1104

1105 1106
      protocol = gdk_window_get_drag_protocol (private->plug_window, NULL);
      if (protocol)
1107
	gtk_drag_dest_set_proxy (GTK_WIDGET (socket), private->plug_window,
1108
				 protocol, TRUE);
1109

1110
      gdk_error_trap_pop_ignored ();
1111

1112
      gdk_window_add_filter (private->plug_window,
1113
			     gtk_socket_filter_func,
1114
			     socket);
1115

1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126
#ifdef HAVE_XFIXES
      gdk_error_trap_push ();
      XFixesChangeSaveSet (GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (GTK_WIDGET (socket))),
                           GDK_WINDOW_XID (private->plug_window),
                           SetModeInsert, SaveSetRoot, SaveSetUnmap);
      gdk_error_trap_pop_ignored ();
#endif
      _gtk_xembed_send_message (private->plug_window,
                                XEMBED_EMBEDDED_NOTIFY, 0,
                                GDK_WINDOW_XID (gtk_widget_get_window (GTK_WIDGET (socket))),
                                private->xembed_version);
1127

1128 1129 1130
      socket_update_active (socket);
      socket_update_focus_in (socket);

1131 1132
      gtk_widget_queue_resize (GTK_WIDGET (socket));
    }
1133

1134
  if (private->plug_window)
Manish Singh's avatar
Manish Singh committed
1135
    g_signal_emit (socket, socket_signals[PLUG_ADDED], 0);
1136 1137
}

1138
/**
1139
 * gtk_socket_handle_map_request:
1140 1141 1142 1143
 * @socket: a #GtkSocket
 *
 * Called from the GtkSocket backend when the plug has been mapped.
 */
1144 1145
static void
gtk_socket_handle_map_request (GtkSocket *socket)
1146
{
1147 1148
  GtkSocketPrivate *private = socket->priv;
  if (!private->is_mapped)
1149
    {
1150 1151
      private->is_mapped = TRUE;
      private->need_map = TRUE;
1152 1153

      gtk_widget_queue_resize (GTK_WIDGET (socket));
1154
    }
1155 1156 1157
}

/**
1158
 * gtk_socket_unmap_notify:
1159 1160 1161 1162
 * @socket: a #GtkSocket
 *
 * Called from the GtkSocket backend when the plug has been unmapped ???
 */
1163 1164
static void
gtk_socket_unmap_notify (GtkSocket *socket)
1165
{
1166 1167
  GtkSocketPrivate *private = socket->priv;
  if (private->is_mapped)
1168
    {
1169
      private->is_mapped = FALSE;
1170
      gtk_widget_queue_resize (GTK_WIDGET (socket));
1171 1172 1173
    }
}

1174
/**
1175
 * gtk_socket_advance_toplevel_focus:
1176 1177 1178 1179 1180 1181
 * @socket: a #GtkSocket
 * @direction: a direction
 *
 * Called from the GtkSocket backend when the corresponding plug
 * has told the socket to move the focus.
 */
1182 1183 1184
static void
gtk_socket_advance_toplevel_focus (GtkSocket        *socket,
				   GtkDirectionType  direction)
1185 1186 1187 1188
{
  GtkBin *bin;
  GtkWindow *window;
  GtkContainer *container;
Javier Jardón's avatar
Javier Jardón committed
1189
  GtkWidget *child;
1190
  GtkWidget *focus_widget;
1191 1192 1193 1194 1195 1196 1197 1198
  GtkWidget *toplevel;
  GtkWidget *old_focus_child;
  GtkWidget *parent;

  toplevel = gtk_widget_get_toplevel (GTK_WIDGET (socket));
  if (!toplevel)
    return;

1199
  if (!gtk_widget_is_toplevel (toplevel) || GTK_IS_PLUG (toplevel))
1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211
    {
      gtk_widget_child_focus (toplevel,direction);
      return;
    }

  container = GTK_CONTAINER (toplevel);
  window = GTK_WINDOW (toplevel);
  bin = GTK_BIN (toplevel);

  /* This is a copy of gtk_window_focus(), modified so that we
   * can detect wrap-around.
   */
1212
  old_focus_child = gtk_container_get_focus_child (container);
1213 1214 1215 1216 1217 1218 1219 1220 1221
  
  if (old_focus_child)
    {
      if (gtk_widget_child_focus (old_focus_child, direction))
	return;

      /* We are allowed exactly one wrap-around per sequence of focus
       * events
       */
1222
      if (_gtk_xembed_get_focus_wrapped ())
1223 1224
	return;
      else
1225
	_gtk_xembed_set_focus_wrapped ();
1226 1227
    }

1228 1229
  focus_widget = gtk_window_get_focus (window);
  if (window)
1230 1231
    {
      /* Wrapped off the end, clear the focus setting for the toplevel */
1232
      parent = gtk_widget_get_parent (focus_widget);
1233 1234 1235
      while (parent)
	{
	  gtk_container_set_focus_child (GTK_CONTAINER (parent), NULL);
1236
          parent = gtk_widget_get_parent (parent);
1237 1238 1239 1240 1241 1242
	}
      
      gtk_window_set_focus (GTK_WINDOW (container), NULL);
    }

  /* Now try to focus the first widget in the window */
Javier Jardón's avatar
Javier Jardón committed
1243 1244
  child = gtk_bin_get_child (bin);
  if (child)
1245
    {
Javier Jardón's avatar
Javier Jardón committed
1246
      if (gtk_widget_child_focus (child, direction))
1247 1248 1249
        return;
    }
}
1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340