1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 2010 Red Hat, Inc.
3  * Author: Matthias Clasen
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #include "config.h"
20 
21 #include <string.h>
22 
23 #include "gtkgrid.h"
24 
25 #include "gtkbuildable.h"
26 #include "gtkcsspositionvalueprivate.h"
27 #include "gtkgridlayout.h"
28 #include "gtkintl.h"
29 #include "gtkorientable.h"
30 #include "gtkprivate.h"
31 #include "gtksizerequest.h"
32 #include "gtkcssnodeprivate.h"
33 #include "gtkwidgetprivate.h"
34 
35 
36 /**
37  * GtkGrid:
38  *
39  * `GtkGrid` is a container which arranges its child widgets in
40  * rows and columns.
41  *
42  * ![An example GtkGrid](grid.png)
43  *
44  * It supports arbitrary positions and horizontal/vertical spans.
45  *
46  * Children are added using [method@Gtk.Grid.attach]. They can span multiple
47  * rows or columns. It is also possible to add a child next to an existing
48  * child, using [method@Gtk.Grid.attach_next_to]. To remove a child from the
49  * grid, use [method@Gtk.Grid.remove].
50  *
51  * The behaviour of `GtkGrid` when several children occupy the same grid
52  * cell is undefined.
53  *
54  * # GtkGrid as GtkBuildable
55  *
56  * Every child in a `GtkGrid` has access to a custom [iface@Gtk.Buildable]
57  * element, called `<layout>`. It can by used to specify a position in the
58  * grid and optionally spans. All properties that can be used in the `<layout>`
59  * element are implemented by [class@Gtk.GridLayoutChild].
60  *
61  * It is implemented by `GtkWidget` using [class@Gtk.LayoutManager].
62  *
63  * To showcase it, here is a simple example:
64  *
65  * ```xml
66  * <object class="GtkGrid" id="my_grid">
67  *   <child>
68  *     <object class="GtkButton" id="button1">
69  *       <property name="label">Button 1</property>
70  *       <layout>
71  *         <property name="column">0</property>
72  *         <property name="row">0</property>
73  *       </layout>
74  *     </object>
75  *   </child>
76  *   <child>
77  *     <object class="GtkButton" id="button2">
78  *       <property name="label">Button 2</property>
79  *       <layout>
80  *         <property name="column">1</property>
81  *         <property name="row">0</property>
82  *       </layout>
83  *     </object>
84  *   </child>
85  *   <child>
86  *     <object class="GtkButton" id="button3">
87  *       <property name="label">Button 3</property>
88  *       <layout>
89  *         <property name="column">2</property>
90  *         <property name="row">0</property>
91  *         <property name="row-span">2</property>
92  *       </layout>
93  *     </object>
94  *   </child>
95  *   <child>
96  *     <object class="GtkButton" id="button4">
97  *       <property name="label">Button 4</property>
98  *       <layout>
99  *         <property name="column">0</property>
100  *         <property name="row">1</property>
101  *         <property name="column-span">2</property>
102  *       </layout>
103  *     </object>
104  *   </child>
105  * </object>
106  * ```
107  *
108  * It organizes the first two buttons side-by-side in one cell each.
109  * The third button is in the last column but spans across two rows.
110  * This is defined by the `row-span` property. The last button is
111  * located in the second row and spans across two columns, which is
112  * defined by the `column-span` property.
113  *
114  * # CSS nodes
115  *
116  * `GtkGrid` uses a single CSS node with name `grid`.
117  *
118  * # Accessibility
119  *
120  * `GtkGrid` uses the %GTK_ACCESSIBLE_ROLE_GROUP role.
121  */
122 
123 typedef struct
124 {
125   GtkLayoutManager *layout_manager;
126 
127   GtkOrientation orientation;
128 } GtkGridPrivate;
129 
130 enum
131 {
132   PROP_0,
133   PROP_ROW_SPACING,
134   PROP_COLUMN_SPACING,
135   PROP_ROW_HOMOGENEOUS,
136   PROP_COLUMN_HOMOGENEOUS,
137   PROP_BASELINE_ROW,
138   N_PROPERTIES,
139 
140   /* GtkOrientable */
141   PROP_ORIENTATION
142 };
143 
144 static void gtk_grid_buildable_iface_init (GtkBuildableIface *iface);
145 
146 static GParamSpec *obj_properties[N_PROPERTIES] = { NULL, };
147 
G_DEFINE_TYPE_WITH_CODE(GtkGrid,gtk_grid,GTK_TYPE_WIDGET,G_ADD_PRIVATE (GtkGrid)G_IMPLEMENT_INTERFACE (GTK_TYPE_ORIENTABLE,NULL)G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,gtk_grid_buildable_iface_init))148 G_DEFINE_TYPE_WITH_CODE (GtkGrid, gtk_grid, GTK_TYPE_WIDGET,
149                          G_ADD_PRIVATE (GtkGrid)
150                          G_IMPLEMENT_INTERFACE (GTK_TYPE_ORIENTABLE, NULL)
151                          G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
152                                                 gtk_grid_buildable_iface_init))
153 
154 
155 static void
156 gtk_grid_get_property (GObject    *object,
157                        guint       prop_id,
158                        GValue     *value,
159                        GParamSpec *pspec)
160 {
161   GtkGrid *grid = GTK_GRID (object);
162   GtkGridPrivate *priv = gtk_grid_get_instance_private (grid);
163 
164   switch (prop_id)
165     {
166     case PROP_ORIENTATION:
167       g_value_set_enum (value, priv->orientation);
168       break;
169 
170     case PROP_ROW_SPACING:
171       g_value_set_int (value, gtk_grid_layout_get_row_spacing (GTK_GRID_LAYOUT (priv->layout_manager)));
172       break;
173 
174     case PROP_COLUMN_SPACING:
175       g_value_set_int (value, gtk_grid_layout_get_column_spacing (GTK_GRID_LAYOUT (priv->layout_manager)));
176       break;
177 
178     case PROP_ROW_HOMOGENEOUS:
179       g_value_set_boolean (value, gtk_grid_layout_get_row_homogeneous (GTK_GRID_LAYOUT (priv->layout_manager)));
180       break;
181 
182     case PROP_COLUMN_HOMOGENEOUS:
183       g_value_set_boolean (value, gtk_grid_layout_get_column_homogeneous (GTK_GRID_LAYOUT (priv->layout_manager)));
184       break;
185 
186     case PROP_BASELINE_ROW:
187       g_value_set_int (value, gtk_grid_layout_get_baseline_row (GTK_GRID_LAYOUT (priv->layout_manager)));
188       break;
189 
190     default:
191       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
192       break;
193     }
194 }
195 
196 static void
gtk_grid_set_orientation(GtkGrid * grid,GtkOrientation orientation)197 gtk_grid_set_orientation (GtkGrid        *grid,
198                           GtkOrientation  orientation)
199 {
200   GtkGridPrivate *priv = gtk_grid_get_instance_private (grid);
201 
202   if (priv->orientation != orientation)
203     {
204       priv->orientation = orientation;
205 
206       gtk_widget_update_orientation (GTK_WIDGET (grid), priv->orientation);
207 
208       g_object_notify (G_OBJECT (grid), "orientation");
209     }
210 }
211 
212 static void
gtk_grid_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)213 gtk_grid_set_property (GObject      *object,
214                        guint         prop_id,
215                        const GValue *value,
216                        GParamSpec   *pspec)
217 {
218   GtkGrid *grid = GTK_GRID (object);
219 
220   switch (prop_id)
221     {
222     case PROP_ORIENTATION:
223       gtk_grid_set_orientation (grid, g_value_get_enum (value));
224       break;
225 
226     case PROP_ROW_SPACING:
227       gtk_grid_set_row_spacing (grid, g_value_get_int (value));
228       break;
229 
230     case PROP_COLUMN_SPACING:
231       gtk_grid_set_column_spacing (grid, g_value_get_int (value));
232       break;
233 
234     case PROP_ROW_HOMOGENEOUS:
235       gtk_grid_set_row_homogeneous (grid, g_value_get_boolean (value));
236       break;
237 
238     case PROP_COLUMN_HOMOGENEOUS:
239       gtk_grid_set_column_homogeneous (grid, g_value_get_boolean (value));
240       break;
241 
242     case PROP_BASELINE_ROW:
243       gtk_grid_set_baseline_row (grid, g_value_get_int (value));
244       break;
245 
246     default:
247       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
248       break;
249     }
250 }
251 
252 static void
grid_attach(GtkGrid * grid,GtkWidget * widget,int column,int row,int width,int height)253 grid_attach (GtkGrid   *grid,
254              GtkWidget *widget,
255              int        column,
256              int        row,
257              int        width,
258              int        height)
259 {
260   GtkGridPrivate *priv = gtk_grid_get_instance_private (grid);
261   GtkGridLayoutChild *grid_child;
262 
263   gtk_widget_set_parent (widget, GTK_WIDGET (grid));
264 
265   grid_child = GTK_GRID_LAYOUT_CHILD (gtk_layout_manager_get_layout_child (priv->layout_manager, widget));
266   gtk_grid_layout_child_set_column (grid_child, column);
267   gtk_grid_layout_child_set_row (grid_child, row);
268   gtk_grid_layout_child_set_column_span (grid_child, width);
269   gtk_grid_layout_child_set_row_span (grid_child, height);
270 }
271 
272 /* Find the position 'touching' existing
273  * children. @orientation and @max determine
274  * from which direction to approach (horizontal
275  * + max = right, vertical + !max = top, etc).
276  * @op_pos, @op_span determine the rows/columns
277  * in which the touching has to happen.
278  */
279 static int
find_attach_position(GtkGrid * grid,GtkOrientation orientation,int op_pos,int op_span,gboolean max)280 find_attach_position (GtkGrid         *grid,
281                       GtkOrientation   orientation,
282                       int              op_pos,
283                       int              op_span,
284                       gboolean         max)
285 {
286   GtkGridPrivate *priv = gtk_grid_get_instance_private (grid);
287   GtkWidget *child;
288   gboolean hit;
289   int pos;
290 
291   if (max)
292     pos = -G_MAXINT;
293   else
294     pos = G_MAXINT;
295 
296   hit = FALSE;
297 
298   for (child = gtk_widget_get_first_child (GTK_WIDGET (grid));
299        child != NULL;
300        child = gtk_widget_get_next_sibling (child))
301     {
302       GtkGridLayoutChild *grid_child;
303       int attach_pos = 0, attach_span = 0;
304       int opposite_pos = 0, opposite_span = 0;
305 
306       grid_child = GTK_GRID_LAYOUT_CHILD (gtk_layout_manager_get_layout_child (priv->layout_manager, child));
307 
308       switch (orientation)
309         {
310         case GTK_ORIENTATION_HORIZONTAL:
311           attach_pos = gtk_grid_layout_child_get_column (grid_child);
312           attach_span = gtk_grid_layout_child_get_column_span (grid_child);
313           opposite_pos = gtk_grid_layout_child_get_row (grid_child);
314           opposite_span = gtk_grid_layout_child_get_row_span (grid_child);
315           break;
316 
317         case GTK_ORIENTATION_VERTICAL:
318           attach_pos = gtk_grid_layout_child_get_row (grid_child);
319           attach_span = gtk_grid_layout_child_get_row_span (grid_child);
320           opposite_pos = gtk_grid_layout_child_get_column (grid_child);
321           opposite_span = gtk_grid_layout_child_get_column_span (grid_child);
322           break;
323 
324         default:
325           break;
326         }
327 
328       /* check if the ranges overlap */
329       if (opposite_pos <= op_pos + op_span && op_pos <= opposite_pos + opposite_span)
330         {
331           hit = TRUE;
332 
333           if (max)
334             pos = MAX (pos, attach_pos + attach_span);
335           else
336             pos = MIN (pos, attach_pos);
337         }
338      }
339 
340   if (!hit)
341     pos = 0;
342 
343   return pos;
344 }
345 
346 static void
gtk_grid_compute_expand(GtkWidget * widget,gboolean * hexpand_p,gboolean * vexpand_p)347 gtk_grid_compute_expand (GtkWidget *widget,
348                          gboolean  *hexpand_p,
349                          gboolean  *vexpand_p)
350 {
351   GtkWidget *w;
352   gboolean hexpand = FALSE;
353   gboolean vexpand = FALSE;
354 
355   for (w = gtk_widget_get_first_child (widget);
356        w != NULL;
357        w = gtk_widget_get_next_sibling (w))
358     {
359       hexpand = hexpand || gtk_widget_compute_expand (w, GTK_ORIENTATION_HORIZONTAL);
360       vexpand = vexpand || gtk_widget_compute_expand (w, GTK_ORIENTATION_VERTICAL);
361     }
362 
363   *hexpand_p = hexpand;
364   *vexpand_p = vexpand;
365 }
366 
367 static GtkSizeRequestMode
gtk_grid_get_request_mode(GtkWidget * widget)368 gtk_grid_get_request_mode (GtkWidget *widget)
369 {
370   GtkWidget *w;
371   int wfh = 0, hfw = 0;
372 
373   for (w = gtk_widget_get_first_child (widget);
374        w != NULL;
375        w = gtk_widget_get_next_sibling (w))
376     {
377       GtkSizeRequestMode mode = gtk_widget_get_request_mode (w);
378 
379       switch (mode)
380         {
381         case GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH:
382           hfw ++;
383           break;
384         case GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT:
385           wfh ++;
386           break;
387         case GTK_SIZE_REQUEST_CONSTANT_SIZE:
388         default:
389           break;
390         }
391     }
392 
393   if (hfw == 0 && wfh == 0)
394     return GTK_SIZE_REQUEST_CONSTANT_SIZE;
395   else
396     return wfh > hfw ?
397         GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT :
398         GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH;
399 }
400 
401 static void
gtk_grid_dispose(GObject * object)402 gtk_grid_dispose (GObject *object)
403 {
404   GtkWidget *child;
405 
406   while ((child = gtk_widget_get_first_child (GTK_WIDGET (object))))
407     gtk_grid_remove (GTK_GRID (object), child);
408 
409   G_OBJECT_CLASS (gtk_grid_parent_class)->dispose (object);
410 }
411 
412 static void
gtk_grid_class_init(GtkGridClass * class)413 gtk_grid_class_init (GtkGridClass *class)
414 {
415   GObjectClass *object_class = G_OBJECT_CLASS (class);
416   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
417 
418   object_class->dispose = gtk_grid_dispose;
419   object_class->get_property = gtk_grid_get_property;
420   object_class->set_property = gtk_grid_set_property;
421 
422   widget_class->compute_expand = gtk_grid_compute_expand;
423   widget_class->get_request_mode = gtk_grid_get_request_mode;
424 
425   g_object_class_override_property (object_class, PROP_ORIENTATION, "orientation");
426 
427   /**
428    * GtkGrid:row-spacing: (attributes org.gtk.Property.get=gtk_grid_get_row_spacing org.gtk.Property.set=gtk_grid_set_row_spacing)
429    *
430    * The amount of space between two consecutive rows.
431    */
432   obj_properties[PROP_ROW_SPACING] =
433     g_param_spec_int ("row-spacing",
434                       P_("Row spacing"),
435                       P_("The amount of space between two consecutive rows"),
436                       0, G_MAXINT16, 0,
437                       GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
438 
439   /**
440    * GtkGrid:column-spacing: (attributes org.gtk.Property.get=gtk_grid_get_column_spacing org.gtk.Property.set=gtk_grid_set_column_spacing)
441    *
442    * The amount of space between two consecutive columns.
443    */
444   obj_properties[PROP_COLUMN_SPACING] =
445     g_param_spec_int ("column-spacing",
446                       P_("Column spacing"),
447                       P_("The amount of space between two consecutive columns"),
448                       0, G_MAXINT16, 0,
449                       GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
450 
451   /**
452    * GtkGrid:row-homogeneous: (attributes org.gtk.Property.get=gtk_grid_get_row_homogeneous org.gtk.Property.set=gtk_grid_set_row_homogeneous)
453    *
454    * If %TRUE, the rows are all the same height.
455    */
456   obj_properties[PROP_ROW_HOMOGENEOUS] =
457     g_param_spec_boolean ("row-homogeneous",
458                           P_("Row Homogeneous"),
459                           P_("If TRUE, the rows are all the same height"),
460                           FALSE,
461                           GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
462 
463   /**
464    * GtkGrid:column-homogeneous: (attributes org.gtk.Property.get=gtk_grid_get_column_homogeneous org.gtk.Property.set=gtk_grid_set_column_homogeneous)
465    *
466    * If %TRUE, the columns are all the same width.
467    */
468   obj_properties[PROP_COLUMN_HOMOGENEOUS] =
469     g_param_spec_boolean ("column-homogeneous",
470                           P_("Column Homogeneous"),
471                           P_("If TRUE, the columns are all the same width"),
472                           FALSE,
473                           GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
474 
475   /**
476    * GtkGrid:baseline-row: (attributes org.gtk.Property.get=gtk_grid_get_baseline_row org.gtk.Property.set=gtk_grid_set_baseline_row)
477    *
478    * The row to align to the baseline when valign is %GTK_ALIGN_BASELINE.
479    */
480   obj_properties[PROP_BASELINE_ROW] =
481     g_param_spec_int ("baseline-row",
482                       P_("Baseline Row"),
483                       P_("The row to align the to the baseline when valign is GTK_ALIGN_BASELINE"),
484                       0, G_MAXINT, 0,
485                       GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
486 
487   g_object_class_install_properties (object_class, N_PROPERTIES, obj_properties);
488 
489   gtk_widget_class_set_css_name (widget_class, I_("grid"));
490   gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_GRID_LAYOUT);
491   gtk_widget_class_set_accessible_role (widget_class, GTK_ACCESSIBLE_ROLE_GROUP);
492 }
493 
494 static GtkBuildableIface *parent_buildable_iface;
495 
496 static void
gtk_grid_buildable_add_child(GtkBuildable * buildable,GtkBuilder * builder,GObject * child,const char * type)497 gtk_grid_buildable_add_child (GtkBuildable *buildable,
498                               GtkBuilder   *builder,
499                               GObject      *child,
500                               const char   *type)
501 {
502   if (GTK_IS_WIDGET (child))
503     {
504       GtkGrid *grid = GTK_GRID ( buildable);
505       GtkGridPrivate *priv = gtk_grid_get_instance_private (grid);
506       int pos[2] = { 0, 0 };
507 
508       pos[priv->orientation] = find_attach_position (grid, priv->orientation, 0, 1, TRUE);
509       grid_attach (grid, GTK_WIDGET (child), pos[0], pos[1], 1, 1);
510     }
511   else
512     parent_buildable_iface->add_child (buildable, builder, child, type);
513 }
514 
515 static void
gtk_grid_buildable_iface_init(GtkBuildableIface * iface)516 gtk_grid_buildable_iface_init (GtkBuildableIface *iface)
517 {
518   parent_buildable_iface = g_type_interface_peek_parent (iface);
519 
520   iface->add_child = gtk_grid_buildable_add_child;
521 }
522 
523 static void
gtk_grid_init(GtkGrid * grid)524 gtk_grid_init (GtkGrid *grid)
525 {
526   GtkGridPrivate *priv = gtk_grid_get_instance_private (grid);
527 
528   priv->layout_manager = gtk_widget_get_layout_manager (GTK_WIDGET (grid));
529 
530   priv->orientation = GTK_ORIENTATION_HORIZONTAL;
531   gtk_widget_update_orientation (GTK_WIDGET (grid), priv->orientation);
532 }
533 
534 /**
535  * gtk_grid_new:
536  *
537  * Creates a new grid widget.
538  *
539  * Returns: the new `GtkGrid`
540  */
541 GtkWidget *
gtk_grid_new(void)542 gtk_grid_new (void)
543 {
544   return g_object_new (GTK_TYPE_GRID, NULL);
545 }
546 
547 /**
548  * gtk_grid_attach:
549  * @grid: a `GtkGrid`
550  * @child: the widget to add
551  * @column: the column number to attach the left side of @child to
552  * @row: the row number to attach the top side of @child to
553  * @width: the number of columns that @child will span
554  * @height: the number of rows that @child will span
555  *
556  * Adds a widget to the grid.
557  *
558  * The position of @child is determined by @column and @row.
559  * The number of “cells” that @child will occupy is determined
560  * by @width and @height.
561  */
562 void
gtk_grid_attach(GtkGrid * grid,GtkWidget * child,int column,int row,int width,int height)563 gtk_grid_attach (GtkGrid   *grid,
564                  GtkWidget *child,
565                  int        column,
566                  int        row,
567                  int        width,
568                  int        height)
569 {
570   g_return_if_fail (GTK_IS_GRID (grid));
571   g_return_if_fail (GTK_IS_WIDGET (child));
572   g_return_if_fail (_gtk_widget_get_parent (child) == NULL);
573   g_return_if_fail (width > 0);
574   g_return_if_fail (height > 0);
575 
576   grid_attach (grid, child, column, row, width, height);
577 }
578 
579 /**
580  * gtk_grid_attach_next_to:
581  * @grid: a `GtkGrid`
582  * @child: the widget to add
583  * @sibling: (nullable): the child of @grid that @child will be placed
584  *   next to, or %NULL to place @child at the beginning or end
585  * @side: the side of @sibling that @child is positioned next to
586  * @width: the number of columns that @child will span
587  * @height: the number of rows that @child will span
588  *
589  * Adds a widget to the grid.
590  *
591  * The widget is placed next to @sibling, on the side determined by
592  * @side. When @sibling is %NULL, the widget is placed in row (for
593  * left or right placement) or column 0 (for top or bottom placement),
594  * at the end indicated by @side.
595  *
596  * Attaching widgets labeled `[1]`, `[2]`, `[3]` with `@sibling == %NULL` and
597  * `@side == %GTK_POS_LEFT` yields a layout of `[3][2][1]`.
598  */
599 void
gtk_grid_attach_next_to(GtkGrid * grid,GtkWidget * child,GtkWidget * sibling,GtkPositionType side,int width,int height)600 gtk_grid_attach_next_to (GtkGrid         *grid,
601                          GtkWidget       *child,
602                          GtkWidget       *sibling,
603                          GtkPositionType  side,
604                          int              width,
605                          int              height)
606 {
607   GtkGridPrivate *priv = gtk_grid_get_instance_private (grid);
608   GtkGridLayoutChild *grid_sibling;
609   int left, top;
610 
611   g_return_if_fail (GTK_IS_GRID (grid));
612   g_return_if_fail (GTK_IS_WIDGET (child));
613   g_return_if_fail (_gtk_widget_get_parent (child) == NULL);
614   g_return_if_fail (sibling == NULL || _gtk_widget_get_parent (sibling) == (GtkWidget*)grid);
615   g_return_if_fail (width > 0);
616   g_return_if_fail (height > 0);
617 
618   if (sibling != NULL)
619     {
620       grid_sibling = GTK_GRID_LAYOUT_CHILD (gtk_layout_manager_get_layout_child (priv->layout_manager, sibling));
621 
622       switch (side)
623         {
624         case GTK_POS_LEFT:
625           left = gtk_grid_layout_child_get_column (grid_sibling) - width;
626           top = gtk_grid_layout_child_get_row (grid_sibling);
627           break;
628         case GTK_POS_RIGHT:
629           left = gtk_grid_layout_child_get_column (grid_sibling) +
630                  gtk_grid_layout_child_get_column_span (grid_sibling);
631           top = gtk_grid_layout_child_get_row (grid_sibling);
632           break;
633         case GTK_POS_TOP:
634           left = gtk_grid_layout_child_get_column (grid_sibling);
635           top = gtk_grid_layout_child_get_row (grid_sibling) - height;
636           break;
637         case GTK_POS_BOTTOM:
638           left = gtk_grid_layout_child_get_column (grid_sibling);
639           top = gtk_grid_layout_child_get_row (grid_sibling) +
640                 gtk_grid_layout_child_get_row_span (grid_sibling);
641           break;
642         default:
643           g_assert_not_reached ();
644         }
645     }
646   else
647     {
648       switch (side)
649         {
650         case GTK_POS_LEFT:
651           left = find_attach_position (grid, GTK_ORIENTATION_HORIZONTAL, 0, height, FALSE);
652           left -= width;
653           top = 0;
654           break;
655         case GTK_POS_RIGHT:
656           left = find_attach_position (grid, GTK_ORIENTATION_HORIZONTAL, 0, height, TRUE);
657           top = 0;
658           break;
659         case GTK_POS_TOP:
660           left = 0;
661           top = find_attach_position (grid, GTK_ORIENTATION_VERTICAL, 0, width, FALSE);
662           top -= height;
663           break;
664         case GTK_POS_BOTTOM:
665           left = 0;
666           top = find_attach_position (grid, GTK_ORIENTATION_VERTICAL, 0, width, TRUE);
667           break;
668         default:
669           g_assert_not_reached ();
670         }
671     }
672 
673   grid_attach (grid, child, left, top, width, height);
674 }
675 
676 /**
677  * gtk_grid_get_child_at:
678  * @grid: a `GtkGrid`
679  * @column: the left edge of the cell
680  * @row: the top edge of the cell
681  *
682  * Gets the child of @grid whose area covers the grid
683  * cell at @column, @row.
684  *
685  * Returns: (transfer none) (nullable): the child at the given position
686  */
687 GtkWidget *
gtk_grid_get_child_at(GtkGrid * grid,int column,int row)688 gtk_grid_get_child_at (GtkGrid *grid,
689                        int      column,
690                        int      row)
691 {
692   GtkGridPrivate *priv = gtk_grid_get_instance_private (grid);
693   GtkWidget *child;
694 
695   g_return_val_if_fail (GTK_IS_GRID (grid), NULL);
696 
697   for (child = gtk_widget_get_first_child (GTK_WIDGET (grid));
698        child != NULL;
699        child = gtk_widget_get_next_sibling (child))
700     {
701       GtkGridLayoutChild *grid_child;
702       int child_column, child_row, child_width, child_height;
703 
704       grid_child = GTK_GRID_LAYOUT_CHILD (gtk_layout_manager_get_layout_child (priv->layout_manager, child));
705       child_column = gtk_grid_layout_child_get_column (grid_child);
706       child_row = gtk_grid_layout_child_get_row (grid_child);
707       child_width = gtk_grid_layout_child_get_column_span (grid_child);
708       child_height = gtk_grid_layout_child_get_row_span (grid_child);
709 
710       if (child_column <= column && child_column + child_width > column &&
711           child_row <= row && child_row + child_height > row)
712         return child;
713     }
714 
715   return NULL;
716 }
717 
718 /**
719  * gtk_grid_remove:
720  * @grid: a `GtkGrid`
721  * @child: the child widget to remove
722  *
723  * Removes a child from @grid.
724  *
725  * The child must have been added with
726  * [method@Gtk.Grid.attach] or [method@Gtk.Grid.attach_next_to].
727  */
728 void
gtk_grid_remove(GtkGrid * grid,GtkWidget * child)729 gtk_grid_remove (GtkGrid   *grid,
730                  GtkWidget *child)
731 {
732   g_return_if_fail (GTK_IS_GRID (grid));
733   g_return_if_fail (GTK_IS_WIDGET (child));
734   g_return_if_fail (gtk_widget_get_parent (child) == GTK_WIDGET (grid));
735 
736   gtk_widget_unparent (child);
737 }
738 
739 /**
740  * gtk_grid_insert_row:
741  * @grid: a `GtkGrid`
742  * @position: the position to insert the row at
743  *
744  * Inserts a row at the specified position.
745  *
746  * Children which are attached at or below this position
747  * are moved one row down. Children which span across this
748  * position are grown to span the new row.
749  */
750 void
gtk_grid_insert_row(GtkGrid * grid,int position)751 gtk_grid_insert_row (GtkGrid *grid,
752                      int      position)
753 {
754   GtkGridPrivate *priv = gtk_grid_get_instance_private (grid);
755   GtkWidget *child;
756   int top, height;
757 
758   g_return_if_fail (GTK_IS_GRID (grid));
759 
760   for (child = gtk_widget_get_first_child (GTK_WIDGET (grid));
761        child != NULL;
762        child = gtk_widget_get_next_sibling (child))
763     {
764       GtkGridLayoutChild *grid_child;
765 
766       grid_child = GTK_GRID_LAYOUT_CHILD (gtk_layout_manager_get_layout_child (priv->layout_manager, child));
767       top = gtk_grid_layout_child_get_row (grid_child);
768       height = gtk_grid_layout_child_get_row_span (grid_child);
769 
770       if (top >= position)
771         gtk_grid_layout_child_set_row (grid_child, top + 1);
772       else if (top + height > position)
773         gtk_grid_layout_child_set_row_span (grid_child, height + 1);
774     }
775 }
776 
777 /**
778  * gtk_grid_remove_row:
779  * @grid: a `GtkGrid`
780  * @position: the position of the row to remove
781  *
782  * Removes a row from the grid.
783  *
784  * Children that are placed in this row are removed,
785  * spanning children that overlap this row have their
786  * height reduced by one, and children below the row
787  * are moved up.
788  */
789 void
gtk_grid_remove_row(GtkGrid * grid,int position)790 gtk_grid_remove_row (GtkGrid *grid,
791                      int      position)
792 {
793   GtkGridPrivate *priv = gtk_grid_get_instance_private (grid);
794   GtkWidget *child;
795 
796   g_return_if_fail (GTK_IS_GRID (grid));
797 
798   child = gtk_widget_get_first_child (GTK_WIDGET (grid));
799   while (child)
800     {
801       GtkWidget *next = gtk_widget_get_next_sibling (child);
802       GtkGridLayoutChild *grid_child;
803       int top, height;
804 
805       grid_child = GTK_GRID_LAYOUT_CHILD (gtk_layout_manager_get_layout_child (priv->layout_manager, child));
806       top = gtk_grid_layout_child_get_row (grid_child);
807       height = gtk_grid_layout_child_get_row_span (grid_child);
808 
809       if (top <= position && top + height > position)
810         height--;
811       if (top > position)
812         top--;
813 
814       if (height <= 0)
815         {
816           gtk_grid_remove (grid, child);
817         }
818       else
819         {
820           gtk_grid_layout_child_set_row_span (grid_child, height);
821           gtk_grid_layout_child_set_row (grid_child, top);
822         }
823 
824       child = next;
825     }
826 }
827 
828 /**
829  * gtk_grid_insert_column:
830  * @grid: a `GtkGrid`
831  * @position: the position to insert the column at
832  *
833  * Inserts a column at the specified position.
834  *
835  * Children which are attached at or to the right of this position
836  * are moved one column to the right. Children which span across this
837  * position are grown to span the new column.
838  */
839 void
gtk_grid_insert_column(GtkGrid * grid,int position)840 gtk_grid_insert_column (GtkGrid *grid,
841                         int      position)
842 {
843   GtkGridPrivate *priv = gtk_grid_get_instance_private (grid);
844   GtkWidget *child;
845 
846   g_return_if_fail (GTK_IS_GRID (grid));
847 
848   for (child = gtk_widget_get_first_child (GTK_WIDGET (grid));
849        child != NULL;
850        child = gtk_widget_get_next_sibling (child))
851     {
852       GtkGridLayoutChild *grid_child;
853       int left, width;
854 
855       grid_child = GTK_GRID_LAYOUT_CHILD (gtk_layout_manager_get_layout_child (priv->layout_manager, child));
856       left = gtk_grid_layout_child_get_column (grid_child);
857       width = gtk_grid_layout_child_get_column_span (grid_child);
858 
859       if (left >= position)
860         gtk_grid_layout_child_set_column (grid_child, left + 1);
861       else if (left + width > position)
862         gtk_grid_layout_child_set_column_span (grid_child, width + 1);
863     }
864 }
865 
866 /**
867  * gtk_grid_remove_column:
868  * @grid: a `GtkGrid`
869  * @position: the position of the column to remove
870  *
871  * Removes a column from the grid.
872  *
873  * Children that are placed in this column are removed,
874  * spanning children that overlap this column have their
875  * width reduced by one, and children after the column
876  * are moved to the left.
877  */
878 void
gtk_grid_remove_column(GtkGrid * grid,int position)879 gtk_grid_remove_column (GtkGrid *grid,
880                         int      position)
881 {
882   GtkGridPrivate *priv = gtk_grid_get_instance_private (grid);
883   GtkWidget *child;
884 
885   g_return_if_fail (GTK_IS_GRID (grid));
886 
887   child = gtk_widget_get_first_child (GTK_WIDGET (grid));
888   while (child)
889     {
890       GtkWidget *next = gtk_widget_get_next_sibling (child);
891       GtkGridLayoutChild *grid_child;
892       int left, width;
893 
894       grid_child = GTK_GRID_LAYOUT_CHILD (gtk_layout_manager_get_layout_child (priv->layout_manager, child));
895 
896       left = gtk_grid_layout_child_get_column (grid_child);
897       width = gtk_grid_layout_child_get_column_span (grid_child);
898 
899       if (left <= position && left + width > position)
900         width--;
901       if (left > position)
902         left--;
903 
904       if (width <= 0)
905         {
906           gtk_grid_remove (grid, child);
907         }
908       else
909         {
910           gtk_grid_layout_child_set_column_span (grid_child, width);
911           gtk_grid_layout_child_set_column (grid_child, left);
912         }
913 
914       child = next;
915     }
916 }
917 
918 /**
919  * gtk_grid_insert_next_to:
920  * @grid: a `GtkGrid`
921  * @sibling: the child of @grid that the new row or column will be
922  *   placed next to
923  * @side: the side of @sibling that @child is positioned next to
924  *
925  * Inserts a row or column at the specified position.
926  *
927  * The new row or column is placed next to @sibling, on the side
928  * determined by @side. If @side is %GTK_POS_TOP or %GTK_POS_BOTTOM,
929  * a row is inserted. If @side is %GTK_POS_LEFT of %GTK_POS_RIGHT,
930  * a column is inserted.
931  */
932 void
gtk_grid_insert_next_to(GtkGrid * grid,GtkWidget * sibling,GtkPositionType side)933 gtk_grid_insert_next_to (GtkGrid         *grid,
934                          GtkWidget       *sibling,
935                          GtkPositionType  side)
936 {
937   GtkGridPrivate *priv = gtk_grid_get_instance_private (grid);
938   GtkGridLayoutChild *child;
939 
940   g_return_if_fail (GTK_IS_GRID (grid));
941   g_return_if_fail (GTK_IS_WIDGET (sibling));
942   g_return_if_fail (_gtk_widget_get_parent (sibling) == (GtkWidget*)grid);
943 
944   child = GTK_GRID_LAYOUT_CHILD (gtk_layout_manager_get_layout_child (priv->layout_manager, sibling));
945 
946   switch (side)
947     {
948     case GTK_POS_LEFT:
949       gtk_grid_insert_column (grid, gtk_grid_layout_child_get_column (child));
950       break;
951     case GTK_POS_RIGHT:
952       {
953         int col = gtk_grid_layout_child_get_column (child) +
954                   gtk_grid_layout_child_get_column_span (child);
955         gtk_grid_insert_column (grid, col);
956       }
957       break;
958     case GTK_POS_TOP:
959       gtk_grid_insert_row (grid, gtk_grid_layout_child_get_row (child));
960       break;
961     case GTK_POS_BOTTOM:
962       {
963         int row = gtk_grid_layout_child_get_row (child) +
964                   gtk_grid_layout_child_get_row_span (child);
965         gtk_grid_insert_row (grid, row);
966       }
967       break;
968     default:
969       g_assert_not_reached ();
970     }
971 }
972 
973 /**
974  * gtk_grid_set_row_homogeneous: (attributes org.gtk.Method.set_property=row-homogeneous)
975  * @grid: a `GtkGrid`
976  * @homogeneous: %TRUE to make rows homogeneous
977  *
978  * Sets whether all rows of @grid will have the same height.
979  */
980 void
gtk_grid_set_row_homogeneous(GtkGrid * grid,gboolean homogeneous)981 gtk_grid_set_row_homogeneous (GtkGrid  *grid,
982                               gboolean  homogeneous)
983 {
984   GtkGridPrivate *priv = gtk_grid_get_instance_private (grid);
985   gboolean old_val;
986 
987   g_return_if_fail (GTK_IS_GRID (grid));
988 
989   old_val = gtk_grid_layout_get_row_homogeneous (GTK_GRID_LAYOUT (priv->layout_manager));
990   if (old_val != !!homogeneous)
991     {
992       gtk_grid_layout_set_row_homogeneous (GTK_GRID_LAYOUT (priv->layout_manager), homogeneous);
993       g_object_notify_by_pspec (G_OBJECT (grid), obj_properties [PROP_ROW_HOMOGENEOUS]);
994     }
995 }
996 
997 /**
998  * gtk_grid_get_row_homogeneous: (attributes org.gtk.Method.get_property=row-homogeneous)
999  * @grid: a `GtkGrid`
1000  *
1001  * Returns whether all rows of @grid have the same height.
1002  *
1003  * Returns: whether all rows of @grid have the same height.
1004  */
1005 gboolean
gtk_grid_get_row_homogeneous(GtkGrid * grid)1006 gtk_grid_get_row_homogeneous (GtkGrid *grid)
1007 {
1008   GtkGridPrivate *priv = gtk_grid_get_instance_private (grid);
1009 
1010   g_return_val_if_fail (GTK_IS_GRID (grid), FALSE);
1011 
1012   return gtk_grid_layout_get_row_homogeneous (GTK_GRID_LAYOUT (priv->layout_manager));
1013 }
1014 
1015 /**
1016  * gtk_grid_set_column_homogeneous: (attributes org.gtk.Method.set_property=column-homogeneous)
1017  * @grid: a `GtkGrid`
1018  * @homogeneous: %TRUE to make columns homogeneous
1019  *
1020  * Sets whether all columns of @grid will have the same width.
1021  */
1022 void
gtk_grid_set_column_homogeneous(GtkGrid * grid,gboolean homogeneous)1023 gtk_grid_set_column_homogeneous (GtkGrid  *grid,
1024                                  gboolean  homogeneous)
1025 {
1026   GtkGridPrivate *priv = gtk_grid_get_instance_private (grid);
1027   gboolean old_val;
1028 
1029   g_return_if_fail (GTK_IS_GRID (grid));
1030 
1031   old_val = gtk_grid_layout_get_column_homogeneous (GTK_GRID_LAYOUT (priv->layout_manager));
1032   if (old_val != !!homogeneous)
1033     {
1034       gtk_grid_layout_set_column_homogeneous (GTK_GRID_LAYOUT (priv->layout_manager), homogeneous);
1035       g_object_notify_by_pspec (G_OBJECT (grid), obj_properties [PROP_COLUMN_HOMOGENEOUS]);
1036     }
1037 }
1038 
1039 /**
1040  * gtk_grid_get_column_homogeneous: (attributes org.gtk.Method.get_property=column-homogeneous)
1041  * @grid: a `GtkGrid`
1042  *
1043  * Returns whether all columns of @grid have the same width.
1044  *
1045  * Returns: whether all columns of @grid have the same width.
1046  */
1047 gboolean
gtk_grid_get_column_homogeneous(GtkGrid * grid)1048 gtk_grid_get_column_homogeneous (GtkGrid *grid)
1049 {
1050   GtkGridPrivate *priv = gtk_grid_get_instance_private (grid);
1051 
1052   g_return_val_if_fail (GTK_IS_GRID (grid), FALSE);
1053 
1054   return gtk_grid_layout_get_column_homogeneous (GTK_GRID_LAYOUT (priv->layout_manager));
1055 }
1056 
1057 /**
1058  * gtk_grid_set_row_spacing: (attributes org.gtk.Method.set_property=row-spacing)
1059  * @grid: a `GtkGrid`
1060  * @spacing: the amount of space to insert between rows
1061  *
1062  * Sets the amount of space between rows of @grid.
1063  */
1064 void
gtk_grid_set_row_spacing(GtkGrid * grid,guint spacing)1065 gtk_grid_set_row_spacing (GtkGrid *grid,
1066                           guint    spacing)
1067 {
1068   GtkGridPrivate *priv = gtk_grid_get_instance_private (grid);
1069   guint old_spacing;
1070 
1071   g_return_if_fail (GTK_IS_GRID (grid));
1072   g_return_if_fail (spacing <= G_MAXINT16);
1073 
1074   old_spacing = gtk_grid_layout_get_row_spacing (GTK_GRID_LAYOUT (priv->layout_manager));
1075   if (old_spacing != spacing)
1076     {
1077       gtk_grid_layout_set_row_spacing (GTK_GRID_LAYOUT (priv->layout_manager), spacing);
1078       g_object_notify_by_pspec (G_OBJECT (grid), obj_properties [PROP_ROW_SPACING]);
1079     }
1080 }
1081 
1082 /**
1083  * gtk_grid_get_row_spacing: (attributes org.gtk.Method.get_property=row-spacing)
1084  * @grid: a `GtkGrid`
1085  *
1086  * Returns the amount of space between the rows of @grid.
1087  *
1088  * Returns: the row spacing of @grid
1089  */
1090 guint
gtk_grid_get_row_spacing(GtkGrid * grid)1091 gtk_grid_get_row_spacing (GtkGrid *grid)
1092 {
1093   GtkGridPrivate *priv = gtk_grid_get_instance_private (grid);
1094 
1095   g_return_val_if_fail (GTK_IS_GRID (grid), 0);
1096 
1097   return gtk_grid_layout_get_row_spacing (GTK_GRID_LAYOUT (priv->layout_manager));
1098 }
1099 
1100 /**
1101  * gtk_grid_set_column_spacing: (attributes org.gtk.Method.set_property=column-spacing)
1102  * @grid: a `GtkGrid`
1103  * @spacing: the amount of space to insert between columns
1104  *
1105  * Sets the amount of space between columns of @grid.
1106  */
1107 void
gtk_grid_set_column_spacing(GtkGrid * grid,guint spacing)1108 gtk_grid_set_column_spacing (GtkGrid *grid,
1109                              guint    spacing)
1110 {
1111   GtkGridPrivate *priv = gtk_grid_get_instance_private (grid);
1112   guint old_spacing;
1113 
1114   g_return_if_fail (GTK_IS_GRID (grid));
1115   g_return_if_fail (spacing <= G_MAXINT16);
1116 
1117   old_spacing = gtk_grid_layout_get_column_spacing (GTK_GRID_LAYOUT (priv->layout_manager));
1118   if (old_spacing != spacing)
1119     {
1120       gtk_grid_layout_set_column_spacing (GTK_GRID_LAYOUT (priv->layout_manager), spacing);
1121       g_object_notify_by_pspec (G_OBJECT (grid), obj_properties [PROP_COLUMN_SPACING]);
1122     }
1123 }
1124 
1125 /**
1126  * gtk_grid_get_column_spacing: (attributes org.gtk.Method.get_property=column-spacing)
1127  * @grid: a `GtkGrid`
1128  *
1129  * Returns the amount of space between the columns of @grid.
1130  *
1131  * Returns: the column spacing of @grid
1132  */
1133 guint
gtk_grid_get_column_spacing(GtkGrid * grid)1134 gtk_grid_get_column_spacing (GtkGrid *grid)
1135 {
1136   GtkGridPrivate *priv = gtk_grid_get_instance_private (grid);
1137 
1138   g_return_val_if_fail (GTK_IS_GRID (grid), 0);
1139 
1140   return gtk_grid_layout_get_column_spacing (GTK_GRID_LAYOUT (priv->layout_manager));
1141 }
1142 
1143 /**
1144  * gtk_grid_set_row_baseline_position:
1145  * @grid: a `GtkGrid`
1146  * @row: a row index
1147  * @pos: a `GtkBaselinePosition`
1148  *
1149  * Sets how the baseline should be positioned on @row of the
1150  * grid, in case that row is assigned more space than is requested.
1151  *
1152  * The default baseline position is %GTK_BASELINE_POSITION_CENTER.
1153  */
1154 void
gtk_grid_set_row_baseline_position(GtkGrid * grid,int row,GtkBaselinePosition pos)1155 gtk_grid_set_row_baseline_position (GtkGrid            *grid,
1156 				    int                 row,
1157 				    GtkBaselinePosition pos)
1158 {
1159   GtkGridPrivate *priv = gtk_grid_get_instance_private (grid);
1160 
1161   g_return_if_fail (GTK_IS_GRID (grid));
1162 
1163   gtk_grid_layout_set_row_baseline_position (GTK_GRID_LAYOUT (priv->layout_manager),
1164                                              row,
1165                                              pos);
1166 }
1167 
1168 /**
1169  * gtk_grid_get_row_baseline_position:
1170  * @grid: a `GtkGrid`
1171  * @row: a row index
1172  *
1173  * Returns the baseline position of @row.
1174  *
1175  * See [method@Gtk.Grid.set_row_baseline_position].
1176  *
1177  * Returns: the baseline position of @row
1178  */
1179 GtkBaselinePosition
gtk_grid_get_row_baseline_position(GtkGrid * grid,int row)1180 gtk_grid_get_row_baseline_position (GtkGrid      *grid,
1181 				    int           row)
1182 {
1183   GtkGridPrivate *priv = gtk_grid_get_instance_private (grid);
1184 
1185   g_return_val_if_fail (GTK_IS_GRID (grid), GTK_BASELINE_POSITION_CENTER);
1186 
1187   return gtk_grid_layout_get_row_baseline_position (GTK_GRID_LAYOUT (priv->layout_manager), row);
1188 }
1189 
1190 /**
1191  * gtk_grid_set_baseline_row: (attributes org.gtk.Method.set_property=baseline-row)
1192  * @grid: a `GtkGrid`
1193  * @row: the row index
1194  *
1195  * Sets which row defines the global baseline for the entire grid.
1196  *
1197  * Each row in the grid can have its own local baseline, but only
1198  * one of those is global, meaning it will be the baseline in the
1199  * parent of the @grid.
1200  */
1201 void
gtk_grid_set_baseline_row(GtkGrid * grid,int row)1202 gtk_grid_set_baseline_row (GtkGrid *grid,
1203 			   int      row)
1204 {
1205   GtkGridPrivate *priv = gtk_grid_get_instance_private (grid);
1206   int old_row;
1207 
1208   g_return_if_fail (GTK_IS_GRID (grid));
1209 
1210   old_row = gtk_grid_layout_get_baseline_row (GTK_GRID_LAYOUT (priv->layout_manager));
1211   if (old_row != row)
1212     {
1213       gtk_grid_layout_set_baseline_row (GTK_GRID_LAYOUT (priv->layout_manager), row);
1214       g_object_notify (G_OBJECT (grid), "baseline-row");
1215     }
1216 }
1217 
1218 /**
1219  * gtk_grid_get_baseline_row: (attributes org.gtk.Method.get_property=baseline-row)
1220  * @grid: a `GtkGrid`
1221  *
1222  * Returns which row defines the global baseline of @grid.
1223  *
1224  * Returns: the row index defining the global baseline
1225  */
1226 int
gtk_grid_get_baseline_row(GtkGrid * grid)1227 gtk_grid_get_baseline_row (GtkGrid *grid)
1228 {
1229   GtkGridPrivate *priv = gtk_grid_get_instance_private (grid);
1230 
1231   g_return_val_if_fail (GTK_IS_GRID (grid), 0);
1232 
1233   return gtk_grid_layout_get_baseline_row (GTK_GRID_LAYOUT (priv->layout_manager));
1234 }
1235 
1236 /**
1237  * gtk_grid_query_child:
1238  * @grid: a `GtkGrid`
1239  * @child: a `GtkWidget` child of @grid
1240  * @column: (out) (optional): the column used to attach the left side of @child
1241  * @row: (out) (optional): the row used to attach the top side of @child
1242  * @width: (out) (optional): the number of columns @child spans
1243  * @height: (out) (optional): the number of rows @child spans
1244  *
1245  * Queries the attach points and spans of @child inside the given `GtkGrid`.
1246  */
1247 void
gtk_grid_query_child(GtkGrid * grid,GtkWidget * child,int * column,int * row,int * width,int * height)1248 gtk_grid_query_child (GtkGrid   *grid,
1249                       GtkWidget *child,
1250                       int       *column,
1251                       int       *row,
1252                       int       *width,
1253                       int       *height)
1254 {
1255   GtkGridPrivate *priv = gtk_grid_get_instance_private (grid);
1256   GtkGridLayoutChild *grid_child;
1257 
1258   g_return_if_fail (GTK_IS_GRID (grid));
1259   g_return_if_fail (GTK_IS_WIDGET (child));
1260   g_return_if_fail (_gtk_widget_get_parent (child) == (GtkWidget *) grid);
1261 
1262   grid_child = GTK_GRID_LAYOUT_CHILD (gtk_layout_manager_get_layout_child (priv->layout_manager, child));
1263 
1264   if (column != NULL)
1265     *column = gtk_grid_layout_child_get_column (grid_child);
1266   if (row != NULL)
1267     *row = gtk_grid_layout_child_get_row (grid_child);
1268   if (width != NULL)
1269     *width = gtk_grid_layout_child_get_column_span (grid_child);
1270   if (height != NULL)
1271     *height = gtk_grid_layout_child_get_row_span (grid_child);
1272 }
1273