gtksocket.c 26.2 KB
Newer Older
1 2 3 4
/* GTK - The GIMP Toolkit
 * 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
15 16 17 18 19 20
 * License along with this library; if not, write to the Free
 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

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

21
/*
22
 * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
23 24 25 26 27
 * 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/. 
 */

28
#include <config.h>
29 30
#include <string.h>

31
#include "gdk/gdkkeysyms.h"
32
#include "gtkmain.h"
33
#include "gtkmarshalers.h"
34
#include "gtkwindow.h"
35
#include "gtkplug.h"
36
#include "gtkprivate.h"
37
#include "gtksocket.h"
38
#include "gtksocketprivate.h"
39
#include "gtkdnd.h"
Matthias Clasen's avatar
Matthias Clasen committed
40
#include "gtkintl.h"
41

42
#include "gtkalias.h"
43

44 45
/* Forward declararations */

46
static void     gtk_socket_finalize             (GObject          *object);
47 48
static void     gtk_socket_notify               (GObject          *object,
						 GParamSpec       *pspec);
49 50 51 52 53 54 55 56 57 58
static void     gtk_socket_realize              (GtkWidget        *widget);
static void     gtk_socket_unrealize            (GtkWidget        *widget);
static void     gtk_socket_size_request         (GtkWidget        *widget,
						 GtkRequisition   *requisition);
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);
59
static gboolean gtk_socket_key_event            (GtkWidget        *widget,
60 61 62 63 64 65 66 67 68 69 70
						 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);


71 72
/* Local data */

73 74 75 76 77 78
typedef struct
{
  guint			 accel_key;
  GdkModifierType	 accel_mods;
} GrabbedKey;

79 80 81 82 83 84 85 86
enum {
  PLUG_ADDED,
  PLUG_REMOVED,
  LAST_SIGNAL
}; 

static guint socket_signals[LAST_SIGNAL] = { 0 };

87
/*
88 89 90 91 92 93 94 95 96
 * _gtk_socket_get_private:
 *
 * @socket: a #GtkSocket
 *
 * Returns the private data associated with a GtkSocket, creating it
 * first if necessary.
 */
GtkSocketPrivate *
_gtk_socket_get_private (GtkSocket *socket)
97
{
98
  return G_TYPE_INSTANCE_GET_PRIVATE (socket, GTK_TYPE_SOCKET, GtkSocketPrivate);
99
}
100

Matthias Clasen's avatar
Matthias Clasen committed
101
G_DEFINE_TYPE (GtkSocket, gtk_socket, GTK_TYPE_CONTAINER)
102

103 104 105 106 107 108 109 110
static void
gtk_socket_finalize (GObject *object)
{
  GtkSocket *socket = GTK_SOCKET (object);
  
  g_object_unref (socket->accel_group);
  socket->accel_group = NULL;

Matthias Clasen's avatar
Matthias Clasen committed
111
  G_OBJECT_CLASS (gtk_socket_parent_class)->finalize (object);
112 113
}

