[gnome-terminal/wip/restore-geometry: 3/3] screen-container: Implement the resize popup for Wayland



commit b612a3523b89f4362a83b0f46f4c31916e6e3058
Author: Debarshi Ray <debarshir gnome org>
Date:   Fri Apr 15 19:32:35 2016 +0200

    screen-container: Implement the resize popup for Wayland
    
    Wayland doesn't have geometry hints for resizing. The size increments
    are implemented entirely on the client side in GDK's Wayland backend.
    This means that the WM cannot show the resize popup as it does on X.
    Therefore, we have to implement it inside the application when running
    on Wayland.
    
    On X, the resize popup is shown when the mouse button is pressed near
    the window edge and hidden when released. Unfortunately, this pointer
    grab is entirely within the WM and not visible to the application.
    Therefore, on Wayland, we show the resize popup when the size of the
    window actually changes, and we hide on key-press-event or
    motion-notify-event.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=760944

 po/POTFILES.in                  |    1 +
 src/terminal-screen-container.c |  162 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 163 insertions(+), 0 deletions(-)
---
diff --git a/po/POTFILES.in b/po/POTFILES.in
index df83840..0f54f45 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -23,6 +23,7 @@ src/terminal-notebook.c
 src/terminal-options.c
 src/terminal-prefs.c
 src/terminal-screen.c
+src/terminal-screen-container.c
 src/terminal-search-popover.c
 src/terminal-tab-label.c
 src/terminal-tabs-menu.c
diff --git a/src/terminal-screen-container.c b/src/terminal-screen-container.c
index 1864712..a805da7 100644
--- a/src/terminal-screen-container.c
+++ b/src/terminal-screen-container.c
@@ -17,20 +17,33 @@
 
 #include "config.h"
 
+#include <glib/gi18n.h>
+
+#include "terminal-libgsystem.h"
 #include "terminal-screen-container.h"
 #include "terminal-debug.h"
 
 #include <gtk/gtk.h>
 
+#ifdef GDK_WINDOWING_WAYLAND
+#include <gdk/gdkwayland.h>
+#endif
+
 #define TERMINAL_SCREEN_CONTAINER_GET_PRIVATE(screen_container)(G_TYPE_INSTANCE_GET_PRIVATE 
((screen_container), TERMINAL_TYPE_SCREEN_CONTAINER, TerminalScreenContainerPrivate))
 
 struct _TerminalScreenContainerPrivate
 {
   TerminalScreen *screen;
   GtkWidget *hbox;
+  GtkWidget *resize_popup;
   GtkWidget *vscrollbar;
   GtkPolicyType hscrollbar_policy;
   GtkPolicyType vscrollbar_policy;
+  int old_grid_height;
+  int old_grid_width;
+  unsigned int connect_toplevel_id;
+  unsigned long motion_notify_id;
+  unsigned long size_allocate_id;
 };
 
 enum
@@ -45,10 +58,126 @@ enum
 
 G_DEFINE_TYPE (TerminalScreenContainer, terminal_screen_container, GTK_TYPE_OVERLAY)
 
+static gboolean is_wayland = FALSE;
+
 /* helper functions */
 
 /* Widget class implementation */
 
