forked from AuroraMiddleware/gtk
Add GtkLayoutChild
Layout managers needs a way to store properties that control the layout policy of a widget; typically, we used to store these in GtkContainer's child properties, but since GtkLayoutManager is decoupled from the actual container widget, we need a separate storage. Additionally, child properties have their own downsides, like requiring a separate, global GParamSpecPool storage, and additional lookup API. GtkLayoutChild is a simple GObject class, which means you can introspect and document it as you would any other type.
This commit is contained in:
parent
15fda18791
commit
5cbf6f5fbd
@ -7164,9 +7164,23 @@ gtk_layout_manager_measure
|
||||
gtk_layout_manager_allocate
|
||||
gtk_layout_manager_get_request_mode
|
||||
gtk_layout_manager_get_widget
|
||||
gtk_layout_manager_get_layout_child
|
||||
gtk_layout_manager_layout_changed
|
||||
|
||||
<SUBSECTION Standard>
|
||||
GTK_TYPE_LAYOUT_MANAGER
|
||||
gtk_layout_manager_get_type
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>gtklayoutchild</FILE>
|
||||
GtkLayoutChild
|
||||
GtkLayoutChildClass
|
||||
|
||||
gtk_layout_child_get_layout_manager
|
||||
gtk_layout_child_get_child_widget
|
||||
|
||||
<SUBSECTION Standard>
|
||||
GTK_TYPE_LAYOUT_CHILD
|
||||
gtk_layout_child_get_type
|
||||
</SECTION>
|
||||
|
@ -135,6 +135,7 @@
|
||||
#include <gtk/gtklabel.h>
|
||||
#include <gtk/gtklayout.h>
|
||||
#include <gtk/gtklayoutmanager.h>
|
||||
#include <gtk/gtklayoutchild.h>
|
||||
#include <gtk/gtklevelbar.h>
|
||||
#include <gtk/gtklinkbutton.h>
|
||||
#include <gtk/gtklistbox.h>
|
||||
|
189
gtk/gtklayoutchild.c
Normal file
189
gtk/gtklayoutchild.c
Normal file
@ -0,0 +1,189 @@
|
||||
#include "config.h"
|
||||
|
||||
#include "gtklayoutchild.h"
|
||||
|
||||
#include "gtklayoutmanager.h"
|
||||
#include "gtkprivate.h"
|
||||
|
||||
/**
|
||||
* SECTION:gtklayoutchild
|
||||
* @Title: GtkLayoutChild
|
||||
* @Short_description: An object containing layout properties
|
||||
*
|
||||
* #GtkLayoutChild is the base class for objects that are meant to hold
|
||||
* layout properties. If a #GtkLayoutManager has per-child properties,
|
||||
* like their packing type, or the horizontal and vertical span, or the
|
||||
* icon name, then the layout manager should use a #GtkLayoutChild
|
||||
* implementation to store those properties.
|
||||
*
|
||||
* A #GtkLayoutChild instance is only ever valid while a widget is part
|
||||
* of a layout.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
GtkLayoutManager *manager;
|
||||
GtkWidget *widget;
|
||||
} GtkLayoutChildPrivate;
|
||||
|
||||
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GtkLayoutChild, gtk_layout_child, G_TYPE_OBJECT)
|
||||
|
||||
enum {
|
||||
PROP_LAYOUT_MANAGER = 1,
|
||||
PROP_CHILD_WIDGET,
|
||||
|
||||
N_PROPS
|
||||
};
|
||||
|
||||
static GParamSpec *layout_child_properties[N_PROPS];
|
||||
|
||||
static void
|
||||
gtk_layout_child_set_property (GObject *gobject,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GtkLayoutChild *layout_child = GTK_LAYOUT_CHILD (gobject);
|
||||
GtkLayoutChildPrivate *priv = gtk_layout_child_get_instance_private (layout_child);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_LAYOUT_MANAGER:
|
||||
priv->manager = g_value_get_object (value);
|
||||
break;
|
||||
|
||||
case PROP_CHILD_WIDGET:
|
||||
priv->widget = g_value_get_object (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_layout_child_get_property (GObject *gobject,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GtkLayoutChild *layout_child = GTK_LAYOUT_CHILD (gobject);
|
||||
GtkLayoutChildPrivate *priv = gtk_layout_child_get_instance_private (layout_child);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_LAYOUT_MANAGER:
|
||||
g_value_set_object (value, priv->manager);
|
||||
break;
|
||||
|
||||
case PROP_CHILD_WIDGET:
|
||||
g_value_set_object (value, priv->widget);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_layout_child_constructed (GObject *gobject)
|
||||
{
|
||||
GtkLayoutChild *layout_child = GTK_LAYOUT_CHILD (gobject);
|
||||
GtkLayoutChildPrivate *priv = gtk_layout_child_get_instance_private (layout_child);
|
||||
|
||||
G_OBJECT_CLASS (gtk_layout_child_parent_class)->constructed (gobject);
|
||||
|
||||
if (priv->manager == NULL)
|
||||
{
|
||||
g_critical ("The layout child of type %s does not have "
|
||||
"the GtkLayoutChild:layout-manager property set",
|
||||
G_OBJECT_TYPE_NAME (gobject));
|
||||
return;
|
||||
}
|
||||
|
||||
if (priv->widget == NULL)
|
||||
{
|
||||
g_critical ("The layout child of type %s does not have "
|
||||
"the GtkLayoutChild:child-widget property set",
|
||||
G_OBJECT_TYPE_NAME (gobject));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_layout_child_class_init (GtkLayoutChildClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
gobject_class->set_property = gtk_layout_child_set_property;
|
||||
gobject_class->get_property = gtk_layout_child_get_property;
|
||||
gobject_class->constructed = gtk_layout_child_constructed;
|
||||
|
||||
/**
|
||||
* GtkLayoutChild:layout-manager:
|
||||
*
|
||||
* The layout manager that created the #GtkLayoutChild instance.
|
||||
*/
|
||||
layout_child_properties[PROP_LAYOUT_MANAGER] =
|
||||
g_param_spec_object ("layout-manager",
|
||||
"Layout Manager",
|
||||
"The layout manager that created this object",
|
||||
GTK_TYPE_LAYOUT_MANAGER,
|
||||
GTK_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY);
|
||||
/**
|
||||
* GtkLayoutChild:child-widget:
|
||||
*
|
||||
* The widget that is associated to the #GtkLayoutChild instance.
|
||||
*/
|
||||
layout_child_properties[PROP_CHILD_WIDGET] =
|
||||
g_param_spec_object ("child-widget",
|
||||
"Child Widget",
|
||||
"The child widget that is associated to this object",
|
||||
GTK_TYPE_WIDGET,
|
||||
GTK_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY);
|
||||
|
||||
g_object_class_install_properties (gobject_class, N_PROPS, layout_child_properties);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_layout_child_init (GtkLayoutChild *self)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_layout_child_get_layout_manager:
|
||||
* @layout_child: a #GtkLayoutChild
|
||||
*
|
||||
* Retrieves the #GtkLayoutManager instance that created the
|
||||
* given @layout_child.
|
||||
*
|
||||
* Returns: (transfer none): a #GtkLayoutManager
|
||||
*/
|
||||
GtkLayoutManager *
|
||||
gtk_layout_child_get_layout_manager (GtkLayoutChild *layout_child)
|
||||
{
|
||||
GtkLayoutChildPrivate *priv = gtk_layout_child_get_instance_private (layout_child);
|
||||
|
||||
g_return_val_if_fail (GTK_IS_LAYOUT_CHILD (layout_child), NULL);
|
||||
|
||||
return priv->manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_layout_child_get_child_widget:
|
||||
* @layout_child: a #GtkLayoutChild
|
||||
*
|
||||
* Retrieves the #GtkWidget associated to the given @layout_child.
|
||||
*
|
||||
* Returns: (transfer none): a #GtkWidget
|
||||
*/
|
||||
GtkWidget *
|
||||
gtk_layout_child_get_child_widget (GtkLayoutChild *layout_child)
|
||||
{
|
||||
GtkLayoutChildPrivate *priv = gtk_layout_child_get_instance_private (layout_child);
|
||||
|
||||
g_return_val_if_fail (GTK_IS_LAYOUT_CHILD (layout_child), NULL);
|
||||
|
||||
return priv->widget;
|
||||
}
|
27
gtk/gtklayoutchild.h
Normal file
27
gtk/gtklayoutchild.h
Normal file
@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
|
||||
#error "Only <gtk/gtk.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#include <gtk/gtktypes.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GTK_TYPE_LAYOUT_CHILD (gtk_layout_child_get_type())
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
G_DECLARE_DERIVABLE_TYPE (GtkLayoutChild, gtk_layout_child, GTK, LAYOUT_CHILD, GObject)
|
||||
|
||||
struct _GtkLayoutChildClass
|
||||
{
|
||||
/*< private >*/
|
||||
GObjectClass parent_class;
|
||||
};
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkLayoutManager * gtk_layout_child_get_layout_manager (GtkLayoutChild *layout_child);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkWidget * gtk_layout_child_get_child_widget (GtkLayoutChild *layout_child);
|
||||
|
||||
G_END_DECLS
|
@ -38,6 +38,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#include "gtklayoutmanagerprivate.h"
|
||||
#include "gtklayoutchild.h"
|
||||
#include "gtkwidget.h"
|
||||
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
@ -57,6 +58,8 @@ typedef struct {
|
||||
|
||||
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GtkLayoutManager, gtk_layout_manager, G_TYPE_OBJECT)
|
||||
|
||||
static GQuark quark_layout_child;
|
||||
|
||||
static GtkSizeRequestMode
|
||||
gtk_layout_manager_real_get_request_mode (GtkLayoutManager *manager,
|
||||
GtkWidget *widget)
|
||||
@ -107,6 +110,8 @@ gtk_layout_manager_class_init (GtkLayoutManagerClass *klass)
|
||||
klass->get_request_mode = gtk_layout_manager_real_get_request_mode;
|
||||
klass->measure = gtk_layout_manager_real_measure;
|
||||
klass->allocate = gtk_layout_manager_real_allocate;
|
||||
|
||||
quark_layout_child = g_quark_from_static_string ("-GtkLayoutManager-layout-child");
|
||||
}
|
||||
|
||||
static void
|
||||
@ -278,3 +283,75 @@ gtk_layout_manager_layout_changed (GtkLayoutManager *manager)
|
||||
if (priv->widget != NULL)
|
||||
gtk_widget_queue_resize (priv->widget);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_layout_manager_get_layout_child:
|
||||
* @manager: a #GtkLayoutManager
|
||||
* @widget: a #GtkWidget
|
||||
*
|
||||
* Retrieves a #GtkLayoutChild instance for the #GtkLayoutManager, creating
|
||||
* one if necessary
|
||||
*
|
||||
* The #GtkLayoutChild instance is owned by the #GtkLayoutManager, and is
|
||||
* guaranteed to exist as long as @widget is a child of the #GtkWidget using
|
||||
* the given #GtkLayoutManager.
|
||||
*
|
||||
* Returns: (transfer none): a #GtkLayoutChild
|
||||
*/
|
||||
GtkLayoutChild *
|
||||
gtk_layout_manager_get_layout_child (GtkLayoutManager *manager,
|
||||
GtkWidget *widget)
|
||||
{
|
||||
GtkLayoutManagerPrivate *priv = gtk_layout_manager_get_instance_private (manager);
|
||||
GtkLayoutChild *res;
|
||||
GtkWidget *parent;
|
||||
|
||||
g_return_val_if_fail (GTK_IS_LAYOUT_MANAGER (manager), NULL);
|
||||
g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
|
||||
|
||||
parent = gtk_widget_get_parent (widget);
|
||||
g_return_val_if_fail (parent != NULL, NULL);
|
||||
|
||||
if (priv->widget != parent)
|
||||
{
|
||||
g_critical ("The parent %s %p of the widget %s %p does not "
|
||||
"use the given layout manager of type %s %p",
|
||||
gtk_widget_get_name (parent), parent,
|
||||
gtk_widget_get_name (widget), widget,
|
||||
G_OBJECT_TYPE_NAME (manager), manager);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (GTK_LAYOUT_MANAGER_GET_CLASS (manager)->create_layout_child == NULL)
|
||||
{
|
||||
g_critical ("The layout manager of type %s %p does not create "
|
||||
"GtkLayoutChild instances",
|
||||
G_OBJECT_TYPE_NAME (manager), manager);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* We store the LayoutChild into the Widget, so that the LayoutChild
|
||||
* instance goes away once the Widget goes away
|
||||
*/
|
||||
res = g_object_get_qdata (G_OBJECT (widget), quark_layout_child);
|
||||
if (res != NULL)
|
||||
{
|
||||
/* If the LayoutChild instance is stale, and refers to another
|
||||
* layout manager, then we simply ask the LayoutManager to
|
||||
* replace it, as it means the layout manager for the parent
|
||||
* widget was replaced
|
||||
*/
|
||||
if (gtk_layout_child_get_layout_manager (res) == manager)
|
||||
return res;
|
||||
}
|
||||
|
||||
res = GTK_LAYOUT_MANAGER_GET_CLASS (manager)->create_layout_child (manager, widget);
|
||||
g_assert (res != NULL);
|
||||
g_assert (g_type_is_a (G_OBJECT_TYPE (res), GTK_TYPE_LAYOUT_CHILD));
|
||||
|
||||
g_object_set_qdata_full (G_OBJECT (widget), quark_layout_child,
|
||||
res,
|
||||
g_object_unref);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
@ -20,6 +20,7 @@
|
||||
|
||||
#include <gtk/gtktypes.h>
|
||||
#include <gtk/gtkwidget.h>
|
||||
#include <gtk/gtklayoutchild.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
@ -48,23 +49,26 @@ struct _GtkLayoutManagerClass
|
||||
GObjectClass parent_class;
|
||||
|
||||
/*< public >*/
|
||||
GtkSizeRequestMode (* get_request_mode) (GtkLayoutManager *manager,
|
||||
GtkWidget *widget);
|
||||
GtkSizeRequestMode (* get_request_mode) (GtkLayoutManager *manager,
|
||||
GtkWidget *widget);
|
||||
|
||||
void (* measure) (GtkLayoutManager *manager,
|
||||
GtkWidget *widget,
|
||||
GtkOrientation orientation,
|
||||
int for_size,
|
||||
int *minimum,
|
||||
int *natural,
|
||||
int *minimum_baseline,
|
||||
int *natural_baseline);
|
||||
void (* measure) (GtkLayoutManager *manager,
|
||||
GtkWidget *widget,
|
||||
GtkOrientation orientation,
|
||||
int for_size,
|
||||
int *minimum,
|
||||
int *natural,
|
||||
int *minimum_baseline,
|
||||
int *natural_baseline);
|
||||
|
||||
void (* allocate) (GtkLayoutManager *manager,
|
||||
GtkWidget *widget,
|
||||
int width,
|
||||
int height,
|
||||
int baseline);
|
||||
void (* allocate) (GtkLayoutManager *manager,
|
||||
GtkWidget *widget,
|
||||
int width,
|
||||
int height,
|
||||
int baseline);
|
||||
|
||||
GtkLayoutChild * (* create_layout_child) (GtkLayoutManager *manager,
|
||||
GtkWidget *widget);
|
||||
|
||||
/*< private >*/
|
||||
gpointer _padding[16];
|
||||
@ -95,4 +99,8 @@ GtkWidget * gtk_layout_manager_get_widget (GtkLayoutManage
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_layout_manager_layout_changed (GtkLayoutManager *manager);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkLayoutChild * gtk_layout_manager_get_layout_child (GtkLayoutManager *manager,
|
||||
GtkWidget *widget);
|
||||
|
||||
G_END_DECLS
|
||||
|
@ -256,6 +256,7 @@ gtk_public_sources = files([
|
||||
'gtkinfobar.c',
|
||||
'gtklabel.c',
|
||||
'gtklayout.c',
|
||||
'gtklayoutchild.c',
|
||||
'gtklayoutmanager.c',
|
||||
'gtklevelbar.c',
|
||||
'gtklinkbutton.c',
|
||||
@ -507,6 +508,7 @@ gtk_public_headers = files([
|
||||
'gtkinfobar.h',
|
||||
'gtklabel.h',
|
||||
'gtklayout.h',
|
||||
'gtklayoutchild.h',
|
||||
'gtklayoutmanager.h',
|
||||
'gtklevelbar.h',
|
||||
'gtklinkbutton.h',
|
||||
|
Loading…
Reference in New Issue
Block a user