114 115 116 117 118
static void
gtk_socket_class_init (GtkSocketClass *class)
{
  GtkWidgetClass *widget_class;
  GtkContainerClass *container_class;
119
  GObjectClass *gobject_class;
120

121
  gobject_class = (GObjectClass *) class;
122 123 124
  widget_class = (GtkWidgetClass*) class;
  container_class = (GtkContainerClass*) class;

125
  gobject_class->finalize = gtk_socket_finalize;
126
  gobject_class->notify = gtk_socket_notify;
127

128 129 130 131
  widget_class->realize = gtk_socket_realize;
  widget_class->unrealize = gtk_socket_unrealize;
  widget_class->size_request = gtk_socket_size_request;
  widget_class->size_allocate = gtk_socket_size_allocate;
132 133
  widget_class->hierarchy_changed = gtk_socket_hierarchy_changed;
  widget_class->grab_notify = gtk_socket_grab_notify;
134 135
  widget_class->key_press_event = gtk_socket_key_event;
  widget_class->key_release_event = gtk_socket_key_event;
136
  widget_class->focus = gtk_socket_focus;
137 138 139 140 141 142

  /* We don't want to show_all/hide_all the in-process
   * plug, if any.
   */
  widget_class->show_all = gtk_widget_show;
  widget_class->hide_all = gtk_widget_hide;
143 144 145
  
  container_class->remove = gtk_socket_remove;
  container_class->forall = gtk_socket_forall;
146

Matthias Clasen's avatar
Matthias Clasen committed
147 148 149 150 151 152 153
  /**
   * GtkSocket::plug-added:
   * @socket_: the object which received the signal
   *
   * This signal is emitted when a client is successfully
   * added to the socket. 
   */
154
  socket_signals[PLUG_ADDED] =
Matthias Clasen's avatar
Matthias Clasen committed
155
    g_signal_new (I_("plug_added"),
156 157 158 159
		  G_OBJECT_CLASS_TYPE (class),
		  G_SIGNAL_RUN_LAST,
		  G_STRUCT_OFFSET (GtkSocketClass, plug_added),
		  NULL, NULL,
160
		  _gtk_marshal_VOID__VOID,
Manish Singh's avatar
Manish Singh committed
161
		  G_TYPE_NONE, 0);
Matthias Clasen's avatar
Matthias Clasen committed
162 163 164 165 166 167 168 169 170 171 172

  /**
   * 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.
   */
173
  socket_signals[PLUG_REMOVED] =
Matthias Clasen's avatar
Matthias Clasen committed
174
    g_signal_new (I_("plug_removed"),
175 176 177 178
		  G_OBJECT_CLASS_TYPE (class),
		  G_SIGNAL_RUN_LAST,
		  G_STRUCT_OFFSET (GtkSocketClass, plug_removed),
                  _gtk_boolean_handled_accumulator, NULL,
179
		  _gtk_marshal_BOOLEAN__VOID,
180
		  G_TYPE_BOOLEAN, 0);
181 182

  g_type_class_add_private (gobject_class, sizeof (GtkSocketPrivate));
183 184 185 186 187 188 189 190 191 192 193
}

static void
gtk_socket_init (GtkSocket *socket)
{
  socket->request_width = 0;
  socket->request_height = 0;
  socket->current_width = 0;
  socket->current_height = 0;
  
  socket->plug_window = NULL;
194
  socket->plug_widget = NULL;
195 196 197
  socket->focus_in = FALSE;
  socket->have_size = FALSE;
  socket->need_map = FALSE;
198
  socket->active = FALSE;
199 200

  socket->accel_group = gtk_accel_group_new ();
Matthias Clasen's avatar
Matthias Clasen committed
201
  g_object_set_data (G_OBJECT (socket->accel_group), I_("gtk-socket"), socket);
202 203
}

204 205 206 207 208 209 210
/**
 * gtk_socket_new:
 * 
 * Create a new empty #GtkSocket.
 * 
 * Return value:  the new #GtkSocket.
 **/
211
GtkWidget*
Tim Janik's avatar
Tim Janik committed
212
gtk_socket_new (void)
213 214 215
{
  GtkSocket *socket;

216
  socket = g_object_new (GTK_TYPE_SOCKET, NULL);
217 218 219 220

  return GTK_WIDGET (socket);
}

221 222
/**
 * gtk_socket_steal:
223
 * @socket_: a #GtkSocket
224
 * @wid: the window ID of an existing toplevel window.
225 226 227 228 229 230 231 232 233
 * 
 * Reparents a pre-existing toplevel window into a #GtkSocket. This is
 * meant to embed clients that do not know about embedding into a
 * #GtkSocket, however doing so is inherently unreliable, and using
 * this function is not recommended.
 *
 * The #GtkSocket must have already be added into a toplevel window
 *  before you can make this call.
 **/
234
void           
235 236
gtk_socket_steal (GtkSocket      *socket,
		  GdkNativeWindow wid)
