1 /*
2  * Copyright (C) 2021 Purism SPC
3  *
4  * SPDX-License-Identifier: LGPL-2.1+
5  *
6  * Author: Alexander Mikhaylenko <alexander.mikhaylenko@puri.sm>
7  */
8 
9 #include "config.h"
10 #include "adw-bin.h"
11 
12 /**
13  * SECTION:adwbin
14  * @Short_description: A widget with one child
15  * @Title: AdwBin
16  *
17  * The #AdwBin widget has only one child, set with the #AdwBin:child property.
18  *
19  * It is useful for deriving subclasses, since it provides common code needed
20  * for handling a single child widget.
21  *
22  * Since: 1.0
23  */
24 
25 typedef struct
26 {
27   GtkWidget *child;
28 } AdwBinPrivate;
29 
30 static void adw_bin_buildable_init (GtkBuildableIface *iface);
31 
32 G_DEFINE_TYPE_WITH_CODE (AdwBin, adw_bin, GTK_TYPE_WIDGET,
33                          G_ADD_PRIVATE (AdwBin)
34                          G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE, adw_bin_buildable_init))
35 
36 static GtkBuildableIface *parent_buildable_iface;
37 
38 enum {
39   PROP_0,
40   PROP_CHILD,
41   LAST_PROP
42 };
43 
44 static GParamSpec *props[LAST_PROP];
45 
46 static void
adw_bin_dispose(GObject * object)47 adw_bin_dispose (GObject *object)
48 {
49   AdwBin *self = ADW_BIN (object);
50   AdwBinPrivate *priv = adw_bin_get_instance_private (self);
51 
52   g_clear_pointer (&priv->child, gtk_widget_unparent);
53 
54   G_OBJECT_CLASS (adw_bin_parent_class)->dispose (object);
55 }
56 
57 static void
adw_bin_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)58 adw_bin_get_property (GObject    *object,
59                       guint       prop_id,
60                       GValue     *value,
61                       GParamSpec *pspec)
62 {
63   AdwBin *self = ADW_BIN (object);
64 
65   switch (prop_id) {
66   case PROP_CHILD:
67     g_value_set_object (value, adw_bin_get_child (self));
68     break;
69   default:
70     G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
71   }
72 }
73 
74 static void
adw_bin_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)75 adw_bin_set_property (GObject      *object,
76                       guint         prop_id,
77                       const GValue *value,
78                       GParamSpec   *pspec)
79 {
80   AdwBin *self = ADW_BIN (object);
81 
82   switch (prop_id) {
83   case PROP_CHILD:
84     adw_bin_set_child (self, g_value_get_object (value));
85     break;
86   default:
87     G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
88   }
89 }
90 
91 static void
adw_bin_class_init(AdwBinClass * klass)92 adw_bin_class_init (AdwBinClass *klass)
93 {
94   GObjectClass *object_class = G_OBJECT_CLASS (klass);
95   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
96 
97   object_class->dispose = adw_bin_dispose;
98   object_class->get_property = adw_bin_get_property;
99   object_class->set_property = adw_bin_set_property;
100 
101   /**
102    * AdwBin:child:
103    *
104    * The child widget of the #AdwBin.
105    *
106    * Since: 1.0
107    */
108   props[PROP_CHILD] =
109       g_param_spec_object ("child",
110                            "Child",
111                            "The child widget",
112                            GTK_TYPE_WIDGET,
113                            G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
114 
115   g_object_class_install_properties (object_class, LAST_PROP, props);
116 
117   gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT);
118 }
119 
120 static void
adw_bin_init(AdwBin * self)121 adw_bin_init (AdwBin *self)
122 {
123 }
124 
125 static void
adw_bin_buildable_add_child(GtkBuildable * buildable,GtkBuilder * builder,GObject * child,const char * type)126 adw_bin_buildable_add_child (GtkBuildable *buildable,
127                              GtkBuilder   *builder,
128                              GObject      *child,
129                              const char   *type)
130 {
131   if (GTK_IS_WIDGET (child))
132     adw_bin_set_child (ADW_BIN (buildable), GTK_WIDGET (child));
133   else
134     parent_buildable_iface->add_child (buildable, builder, child, type);
135 }
136 
137 static void
adw_bin_buildable_init(GtkBuildableIface * iface)138 adw_bin_buildable_init (GtkBuildableIface *iface)
139 {
140   parent_buildable_iface = g_type_interface_peek_parent (iface);
141 
142   iface->add_child = adw_bin_buildable_add_child;
143 }
144 
145 /**
146  * adw_bin_new:
147  *
148  * Creates a new #AdwBin.
149  *
150  * Returns: a new #AdwBin
151  *
152  * Since: 1.0
153  */
154 GtkWidget *
adw_bin_new(void)155 adw_bin_new (void)
156 {
157   return g_object_new (ADW_TYPE_BIN, NULL);
158 }
159 
160 /**
161  * adw_bin_get_child:
162  * @self: an #AdwBin
163  *
164  * Gets the child widget of @self.
165  *
166  * Returns: (nullable) (transfer none): the child widget of @self
167  *
168  * Since: 1.0
169  */
170 GtkWidget *
adw_bin_get_child(AdwBin * self)171 adw_bin_get_child (AdwBin *self)
172 {
173   AdwBinPrivate *priv;
174 
175   g_return_val_if_fail (ADW_IS_BIN (self), NULL);
176 
177   priv = adw_bin_get_instance_private (self);
178 
179   return priv->child;
180 }
181 
182 /**
183  * adw_bin_set_child:
184  * @self: an #AdwBin
185  * @child: (nullable): the child widget
186  *
187  * Sets the child widget of @self.
188  *
189  * Since: 1.0
190  */
191 void
adw_bin_set_child(AdwBin * self,GtkWidget * child)192 adw_bin_set_child (AdwBin    *self,
193                    GtkWidget *child)
194 {
195   AdwBinPrivate *priv;
196 
197   g_return_if_fail (ADW_IS_BIN (self));
198   g_return_if_fail (child == NULL || GTK_IS_WIDGET (child));
199 
200   priv = adw_bin_get_instance_private (self);
201 
202   if (priv->child == child)
203     return;
204 
205   if (priv->child)
206     gtk_widget_unparent (priv->child);
207 
208   priv->child = child;
209 
210   if (priv->child)
211     gtk_widget_set_parent (priv->child, GTK_WIDGET (self));
212 
213   g_object_notify_by_pspec (G_OBJECT (self), props[PROP_CHILD]);
214 }
215