gtk: Replaced GtkScrolledWindow with GtkScrollingWindow.
authorMatt Birkholz <matt@birkholz.chandler.az.us>
Tue, 14 Aug 2012 04:39:48 +0000 (21:39 -0700)
committerMatt Birkholz <matt@birkholz.chandler.az.us>
Tue, 14 Aug 2012 04:39:48 +0000 (21:39 -0700)
Define GtkScrollingWindow as a subclass of GtkScrolledWindow that
specializes (overrides) the geometry protocol, while inheriting
kinetic scrolling and other goodies(?).

src/gtk/Makefile-fragment
src/gtk/gtk-shim.h
src/gtk/gtk-widget.scm
src/gtk/gtk.cdecl
src/gtk/gtkscrollingwindow.c.stay [new file with mode: 0644]
src/gtk/gtkscrollingwindow.h [new file with mode: 0644]

index 4c3dc3dbb40f8d6f6a79758502b6c002e4f7b9d6..f0a80d50df7bf6d68445c81c23a763478152e7b5 100644 (file)
@@ -59,11 +59,17 @@ install:
                 | ../microcode/scheme --library ../lib --batch-mode` = "c"; \
        then $(MAKE) install-liarc-bundle; fi
 
-gtk-shim.so: gtk-shim.o scmwidget.o gtkio.o $(SHIM_LOADER)
-       $(LINK_SHIM) gtk-shim.o scmwidget.o gtkio.o                     \
+gtk-shim.so: gtk-shim.o gtkscrollingwindow.o scmwidget.o gtkio.o $(SHIM_LOADER)
+       $(LINK_SHIM) gtk-shim.o gtkscrollingwindow.o scmwidget.o gtkio.o       \
                `pkg-config --libs gtk+-3.0 gthread-2.0` $(SHIM_LIBS)
 
-scmwidget.o: scmwidget.c
+gtkscrollingwindow.o: gtkscrollingwindow.c gtkscrollingwindow.h
+       $(COMPILE_SHIM) `pkg-config --cflags gtk+-3.0` -c gtkscrollingwindow.c
+
+gtkscrollingwindow.c: gtkscrollingwindow.c.stay
+       cp -p gtkscrollingwindow.c.stay gtkscrollingwindow.c
+
+scmwidget.o: scmwidget.c scmwidget.h
        $(COMPILE_SHIM) `pkg-config --cflags gtk+-3.0` -c scmwidget.c
 
 scmwidget.c: scmwidget.c.stay
index 3949d085bde619329c05b331480f8c34f41d0cf0..0fcb622766f8407552e9d83fca9458e69a071a74 100644 (file)
@@ -30,6 +30,7 @@ USA.
 
 #include <gtk/gtk.h>
 #include "scmwidget.h"
+#include "gtkscrollingwindow.h"
 
 typedef unsigned int uint;
 extern gboolean start_gtk (int *argc, char ***argv);
index 7d5de419923a3baf11fe4cc28ea6d40d63578f28..e6603c4023144b570fee6c6511aa11faf8c20095 100644 (file)
@@ -623,7 +623,7 @@ USA.
 (define (gtk-scrolled-window-new)
   (let* ((window (make-gtk-scrolled-window))
         (alien (gobject-alien window)))
-    (C-call "gtk_scrolled_window_new" alien 0 0)
+    (C-call "gtk_scrolling_window_new" alien 0 0)
     (error-if-null alien "Could not create:" window)
     (C-call "g_object_ref_sink" alien alien)
     (set-gtk-widget-destroy-callback! window)
index 6375ee94b6d12580d7c55adb91cb34f9dff4a54e..1f56dfc83320bbf082debff155861cba260f5d53 100644 (file)
@@ -99,6 +99,11 @@ USA.
 
 ;;; miscellaneous
 
+(extern (* GtkWidget)                  ;gtkscrollingwindow.h
+       gtk_scrolling_window_new
+       (hadjustment (* GtkAdjustment))
+       (vadjustment (* GtkAdjustment)))
+
 (extern void g_free                    ;glib-2.8.6/glib/gmem.h
        (mem gpointer))
 
diff --git a/src/gtk/gtkscrollingwindow.c.stay b/src/gtk/gtkscrollingwindow.c.stay
new file mode 100644 (file)
index 0000000..38efa8b
--- /dev/null
@@ -0,0 +1,336 @@
+#include "gtkscrollingwindow.h"
+
+/**
+ * SECTION:gtkscrollingwindow
+ * @Short_description: Adds scrollbars to its child widget
+ * @Title: GtkScrollingWindow
+ * @See_also: #GtkScrollable, #GtkViewport, #GtkAdjustment
+ *
+ * #GtkScrollingWindow is a #GtkBin subclass: it's a container that
+ * accepts a single child widget (a GtkScrollable) and adds an
+ * optional beveled frame and scrollbars.
+ *
+ * The position of the scrollbars is controlled by the scroll
+ * adjustments. See #GtkAdjustment for the fields in an adjustment.
+ *
+ * #GtkScrollingWindow is a #GtkScrolledWindow subclass that overrides
+ * the geometry protocol to work as follows:
+ *
+ * A scrolled window (GtkScrolledWindow) is about squeezing an overly
+ * large widget into a small space and allowing the user to scroll it.
+ * It ignores the natural size of the problem widget, expecting a
+ * gtk_widget_set_size_request to override (squeeze) it.
+ *
+ * A scrolling window (GtkScrollingWindow) is about sticking
+ * scrollbars on a viewport -- a GtkScrollable.  Its natural size is
+ * the natural size of the viewport, scrollbars and frame (with
+ * spacing).  Using gtk_widget_set_size_request interferes with the
+ * natural sizing (esp. shrinking of expandable viewports).
+ */
+
+struct _GtkScrolledWindowPrivate
+{
+  GtkWidget     *hscrollbar;
+  GtkWidget     *vscrollbar;
+
+  GtkCornerType  real_window_placement;
+  guint16  shadow_type;
+
+  guint    window_placement_set   : 1;
+  guint    hscrollbar_policy      : 2;
+  guint    vscrollbar_policy      : 2;
+  guint    hscrollbar_visible     : 1;
+  guint    vscrollbar_visible     : 1;
+  guint    window_placement       : 2;
+  guint    focus_out              : 1; /* Flag used by ::move-focus-out implementation */
+
+  gint     min_content_width;
+  gint     min_content_height;
+
+  /* Kinetic scrolling */
+  GdkEvent              *button_press_event;
+  GdkWindow             *overshoot_window;
+  GdkDevice             *drag_device;
+  guint                  kinetic_scrolling         : 1;
+  guint                  capture_button_press      : 1;
+  guint                  in_drag                   : 1;
+  guint                  last_button_event_valid   : 1;
+
+  guint                  release_timeout_id;
+  guint                  deceleration_id;
+
+  gdouble                last_button_event_x_root;
+  gdouble                last_button_event_y_root;
+
+  gdouble                last_motion_event_x_root;
+  gdouble                last_motion_event_y_root;
+  guint32                last_motion_event_time;
+
+  gdouble                x_velocity;
+  gdouble                y_velocity;
+
+  gdouble                unclamped_hadj_value;
+  gdouble                unclamped_vadj_value;
+};
+
+static void
+gtk_scrolled_window_update_real_placement (GtkScrolledWindow *scrolled_window)
+{
+  GtkScrolledWindowPrivate *priv = scrolled_window->priv;
+  GtkSettings *settings;
+
+  settings = gtk_widget_get_settings (GTK_WIDGET (scrolled_window));
+
+  if (priv->window_placement_set || settings == NULL)
+    priv->real_window_placement = priv->window_placement;
+  else
+    g_object_get (settings,
+                 "gtk-scrolled-window-placement",
+                 &priv->real_window_placement,
+                 NULL);
+}
+
+static void
+gtk_scrolled_window_init (GtkScrolledWindow *scrolled_window)
+{
+  GtkScrolledWindowPrivate *priv;
+
+  scrolled_window->priv = priv = G_TYPE_INSTANCE_GET_PRIVATE (scrolled_window,
+                                                              GTK_TYPE_SCROLLED_WINDOW,
+                                                              GtkScrolledWindowPrivate);
+
+  gtk_widget_set_has_window (GTK_WIDGET (scrolled_window), FALSE);
+  gtk_widget_set_can_focus (GTK_WIDGET (scrolled_window), TRUE);
+
+  priv->hscrollbar = NULL;
+  priv->vscrollbar = NULL;
+  priv->hscrollbar_policy = GTK_POLICY_AUTOMATIC;
+  priv->vscrollbar_policy = GTK_POLICY_AUTOMATIC;
+  priv->hscrollbar_visible = FALSE;
+  priv->vscrollbar_visible = FALSE;
+  priv->focus_out = FALSE;
+  priv->window_placement = GTK_CORNER_TOP_LEFT;
+  gtk_scrolled_window_update_real_placement (scrolled_window);
+  priv->min_content_width = -1;
+  priv->min_content_height = -1;
+
+  gtk_scrolled_window_set_kinetic_scrolling (scrolled_window, TRUE);
+  gtk_scrolled_window_set_capture_button_press (scrolled_window, TRUE);
+}
+
+static void  gtk_scrolling_window_get_preferred_width   (GtkWidget           *widget,
+                                                       gint                *minimum_size,
+                                                       gint                *natural_size);
+static void  gtk_scrolling_window_get_preferred_height  (GtkWidget           *widget,
+                                                       gint                *minimum_size,
+                                                       gint                *natural_size);
+static void  gtk_scrolling_window_get_preferred_height_for_width  (GtkWidget           *layout,
+                                                       gint                 width,
+                                                       gint                *minimum_height,
+                                                       gint                *natural_height);
+static void  gtk_scrolling_window_get_preferred_width_for_height  (GtkWidget           *layout,
+                                                       gint                 width,
+                                                       gint                *minimum_height,
+                                                       gint                *natural_height);
+
+G_DEFINE_TYPE (GtkScrollingWindow, gtk_scrolling_window,
+              GTK_TYPE_SCROLLED_WINDOW)
+
+static void
+gtk_scrolling_window_class_init (GtkScrollingWindowClass *class)
+{
+  GtkWidgetClass *widget_class = (GtkWidgetClass*) class;
+
+  widget_class->get_preferred_width = gtk_scrolling_window_get_preferred_width;
+  widget_class->get_preferred_height = gtk_scrolling_window_get_preferred_height;
+  widget_class->get_preferred_height_for_width = gtk_scrolling_window_get_preferred_height_for_width;
+  widget_class->get_preferred_width_for_height = gtk_scrolling_window_get_preferred_width_for_height;
+}
+
+static void
+gtk_scrolling_window_init (GtkScrollingWindow *scrolling_window)
+{
+  gtk_scrolled_window_init (GTK_SCROLLED_WINDOW (scrolling_window));
+}
+
+/**
+ * gtk_scrolling_window_new:
+ * @hadjustment: (allow-none): horizontal adjustment
+ * @vadjustment: (allow-none): vertical adjustment
+ *
+ * Creates a new scrolling window.
+ *
+ * The two arguments are the scrolling window's adjustments; these will be
+ * shared with the scrollbars and the child widget to keep the bars in sync 
+ * with the child. Usually you want to pass %NULL for the adjustments, which 
+ * will cause the scrolling window to create them for you.
+ *
+ * Returns: a new scrolling window
+ */
+GtkWidget*
+gtk_scrolling_window_new (GtkAdjustment *hadjustment,
+                         GtkAdjustment *vadjustment)
+{
+  GtkWidget *scrolling_window;
+
+  if (hadjustment)
+    g_return_val_if_fail (GTK_IS_ADJUSTMENT (hadjustment), NULL);
+
+  if (vadjustment)
+    g_return_val_if_fail (GTK_IS_ADJUSTMENT (vadjustment), NULL);
+
+  scrolling_window = g_object_new (GTK_TYPE_SCROLLING_WINDOW,
+                                  "hadjustment", hadjustment,
+                                  "vadjustment", vadjustment,
+                                  NULL);
+
+  return scrolling_window;
+}
+
+extern gboolean ubuntu_overlay_scrollbar_get_enabled (void);
+
+static gint
+gtk_scrolled_window_get_scrollbar_spacing (GtkScrolledWindow *scrolled_window)
+{
+  GtkScrolledWindowClass *class;
+    
+  g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window), 0);
+
+  if (ubuntu_overlay_scrollbar_get_enabled ())
+    return 0;
+
+  class = GTK_SCROLLED_WINDOW_GET_CLASS (scrolled_window);
+
+  if (class->scrollbar_spacing >= 0)
+    return class->scrollbar_spacing;
+  else
+    {
+      gint scrollbar_spacing;
+      
+      gtk_widget_style_get (GTK_WIDGET (scrolled_window),
+                           "scrollbar-spacing", &scrollbar_spacing,
+                           NULL);
+
+      return scrollbar_spacing;
+    }
+}
+
+static void
+gtk_scrolling_window_get_preferred_size (GtkWidget      *widget,
+                                        GtkOrientation  orientation,
+                                        gint           *minimum_size,
+                                        gint           *natural_size)
+{
+  GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
+  GtkScrolledWindowPrivate *priv = scrolled_window->priv;
+  GtkBin *bin = GTK_BIN (scrolled_window);
+  gint minimum;
+  gint natural;
+  GtkWidget *child;
+
+  /* Init to child size. */
+  child = gtk_bin_get_child (bin);
+  if (child && gtk_widget_get_visible (child))
+    {
+      if (orientation == GTK_ORIENTATION_HORIZONTAL)
+         gtk_widget_get_preferred_width (child, &minimum, &natural);
+      else
+         gtk_widget_get_preferred_height (child, &minimum, &natural);
+    }
+
+  /* Add min_content_width/height. */
+  {
+    gint min_content_size = (orientation == GTK_ORIENTATION_HORIZONTAL
+                            ? priv->min_content_width
+                            : priv->min_content_height);
+    if (min_content_size >= 0)
+      {
+       minimum = MAX (minimum, min_content_size);
+       natural = MAX (natural, min_content_size);
+      }
+  }
+
+  /* Add scrollbar size. */
+  if (priv->vscrollbar_policy != GTK_POLICY_NEVER)
+    {
+      gint min, nat;
+      gint space = gtk_scrolled_window_get_scrollbar_spacing (scrolled_window);
+      if (orientation == GTK_ORIENTATION_VERTICAL)
+       gtk_widget_get_preferred_height (priv->hscrollbar, &min, &nat);
+      else
+       gtk_widget_get_preferred_width (priv->vscrollbar, &min, &nat);
+      minimum += space + min;
+      natural += space + nat;
+    }
+
+  /* Add shadow size. */
+  if (priv->shadow_type != GTK_SHADOW_NONE)
+    {
+      GtkStyleContext *context;
+      GtkStateFlags state;
+      GtkBorder padding, border;
+
+      context = gtk_widget_get_style_context (GTK_WIDGET (widget));
+      state = gtk_widget_get_state_flags (GTK_WIDGET (widget));
+
+      gtk_style_context_save (context);
+      gtk_style_context_add_class (context, GTK_STYLE_CLASS_FRAME);
+      gtk_style_context_get_padding (context, state, &padding);
+      gtk_style_context_get_border (context, state, &border);
+      gtk_style_context_restore (context);
+
+      if (orientation == GTK_ORIENTATION_VERTICAL)
+       {
+         minimum += padding.top + padding.bottom + border.top + border.bottom;
+         natural += padding.top + padding.bottom + border.top + border.bottom;
+       }
+      else
+       {
+         minimum += padding.left + padding.right + border.left + border.right;
+         natural += padding.left + padding.right + border.left + border.right;
+       }
+    }
+
+  if (minimum_size)
+    *minimum_size = minimum;
+  if (natural_size)
+    *natural_size = natural;
+}
+
+static void     
+gtk_scrolling_window_get_preferred_width (GtkWidget *widget,
+                                         gint      *minimum_size,
+                                         gint      *natural_size)
+{
+  gtk_scrolling_window_get_preferred_size (widget, GTK_ORIENTATION_HORIZONTAL, minimum_size, natural_size);
+}
+
+static void
+gtk_scrolling_window_get_preferred_height (GtkWidget *widget,
+                                          gint      *minimum_size,
+                                          gint      *natural_size)
+{  
+  gtk_scrolling_window_get_preferred_size (widget, GTK_ORIENTATION_VERTICAL, minimum_size, natural_size);
+}
+
+static void
+gtk_scrolling_window_get_preferred_height_for_width (GtkWidget *widget,
+                                                    gint       width,
+                                                    gint      *minimum_height,
+                                                    gint      *natural_height)
+{
+  g_return_if_fail (GTK_IS_WIDGET (widget));
+
+  GTK_WIDGET_GET_CLASS (widget)->get_preferred_height (widget, minimum_height, natural_height);
+}
+
+static void
+gtk_scrolling_window_get_preferred_width_for_height (GtkWidget *widget,
+                                                    gint       height,
+                                                    gint      *minimum_width,
+                                                    gint      *natural_width)
+{
+  g_return_if_fail (GTK_IS_WIDGET (widget));
+
+  GTK_WIDGET_GET_CLASS (widget)->get_preferred_width (widget, minimum_width, natural_width);
+}
diff --git a/src/gtk/gtkscrollingwindow.h b/src/gtk/gtkscrollingwindow.h
new file mode 100644 (file)
index 0000000..72fce3e
--- /dev/null
@@ -0,0 +1,27 @@
+#include <gtk/gtk.h>
+
+#define GTK_TYPE_SCROLLING_WINDOW            (gtk_scrolling_window_get_type ())
+#define GTK_SCROLLING_WINDOW(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_SCROLLING_WINDOW, GtkScrollingWindow))
+#define GTK_SCROLLING_WINDOW_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_SCROLLING_WINDOW, GtkScrollingWindowClass))
+#define GTK_IS_SCROLLING_WINDOW(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_SCROLLING_WINDOW))
+#define GTK_IS_SCROLLING_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_SCROLLING_WINDOW))
+#define GTK_SCROLLING_WINDOW_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_SCROLLING_WINDOW, GtkScrollingWindowClass))
+
+
+typedef struct _GtkScrollingWindow     GtkScrollingWindow;
+typedef struct _GtkScrollingWindowClass        GtkScrollingWindowClass;
+
+struct _GtkScrollingWindow
+{
+  GtkScrolledWindow scrolled;
+};
+
+struct _GtkScrollingWindowClass
+{
+  GtkScrolledWindowClass parent_class;
+};
+
+
+GType          gtk_scrolling_window_get_type (void) G_GNUC_CONST;
+GtkWidget*     gtk_scrolling_window_new      (GtkAdjustment     *hadjustment,
+                                             GtkAdjustment     *vadjustment);