237
{
238 239 240 241 242 243
  g_return_if_fail (GTK_IS_SOCKET (socket));
  g_return_if_fail (GTK_WIDGET_ANCHORED (socket));

  if (!GTK_WIDGET_REALIZED (socket))
    gtk_widget_realize (GTK_WIDGET (socket));

244
  _gtk_socket_add_window (socket, wid, TRUE);
245 246
}

247 248
/**
 * gtk_socket_add_id:
249
 * @socket_: a #GtkSocket
250
 * @window_id: the window ID of a client participating in the XEMBED protocol.
251 252 253 254 255
 *
 * 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
256 257
 * #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
258 259 260 261 262 263 264 265
 * 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           
266 267
gtk_socket_add_id (GtkSocket      *socket,
		   GdkNativeWindow window_id)
268 269 270 271 272 273 274
{
  g_return_if_fail (GTK_IS_SOCKET (socket));
  g_return_if_fail (GTK_WIDGET_ANCHORED (socket));

  if (!GTK_WIDGET_REALIZED (socket))
    gtk_widget_realize (GTK_WIDGET (socket));

275
  _gtk_socket_add_window (socket, window_id, TRUE);
276 277 278 279
}

/**
 * gtk_socket_get_id:
280
 * @socket_: a #GtkSocket.
281 282 283
 * 
 * Gets the window ID of a #GtkSocket widget, which can then
 * be used to create a client embedded inside the socket, for
284
 * instance with gtk_plug_new(). 
Matthias Clasen's avatar
Matthias Clasen committed
285 286 287
 *
 * The #GtkSocket must have already be added into a toplevel window 
 * before you can make this call.
288 289 290 291 292 293 294 295 296 297 298 299
 * 
 * Return value: the window ID for the socket
 **/
GdkNativeWindow
gtk_socket_get_id (GtkSocket *socket)
{
  g_return_val_if_fail (GTK_IS_SOCKET (socket), 0);
  g_return_val_if_fail (GTK_WIDGET_ANCHORED (socket), 0);

  if (!GTK_WIDGET_REALIZED (socket))
    gtk_widget_realize (GTK_WIDGET (socket));

300
  return _gtk_socket_windowing_get_id (socket);
301 302
}

303 304 305
static void
gtk_socket_realize (GtkWidget *widget)
{
306
  GtkSocket *socket = GTK_SOCKET (widget);
307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330
  GdkWindowAttr attributes;
  gint attributes_mask;

  GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);

  attributes.window_type = GDK_WINDOW_CHILD;
  attributes.x = widget->allocation.x;
  attributes.y = widget->allocation.y;
  attributes.width = widget->allocation.width;
  attributes.height = widget->allocation.height;
  attributes.wclass = GDK_INPUT_OUTPUT;
  attributes.visual = gtk_widget_get_visual (widget);
  attributes.colormap = gtk_widget_get_colormap (widget);
  attributes.event_mask = GDK_FOCUS_CHANGE_MASK;

  attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;

  widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), 
				   &attributes, attributes_mask);
  gdk_window_set_user_data (widget->window, socket);

  widget->style = gtk_style_attach (widget->style, widget->window);
  gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);

331
  _gtk_socket_windowing_realize_window (socket);
332

333 334 335
  gdk_window_add_filter (widget->window,
			 _gtk_socket_windowing_filter_func,
			 widget);
336 337 338 339 340

  /* 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.
   */
341
  gdk_display_sync (gtk_widget_get_display (widget));
342 343
}

344 345 346 347 348 349 350 351 352
/**
 * _gtk_socket_end_embedding:
 *
 * @socket: a #GtkSocket
 *
 * Called to end the embedding of a plug in the socket.
 */
void
_gtk_socket_end_embedding (GtkSocket *socket)
353
{
354
  GtkSocketPrivate *private = _gtk_socket_get_private (socket);
355 356 357
  GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (socket));
  gint i;
  
358
  if (GTK_IS_WINDOW (toplevel))
359
    _gtk_socket_windowing_end_embedding_toplevel (socket);
360 361 362

  g_object_unref (socket->plug_window);
  socket->plug_window = NULL;
363 364
  socket->current_width = 0;
  socket->current_height = 0;
365
  private->resize_count = 0;
366

