From 149125b1a9d9f0bb2552c49bd17969fd2ddde2ae Mon Sep 17 00:00:00 2001 From: Viktor Odintsev Date: Thu, 14 Sep 2017 07:21:30 +0300 Subject: [PATCH] Extend GtkSocket and GtkPlug in order to pass min and nat sizes --- panel/panel-plugin-external.c | 128 ++++++++++++++++++++++++++++++++++++++++++ wrapper/wrapper-plug.c | 40 ++++++++++++- 2 files changed, 166 insertions(+), 2 deletions(-) diff --git a/panel/panel-plugin-external.c b/panel/panel-plugin-external.c index 2936d2fc..8bde9406 100644 --- a/panel/panel-plugin-external.c +++ b/panel/panel-plugin-external.c @@ -64,6 +64,12 @@ static void panel_plugin_external_set_property (GObject GParamSpec *pspec); static void panel_plugin_external_realize (GtkWidget *widget); static void panel_plugin_external_unrealize (GtkWidget *widget); +static void panel_plugin_external_get_preferred_width (GtkWidget *widget, + gint *minimum_width, + gint *natural_width); +static void panel_plugin_external_get_preferred_height (GtkWidget *widget, + gint *minimum_height, + gint *natural_height); static void panel_plugin_external_plug_added (GtkSocket *socket); static gboolean panel_plugin_external_plug_removed (GtkSocket *socket); static gboolean panel_plugin_external_child_ask_restart (PanelPluginExternal *external); @@ -126,6 +132,14 @@ struct _PanelPluginExternalPrivate /* delayed spawning */ guint spawn_timeout_id; + + /* remote size */ + guint have_size_idle_id; + gboolean have_size : 1; + gint remote_min_width; + gint remote_min_height; + gint remote_base_width; + gint remote_base_height; }; enum @@ -160,6 +174,8 @@ panel_plugin_external_class_init (PanelPluginExternalClass *klass) gtkwidget_class = GTK_WIDGET_CLASS (klass); gtkwidget_class->realize = panel_plugin_external_realize; gtkwidget_class->unrealize = panel_plugin_external_unrealize; + gtkwidget_class->get_preferred_width = panel_plugin_external_get_preferred_width; + gtkwidget_class->get_preferred_height = panel_plugin_external_get_preferred_height; gtksocket_class = GTK_SOCKET_CLASS (klass); gtksocket_class->plug_added = panel_plugin_external_plug_added; @@ -208,6 +224,8 @@ panel_plugin_external_init (PanelPluginExternal *external) external->priv->embedded = FALSE; external->priv->pid = 0; external->priv->spawn_timeout_id = 0; + external->priv->have_size_idle_id = 0; + external->priv->have_size = FALSE; /* signal to pass gtk_widget_set_sensitive() changes to the remote window */ g_signal_connect (G_OBJECT (external), "notify::sensitive", @@ -243,6 +261,9 @@ panel_plugin_external_finalize (GObject *object) { PanelPluginExternal *external = PANEL_PLUGIN_EXTERNAL (object); + if (external->priv->have_size_idle_id != 0) + g_source_remove (external->priv->have_size_idle_id); + if (external->priv->spawn_timeout_id != 0) g_source_remove (external->priv->spawn_timeout_id); @@ -377,6 +398,113 @@ panel_plugin_external_unrealize (GtkWidget *widget) +static gboolean +panel_plugin_external_have_size_handler (gpointer user_data) +{ + PanelPluginExternal *external = user_data; + + external->priv->have_size_idle_id = 0; + external->priv->have_size = FALSE; + + return G_SOURCE_REMOVE; +} + + + +static void +panel_plugin_external_get_preferred_size (GtkWidget *widget, + gint *minimum, + gint *natural, + gboolean horizontal) +{ + PanelPluginExternal *external = PANEL_PLUGIN_EXTERNAL (widget); + PanelPluginExternalPrivate *priv = external->priv; + GdkWindow *window; + XSizeHints size_hints; + long supplied; + + if (!priv->have_size) + { + priv->remote_min_width = 1; + priv->remote_base_width = 1; + priv->remote_min_height = 1; + priv->remote_base_height = 1; + + window = gtk_socket_get_plug_window (GTK_SOCKET (widget)); + + if (window != NULL && gdk_window_is_visible (window)) + { + gdk_error_trap_push (); + + if (XGetWMNormalHints (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window), + &size_hints, &supplied)) + { + /* With extended WrapperPlug both min_* and base_* should will be provided. + Otherwise make similar check as GtkSocket does. */ + + if ((size_hints.flags & PMinSize) && (size_hints.flags & PBaseSize)) + { + priv->remote_min_width = MAX (size_hints.min_width, 1); + priv->remote_min_height = MAX (size_hints.min_height, 1); + priv->remote_base_width = MAX (size_hints.base_width, 1); + priv->remote_base_height = MAX (size_hints.base_height, 1); + } + else if (size_hints.flags & PMinSize) + { + priv->remote_base_width = priv->remote_min_width = MAX (size_hints.min_width, 1); + priv->remote_base_height = priv->remote_min_height = MAX (size_hints.min_height, 1); + } + else if (size_hints.flags & PBaseSize) + { + priv->remote_base_width = priv->remote_min_width = MAX (size_hints.base_width, 1); + priv->remote_base_height = priv->remote_min_height = MAX (size_hints.base_height, 1); + } + + priv->remote_base_width = MAX (priv->remote_min_width, priv->remote_base_width); + priv->remote_base_height = MAX (priv->remote_min_height, priv->remote_base_height); + } + + gdk_error_trap_pop_ignored (); + + priv->have_size = TRUE; + + if (priv->have_size_idle_id != 0) + g_source_remove (priv->have_size_idle_id); + + /* cache sizes allowing to fetch the same values during current loop iteration */ + priv->have_size_idle_id = g_idle_add (panel_plugin_external_have_size_handler, external); + } + } + + if (minimum != NULL) + *minimum = horizontal ? external->priv->remote_min_width : external->priv->remote_min_height; + + if (natural != NULL) + *natural = horizontal ? external->priv->remote_base_width : external->priv->remote_base_height; +} + + + +static void +panel_plugin_external_get_preferred_width (GtkWidget *widget, + gint *minimum_width, + gint *natural_width) +{ + panel_plugin_external_get_preferred_size (widget, minimum_width, natural_width, TRUE); +} + + + +static void +panel_plugin_external_get_preferred_height (GtkWidget *widget, + gint *minimum_height, + gint *natural_height) +{ + panel_plugin_external_get_preferred_size (widget, minimum_height, natural_height, FALSE); +} + + + static void panel_plugin_external_plug_added (GtkSocket *socket) { diff --git a/wrapper/wrapper-plug.c b/wrapper/wrapper-plug.c index 6dde8c9b..8257c123 100644 --- a/wrapper/wrapper-plug.c +++ b/wrapper/wrapper-plug.c @@ -38,6 +38,7 @@ static gboolean wrapper_plug_expose_event (GtkWidget *widget, GdkEventExpose *event); #endif static void wrapper_plug_background_reset (WrapperPlug *plug); +static void wrapper_plug_check_resize (GtkContainer *container); @@ -74,8 +75,9 @@ G_DEFINE_TYPE (WrapperPlug, wrapper_plug, GTK_TYPE_PLUG) static void wrapper_plug_class_init (WrapperPlugClass *klass) { - GObjectClass *gobject_class; - GtkWidgetClass *gtkwidget_class; + GObjectClass *gobject_class; + GtkWidgetClass *gtkwidget_class; + GtkContainerClass *gtkcontainer_class; gobject_class = G_OBJECT_CLASS (klass); gobject_class->finalize = wrapper_plug_finalize; @@ -86,6 +88,9 @@ wrapper_plug_class_init (WrapperPlugClass *klass) #else gtkwidget_class->expose_event = wrapper_plug_expose_event; #endif + + gtkcontainer_class = GTK_CONTAINER_CLASS (klass); + gtkcontainer_class->check_resize = wrapper_plug_check_resize; } @@ -351,6 +356,37 @@ wrapper_plug_background_reset (WrapperPlug *plug) plug->background_image = NULL; } +static void +wrapper_plug_check_resize (GtkContainer *container) +{ +#if GTK_CHECK_VERSION (3, 0, 0) + gint min_width, width, min_height, height; + GdkGeometry geometry; + GtkWidget *child; +#endif + + GTK_CONTAINER_CLASS (wrapper_plug_parent_class)->check_resize (container); + +#if GTK_CHECK_VERSION (3, 0, 0) + child = gtk_bin_get_child (GTK_BIN (container)); + gtk_widget_get_preferred_width (child, &min_width, &width); + gtk_widget_get_preferred_height (child, &min_height, &height); + + width = MAX (width, 1); + height = MAX (height, 1); + min_width = MIN (width, MAX (min_width, 1)); + min_height = MIN (height, MAX (min_height, 1)); + + geometry.min_width = min_width; + geometry.base_width = width; + geometry.min_height = min_height; + geometry.base_height = height; + + gdk_window_set_geometry_hints (gtk_widget_get_window (GTK_WIDGET (container)), + &geometry, GDK_HINT_MIN_SIZE | GDK_HINT_BASE_SIZE); +#endif +} + WrapperPlug * -- 2.14.1