scrolledwindow: Derive from GtkWidget

We want to remove GtkBin and GtkContainer as they don't
provide much useful functionality anymore. This requires
us to move get_request_mode and compute_expand down.

We have to implement GtkBuildable, in order to keep
the <child> element in ui files working for aspect
frames.

See #2681
This commit is contained in:
Matthias Clasen 2020-05-02 01:48:52 -04:00
parent 67759d4c3e
commit 9d7b77f874
3 changed files with 159 additions and 146 deletions

View File

@ -21,7 +21,7 @@
#include "gtkscrolledwindowaccessible.h"
G_DEFINE_TYPE (GtkScrolledWindowAccessible, gtk_scrolled_window_accessible, GTK_TYPE_CONTAINER_ACCESSIBLE)
G_DEFINE_TYPE (GtkScrolledWindowAccessible, gtk_scrolled_window_accessible, GTK_TYPE_WIDGET_ACCESSIBLE)
static void
visibility_changed (GObject *object,
@ -33,7 +33,6 @@ visibility_changed (GObject *object,
gint index;
gint n_children;
gboolean child_added = FALSE;
GList *children;
AtkObject *child;
GtkWidget *widget;
GtkScrolledWindow *scrolled_window;
@ -45,9 +44,7 @@ visibility_changed (GObject *object,
return;
scrolled_window = GTK_SCROLLED_WINDOW (widget);
children = gtk_container_get_children (GTK_CONTAINER (widget));
index = n_children = g_list_length (children);
g_list_free (children);
index = n_children = 1;
hscrollbar = gtk_scrolled_window_get_hscrollbar (scrolled_window);
vscrollbar = gtk_scrolled_window_get_vscrollbar (scrolled_window);

View File

@ -28,6 +28,7 @@
#include "gtkadjustment.h"
#include "gtkadjustmentprivate.h"
#include "gtkbuildable.h"
#include "gtkeventcontrollermotion.h"
#include "gtkeventcontrollerscroll.h"
#include "gtkeventcontrollerprivate.h"
@ -202,12 +203,12 @@ typedef struct _GtkScrolledWindowClass GtkScrolledWindowClass;
struct _GtkScrolledWindow
{
GtkBin parent_instance;
GtkWidget parent_instance;
};
struct _GtkScrolledWindowClass
{
GtkBinClass parent_class;
GtkWidgetClass parent_class;
/* Unfortunately, GtkScrollType is deficient in that there is
* no horizontal/vertical variants for GTK_SCROLL_START/END,
@ -238,6 +239,8 @@ typedef struct
typedef struct
{
GtkWidget *child;
GtkWidget *hscrollbar;
GtkWidget *vscrollbar;
@ -349,10 +352,6 @@ static void gtk_scrolled_window_size_allocate (GtkWidget *widge
int baseline);
static gboolean gtk_scrolled_window_focus (GtkWidget *widget,
GtkDirectionType direction);
static void gtk_scrolled_window_add (GtkContainer *container,
GtkWidget *widget);
static void gtk_scrolled_window_remove (GtkContainer *container,
GtkWidget *widget);
static gboolean gtk_scrolled_window_scroll_child (GtkScrolledWindow *scrolled_window,
GtkScrollType scroll,
gboolean horizontal);
@ -412,7 +411,34 @@ static void uninstall_scroll_cursor (GtkScrolledWindow *scrolled_window);
static guint signals[LAST_SIGNAL] = {0};
static GParamSpec *properties[NUM_PROPERTIES];
G_DEFINE_TYPE_WITH_PRIVATE (GtkScrolledWindow, gtk_scrolled_window, GTK_TYPE_BIN)
static void gtk_scrolled_window_buildable_init (GtkBuildableIface *iface);
G_DEFINE_TYPE_WITH_CODE (GtkScrolledWindow, gtk_scrolled_window, GTK_TYPE_WIDGET,
G_ADD_PRIVATE (GtkScrolledWindow)
G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
gtk_scrolled_window_buildable_init))
static GtkBuildableIface *parent_buildable_iface;
static void
gtk_scrolled_window_buildable_add_child (GtkBuildable *buildable,
GtkBuilder *builder,
GObject *child,
const gchar *type)
{
if (GTK_IS_WIDGET (child))
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW(buildable), GTK_WIDGET (child));
else
parent_buildable_iface->add_child (buildable, builder, child, type);
}
static void
gtk_scrolled_window_buildable_init (GtkBuildableIface *iface)
{
parent_buildable_iface = g_type_interface_peek_parent (iface);
iface->add_child = gtk_scrolled_window_buildable_add_child;
}
static void
add_scroll_binding (GtkWidgetClass *widget_class,
@ -515,12 +541,43 @@ gtk_scrolled_window_direction_changed (GtkWidget *widget,
GTK_WIDGET_CLASS (gtk_scrolled_window_parent_class)->direction_changed (widget, previous_dir);
}
static void
gtk_scrolled_window_compute_expand (GtkWidget *widget,
gboolean *hexpand,
gboolean *vexpand)
{
GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
GtkScrolledWindowPrivate *priv = gtk_scrolled_window_get_instance_private (scrolled_window);
if (priv->child)
{
*hexpand = gtk_widget_compute_expand (priv->child, GTK_ORIENTATION_HORIZONTAL);
*vexpand = gtk_widget_compute_expand (priv->child, GTK_ORIENTATION_VERTICAL);
}
else
{
*hexpand = FALSE;
*vexpand = FALSE;
}
}
static GtkSizeRequestMode
gtk_scrolled_window_get_request_mode (GtkWidget *widget)
{
GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
GtkScrolledWindowPrivate *priv = gtk_scrolled_window_get_instance_private (scrolled_window);
if (priv->child)
return gtk_widget_get_request_mode (priv->child);
else
return GTK_SIZE_REQUEST_CONSTANT_SIZE;
}
static void
gtk_scrolled_window_class_init (GtkScrolledWindowClass *class)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (class);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
GtkContainerClass *container_class = GTK_CONTAINER_CLASS (class);
gobject_class->set_property = gtk_scrolled_window_set_property;
gobject_class->get_property = gtk_scrolled_window_get_property;
@ -535,9 +592,8 @@ gtk_scrolled_window_class_init (GtkScrolledWindowClass *class)
widget_class->unmap = gtk_scrolled_window_unmap;
widget_class->realize = gtk_scrolled_window_realize;
widget_class->direction_changed = gtk_scrolled_window_direction_changed;
container_class->add = gtk_scrolled_window_add;
container_class->remove = gtk_scrolled_window_remove;
widget_class->compute_expand = gtk_scrolled_window_compute_expand;
widget_class->get_request_mode = gtk_scrolled_window_get_request_mode;
class->scroll_child = gtk_scrolled_window_scroll_child;
class->move_focus_out = gtk_scrolled_window_move_focus_out;
@ -1409,7 +1465,6 @@ gtk_scrolled_window_size_allocate (GtkWidget *widget,
GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
GtkScrolledWindowPrivate *priv = gtk_scrolled_window_get_instance_private (scrolled_window);
GtkAllocation child_allocation;
GtkWidget *child;
gint sb_width;
gint sb_height;
@ -1431,26 +1486,25 @@ gtk_scrolled_window_size_allocate (GtkWidget *widget,
priv->vscrollbar_policy == GTK_POLICY_EXTERNAL)
priv->vscrollbar_visible = FALSE;
child = gtk_bin_get_child (GTK_BIN (scrolled_window));
if (child && gtk_widget_get_visible (child))
if (priv->child && gtk_widget_get_visible (priv->child))
{
gint child_scroll_width;
gint child_scroll_height;
gboolean previous_hvis;
gboolean previous_vvis;
guint count = 0;
GtkScrollable *scrollable_child = GTK_SCROLLABLE (child);
GtkScrollable *scrollable_child = GTK_SCROLLABLE (priv->child);
GtkScrollablePolicy hscroll_policy = gtk_scrollable_get_hscroll_policy (scrollable_child);
GtkScrollablePolicy vscroll_policy = gtk_scrollable_get_vscroll_policy (scrollable_child);
/* Determine scrollbar visibility first via hfw apis */
if (gtk_widget_get_request_mode (child) == GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH)
if (gtk_widget_get_request_mode (priv->child) == GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH)
{
if (hscroll_policy == GTK_SCROLL_MINIMUM)
gtk_widget_measure (child, GTK_ORIENTATION_HORIZONTAL, -1,
gtk_widget_measure (priv->child, GTK_ORIENTATION_HORIZONTAL, -1,
&child_scroll_width, NULL, NULL, NULL);
else
gtk_widget_measure (child, GTK_ORIENTATION_HORIZONTAL, -1,
gtk_widget_measure (priv->child, GTK_ORIENTATION_HORIZONTAL, -1,
NULL, &child_scroll_width, NULL, NULL);
if (priv->vscrollbar_policy == GTK_POLICY_AUTOMATIC)
@ -1458,11 +1512,11 @@ gtk_scrolled_window_size_allocate (GtkWidget *widget,
/* First try without a vertical scrollbar if the content will fit the height
* given the extra width of the scrollbar */
if (vscroll_policy == GTK_SCROLL_MINIMUM)
gtk_widget_measure (child, GTK_ORIENTATION_VERTICAL,
gtk_widget_measure (priv->child, GTK_ORIENTATION_VERTICAL,
MAX (width, child_scroll_width),
&child_scroll_height, NULL, NULL, NULL);
else
gtk_widget_measure (child, GTK_ORIENTATION_VERTICAL,
gtk_widget_measure (priv->child, GTK_ORIENTATION_VERTICAL,
MAX (width, child_scroll_width),
NULL, &child_scroll_height, NULL, NULL);
@ -1508,10 +1562,10 @@ gtk_scrolled_window_size_allocate (GtkWidget *widget,
else /* GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT */
{
if (vscroll_policy == GTK_SCROLL_MINIMUM)
gtk_widget_measure (child, GTK_ORIENTATION_VERTICAL, -1,
gtk_widget_measure (priv->child, GTK_ORIENTATION_VERTICAL, -1,
&child_scroll_height, NULL, NULL, NULL);
else
gtk_widget_measure (child, GTK_ORIENTATION_VERTICAL, -1,
gtk_widget_measure (priv->child, GTK_ORIENTATION_VERTICAL, -1,
NULL, &child_scroll_height, NULL, NULL);
if (priv->hscrollbar_policy == GTK_POLICY_AUTOMATIC)
@ -1519,11 +1573,11 @@ gtk_scrolled_window_size_allocate (GtkWidget *widget,
/* First try without a horizontal scrollbar if the content will fit the width
* given the extra height of the scrollbar */
if (hscroll_policy == GTK_SCROLL_MINIMUM)
gtk_widget_measure (child, GTK_ORIENTATION_HORIZONTAL,
gtk_widget_measure (priv->child, GTK_ORIENTATION_HORIZONTAL,
MAX (height, child_scroll_height),
&child_scroll_width, NULL, NULL, NULL);
else
gtk_widget_measure (child, GTK_ORIENTATION_HORIZONTAL,
gtk_widget_measure (priv->child, GTK_ORIENTATION_HORIZONTAL,
MAX (height, child_scroll_height),
NULL, &child_scroll_width, NULL, NULL);
@ -1652,22 +1706,19 @@ gtk_scrolled_window_measure (GtkWidget *widget,
GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
GtkScrolledWindowPrivate *priv = gtk_scrolled_window_get_instance_private (scrolled_window);
int minimum_req = 0, natural_req = 0;
GtkWidget *child;
GtkBorder sborder = { 0 };
child = gtk_bin_get_child (GTK_BIN (scrolled_window));
if (child)
gtk_scrollable_get_border (GTK_SCROLLABLE (child), &sborder);
if (priv->child)
gtk_scrollable_get_border (GTK_SCROLLABLE (priv->child), &sborder);
/*
* First collect the child requisition
*/
if (child && gtk_widget_get_visible (child))
if (priv->child && gtk_widget_get_visible (priv->child))
{
int min_child_size, nat_child_size;
gtk_widget_measure (child, orientation, -1,
gtk_widget_measure (priv->child, orientation, -1,
&min_child_size, &nat_child_size,
NULL, NULL);
@ -2070,7 +2121,6 @@ gtk_scrolled_window_set_hadjustment (GtkScrolledWindow *scrolled_window,
GtkAdjustment *hadjustment)
{
GtkScrolledWindowPrivate *priv = gtk_scrolled_window_get_instance_private (scrolled_window);
GtkWidget *child;
g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
@ -2119,9 +2169,8 @@ gtk_scrolled_window_set_hadjustment (GtkScrolledWindow *scrolled_window,
gtk_scrolled_window_adjustment_changed (hadjustment, scrolled_window);
gtk_scrolled_window_adjustment_value_changed (hadjustment, scrolled_window);
child = gtk_bin_get_child (GTK_BIN (scrolled_window));
if (child)
gtk_scrollable_set_hadjustment (GTK_SCROLLABLE (child), hadjustment);
if (priv->child)
gtk_scrollable_set_hadjustment (GTK_SCROLLABLE (priv->child), hadjustment);
if (gtk_widget_should_animate (GTK_WIDGET (scrolled_window)))
gtk_adjustment_enable_animation (hadjustment, gtk_widget_get_frame_clock (GTK_WIDGET (scrolled_window)), ANIMATION_DURATION);
@ -2141,7 +2190,6 @@ gtk_scrolled_window_set_vadjustment (GtkScrolledWindow *scrolled_window,
GtkAdjustment *vadjustment)
{
GtkScrolledWindowPrivate *priv = gtk_scrolled_window_get_instance_private (scrolled_window);
GtkWidget *child;
g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
@ -2190,9 +2238,8 @@ gtk_scrolled_window_set_vadjustment (GtkScrolledWindow *scrolled_window,
gtk_scrolled_window_adjustment_changed (vadjustment, scrolled_window);
gtk_scrolled_window_adjustment_value_changed (vadjustment, scrolled_window);
child = gtk_bin_get_child (GTK_BIN (scrolled_window));
if (child)
gtk_scrollable_set_vadjustment (GTK_SCROLLABLE (child), vadjustment);
if (priv->child)
gtk_scrollable_set_vadjustment (GTK_SCROLLABLE (priv->child), vadjustment);
if (gtk_widget_should_animate (GTK_WIDGET (scrolled_window)))
gtk_adjustment_enable_animation (vadjustment, gtk_widget_get_frame_clock (GTK_WIDGET (scrolled_window)), ANIMATION_DURATION);
@ -2569,14 +2616,8 @@ gtk_scrolled_window_dispose (GObject *object)
{
GtkScrolledWindow *self = GTK_SCROLLED_WINDOW (object);
GtkScrolledWindowPrivate *priv = gtk_scrolled_window_get_instance_private (self);
GtkWidget *child;
child = gtk_bin_get_child (GTK_BIN (self));
if (child)
{
gtk_widget_unparent (child);
_gtk_bin_set_child (GTK_BIN (self), NULL);
}
g_clear_pointer (&priv->child, gtk_widget_unparent);
remove_indicator (self, &priv->hindicator);
remove_indicator (self, &priv->vindicator);
@ -2764,14 +2805,13 @@ static void
gtk_scrolled_window_inner_allocation (GtkScrolledWindow *scrolled_window,
GtkAllocation *rect)
{
GtkWidget *child;
GtkScrolledWindowPrivate *priv = gtk_scrolled_window_get_instance_private (scrolled_window);
GtkBorder border = { 0 };
gtk_scrolled_window_relative_allocation (scrolled_window, rect);
rect->x = 0;
rect->y = 0;
child = gtk_bin_get_child (GTK_BIN (scrolled_window));
if (child && gtk_scrollable_get_border (GTK_SCROLLABLE (child), &border))
if (priv->child && gtk_scrollable_get_border (GTK_SCROLLABLE (priv->child), &border))
{
rect->x += border.left;
rect->y += border.top;
@ -3044,13 +3084,11 @@ gtk_scrolled_window_allocate_child (GtkScrolledWindow *swindow,
int height)
{
GtkScrolledWindowPrivate *priv = gtk_scrolled_window_get_instance_private (swindow);
GtkWidget *widget = GTK_WIDGET (swindow), *child;
GtkAllocation child_allocation;
GtkWidget *widget = GTK_WIDGET (swindow);
GtkAllocation child_allocation;
int sb_width;
int sb_height;
child = gtk_bin_get_child (GTK_BIN (widget));
child_allocation = (GtkAllocation) {0, 0, width, height};
/* Get possible scrollbar dimensions */
@ -3087,7 +3125,7 @@ gtk_scrolled_window_allocate_child (GtkScrolledWindow *swindow,
child_allocation.height = MAX (1, child_allocation.height - sb_height);
}
gtk_widget_size_allocate (child, &child_allocation, -1);
gtk_widget_size_allocate (priv->child, &child_allocation, -1);
}
static void
@ -3360,7 +3398,6 @@ gtk_scrolled_window_focus (GtkWidget *widget,
{
GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
GtkScrolledWindowPrivate *priv = gtk_scrolled_window_get_instance_private (scrolled_window);
GtkWidget *child;
gboolean had_focus_child;
had_focus_child = gtk_widget_get_focus_child (widget) != NULL;
@ -3377,10 +3414,9 @@ gtk_scrolled_window_focus (GtkWidget *widget,
/* We only put the scrolled window itself in the focus chain if it
* isn't possible to focus any children.
*/
child = gtk_bin_get_child (GTK_BIN (widget));
if (child)
if (priv->child)
{
if (gtk_widget_child_focus (child, direction))
if (gtk_widget_child_focus (priv->child, direction))
return TRUE;
}
@ -3483,86 +3519,6 @@ gtk_scrolled_window_adjustment_value_changed (GtkAdjustment *adjustment,
priv->unclamped_vadj_value = gtk_adjustment_get_value (adjustment);
}
static void
gtk_scrolled_window_add (GtkContainer *container,
GtkWidget *child)
{
GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (container);
GtkScrolledWindowPrivate *priv = gtk_scrolled_window_get_instance_private (scrolled_window);
GtkBin *bin;
GtkWidget *scrollable_child;
GtkAdjustment *hadj, *vadj;
bin = GTK_BIN (container);
g_return_if_fail (gtk_bin_get_child (bin) == NULL);
/* gtk_scrolled_window_set_[hv]adjustment have the side-effect
* of creating the scrollbars
*/
if (!priv->hscrollbar)
gtk_scrolled_window_set_hadjustment (scrolled_window, NULL);
if (!priv->vscrollbar)
gtk_scrolled_window_set_vadjustment (scrolled_window, NULL);
hadj = gtk_scrollbar_get_adjustment (GTK_SCROLLBAR (priv->hscrollbar));
vadj = gtk_scrollbar_get_adjustment (GTK_SCROLLBAR (priv->vscrollbar));
if (GTK_IS_SCROLLABLE (child))
{
scrollable_child = child;
}
else
{
scrollable_child = gtk_viewport_new (hadj, vadj);
gtk_viewport_set_child (GTK_VIEWPORT (scrollable_child), child);
priv->auto_added_viewport = TRUE;
}
_gtk_bin_set_child (bin, scrollable_child);
gtk_widget_insert_after (scrollable_child, GTK_WIDGET (bin), NULL);
g_object_set (scrollable_child, "hadjustment", hadj, "vadjustment", vadj, NULL);
}
static void
gtk_scrolled_window_remove (GtkContainer *container,
GtkWidget *child)
{
GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (container);
GtkScrolledWindowPrivate *priv = gtk_scrolled_window_get_instance_private (scrolled_window);
GtkWidget *scrollable_child;
if (!priv->auto_added_viewport)
{
scrollable_child = child;
}
else
{
scrollable_child = gtk_bin_get_child (GTK_BIN (container));
if (scrollable_child == child)
{
/* @child is the automatically added viewport. */
GtkWidget *grandchild = gtk_bin_get_child (GTK_BIN (child));
/* Remove the viewport's child, if any. */
if (grandchild)
gtk_container_remove (GTK_CONTAINER (child), grandchild);
}
else
{
/* @child is (assumed to be) the viewport's child. */
gtk_container_remove (GTK_CONTAINER (scrollable_child), child);
}
}
g_object_set (scrollable_child, "hadjustment", NULL, "vadjustment", NULL, NULL);
GTK_CONTAINER_CLASS (gtk_scrolled_window_parent_class)->remove (container, scrollable_child);
priv->auto_added_viewport = FALSE;
}
static gboolean
gtk_widget_should_animate (GtkWidget *widget)
{
@ -4197,9 +4153,67 @@ void
gtk_scrolled_window_set_child (GtkScrolledWindow *scrolled_window,
GtkWidget *child)
{
GtkScrolledWindowPrivate *priv = gtk_scrolled_window_get_instance_private (scrolled_window);
GtkWidget *scrollable_child;
g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
_gtk_bin_set_child (GTK_BIN (scrolled_window), child);
if (priv->child)
{
if (!priv->auto_added_viewport)
{
scrollable_child = priv->child;
}
else
{
scrollable_child = gtk_viewport_get_child (GTK_VIEWPORT (priv->child));
gtk_viewport_set_child (GTK_VIEWPORT (priv->child), NULL);
}
g_object_set (scrollable_child,
"hadjustment", NULL,
"vadjustment", NULL,
NULL);
g_clear_pointer (&priv->child, gtk_widget_unparent);
}
if (child)
{
GtkAdjustment *hadj, *vadj;
/* gtk_scrolled_window_set_[hv]adjustment have the side-effect
* of creating the scrollbars
*/
if (!priv->hscrollbar)
gtk_scrolled_window_set_hadjustment (scrolled_window, NULL);
if (!priv->vscrollbar)
gtk_scrolled_window_set_vadjustment (scrolled_window, NULL);
hadj = gtk_scrollbar_get_adjustment (GTK_SCROLLBAR (priv->hscrollbar));
vadj = gtk_scrollbar_get_adjustment (GTK_SCROLLBAR (priv->vscrollbar));
if (GTK_IS_SCROLLABLE (child))
{
scrollable_child = child;
priv->auto_added_viewport = FALSE;
}
else
{
scrollable_child = gtk_viewport_new (hadj, vadj);
gtk_viewport_set_child (GTK_VIEWPORT (scrollable_child), child);
priv->auto_added_viewport = TRUE;
}
priv->child = scrollable_child;
gtk_widget_set_parent (scrollable_child, GTK_WIDGET (scrolled_window));
g_object_set (scrollable_child,
"hadjustment", hadj,
"vadjustment", vadj,
NULL);
}
g_object_notify_by_pspec (G_OBJECT (scrolled_window), properties[PROP_CHILD]);
}
@ -4214,7 +4228,9 @@ gtk_scrolled_window_set_child (GtkScrolledWindow *scrolled_window,
GtkWidget *
gtk_scrolled_window_get_child (GtkScrolledWindow *scrolled_window)
{
GtkScrolledWindowPrivate *priv = gtk_scrolled_window_get_instance_private (scrolled_window);
g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window), NULL);
return gtk_bin_get_child (GTK_BIN (scrolled_window));
return priv->child;
}

View File

@ -29,7 +29,7 @@
#error "Only <gtk/gtk.h> can be included directly."
#endif
#include <gtk/gtkbin.h>
#include <gtk/gtkwidget.h>
G_BEGIN_DECLS