367 368
  /* Remove from end to avoid indexes shifting. This is evil */
  for (i = socket->accel_group->n_accels - 1; i >= 0; i--)
369 370 371 372 373 374
    {
      GtkAccelGroupEntry *accel_entry = &socket->accel_group->priv_accels[i];
      gtk_accel_group_disconnect (socket->accel_group, accel_entry->closure);
    }
}

375 376 377
static void
gtk_socket_unrealize (GtkWidget *widget)
{
378
  GtkSocket *socket = GTK_SOCKET (widget);
379

380 381
  GTK_WIDGET_UNSET_FLAGS (widget, GTK_REALIZED);

382 383 384 385 386
  if (socket->plug_widget)
    {
      _gtk_plug_remove_from_socket (GTK_PLUG (socket->plug_widget), socket);
    }
  else if (socket->plug_window)
387
    {
388
      _gtk_socket_end_embedding (socket);
389 390
    }

Matthias Clasen's avatar
Matthias Clasen committed
391 392
  if (GTK_WIDGET_CLASS (gtk_socket_parent_class)->unrealize)
    (* GTK_WIDGET_CLASS (gtk_socket_parent_class)->unrealize) (widget);
393 394 395 396 397 398
}
  
static void 
gtk_socket_size_request (GtkWidget      *widget,
			 GtkRequisition *requisition)
{
399
  GtkSocket *socket = GTK_SOCKET (widget);
400

401
  if (socket->plug_widget)
402
    {
403 404 405 406 407
      gtk_widget_size_request (socket->plug_widget, requisition);
    }
  else
    {
      if (socket->is_mapped && !socket->have_size && socket->plug_window)
408
	_gtk_socket_windowing_size_request (socket);
409

410 411 412 413 414 415 416 417 418 419
      if (socket->is_mapped && socket->have_size)
	{
	  requisition->width = MAX (socket->request_width, 1);
	  requisition->height = MAX (socket->request_height, 1);
	}
      else
	{
	  requisition->width = 1;
	  requisition->height = 1;
	}
420 421 422 423 424 425 426
    }
}

static void
gtk_socket_size_allocate (GtkWidget     *widget,
			  GtkAllocation *allocation)
{
427
  GtkSocket *socket = GTK_SOCKET (widget);
428 429 430 431 432 433 434 435

  widget->allocation = *allocation;
  if (GTK_WIDGET_REALIZED (widget))
    {
      gdk_window_move_resize (widget->window,
			      allocation->x, allocation->y,
			      allocation->width, allocation->height);

436 437 438 439 440 441 442 443 444 445 446 447
      if (socket->plug_widget)
	{
	  GtkAllocation child_allocation;

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

	  gtk_widget_size_allocate (socket->plug_widget, &child_allocation);
	}
      else if (socket->plug_window)
448
	{
449
	  GtkSocketPrivate *private = _gtk_socket_get_private (socket);
450
	  
451 452
	  gdk_error_trap_push ();
	  
453 454
	  if (allocation->width != socket->current_width ||
	      allocation->height != socket->current_height)
455 456 457 458
	    {
	      gdk_window_move_resize (socket->plug_window,
				      0, 0,
				      allocation->width, allocation->height);
459 460 461
	      if (private->resize_count)
		private->resize_count--;
	      
462 463 464
	      GTK_NOTE (PLUGSOCKET,
			g_message ("GtkSocket - allocated: %d %d",
				   allocation->width, allocation->height));
465 466 467 468 469 470 471 472 473 474
	      socket->current_width = allocation->width;
	      socket->current_height = allocation->height;
	    }

	  if (socket->need_map)
	    {
	      gdk_window_show (socket->plug_window);
	      socket->need_map = FALSE;
	    }

475 476
	  while (private->resize_count)
 	    {
477
 	      _gtk_socket_windowing_send_configure_event (socket);
478
 	      private->resize_count--;
479 480 481
 	      GTK_NOTE (PLUGSOCKET,
			g_message ("GtkSocket - sending synthetic configure: %d %d",
				   allocation->width, allocation->height));
482 483
 	    }
	  
484
	  gdk_display_sync (gtk_widget_get_display (widget));
485
	  gdk_error_trap_pop ();
486 487 488 489
	}
    }
}