+static gboolean
+terminal_screen_container_key_press_event (TerminalScreenContainer *container)
+{
+  TerminalScreenContainerPrivate *priv = container->priv;
+
+  gtk_widget_hide (priv->resize_popup);
+  return GDK_EVENT_PROPAGATE;
+}
+
+static gboolean
+terminal_screen_container_motion_notify_event (TerminalScreenContainer *container)
+{
+  TerminalScreenContainerPrivate *priv = container->priv;
+
+  gtk_widget_hide (priv->resize_popup);
+  return GDK_EVENT_PROPAGATE;
+}
+
+static gboolean
+terminal_screen_container_size_allocate (TerminalScreenContainer *container)
+{
+  TerminalScreenContainerPrivate *priv = container->priv;
+  gs_free char *text = NULL;
+  int grid_height;
+  int grid_width;
+
+  if (priv->screen == NULL)
+    goto out;
+
+  terminal_screen_get_size (priv->screen, &grid_width, &grid_height);
+  if (grid_height == priv->old_grid_height && grid_width == priv->old_grid_width)
+    goto out;
+
+  text = g_strdup_printf (_("%d x %d"), grid_width, grid_height);
+  gtk_label_set_text (GTK_LABEL (priv->resize_popup), text);
+  gtk_widget_show (priv->resize_popup);
+
+  priv->old_grid_height = grid_height;
+  priv->old_grid_width = grid_width;
+
+ out:
+  return GDK_EVENT_PROPAGATE;
+}
+
+static gboolean
+terminal_screen_container_connect_toplevel (TerminalScreenContainer *container)
+{
+  TerminalScreenContainerPrivate *priv = container->priv;
+  GtkWidget *toplevel;
+
+  priv->connect_toplevel_id = 0;
+
+  toplevel = gtk_widget_get_toplevel (GTK_WIDGET (container));
+  if (gtk_widget_is_toplevel (toplevel))
+    {
+      priv->motion_notify_id = g_signal_connect_object (toplevel,
+                                                        "motion-notify-event",
+                                                        G_CALLBACK 
(terminal_screen_container_motion_notify_event),
+                                                        container,
+                                                        G_CONNECT_SWAPPED);
+
+      priv->size_allocate_id = g_signal_connect_object (toplevel,
+                                                        "size-allocate",
+                                                        G_CALLBACK (terminal_screen_container_size_allocate),
+                                                        container,
+                                                        G_CONNECT_SWAPPED);
+    }
+
+  return G_SOURCE_REMOVE;
+}
+
+static void
+terminal_screen_container_remove_idle (TerminalScreenContainer *container)
+{
+  TerminalScreenContainerPrivate *priv = container->priv;
+
+  if (priv->connect_toplevel_id != 0)
+    {
+      g_source_remove (priv->connect_toplevel_id);
+      priv->connect_toplevel_id = 0;
+    }
+}
+
+static void
+terminal_screen_container_parent_set (GtkWidget *widget, GtkWidget *old_parent)
+{
+  TerminalScreenContainer *container = TERMINAL_SCREEN_CONTAINER (widget);
+  TerminalScreenContainerPrivate *priv = container->priv;
+  GtkWidget *toplevel;
+
+  if (!is_wayland)
+    return;
+
+  toplevel = gtk_widget_get_toplevel (widget);
+  if (gtk_widget_is_toplevel (toplevel))
+    {
+      if (priv->motion_notify_id != 0)
+        {
+          g_signal_handler_disconnect (old_parent, priv->motion_notify_id);
+          priv->motion_notify_id = 0;
+        }
+
+      if (priv->size_allocate_id != 0)
+        {
+          g_signal_handler_disconnect (old_parent, priv->size_allocate_id);
+          priv->size_allocate_id = 0;
+        }
+
+      terminal_screen_container_remove_idle (container);
+      priv->connect_toplevel_id = g_idle_add ((GSourceFunc) terminal_screen_container_connect_toplevel,
+                                              container);
+    }
+}
+
 static void
 terminal_screen_container_style_updated (GtkWidget *widget)
 {
@@ -93,6 +222,12 @@ terminal_screen_container_init (TerminalScreenContainer *container)
 
   priv = container->priv = TERMINAL_SCREEN_CONTAINER_GET_PRIVATE (container);
 
+  priv->resize_popup = gtk_label_new (NULL);
+  gtk_widget_set_halign (priv->resize_popup, GTK_ALIGN_CENTER);
+  gtk_widget_set_valign (priv->resize_popup, GTK_ALIGN_CENTER);
+  gtk_widget_set_no_show_all (priv->resize_popup, TRUE);
+  gtk_overlay_add_overlay (GTK_OVERLAY (container), priv->resize_popup);
+
   priv->hscrollbar_policy = GTK_POLICY_AUTOMATIC;
   priv->vscrollbar_policy = GTK_POLICY_AUTOMATIC;
 }
@@ -107,6 +242,11 @@ terminal_screen_container_constructed (GObject *object)
 
   g_assert (priv->screen != NULL);
 
+  g_signal_connect_swapped (priv->screen,
+                            "key-press-event",
+                            G_CALLBACK (terminal_screen_container_key_press_event),
+                            container);
+
   priv->hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
 
   priv->vscrollbar = gtk_scrollbar_new (GTK_ORIENTATION_VERTICAL,
@@ -175,6 +315,16 @@ terminal_screen_container_set_property (GObject *object,
 }
 
 static void
+terminal_screen_container_dispose (GObject *object)
+{
+  TerminalScreenContainer *container = TERMINAL_SCREEN_CONTAINER (object);
+
+  terminal_screen_container_remove_idle (container);
+
+  G_OBJECT_CLASS (terminal_screen_container_parent_class)->dispose (object);
+}
+
+static void
 terminal_screen_container_class_init (TerminalScreenContainerClass *klass)
 {
   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
@@ -183,9 +333,11 @@ terminal_screen_container_class_init (TerminalScreenContainerClass *klass)
   g_type_class_add_private (gobject_class, sizeof (TerminalScreenContainerPrivate));
 
   gobject_class->constructed = terminal_screen_container_constructed;
+  gobject_class->dispose = terminal_screen_container_dispose;
   gobject_class->get_property = terminal_screen_container_get_property;
   gobject_class->set_property = terminal_screen_container_set_property;
 
+  widget_class->parent_set = terminal_screen_container_parent_set;
   widget_class->style_updated = terminal_screen_container_style_updated;
 
   g_object_class_install_property
@@ -225,6 +377,16 @@ terminal_screen_container_class_init (TerminalScreenContainerClass *klass)
                                                                  FALSE,
                                                                  G_PARAM_READWRITE |
                                                                  G_PARAM_STATIC_STRINGS));
+
+#ifdef GDK_WINDOWING_WAYLAND
+  {
+    GdkDisplay *display;
+
+    display = gdk_display_get_default ();
+    if (GDK_IS_WAYLAND_DISPLAY (display))
+      is_wayland = TRUE;
+  }
+#endif
 }
 
 /* public API */


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]