summaryrefslogtreecommitdiff
path: root/gtk
diff options
context:
space:
mode:
Diffstat (limited to 'gtk')
-rw-r--r--gtk/gtkentry.c12
-rw-r--r--gtk/gtkmain.c9
-rw-r--r--gtk/gtkplug.c276
-rw-r--r--gtk/gtkplug.h6
-rw-r--r--gtk/gtksocket.c520
-rw-r--r--gtk/gtksocket.h4
-rw-r--r--gtk/gtkwidget.c17
-rw-r--r--gtk/xembed.h3
8 files changed, 648 insertions, 199 deletions
diff --git a/gtk/gtkentry.c b/gtk/gtkentry.c
index 9eb7fc1280..58c910c961 100644
--- a/gtk/gtkentry.c
+++ b/gtk/gtkentry.c
@@ -2022,17 +2022,21 @@ static void
gtk_entry_real_activate (GtkEntry *entry)
{
GtkWindow *window;
+ GtkWidget *toplevel;
GtkWidget *widget;
widget = GTK_WIDGET (entry);
if (entry->activates_default)
{
- window = (GtkWindow *) gtk_widget_get_ancestor (widget, GTK_TYPE_WINDOW);
+ toplevel = gtk_widget_get_toplevel (widget);
+ if (toplevel && GTK_IS_WINDOW (toplevel))
+ {
+ window = GTK_WINDOW (toplevel);
- if (window &&
- window->default_widget != widget)
- gtk_window_activate_default (window);
+ if (window && window->default_widget != widget)
+ gtk_window_activate_default (window);
+ }
}
}
diff --git a/gtk/gtkmain.c b/gtk/gtkmain.c
index 6c7bcd3a1f..a8a6928041 100644
--- a/gtk/gtkmain.c
+++ b/gtk/gtkmain.c
@@ -1627,9 +1627,8 @@ gtk_propagate_event (GtkWidget *widget,
*/
GtkWidget *window;
- window = gtk_widget_get_ancestor (widget, GTK_TYPE_WINDOW);
-
- if (window)
+ window = gtk_widget_get_toplevel (widget);
+ if (window && GTK_IS_WINDOW (window))
{
/* If there is a grab within the window, give the grab widget
* a first crack at the key event
@@ -1639,8 +1638,8 @@ gtk_propagate_event (GtkWidget *widget,
if (!handled_event)
{
- window = gtk_widget_get_ancestor (widget, GTK_TYPE_WINDOW);
- if (window)
+ window = gtk_widget_get_toplevel (widget);
+ if (window && GTK_IS_WINDOW (window))
{
if (GTK_WIDGET_IS_SENSITIVE (window))
gtk_widget_event (window, event);
diff --git a/gtk/gtkplug.c b/gtk/gtkplug.c
index fa2b37c9f2..03d7e22f06 100644
--- a/gtk/gtkplug.c
+++ b/gtk/gtkplug.c
@@ -27,6 +27,7 @@
#include "gtkmain.h"
#include "gtkplug.h"
+#include "gtkprivate.h"
#include "gdk/gdkkeysyms.h"
#include "x11/gdkx.h"
@@ -37,6 +38,12 @@ static void gtk_plug_class_init (GtkPlugClass *klass);
static void gtk_plug_init (GtkPlug *plug);
static void gtk_plug_realize (GtkWidget *widget);
static void gtk_plug_unrealize (GtkWidget *widget);
+static void gtk_plug_show (GtkWidget *widget);
+static void gtk_plug_hide (GtkWidget *widget);
+static void gtk_plug_map (GtkWidget *widget);
+static void gtk_plug_unmap (GtkWidget *widget);
+static void gtk_plug_size_allocate (GtkWidget *widget,
+ GtkAllocation *allocation);
static gboolean gtk_plug_key_press_event (GtkWidget *widget,
GdkEventKey *event);
static void gtk_plug_forward_key_press (GtkPlug *plug,
@@ -45,24 +52,28 @@ static void gtk_plug_set_focus (GtkWindow *window,
GtkWidget *focus);
static gboolean gtk_plug_focus (GtkWidget *widget,
GtkDirectionType direction);
+static void gtk_plug_check_resize (GtkContainer *container);
static void gtk_plug_accel_entries_changed (GtkWindow *window);
static GdkFilterReturn gtk_plug_filter_func (GdkXEvent *gdk_xevent,
GdkEvent *event,
gpointer data);
-static void gtk_plug_free_grabbed_keys (GHashTable *key_table);
-static void handle_modality_off (GtkPlug *plug);
-static void send_xembed_message (GtkPlug *plug,
- glong message,
- glong detail,
- glong data1,
- glong data2,
- guint32 time);
+static void gtk_plug_free_grabbed_keys (GHashTable *key_table);
+static void handle_modality_off (GtkPlug *plug);
+static void send_xembed_message (GtkPlug *plug,
+ glong message,
+ glong detail,
+ glong data1,
+ glong data2,
+ guint32 time);
+static void xembed_set_info (GdkWindow *window,
+ unsigned long flags);
/* From Tk */
#define EMBEDDED_APP_WANTS_FOCUS NotifyNormal+20
static GtkWindowClass *parent_class = NULL;
+static GtkBinClass *bin_class = NULL;
GtkType
gtk_plug_get_type ()
@@ -95,14 +106,24 @@ gtk_plug_class_init (GtkPlugClass *class)
{
GtkWidgetClass *widget_class = (GtkWidgetClass *)class;
GtkWindowClass *window_class = (GtkWindowClass *)class;
+ GtkContainerClass *container_class = (GtkContainerClass *)class;
parent_class = gtk_type_class (GTK_TYPE_WINDOW);
+ bin_class = gtk_type_class (GTK_TYPE_BIN);
widget_class->realize = gtk_plug_realize;
widget_class->unrealize = gtk_plug_unrealize;
widget_class->key_press_event = gtk_plug_key_press_event;
- widget_class->focus = gtk_plug_focus;
+ widget_class->show = gtk_plug_show;
+ widget_class->hide = gtk_plug_hide;
+ widget_class->map = gtk_plug_map;
+ widget_class->unmap = gtk_plug_unmap;
+ widget_class->size_allocate = gtk_plug_size_allocate;
+
+ widget_class->focus = gtk_plug_focus;
+
+ container_class->check_resize = gtk_plug_check_resize;
window_class->set_focus = gtk_plug_set_focus;
#if 0
@@ -121,18 +142,79 @@ gtk_plug_init (GtkPlug *plug)
window->auto_shrink = TRUE;
}
+static void
+gtk_plug_set_is_child (GtkPlug *plug,
+ gboolean is_child)
+{
+ if (is_child)
+ {
+ GTK_WIDGET_UNSET_FLAGS (plug, GTK_TOPLEVEL);
+ GTK_PRIVATE_UNSET_FLAG (plug, GTK_ANCHORED);
+ gtk_container_set_resize_mode (GTK_CONTAINER (plug), GTK_RESIZE_PARENT);
+ }
+}
+
+/**
+ * _gtk_plug_add_to_socket:
+ * @plug: a #GtkPlug
+ * @socket: a #GtkSocket
+ *
+ * Add a plug to a socket within the same application.
+ **/
void
-gtk_plug_construct (GtkPlug *plug, GdkNativeWindow socket_id)
+_gtk_plug_add_to_socket (GtkPlug *plug,
+ GtkSocket *socket)
+{
+ GtkWidget *widget = GTK_WIDGET (plug);
+
+ g_return_if_fail (GTK_IS_PLUG (plug));
+ g_return_if_fail (GTK_IS_SOCKET (socket));
+ g_return_if_fail (GTK_WIDGET_REALIZED (socket));
+
+ gtk_plug_set_is_child (plug, TRUE);
+ plug->same_app = TRUE;
+ socket->plug_widget = widget;
+
+ gtk_widget_set_parent (widget, GTK_WIDGET (socket));
+
+ if (GTK_WIDGET_REALIZED (widget))
+ gdk_window_reparent (widget->window, plug->socket_window, 0, 0);
+ else
+ gtk_widget_realize (widget);
+
+ if (GTK_WIDGET_VISIBLE (socket) && GTK_WIDGET_VISIBLE (widget))
+ {
+ if (GTK_WIDGET_MAPPED (socket))
+ gtk_widget_map (widget);
+
+ gtk_widget_queue_resize (widget);
+ }
+}
+
+void
+gtk_plug_construct (GtkPlug *plug,
+ GdkNativeWindow socket_id)
{
if (socket_id)
{
+ gpointer user_data = NULL;
+
plug->socket_window = gdk_window_lookup (socket_id);
- plug->same_app = TRUE;
- if (plug->socket_window == NULL)
+ if (plug->socket_window)
+ gdk_window_get_user_data (plug->socket_window, &user_data);
+ else
+ plug->socket_window = gdk_window_foreign_new (socket_id);
+
+ if (user_data)
{
- plug->socket_window = gdk_window_foreign_new (socket_id);
- plug->same_app = FALSE;
+ if (GTK_IS_SOCKET (user_data))
+ _gtk_plug_add_to_socket (plug, user_data);
+ else
+ {
+ g_warning (G_STRLOC "Can't create GtkPlug as child of non-GtkSocket");
+ plug->socket_window = NULL;
+ }
}
}
}
@@ -164,11 +246,14 @@ gtk_plug_unrealize (GtkWidget *widget)
plug->socket_window = NULL;
}
- if (plug->modality_window)
- handle_modality_off (plug);
+ if (!plug->same_app)
+ {
+ if (plug->modality_window)
+ handle_modality_off (plug);
- gtk_window_group_remove_window (plug->modality_group, GTK_WINDOW (plug));
- g_object_unref (plug->modality_group);
+ gtk_window_group_remove_window (plug->modality_group, GTK_WINDOW (plug));
+ g_object_unref (plug->modality_group);
+ }
if (GTK_WIDGET_CLASS (parent_class)->unrealize)
(* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
@@ -213,29 +298,132 @@ gtk_plug_realize (GtkWidget *widget)
attributes_mask |= (window->title ? GDK_WA_TITLE : 0);
attributes_mask |= (window->wmclass_name ? GDK_WA_WMCLASS : 0);
- gdk_error_trap_push ();
- widget->window = gdk_window_new (plug->socket_window,
- &attributes, attributes_mask);
- gdk_flush ();
- if (gdk_error_trap_pop ()) /* Uh-oh */
+ if (GTK_WIDGET_TOPLEVEL (widget))
{
gdk_error_trap_push ();
- gdk_window_destroy (widget->window);
+ widget->window = gdk_window_new (plug->socket_window,
+ &attributes, attributes_mask);
gdk_flush ();
- gdk_error_trap_pop ();
- widget->window = gdk_window_new (NULL, &attributes, attributes_mask);
+ if (gdk_error_trap_pop ()) /* Uh-oh */
+ {
+ gdk_error_trap_push ();
+ gdk_window_destroy (widget->window);
+ gdk_flush ();
+ gdk_error_trap_pop ();
+ widget->window = gdk_window_new (NULL, &attributes, attributes_mask);
+ }
+
+ GDK_WINDOW_TYPE (widget->window) = GDK_WINDOW_TOPLEVEL;
+ gdk_window_add_filter (widget->window, gtk_plug_filter_func, widget);
+
+ plug->modality_group = gtk_window_group_new ();
+ gtk_window_group_add_window (plug->modality_group, window);
+
+ xembed_set_info (widget->window, 0);
}
+ else
+ widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
- GDK_WINDOW_TYPE (widget->window) = GDK_WINDOW_TOPLEVEL;
gdk_window_set_user_data (widget->window, window);
widget->style = gtk_style_attach (widget->style, widget->window);
gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
+}
+
+static void
+gtk_plug_show (GtkWidget *widget)
+{
+ if (GTK_WIDGET_TOPLEVEL (widget))
+ GTK_WIDGET_CLASS (parent_class)->show (widget);
+ else
+ GTK_WIDGET_CLASS (bin_class)->show (widget);
+}
+
+static void
+gtk_plug_hide (GtkWidget *widget)
+{
+ if (GTK_WIDGET_TOPLEVEL (widget))
+ GTK_WIDGET_CLASS (parent_class)->hide (widget);
+ else
+ GTK_WIDGET_CLASS (bin_class)->hide (widget);
+}
+
+/* From gdkinternals.h */
+void gdk_synthesize_window_state (GdkWindow *window,
+ GdkWindowState unset_flags,
+ GdkWindowState set_flags);
+
+static void
+gtk_plug_map (GtkWidget *widget)
+{
+ if (GTK_WIDGET_TOPLEVEL (widget))
+ {
+ GtkBin *bin = GTK_BIN (widget);
+
+ GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
+
+ if (bin->child &&
+ GTK_WIDGET_VISIBLE (bin->child) &&
+ !GTK_WIDGET_MAPPED (bin->child))
+ gtk_widget_map (bin->child);
+
+ xembed_set_info (widget->window, XEMBED_MAPPED);
+
+ gdk_synthesize_window_state (widget->window,
+ GDK_WINDOW_STATE_WITHDRAWN,
+ 0);
+ }
+ else
+ GTK_WIDGET_CLASS (bin_class)->map (widget);
+}
+
+static void
+gtk_plug_unmap (GtkWidget *widget)
+{
+ if (GTK_WIDGET_TOPLEVEL (widget))
+ {
+ GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
+
+ gdk_window_hide (widget->window);
+ xembed_set_info (widget->window, 0);
+
+ gdk_synthesize_window_state (widget->window,
+ 0,
+ GDK_WINDOW_STATE_WITHDRAWN);
+ }
+ else
+ GTK_WIDGET_CLASS (bin_class)->unmap (widget);
+}
- gdk_window_add_filter (widget->window, gtk_plug_filter_func, widget);
+static void
+gtk_plug_size_allocate (GtkWidget *widget,
+ GtkAllocation *allocation)
+{
+ if (GTK_WIDGET_TOPLEVEL (widget))
+ GTK_WIDGET_CLASS (parent_class)->size_allocate (widget, allocation);
+ else
+ {
+ GtkBin *bin = GTK_BIN (widget);
+
+ if (GTK_WIDGET_REALIZED (widget))
+ gdk_window_move_resize (widget->window,
+ allocation->x, allocation->y,
+ allocation->width, allocation->height);
- plug->modality_group = gtk_window_group_new ();
- gtk_window_group_add_window (plug->modality_group, window);
+ if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
+ {
+ GtkAllocation child_allocation;
+
+ child_allocation.x = child_allocation.y = GTK_CONTAINER (widget)->border_width;
+ child_allocation.width =
+ MAX (1, (gint)allocation->width - child_allocation.x * 2);
+ child_allocation.height =
+ MAX (1, (gint)allocation->height - child_allocation.y * 2);
+
+ gtk_widget_size_allocate (bin->child, &child_allocation);
+ }
+
+ }
}
static gboolean
@@ -519,6 +707,15 @@ gtk_plug_focus (GtkWidget *widget,
}
static void
+gtk_plug_check_resize (GtkContainer *container)
+{
+ if (GTK_WIDGET_TOPLEVEL (container))
+ GTK_CONTAINER_CLASS (parent_class)->check_resize (container);
+ else
+ GTK_CONTAINER_CLASS (bin_class)->check_resize (container);
+}
+
+static void
send_xembed_message (GtkPlug *plug,
glong message,
glong detail,
@@ -593,6 +790,25 @@ handle_modality_off (GtkPlug *plug)
}
static void
+xembed_set_info (GdkWindow *gdk_window,
+ unsigned long flags)
+{
+ Display *display = GDK_WINDOW_XDISPLAY (gdk_window);
+ Window window = GDK_WINDOW_XWINDOW (gdk_window);
+ unsigned long buffer[2];
+
+ Atom xembed_info_atom = gdk_atom_intern ("_XEMBED_INFO", FALSE);
+
+ buffer[1] = 0; /* Protocol version */
+ buffer[1] = flags;
+
+ XChangeProperty (display, window,
+ xembed_info_atom, xembed_info_atom, 32,
+ PropModeReplace,
+ (unsigned char *)buffer, 2);
+}
+
+static void
handle_xembed_message (GtkPlug *plug,
glong message,
glong detail,
diff --git a/gtk/gtkplug.h b/gtk/gtkplug.h
index 37907574da..d3274c50b4 100644
--- a/gtk/gtkplug.h
+++ b/gtk/gtkplug.h
@@ -28,6 +28,7 @@
#include <gdk/gdk.h>
+#include <gtk/gtksocket.h>
#include <gtk/gtkwindow.h>
@@ -55,7 +56,7 @@ struct _GtkPlug
GdkWindow *socket_window;
GtkWidget *modality_window;
GtkWindowGroup *modality_group;
- gboolean same_app;
+ guint same_app : 1;
};
struct _GtkPlugClass
@@ -69,6 +70,9 @@ void gtk_plug_construct (GtkPlug *plug, GdkNativeWindow socket_id);
GtkWidget* gtk_plug_new (GdkNativeWindow socket_id);
+void _gtk_plug_add_to_socket (GtkPlug *plug,
+ GtkSocket *socket);
+
#ifdef __cplusplus
}
#endif /* __cplusplus */
diff --git a/gtk/gtksocket.c b/gtk/gtksocket.c
index f28310bccc..a8e76850b1 100644
--- a/gtk/gtksocket.c
+++ b/gtk/gtksocket.c
@@ -28,6 +28,7 @@
#include "gdk/gdkkeysyms.h"
#include "gtkmain.h"
#include "gtkwindow.h"
+#include "gtkplug.h"
#include "gtksignal.h"
#include "gtksocket.h"
#include "gtkdnd.h"
@@ -38,38 +39,52 @@
/* Forward declararations */
-static void gtk_socket_class_init (GtkSocketClass *klass);
-static void gtk_socket_init (GtkSocket *socket);
-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);
-static gboolean gtk_socket_key_press_event (GtkWidget *widget,
- GdkEventKey *event);
-static gboolean gtk_socket_focus_in_event (GtkWidget *widget,
- GdkEventFocus *event);
-static void gtk_socket_claim_focus (GtkSocket *socket);
-static gboolean gtk_socket_focus_out_event (GtkWidget *widget,
- GdkEventFocus *event);
-static void gtk_socket_send_configure_event (GtkSocket *socket);
-static gboolean gtk_socket_focus (GtkWidget *widget,
- GtkDirectionType direction);
-static GdkFilterReturn gtk_socket_filter_func (GdkXEvent *gdk_xevent,
- GdkEvent *event,
- gpointer data);
-
-static void send_xembed_message (GtkSocket *socket,
- glong message,
- glong detail,
- glong data1,
- glong data2,
- guint32 time);
+static void gtk_socket_class_init (GtkSocketClass *klass);
+static void gtk_socket_init (GtkSocket *socket);
+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);
+static gboolean gtk_socket_key_press_event (GtkWidget *widget,
+ GdkEventKey *event);
+static gboolean gtk_socket_focus_in_event (GtkWidget *widget,
+ GdkEventFocus *event);
+static void gtk_socket_claim_focus (GtkSocket *socket);
+static gboolean gtk_socket_focus_out_event (GtkWidget *widget,
+ GdkEventFocus *event);
+static void gtk_socket_send_configure_event (GtkSocket *socket);
+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);
+
+
+static void gtk_socket_add_window (GtkSocket *socket,
+ GdkNativeWindow xid,
+ gboolean need_reparent);
+static GdkFilterReturn gtk_socket_filter_func (GdkXEvent *gdk_xevent,
+ GdkEvent *event,
+ gpointer data);
+
+static void send_xembed_message (GtkSocket *socket,
+ glong message,
+ glong detail,
+ glong data1,
+ glong data2,
+ guint32 time);
+static gboolean xembed_get_info (GdkWindow *gdk_window,
+ unsigned long *version,
+ unsigned long *flags);
/* From Tk */
#define EMBEDDED_APP_WANTS_FOCUS NotifyNormal+20
@@ -124,8 +139,10 @@ gtk_socket_class_init (GtkSocketClass *class)
widget_class->key_press_event = gtk_socket_key_press_event;
widget_class->focus_in_event = gtk_socket_focus_in_event;
widget_class->focus_out_event = gtk_socket_focus_out_event;
-
widget_class->focus = gtk_socket_focus;
+
+ container_class->remove = gtk_socket_remove;
+ container_class->forall = gtk_socket_forall;
}
static void
@@ -137,7 +154,7 @@ gtk_socket_init (GtkSocket *socket)
socket->current_height = 0;
socket->plug_window = NULL;
- socket->same_app = FALSE;
+ socket->plug_widget = NULL;
socket->focus_in = FALSE;
socket->have_size = FALSE;
socket->need_map = FALSE;
@@ -156,57 +173,7 @@ gtk_socket_new (void)
void
gtk_socket_steal (GtkSocket *socket, GdkNativeWindow id)
{
- GtkWidget *widget;
- gpointer user_data = NULL;
-
- widget = GTK_WIDGET (socket);
-
- socket->plug_window = gdk_window_lookup (id);
-
- gdk_error_trap_push ();
-
- if (socket->plug_window)
- gdk_window_get_user_data (socket->plug_window,
- &user_data);
-
- if (user_data)
- {
- /*
- GtkWidget *child_widget;
-
- child_widget = GTK_WIDGET (socket->plug_window->user_data);
- */
-
- g_warning("Stealing from same app not yet implemented");
-
- socket->same_app = TRUE;
- }
- else
- {
- socket->plug_window = gdk_window_foreign_new (id);
- if (!socket->plug_window) /* was deleted before we could get it */
- {
- gdk_error_trap_pop ();
- return;
- }
-
- socket->same_app = FALSE;
- socket->have_size = FALSE;
-
- XSelectInput (GDK_DISPLAY (),
- GDK_WINDOW_XWINDOW(socket->plug_window),
- StructureNotifyMask | PropertyChangeMask);
-
- gtk_widget_queue_resize (widget);
- }
-
- gdk_window_hide (socket->plug_window);
- gdk_window_reparent (socket->plug_window, widget->window, 0, 0);
-
- gdk_flush ();
- gdk_error_trap_pop ();
-
- socket->need_map = TRUE;
+ gtk_socket_add_window (socket, id, TRUE);
}
static void
@@ -307,42 +274,57 @@ gtk_socket_size_request (GtkWidget *widget,
socket = GTK_SOCKET (widget);
- if (!socket->have_size && socket->plug_window)
+ if (socket->plug_widget)
{
- XSizeHints hints;
- long supplied;
-
- gdk_error_trap_push ();
-
- if (XGetWMNormalHints (GDK_DISPLAY(),
- GDK_WINDOW_XWINDOW (socket->plug_window),
- &hints, &supplied))
+ gtk_widget_size_request (socket->plug_widget, requisition);
+ }
+ else
+ {
+ if (socket->is_mapped && !socket->have_size && socket->plug_window)
{
- /* This is obsolete, according the X docs, but many programs
- * still use it */
- if (hints.flags & (PSize | USSize))
- {
- socket->request_width = hints.width;
- socket->request_height = hints.height;
- }
- else if (hints.flags & PMinSize)
- {
- socket->request_width = hints.min_width;
- socket->request_height = hints.min_height;
- }
- else if (hints.flags & PBaseSize)
+ XSizeHints hints;
+ long supplied;
+
+ gdk_error_trap_push ();
+
+ if (XGetWMNormalHints (GDK_DISPLAY(),
+ GDK_WINDOW_XWINDOW (socket->plug_window),
+ &hints, &supplied))
{
- socket->request_width = hints.base_width;
- socket->request_height = hints.base_height;
+ /* This is obsolete, according the X docs, but many programs
+ * still use it */
+ if (hints.flags & (PSize | USSize))
+ {
+ socket->request_width = hints.width;
+ socket->request_height = hints.height;
+ }
+ else if (hints.flags & PMinSize)
+ {
+ socket->request_width = hints.min_width;
+ socket->request_height = hints.min_height;
+ }
+ else if (hints.flags & PBaseSize)
+ {
+ socket->request_width = hints.base_width;
+ socket->request_height = hints.base_height;
+ }
}
+ socket->have_size = TRUE; /* don't check again? */
+
+ gdk_error_trap_pop ();
}
- socket->have_size = TRUE; /* don't check again? */
- gdk_error_trap_pop ();
+ 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;
+ }
}
-
- requisition->width = MAX (socket->request_width, 1);
- requisition->height = MAX (socket->request_height, 1);
}
static void
@@ -364,7 +346,18 @@ gtk_socket_size_allocate (GtkWidget *widget,
allocation->x, allocation->y,
allocation->width, allocation->height);
- if (socket->plug_window)
+ 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)
{
gdk_error_trap_push ();
@@ -652,9 +645,9 @@ gtk_socket_focus_out_event (GtkWidget *widget, GdkEventFocus *event)
#if 0
GtkWidget *toplevel;
- toplevel = gtk_widget_get_ancestor (widget, GTK_TYPE_WINDOW);
+ toplevel = gtk_widget_get_toplevel (widget);
- if (toplevel)
+ if (toplevel && GTK_IS_WINDOW (toplevel))
{
XSetInputFocus (GDK_DISPLAY (),
GDK_WINDOW_XWINDOW (toplevel->window),
@@ -711,6 +704,9 @@ gtk_socket_focus (GtkWidget *widget, GtkDirectionType direction)
socket = GTK_SOCKET (widget);
+ if (socket->plug_widget)
+ return gtk_widget_child_focus (socket->plug_widget, direction);
+
if (!GTK_WIDGET_HAS_FOCUS (widget))
{
switch (direction)
@@ -800,6 +796,39 @@ gtk_socket_focus (GtkWidget *widget, GtkDirectionType direction)
}
static void
+gtk_socket_remove (GtkContainer *container,
+ GtkWidget *child)
+{
+ GtkSocket *socket = GTK_SOCKET (container);
+ gboolean widget_was_visible;
+
+ g_return_if_fail (child == socket->plug_widget);
+
+ widget_was_visible = GTK_WIDGET_VISIBLE (child);
+
+ gtk_widget_unparent (child);
+ socket->plug_widget = NULL;
+
+ /* queue resize regardless of GTK_WIDGET_VISIBLE (container),
+ * since that's what is needed by toplevels, which derive from GtkBin.
+ */
+ if (widget_was_visible)
+ gtk_widget_queue_resize (GTK_WIDGET (container));
+}
+
+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);
+}
+
+static void
gtk_socket_send_configure_event (GtkSocket *socket)
{
XEvent event;
@@ -830,30 +859,98 @@ gtk_socket_send_configure_event (GtkSocket *socket)
}
static void
-gtk_socket_add_window (GtkSocket *socket, GdkNativeWindow xid)
+gtk_socket_add_window (GtkSocket *socket,
+ GdkNativeWindow xid,
+ gboolean need_reparent)
{
+
+ GtkWidget *widget = GTK_WIDGET (socket);
+ gpointer user_data = NULL;
+
socket->plug_window = gdk_window_lookup (xid);
- socket->same_app = TRUE;
- if (!socket->plug_window)
+ 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))
+ {
+ g_warning (G_STRLOC "Can't add non-GtkPlug to GtkSocket");
+ socket->plug_window = NULL;
+ gdk_error_trap_pop ();
+
+ return;
+ }
+
+ _gtk_plug_add_to_socket (GTK_PLUG (child_widget), socket);
+ }
+ else /* A foreign window */
{
GtkWidget *toplevel;
GdkDragProtocol protocol;
-
- socket->plug_window = gdk_window_foreign_new (xid);
- if (!socket->plug_window) /* Already gone */
- return;
-
- socket->same_app = FALSE;
+ unsigned long version;
+ unsigned long flags;
gdk_error_trap_push ();
+
+ if (!socket->plug_window)
+ {
+ socket->plug_window = gdk_window_foreign_new (xid);
+ if (!socket->plug_window) /* was deleted before we could get it */
+ {
+ gdk_error_trap_pop ();
+ return;
+ }
+ }
+
XSelectInput (GDK_DISPLAY (),
GDK_WINDOW_XWINDOW(socket->plug_window),
StructureNotifyMask | PropertyChangeMask);
+ if (gdk_error_trap_pop ())
+ {
+ gdk_window_unref (socket->plug_window);
+ 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;
+
+ socket->xembed_version = -1;
+ if (xembed_get_info (socket->plug_window, &version, &flags))
+ {
+ socket->xembed_version = version;
+ socket->is_mapped = (flags & XEMBED_MAPPED) != 0;
+ }
+ else
+ {
+ /* FIXME, we should probably actually check the state before we started */
+
+ socket->is_mapped = need_reparent ? TRUE : FALSE;
+ }
+
+ socket->need_map = socket->is_mapped;
+
if (gdk_drag_get_protocol (xid, &protocol))
gtk_drag_dest_set_proxy (GTK_WIDGET (socket), socket->plug_window,
protocol, TRUE);
+
gdk_flush ();
gdk_error_trap_pop ();
@@ -864,9 +961,7 @@ gtk_socket_add_window (GtkSocket *socket, GdkNativeWindow xid)
toplevel = gtk_widget_get_toplevel (GTK_WIDGET (socket));
if (toplevel && GTK_IS_WINDOW (toplevel))
- {
- gtk_window_add_embedded_xid (GTK_WINDOW (toplevel), xid);
- }
+ gtk_window_add_embedded_xid (GTK_WINDOW (toplevel), xid);
gtk_widget_queue_resize (GTK_WIDGET (socket));
}
@@ -907,6 +1002,58 @@ send_xembed_message (GtkSocket *socket,
}
}
+static gboolean
+xembed_get_info (GdkWindow *gdk_window,
+ unsigned long *version,
+ unsigned long *flags)
+{
+ Display *display = GDK_WINDOW_XDISPLAY (gdk_window);
+ Window window = GDK_WINDOW_XWINDOW (gdk_window);
+ Atom xembed_info_atom = gdk_atom_intern ("_XEMBED_INFO", FALSE);
+ Atom type;
+ int format;
+ unsigned long nitems, bytes_after;
+ unsigned char *data;
+ unsigned long *data_long;
+ int status;
+
+ gdk_error_trap_push();
+ status = XGetWindowProperty (display, window,
+ xembed_info_atom,
+ 0, 2, False,
+ xembed_info_atom, &type, &format,
+ &nitems, &bytes_after, &data);
+ gdk_error_trap_pop();
+
+ if (status != Success)
+ return FALSE; /* Window vanished? */
+
+ if (type == None) /* No info property */
+ return FALSE;
+
+ if (type != xembed_info_atom)
+ {
+ g_warning ("_XEMBED_INFO property has wrong type\n");
+ return FALSE;
+ }
+
+ if (nitems < 2)
+ {
+ g_warning ("_XEMBED_INFO too short\n");
+ XFree (data);
+ return FALSE;
+ }
+
+ data_long = (unsigned long *)data;
+ if (version)
+ *version = data_long[0];
+ if (flags)
+ *flags = data_long[1] & XEMBED_MAPPED;
+
+ XFree (data);
+ return TRUE;
+}
+
static void
handle_xembed_message (GtkSocket *socket,
glong message,
@@ -962,6 +1109,28 @@ handle_xembed_message (GtkSocket *socket,
}
}
+static void
+map_request (GtkSocket *socket)
+{
+ if (!socket->is_mapped)
+ {
+ socket->is_mapped = TRUE;
+ socket->need_map = TRUE;
+
+ gtk_widget_queue_resize (GTK_WIDGET (socket));
+ }
+}
+
+static void
+unmap_notify (GtkSocket *socket)
+{
+ if (socket->is_mapped)
+ {
+ socket->is_mapped = FALSE;
+ gtk_widget_queue_resize (GTK_WIDGET (socket));
+ }
+}
+
static GdkFilterReturn
gtk_socket_filter_func (GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data)
{
@@ -977,16 +1146,35 @@ gtk_socket_filter_func (GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data)
return_val = GDK_FILTER_CONTINUE;
+ if (socket->plug_widget)
+ return return_val;
+
switch (xevent->type)
{
+ case ClientMessage:
+ if (xevent->xclient.message_type == gdk_atom_intern ("_XEMBED", FALSE))
+ {
+ handle_xembed_message (socket,
+ xevent->xclient.data.l[1],
+ xevent->xclient.data.l[2],
+ xevent->xclient.data.l[3],
+ xevent->xclient.data.l[4],
+ xevent->xclient.data.l[0]);
+
+
+ return_val = GDK_FILTER_REMOVE;
+ }
+ break;
+
case CreateNotify:
{
XCreateWindowEvent *xcwe = &xevent->xcreatewindow;
if (!socket->plug_window)
- {
- gtk_socket_add_window (socket, xcwe->window);
+ gtk_socket_add_window (socket, xcwe->window, FALSE);
+ if (socket->plug_window)
+ {
gdk_error_trap_push ();
gdk_window_move_resize(socket->plug_window,
0, 0,
@@ -1015,9 +1203,9 @@ gtk_socket_filter_func (GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data)
XConfigureRequestEvent *xcre = &xevent->xconfigurerequest;
if (!socket->plug_window)
- gtk_socket_add_window (socket, xcre->window);
+ gtk_socket_add_window (socket, xcre->window, FALSE);
- if (xcre->window == GDK_WINDOW_XWINDOW (socket->plug_window))
+ if (socket->plug_window)
{
if (xcre->value_mask & (CWWidth | CWHeight))
{
@@ -1047,8 +1235,7 @@ gtk_socket_filter_func (GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data)
{
XDestroyWindowEvent *xdwe = &xevent->xdestroywindow;
- if (socket->plug_window &&
- (xdwe->window == GDK_WINDOW_XWINDOW (socket->plug_window)))
+ if (socket->plug_window && (xdwe->window == GDK_WINDOW_XWINDOW (socket->plug_window)))
{
GtkWidget *toplevel;
@@ -1078,9 +1265,9 @@ gtk_socket_filter_func (GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data)
{
#if 0
GtkWidget *toplevel;
- toplevel = gtk_widget_get_ancestor (widget, GTK_TYPE_WINDOW);
+ toplevel = gtk_widget_get_toplevel (widget);
- if (toplevel)
+ if (toplevel && GTK_IS_WINDOW (topelevel))
{
XSetInputFocus (GDK_DISPLAY (),
GDK_WINDOW_XWINDOW (toplevel->window),
@@ -1095,25 +1282,20 @@ gtk_socket_filter_func (GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data)
break;
case MapRequest:
if (!socket->plug_window)
- gtk_socket_add_window (socket, xevent->xmaprequest.window);
+ gtk_socket_add_window (socket, xevent->xmaprequest.window, FALSE);
- if (xevent->xmaprequest.window ==
- GDK_WINDOW_XWINDOW (socket->plug_window))
+ if (socket->plug_window)
{
GTK_NOTE(PLUGSOCKET,
g_message ("GtkSocket - Map Request"));
-
- gdk_error_trap_push ();
- gdk_window_show (socket->plug_window);
- gdk_flush ();
- gdk_error_trap_pop ();
+ map_request (socket);
return_val = GDK_FILTER_REMOVE;
}
break;
case PropertyNotify:
- if (xevent->xproperty.window ==
- GDK_WINDOW_XWINDOW (socket->plug_window))
+ if (socket->plug_window &&
+ xevent->xproperty.window == GDK_WINDOW_XWINDOW (socket->plug_window))
{
GdkDragProtocol protocol;
@@ -1128,23 +1310,47 @@ gtk_socket_filter_func (GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data)
gdk_flush ();
gdk_error_trap_pop ();
}
+ else if (xevent->xproperty.atom == gdk_atom_intern ("_XEMBED_INFO", FALSE))
+ {
+ unsigned long flags;
+
+ if (xembed_get_info (socket->plug_window, NULL, &flags))
+ {
+ gboolean was_mapped = socket->is_mapped;
+ gboolean is_mapped = (flags & XEMBED_MAPPED) != 0;
+
+ if (was_mapped != is_mapped)
+ {
+ if (is_mapped)
+ map_request (socket);
+ else
+ {
+ gdk_error_trap_push ();
+ gdk_window_show (socket->plug_window);
+ gdk_flush ();
+ gdk_error_trap_pop ();
+
+ unmap_notify (socket);
+ }
+ }
+ }
+ }
+
return_val = GDK_FILTER_REMOVE;
}
break;
- case ClientMessage:
- if (xevent->xclient.message_type == gdk_atom_intern ("_XEMBED", FALSE))
+ case UnmapNotify:
+ if (socket->plug_window &&
+ xevent->xunmap.window == GDK_WINDOW_XWINDOW (socket->plug_window))
{
- handle_xembed_message (socket,
- xevent->xclient.data.l[1],
- xevent->xclient.data.l[2],
- xevent->xclient.data.l[3],
- xevent->xclient.data.l[4],
- xevent->xclient.data.l[0]);
-
-
+ GTK_NOTE(PLUGSOCKET,
+ g_message ("GtkSocket - Unmap notify"));
+
+ unmap_notify (socket);
return_val = GDK_FILTER_REMOVE;
}
break;
+
}
return return_val;
diff --git a/gtk/gtksocket.h b/gtk/gtksocket.h
index d6dc92d710..18a762bbe9 100644
--- a/gtk/gtksocket.h
+++ b/gtk/gtksocket.h
@@ -54,10 +54,14 @@ struct _GtkSocket
guint16 current_height;
GdkWindow *plug_window;
+ GtkWidget *plug_widget;
+
+ gshort xembed_version; /* -1 == not xembed */
guint same_app : 1;
guint focus_in : 1;
guint have_size : 1;
guint need_map : 1;
+ guint is_mapped : 1;
GHashTable *grabbed_keys;
GtkWidget *toplevel;
diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c
index 3a2848b521..295855b89f 100644
--- a/gtk/gtkwidget.c
+++ b/gtk/gtkwidget.c
@@ -4550,7 +4550,19 @@ gtk_widget_set_extension_events (GtkWidget *widget,
*
* Note the difference in behavior vs. gtk_widget_get_ancestor();
* gtk_widget_get_ancestor (widget, GTK_TYPE_WINDOW) would return
- * %NULL if @widget wasn't inside a toplevel window.
+ * %NULL if @widget wasn't inside a toplevel window, and if the
+ * window was inside a GtkWindow-derived widget which was in turn
+ * inside the toplevel GtkWindow. While the second case may
+ * seem unlikely, it actually happens when a GtkPlug is embedded
+ * inside a GtkSocket within the same application
+ *
+ * To reliably find for the toplevel GtkWindow, use
+ *
+ * GtkWidget *toplevel = gtk_widget_get_toplevel (widget);
+ * if (GTK_IS_WINDOW (toplevel))
+ * {
+ * /* Perform action on toplevel.
+ * }
*
* Return value: the topmost ancestor of @widget, or @widget itself if there's no ancestor
**/
@@ -4574,7 +4586,8 @@ gtk_widget_get_toplevel (GtkWidget *widget)
* Gets the first ancestor of @widget with type @widget_type. For example,
* gtk_widget_get_ancestor (widget, GTK_TYPE_BOX) gets the first #GtkBox that's
* an ancestor of @widget. No reference will be added to the returned widget;
- * it should not be unreferenced.
+ * it should not be unreferenced. See note about checking for a toplevel
+ * GtkWindow in the docs for gtk_widget_get_toplevel().
*
* Return value: the ancestor widget, or %NULL if not found
**/
diff --git a/gtk/xembed.h b/gtk/xembed.h
index 5c4e35d774..d6de700f2a 100644
--- a/gtk/xembed.h
+++ b/gtk/xembed.h
@@ -17,3 +17,6 @@
#define XEMBED_FOCUS_FIRST 1
#define XEMBED_FOCUS_LAST 2
+
+/* Flags for _XEMBED_INFO */
+#define XEMBED_MAPPED (1 << 0)