490 491 492 493 494 495
static gboolean
activate_key (GtkAccelGroup  *accel_group,
	      GObject        *acceleratable,
	      guint           accel_key,
	      GdkModifierType accel_mods,
	      GrabbedKey     *grabbed_key)
496
{
497
  GdkEvent *gdk_event = gtk_get_current_event ();
498
  
499
  GtkSocket *socket = g_object_get_data (G_OBJECT (accel_group), "gtk-socket");
500
  gboolean retval = FALSE;
501

502 503
  if (gdk_event && gdk_event->type == GDK_KEY_PRESS && socket->plug_window)
    {
504
      _gtk_socket_windowing_send_key_event (socket, gdk_event, TRUE);
505
      retval = TRUE;
506 507 508 509
    }

  if (gdk_event)
    gdk_event_free (gdk_event);
510 511

  return retval;
512 513 514
}

static gboolean
515 516 517
find_accel_key (GtkAccelKey *key,
		GClosure    *closure,
		gpointer     data)
518
{
519 520 521 522
  GrabbedKey *grabbed_key = data;
  
  return (key->accel_key == grabbed_key->accel_key &&
	  key->accel_mods == grabbed_key->accel_mods);
523 524
}

525 526 527 528 529 530 531 532 533 534 535 536 537 538
/**
 * _gtk_socket_add_grabbed_key:
 *
 * @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.
 */
void
_gtk_socket_add_grabbed_key (GtkSocket       *socket,
			     guint            keyval,
			     GdkModifierType  modifiers)
539
{
540 541
  GClosure *closure;
  GrabbedKey *grabbed_key;
542

543 544 545 546
  grabbed_key = g_new (GrabbedKey, 1);
  
  grabbed_key->accel_key = keyval;
  grabbed_key->accel_mods = modifiers;
547

548 549 550 551 552 553 554 555
  if (gtk_accel_group_find (socket->accel_group,
			    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;
556 557
    }

558
  closure = g_cclosure_new (G_CALLBACK (activate_key), grabbed_key, (GClosureNotify)g_free);
559

560 561
  gtk_accel_group_connect (socket->accel_group, keyval, modifiers, GTK_ACCEL_LOCKED,
			   closure);
562 563
}

564 565 566 567 568 569 570 571 572 573 574 575 576 577
/**
 * _gtk_socket_remove_grabbed_key:
 *
 * @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.
 */
void
_gtk_socket_remove_grabbed_key (GtkSocket      *socket,
				guint           keyval,
				GdkModifierType modifiers)
578
{
579
  gint i;
580

581
  for (i = 0; i < socket->accel_group->n_accels; i++)
582
    {
583 584 585 586 587 588 589 590
      GtkAccelGroupEntry *accel_entry = &socket->accel_group->priv_accels[i];
      if (accel_entry->key.accel_key == keyval &&
	  accel_entry->key.accel_mods == modifiers)
	{
	  gtk_accel_group_disconnect (socket->accel_group,
				      accel_entry->closure);
	  return;
	}
591 592
    }

593 594
  g_warning ("GtkSocket: request to remove non-present grabbed key %u,%#x\n",
	     keyval, modifiers);
595 596
}

597 598
static void
socket_update_focus_in (GtkSocket *socket)
599
{
600 601 602 603 604
  gboolean focus_in = FALSE;

  if (socket->plug_window)
    {
      GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (socket));
605

606 607 608 609 610 611 612 613 614
      if (GTK_WIDGET_TOPLEVEL (toplevel) &&
	  GTK_WINDOW (toplevel)->has_toplevel_focus &&
	  gtk_widget_is_focus (GTK_WIDGET (socket)))
	focus_in = TRUE;
    }

  if (focus_in != socket->focus_in)
    {
      socket->focus_in = focus_in;
615

616
      _gtk_socket_windowing_focus_change (socket, focus_in);
617
    }
618 619
}

