forked from AuroraMiddleware/gtk
Hook GtkLayoutManager into GtkWidget
We delegate the size request mode, the measuring, and the allocation of a widget through a GtkLayoutManager instance, if one has been attached to the widget; otherwise, we fall back to the widget's own implementation.
This commit is contained in:
parent
24754c3259
commit
1b8595b5f2
@ -4590,6 +4590,8 @@ gtk_widget_get_first_child
|
||||
gtk_widget_get_last_child
|
||||
gtk_widget_insert_before
|
||||
gtk_widget_insert_after
|
||||
gtk_widget_set_layout_manager
|
||||
gtk_widget_get_layout_manager
|
||||
|
||||
<SUBSECTION>
|
||||
gtk_widget_get_path
|
||||
|
@ -22,12 +22,23 @@
|
||||
* @Title: GtkLayoutManager
|
||||
* @Short_description: Base class for layout manager
|
||||
*
|
||||
* ...
|
||||
* Layout managers are delegate classes that handle the preferred size
|
||||
* and the allocation of a container widget.
|
||||
*
|
||||
* You typically subclass #GtkLayoutManager if you want to implement a
|
||||
* layout policy for the children of a widget, without necessarily
|
||||
* implementing the @GtkWidgetClass.measure() and @GtkWidgetClass.size_allocate()
|
||||
* virtual functions directly.
|
||||
*
|
||||
* Each #GtkWidget can only have a #GtkLayoutManager instance associated to it
|
||||
* at any given time; it is possible, though, to replace the layout manager
|
||||
* instance using gtk_widget_set_layout_manager().
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "gtklayoutmanager.h"
|
||||
#include "gtklayoutmanagerprivate.h"
|
||||
#include "gtkwidget.h"
|
||||
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
#define LAYOUT_MANAGER_WARN_NOT_IMPLEMENTED(m,method) G_STMT_START { \
|
||||
@ -108,7 +119,7 @@ gtk_layout_manager_init (GtkLayoutManager *self)
|
||||
* @layout_manager: a #GtkLayoutManager
|
||||
* @widget: (nullable): a #GtkWidget
|
||||
*
|
||||
* ...
|
||||
* Sets a back pointer from @widget to @layout_manager.
|
||||
*/
|
||||
void
|
||||
gtk_layout_manager_set_widget (GtkLayoutManager *layout_manager,
|
||||
@ -116,22 +127,44 @@ gtk_layout_manager_set_widget (GtkLayoutManager *layout_manager,
|
||||
{
|
||||
GtkLayoutManagerPrivate *priv = gtk_layout_manager_get_instance_private (layout_manager);
|
||||
|
||||
if (widget != NULL && priv->widget != NULL)
|
||||
{
|
||||
g_critical ("The layout manager %p of type %s is already in use "
|
||||
"by widget %p '%s', and cannot be used by widget %p '%s'",
|
||||
layout_manager, G_OBJECT_TYPE_NAME (layout_manager),
|
||||
priv->widget, gtk_widget_get_name (priv->widget),
|
||||
widget, gtk_widget_get_name (widget));
|
||||
return;
|
||||
}
|
||||
|
||||
priv->widget = widget;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_layout_manager_measure:
|
||||
* @manager:
|
||||
* @widget:
|
||||
* @orientation:
|
||||
* @for_size:
|
||||
* @minimum: (out):
|
||||
* @natural: (out):
|
||||
* @minimum_baseline: (out):
|
||||
* @natural_baseline: (out):
|
||||
* @manager: a #GtkLayoutManager
|
||||
* @widget: the #GtkWidget using @manager
|
||||
* @orientation: the orientation to measure
|
||||
* @for_size: Size for the opposite of @orientation; for instance, if
|
||||
* the @orientation is %GTK_ORIENTATION_HORIZONTAL, this is the height
|
||||
* of the widget; if the @orientation is %GTK_ORIENTATION_VERTICAL, this
|
||||
* is the width of the widget. This allows to measure the height for the
|
||||
* given width, and the width for the given height. Use -1 if the size
|
||||
* is not known
|
||||
* @minimum: (out) (optional): the minimum size for the given size and
|
||||
* orientation
|
||||
* @natural: (out) (optional): the natural, or preferred size for the
|
||||
* given size and orientation
|
||||
* @minimum_baseline: (out) (optional): the baseline position for the
|
||||
* minimum size
|
||||
* @natural_baseline: (out) (optional): the baseline position for the
|
||||
* natural size
|
||||
*
|
||||
* ...
|
||||
* Measures the size of the @widget using @manager, for the
|
||||
* given @orientation and size.
|
||||
*
|
||||
* See [GtkWidget's geometry management section][geometry-management] for
|
||||
* more details.
|
||||
*/
|
||||
void
|
||||
gtk_layout_manager_measure (GtkLayoutManager *manager,
|
||||
@ -158,13 +191,15 @@ gtk_layout_manager_measure (GtkLayoutManager *manager,
|
||||
|
||||
/**
|
||||
* gtk_layout_manager_allocate:
|
||||
* @manager:
|
||||
* @widget:
|
||||
* @width:
|
||||
* @height:
|
||||
* @baseline:
|
||||
* @manager: a #GtkLayoutManager
|
||||
* @widget: the #GtkWidget using @manager
|
||||
* @width: the new width of the @widget
|
||||
* @height: the new height of the @widget
|
||||
* @baseline: the baseline position of the @widget
|
||||
*
|
||||
* ...
|
||||
* This function assigns the given @width, @height, and @baseline to
|
||||
* a @widget, and computes the position and sizes of the children of
|
||||
* the @widget using the layout management policy of @manager.
|
||||
*/
|
||||
void
|
||||
gtk_layout_manager_allocate (GtkLayoutManager *manager,
|
||||
@ -185,12 +220,12 @@ gtk_layout_manager_allocate (GtkLayoutManager *manager,
|
||||
|
||||
/**
|
||||
* gtk_layout_manager_get_request_mode:
|
||||
* @manager:
|
||||
* @widget:
|
||||
* @manager: a #GtkLayoutManager
|
||||
* @widget: the #GtkWidget using @manager
|
||||
*
|
||||
* ...
|
||||
* Retrieves the request mode of @manager.
|
||||
*
|
||||
* Returns: ...
|
||||
* Returns: a #GtkSizeRequestMode
|
||||
*/
|
||||
GtkSizeRequestMode
|
||||
gtk_layout_manager_get_request_mode (GtkLayoutManager *manager,
|
||||
@ -206,17 +241,40 @@ gtk_layout_manager_get_request_mode (GtkLayoutManager *manager,
|
||||
return klass->get_request_mode (manager, widget);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_layout_manager_get_widget:
|
||||
* @manager: a #GtkLayoutManager
|
||||
*
|
||||
* Retrieves the #GtkWidget using the given #GtkLayoutManager.
|
||||
*
|
||||
* Returns: (transfer none) (nullable): a #GtkWidget
|
||||
*/
|
||||
GtkWidget *
|
||||
gtk_layout_manager_get_widget (GtkLayoutManager *manager)
|
||||
{
|
||||
GtkLayoutManagerPrivate *priv = gtk_layout_manager_get_instance_private (manager);
|
||||
|
||||
g_return_val_if_fail (GTK_IS_LAYOUT_MANAGER (manager), NULL);
|
||||
|
||||
return priv->widget;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_layout_manager_layout_changed:
|
||||
* @manager: a #GtkLayoutManager
|
||||
*
|
||||
* ...
|
||||
* Queues a resize on the #GtkWidget using @manager, if any.
|
||||
*
|
||||
* This function should be called by subclasses of #GtkLayoutManager in
|
||||
* response to changes to their layout management policies.
|
||||
*/
|
||||
void
|
||||
gtk_layout_manager_layout_changed (GtkLayoutManager *manager)
|
||||
{
|
||||
GtkLayoutManagerPrivate *priv = gtk_layout_manager_get_instance_private (manager);
|
||||
|
||||
g_return_if_fail (GTK_IS_LAYOUT_MANAGER (manager));
|
||||
|
||||
if (priv->widget != NULL)
|
||||
gtk_widget_queue_resize (priv->widget);
|
||||
}
|
||||
|
@ -18,7 +18,8 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <gtk/gtkcontainer.h>
|
||||
#include <gtk/gtktypes.h>
|
||||
#include <gtk/gtkwidget.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
@ -88,6 +89,9 @@ GDK_AVAILABLE_IN_ALL
|
||||
GtkSizeRequestMode gtk_layout_manager_get_request_mode (GtkLayoutManager *manager,
|
||||
GtkWidget *widget);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkWidget * gtk_layout_manager_get_widget (GtkLayoutManager *manager);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_layout_manager_layout_changed (GtkLayoutManager *manager);
|
||||
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include "gtkwidgetprivate.h"
|
||||
#include "gtkcssnodeprivate.h"
|
||||
#include "gtkcssnumbervalueprivate.h"
|
||||
#include "gtklayoutmanagerprivate.h"
|
||||
|
||||
|
||||
#ifdef G_ENABLE_CONSISTENCY_CHECKS
|
||||
@ -195,45 +196,94 @@ gtk_widget_query_size_for_orientation (GtkWidget *widget,
|
||||
css_min_for_size = get_number_ceil (style, GTK_CSS_PROPERTY_MIN_WIDTH);
|
||||
}
|
||||
|
||||
if (for_size < 0)
|
||||
GtkLayoutManager *layout_manager = gtk_widget_get_layout_manager (widget);
|
||||
|
||||
if (layout_manager != NULL)
|
||||
{
|
||||
push_recursion_check (widget, orientation);
|
||||
widget_class->measure (widget, orientation, -1,
|
||||
&reported_min_size, &reported_nat_size,
|
||||
&min_baseline, &nat_baseline);
|
||||
pop_recursion_check (widget, orientation);
|
||||
if (for_size < 0)
|
||||
{
|
||||
push_recursion_check (widget, orientation);
|
||||
gtk_layout_manager_measure (layout_manager, widget,
|
||||
orientation, -1,
|
||||
&reported_min_size, &reported_nat_size,
|
||||
&min_baseline, &nat_baseline);
|
||||
pop_recursion_check (widget, orientation);
|
||||
}
|
||||
else
|
||||
{
|
||||
int adjusted_for_size;
|
||||
int minimum_for_size = 0;
|
||||
int natural_for_size = 0;
|
||||
int dummy = 0;
|
||||
|
||||
/* Pull the minimum for_size from the cache as it's needed to adjust
|
||||
* the proposed 'for_size' */
|
||||
gtk_layout_manager_measure (layout_manager, widget,
|
||||
OPPOSITE_ORIENTATION (orientation), -1,
|
||||
&minimum_for_size, &natural_for_size,
|
||||
NULL, NULL);
|
||||
|
||||
if (for_size < MAX (minimum_for_size, css_min_for_size))
|
||||
for_size = MAX (minimum_for_size, css_min_for_size);
|
||||
|
||||
adjusted_for_size = for_size;
|
||||
gtk_widget_adjust_size_allocation (widget, OPPOSITE_ORIENTATION (orientation),
|
||||
&for_size, &natural_for_size,
|
||||
&dummy, &adjusted_for_size);
|
||||
adjusted_for_size -= css_extra_for_size;
|
||||
if (adjusted_for_size < 0)
|
||||
adjusted_for_size = MAX (minimum_for_size, css_min_for_size);
|
||||
|
||||
push_recursion_check (widget, orientation);
|
||||
gtk_layout_manager_measure (layout_manager, widget,
|
||||
orientation,
|
||||
adjusted_for_size,
|
||||
&reported_min_size, &reported_nat_size,
|
||||
&min_baseline, &nat_baseline);
|
||||
pop_recursion_check (widget, orientation);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int adjusted_for_size;
|
||||
int minimum_for_size = 0;
|
||||
int natural_for_size = 0;
|
||||
int dummy = 0;
|
||||
if (for_size < 0)
|
||||
{
|
||||
push_recursion_check (widget, orientation);
|
||||
widget_class->measure (widget, orientation, -1,
|
||||
&reported_min_size, &reported_nat_size,
|
||||
&min_baseline, &nat_baseline);
|
||||
pop_recursion_check (widget, orientation);
|
||||
}
|
||||
else
|
||||
{
|
||||
int adjusted_for_size;
|
||||
int minimum_for_size = 0;
|
||||
int natural_for_size = 0;
|
||||
int dummy = 0;
|
||||
|
||||
/* Pull the minimum for_size from the cache as it's needed to adjust
|
||||
* the proposed 'for_size' */
|
||||
gtk_widget_measure (widget, OPPOSITE_ORIENTATION (orientation), -1,
|
||||
&minimum_for_size, &natural_for_size, NULL, NULL);
|
||||
/* Pull the minimum for_size from the cache as it's needed to adjust
|
||||
* the proposed 'for_size' */
|
||||
gtk_widget_measure (widget, OPPOSITE_ORIENTATION (orientation), -1,
|
||||
&minimum_for_size, &natural_for_size, NULL, NULL);
|
||||
|
||||
/* TODO: Warn if the given for_size is too small? */
|
||||
if (for_size < MAX (minimum_for_size, css_min_for_size))
|
||||
for_size = MAX (minimum_for_size, css_min_for_size);
|
||||
/* TODO: Warn if the given for_size is too small? */
|
||||
if (for_size < MAX (minimum_for_size, css_min_for_size))
|
||||
for_size = MAX (minimum_for_size, css_min_for_size);
|
||||
|
||||
adjusted_for_size = for_size;
|
||||
gtk_widget_adjust_size_allocation (widget, OPPOSITE_ORIENTATION (orientation),
|
||||
&for_size, &natural_for_size,
|
||||
&dummy, &adjusted_for_size);
|
||||
adjusted_for_size = for_size;
|
||||
gtk_widget_adjust_size_allocation (widget, OPPOSITE_ORIENTATION (orientation),
|
||||
&for_size, &natural_for_size,
|
||||
&dummy, &adjusted_for_size);
|
||||
|
||||
adjusted_for_size -= css_extra_for_size;
|
||||
|
||||
push_recursion_check (widget, orientation);
|
||||
widget_class->measure (widget,
|
||||
orientation,
|
||||
adjusted_for_size,
|
||||
&reported_min_size, &reported_nat_size,
|
||||
&min_baseline, &nat_baseline);
|
||||
pop_recursion_check (widget, orientation);
|
||||
adjusted_for_size -= css_extra_for_size;
|
||||
|
||||
push_recursion_check (widget, orientation);
|
||||
widget_class->measure (widget,
|
||||
orientation,
|
||||
adjusted_for_size,
|
||||
&reported_min_size, &reported_nat_size,
|
||||
&min_baseline, &nat_baseline);
|
||||
pop_recursion_check (widget, orientation);
|
||||
}
|
||||
}
|
||||
|
||||
min_size = MAX (0, MAX (reported_min_size, css_min_size)) + css_extra_size;
|
||||
@ -512,7 +562,13 @@ gtk_widget_get_request_mode (GtkWidget *widget)
|
||||
|
||||
if (G_UNLIKELY (!cache->request_mode_valid))
|
||||
{
|
||||
cache->request_mode = GTK_WIDGET_GET_CLASS (widget)->get_request_mode (widget);
|
||||
GtkLayoutManager *layout_manager = gtk_widget_get_layout_manager (widget);
|
||||
|
||||
if (layout_manager != NULL)
|
||||
cache->request_mode = gtk_layout_manager_get_request_mode (layout_manager, widget);
|
||||
else
|
||||
cache->request_mode = GTK_WIDGET_GET_CLASS (widget)->get_request_mode (widget);
|
||||
|
||||
cache->request_mode_valid = TRUE;
|
||||
}
|
||||
|
||||
|
@ -38,6 +38,7 @@ typedef struct _GtkBuilder GtkBuilder;
|
||||
typedef struct _GtkClipboard GtkClipboard;
|
||||
typedef struct _GtkEventController GtkEventController;
|
||||
typedef struct _GtkGesture GtkGesture;
|
||||
typedef struct _GtkLayoutManager GtkLayoutManager;
|
||||
typedef struct _GtkRequisition GtkRequisition;
|
||||
typedef struct _GtkRoot GtkRoot;
|
||||
typedef struct _GtkSelectionData GtkSelectionData;
|
||||
|
@ -48,6 +48,7 @@
|
||||
#include "gtkgesturesingle.h"
|
||||
#include "gtkgestureswipe.h"
|
||||
#include "gtkintl.h"
|
||||
#include "gtklayoutmanagerprivate.h"
|
||||
#include "gtkmain.h"
|
||||
#include "gtkmarshalers.h"
|
||||
#include "gtkmenu.h"
|
||||
@ -4346,16 +4347,26 @@ gtk_widget_allocate (GtkWidget *widget,
|
||||
priv->height = adjusted.height;
|
||||
priv->baseline = baseline;
|
||||
|
||||
if (g_signal_has_handler_pending (widget, widget_signals[SIZE_ALLOCATE], 0, FALSE))
|
||||
g_signal_emit (widget, widget_signals[SIZE_ALLOCATE], 0,
|
||||
priv->width,
|
||||
priv->height,
|
||||
baseline);
|
||||
if (priv->layout_manager != NULL)
|
||||
{
|
||||
gtk_layout_manager_allocate (priv->layout_manager, widget,
|
||||
priv->width,
|
||||
priv->priv->height,
|
||||
baseline);
|
||||
}
|
||||
else
|
||||
GTK_WIDGET_GET_CLASS (widget)->size_allocate (widget,
|
||||
priv->width,
|
||||
priv->height,
|
||||
baseline);
|
||||
{
|
||||
if (g_signal_has_handler_pending (widget, widget_signals[SIZE_ALLOCATE], 0, FALSE))
|
||||
g_signal_emit (widget, widget_signals[SIZE_ALLOCATE], 0,
|
||||
priv->width,
|
||||
priv->height,
|
||||
baseline);
|
||||
else
|
||||
GTK_WIDGET_GET_CLASS (widget)->size_allocate (widget,
|
||||
priv->width,
|
||||
priv->height,
|
||||
baseline);
|
||||
}
|
||||
|
||||
/* Size allocation is god... after consulting god, no further requests or allocations are needed */
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
@ -8041,6 +8052,9 @@ gtk_widget_dispose (GObject *object)
|
||||
while (priv->paintables)
|
||||
gtk_widget_paintable_set_widget (priv->paintables->data, NULL);
|
||||
|
||||
gtk_widget_set_layout_manager (widget, NULL);
|
||||
g_clear_object (&priv->layout_manager);
|
||||
|
||||
priv->visible = FALSE;
|
||||
if (_gtk_widget_get_realized (widget))
|
||||
gtk_widget_unrealize (widget);
|
||||
@ -13361,3 +13375,50 @@ gtk_widget_get_height (GtkWidget *widget)
|
||||
|
||||
return priv->height;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_widget_set_layout_manager:
|
||||
* @widget: a #GtkWidget
|
||||
* @layout_manager: (nullable) (transfer full): a #GtkLayoutManager
|
||||
*
|
||||
* Sets the layout manager delegate instance that provides an implementation
|
||||
* for measuring and allocating the children of @widget.
|
||||
*
|
||||
* The @widget acquires a reference to the given @layout_manager.
|
||||
*/
|
||||
void
|
||||
gtk_widget_set_layout_manager (GtkWidget *widget,
|
||||
GtkLayoutManager *layout_manager)
|
||||
{
|
||||
GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget);
|
||||
|
||||
g_return_if_fail (GTK_IS_WIDGET (widget));
|
||||
g_return_if_fail (layout_manager == NULL || GTK_IS_LAYOUT_MANAGER (layout_manager));
|
||||
g_return_if_fail (layout_manager == NULL || gtk_layout_manager_get_widget (layout_manager) == NULL);
|
||||
|
||||
if (g_set_object (&priv->layout_manager, layout_manager))
|
||||
{
|
||||
if (priv->layout_manager != NULL)
|
||||
gtk_layout_manager_set_widget (priv->layout_manager, widget);
|
||||
|
||||
gtk_widget_queue_resize (widget);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_widget_get_layout_manager:
|
||||
* @widget: a #GtkWidget
|
||||
*
|
||||
* Retrieves the layout manager set using gtk_widget_set_layout_manager().
|
||||
*
|
||||
* Returns: (transfer none) (nullable): a #GtkLayoutManager
|
||||
*/
|
||||
GtkLayoutManager *
|
||||
gtk_widget_get_layout_manager (GtkWidget *widget)
|
||||
{
|
||||
GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget);
|
||||
|
||||
g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
|
||||
|
||||
return priv->layout_manager;
|
||||
}
|
||||
|
@ -424,6 +424,12 @@ void gtk_widget_get_preferred_size (GtkWidget *w
|
||||
GtkRequisition *minimum_size,
|
||||
GtkRequisition *natural_size);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_widget_set_layout_manager (GtkWidget *widget,
|
||||
GtkLayoutManager *layout_manager);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkLayoutManager * gtk_widget_get_layout_manager (GtkWidget *widget);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_widget_add_accelerator (GtkWidget *widget,
|
||||
const gchar *accel_signal,
|
||||
|
@ -160,6 +160,9 @@ struct _GtkWidgetPrivate
|
||||
/* The render node we draw or %NULL if not yet created.*/
|
||||
GskRenderNode *render_node;
|
||||
|
||||
/* The layout manager, or %NULL */
|
||||
GtkLayoutManager *layout_manager;
|
||||
|
||||
GSList *paintables;
|
||||
|
||||
/* The widget's surface or its parent surface if it does
|
||||
|
Loading…
Reference in New Issue
Block a user