From 56edab35539fa81b8061dc7e963905b625bc2583 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Sat, 19 Dec 2009 01:23:58 -0500 Subject: [PATCH] Implement extended layout for plug/socket --- gtk/gtkplug-x11.c | 27 ++++++++++++++++ gtk/gtkplug.c | 8 +++++ gtk/gtkplugprivate.h | 3 ++ gtk/gtksocket-x11.c | 62 ++++++++++++++++++++++++++++++++++++ gtk/gtksocket.c | 72 +++++++++++++++++++++++++++++++++++++++++- gtk/gtksocketprivate.h | 4 +++ 6 files changed, 175 insertions(+), 1 deletion(-) diff --git a/gtk/gtkplug-x11.c b/gtk/gtkplug-x11.c index 95dcf1ab6f..fa81b61b54 100644 --- a/gtk/gtkplug-x11.c +++ b/gtk/gtkplug-x11.c @@ -32,6 +32,7 @@ #include "gtkplugprivate.h" #include "x11/gdkx.h" +#include #include "gtkxembed.h" #include "gtkalias.h" @@ -330,3 +331,29 @@ _gtk_plug_windowing_filter_func (GdkXEvent *gdk_xevent, return return_val; } + +void +_gtk_plug_windowing_publish_natural_size (GtkPlug *plug, + GtkRequisition *requisition) +{ + GtkWidget *widget = GTK_WIDGET (plug); + GdkDisplay *display; + GdkWindow *window; + gint32 data[2]; + Atom property; + + gtk_widget_realize (widget); + + window = GTK_WIDGET (plug)->window; + display = gdk_drawable_get_display (window); + property = gdk_x11_get_xatom_by_name_for_display (display, "_GTK_NATURAL_SIZE"); + + data[0] = requisition->width; + data[1] = requisition->height; + + XChangeProperty (GDK_DISPLAY_XDISPLAY (display), + GDK_WINDOW_XWINDOW (window), property, + XA_CARDINAL, 32, PropModeReplace, + (unsigned char*)data, 2); +} + diff --git a/gtk/gtkplug.c b/gtk/gtkplug.c index 4c31ea70d6..593df8c1d0 100644 --- a/gtk/gtkplug.c +++ b/gtk/gtkplug.c @@ -30,6 +30,7 @@ #include "gtkmain.h" #include "gtkmarshalers.h" #include "gtkplug.h" +#include "gtkextendedlayout.h" #include "gtkintl.h" #include "gtkprivate.h" #include "gtkplugprivate.h" @@ -721,6 +722,9 @@ static void gtk_plug_size_allocate (GtkWidget *widget, GtkAllocation *allocation) { + GtkBin *bin = GTK_BIN (widget); + GtkRequisition natural_size; + if (GTK_WIDGET_TOPLEVEL (widget)) GTK_WIDGET_CLASS (gtk_plug_parent_class)->size_allocate (widget, allocation); else @@ -748,6 +752,10 @@ gtk_plug_size_allocate (GtkWidget *widget, } } + + gtk_extended_layout_get_desired_size (GTK_EXTENDED_LAYOUT (bin->child), + NULL, &natural_size); + _gtk_plug_windowing_publish_natural_size (GTK_PLUG (widget), &natural_size); } static gboolean diff --git a/gtk/gtkplugprivate.h b/gtk/gtkplugprivate.h index 74f0374bc5..83dcaaf7ff 100644 --- a/gtk/gtkplugprivate.h +++ b/gtk/gtkplugprivate.h @@ -138,4 +138,7 @@ GdkFilterReturn _gtk_plug_windowing_filter_func (GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data); +void _gtk_plug_windowing_publish_natural_size (GtkPlug *plug, + GtkRequisition *requisition); + #endif /* __GTK_PLUG_PRIVATE_H__ */ diff --git a/gtk/gtksocket-x11.c b/gtk/gtksocket-x11.c index 5dbde457a8..c076f9d0dd 100644 --- a/gtk/gtksocket-x11.c +++ b/gtk/gtksocket-x11.c @@ -39,6 +39,7 @@ #include "gtkdnd.h" #include "x11/gdkx.h" +#include #ifdef HAVE_XFIXES #include @@ -122,6 +123,63 @@ _gtk_socket_windowing_size_request (GtkSocket *socket) gdk_error_trap_pop (); } +void +_gtk_socket_windowing_get_natural_size (GtkSocket *socket) +{ + GtkSocketPrivate *priv; + GdkDisplay *display; + + Atom property, type; + int format, status; + + unsigned long nitems, bytes_after; + unsigned char *data; + gint32 *data_long; + + priv = _gtk_socket_get_private (socket); + + priv->natural_width = 1; + priv->natural_height = 1; + + if (GTK_WIDGET_MAPPED (socket)) + { + display = gdk_drawable_get_display (socket->plug_window); + property = gdk_x11_get_xatom_by_name_for_display (display, "_GTK_NATURAL_SIZE"); + + gdk_error_trap_push (); + status = XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), + GDK_WINDOW_XWINDOW (socket->plug_window), + property, 0, 2, False, XA_CARDINAL, + &type, &format, &nitems, &bytes_after, + &data); + gdk_error_trap_pop (); + + priv->have_natural_size = TRUE; + + if (Success != status || !type) + return; + + if (type != XA_CARDINAL) + { + g_warning ("_GTK_NATURAL_SIZE property has wrong type: %d\n", (int)type); + return; + } + + if (nitems < 2) + { + g_warning ("_GTK_NATURAL_SIZE too short\n"); + XFree (data); + return; + } + + data_long = (gint32*) data; + priv->natural_width = MAX (1, data_long[0]); + priv->natural_height = MAX (1, data_long[1]); + + XFree (data); + } +} + void _gtk_socket_windowing_send_key_event (GtkSocket *socket, GdkEvent *gdk_event, @@ -602,6 +660,10 @@ _gtk_socket_windowing_filter_func (GdkXEvent *gdk_xevent, } return_val = GDK_FILTER_REMOVE; } + else if (xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "_GTK_NATURAL_SIZE")) + { + _gtk_socket_windowing_get_natural_size (socket); + } } break; case ReparentNotify: diff --git a/gtk/gtksocket.c b/gtk/gtksocket.c index f059f8d6de..c109348148 100644 --- a/gtk/gtksocket.c +++ b/gtk/gtksocket.c @@ -37,6 +37,7 @@ #include "gtksocket.h" #include "gtksocketprivate.h" #include "gtkdnd.h" +#include "gtkextendedlayout.h" #include "gtkintl.h" #include "gtkalias.h" @@ -67,6 +68,7 @@ static void gtk_socket_forall (GtkContainer *container, GtkCallback callback, gpointer callback_data); +static void gtk_socket_extended_layout_interface_init (GtkExtendedLayoutIface *iface); /* Local data */ @@ -98,7 +100,10 @@ _gtk_socket_get_private (GtkSocket *socket) return G_TYPE_INSTANCE_GET_PRIVATE (socket, GTK_TYPE_SOCKET, GtkSocketPrivate); } -G_DEFINE_TYPE (GtkSocket, gtk_socket, GTK_TYPE_CONTAINER) +G_DEFINE_TYPE_WITH_CODE (GtkSocket, gtk_socket, GTK_TYPE_CONTAINER, + G_IMPLEMENT_INTERFACE (GTK_TYPE_EXTENDED_LAYOUT, + gtk_socket_extended_layout_interface_init)) + static void gtk_socket_finalize (GObject *object) @@ -185,6 +190,8 @@ gtk_socket_class_init (GtkSocketClass *class) static void gtk_socket_init (GtkSocket *socket) { + GtkSocketPrivate *priv; + socket->request_width = 0; socket->request_height = 0; socket->current_width = 0; @@ -199,6 +206,9 @@ gtk_socket_init (GtkSocket *socket) socket->accel_group = gtk_accel_group_new (); g_object_set_data (G_OBJECT (socket->accel_group), I_("gtk-socket"), socket); + + priv = _gtk_socket_get_private (socket); + priv->have_natural_size = FALSE; } /** @@ -1000,5 +1010,65 @@ _gtk_socket_advance_toplevel_focus (GtkSocket *socket, } } +static void +gtk_socket_extended_layout_get_desired_size (GtkExtendedLayout *layout, + GtkRequisition *minimal_size, + GtkRequisition *desired_size) +{ + GtkSocket *socket = GTK_SOCKET (layout); + GtkSocketPrivate *priv; + + if (socket->plug_widget) + { + gtk_extended_layout_get_desired_size (GTK_EXTENDED_LAYOUT (socket->plug_widget), + minimal_size, + desired_size); + } + else + { + priv = _gtk_socket_get_private (socket); + + if (socket->is_mapped && !priv->have_natural_size && socket->plug_window) + { + _gtk_socket_windowing_size_request (socket); + _gtk_socket_windowing_get_natural_size (socket); + } + + if (socket->is_mapped && priv->have_natural_size) + { + if (minimal_size) + { + minimal_size->width = MAX (socket->request_width, 1); + minimal_size->height = MAX (socket->request_height, 1); + } + if (desired_size) + { + desired_size->width = MAX (priv->natural_width, 1); + desired_size->height = MAX (priv->natural_height, 1); + } + } + else + { + if (minimal_size) + { + minimal_size->width = 1; + minimal_size->height = 1; + } + if (desired_size) + { + desired_size->width = 1; + desired_size->height = 1; + } + } + } +} + +static void +gtk_socket_extended_layout_interface_init (GtkExtendedLayoutIface *iface) +{ + iface->get_desired_size = gtk_socket_extended_layout_get_desired_size; +} + + #define __GTK_SOCKET_C__ #include "gtkaliasdef.c" diff --git a/gtk/gtksocketprivate.h b/gtk/gtksocketprivate.h index 44a6c6b36e..8eda1ae6b3 100644 --- a/gtk/gtksocketprivate.h +++ b/gtk/gtksocketprivate.h @@ -31,6 +31,9 @@ typedef struct _GtkSocketPrivate GtkSocketPrivate; struct _GtkSocketPrivate { gint resize_count; + gint natural_width; + gint natural_height; + gboolean have_natural_size; }; /* In gtksocket.c: */ @@ -83,6 +86,7 @@ void _gtk_socket_windowing_end_embedding_toplevel (GtkSocket *socket); */ void _gtk_socket_windowing_size_request (GtkSocket *socket); +void _gtk_socket_windowing_get_natural_size (GtkSocket *socket); /* * _gtk_socket_windowing_send_key_event: *