620 621
static void
socket_update_active (GtkSocket *socket)
622
{
623
  gboolean active = FALSE;
624

625 626 627
  if (socket->plug_window)
    {
      GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (socket));
628

629 630 631 632 633 634 635 636 637
      if (GTK_WIDGET_TOPLEVEL (toplevel) &&
	  GTK_WINDOW (toplevel)->is_active)
	active = TRUE;
    }

  if (active != socket->active)
    {
      socket->active = active;

638
      _gtk_socket_windowing_update_active (socket, active);
639
    }
640 641 642
}

static void
643 644
gtk_socket_hierarchy_changed (GtkWidget *widget,
			      GtkWidget *old_toplevel)
645 646 647 648 649 650 651 652 653 654 655
{
  GtkSocket *socket = GTK_SOCKET (widget);
  GtkWidget *toplevel = gtk_widget_get_toplevel (widget);

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

  if (toplevel != socket->toplevel)
    {
      if (socket->toplevel)
	{
656
	  gtk_window_remove_accel_group (GTK_WINDOW (socket->toplevel), socket->accel_group);
657
	  g_signal_handlers_disconnect_by_func (socket->toplevel,
Manish Singh's avatar
Manish Singh committed
658 659
						socket_update_focus_in,
						socket);
660
	  g_signal_handlers_disconnect_by_func (socket->toplevel,
Manish Singh's avatar
Manish Singh committed
661 662
						socket_update_active,
						socket);
663 664 665 666 667 668
	}

      socket->toplevel = toplevel;

      if (toplevel)
	{
669
	  gtk_window_add_accel_group (GTK_WINDOW (socket->toplevel), socket->accel_group);
670
	  g_signal_connect_swapped (socket->toplevel, "notify::has-toplevel-focus",
671
				    G_CALLBACK (socket_update_focus_in), socket);
672
	  g_signal_connect_swapped (socket->toplevel, "notify::is-active",
673
				    G_CALLBACK (socket_update_active), socket);
674
	}
675 676 677

      socket_update_focus_in (socket);
      socket_update_active (socket);
678 679 680 681 682 683 684
    }
}

static void
gtk_socket_grab_notify (GtkWidget *widget,
			gboolean   was_grabbed)
{
685 686 687
  GtkSocket *socket = GTK_SOCKET (widget);

  if (!socket->same_app)
688
    _gtk_socket_windowing_update_modality (socket, !was_grabbed);
689 690 691
}

static gboolean
692 693
gtk_socket_key_event (GtkWidget   *widget,
                      GdkEventKey *event)
694 695 696
{
  GtkSocket *socket = GTK_SOCKET (widget);
  
697
  if (GTK_WIDGET_HAS_FOCUS (socket) && socket->plug_window && !socket->plug_widget)
698
    {
699 700
      _gtk_socket_windowing_send_key_event (socket, (GdkEvent *) event, FALSE);

701 702 703 704 705 706
      return TRUE;
    }
  else
    return FALSE;
}

707 708 709
static void
gtk_socket_notify (GObject    *object,
		   GParamSpec *pspec)
710
{
711
  if (!strcmp (pspec->name, "is-focus"))
712 713
    return;
  socket_update_focus_in (GTK_SOCKET (object));
714 715
}

716 717 718 719 720 721 722 723 724 725 726
/**
 * _gtk_socket_claim_focus:
 *
 * @socket: a #GtkSocket
 * @send_event: huh?
 *
 * Claims focus for the socket. XXX send_event?
 */
void
_gtk_socket_claim_focus (GtkSocket *socket,
			 gboolean   send_event)
727
{
728 729
  if (!send_event)
    socket->focus_in = TRUE;	/* Otherwise, our notify handler will send FOCUS_IN  */
730 731 732 733 734 735 736 737
      
  /* Oh, the trickery... */
  
  GTK_WIDGET_SET_FLAGS (socket, GTK_CAN_FOCUS);
  gtk_widget_grab_focus (GTK_WIDGET (socket));
  GTK_WIDGET_UNSET_FLAGS (socket, GTK_CAN_FOCUS);
}

738
static gboolean
739 740
gtk_socket_focus (GtkWidget       *widget,
		  GtkDirectionType direction)
741
{
742
  GtkSocket *socket = GTK_SOCKET (widget);
743

744 745 746
  if (socket->plug_widget)
    return gtk_widget_child_focus (socket->plug_widget, direction);

747
  if (!gtk_widget_is_focus (widget))
748
    {
749 750
      _gtk_socket_windowing_focus (socket, direction);
      _gtk_socket_claim_focus (socket, FALSE);
751 752 753 754 755
 
      return TRUE;
    }
  else
    return FALSE;
756 757
}

758 759 760 761 762 763 764 765
static void
gtk_socket_remove (GtkContainer *container,
		   GtkWidget    *child)
{
  GtkSocket *socket = GTK_SOCKET (container);

  g_return_if_fail (child == socket->plug_widget);

766
  _gtk_plug_remove_from_socket (GTK_PLUG (socket->plug_widget), socket);
767 768 769 770 771 772 773 774 775 776 777 778 779 780
}

static void
gtk_socket_forall (GtkContainer *container,
		   gboolean      include_internals,
		   GtkCallback   callback,
		   gpointer      callback_data)
{
  GtkSocket *socket = GTK_SOCKET (container);

  if (socket->plug_widget)
    (* callback) (socket->plug_widget, callback_data);
}

781 782 783 784 785 786 787 788 789 790 791 792 793 794
/**
 * _gtk_socket_add_window:
 *
 * @socket: a #GtkSocket
 * @xid: the native identifier for a window
 * @need_reparent: whether the socket's plug's window needs to be
 *		   reparented to the socket
 *
 * Adds a window to a GtkSocket.
 */
void
_gtk_socket_add_window (GtkSocket       *socket,
			GdkNativeWindow  xid,
			gboolean         need_reparent)
795
{
796
  GtkWidget *widget = GTK_WIDGET (socket);
797
  GdkDisplay *display = gtk_widget_get_display (widget);
798 799
  gpointer user_data = NULL;
  
800
  socket->plug_window = gdk_window_lookup_for_display (display, xid);
801

802 803 804 805 806 807 808 809 810 811 812 813
  if (socket->plug_window)
    {
      g_object_ref (socket->plug_window);
      gdk_window_get_user_data (socket->plug_window, &user_data);
    }

  if (user_data)		/* A widget's window in this process */
    {
      GtkWidget *child_widget = user_data;

      if (!GTK_IS_PLUG (child_widget))
	{
814
	  g_warning (G_STRLOC ": Can't add non-GtkPlug to GtkSocket");
815 816 817 818 819 820 821 822 823
	  socket->plug_window = NULL;
	  gdk_error_trap_pop ();
	  
	  return;
	}

      _gtk_plug_add_to_socket (GTK_PLUG (child_widget), socket);
    }
  else				/* A foreign window */
824 825 826
    {
      GtkWidget *toplevel;
      GdkDragProtocol protocol;
827 828

      gdk_error_trap_push ();
829 830 831

      if (!socket->plug_window)
	{  
832
	  socket->plug_window = gdk_window_foreign_new_for_display (display, xid);
833 834 835 836 837 838 839
	  if (!socket->plug_window) /* was deleted before we could get it */
	    {
	      gdk_error_trap_pop ();
	      return;
	    }
	}
	
840 841
      _gtk_socket_windowing_select_plug_window_input (socket);

842 843
      if (gdk_error_trap_pop ())
	{
Manish Singh's avatar
Manish Singh committed
844
	  g_object_unref (socket->plug_window);
845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860
	  socket->plug_window = NULL;
	  return;
	}
      
      /* OK, we now will reliably get destroy notification on socket->plug_window */

      gdk_error_trap_push ();

      if (need_reparent)
	{
	  gdk_window_hide (socket->plug_window); /* Shouldn't actually be necessary for XEMBED, but just in case */
	  gdk_window_reparent (socket->plug_window, widget->window, 0, 0);
	}

      socket->have_size = FALSE;

861 862
      _gtk_socket_windowing_embed_get_info (socket);

863 864
      socket->need_map = socket->is_mapped;

865
      if (gdk_drag_get_protocol_for_display (display, xid, &protocol))
866 867
	gtk_drag_dest_set_proxy (GTK_WIDGET (socket), socket->plug_window, 
				 protocol, TRUE);
868 869

      gdk_display_sync (display);
870
      gdk_error_trap_pop ();
871

872 873 874
      gdk_window_add_filter (socket->plug_window,
			     _gtk_socket_windowing_filter_func,
			     socket);
875 876 877 878

      /* Add a pointer to the socket on our toplevel window */

      toplevel = gtk_widget_get_toplevel (GTK_WIDGET (socket));
879
      if (GTK_IS_WINDOW (toplevel))
880
	gtk_window_add_embedded_xid (GTK_WINDOW (toplevel), xid);
881

882 883
      _gtk_socket_windowing_embed_notify (socket);

884 885 886
      socket_update_active (socket);
      socket_update_focus_in (socket);

887 888
      gtk_widget_queue_resize (GTK_WIDGET (socket));
    }
889 890

  if (socket->plug_window)
Manish Singh's avatar
Manish Singh committed
891
    g_signal_emit (socket, socket_signals[PLUG_ADDED], 0);
892 893
}

894 895 896 897 898 899 900 901 902
/**
 * _gtk_socket_handle_map_request:
 *
 * @socket: a #GtkSocket
 *
 * Called from the GtkSocket backend when the plug has been mapped.
 */
void
_gtk_socket_handle_map_request (GtkSocket *socket)
903
{
904
  if (!socket->is_mapped)
905
    {
906 907 908 909
      socket->is_mapped = TRUE;
      socket->need_map = TRUE;

      gtk_widget_queue_resize (GTK_WIDGET (socket));
910
    }
911 912 913 914 915 916 917 918 919 920 921 922 923
}

/**
 * _gtk_socket_unmap_notify:
 *
 * @socket: a #GtkSocket
 *
 * Called from the GtkSocket backend when the plug has been unmapped ???
 */
void
_gtk_socket_unmap_notify (GtkSocket *socket)
{
  if (socket->is_mapped)
924
    {
925 926
      socket->is_mapped = FALSE;
      gtk_widget_queue_resize (GTK_WIDGET (socket));
927 928 929
    }
}

930 931 932 933 934 935 936 937 938 939 940 941
/**
 * _gtk_socket_advance_toplevel_focus:
 *
 * @socket: a #GtkSocket
 * @direction: a direction
 *
 * Called from the GtkSocket backend when the corresponding plug
 * has told the socket to move the focus.
 */
void
_gtk_socket_advance_toplevel_focus (GtkSocket        *socket,
				    GtkDirectionType  direction)
942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976
{
  GtkBin *bin;
  GtkWindow *window;
  GtkContainer *container;
  GtkWidget *toplevel;
  GtkWidget *old_focus_child;
  GtkWidget *parent;

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

  if (!GTK_WIDGET_TOPLEVEL (toplevel) || GTK_IS_PLUG (toplevel))
    {
      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.
   */
  old_focus_child = container->focus_child;
  
  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
       */
977
      if (_gtk_socket_windowing_embed_get_focus_wrapped ())
978 979
	return;
      else
980
	_gtk_socket_windowing_embed_set_focus_wrapped ();
981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003
    }

  if (window->focus_widget)
    {
      /* Wrapped off the end, clear the focus setting for the toplevel */
      parent = window->focus_widget->parent;
      while (parent)
	{
	  gtk_container_set_focus_child (GTK_CONTAINER (parent), NULL);
	  parent = GTK_WIDGET (parent)->parent;
	}
      
      gtk_window_set_focus (GTK_WINDOW (container), NULL);
    }

  /* Now try to focus the first widget in the window */
  if (bin->child)
    {
      if (gtk_widget_child_focus (bin->child, direction))
        return;
    }
}

1004 1005
#define __GTK_SOCKET_C__
#include "gtkaliasdef.c"