Bug Summary

File:ctk/ctkflowbox.c
Warning:line 2643, column 7
Value stored to 'context' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name ctkflowbox.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/rootdir/ctk -resource-dir /usr/lib/llvm-16/lib/clang/16 -D HAVE_CONFIG_H -I . -I .. -D G_LOG_DOMAIN="Ctk" -D G_LOG_USE_STRUCTURED=1 -D CTK_VERSION="3.25.5" -D CTK_BINARY_VERSION="3.0.0" -D CTK_COMPILATION -D CTK_PRINT_BACKEND_ENABLE_UNSUPPORTED -D CTK_LIBDIR="/usr/lib" -D CTK_LOCALEDIR="/usr/share/locale" -D CTK_DATADIR="/usr/share" -D CTK_DATA_PREFIX="/usr" -D CTK_SYSCONFDIR="/usr/etc" -D CTK_HOST="x86_64-pc-linux-gnu" -D CTK_PRINT_BACKENDS="file,cups" -D X11_DATA_PREFIX="/usr" -D ISO_CODES_PREFIX="" -I .. -I ../ctk -I .. -I ../cdk -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -D G_ENABLE_DEBUG -D G_ENABLE_CONSISTENCY_CHECKS -D GLIB_MIN_REQUIRED_VERSION=GLIB_VERSION_2_66 -D GLIB_MAX_ALLOWED_VERSION=GLIB_VERSION_2_66 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/atk-1.0 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/x86_64-linux-gnu -I /usr/include/webp -I /usr/include/at-spi2-atk/2.0 -I /usr/include/at-spi-2.0 -I /usr/include/dbus-1.0 -I /usr/lib/x86_64-linux-gnu/dbus-1.0/include -I /usr/include/gio-unix-2.0 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -I /usr/include/pango-1.0 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/cairo -I /usr/include/pixman-1 -D PIC -internal-isystem /usr/lib/llvm-16/lib/clang/16/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fdebug-compilation-dir=/rootdir/ctk -ferror-limit 19 -fvisibility=hidden -fgnuc-version=4.2.1 -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2024-09-19-172241-43638-1 -x c ctkflowbox.c
1/*
2 * Copyright (C) 2007-2010 Openismus GmbH
3 * Copyright (C) 2013 Red Hat, Inc.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library 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 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
17 *
18 * Authors:
19 * Tristan Van Berkom <tristanvb@openismus.com>
20 * Matthias Clasen <mclasen@redhat.com>
21 * William Jon McCann <jmccann@redhat.com>
22 */
23
24/* Preamble {{{1 */
25
26/**
27 * SECTION:ctkflowbox
28 * @Short_Description: A container that allows reflowing its children
29 * @Title: CtkFlowBox
30 *
31 * A CtkFlowBox positions child widgets in sequence according to its
32 * orientation.
33 *
34 * For instance, with the horizontal orientation, the widgets will be
35 * arranged from left to right, starting a new row under the previous
36 * row when necessary. Reducing the width in this case will require more
37 * rows, so a larger height will be requested.
38 *
39 * Likewise, with the vertical orientation, the widgets will be arranged
40 * from top to bottom, starting a new column to the right when necessary.
41 * Reducing the height will require more columns, so a larger width will
42 * be requested.
43 *
44 * The size request of a CtkFlowBox alone may not be what you expect; if you
45 * need to be able to shrink it along both axes and dynamically reflow its
46 * children, you may have to wrap it in a #CtkScrolledWindow to enable that.
47 *
48 * The children of a CtkFlowBox can be dynamically sorted and filtered.
49 *
50 * Although a CtkFlowBox must have only #CtkFlowBoxChild children,
51 * you can add any kind of widget to it via ctk_container_add(), and
52 * a CtkFlowBoxChild widget will automatically be inserted between
53 * the box and the widget.
54 *
55 * Also see #CtkListBox.
56 *
57 * CtkFlowBox was added in CTK+ 3.12.
58 *
59 * # CSS nodes
60 *
61 * |[<!-- language="plain" -->
62 * flowbox
63 * ├── flowboxchild
64 * │ ╰── <child>
65 * ├── flowboxchild
66 * │ ╰── <child>
67 * ┊
68 * ╰── [rubberband]
69 * ]|
70 *
71 * CtkFlowBox uses a single CSS node with name flowbox. CtkFlowBoxChild
72 * uses a single CSS node with name flowboxchild.
73 * For rubberband selection, a subnode with name rubberband is used.
74 */
75
76#include <config.h>
77
78#include "ctkflowbox.h"
79#include "ctkmarshalers.h"
80#include "ctkprivate.h"
81#include "ctkorientableprivate.h"
82#include "ctkintl.h"
83#include "ctkcssnodeprivate.h"
84#include "ctkwidgetprivate.h"
85#include "ctkstylecontextprivate.h"
86#include "ctkcsscustomgadgetprivate.h"
87#include "ctkcontainerprivate.h"
88
89#include "a11y/ctkflowboxaccessibleprivate.h"
90#include "a11y/ctkflowboxchildaccessible.h"
91
92/* Forward declarations and utilities {{{1 */
93
94static void ctk_flow_box_update_cursor (CtkFlowBox *box,
95 CtkFlowBoxChild *child);
96static void ctk_flow_box_select_and_activate (CtkFlowBox *box,
97 CtkFlowBoxChild *child);
98static void ctk_flow_box_update_selection (CtkFlowBox *box,
99 CtkFlowBoxChild *child,
100 gboolean modify,
101 gboolean extend);
102static void ctk_flow_box_apply_filter (CtkFlowBox *box,
103 CtkFlowBoxChild *child);
104static void ctk_flow_box_apply_sort (CtkFlowBox *box,
105 CtkFlowBoxChild *child);
106static gint ctk_flow_box_sort (CtkFlowBoxChild *a,
107 CtkFlowBoxChild *b,
108 CtkFlowBox *box);
109
110static void ctk_flow_box_bound_model_changed (GListModel *list,
111 guint position,
112 guint removed,
113 guint added,
114 gpointer user_data);
115
116static void ctk_flow_box_check_model_compat (CtkFlowBox *box);
117
118static void
119get_current_selection_modifiers (CtkWidget *widget,
120 gboolean *modify,
121 gboolean *extend)
122{
123 CdkModifierType state = 0;
124 CdkModifierType mask;
125
126 *modify = FALSE(0);
127 *extend = FALSE(0);
128
129 if (ctk_get_current_event_state (&state))
130 {
131 mask = ctk_widget_get_modifier_mask (widget, CDK_MODIFIER_INTENT_MODIFY_SELECTION);
132 if ((state & mask) == mask)
133 *modify = TRUE(!(0));
134 mask = ctk_widget_get_modifier_mask (widget, CDK_MODIFIER_INTENT_EXTEND_SELECTION);
135 if ((state & mask) == mask)
136 *extend = TRUE(!(0));
137 }
138}
139
140static void
141path_from_horizontal_line_rects (cairo_t *cr,
142 CdkRectangle *lines,
143 gint n_lines)
144{
145 gint start_line, end_line;
146 CdkRectangle *r;
147 gint i;
148
149 /* Join rows vertically by extending to the middle */
150 for (i = 0; i < n_lines - 1; i++)
151 {
152 CdkRectangle *r1 = &lines[i];
153 CdkRectangle *r2 = &lines[i+1];
154 gint gap, old;
155
156 gap = r2->y - (r1->y + r1->height);
157 r1->height += gap / 2;
158 old = r2->y;
159 r2->y = r1->y + r1->height;
160 r2->height += old - r2->y;
161 }
162
163 cairo_new_path (cr);
164 start_line = 0;
165
166 do
167 {
168 for (i = start_line; i < n_lines; i++)
169 {
170 r = &lines[i];
171 if (i == start_line)
172 cairo_move_to (cr, r->x + r->width, r->y);
173 else
174 cairo_line_to (cr, r->x + r->width, r->y);
175 cairo_line_to (cr, r->x + r->width, r->y + r->height);
176
177 if (i < n_lines - 1 &&
178 (r->x + r->width < lines[i+1].x ||
179 r->x > lines[i+1].x + lines[i+1].width))
180 {
181 i++;
182 break;
183 }
184 }
185 end_line = i;
186 for (i = end_line - 1; i >= start_line; i--)
187 {
188 r = &lines[i];
189 cairo_line_to (cr, r->x, r->y + r->height);
190 cairo_line_to (cr, r->x, r->y);
191 }
192 cairo_close_path (cr);
193 start_line = end_line;
194 }
195 while (end_line < n_lines);
196}
197
198static void
199path_from_vertical_line_rects (cairo_t *cr,
200 CdkRectangle *lines,
201 gint n_lines)
202{
203 gint start_line, end_line;
204 CdkRectangle *r;
205 gint i;
206
207 /* Join rows horizontally by extending to the middle */
208 for (i = 0; i < n_lines - 1; i++)
209 {
210 CdkRectangle *r1 = &lines[i];
211 CdkRectangle *r2 = &lines[i+1];
212 gint gap, old;
213
214 gap = r2->x - (r1->x + r1->width);
215 r1->width += gap / 2;
216 old = r2->x;
217 r2->x = r1->x + r1->width;
218 r2->width += old - r2->x;
219 }
220
221 cairo_new_path (cr);
222 start_line = 0;
223
224 do
225 {
226 for (i = start_line; i < n_lines; i++)
227 {
228 r = &lines[i];
229 if (i == start_line)
230 cairo_move_to (cr, r->x, r->y + r->height);
231 else
232 cairo_line_to (cr, r->x, r->y + r->height);
233 cairo_line_to (cr, r->x + r->width, r->y + r->height);
234
235 if (i < n_lines - 1 &&
236 (r->y + r->height < lines[i+1].y ||
237 r->y > lines[i+1].y + lines[i+1].height))
238 {
239 i++;
240 break;
241 }
242 }
243 end_line = i;
244 for (i = end_line - 1; i >= start_line; i--)
245 {
246 r = &lines[i];
247 cairo_line_to (cr, r->x + r->width, r->y);
248 cairo_line_to (cr, r->x, r->y);
249 }
250 cairo_close_path (cr);
251 start_line = end_line;
252 }
253 while (end_line < n_lines);
254}
255
256/* CtkFlowBoxChild {{{1 */
257
258/* GObject boilerplate {{{2 */
259
260enum {
261 CHILD_ACTIVATE,
262 CHILD_LAST_SIGNAL
263};
264
265static guint child_signals[CHILD_LAST_SIGNAL] = { 0 };
266
267typedef struct _CtkFlowBoxChildPrivate CtkFlowBoxChildPrivate;
268struct _CtkFlowBoxChildPrivate
269{
270 GSequenceIter *iter;
271 CtkCssGadget *gadget;
272 gboolean selected;
273};
274
275#define CHILD_PRIV(child)((CtkFlowBoxChildPrivate*)ctk_flow_box_child_get_instance_private
((CtkFlowBoxChild*)(child)))
((CtkFlowBoxChildPrivate*)ctk_flow_box_child_get_instance_private ((CtkFlowBoxChild*)(child)))
276
277G_DEFINE_TYPE_WITH_PRIVATE (CtkFlowBoxChild, ctk_flow_box_child, CTK_TYPE_BIN)static void ctk_flow_box_child_init (CtkFlowBoxChild *self); static
void ctk_flow_box_child_class_init (CtkFlowBoxChildClass *klass
); static GType ctk_flow_box_child_get_type_once (void); static
gpointer ctk_flow_box_child_parent_class = ((void*)0); static
gint CtkFlowBoxChild_private_offset; static void ctk_flow_box_child_class_intern_init
(gpointer klass) { ctk_flow_box_child_parent_class = g_type_class_peek_parent
(klass); if (CtkFlowBoxChild_private_offset != 0) g_type_class_adjust_private_offset
(klass, &CtkFlowBoxChild_private_offset); ctk_flow_box_child_class_init
((CtkFlowBoxChildClass*) klass); } __attribute__ ((__unused__
)) static inline gpointer ctk_flow_box_child_get_instance_private
(CtkFlowBoxChild *self) { return (((gpointer) ((guint8*) (self
) + (glong) (CtkFlowBoxChild_private_offset)))); } GType ctk_flow_box_child_get_type
(void) { static GType static_g_define_type_id = 0; if ((__extension__
({ _Static_assert (sizeof *(&static_g_define_type_id) ==
sizeof (gpointer), "Expression evaluates to false"); (void) (
0 ? (gpointer) * (&static_g_define_type_id) : ((void*)0))
; (!(__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id
) == sizeof (gpointer), "Expression evaluates to false"); __typeof__
(*(&static_g_define_type_id)) gapg_temp_newval; __typeof__
((&static_g_define_type_id)) gapg_temp_atomic = (&static_g_define_type_id
); __atomic_load (gapg_temp_atomic, &gapg_temp_newval, 5)
; gapg_temp_newval; })) && g_once_init_enter_pointer (
&static_g_define_type_id)); })) ) { GType g_define_type_id
= ctk_flow_box_child_get_type_once (); (__extension__ ({ _Static_assert
(sizeof *(&static_g_define_type_id) == sizeof (gpointer)
, "Expression evaluates to false"); 0 ? (void) (*(&static_g_define_type_id
) = (g_define_type_id)) : (void) 0; g_once_init_leave_pointer
((&static_g_define_type_id), (gpointer) (guintptr) (g_define_type_id
)); })) ; } return static_g_define_type_id; } __attribute__ (
(__noinline__)) static GType ctk_flow_box_child_get_type_once
(void) { GType g_define_type_id = g_type_register_static_simple
((ctk_bin_get_type ()), g_intern_static_string ("CtkFlowBoxChild"
), sizeof (CtkFlowBoxChildClass), (GClassInitFunc)(void (*)(void
)) ctk_flow_box_child_class_intern_init, sizeof (CtkFlowBoxChild
), (GInstanceInitFunc)(void (*)(void)) ctk_flow_box_child_init
, (GTypeFlags) 0); { {{ CtkFlowBoxChild_private_offset = g_type_add_instance_private
(g_define_type_id, sizeof (CtkFlowBoxChildPrivate)); };} } return
g_define_type_id; }
278
279/* Internal API {{{2 */
280
281static CtkFlowBox *
282ctk_flow_box_child_get_box (CtkFlowBoxChild *child)
283{
284 CtkWidget *parent;
285
286 parent = ctk_widget_get_parent (CTK_WIDGET (child)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((child)), ((ctk_widget_get_type ()))))))
);
287 if (parent && CTK_IS_FLOW_BOX (parent)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(parent)); GType __t = ((ctk_flow_box_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
288 return CTK_FLOW_BOX (parent)((((CtkFlowBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((parent)), ((ctk_flow_box_get_type ()))))))
;
289
290 return NULL((void*)0);
291}
292
293static void
294ctk_flow_box_child_set_focus (CtkFlowBoxChild *child)
295{
296 CtkFlowBox *box = ctk_flow_box_child_get_box (child);
297 gboolean modify;
298 gboolean extend;
299
300 if (box == NULL((void*)0))
301 return;
302
303 get_current_selection_modifiers (CTK_WIDGET (box)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_widget_get_type ()))))))
, &modify, &extend);
304
305 if (modify)
306 ctk_flow_box_update_cursor (box, child);
307 else
308 ctk_flow_box_update_selection (box, child, FALSE(0), FALSE(0));
309}
310
311/* CtkWidget implementation {{{2 */
312
313static gboolean
314ctk_flow_box_child_focus (CtkWidget *widget,
315 CtkDirectionType direction)
316{
317 gboolean had_focus = FALSE(0);
318 CtkWidget *child;
319
320 child = ctk_bin_get_child (CTK_BIN (widget)((((CtkBin*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_bin_get_type ()))))))
);
321
322 /* Without "can-focus" flag try to pass the focus to the child immediately */
323 if (!ctk_widget_get_can_focus (widget))
324 {
325 if (child)
326 {
327 if (ctk_widget_child_focus (child, direction))
328 {
329 CtkFlowBox *box;
330 box = ctk_flow_box_child_get_box (CTK_FLOW_BOX_CHILD (widget)((((CtkFlowBoxChild*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_flow_box_child_get_type ()))))))
);
331 if (box)
332 ctk_flow_box_update_cursor (box, CTK_FLOW_BOX_CHILD (widget)((((CtkFlowBoxChild*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_flow_box_child_get_type ()))))))
);
333 return TRUE(!(0));
334 }
335 }
336 return FALSE(0);
337 }
338
339 g_object_get (widget, "has-focus", &had_focus, NULL((void*)0));
340 if (had_focus)
341 {
342 /* If on row, going right, enter into possible container */
343 if (child &&
344 (direction == CTK_DIR_RIGHT || direction == CTK_DIR_TAB_FORWARD))
345 {
346 if (ctk_widget_child_focus (CTK_WIDGET (child)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((child)), ((ctk_widget_get_type ()))))))
, direction))
347 return TRUE(!(0));
348 }
349
350 return FALSE(0);
351 }
352 else if (ctk_container_get_focus_child (CTK_CONTAINER (widget)((((CtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_container_get_type ()))))))
) != NULL((void*)0))
353 {
354 /* Child has focus, always navigate inside it first */
355 if (ctk_widget_child_focus (child, direction))
356 return TRUE(!(0));
357
358 /* If exiting child container to the left, select child */
359 if (direction == CTK_DIR_LEFT || direction == CTK_DIR_TAB_BACKWARD)
360 {
361 ctk_flow_box_child_set_focus (CTK_FLOW_BOX_CHILD (widget)((((CtkFlowBoxChild*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_flow_box_child_get_type ()))))))
);
362 return TRUE(!(0));
363 }
364
365 return FALSE(0);
366 }
367 else
368 {
369 /* If coming from the left, enter into possible container */
370 if (child &&
371 (direction == CTK_DIR_LEFT || direction == CTK_DIR_TAB_BACKWARD))
372 {
373 if (ctk_widget_child_focus (child, direction))
374 return TRUE(!(0));
375 }
376
377 ctk_flow_box_child_set_focus (CTK_FLOW_BOX_CHILD (widget)((((CtkFlowBoxChild*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_flow_box_child_get_type ()))))))
);
378 return TRUE(!(0));
379 }
380}
381
382static void
383ctk_flow_box_child_activate (CtkFlowBoxChild *child)
384{
385 CtkFlowBox *box;
386
387 box = ctk_flow_box_child_get_box (child);
388 if (box)
389 ctk_flow_box_select_and_activate (box, child);
390}
391
392static gboolean
393ctk_flow_box_child_draw (CtkWidget *widget,
394 cairo_t *cr)
395{
396 ctk_css_gadget_draw (CHILD_PRIV (CTK_FLOW_BOX_CHILD (widget))((CtkFlowBoxChildPrivate*)ctk_flow_box_child_get_instance_private
((CtkFlowBoxChild*)(((((CtkFlowBoxChild*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((widget)), ((ctk_flow_box_child_get_type (
))))))))))
->gadget, cr);
397
398 return FALSE(0);
399}
400
401static gboolean
402ctk_flow_box_child_render (CtkCssGadget *gadget,
403 cairo_t *cr,
404 int x G_GNUC_UNUSED__attribute__ ((__unused__)),
405 int y G_GNUC_UNUSED__attribute__ ((__unused__)),
406 int width G_GNUC_UNUSED__attribute__ ((__unused__)),
407 int height G_GNUC_UNUSED__attribute__ ((__unused__)),
408 gpointer data G_GNUC_UNUSED__attribute__ ((__unused__)))
409{
410 CtkWidget *widget;
411
412 widget = ctk_css_gadget_get_owner (gadget);
413
414 CTK_WIDGET_CLASS (ctk_flow_box_child_parent_class)((((CtkWidgetClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((ctk_flow_box_child_parent_class)), ((ctk_widget_get_type
()))))))
->draw (widget, cr);
415
416 return ctk_widget_has_visible_focus (widget);
417}
418
419/* Size allocation {{{3 */
420
421static CtkSizeRequestMode
422ctk_flow_box_child_get_request_mode (CtkWidget *widget)
423{
424 CtkFlowBox *box;
425
426 box = ctk_flow_box_child_get_box (CTK_FLOW_BOX_CHILD (widget)((((CtkFlowBoxChild*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_flow_box_child_get_type ()))))))
);
427 if (box)
428 return ctk_widget_get_request_mode (CTK_WIDGET (box)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_widget_get_type ()))))))
);
429 else
430 return CTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH;
431}
432
433static void
434ctk_flow_box_child_get_preferred_height (CtkWidget *widget,
435 gint *minimum,
436 gint *natural)
437{
438 ctk_css_gadget_get_preferred_size (CHILD_PRIV (CTK_FLOW_BOX_CHILD (widget))((CtkFlowBoxChildPrivate*)ctk_flow_box_child_get_instance_private
((CtkFlowBoxChild*)(((((CtkFlowBoxChild*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((widget)), ((ctk_flow_box_child_get_type (
))))))))))
->gadget,
439 CTK_ORIENTATION_VERTICAL,
440 -1,
441 minimum, natural,
442 NULL((void*)0), NULL((void*)0));
443}
444
445static void
446ctk_flow_box_child_get_preferred_height_for_width (CtkWidget *widget,
447 gint width,
448 gint *minimum,
449 gint *natural)
450{
451 ctk_css_gadget_get_preferred_size (CHILD_PRIV (CTK_FLOW_BOX_CHILD (widget))((CtkFlowBoxChildPrivate*)ctk_flow_box_child_get_instance_private
((CtkFlowBoxChild*)(((((CtkFlowBoxChild*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((widget)), ((ctk_flow_box_child_get_type (
))))))))))
->gadget,
452 CTK_ORIENTATION_VERTICAL,
453 width,
454 minimum, natural,
455 NULL((void*)0), NULL((void*)0));
456}
457
458static void
459ctk_flow_box_child_get_preferred_width (CtkWidget *widget,
460 gint *minimum,
461 gint *natural)
462{
463 ctk_css_gadget_get_preferred_size (CHILD_PRIV (CTK_FLOW_BOX_CHILD (widget))((CtkFlowBoxChildPrivate*)ctk_flow_box_child_get_instance_private
((CtkFlowBoxChild*)(((((CtkFlowBoxChild*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((widget)), ((ctk_flow_box_child_get_type (
))))))))))
->gadget,
464 CTK_ORIENTATION_HORIZONTAL,
465 -1,
466 minimum, natural,
467 NULL((void*)0), NULL((void*)0));
468}
469
470static void
471ctk_flow_box_child_get_preferred_width_for_height (CtkWidget *widget,
472 gint height,
473 gint *minimum,
474 gint *natural)
475{
476 ctk_css_gadget_get_preferred_size (CHILD_PRIV (CTK_FLOW_BOX_CHILD (widget))((CtkFlowBoxChildPrivate*)ctk_flow_box_child_get_instance_private
((CtkFlowBoxChild*)(((((CtkFlowBoxChild*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((widget)), ((ctk_flow_box_child_get_type (
))))))))))
->gadget,
477 CTK_ORIENTATION_HORIZONTAL,
478 height,
479 minimum, natural,
480 NULL((void*)0), NULL((void*)0));
481}
482
483static void
484ctk_flow_box_child_measure (CtkCssGadget *gadget,
485 CtkOrientation orientation,
486 int for_size,
487 int *minimum,
488 int *natural,
489 int *minimum_baseline G_GNUC_UNUSED__attribute__ ((__unused__)),
490 int *natural_baseline G_GNUC_UNUSED__attribute__ ((__unused__)),
491 gpointer data G_GNUC_UNUSED__attribute__ ((__unused__)))
492{
493 CtkWidget *widget;
494 CtkWidget *child;
495
496 widget = ctk_css_gadget_get_owner (gadget);
497 child = ctk_bin_get_child (CTK_BIN (widget)((((CtkBin*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_bin_get_type ()))))))
);
498 if (!child || ! ctk_widget_get_visible (child))
499 {
500 *minimum = *natural = 0;
501 return;
502 }
503
504 if (orientation == CTK_ORIENTATION_HORIZONTAL)
505 {
506 if (for_size < 0)
507 {
508 if (ctk_flow_box_child_get_request_mode (widget) == CTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH)
509 {
510 ctk_widget_get_preferred_width (child, minimum, natural);
511 }
512 else
513 {
514 gint height;
515 ctk_widget_get_preferred_height (child, NULL((void*)0), &height);
516 ctk_widget_get_preferred_width_for_height (child, height, minimum, natural);
517 }
518 }
519 else
520 {
521 if (ctk_flow_box_child_get_request_mode (widget) == CTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH)
522 ctk_widget_get_preferred_width (child, minimum, natural);
523 else
524 ctk_widget_get_preferred_width_for_height (child, for_size, minimum, natural);
525 }
526 }
527 else
528 {
529 if (for_size < 0)
530 {
531 if (ctk_flow_box_child_get_request_mode (widget) == CTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH)
532 {
533 gint width;
534 ctk_widget_get_preferred_width (child, NULL((void*)0), &width);
535 ctk_widget_get_preferred_height_for_width (child, width, minimum, natural);
536 }
537 else
538 {
539 ctk_widget_get_preferred_height (child, minimum, natural);
540 }
541 }
542 else
543 {
544 if (ctk_flow_box_child_get_request_mode (widget) == CTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH)
545 ctk_widget_get_preferred_height_for_width (child, for_size, minimum, natural);
546 else
547 ctk_widget_get_preferred_height (child, minimum, natural);
548 }
549 }
550}
551
552static void
553ctk_flow_box_child_size_allocate (CtkWidget *widget,
554 CtkAllocation *allocation)
555{
556 CtkAllocation clip;
557
558 ctk_widget_set_allocation (widget, allocation);
559
560 ctk_css_gadget_allocate (CHILD_PRIV (CTK_FLOW_BOX_CHILD (widget))((CtkFlowBoxChildPrivate*)ctk_flow_box_child_get_instance_private
((CtkFlowBoxChild*)(((((CtkFlowBoxChild*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((widget)), ((ctk_flow_box_child_get_type (
))))))))))
->gadget,
561 allocation,
562 ctk_widget_get_allocated_baseline (widget),
563 &clip);
564
565 ctk_widget_set_clip (widget, &clip);
566}
567
568static void
569ctk_flow_box_child_allocate (CtkCssGadget *gadget,
570 const CtkAllocation *allocation,
571 int baseline G_GNUC_UNUSED__attribute__ ((__unused__)),
572 CtkAllocation *out_clip,
573 gpointer data G_GNUC_UNUSED__attribute__ ((__unused__)))
574{
575 CtkWidget *widget;
576 CtkWidget *child;
577
578 widget = ctk_css_gadget_get_owner (gadget);
579
580 child = ctk_bin_get_child (CTK_BIN (widget)((((CtkBin*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_bin_get_type ()))))))
);
581 if (child && ctk_widget_get_visible (child))
582 ctk_widget_size_allocate (child, (CtkAllocation *)allocation);
583
584 ctk_container_get_children_clip (CTK_CONTAINER (widget)((((CtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_container_get_type ()))))))
, out_clip);
585}
586
587/* GObject implementation {{{2 */
588
589static void
590ctk_flow_box_child_finalize (GObject *object)
591{
592 g_clear_object (&CHILD_PRIV (CTK_FLOW_BOX_CHILD (object))->gadget)do { _Static_assert (sizeof *((&((CtkFlowBoxChildPrivate*
)ctk_flow_box_child_get_instance_private ((CtkFlowBoxChild*)(
((((CtkFlowBoxChild*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((object)), ((ctk_flow_box_child_get_type ())))))))))->
gadget)) == sizeof (gpointer), "Expression evaluates to false"
); __typeof__ (((&((CtkFlowBoxChildPrivate*)ctk_flow_box_child_get_instance_private
((CtkFlowBoxChild*)(((((CtkFlowBoxChild*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((object)), ((ctk_flow_box_child_get_type (
))))))))))->gadget))) _pp = ((&((CtkFlowBoxChildPrivate
*)ctk_flow_box_child_get_instance_private ((CtkFlowBoxChild*)
(((((CtkFlowBoxChild*) (void *) g_type_check_instance_cast ((
GTypeInstance*) ((object)), ((ctk_flow_box_child_get_type ())
))))))))->gadget)); __typeof__ (*((&((CtkFlowBoxChildPrivate
*)ctk_flow_box_child_get_instance_private ((CtkFlowBoxChild*)
(((((CtkFlowBoxChild*) (void *) g_type_check_instance_cast ((
GTypeInstance*) ((object)), ((ctk_flow_box_child_get_type ())
))))))))->gadget))) _ptr = *_pp; *_pp = ((void*)0); if (_ptr
) (g_object_unref) (_ptr); } while (0)
;
593
594 G_OBJECT_CLASS (ctk_flow_box_child_parent_class)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((ctk_flow_box_child_parent_class)), (((GType) ((20) <<
(2))))))))
->finalize (object);
595}
596
597static void
598ctk_flow_box_child_class_init (CtkFlowBoxChildClass *class)
599{
600 GObjectClass *object_class = G_OBJECT_CLASS (class)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((class)), (((GType) ((20) << (2))))))))
;
601 CtkWidgetClass *widget_class = CTK_WIDGET_CLASS (class)((((CtkWidgetClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((class)), ((ctk_widget_get_type ()))))))
;
602
603 object_class->finalize = ctk_flow_box_child_finalize;
604
605 widget_class->draw = ctk_flow_box_child_draw;
606 widget_class->get_request_mode = ctk_flow_box_child_get_request_mode;
607 widget_class->get_preferred_height = ctk_flow_box_child_get_preferred_height;
608 widget_class->get_preferred_height_for_width = ctk_flow_box_child_get_preferred_height_for_width;
609 widget_class->get_preferred_width = ctk_flow_box_child_get_preferred_width;
610 widget_class->get_preferred_width_for_height = ctk_flow_box_child_get_preferred_width_for_height;
611 widget_class->size_allocate = ctk_flow_box_child_size_allocate;
612 widget_class->focus = ctk_flow_box_child_focus;
613
614 class->activate = ctk_flow_box_child_activate;
615
616 /**
617 * CtkFlowBoxChild::activate:
618 * @child: The child on which the signal is emitted
619 *
620 * The ::activate signal is emitted when the user activates
621 * a child widget in a #CtkFlowBox, either by clicking or
622 * double-clicking, or by using the Space or Enter key.
623 *
624 * While this signal is used as a
625 * [keybinding signal][CtkBindingSignal],
626 * it can be used by applications for their own purposes.
627 */
628 child_signals[CHILD_ACTIVATE] =
629 g_signal_new (I_("activate")g_intern_static_string ("activate"),
630 G_OBJECT_CLASS_TYPE (object_class)((((GTypeClass*) (object_class))->g_type)),
631 G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
632 G_STRUCT_OFFSET (CtkFlowBoxChildClass, activate)((glong) __builtin_offsetof(CtkFlowBoxChildClass, activate)),
633 NULL((void*)0), NULL((void*)0),
634 NULL((void*)0),
635 G_TYPE_NONE((GType) ((1) << (2))), 0);
636 widget_class->activate_signal = child_signals[CHILD_ACTIVATE];
637
638 ctk_widget_class_set_accessible_role (widget_class, ATK_ROLE_LIST_ITEM);
639 ctk_widget_class_set_css_name (widget_class, "flowboxchild");
640}
641
642static void
643ctk_flow_box_child_init (CtkFlowBoxChild *child)
644{
645 ctk_widget_set_can_focus (CTK_WIDGET (child)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((child)), ((ctk_widget_get_type ()))))))
, TRUE(!(0)));
646
647 CHILD_PRIV (child)((CtkFlowBoxChildPrivate*)ctk_flow_box_child_get_instance_private
((CtkFlowBoxChild*)(child)))
->gadget = ctk_css_custom_gadget_new_for_node (ctk_widget_get_css_node (CTK_WIDGET (child)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((child)), ((ctk_widget_get_type ()))))))
),
648 CTK_WIDGET (child)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((child)), ((ctk_widget_get_type ()))))))
,
649 ctk_flow_box_child_measure,
650 ctk_flow_box_child_allocate,
651 ctk_flow_box_child_render,
652 NULL((void*)0),
653 NULL((void*)0));
654}
655
656/* Public API {{{2 */
657
658/**
659 * ctk_flow_box_child_new:
660 *
661 * Creates a new #CtkFlowBoxChild, to be used as a child
662 * of a #CtkFlowBox.
663 *
664 * Returns: a new #CtkFlowBoxChild
665 *
666 * Since: 3.12
667 */
668CtkWidget *
669ctk_flow_box_child_new (void)
670{
671 return g_object_new (CTK_TYPE_FLOW_BOX_CHILD(ctk_flow_box_child_get_type ()), NULL((void*)0));
672}
673
674/**
675 * ctk_flow_box_child_get_index:
676 * @child: a #CtkFlowBoxChild
677 *
678 * Gets the current index of the @child in its #CtkFlowBox container.
679 *
680 * Returns: the index of the @child, or -1 if the @child is not
681 * in a flow box.
682 *
683 * Since: 3.12
684 */
685gint
686ctk_flow_box_child_get_index (CtkFlowBoxChild *child)
687{
688 CtkFlowBoxChildPrivate *priv;
689
690 g_return_val_if_fail (CTK_IS_FLOW_BOX_CHILD (child), -1)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((child)); GType __t = ((ctk_flow_box_child_get_type ()));
gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class
&& __inst->g_class->g_type == __t) __r = (!(0)
); else __r = g_type_check_instance_is_a (__inst, __t); __r; }
)))))) { } else { g_return_if_fail_warning ("Ctk", ((const char
*) (__func__)), "CTK_IS_FLOW_BOX_CHILD (child)"); return (-1)
; } } while (0)
;
691
692 priv = CHILD_PRIV (child)((CtkFlowBoxChildPrivate*)ctk_flow_box_child_get_instance_private
((CtkFlowBoxChild*)(child)))
;
693
694 if (priv->iter != NULL((void*)0))
695 return g_sequence_iter_get_position (priv->iter);
696
697 return -1;
698}
699
700/**
701 * ctk_flow_box_child_is_selected:
702 * @child: a #CtkFlowBoxChild
703 *
704 * Returns whether the @child is currently selected in its
705 * #CtkFlowBox container.
706 *
707 * Returns: %TRUE if @child is selected
708 *
709 * Since: 3.12
710 */
711gboolean
712ctk_flow_box_child_is_selected (CtkFlowBoxChild *child)
713{
714 g_return_val_if_fail (CTK_IS_FLOW_BOX_CHILD (child), FALSE)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((child)); GType __t = ((ctk_flow_box_child_get_type ()));
gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class
&& __inst->g_class->g_type == __t) __r = (!(0)
); else __r = g_type_check_instance_is_a (__inst, __t); __r; }
)))))) { } else { g_return_if_fail_warning ("Ctk", ((const char
*) (__func__)), "CTK_IS_FLOW_BOX_CHILD (child)"); return ((0)
); } } while (0)
;
715
716 return CHILD_PRIV (child)((CtkFlowBoxChildPrivate*)ctk_flow_box_child_get_instance_private
((CtkFlowBoxChild*)(child)))
->selected;
717}
718
719/**
720 * ctk_flow_box_child_changed:
721 * @child: a #CtkFlowBoxChild
722 *
723 * Marks @child as changed, causing any state that depends on this
724 * to be updated. This affects sorting and filtering.
725 *
726 * Note that calls to this method must be in sync with the data
727 * used for the sorting and filtering functions. For instance, if
728 * the list is mirroring some external data set, and *two* children
729 * changed in the external data set when you call
730 * ctk_flow_box_child_changed() on the first child, the sort function
731 * must only read the new data for the first of the two changed
732 * children, otherwise the resorting of the children will be wrong.
733 *
734 * This generally means that if you don’t fully control the data
735 * model, you have to duplicate the data that affects the sorting
736 * and filtering functions into the widgets themselves. Another
737 * alternative is to call ctk_flow_box_invalidate_sort() on any
738 * model change, but that is more expensive.
739 *
740 * Since: 3.12
741 */
742void
743ctk_flow_box_child_changed (CtkFlowBoxChild *child)
744{
745 CtkFlowBox *box;
746
747 g_return_if_fail (CTK_IS_FLOW_BOX_CHILD (child))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((child)); GType __t = ((ctk_flow_box_child_get_type ()));
gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class
&& __inst->g_class->g_type == __t) __r = (!(0)
); else __r = g_type_check_instance_is_a (__inst, __t); __r; }
)))))) { } else { g_return_if_fail_warning ("Ctk", ((const char
*) (__func__)), "CTK_IS_FLOW_BOX_CHILD (child)"); return; } }
while (0)
;
748
749 box = ctk_flow_box_child_get_box (child);
750
751 if (box == NULL((void*)0))
752 return;
753
754 ctk_flow_box_apply_sort (box, child);
755 ctk_flow_box_apply_filter (box, child);
756}
757
758/* CtkFlowBox {{{1 */
759
760/* Constants {{{2 */
761
762#define DEFAULT_MAX_CHILDREN_PER_LINE7 7
763#define RUBBERBAND_START_DISTANCE32 32
764#define AUTOSCROLL_FAST_DISTANCE32 32
765#define AUTOSCROLL_FACTOR20 20
766#define AUTOSCROLL_FACTOR_FAST10 10
767
768/* GObject boilerplate {{{2 */
769
770enum {
771 CHILD_ACTIVATED,
772 SELECTED_CHILDREN_CHANGED,
773 ACTIVATE_CURSOR_CHILD,
774 TOGGLE_CURSOR_CHILD,
775 MOVE_CURSOR,
776 SELECT_ALL,
777 UNSELECT_ALL,
778 LAST_SIGNAL
779};
780
781static guint signals[LAST_SIGNAL] = { 0 };
782
783enum {
784 PROP_0,
785 PROP_HOMOGENEOUS,
786 PROP_COLUMN_SPACING,
787 PROP_ROW_SPACING,
788 PROP_MIN_CHILDREN_PER_LINE,
789 PROP_MAX_CHILDREN_PER_LINE,
790 PROP_SELECTION_MODE,
791 PROP_ACTIVATE_ON_SINGLE_CLICK,
792
793 /* orientable */
794 PROP_ORIENTATION,
795 LAST_PROP = PROP_ORIENTATION
796};
797
798static GParamSpec *props[LAST_PROP] = { NULL((void*)0), };
799
800typedef struct _CtkFlowBoxPrivate CtkFlowBoxPrivate;
801struct _CtkFlowBoxPrivate {
802 CtkOrientation orientation;
803 gboolean homogeneous;
804
805 guint row_spacing;
806 guint column_spacing;
807
808 CtkFlowBoxChild *cursor_child;
809 CtkFlowBoxChild *selected_child;
810
811 gboolean active_child_active;
812 CtkFlowBoxChild *active_child;
813
814 CtkSelectionMode selection_mode;
815
816 CtkAdjustment *hadjustment;
817 CtkAdjustment *vadjustment;
818 gboolean activate_on_single_click;
819
820 guint16 min_children_per_line;
821 guint16 max_children_per_line;
822 guint16 cur_children_per_line;
823
824 GSequence *children;
825
826 CtkCssGadget *gadget;
827 CtkFlowBoxFilterFunc filter_func;
828 gpointer filter_data;
829 GDestroyNotify filter_destroy;
830
831 CtkFlowBoxSortFunc sort_func;
832 gpointer sort_data;
833 GDestroyNotify sort_destroy;
834
835 CtkGesture *multipress_gesture;
836 CtkGesture *drag_gesture;
837
838 CtkFlowBoxChild *rubberband_first;
839 CtkFlowBoxChild *rubberband_last;
840 CtkCssNode *rubberband_node;
841 gboolean rubberband_select;
842 gboolean rubberband_modify;
843 gboolean rubberband_extend;
844
845 CtkScrollType autoscroll_mode;
846 guint autoscroll_id;
847
848 GListModel *bound_model;
849 CtkFlowBoxCreateWidgetFunc create_widget_func;
850 gpointer create_widget_func_data;
851 GDestroyNotify create_widget_func_data_destroy;
852};
853
854#define BOX_PRIV(box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox*)(box)))
855
856G_DEFINE_TYPE_WITH_CODE (CtkFlowBox, ctk_flow_box, CTK_TYPE_CONTAINER,static void ctk_flow_box_init (CtkFlowBox *self); static void
ctk_flow_box_class_init (CtkFlowBoxClass *klass); static GType
ctk_flow_box_get_type_once (void); static gpointer ctk_flow_box_parent_class
= ((void*)0); static gint CtkFlowBox_private_offset; static void
ctk_flow_box_class_intern_init (gpointer klass) { ctk_flow_box_parent_class
= g_type_class_peek_parent (klass); if (CtkFlowBox_private_offset
!= 0) g_type_class_adjust_private_offset (klass, &CtkFlowBox_private_offset
); ctk_flow_box_class_init ((CtkFlowBoxClass*) klass); } __attribute__
((__unused__)) static inline gpointer ctk_flow_box_get_instance_private
(CtkFlowBox *self) { return (((gpointer) ((guint8*) (self) +
(glong) (CtkFlowBox_private_offset)))); } GType ctk_flow_box_get_type
(void) { static GType static_g_define_type_id = 0; if ((__extension__
({ _Static_assert (sizeof *(&static_g_define_type_id) ==
sizeof (gpointer), "Expression evaluates to false"); (void) (
0 ? (gpointer) * (&static_g_define_type_id) : ((void*)0))
; (!(__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id
) == sizeof (gpointer), "Expression evaluates to false"); __typeof__
(*(&static_g_define_type_id)) gapg_temp_newval; __typeof__
((&static_g_define_type_id)) gapg_temp_atomic = (&static_g_define_type_id
); __atomic_load (gapg_temp_atomic, &gapg_temp_newval, 5)
; gapg_temp_newval; })) && g_once_init_enter_pointer (
&static_g_define_type_id)); })) ) { GType g_define_type_id
= ctk_flow_box_get_type_once (); (__extension__ ({ _Static_assert
(sizeof *(&static_g_define_type_id) == sizeof (gpointer)
, "Expression evaluates to false"); 0 ? (void) (*(&static_g_define_type_id
) = (g_define_type_id)) : (void) 0; g_once_init_leave_pointer
((&static_g_define_type_id), (gpointer) (guintptr) (g_define_type_id
)); })) ; } return static_g_define_type_id; } __attribute__ (
(__noinline__)) static GType ctk_flow_box_get_type_once (void
) { GType g_define_type_id = g_type_register_static_simple ((
ctk_container_get_type ()), g_intern_static_string ("CtkFlowBox"
), sizeof (CtkFlowBoxClass), (GClassInitFunc)(void (*)(void))
ctk_flow_box_class_intern_init, sizeof (CtkFlowBox), (GInstanceInitFunc
)(void (*)(void)) ctk_flow_box_init, (GTypeFlags) 0); { {{ CtkFlowBox_private_offset
= g_type_add_instance_private (g_define_type_id, sizeof (CtkFlowBoxPrivate
)); } { const GInterfaceInfo g_implement_interface_info = { (
GInterfaceInitFunc)(void (*)(void)) ((void*)0), ((void*)0), (
(void*)0) }; g_type_add_interface_static (g_define_type_id, (
ctk_orientable_get_type ()), &g_implement_interface_info)
; };} } return g_define_type_id; }
857 G_ADD_PRIVATE (CtkFlowBox)static void ctk_flow_box_init (CtkFlowBox *self); static void
ctk_flow_box_class_init (CtkFlowBoxClass *klass); static GType
ctk_flow_box_get_type_once (void); static gpointer ctk_flow_box_parent_class
= ((void*)0); static gint CtkFlowBox_private_offset; static void
ctk_flow_box_class_intern_init (gpointer klass) { ctk_flow_box_parent_class
= g_type_class_peek_parent (klass); if (CtkFlowBox_private_offset
!= 0) g_type_class_adjust_private_offset (klass, &CtkFlowBox_private_offset
); ctk_flow_box_class_init ((CtkFlowBoxClass*) klass); } __attribute__
((__unused__)) static inline gpointer ctk_flow_box_get_instance_private
(CtkFlowBox *self) { return (((gpointer) ((guint8*) (self) +
(glong) (CtkFlowBox_private_offset)))); } GType ctk_flow_box_get_type
(void) { static GType static_g_define_type_id = 0; if ((__extension__
({ _Static_assert (sizeof *(&static_g_define_type_id) ==
sizeof (gpointer), "Expression evaluates to false"); (void) (
0 ? (gpointer) * (&static_g_define_type_id) : ((void*)0))
; (!(__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id
) == sizeof (gpointer), "Expression evaluates to false"); __typeof__
(*(&static_g_define_type_id)) gapg_temp_newval; __typeof__
((&static_g_define_type_id)) gapg_temp_atomic = (&static_g_define_type_id
); __atomic_load (gapg_temp_atomic, &gapg_temp_newval, 5)
; gapg_temp_newval; })) && g_once_init_enter_pointer (
&static_g_define_type_id)); })) ) { GType g_define_type_id
= ctk_flow_box_get_type_once (); (__extension__ ({ _Static_assert
(sizeof *(&static_g_define_type_id) == sizeof (gpointer)
, "Expression evaluates to false"); 0 ? (void) (*(&static_g_define_type_id
) = (g_define_type_id)) : (void) 0; g_once_init_leave_pointer
((&static_g_define_type_id), (gpointer) (guintptr) (g_define_type_id
)); })) ; } return static_g_define_type_id; } __attribute__ (
(__noinline__)) static GType ctk_flow_box_get_type_once (void
) { GType g_define_type_id = g_type_register_static_simple ((
ctk_container_get_type ()), g_intern_static_string ("CtkFlowBox"
), sizeof (CtkFlowBoxClass), (GClassInitFunc)(void (*)(void))
ctk_flow_box_class_intern_init, sizeof (CtkFlowBox), (GInstanceInitFunc
)(void (*)(void)) ctk_flow_box_init, (GTypeFlags) 0); { {{ CtkFlowBox_private_offset
= g_type_add_instance_private (g_define_type_id, sizeof (CtkFlowBoxPrivate
)); } { const GInterfaceInfo g_implement_interface_info = { (
GInterfaceInitFunc)(void (*)(void)) ((void*)0), ((void*)0), (
(void*)0) }; g_type_add_interface_static (g_define_type_id, (
ctk_orientable_get_type ()), &g_implement_interface_info)
; };} } return g_define_type_id; }
858 G_IMPLEMENT_INTERFACE (CTK_TYPE_ORIENTABLE, NULL))static void ctk_flow_box_init (CtkFlowBox *self); static void
ctk_flow_box_class_init (CtkFlowBoxClass *klass); static GType
ctk_flow_box_get_type_once (void); static gpointer ctk_flow_box_parent_class
= ((void*)0); static gint CtkFlowBox_private_offset; static void
ctk_flow_box_class_intern_init (gpointer klass) { ctk_flow_box_parent_class
= g_type_class_peek_parent (klass); if (CtkFlowBox_private_offset
!= 0) g_type_class_adjust_private_offset (klass, &CtkFlowBox_private_offset
); ctk_flow_box_class_init ((CtkFlowBoxClass*) klass); } __attribute__
((__unused__)) static inline gpointer ctk_flow_box_get_instance_private
(CtkFlowBox *self) { return (((gpointer) ((guint8*) (self) +
(glong) (CtkFlowBox_private_offset)))); } GType ctk_flow_box_get_type
(void) { static GType static_g_define_type_id = 0; if ((__extension__
({ _Static_assert (sizeof *(&static_g_define_type_id) ==
sizeof (gpointer), "Expression evaluates to false"); (void) (
0 ? (gpointer) * (&static_g_define_type_id) : ((void*)0))
; (!(__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id
) == sizeof (gpointer), "Expression evaluates to false"); __typeof__
(*(&static_g_define_type_id)) gapg_temp_newval; __typeof__
((&static_g_define_type_id)) gapg_temp_atomic = (&static_g_define_type_id
); __atomic_load (gapg_temp_atomic, &gapg_temp_newval, 5)
; gapg_temp_newval; })) && g_once_init_enter_pointer (
&static_g_define_type_id)); })) ) { GType g_define_type_id
= ctk_flow_box_get_type_once (); (__extension__ ({ _Static_assert
(sizeof *(&static_g_define_type_id) == sizeof (gpointer)
, "Expression evaluates to false"); 0 ? (void) (*(&static_g_define_type_id
) = (g_define_type_id)) : (void) 0; g_once_init_leave_pointer
((&static_g_define_type_id), (gpointer) (guintptr) (g_define_type_id
)); })) ; } return static_g_define_type_id; } __attribute__ (
(__noinline__)) static GType ctk_flow_box_get_type_once (void
) { GType g_define_type_id = g_type_register_static_simple ((
ctk_container_get_type ()), g_intern_static_string ("CtkFlowBox"
), sizeof (CtkFlowBoxClass), (GClassInitFunc)(void (*)(void))
ctk_flow_box_class_intern_init, sizeof (CtkFlowBox), (GInstanceInitFunc
)(void (*)(void)) ctk_flow_box_init, (GTypeFlags) 0); { {{ CtkFlowBox_private_offset
= g_type_add_instance_private (g_define_type_id, sizeof (CtkFlowBoxPrivate
)); } { const GInterfaceInfo g_implement_interface_info = { (
GInterfaceInitFunc)(void (*)(void)) ((void*)0), ((void*)0), (
(void*)0) }; g_type_add_interface_static (g_define_type_id, (
ctk_orientable_get_type ()), &g_implement_interface_info)
; };} } return g_define_type_id; }
859
860/* Internal API, utilities {{{2 */
861
862#define ORIENTATION_ALIGN(box)(((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))->orientation == CTK_ORIENTATION_HORIZONTAL ? ctk_widget_get_halign
(((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_widget_get_type ()))))))) : ctk_widget_get_valign
(((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_widget_get_type ()))))))))
\
863 (BOX_PRIV(box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
->orientation == CTK_ORIENTATION_HORIZONTAL \
864 ? ctk_widget_get_halign (CTK_WIDGET (box)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_widget_get_type ()))))))
) \
865 : ctk_widget_get_valign (CTK_WIDGET (box)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_widget_get_type ()))))))
))
866
867#define OPPOSING_ORIENTATION_ALIGN(box)(((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))->orientation == CTK_ORIENTATION_HORIZONTAL ? ctk_widget_get_valign
(((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_widget_get_type ()))))))) : ctk_widget_get_halign
(((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_widget_get_type ()))))))))
\
868 (BOX_PRIV(box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
->orientation == CTK_ORIENTATION_HORIZONTAL \
869 ? ctk_widget_get_valign (CTK_WIDGET (box)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_widget_get_type ()))))))
) \
870 : ctk_widget_get_halign (CTK_WIDGET (box)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_widget_get_type ()))))))
))
871
872/* Children are visible if they are shown by the app (visible)
873 * and not filtered out (child_visible) by the box
874 */
875static inline gboolean
876child_is_visible (CtkWidget *child)
877{
878 return ctk_widget_get_visible (child) &&
879 ctk_widget_get_child_visible (child);
880}
881
882static gint
883get_visible_children (CtkFlowBox *box)
884{
885 GSequenceIter *iter;
886 gint i = 0;
887
888 for (iter = g_sequence_get_begin_iter (BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
->children);
889 !g_sequence_iter_is_end (iter);
890 iter = g_sequence_iter_next (iter))
891 {
892 CtkWidget *child;
893
894 child = g_sequence_get (iter);
895 if (child_is_visible (child))
896 i++;
897 }
898
899 return i;
900}
901
902static void
903ctk_flow_box_update_active (CtkFlowBox *box,
904 CtkFlowBoxChild *child)
905{
906 CtkFlowBoxPrivate *priv = BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
;
907 gboolean val;
908
909 val = priv->active_child == child;
910 if (priv->active_child != NULL((void*)0) &&
911 val != priv->active_child_active)
912 {
913 priv->active_child_active = val;
914 ctk_widget_queue_draw (CTK_WIDGET (box)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_widget_get_type ()))))))
);
915 }
916}
917
918static void
919ctk_flow_box_apply_filter (CtkFlowBox *box,
920 CtkFlowBoxChild *child)
921{
922 CtkFlowBoxPrivate *priv = BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
;
923 gboolean do_show;
924
925 do_show = TRUE(!(0));
926 if (priv->filter_func != NULL((void*)0))
927 do_show = priv->filter_func (child, priv->filter_data);
928
929 ctk_widget_set_child_visible (CTK_WIDGET (child)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((child)), ((ctk_widget_get_type ()))))))
, do_show);
930}
931
932static void
933ctk_flow_box_apply_filter_all (CtkFlowBox *box)
934{
935 GSequenceIter *iter;
936
937 for (iter = g_sequence_get_begin_iter (BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
->children);
938 !g_sequence_iter_is_end (iter);
939 iter = g_sequence_iter_next (iter))
940 {
941 CtkFlowBoxChild *child;
942
943 child = g_sequence_get (iter);
944 ctk_flow_box_apply_filter (box, child);
945 }
946 ctk_widget_queue_resize (CTK_WIDGET (box)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_widget_get_type ()))))))
);
947}
948
949static void
950ctk_flow_box_apply_sort (CtkFlowBox *box,
951 CtkFlowBoxChild *child)
952{
953 if (BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
->sort_func != NULL((void*)0))
954 {
955 g_sequence_sort_changed (CHILD_PRIV (child)((CtkFlowBoxChildPrivate*)ctk_flow_box_child_get_instance_private
((CtkFlowBoxChild*)(child)))
->iter,
956 (GCompareDataFunc)ctk_flow_box_sort, box);
957 ctk_widget_queue_resize (CTK_WIDGET (box)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_widget_get_type ()))))))
);
958 }
959}
960
961/* Selection utilities {{{3 */
962
963static gboolean
964ctk_flow_box_child_set_selected (CtkFlowBoxChild *child,
965 gboolean selected)
966{
967 if (CHILD_PRIV (child)((CtkFlowBoxChildPrivate*)ctk_flow_box_child_get_instance_private
((CtkFlowBoxChild*)(child)))
->selected != selected)
968 {
969 CHILD_PRIV (child)((CtkFlowBoxChildPrivate*)ctk_flow_box_child_get_instance_private
((CtkFlowBoxChild*)(child)))
->selected = selected;
970 if (selected)
971 ctk_widget_set_state_flags (CTK_WIDGET (child)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((child)), ((ctk_widget_get_type ()))))))
,
972 CTK_STATE_FLAG_SELECTED, FALSE(0));
973 else
974 ctk_widget_unset_state_flags (CTK_WIDGET (child)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((child)), ((ctk_widget_get_type ()))))))
,
975 CTK_STATE_FLAG_SELECTED);
976
977 return TRUE(!(0));
978 }
979
980 return FALSE(0);
981}
982
983static gboolean
984ctk_flow_box_unselect_all_internal (CtkFlowBox *box)
985{
986 CtkFlowBoxChild *child;
987 GSequenceIter *iter;
988 gboolean dirty = FALSE(0);
989
990 if (BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
->selection_mode == CTK_SELECTION_NONE)
991 return FALSE(0);
992
993 for (iter = g_sequence_get_begin_iter (BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
->children);
994 !g_sequence_iter_is_end (iter);
995 iter = g_sequence_iter_next (iter))
996 {
997 child = g_sequence_get (iter);
998 dirty |= ctk_flow_box_child_set_selected (child, FALSE(0));
999 }
1000
1001 return dirty;
1002}
1003
1004static void
1005ctk_flow_box_unselect_child_internal (CtkFlowBox *box,
1006 CtkFlowBoxChild *child)
1007{
1008 if (!CHILD_PRIV (child)((CtkFlowBoxChildPrivate*)ctk_flow_box_child_get_instance_private
((CtkFlowBoxChild*)(child)))
->selected)
1009 return;
1010
1011 if (BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
->selection_mode == CTK_SELECTION_NONE)
1012 return;
1013 else if (BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
->selection_mode != CTK_SELECTION_MULTIPLE)
1014 ctk_flow_box_unselect_all_internal (box);
1015 else
1016 ctk_flow_box_child_set_selected (child, FALSE(0));
1017
1018 g_signal_emit (box, signals[SELECTED_CHILDREN_CHANGED], 0);
1019}
1020
1021static void
1022ctk_flow_box_update_cursor (CtkFlowBox *box,
1023 CtkFlowBoxChild *child)
1024{
1025 BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
->cursor_child = child;
1026 ctk_widget_grab_focus (CTK_WIDGET (child)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((child)), ((ctk_widget_get_type ()))))))
);
1027 ctk_widget_queue_draw (CTK_WIDGET (child)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((child)), ((ctk_widget_get_type ()))))))
);
1028 _ctk_flow_box_accessible_update_cursor (CTK_WIDGET (box)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_widget_get_type ()))))))
, CTK_WIDGET (child)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((child)), ((ctk_widget_get_type ()))))))
);
1029}
1030
1031static void
1032ctk_flow_box_select_child_internal (CtkFlowBox *box,
1033 CtkFlowBoxChild *child)
1034{
1035 if (CHILD_PRIV (child)((CtkFlowBoxChildPrivate*)ctk_flow_box_child_get_instance_private
((CtkFlowBoxChild*)(child)))
->selected)
1036 return;
1037
1038 if (BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
->selection_mode == CTK_SELECTION_NONE)
1039 return;
1040 if (BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
->selection_mode != CTK_SELECTION_MULTIPLE)
1041 ctk_flow_box_unselect_all_internal (box);
1042
1043 ctk_flow_box_child_set_selected (child, TRUE(!(0)));
1044 BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
->selected_child = child;
1045
1046 g_signal_emit (box, signals[SELECTED_CHILDREN_CHANGED], 0);
1047}
1048
1049static void
1050ctk_flow_box_select_all_between (CtkFlowBox *box,
1051 CtkFlowBoxChild *child1,
1052 CtkFlowBoxChild *child2,
1053 gboolean modify)
1054{
1055 GSequenceIter *iter, *iter1, *iter2;
1056
1057 if (child1)
1058 iter1 = CHILD_PRIV (child1)((CtkFlowBoxChildPrivate*)ctk_flow_box_child_get_instance_private
((CtkFlowBoxChild*)(child1)))
->iter;
1059 else
1060 iter1 = g_sequence_get_begin_iter (BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
->children);
1061
1062 if (child2)
1063 iter2 = CHILD_PRIV (child2)((CtkFlowBoxChildPrivate*)ctk_flow_box_child_get_instance_private
((CtkFlowBoxChild*)(child2)))
->iter;
1064 else
1065 iter2 = g_sequence_get_end_iter (BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
->children);
1066
1067 if (g_sequence_iter_compare (iter2, iter1) < 0)
1068 {
1069 iter = iter1;
1070 iter1 = iter2;
1071 iter2 = iter;
1072 }
1073
1074 for (iter = iter1;
1075 !g_sequence_iter_is_end (iter);
1076 iter = g_sequence_iter_next (iter))
1077 {
1078 CtkWidget *child;
1079
1080 child = g_sequence_get (iter);
1081 if (child_is_visible (child))
1082 {
1083 if (modify)
1084 ctk_flow_box_child_set_selected (CTK_FLOW_BOX_CHILD (child)((((CtkFlowBoxChild*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((child)), ((ctk_flow_box_child_get_type ()))))))
, !CHILD_PRIV (child)((CtkFlowBoxChildPrivate*)ctk_flow_box_child_get_instance_private
((CtkFlowBoxChild*)(child)))
->selected);
1085 else
1086 ctk_flow_box_child_set_selected (CTK_FLOW_BOX_CHILD (child)((((CtkFlowBoxChild*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((child)), ((ctk_flow_box_child_get_type ()))))))
, TRUE(!(0)));
1087 }
1088
1089 if (g_sequence_iter_compare (iter, iter2) == 0)
1090 break;
1091 }
1092}
1093
1094static void
1095ctk_flow_box_update_selection (CtkFlowBox *box,
1096 CtkFlowBoxChild *child,
1097 gboolean modify,
1098 gboolean extend)
1099{
1100 CtkFlowBoxPrivate *priv = BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
;
1101
1102 ctk_flow_box_update_cursor (box, child);
1103
1104 if (priv->selection_mode == CTK_SELECTION_NONE)
1105 return;
1106
1107 if (priv->selection_mode == CTK_SELECTION_BROWSE)
1108 {
1109 ctk_flow_box_unselect_all_internal (box);
1110 ctk_flow_box_child_set_selected (child, TRUE(!(0)));
1111 priv->selected_child = child;
1112 }
1113 else if (priv->selection_mode == CTK_SELECTION_SINGLE)
1114 {
1115 gboolean was_selected;
1116
1117 was_selected = CHILD_PRIV (child)((CtkFlowBoxChildPrivate*)ctk_flow_box_child_get_instance_private
((CtkFlowBoxChild*)(child)))
->selected;
1118 ctk_flow_box_unselect_all_internal (box);
1119 ctk_flow_box_child_set_selected (child, modify ? !was_selected : TRUE(!(0)));
1120 priv->selected_child = CHILD_PRIV (child)((CtkFlowBoxChildPrivate*)ctk_flow_box_child_get_instance_private
((CtkFlowBoxChild*)(child)))
->selected ? child : NULL((void*)0);
1121 }
1122 else /* CTK_SELECTION_MULTIPLE */
1123 {
1124 if (extend)
1125 {
1126 ctk_flow_box_unselect_all_internal (box);
1127 if (priv->selected_child == NULL((void*)0))
1128 {
1129 ctk_flow_box_child_set_selected (child, TRUE(!(0)));
1130 priv->selected_child = child;
1131 }
1132 else
1133 ctk_flow_box_select_all_between (box, priv->selected_child, child, FALSE(0));
1134 }
1135 else
1136 {
1137 if (modify)
1138 {
1139 ctk_flow_box_child_set_selected (child, !CHILD_PRIV (child)((CtkFlowBoxChildPrivate*)ctk_flow_box_child_get_instance_private
((CtkFlowBoxChild*)(child)))
->selected);
1140 }
1141 else
1142 {
1143 ctk_flow_box_unselect_all_internal (box);
1144 ctk_flow_box_child_set_selected (child, !CHILD_PRIV (child)((CtkFlowBoxChildPrivate*)ctk_flow_box_child_get_instance_private
((CtkFlowBoxChild*)(child)))
->selected);
1145 priv->selected_child = child;
1146 }
1147 }
1148 }
1149
1150 g_signal_emit (box, signals[SELECTED_CHILDREN_CHANGED], 0);
1151}
1152
1153static void
1154ctk_flow_box_select_and_activate (CtkFlowBox *box,
1155 CtkFlowBoxChild *child)
1156{
1157 if (child != NULL((void*)0))
1158 {
1159 ctk_flow_box_select_child_internal (box, child);
1160 ctk_flow_box_update_cursor (box, child);
1161 g_signal_emit (box, signals[CHILD_ACTIVATED], 0, child);
1162 }
1163}
1164
1165/* Focus utilities {{{3 */
1166
1167static GSequenceIter *
1168ctk_flow_box_get_previous_focusable (CtkFlowBox *box G_GNUC_UNUSED__attribute__ ((__unused__)),
1169 GSequenceIter *iter)
1170{
1171 CtkFlowBoxChild *child;
1172
1173 while (!g_sequence_iter_is_begin (iter))
1174 {
1175 iter = g_sequence_iter_prev (iter);
1176 child = g_sequence_get (iter);
1177 if (child_is_visible (CTK_WIDGET (child)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((child)), ((ctk_widget_get_type ()))))))
) &&
1178 ctk_widget_is_sensitive (CTK_WIDGET (child)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((child)), ((ctk_widget_get_type ()))))))
))
1179 return iter;
1180 }
1181
1182 return NULL((void*)0);
1183}
1184
1185static GSequenceIter *
1186ctk_flow_box_get_next_focusable (CtkFlowBox *box G_GNUC_UNUSED__attribute__ ((__unused__)),
1187 GSequenceIter *iter)
1188{
1189 CtkFlowBoxChild *child;
1190
1191 while (TRUE(!(0)))
1192 {
1193 iter = g_sequence_iter_next (iter);
1194 if (g_sequence_iter_is_end (iter))
1195 return NULL((void*)0);
1196 child = g_sequence_get (iter);
1197 if (child_is_visible (CTK_WIDGET (child)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((child)), ((ctk_widget_get_type ()))))))
) &&
1198 ctk_widget_is_sensitive (CTK_WIDGET (child)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((child)), ((ctk_widget_get_type ()))))))
))
1199 return iter;
1200 }
1201
1202 return NULL((void*)0);
1203}
1204
1205static GSequenceIter *
1206ctk_flow_box_get_first_focusable (CtkFlowBox *box)
1207{
1208 GSequenceIter *iter;
1209 CtkFlowBoxChild *child;
1210
1211 iter = g_sequence_get_begin_iter (BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
->children);
1212 if (g_sequence_iter_is_end (iter))
1213 return NULL((void*)0);
1214
1215 child = g_sequence_get (iter);
1216 if (child_is_visible (CTK_WIDGET (child)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((child)), ((ctk_widget_get_type ()))))))
) &&
1217 ctk_widget_is_sensitive (CTK_WIDGET (child)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((child)), ((ctk_widget_get_type ()))))))
))
1218 return iter;
1219
1220 return ctk_flow_box_get_next_focusable (box, iter);
1221}
1222
1223static GSequenceIter *
1224ctk_flow_box_get_last_focusable (CtkFlowBox *box)
1225{
1226 GSequenceIter *iter;
1227
1228 iter = g_sequence_get_end_iter (BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
->children);
1229 return ctk_flow_box_get_previous_focusable (box, iter);
1230}
1231
1232
1233static GSequenceIter *
1234ctk_flow_box_get_above_focusable (CtkFlowBox *box,
1235 GSequenceIter *iter)
1236{
1237 CtkFlowBoxChild *child = NULL((void*)0);
1238 gint i;
1239
1240 while (TRUE(!(0)))
1241 {
1242 i = 0;
1243 while (i < BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
->cur_children_per_line)
1244 {
1245 if (g_sequence_iter_is_begin (iter))
1246 return NULL((void*)0);
1247 iter = g_sequence_iter_prev (iter);
1248 child = g_sequence_get (iter);
1249 if (child_is_visible (CTK_WIDGET (child)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((child)), ((ctk_widget_get_type ()))))))
))
1250 i++;
1251 }
1252 if (child && ctk_widget_get_sensitive (CTK_WIDGET (child)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((child)), ((ctk_widget_get_type ()))))))
))
1253 return iter;
1254 }
1255
1256 return NULL((void*)0);
1257}
1258
1259static GSequenceIter *
1260ctk_flow_box_get_below_focusable (CtkFlowBox *box,
1261 GSequenceIter *iter)
1262{
1263 CtkFlowBoxChild *child = NULL((void*)0);
1264 gint i;
1265
1266 while (TRUE(!(0)))
1267 {
1268 i = 0;
1269 while (i < BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
->cur_children_per_line)
1270 {
1271 iter = g_sequence_iter_next (iter);
1272 if (g_sequence_iter_is_end (iter))
1273 return NULL((void*)0);
1274 child = g_sequence_get (iter);
1275 if (child_is_visible (CTK_WIDGET (child)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((child)), ((ctk_widget_get_type ()))))))
))
1276 i++;
1277 }
1278 if (child && ctk_widget_get_sensitive (CTK_WIDGET (child)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((child)), ((ctk_widget_get_type ()))))))
))
1279 return iter;
1280 }
1281
1282 return NULL((void*)0);
1283}
1284
1285/* CtkWidget implementation {{{2 */
1286
1287/* Size allocation {{{3 */
1288
1289/* Used in columned modes where all items share at least their
1290 * equal widths or heights
1291 */
1292static void
1293get_max_item_size (CtkFlowBox *box,
1294 CtkOrientation orientation,
1295 gint *min_size,
1296 gint *nat_size)
1297{
1298 GSequenceIter *iter;
1299 gint max_min_size = 0;
1300 gint max_nat_size = 0;
1301
1302 for (iter = g_sequence_get_begin_iter (BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
->children);
1303 !g_sequence_iter_is_end (iter);
1304 iter = g_sequence_iter_next (iter))
1305 {
1306 CtkWidget *child;
1307 gint child_min, child_nat;
1308
1309 child = g_sequence_get (iter);
1310
1311 if (!child_is_visible (child))
1312 continue;
1313
1314 if (orientation == CTK_ORIENTATION_HORIZONTAL)
1315 ctk_widget_get_preferred_width (child, &child_min, &child_nat);
1316 else
1317 ctk_widget_get_preferred_height (child, &child_min, &child_nat);
1318
1319 max_min_size = MAX (max_min_size, child_min)(((max_min_size) > (child_min)) ? (max_min_size) : (child_min
))
;
1320 max_nat_size = MAX (max_nat_size, child_nat)(((max_nat_size) > (child_nat)) ? (max_nat_size) : (child_nat
))
;
1321 }
1322
1323 if (min_size)
1324 *min_size = max_min_size;
1325
1326 if (nat_size)
1327 *nat_size = max_nat_size;
1328}
1329
1330
1331/* Gets the largest minimum/natural size for a given size (used to get
1332 * the largest item heights for a fixed item width and the opposite)
1333 */
1334static void
1335get_largest_size_for_opposing_orientation (CtkFlowBox *box,
1336 CtkOrientation orientation,
1337 gint item_size,
1338 gint *min_item_size,
1339 gint *nat_item_size)
1340{
1341 GSequenceIter *iter;
1342 gint max_min_size = 0;
1343 gint max_nat_size = 0;
1344
1345 for (iter = g_sequence_get_begin_iter (BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
->children);
1346 !g_sequence_iter_is_end (iter);
1347 iter = g_sequence_iter_next (iter))
1348 {
1349 CtkWidget *child;
1350 gint child_min, child_nat;
1351
1352 child = g_sequence_get (iter);
1353
1354 if (!child_is_visible (child))
1355 continue;
1356
1357 if (orientation == CTK_ORIENTATION_HORIZONTAL)
1358 ctk_widget_get_preferred_height_for_width (child,
1359 item_size,
1360 &child_min, &child_nat);
1361 else
1362 ctk_widget_get_preferred_width_for_height (child,
1363 item_size,
1364 &child_min, &child_nat);
1365
1366 max_min_size = MAX (max_min_size, child_min)(((max_min_size) > (child_min)) ? (max_min_size) : (child_min
))
;
1367 max_nat_size = MAX (max_nat_size, child_nat)(((max_nat_size) > (child_nat)) ? (max_nat_size) : (child_nat
))
;
1368 }
1369
1370 if (min_item_size)
1371 *min_item_size = max_min_size;
1372
1373 if (nat_item_size)
1374 *nat_item_size = max_nat_size;
1375}
1376
1377/* Gets the largest minimum/natural size on a single line for a given size
1378 * (used to get the largest line heights for a fixed item width and the opposite
1379 * while iterating over a list of children, note the new index is returned)
1380 */
1381static GSequenceIter *
1382get_largest_size_for_line_in_opposing_orientation (CtkFlowBox *box,
1383 CtkOrientation orientation,
1384 GSequenceIter *cursor,
1385 gint line_length,
1386 CtkRequestedSize *item_sizes,
1387 gint extra_pixels,
1388 gint *min_item_size,
1389 gint *nat_item_size)
1390{
1391 GSequenceIter *iter;
1392 gint max_min_size = 0;
1393 gint max_nat_size = 0;
1394 gint i;
1395
1396 i = 0;
1397 for (iter = cursor;
1398 !g_sequence_iter_is_end (iter) && i < line_length;
1399 iter = g_sequence_iter_next (iter))
1400 {
1401 CtkWidget *child;
1402 gint child_min, child_nat, this_item_size;
1403
1404 child = g_sequence_get (iter);
1405
1406 if (!child_is_visible (child))
1407 continue;
1408
1409 /* Distribute the extra pixels to the first children in the line
1410 * (could be fancier and spread them out more evenly) */
1411 this_item_size = item_sizes[i].minimum_size;
1412 if (extra_pixels > 0 && ORIENTATION_ALIGN (box)(((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))->orientation == CTK_ORIENTATION_HORIZONTAL ? ctk_widget_get_halign
(((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_widget_get_type ()))))))) : ctk_widget_get_valign
(((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_widget_get_type ()))))))))
== CTK_ALIGN_FILL)
1413 {
1414 this_item_size++;
1415 extra_pixels--;
1416 }
1417
1418 if (orientation == CTK_ORIENTATION_HORIZONTAL)
1419 ctk_widget_get_preferred_height_for_width (child,
1420 this_item_size,
1421 &child_min, &child_nat);
1422 else
1423 ctk_widget_get_preferred_width_for_height (child,
1424 this_item_size,
1425 &child_min, &child_nat);
1426
1427 max_min_size = MAX (max_min_size, child_min)(((max_min_size) > (child_min)) ? (max_min_size) : (child_min
))
;
1428 max_nat_size = MAX (max_nat_size, child_nat)(((max_nat_size) > (child_nat)) ? (max_nat_size) : (child_nat
))
;
1429
1430 i++;
1431 }
1432
1433 if (min_item_size)
1434 *min_item_size = max_min_size;
1435
1436 if (nat_item_size)
1437 *nat_item_size = max_nat_size;
1438
1439 /* Return next item in the list */
1440 return iter;
1441}
1442
1443/* fit_aligned_item_requests() helper */
1444static gint
1445gather_aligned_item_requests (CtkFlowBox *box,
1446 CtkOrientation orientation,
1447 gint line_length,
1448 gint item_spacing,
1449 gint n_children,
1450 CtkRequestedSize *item_sizes)
1451{
1452 GSequenceIter *iter;
1453 gint i;
1454 gint extra_items, natural_line_size = 0;
1455
1456 extra_items = n_children % line_length;
1457
1458 i = 0;
1459 for (iter = g_sequence_get_begin_iter (BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
->children);
1460 !g_sequence_iter_is_end (iter);
1461 iter = g_sequence_iter_next (iter))
1462 {
1463 CtkWidget *child;
1464 CtkAlign item_align;
1465 gint child_min, child_nat;
1466 gint position;
1467
1468 child = g_sequence_get (iter);
1469
1470 if (!child_is_visible (child))
1471 continue;
1472
1473 if (orientation == CTK_ORIENTATION_HORIZONTAL)
1474 ctk_widget_get_preferred_width (child,
1475 &child_min, &child_nat);
1476 else
1477 ctk_widget_get_preferred_height (child,
1478 &child_min, &child_nat);
1479
1480 /* Get the index and push it over for the last line when spreading to the end */
1481 position = i % line_length;
1482
1483 item_align = ORIENTATION_ALIGN (box)(((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))->orientation == CTK_ORIENTATION_HORIZONTAL ? ctk_widget_get_halign
(((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_widget_get_type ()))))))) : ctk_widget_get_valign
(((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_widget_get_type ()))))))))
;
1484 if (item_align == CTK_ALIGN_END && i >= n_children - extra_items)
1485 position += line_length - extra_items;
1486
1487 /* Round up the size of every column/row */
1488 item_sizes[position].minimum_size = MAX (item_sizes[position].minimum_size, child_min)(((item_sizes[position].minimum_size) > (child_min)) ? (item_sizes
[position].minimum_size) : (child_min))
;
1489 item_sizes[position].natural_size = MAX (item_sizes[position].natural_size, child_nat)(((item_sizes[position].natural_size) > (child_nat)) ? (item_sizes
[position].natural_size) : (child_nat))
;
1490
1491 i++;
1492 }
1493
1494 for (i = 0; i < line_length; i++)
1495 natural_line_size += item_sizes[i].natural_size;
1496
1497 natural_line_size += (line_length - 1) * item_spacing;
1498
1499 return natural_line_size;
1500}
1501
1502static CtkRequestedSize *
1503fit_aligned_item_requests (CtkFlowBox *box,
1504 CtkOrientation orientation,
1505 gint avail_size,
1506 gint item_spacing,
1507 gint *line_length, /* in-out */
1508 gint items_per_line,
1509 gint n_children)
1510{
1511 CtkRequestedSize *sizes, *try_sizes;
1512 gint try_line_size, try_length;
1513
1514 sizes = g_new0 (CtkRequestedSize, *line_length)((CtkRequestedSize *) g_malloc0_n ((*line_length), sizeof (CtkRequestedSize
)))
;
1515
1516 /* get the sizes for the initial guess */
1517 try_line_size = gather_aligned_item_requests (box,
1518 orientation,
1519 *line_length,
1520 item_spacing,
1521 n_children,
1522 sizes);
1523
1524 /* Try columnizing the whole thing and adding an item to the end of
1525 * the line; try to fit as many columns into the available size as
1526 * possible
1527 */
1528 for (try_length = *line_length + 1; try_line_size < avail_size; try_length++)
1529 {
1530 try_sizes = g_new0 (CtkRequestedSize, try_length)((CtkRequestedSize *) g_malloc0_n ((try_length), sizeof (CtkRequestedSize
)))
;
1531 try_line_size = gather_aligned_item_requests (box,
1532 orientation,
1533 try_length,
1534 item_spacing,
1535 n_children,
1536 try_sizes);
1537
1538 if (try_line_size <= avail_size &&
1539 items_per_line >= try_length)
1540 {
1541 *line_length = try_length;
1542
1543 g_free (sizes);
1544 sizes = try_sizes;
1545 }
1546 else
1547 {
1548 /* oops, this one failed; stick to the last size that fit and then return */
1549 g_free (try_sizes);
1550 break;
1551 }
1552 }
1553
1554 return sizes;
1555}
1556
1557typedef struct {
1558 GArray *requested;
1559 gint extra_pixels;
1560} AllocatedLine;
1561
1562static gint
1563get_offset_pixels (CtkAlign align,
1564 gint pixels)
1565{
1566 gint offset;
1567
1568 switch (align) {
1569 case CTK_ALIGN_START:
1570 case CTK_ALIGN_FILL:
1571 offset = 0;
1572 break;
1573 case CTK_ALIGN_CENTER:
1574 offset = pixels / 2;
1575 break;
1576 case CTK_ALIGN_END:
1577 offset = pixels;
1578 break;
1579 default:
1580 g_assert_not_reached ()do { g_assertion_message_expr ("Ctk", "ctkflowbox.c", 1580, (
(const char*) (__func__)), ((void*)0)); } while (0)
;
1581 break;
1582 }
1583
1584 return offset;
1585}
1586
1587static void
1588ctk_flow_box_size_allocate (CtkWidget *widget,
1589 CtkAllocation *allocation)
1590{
1591 CtkAllocation clip;
1592 CdkWindow *window;
1593 CtkAllocation child_allocation;
1594
1595 ctk_widget_set_allocation (widget, allocation);
1596
1597 window = ctk_widget_get_window (widget);
1598 if (window != NULL((void*)0))
1599 cdk_window_move_resize (window,
1600 allocation->x, allocation->y,
1601 allocation->width, allocation->height);
1602
1603 child_allocation.x = 0;
1604 child_allocation.y = 0;
1605 child_allocation.width = allocation->width;
1606 child_allocation.height = allocation->height;
1607
1608 ctk_css_gadget_allocate (BOX_PRIV (widget)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(widget)))
->gadget,
1609 &child_allocation,
1610 ctk_widget_get_allocated_baseline (widget),
1611 &clip);
1612
1613 _ctk_widget_set_simple_clip (widget, &clip);
1614}
1615
1616static void
1617ctk_flow_box_allocate (CtkCssGadget *gadget,
1618 const CtkAllocation *allocation,
1619 int baseline G_GNUC_UNUSED__attribute__ ((__unused__)),
1620 CtkAllocation *out_clip,
1621 gpointer unused G_GNUC_UNUSED__attribute__ ((__unused__)))
1622{
1623 CtkWidget *widget = ctk_css_gadget_get_owner (gadget);
1624 CtkFlowBox *box = CTK_FLOW_BOX (widget)((((CtkFlowBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_flow_box_get_type ()))))))
;
1625 CtkFlowBoxPrivate *priv = BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
;
1626 CtkAllocation child_allocation;
1627 gint avail_size, avail_other_size, min_items, item_spacing, line_spacing;
1628 CtkAlign item_align;
1629 CtkAlign line_align;
1630 CtkRequestedSize *line_sizes = NULL((void*)0);
1631 CtkRequestedSize *item_sizes = NULL((void*)0);
1632 gint min_item_size, nat_item_size;
1633 gint line_length;
1634 gint item_size = 0;
1635 gint line_size = 0, min_fixed_line_size = 0, nat_fixed_line_size = 0;
1636 gint line_offset, item_offset, n_children, n_lines, line_count;
1637 gint extra_pixels = 0, extra_per_item = 0, extra_extra = 0;
1638 gint extra_line_pixels = 0, extra_per_line = 0, extra_line_extra = 0;
1639 gint i, this_line_size;
1640 GSequenceIter *iter;
1641
1642 min_items = MAX (1, priv->min_children_per_line)(((1) > (priv->min_children_per_line)) ? (1) : (priv->
min_children_per_line))
;
1643
1644 if (priv->orientation == CTK_ORIENTATION_HORIZONTAL)
1645 {
1646 avail_size = allocation->width;
1647 avail_other_size = allocation->height;
1648 item_spacing = priv->column_spacing; line_spacing = priv->row_spacing;
1649 }
1650 else /* CTK_ORIENTATION_VERTICAL */
1651 {
1652 avail_size = allocation->height;
1653 avail_other_size = allocation->width;
1654 item_spacing = priv->row_spacing;
1655 line_spacing = priv->column_spacing;
1656 }
1657
1658 item_align = ORIENTATION_ALIGN (box)(((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))->orientation == CTK_ORIENTATION_HORIZONTAL ? ctk_widget_get_halign
(((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_widget_get_type ()))))))) : ctk_widget_get_valign
(((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_widget_get_type ()))))))))
;
1659 line_align = OPPOSING_ORIENTATION_ALIGN (box)(((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))->orientation == CTK_ORIENTATION_HORIZONTAL ? ctk_widget_get_valign
(((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_widget_get_type ()))))))) : ctk_widget_get_halign
(((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_widget_get_type ()))))))))
;
1660
1661 /* Get how many lines we'll be needing to flow */
1662 n_children = get_visible_children (box);
1663 if (n_children <= 0)
1664 return;
1665
1666 /* Deal with ALIGNED/HOMOGENEOUS modes first, start with
1667 * initial guesses at item/line sizes
1668 */
1669 get_max_item_size (box, priv->orientation, &min_item_size, &nat_item_size);
1670 if (nat_item_size <= 0)
1671 return;
1672
1673 /* By default flow at the natural item width */
1674 line_length = avail_size / (nat_item_size + item_spacing);
1675
1676 /* After the above aproximation, check if we cant fit one more on the line */
1677 if (line_length * item_spacing + (line_length + 1) * nat_item_size <= avail_size)
1678 line_length++;
1679
1680 /* Its possible we were allocated just less than the natural width of the
1681 * minimum item flow length
1682 */
1683 line_length = MAX (min_items, line_length)(((min_items) > (line_length)) ? (min_items) : (line_length
))
;
1684 line_length = MIN (line_length, priv->max_children_per_line)(((line_length) < (priv->max_children_per_line)) ? (line_length
) : (priv->max_children_per_line))
;
1685
1686 /* Here we just use the largest height-for-width and use that for the height
1687 * of all lines
1688 */
1689 if (priv->homogeneous)
1690 {
1691 n_lines = n_children / line_length;
1692 if ((n_children % line_length) > 0)
1693 n_lines++;
1694
1695 n_lines = MAX (n_lines, 1)(((n_lines) > (1)) ? (n_lines) : (1));
1696
1697 /* Now we need the real item allocation size */
1698 item_size = (avail_size - (line_length - 1) * item_spacing) / line_length;
1699
1700 /* Cut out the expand space if we're not distributing any */
1701 if (item_align != CTK_ALIGN_FILL)
1702 item_size = MIN (item_size, nat_item_size)(((item_size) < (nat_item_size)) ? (item_size) : (nat_item_size
))
;
1703
1704 get_largest_size_for_opposing_orientation (box,
1705 priv->orientation,
1706 item_size,
1707 &min_fixed_line_size,
1708 &nat_fixed_line_size);
1709
1710 /* resolve a fixed 'line_size' */
1711 line_size = (avail_other_size - (n_lines - 1) * line_spacing) / n_lines;
1712
1713 if (line_align != CTK_ALIGN_FILL)
1714 line_size = MIN (line_size, nat_fixed_line_size)(((line_size) < (nat_fixed_line_size)) ? (line_size) : (nat_fixed_line_size
))
;
1715
1716 /* Get the real extra pixels incase of CTK_ALIGN_START lines */
1717 extra_pixels = avail_size - (line_length - 1) * item_spacing - item_size * line_length;
1718 extra_line_pixels = avail_other_size - (n_lines - 1) * line_spacing - line_size * n_lines;
1719 }
1720 else
1721 {
1722 gboolean first_line = TRUE(!(0));
1723
1724 /* Find the amount of columns that can fit aligned into the available space
1725 * and collect their requests.
1726 */
1727 item_sizes = fit_aligned_item_requests (box,
1728 priv->orientation,
1729 avail_size,
1730 item_spacing,
1731 &line_length,
1732 priv->max_children_per_line,
1733 n_children);
1734
1735 /* Calculate the number of lines after determining the final line_length */
1736 n_lines = n_children / line_length;
1737 if ((n_children % line_length) > 0)
1738 n_lines++;
1739
1740 n_lines = MAX (n_lines, 1)(((n_lines) > (1)) ? (n_lines) : (1));
1741 line_sizes = g_new0 (CtkRequestedSize, n_lines)((CtkRequestedSize *) g_malloc0_n ((n_lines), sizeof (CtkRequestedSize
)))
;
1742
1743 /* Get the available remaining size */
1744 avail_size -= (line_length - 1) * item_spacing;
1745 for (i = 0; i < line_length; i++)
1746 avail_size -= item_sizes[i].minimum_size;
1747
1748 /* Perform a natural allocation on the columnized items and get the remaining pixels */
1749 if (avail_size > 0)
1750 extra_pixels = ctk_distribute_natural_allocation (avail_size, line_length, item_sizes);
1751
1752 /* Now that we have the size of each column of items find the size of each individual
1753 * line based on the aligned item sizes.
1754 */
1755
1756 for (i = 0, iter = g_sequence_get_begin_iter (priv->children);
1757 !g_sequence_iter_is_end (iter) && i < n_lines;
1758 i++)
1759 {
1760 iter = get_largest_size_for_line_in_opposing_orientation (box,
1761 priv->orientation,
1762 iter,
1763 line_length,
1764 item_sizes,
1765 extra_pixels,
1766 &line_sizes[i].minimum_size,
1767 &line_sizes[i].natural_size);
1768
1769
1770 /* Its possible a line is made of completely invisible children */
1771 if (line_sizes[i].natural_size > 0)
1772 {
1773 if (first_line)
1774 first_line = FALSE(0);
1775 else
1776 avail_other_size -= line_spacing;
1777
1778 avail_other_size -= line_sizes[i].minimum_size;
1779
1780 line_sizes[i].data = GINT_TO_POINTER (i)((gpointer) (glong) (i));
1781 }
1782 }
1783
1784 /* Distribute space among lines naturally */
1785 if (avail_other_size > 0)
1786 extra_line_pixels = ctk_distribute_natural_allocation (avail_other_size, n_lines, line_sizes);
1787 }
1788
1789 /*
1790 * Initial sizes of items/lines guessed at this point,
1791 * go on to distribute expand space if needed.
1792 */
1793
1794 priv->cur_children_per_line = line_length;
1795
1796 /* FIXME: This portion needs to consider which columns
1797 * and rows asked for expand space and distribute those
1798 * accordingly for the case of ALIGNED allocation.
1799 *
1800 * If at least one child in a column/row asked for expand;
1801 * we should make that row/column expand entirely.
1802 */
1803
1804 /* Calculate expand space per item */
1805 if (item_align == CTK_ALIGN_FILL)
1806 {
1807 extra_per_item = extra_pixels / line_length;
1808 extra_extra = extra_pixels % line_length;
1809 }
1810
1811 /* Calculate expand space per line */
1812 if (line_align == CTK_ALIGN_FILL)
1813 {
1814 extra_per_line = extra_line_pixels / n_lines;
1815 extra_line_extra = extra_line_pixels % n_lines;
1816 }
1817
1818 /*
1819 * Prepare item/line initial offsets and jump into the
1820 * real allocation loop.
1821 */
1822 line_offset = allocation->y;
1823 item_offset = allocation->x;
1824
1825 /* prepend extra space to item_offset/line_offset for SPREAD_END */
1826 item_offset += get_offset_pixels (item_align, extra_pixels);
1827 line_offset += get_offset_pixels (line_align, extra_line_pixels);
1828
1829 /* Get the allocation size for the first line */
1830 if (priv->homogeneous)
1831 this_line_size = line_size;
1832 else
1833 {
1834 this_line_size = line_sizes[0].minimum_size;
1835
1836 if (line_align == CTK_ALIGN_FILL)
1837 {
1838 this_line_size += extra_per_line;
1839
1840 if (extra_line_extra > 0)
1841 this_line_size++;
1842 }
1843 }
1844
1845 i = 0;
1846 line_count = 0;
1847 for (iter = g_sequence_get_begin_iter (priv->children);
1848 !g_sequence_iter_is_end (iter);
1849 iter = g_sequence_iter_next (iter))
1850 {
1851 CtkWidget *child;
1852 gint position;
1853 gint this_item_size;
1854
1855 child = g_sequence_get (iter);
1856
1857 if (!child_is_visible (child))
1858 continue;
1859
1860 /* Get item position */
1861 position = i % line_length;
1862
1863 /* adjust the line_offset/count at the beginning of each new line */
1864 if (i > 0 && position == 0)
1865 {
1866 /* Push the line_offset */
1867 line_offset += this_line_size + line_spacing;
1868
1869 line_count++;
1870
1871 /* Get the new line size */
1872 if (priv->homogeneous)
1873 this_line_size = line_size;
1874 else
1875 {
1876 this_line_size = line_sizes[line_count].minimum_size;
1877
1878 if (line_align == CTK_ALIGN_FILL)
1879 {
1880 this_line_size += extra_per_line;
1881
1882 if (line_count < extra_line_extra)
1883 this_line_size++;
1884 }
1885 }
1886
1887 item_offset = allocation->x;
1888
1889 if (item_align == CTK_ALIGN_CENTER)
1890 {
1891 item_offset += get_offset_pixels (item_align, extra_pixels);
1892 }
1893 else if (item_align == CTK_ALIGN_END)
1894 {
1895 item_offset += get_offset_pixels (item_align, extra_pixels);
1896
1897 /* If we're on the last line, prepend the space for
1898 * any leading items */
1899 if (line_count == n_lines -1)
1900 {
1901 gint extra_items = n_children % line_length;
1902
1903 if (priv->homogeneous)
1904 {
1905 item_offset += item_size * (line_length - extra_items);
1906 item_offset += item_spacing * (line_length - extra_items);
1907 }
1908 else
1909 {
1910 gint j;
1911
1912 for (j = 0; j < (line_length - extra_items); j++)
1913 {
1914 item_offset += item_sizes[j].minimum_size;
1915 item_offset += item_spacing;
1916 }
1917 }
1918 }
1919 }
1920 }
1921
1922 /* Push the index along for the last line when spreading to the end */
1923 if (item_align == CTK_ALIGN_END && line_count == n_lines -1)
1924 {
1925 gint extra_items = n_children % line_length;
1926
1927 position += line_length - extra_items;
1928 }
1929
1930 if (priv->homogeneous)
1931 this_item_size = item_size;
1932 else
1933 this_item_size = item_sizes[position].minimum_size;
1934
1935 if (item_align == CTK_ALIGN_FILL)
1936 {
1937 this_item_size += extra_per_item;
1938
1939 if (position < extra_extra)
1940 this_item_size++;
1941 }
1942
1943 /* Do the actual allocation */
1944 if (priv->orientation == CTK_ORIENTATION_HORIZONTAL)
1945 {
1946 child_allocation.x = item_offset;
1947 child_allocation.y = line_offset;
1948 child_allocation.width = this_item_size;
1949 child_allocation.height = this_line_size;
1950 }
1951 else /* CTK_ORIENTATION_VERTICAL */
1952 {
1953 child_allocation.x = line_offset;
1954 child_allocation.y = item_offset;
1955 child_allocation.width = this_line_size;
1956 child_allocation.height = this_item_size;
1957 }
1958
1959 if (ctk_widget_get_direction (widget) == CTK_TEXT_DIR_RTL)
1960 child_allocation.x = allocation->width - child_allocation.x - child_allocation.width;
1961 ctk_widget_size_allocate (child, &child_allocation);
1962
1963 item_offset += this_item_size;
1964 item_offset += item_spacing;
1965
1966 i++;
1967 }
1968
1969 g_free (item_sizes);
1970 g_free (line_sizes);
1971
1972 ctk_container_get_children_clip (CTK_CONTAINER (widget)((((CtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_container_get_type ()))))))
, out_clip);
1973}
1974
1975static CtkSizeRequestMode
1976ctk_flow_box_get_request_mode (CtkWidget *widget)
1977{
1978 CtkFlowBox *box = CTK_FLOW_BOX (widget)((((CtkFlowBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_flow_box_get_type ()))))))
;
1979
1980 return (BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
->orientation == CTK_ORIENTATION_HORIZONTAL) ?
1981 CTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH : CTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT;
1982}
1983
1984/* Gets the largest minimum and natural length of
1985 * 'line_length' consecutive items when aligned into rows/columns */
1986static void
1987get_largest_aligned_line_length (CtkFlowBox *box,
1988 CtkOrientation orientation,
1989 gint line_length,
1990 gint *min_size,
1991 gint *nat_size)
1992{
1993 GSequenceIter *iter;
1994 gint max_min_size = 0;
1995 gint max_nat_size = 0;
1996 gint spacing, i;
1997 CtkRequestedSize *aligned_item_sizes;
1998
1999 if (orientation == CTK_ORIENTATION_HORIZONTAL)
2000 spacing = BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
->column_spacing;
2001 else
2002 spacing = BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
->row_spacing;
2003
2004 aligned_item_sizes = g_new0 (CtkRequestedSize, line_length)((CtkRequestedSize *) g_malloc0_n ((line_length), sizeof (CtkRequestedSize
)))
;
2005
2006 /* Get the largest sizes of each index in the line.
2007 */
2008 i = 0;
2009 for (iter = g_sequence_get_begin_iter (BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
->children);
2010 !g_sequence_iter_is_end (iter);
2011 iter = g_sequence_iter_next (iter))
2012 {
2013 CtkWidget *child;
2014 gint child_min, child_nat;
2015
2016 child = g_sequence_get (iter);
2017 if (!child_is_visible (child))
2018 continue;
2019
2020 if (orientation == CTK_ORIENTATION_HORIZONTAL)
2021 ctk_widget_get_preferred_width (child,
2022 &child_min, &child_nat);
2023 else /* CTK_ORIENTATION_VERTICAL */
2024 ctk_widget_get_preferred_height (child,
2025 &child_min, &child_nat);
2026
2027 aligned_item_sizes[i % line_length].minimum_size =
2028 MAX (aligned_item_sizes[i % line_length].minimum_size, child_min)(((aligned_item_sizes[i % line_length].minimum_size) > (child_min
)) ? (aligned_item_sizes[i % line_length].minimum_size) : (child_min
))
;
2029
2030 aligned_item_sizes[i % line_length].natural_size =
2031 MAX (aligned_item_sizes[i % line_length].natural_size, child_nat)(((aligned_item_sizes[i % line_length].natural_size) > (child_nat
)) ? (aligned_item_sizes[i % line_length].natural_size) : (child_nat
))
;
2032
2033 i++;
2034 }
2035
2036 /* Add up the largest indexes */
2037 for (i = 0; i < line_length; i++)
2038 {
2039 max_min_size += aligned_item_sizes[i].minimum_size;
2040 max_nat_size += aligned_item_sizes[i].natural_size;
2041 }
2042
2043 g_free (aligned_item_sizes);
2044
2045 max_min_size += (line_length - 1) * spacing;
2046 max_nat_size += (line_length - 1) * spacing;
2047
2048 if (min_size)
2049 *min_size = max_min_size;
2050
2051 if (nat_size)
2052 *nat_size = max_nat_size;
2053}
2054
2055static void
2056ctk_flow_box_get_preferred_width (CtkWidget *widget,
2057 gint *minimum,
2058 gint *natural)
2059{
2060 ctk_css_gadget_get_preferred_size (BOX_PRIV (widget)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(widget)))
->gadget,
2061 CTK_ORIENTATION_HORIZONTAL,
2062 -1,
2063 minimum, natural,
2064 NULL((void*)0), NULL((void*)0));
2065}
2066
2067static void
2068ctk_flow_box_get_preferred_height (CtkWidget *widget,
2069 gint *minimum,
2070 gint *natural)
2071{
2072 ctk_css_gadget_get_preferred_size (BOX_PRIV (widget)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(widget)))
->gadget,
2073 CTK_ORIENTATION_VERTICAL,
2074 -1,
2075 minimum, natural,
2076 NULL((void*)0), NULL((void*)0));
2077}
2078
2079static void
2080ctk_flow_box_get_preferred_height_for_width (CtkWidget *widget,
2081 gint width,
2082 gint *minimum,
2083 gint *natural)
2084{
2085 ctk_css_gadget_get_preferred_size (BOX_PRIV (widget)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(widget)))
->gadget,
2086 CTK_ORIENTATION_VERTICAL,
2087 width,
2088 minimum, natural,
2089 NULL((void*)0), NULL((void*)0));
2090}
2091
2092static void
2093ctk_flow_box_get_preferred_width_for_height (CtkWidget *widget,
2094 gint height,
2095 gint *minimum,
2096 gint *natural)
2097{
2098 ctk_css_gadget_get_preferred_size (BOX_PRIV (widget)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(widget)))
->gadget,
2099 CTK_ORIENTATION_HORIZONTAL,
2100 height,
2101 minimum, natural,
2102 NULL((void*)0), NULL((void*)0));
2103}
2104
2105static void
2106ctk_flow_box_measure (CtkCssGadget *gadget,
2107 CtkOrientation orientation,
2108 int for_size,
2109 int *minimum,
2110 int *natural,
2111 int *minimum_baseline G_GNUC_UNUSED__attribute__ ((__unused__)),
2112 int *natural_baseline G_GNUC_UNUSED__attribute__ ((__unused__)),
2113 gpointer data G_GNUC_UNUSED__attribute__ ((__unused__)))
2114{
2115 CtkWidget *widget = ctk_css_gadget_get_owner (gadget);
2116 CtkFlowBox *box = CTK_FLOW_BOX (widget)((((CtkFlowBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_flow_box_get_type ()))))))
;
2117 CtkFlowBoxPrivate *priv = BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
;
2118
2119 if (orientation == CTK_ORIENTATION_HORIZONTAL)
2120 {
2121 if (for_size < 0)
2122 {
2123 gint min_item_width, nat_item_width;
2124 gint min_items, nat_items;
2125 gint min_width, nat_width;
2126
2127 min_items = MAX (1, priv->min_children_per_line)(((1) > (priv->min_children_per_line)) ? (1) : (priv->
min_children_per_line))
;
2128 nat_items = MAX (min_items, priv->max_children_per_line)(((min_items) > (priv->max_children_per_line)) ? (min_items
) : (priv->max_children_per_line))
;
2129
2130 if (priv->orientation == CTK_ORIENTATION_HORIZONTAL)
2131 {
2132 min_width = nat_width = 0;
2133
2134 if (!priv->homogeneous)
2135 {
2136 /* When not homogeneous; horizontally oriented boxes
2137 * need enough width for the widest row
2138 */
2139 if (min_items == 1)
2140 {
2141 get_max_item_size (box,
2142 CTK_ORIENTATION_HORIZONTAL,
2143 &min_item_width,
2144 &nat_item_width);
2145
2146 min_width += min_item_width;
2147 nat_width += nat_item_width;
2148 }
2149 else
2150 {
2151 gint min_line_length, nat_line_length;
2152
2153 get_largest_aligned_line_length (box,
2154 CTK_ORIENTATION_HORIZONTAL,
2155 min_items,
2156 &min_line_length,
2157 &nat_line_length);
2158
2159 if (nat_items > min_items)
2160 get_largest_aligned_line_length (box,
2161 CTK_ORIENTATION_HORIZONTAL,
2162 nat_items,
2163 NULL((void*)0),
2164 &nat_line_length);
2165
2166 min_width += min_line_length;
2167 nat_width += nat_line_length;
2168 }
2169 }
2170 else /* In homogeneous mode; horizontally oriented boxs
2171 * give the same width to all children */
2172 {
2173 get_max_item_size (box, CTK_ORIENTATION_HORIZONTAL,
2174 &min_item_width, &nat_item_width);
2175
2176 min_width += min_item_width * min_items;
2177 min_width += (min_items -1) * priv->column_spacing;
2178
2179 nat_width += nat_item_width * nat_items;
2180 nat_width += (nat_items -1) * priv->column_spacing;
2181 }
2182 }
2183 else /* CTK_ORIENTATION_VERTICAL */
2184 {
2185 /* Return the width for the minimum height */
2186 gint min_height;
2187
2188 ctk_css_gadget_get_preferred_size (gadget,
2189 CTK_ORIENTATION_VERTICAL,
2190 -1,
2191 &min_height, NULL((void*)0),
2192 NULL((void*)0), NULL((void*)0));
2193 ctk_css_gadget_get_preferred_size (gadget,
2194 CTK_ORIENTATION_HORIZONTAL,
2195 min_height,
2196 &min_width, &nat_width,
2197 NULL((void*)0), NULL((void*)0));
2198 }
2199
2200 *minimum = min_width;
2201 *natural = nat_width;
2202 }
2203 else
2204 {
2205 gint min_item_height, nat_item_height;
2206 gint min_items;
2207 gint min_width, nat_width;
2208 gint avail_size, n_children;
2209
2210 min_items = MAX (1, priv->min_children_per_line)(((1) > (priv->min_children_per_line)) ? (1) : (priv->
min_children_per_line))
;
2211
2212 min_width = 0;
2213 nat_width = 0;
2214
2215 if (priv->orientation == CTK_ORIENTATION_HORIZONTAL)
2216 {
2217 /* Return the minimum width */
2218 ctk_css_gadget_get_preferred_size (gadget,
2219 CTK_ORIENTATION_HORIZONTAL,
2220 -1,
2221 &min_width, &nat_width,
2222 NULL((void*)0), NULL((void*)0));
2223 }
2224 else /* CTK_ORIENTATION_VERTICAL */
2225 {
2226 gint min_height;
2227 gint line_length;
2228 gint item_size, extra_pixels;
2229
2230 n_children = get_visible_children (box);
2231 if (n_children <= 0)
2232 goto out_width;
2233
2234 /* Make sure its no smaller than the minimum */
2235 ctk_css_gadget_get_preferred_size (gadget,
2236 CTK_ORIENTATION_VERTICAL,
2237 -1,
2238 &min_height, NULL((void*)0),
2239 NULL((void*)0), NULL((void*)0));
2240
2241 avail_size = MAX (for_size, min_height)(((for_size) > (min_height)) ? (for_size) : (min_height));
2242 if (avail_size <= 0)
2243 goto out_width;
2244
2245 get_max_item_size (box, CTK_ORIENTATION_VERTICAL, &min_item_height, &nat_item_height);
2246
2247 /* By default flow at the natural item width */
2248 line_length = avail_size / (nat_item_height + priv->row_spacing);
2249
2250 /* After the above aproximation, check if we cant fit one more on the line */
2251 if (line_length * priv->row_spacing + (line_length + 1) * nat_item_height <= avail_size)
2252 line_length++;
2253
2254 /* Its possible we were allocated just less than the natural width of the
2255 * minimum item flow length
2256 */
2257 line_length = MAX (min_items, line_length)(((min_items) > (line_length)) ? (min_items) : (line_length
))
;
2258 line_length = MIN (line_length, priv->max_children_per_line)(((line_length) < (priv->max_children_per_line)) ? (line_length
) : (priv->max_children_per_line))
;
2259
2260 /* Now we need the real item allocation size */
2261 item_size = (avail_size - (line_length - 1) * priv->row_spacing) / line_length;
2262
2263 /* Cut out the expand space if we're not distributing any */
2264 if (ctk_widget_get_valign (widget) != CTK_ALIGN_FILL)
2265 {
2266 item_size = MIN (item_size, nat_item_height)(((item_size) < (nat_item_height)) ? (item_size) : (nat_item_height
))
;
2267 extra_pixels = 0;
2268 }
2269 else
2270 /* Collect the extra pixels for expand children */
2271 extra_pixels = (avail_size - (line_length - 1) * priv->row_spacing) % line_length;
2272
2273 if (priv->homogeneous)
2274 {
2275 gint min_item_width, nat_item_width;
2276 gint lines;
2277
2278 /* Here we just use the largest height-for-width and
2279 * add up the size accordingly
2280 */
2281 get_largest_size_for_opposing_orientation (box,
2282 CTK_ORIENTATION_VERTICAL,
2283 item_size,
2284 &min_item_width,
2285 &nat_item_width);
2286
2287 /* Round up how many lines we need to allocate for */
2288 n_children = get_visible_children (box);
2289 lines = n_children / line_length;
2290 if ((n_children % line_length) > 0)
2291 lines++;
2292
2293 min_width = min_item_width * lines;
2294 nat_width = nat_item_width * lines;
2295
2296 min_width += (lines - 1) * priv->column_spacing;
2297 nat_width += (lines - 1) * priv->column_spacing;
2298 }
2299 else
2300 {
2301 gint min_line_width, nat_line_width, i;
2302 gboolean first_line = TRUE(!(0));
2303 CtkRequestedSize *item_sizes;
2304 GSequenceIter *iter;
2305
2306 /* First get the size each set of items take to span the line
2307 * when aligning the items above and below after flowping.
2308 */
2309 item_sizes = fit_aligned_item_requests (box,
2310 priv->orientation,
2311 avail_size,
2312 priv->row_spacing,
2313 &line_length,
2314 priv->max_children_per_line,
2315 n_children);
2316
2317 /* Get the available remaining size */
2318 avail_size -= (line_length - 1) * priv->column_spacing;
2319 for (i = 0; i < line_length; i++)
2320 avail_size -= item_sizes[i].minimum_size;
2321
2322 if (avail_size > 0)
2323 extra_pixels = ctk_distribute_natural_allocation (avail_size, line_length, item_sizes);
2324
2325 for (iter = g_sequence_get_begin_iter (priv->children);
2326 !g_sequence_iter_is_end (iter);)
2327 {
2328 iter = get_largest_size_for_line_in_opposing_orientation (box,
2329 CTK_ORIENTATION_VERTICAL,
2330 iter,
2331 line_length,
2332 item_sizes,
2333 extra_pixels,
2334 &min_line_width,
2335 &nat_line_width);
2336
2337 /* Its possible the last line only had invisible widgets */
2338 if (nat_line_width > 0)
2339 {
2340 if (first_line)
2341 first_line = FALSE(0);
2342 else
2343 {
2344 min_width += priv->column_spacing;
2345 nat_width += priv->column_spacing;
2346 }
2347
2348 min_width += min_line_width;
2349 nat_width += nat_line_width;
2350 }
2351 }
2352 g_free (item_sizes);
2353 }
2354 }
2355
2356 out_width:
2357 *minimum = min_width;
2358 *natural = nat_width;
2359 }
2360 }
2361 else
2362 {
2363 if (for_size < 0)
2364 {
2365 gint min_item_height, nat_item_height;
2366 gint min_items, nat_items;
2367 gint min_height, nat_height;
2368
2369 min_items = MAX (1, priv->min_children_per_line)(((1) > (priv->min_children_per_line)) ? (1) : (priv->
min_children_per_line))
;
2370 nat_items = MAX (min_items, priv->max_children_per_line)(((min_items) > (priv->max_children_per_line)) ? (min_items
) : (priv->max_children_per_line))
;
2371
2372 if (priv->orientation == CTK_ORIENTATION_HORIZONTAL)
2373 {
2374 /* Return the height for the minimum width */
2375 gint min_width;
2376
2377 ctk_css_gadget_get_preferred_size (gadget,
2378 CTK_ORIENTATION_HORIZONTAL,
2379 -1,
2380 &min_width, NULL((void*)0),
2381 NULL((void*)0), NULL((void*)0));
2382 ctk_css_gadget_get_preferred_size (gadget,
2383 CTK_ORIENTATION_VERTICAL,
2384 min_width,
2385 &min_height, &nat_height,
2386 NULL((void*)0), NULL((void*)0));
2387 }
2388 else /* CTK_ORIENTATION_VERTICAL */
2389 {
2390 min_height = nat_height = 0;
2391
2392 if (! priv->homogeneous)
2393 {
2394 /* When not homogeneous; vertically oriented boxes
2395 * need enough height for the tallest column
2396 */
2397 if (min_items == 1)
2398 {
2399 get_max_item_size (box, CTK_ORIENTATION_VERTICAL,
2400 &min_item_height, &nat_item_height);
2401
2402 min_height += min_item_height;
2403 nat_height += nat_item_height;
2404 }
2405 else
2406 {
2407 gint min_line_length, nat_line_length;
2408
2409 get_largest_aligned_line_length (box,
2410 CTK_ORIENTATION_VERTICAL,
2411 min_items,
2412 &min_line_length,
2413 &nat_line_length);
2414
2415 if (nat_items > min_items)
2416 get_largest_aligned_line_length (box,
2417 CTK_ORIENTATION_VERTICAL,
2418 nat_items,
2419 NULL((void*)0),
2420 &nat_line_length);
2421
2422 min_height += min_line_length;
2423 nat_height += nat_line_length;
2424 }
2425
2426 }
2427 else
2428 {
2429 /* In homogeneous mode; vertically oriented boxes
2430 * give the same height to all children
2431 */
2432 get_max_item_size (box,
2433 CTK_ORIENTATION_VERTICAL,
2434 &min_item_height,
2435 &nat_item_height);
2436
2437 min_height += min_item_height * min_items;
2438 min_height += (min_items -1) * priv->row_spacing;
2439
2440 nat_height += nat_item_height * nat_items;
2441 nat_height += (nat_items -1) * priv->row_spacing;
2442 }
2443 }
2444
2445 *minimum = min_height;
2446 *natural = nat_height;
2447 }
2448 else
2449 {
2450 gint min_item_width, nat_item_width;
2451 gint min_items;
2452 gint min_height, nat_height;
2453 gint avail_size, n_children;
2454
2455 min_items = MAX (1, priv->min_children_per_line)(((1) > (priv->min_children_per_line)) ? (1) : (priv->
min_children_per_line))
;
2456
2457 min_height = 0;
2458 nat_height = 0;
2459
2460 if (priv->orientation == CTK_ORIENTATION_HORIZONTAL)
2461 {
2462 gint min_width;
2463 gint line_length;
2464 gint item_size, extra_pixels;
2465
2466 n_children = get_visible_children (box);
2467 if (n_children <= 0)
2468 goto out_height;
2469
2470 /* Make sure its no smaller than the minimum */
2471 ctk_css_gadget_get_preferred_size (gadget,
2472 CTK_ORIENTATION_HORIZONTAL,
2473 -1,
2474 &min_width, NULL((void*)0),
2475 NULL((void*)0), NULL((void*)0));
2476
2477 avail_size = MAX (for_size, min_width)(((for_size) > (min_width)) ? (for_size) : (min_width));
2478 if (avail_size <= 0)
2479 goto out_height;
2480
2481 get_max_item_size (box, CTK_ORIENTATION_HORIZONTAL, &min_item_width, &nat_item_width);
2482 if (nat_item_width <= 0)
2483 goto out_height;
2484
2485 /* By default flow at the natural item width */
2486 line_length = avail_size / (nat_item_width + priv->column_spacing);
2487
2488 /* After the above aproximation, check if we cant fit one more on the line */
2489 if (line_length * priv->column_spacing + (line_length + 1) * nat_item_width <= avail_size)
2490 line_length++;
2491
2492 /* Its possible we were allocated just less than the natural width of the
2493 * minimum item flow length
2494 */
2495 line_length = MAX (min_items, line_length)(((min_items) > (line_length)) ? (min_items) : (line_length
))
;
2496 line_length = MIN (line_length, priv->max_children_per_line)(((line_length) < (priv->max_children_per_line)) ? (line_length
) : (priv->max_children_per_line))
;
2497
2498 /* Now we need the real item allocation size */
2499 item_size = (avail_size - (line_length - 1) * priv->column_spacing) / line_length;
2500
2501 /* Cut out the expand space if we're not distributing any */
2502 if (ctk_widget_get_halign (widget) != CTK_ALIGN_FILL)
2503 {
2504 item_size = MIN (item_size, nat_item_width)(((item_size) < (nat_item_width)) ? (item_size) : (nat_item_width
))
;
2505 extra_pixels = 0;
2506 }
2507 else
2508 /* Collect the extra pixels for expand children */
2509 extra_pixels = (avail_size - (line_length - 1) * priv->column_spacing) % line_length;
2510
2511 if (priv->homogeneous)
2512 {
2513 gint min_item_height, nat_item_height;
2514 gint lines;
2515
2516 /* Here we just use the largest height-for-width and
2517 * add up the size accordingly
2518 */
2519 get_largest_size_for_opposing_orientation (box,
2520 CTK_ORIENTATION_HORIZONTAL,
2521 item_size,
2522 &min_item_height,
2523 &nat_item_height);
2524
2525 /* Round up how many lines we need to allocate for */
2526 lines = n_children / line_length;
2527 if ((n_children % line_length) > 0)
2528 lines++;
2529
2530 min_height = min_item_height * lines;
2531 nat_height = nat_item_height * lines;
2532
2533 min_height += (lines - 1) * priv->row_spacing;
2534 nat_height += (lines - 1) * priv->row_spacing;
2535 }
2536 else
2537 {
2538 gint min_line_height, nat_line_height, i;
2539 gboolean first_line = TRUE(!(0));
2540 CtkRequestedSize *item_sizes;
2541 GSequenceIter *iter;
2542
2543 /* First get the size each set of items take to span the line
2544 * when aligning the items above and below after flowping.
2545 */
2546 item_sizes = fit_aligned_item_requests (box,
2547 priv->orientation,
2548 avail_size,
2549 priv->column_spacing,
2550 &line_length,
2551 priv->max_children_per_line,
2552 n_children);
2553
2554 /* Get the available remaining size */
2555 avail_size -= (line_length - 1) * priv->column_spacing;
2556 for (i = 0; i < line_length; i++)
2557 avail_size -= item_sizes[i].minimum_size;
2558
2559 if (avail_size > 0)
2560 extra_pixels = ctk_distribute_natural_allocation (avail_size, line_length, item_sizes);
2561
2562 for (iter = g_sequence_get_begin_iter (priv->children);
2563 !g_sequence_iter_is_end (iter);)
2564 {
2565 iter = get_largest_size_for_line_in_opposing_orientation (box,
2566 CTK_ORIENTATION_HORIZONTAL,
2567 iter,
2568 line_length,
2569 item_sizes,
2570 extra_pixels,
2571 &min_line_height,
2572 &nat_line_height);
2573 /* Its possible the line only had invisible widgets */
2574 if (nat_line_height > 0)
2575 {
2576 if (first_line)
2577 first_line = FALSE(0);
2578 else
2579 {
2580 min_height += priv->row_spacing;
2581 nat_height += priv->row_spacing;
2582 }
2583
2584 min_height += min_line_height;
2585 nat_height += nat_line_height;
2586 }
2587 }
2588
2589 g_free (item_sizes);
2590 }
2591 }
2592 else /* CTK_ORIENTATION_VERTICAL */
2593 {
2594 /* Return the minimum height */
2595 ctk_css_gadget_get_preferred_size (gadget,
2596 CTK_ORIENTATION_VERTICAL,
2597 -1,
2598 &min_height, &nat_height,
2599 NULL((void*)0), NULL((void*)0));
2600 }
2601
2602 out_height:
2603 *minimum = min_height;
2604 *natural = nat_height;
2605 }
2606 }
2607}
2608
2609/* Drawing {{{3 */
2610
2611static gboolean
2612ctk_flow_box_draw (CtkWidget *widget,
2613 cairo_t *cr)
2614{
2615 ctk_css_gadget_draw (BOX_PRIV (widget)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(widget)))
->gadget, cr);
2616
2617 return FALSE(0);
2618}
2619
2620static gboolean
2621ctk_flow_box_render (CtkCssGadget *gadget,
2622 cairo_t *cr,
2623 int x,
2624 int y,
2625 int width,
2626 int height,
2627 gpointer data G_GNUC_UNUSED__attribute__ ((__unused__)))
2628{
2629 CtkWidget *widget = ctk_css_gadget_get_owner (gadget);
2630 CtkFlowBox *box = CTK_FLOW_BOX (widget)((((CtkFlowBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_flow_box_get_type ()))))))
;
2631 CtkFlowBoxPrivate *priv = BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
;
2632
2633 CTK_WIDGET_CLASS (ctk_flow_box_parent_class)((((CtkWidgetClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((ctk_flow_box_parent_class)), ((ctk_widget_get_type ())))
)))
->draw (widget, cr);
2634
2635 if (priv->rubberband_first && priv->rubberband_last)
2636 {
2637 CtkStyleContext *context;
2638 GSequenceIter *iter, *iter1, *iter2;
2639 CdkRectangle line_rect, rect;
2640 GArray *lines;
2641 gboolean vertical;
2642
2643 context = ctk_widget_get_style_context (CTK_WIDGET (box)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_widget_get_type ()))))))
)
;
Value stored to 'context' is never read
2644
2645 vertical = priv->orientation == CTK_ORIENTATION_VERTICAL;
2646
2647 cairo_save (cr);
2648
2649 context = ctk_widget_get_style_context (widget);
2650 ctk_style_context_save_to_node (context, priv->rubberband_node);
2651
2652 iter1 = CHILD_PRIV (priv->rubberband_first)((CtkFlowBoxChildPrivate*)ctk_flow_box_child_get_instance_private
((CtkFlowBoxChild*)(priv->rubberband_first)))
->iter;
2653 iter2 = CHILD_PRIV (priv->rubberband_last)((CtkFlowBoxChildPrivate*)ctk_flow_box_child_get_instance_private
((CtkFlowBoxChild*)(priv->rubberband_last)))
->iter;
2654
2655 if (g_sequence_iter_compare (iter2, iter1) < 0)
2656 {
2657 iter = iter1;
2658 iter1 = iter2;
2659 iter2 = iter;
2660 }
2661
2662 line_rect.width = 0;
2663 lines = g_array_new (FALSE(0), FALSE(0), sizeof (CdkRectangle));
2664
2665 for (iter = iter1;
2666 !g_sequence_iter_is_end (iter);
2667 iter = g_sequence_iter_next (iter))
2668 {
2669 CtkWidget *child;
2670
2671 child = g_sequence_get (iter);
2672 ctk_widget_get_allocation (CTK_WIDGET (child)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((child)), ((ctk_widget_get_type ()))))))
, &rect);
2673 if (line_rect.width == 0)
2674 line_rect = rect;
2675 else
2676 {
2677 if ((vertical && rect.x == line_rect.x) ||
2678 (!vertical && rect.y == line_rect.y))
2679 cdk_rectangle_union (&rect, &line_rect, &line_rect);
2680 else
2681 {
2682 g_array_append_val (lines, line_rect)g_array_append_vals (lines, &(line_rect), 1);
2683 line_rect = rect;
2684 }
2685 }
2686
2687 if (g_sequence_iter_compare (iter, iter2) == 0)
2688 break;
2689 }
2690
2691 if (line_rect.width != 0)
2692 g_array_append_val (lines, line_rect)g_array_append_vals (lines, &(line_rect), 1);
2693
2694 if (lines->len > 0)
2695 {
2696 CtkStateFlags state;
2697 cairo_path_t *path;
2698 CtkBorder border;
2699 CdkRGBA border_color;
2700
2701 if (vertical)
2702 path_from_vertical_line_rects (cr, (CdkRectangle *)lines->data, lines->len);
2703 else
2704 path_from_horizontal_line_rects (cr, (CdkRectangle *)lines->data, lines->len);
2705
2706 /* For some reason we need to copy and reapply the path,
2707 * or it gets eaten by ctk_render_background()
2708 */
2709 path = cairo_copy_path (cr);
2710
2711 cairo_save (cr);
2712 cairo_clip (cr);
2713 ctk_render_background (context, cr, x, y, width, height);
2714 cairo_restore (cr);
2715
2716 cairo_append_path (cr, path);
2717 cairo_path_destroy (path);
2718
2719 state = ctk_style_context_get_state (context);
2720G_GNUC_BEGIN_IGNORE_DEPRECATIONSclang diagnostic push clang diagnostic ignored "-Wdeprecated-declarations"
2721 ctk_style_context_get_border_color (context, state, &border_color);
2722G_GNUC_END_IGNORE_DEPRECATIONSclang diagnostic pop
2723 ctk_style_context_get_border (context, state, &border);
2724
2725 cairo_set_line_width (cr, border.left);
2726 cdk_cairo_set_source_rgba (cr, &border_color);
2727 cairo_stroke (cr);
2728 }
2729 g_array_free (lines, TRUE(!(0)));
2730
2731 ctk_style_context_restore (context);
2732 cairo_restore (cr);
2733 }
2734
2735 return ctk_widget_has_visible_focus (widget);
2736}
2737
2738/* Autoscrolling {{{3 */
2739
2740static void
2741remove_autoscroll (CtkFlowBox *box)
2742{
2743 CtkFlowBoxPrivate *priv = BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
;
2744
2745 if (priv->autoscroll_id)
2746 {
2747 ctk_widget_remove_tick_callback (CTK_WIDGET (box)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_widget_get_type ()))))))
, priv->autoscroll_id);
2748 priv->autoscroll_id = 0;
2749 }
2750
2751 priv->autoscroll_mode = CTK_SCROLL_NONE;
2752}
2753
2754static gboolean
2755autoscroll_cb (CtkWidget *widget G_GNUC_UNUSED__attribute__ ((__unused__)),
2756 CdkFrameClock *frame_clock G_GNUC_UNUSED__attribute__ ((__unused__)),
2757 gpointer data)
2758{
2759 CtkFlowBox *box = CTK_FLOW_BOX (data)((((CtkFlowBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((data)), ((ctk_flow_box_get_type ()))))))
;
2760 CtkFlowBoxPrivate *priv = BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
;
2761 CtkAdjustment *adjustment;
2762 gdouble factor;
2763 gdouble increment;
2764 gdouble value;
2765
2766 if (priv->orientation == CTK_ORIENTATION_HORIZONTAL)
2767 adjustment = priv->vadjustment;
2768 else
2769 adjustment = priv->hadjustment;
2770
2771 switch (priv->autoscroll_mode)
2772 {
2773 case CTK_SCROLL_STEP_FORWARD:
2774 factor = AUTOSCROLL_FACTOR20;
2775 break;
2776 case CTK_SCROLL_STEP_BACKWARD:
2777 factor = - AUTOSCROLL_FACTOR20;
2778 break;
2779 case CTK_SCROLL_PAGE_FORWARD:
2780 factor = AUTOSCROLL_FACTOR_FAST10;
2781 break;
2782 case CTK_SCROLL_PAGE_BACKWARD:
2783 factor = - AUTOSCROLL_FACTOR_FAST10;
2784 break;
2785 default:
2786 g_assert_not_reached ()do { g_assertion_message_expr ("Ctk", "ctkflowbox.c", 2786, (
(const char*) (__func__)), ((void*)0)); } while (0)
;
2787 }
2788
2789 increment = ctk_adjustment_get_step_increment (adjustment) / factor;
2790
2791 value = ctk_adjustment_get_value (adjustment);
2792 value += increment;
2793 ctk_adjustment_set_value (adjustment, value);
2794
2795 if (priv->rubberband_select)
2796 {
2797 CdkEventSequence *sequence;
2798 gdouble x, y;
2799 CtkFlowBoxChild *child;
2800
2801 sequence = ctk_gesture_single_get_current_sequence (CTK_GESTURE_SINGLE (priv->drag_gesture)((((CtkGestureSingle*) (void *) g_type_check_instance_cast ((
GTypeInstance*) ((priv->drag_gesture)), ((ctk_gesture_single_get_type
()))))))
);
2802 ctk_gesture_get_point (priv->drag_gesture, sequence, &x, &y);
2803
2804 child = ctk_flow_box_get_child_at_pos (box, x, y);
2805
2806 ctk_flow_box_update_active (box, child);
2807
2808 if (child != NULL((void*)0))
2809 priv->rubberband_last = child;
2810 }
2811
2812 return G_SOURCE_CONTINUE(!(0));
2813}
2814
2815static void
2816add_autoscroll (CtkFlowBox *box)
2817{
2818 CtkFlowBoxPrivate *priv = BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
;
2819
2820 if (priv->autoscroll_id != 0 ||
2821 priv->autoscroll_mode == CTK_SCROLL_NONE)
2822 return;
2823
2824 priv->autoscroll_id = ctk_widget_add_tick_callback (CTK_WIDGET (box)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_widget_get_type ()))))))
,
2825 autoscroll_cb,
2826 box,
2827 NULL((void*)0));
2828}
2829
2830static gboolean
2831get_view_rect (CtkFlowBox *box,
2832 CdkRectangle *rect)
2833{
2834 CtkFlowBoxPrivate *priv = BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
;
2835 CtkWidget *parent;
2836 CdkWindow *view;
2837
2838 parent = ctk_widget_get_parent (CTK_WIDGET (box)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_widget_get_type ()))))))
);
2839 if (CTK_IS_VIEWPORT (parent)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(parent)); GType __t = ((ctk_viewport_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
2840 {
2841 view = ctk_viewport_get_view_window (CTK_VIEWPORT (parent)((((CtkViewport*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((parent)), ((ctk_viewport_get_type ()))))))
);
2842 rect->x = rect->y = 0;
2843
2844 rect->x = ctk_adjustment_get_value (priv->hadjustment);
2845 rect->y = ctk_adjustment_get_value (priv->vadjustment);
2846 rect->width = cdk_window_get_width (view);
2847 rect->height = cdk_window_get_height (view);
2848 return TRUE(!(0));
2849 }
2850
2851 return FALSE(0);
2852}
2853
2854static void
2855update_autoscroll_mode (CtkFlowBox *box,
2856 gint x,
2857 gint y)
2858{
2859 CtkFlowBoxPrivate *priv = BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
;
2860 CtkScrollType mode = CTK_SCROLL_NONE;
2861 CdkRectangle rect;
2862 gint size, pos;
2863
2864 if (priv->rubberband_select && get_view_rect (box, &rect))
2865 {
2866 if (priv->orientation == CTK_ORIENTATION_VERTICAL)
2867 {
2868 size = rect.width;
2869 pos = x - rect.x;
2870 }
2871 else
2872 {
2873 size = rect.height;
2874 pos = y - rect.y;
2875 }
2876
2877 if (pos < 0 - AUTOSCROLL_FAST_DISTANCE32)
2878 mode = CTK_SCROLL_PAGE_BACKWARD;
2879 else if (pos > size + AUTOSCROLL_FAST_DISTANCE32)
2880 mode = CTK_SCROLL_PAGE_FORWARD;
2881 else if (pos < 0)
2882 mode = CTK_SCROLL_STEP_BACKWARD;
2883 else if (pos > size)
2884 mode = CTK_SCROLL_STEP_FORWARD;
2885 }
2886
2887 if (mode != priv->autoscroll_mode)
2888 {
2889 remove_autoscroll (box);
2890 priv->autoscroll_mode = mode;
2891 add_autoscroll (box);
2892 }
2893}
2894
2895/* Event handling {{{3 */
2896
2897static gboolean
2898ctk_flow_box_enter_notify_event (CtkWidget *widget,
2899 CdkEventCrossing *event)
2900{
2901 CtkFlowBox *box = CTK_FLOW_BOX (widget)((((CtkFlowBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_flow_box_get_type ()))))))
;
2902 CtkFlowBoxChild *child;
2903
2904 if (event->window != ctk_widget_get_window (CTK_WIDGET (box)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_widget_get_type ()))))))
))
2905 return FALSE(0);
2906
2907 child = ctk_flow_box_get_child_at_pos (box, event->x, event->y);
2908 ctk_flow_box_update_active (box, child);
2909
2910 return FALSE(0);
2911}
2912
2913static gboolean
2914ctk_flow_box_leave_notify_event (CtkWidget *widget,
2915 CdkEventCrossing *event)
2916{
2917 CtkFlowBox *box = CTK_FLOW_BOX (widget)((((CtkFlowBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_flow_box_get_type ()))))))
;
2918 CtkFlowBoxChild *child = NULL((void*)0);
2919
2920 if (event->window != ctk_widget_get_window (CTK_WIDGET (box)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_widget_get_type ()))))))
))
2921 return FALSE(0);
2922
2923 if (event->detail != CDK_NOTIFY_INFERIOR)
2924 child = NULL((void*)0);
2925 else
2926 child = ctk_flow_box_get_child_at_pos (box, event->x, event->y);
2927
2928 ctk_flow_box_update_active (box, child);
2929
2930 return FALSE(0);
2931}
2932
2933static void
2934ctk_flow_box_drag_gesture_update (CtkGestureDrag *gesture,
2935 gdouble offset_x,
2936 gdouble offset_y,
2937 CtkFlowBox *box)
2938{
2939 CtkFlowBoxPrivate *priv = BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
;
2940 gdouble start_x, start_y;
2941 CtkFlowBoxChild *child;
2942 CtkCssNode *widget_node;
2943
2944 ctk_gesture_drag_get_start_point (gesture, &start_x, &start_y);
2945
2946 if (!priv->rubberband_select &&
2947 (offset_x * offset_x) + (offset_y * offset_y) > RUBBERBAND_START_DISTANCE32 * RUBBERBAND_START_DISTANCE32)
2948 {
2949 priv->rubberband_select = TRUE(!(0));
2950 priv->rubberband_first = ctk_flow_box_get_child_at_pos (box, start_x, start_y);
2951
2952 widget_node = ctk_widget_get_css_node (CTK_WIDGET (box)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_widget_get_type ()))))))
);
2953 priv->rubberband_node = ctk_css_node_new ();
2954 ctk_css_node_set_name (priv->rubberband_node, I_("rubberband")g_intern_static_string ("rubberband"));
2955 ctk_css_node_set_parent (priv->rubberband_node, widget_node);
2956 ctk_css_node_set_state (priv->rubberband_node, ctk_css_node_get_state (widget_node));
2957 g_object_unref (priv->rubberband_node);
2958
2959 /* Grab focus here, so Escape-to-stop-rubberband works */
2960 if (priv->rubberband_first)
2961 ctk_flow_box_update_cursor (box, priv->rubberband_first);
2962 ctk_gesture_set_state (CTK_GESTURE (gesture)((((CtkGesture*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((gesture)), ((ctk_gesture_get_type ()))))))
, CTK_EVENT_SEQUENCE_CLAIMED);
2963 }
2964
2965 if (priv->rubberband_select)
2966 {
2967 child = ctk_flow_box_get_child_at_pos (box, start_x + offset_x,
2968 start_y + offset_y);
2969
2970 if (priv->rubberband_first == NULL((void*)0))
2971 {
2972 priv->rubberband_first = child;
2973 if (priv->rubberband_first)
2974 ctk_flow_box_update_cursor (box, priv->rubberband_first);
2975 }
2976 if (child != NULL((void*)0))
2977 priv->rubberband_last = child;
2978
2979 update_autoscroll_mode (box, start_x + offset_x, start_y + offset_y);
2980 ctk_widget_queue_draw (CTK_WIDGET (box)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_widget_get_type ()))))))
);
2981 }
2982}
2983
2984static gboolean
2985ctk_flow_box_motion_notify_event (CtkWidget *widget,
2986 CdkEventMotion *event)
2987{
2988 CtkFlowBox *box = CTK_FLOW_BOX (widget)((((CtkFlowBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_flow_box_get_type ()))))))
;
2989 CtkFlowBoxChild *child;
2990 CdkWindow *window;
2991 CdkWindow *event_window;
2992 gint relative_x;
2993 gint relative_y;
2994 gdouble parent_x;
2995 gdouble parent_y;
2996
2997 window = ctk_widget_get_window (CTK_WIDGET (box)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_widget_get_type ()))))))
);
2998 event_window = event->window;
2999 relative_x = event->x;
3000 relative_y = event->y;
3001
3002 while ((event_window != NULL((void*)0)) && (event_window != window))
3003 {
3004 cdk_window_coords_to_parent (event_window,
3005 relative_x, relative_y,
3006 &parent_x, &parent_y);
3007 relative_x = parent_x;
3008 relative_y = parent_y;
3009 event_window = cdk_window_get_effective_parent (event_window);
3010 }
3011
3012 child = ctk_flow_box_get_child_at_pos (box, relative_x, relative_y);
3013 ctk_flow_box_update_active (box, child);
3014
3015 return CTK_WIDGET_CLASS (ctk_flow_box_parent_class)((((CtkWidgetClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((ctk_flow_box_parent_class)), ((ctk_widget_get_type ())))
)))
->motion_notify_event (widget, event);
3016}
3017
3018static void
3019ctk_flow_box_multipress_gesture_pressed (CtkGestureMultiPress *gesture,
3020 guint n_press,
3021 gdouble x,
3022 gdouble y,
3023 CtkFlowBox *box)
3024{
3025 CtkFlowBoxPrivate *priv = BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
;
3026 CtkFlowBoxChild *child;
3027
3028 child = ctk_flow_box_get_child_at_pos (box, x, y);
3029
3030 if (child == NULL((void*)0))
3031 return;
3032
3033 /* The drag gesture is only triggered by first press */
3034 if (n_press != 1)
3035 ctk_gesture_set_state (priv->drag_gesture, CTK_EVENT_SEQUENCE_DENIED);
3036
3037 priv->active_child = child;
3038 priv->active_child_active = TRUE(!(0));
3039 ctk_widget_queue_draw (CTK_WIDGET (box)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_widget_get_type ()))))))
);
3040
3041 if (n_press == 2 && !priv->activate_on_single_click)
3042 {
3043 ctk_gesture_set_state (CTK_GESTURE (gesture)((((CtkGesture*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((gesture)), ((ctk_gesture_get_type ()))))))
,
3044 CTK_EVENT_SEQUENCE_CLAIMED);
3045 g_signal_emit (box, signals[CHILD_ACTIVATED], 0, child);
3046 }
3047}
3048
3049static void
3050ctk_flow_box_multipress_gesture_released (CtkGestureMultiPress *gesture,
3051 guint n_press G_GNUC_UNUSED__attribute__ ((__unused__)),
3052 gdouble x G_GNUC_UNUSED__attribute__ ((__unused__)),
3053 gdouble y G_GNUC_UNUSED__attribute__ ((__unused__)),
3054 CtkFlowBox *box)
3055{
3056 CtkFlowBoxPrivate *priv = BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
;
3057
3058 if (priv->active_child != NULL((void*)0) && priv->active_child_active)
3059 {
3060 ctk_gesture_set_state (CTK_GESTURE (gesture)((((CtkGesture*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((gesture)), ((ctk_gesture_get_type ()))))))
,
3061 CTK_EVENT_SEQUENCE_CLAIMED);
3062
3063 if (priv->activate_on_single_click)
3064 ctk_flow_box_select_and_activate (box, priv->active_child);
3065 else
3066 {
3067 CdkEventSequence *sequence;
3068 CdkInputSource source;
3069 const CdkEvent *event;
3070 gboolean modify;
3071 gboolean extend;
3072
3073 get_current_selection_modifiers (CTK_WIDGET (box)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_widget_get_type ()))))))
, &modify, &extend);
3074
3075 /* With touch, we default to modifying the selection.
3076 * You can still clear the selection and start over
3077 * by holding Ctrl.
3078 */
3079
3080 sequence = ctk_gesture_single_get_current_sequence (CTK_GESTURE_SINGLE (gesture)((((CtkGestureSingle*) (void *) g_type_check_instance_cast ((
GTypeInstance*) ((gesture)), ((ctk_gesture_single_get_type ()
))))))
);
3081 event = ctk_gesture_get_last_event (CTK_GESTURE (gesture)((((CtkGesture*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((gesture)), ((ctk_gesture_get_type ()))))))
, sequence);
3082 source = cdk_device_get_source (cdk_event_get_source_device (event));
3083
3084 if (source == CDK_SOURCE_TOUCHSCREEN)
3085 modify = !modify;
3086
3087 ctk_flow_box_update_selection (box, priv->active_child, modify, extend);
3088 }
3089 }
3090}
3091
3092static void
3093ctk_flow_box_multipress_gesture_stopped (CtkGestureMultiPress *gesture G_GNUC_UNUSED__attribute__ ((__unused__)),
3094 CtkFlowBox *box)
3095{
3096 CtkFlowBoxPrivate *priv = BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
;
3097
3098 priv->active_child = NULL((void*)0);
3099 priv->active_child_active = FALSE(0);
3100 ctk_widget_queue_draw (CTK_WIDGET (box)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_widget_get_type ()))))))
);
3101}
3102
3103static void
3104ctk_flow_box_drag_gesture_begin (CtkGestureDrag *gesture,
3105 gdouble start_x G_GNUC_UNUSED__attribute__ ((__unused__)),
3106 gdouble start_y G_GNUC_UNUSED__attribute__ ((__unused__)),
3107 CtkWidget *widget)
3108{
3109 CtkFlowBoxPrivate *priv = BOX_PRIV (widget)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(widget)))
;
3110
3111 if (priv->selection_mode != CTK_SELECTION_MULTIPLE)
3112 {
3113 ctk_gesture_set_state (CTK_GESTURE (gesture)((((CtkGesture*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((gesture)), ((ctk_gesture_get_type ()))))))
, CTK_EVENT_SEQUENCE_DENIED);
3114 return;
3115 }
3116
3117 priv->rubberband_select = FALSE(0);
3118 priv->rubberband_first = NULL((void*)0);
3119 priv->rubberband_last = NULL((void*)0);
3120 get_current_selection_modifiers (widget, &priv->rubberband_modify, &priv->rubberband_extend);
3121}
3122
3123static void
3124ctk_flow_box_stop_rubberband (CtkFlowBox *box)
3125{
3126 CtkFlowBoxPrivate *priv = BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
;
3127
3128 priv->rubberband_select = FALSE(0);
3129 priv->rubberband_first = NULL((void*)0);
3130 priv->rubberband_last = NULL((void*)0);
3131
3132 ctk_css_node_set_parent (priv->rubberband_node, NULL((void*)0));
3133 priv->rubberband_node = NULL((void*)0);
3134
3135 remove_autoscroll (box);
3136
3137 ctk_widget_queue_draw (CTK_WIDGET (box)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_widget_get_type ()))))))
);
3138}
3139
3140static void
3141ctk_flow_box_drag_gesture_end (CtkGestureDrag *gesture,
3142 gdouble offset_x G_GNUC_UNUSED__attribute__ ((__unused__)),
3143 gdouble offset_y G_GNUC_UNUSED__attribute__ ((__unused__)),
3144 CtkFlowBox *box)
3145{
3146 CtkFlowBoxPrivate *priv = BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
;
3147 CdkEventSequence *sequence;
3148
3149 if (!priv->rubberband_select)
3150 return;
3151
3152 sequence = ctk_gesture_single_get_current_sequence (CTK_GESTURE_SINGLE (gesture)((((CtkGestureSingle*) (void *) g_type_check_instance_cast ((
GTypeInstance*) ((gesture)), ((ctk_gesture_single_get_type ()
))))))
);
3153
3154 if (ctk_gesture_handles_sequence (CTK_GESTURE (gesture)((((CtkGesture*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((gesture)), ((ctk_gesture_get_type ()))))))
, sequence))
3155 {
3156 if (!priv->rubberband_extend && !priv->rubberband_modify)
3157 ctk_flow_box_unselect_all_internal (box);
3158
3159 if (priv->rubberband_first && priv->rubberband_last)
3160 ctk_flow_box_select_all_between (box, priv->rubberband_first, priv->rubberband_last, priv->rubberband_modify);
3161
3162 ctk_flow_box_stop_rubberband (box);
3163
3164 g_signal_emit (box, signals[SELECTED_CHILDREN_CHANGED], 0);
3165 }
3166 else
3167 ctk_flow_box_stop_rubberband (box);
3168
3169 ctk_widget_queue_draw (CTK_WIDGET (box)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_widget_get_type ()))))))
);
3170}
3171
3172static gboolean
3173ctk_flow_box_key_press_event (CtkWidget *widget,
3174 CdkEventKey *event)
3175{
3176 CtkFlowBox *box = CTK_FLOW_BOX (widget)((((CtkFlowBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_flow_box_get_type ()))))))
;
3177 CtkFlowBoxPrivate *priv = BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
;
3178
3179 if (priv->rubberband_select)
3180 {
3181 if (event->keyval == CDK_KEY_Escape0xff1b)
3182 {
3183 ctk_flow_box_stop_rubberband (box);
3184 return TRUE(!(0));
3185 }
3186 }
3187
3188 return CTK_WIDGET_CLASS (ctk_flow_box_parent_class)((((CtkWidgetClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((ctk_flow_box_parent_class)), ((ctk_widget_get_type ())))
)))
->key_press_event (widget, event);
3189}
3190
3191/* Realize and map {{{3 */
3192
3193static void
3194ctk_flow_box_realize (CtkWidget *widget)
3195{
3196 CtkFlowBox *box = CTK_FLOW_BOX (widget)((((CtkFlowBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_flow_box_get_type ()))))))
;
3197 CtkAllocation allocation;
3198 CdkWindowAttr attributes = {0};
3199 CdkWindow *window;
3200
3201 ctk_widget_get_allocation (CTK_WIDGET (box)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_widget_get_type ()))))))
, &allocation);
3202 ctk_widget_set_realized (CTK_WIDGET (box)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_widget_get_type ()))))))
, TRUE(!(0)));
3203
3204 attributes.x = allocation.x;
3205 attributes.y = allocation.y;
3206 attributes.width = allocation.width;
3207 attributes.height = allocation.height;
3208 attributes.window_type = CDK_WINDOW_CHILD;
3209 attributes.event_mask = ctk_widget_get_events (CTK_WIDGET (box)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_widget_get_type ()))))))
)
3210 | CDK_ENTER_NOTIFY_MASK
3211 | CDK_LEAVE_NOTIFY_MASK
3212 | CDK_POINTER_MOTION_MASK
3213 | CDK_KEY_PRESS_MASK
3214 | CDK_BUTTON_PRESS_MASK
3215 | CDK_BUTTON_RELEASE_MASK;
3216 attributes.wclass = CDK_INPUT_OUTPUT;
3217
3218 window = cdk_window_new (ctk_widget_get_parent_window (CTK_WIDGET (box)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_widget_get_type ()))))))
),
3219 &attributes, CDK_WA_X | CDK_WA_Y);
3220 ctk_widget_register_window (CTK_WIDGET (box)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_widget_get_type ()))))))
, window);
3221 ctk_widget_set_window (CTK_WIDGET (box)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_widget_get_type ()))))))
, window);
3222}
3223
3224static void
3225ctk_flow_box_unmap (CtkWidget *widget)
3226{
3227 CtkFlowBox *box = CTK_FLOW_BOX (widget)((((CtkFlowBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_flow_box_get_type ()))))))
;
3228
3229 remove_autoscroll (box);
3230
3231 CTK_WIDGET_CLASS (ctk_flow_box_parent_class)((((CtkWidgetClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((ctk_flow_box_parent_class)), ((ctk_widget_get_type ())))
)))
->unmap (widget);
3232}
3233
3234/* CtkContainer implementation {{{2 */
3235
3236static void
3237ctk_flow_box_add (CtkContainer *container,
3238 CtkWidget *child)
3239{
3240 ctk_flow_box_insert (CTK_FLOW_BOX (container)((((CtkFlowBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((container)), ((ctk_flow_box_get_type ()))))))
, child, -1);
3241}
3242
3243static void
3244ctk_flow_box_remove (CtkContainer *container,
3245 CtkWidget *widget)
3246{
3247 CtkFlowBox *box = CTK_FLOW_BOX (container)((((CtkFlowBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((container)), ((ctk_flow_box_get_type ()))))))
;
3248 CtkFlowBoxPrivate *priv = BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
;
3249 gboolean was_visible;
3250 gboolean was_selected;
3251 CtkFlowBoxChild *child;
3252
3253 if (CTK_IS_FLOW_BOX_CHILD (widget)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(widget)); GType __t = ((ctk_flow_box_child_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
3254 child = CTK_FLOW_BOX_CHILD (widget)((((CtkFlowBoxChild*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_flow_box_child_get_type ()))))))
;
3255 else
3256 {
3257 child = (CtkFlowBoxChild*)ctk_widget_get_parent (widget);
3258 if (!CTK_IS_FLOW_BOX_CHILD (child)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(child)); GType __t = ((ctk_flow_box_child_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
3259 {
3260 g_warning ("Tried to remove non-child %p", widget);
3261 return;
3262 }
3263 }
3264
3265 was_visible = child_is_visible (CTK_WIDGET (child)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((child)), ((ctk_widget_get_type ()))))))
);
3266 was_selected = CHILD_PRIV (child)((CtkFlowBoxChildPrivate*)ctk_flow_box_child_get_instance_private
((CtkFlowBoxChild*)(child)))
->selected;
3267
3268 if (child == priv->active_child)
3269 priv->active_child = NULL((void*)0);
3270 if (child == priv->selected_child)
3271 priv->selected_child = NULL((void*)0);
3272
3273 g_sequence_remove (CHILD_PRIV (child)((CtkFlowBoxChildPrivate*)ctk_flow_box_child_get_instance_private
((CtkFlowBoxChild*)(child)))
->iter);
3274 ctk_widget_unparent (CTK_WIDGET (child)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((child)), ((ctk_widget_get_type ()))))))
);
3275
3276 if (was_visible && ctk_widget_get_visible (CTK_WIDGET (box)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_widget_get_type ()))))))
))
3277 ctk_widget_queue_resize (CTK_WIDGET (box)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_widget_get_type ()))))))
);
3278
3279 if (was_selected && !ctk_widget_in_destruction (CTK_WIDGET (box)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_widget_get_type ()))))))
))
3280 g_signal_emit (box, signals[SELECTED_CHILDREN_CHANGED], 0);
3281}
3282
3283static void
3284ctk_flow_box_forall (CtkContainer *container,
3285 gboolean include_internals G_GNUC_UNUSED__attribute__ ((__unused__)),
3286 CtkCallback callback,
3287 gpointer callback_target)
3288{
3289 GSequenceIter *iter;
3290 CtkWidget *child;
3291
3292 iter = g_sequence_get_begin_iter (BOX_PRIV (container)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(container)))
->children);
3293 while (!g_sequence_iter_is_end (iter))
3294 {
3295 child = g_sequence_get (iter);
3296 iter = g_sequence_iter_next (iter);
3297 callback (child, callback_target);
3298 }
3299}
3300
3301static GType
3302ctk_flow_box_child_type (CtkContainer *container G_GNUC_UNUSED__attribute__ ((__unused__)))
3303{
3304 return CTK_TYPE_FLOW_BOX_CHILD(ctk_flow_box_child_get_type ());
3305}
3306
3307/* Keynav {{{2 */
3308
3309static gboolean
3310ctk_flow_box_focus (CtkWidget *widget,
3311 CtkDirectionType direction)
3312{
3313 CtkFlowBox *box = CTK_FLOW_BOX (widget)((((CtkFlowBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_flow_box_get_type ()))))))
;
3314 CtkWidget *focus_child;
3315 GSequenceIter *iter;
3316 CtkFlowBoxChild *next_focus_child;
3317
3318 /* Without "can-focus" flag fall back to the default behavior immediately */
3319 if (!ctk_widget_get_can_focus (widget))
3320 {
3321 return CTK_WIDGET_CLASS (ctk_flow_box_parent_class)((((CtkWidgetClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((ctk_flow_box_parent_class)), ((ctk_widget_get_type ())))
)))
->focus (widget, direction);
3322 }
3323
3324 focus_child = ctk_container_get_focus_child (CTK_CONTAINER (box)((((CtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_container_get_type ()))))))
);
3325 next_focus_child = NULL((void*)0);
3326
3327 if (focus_child != NULL((void*)0))
3328 {
3329 if (ctk_widget_child_focus (focus_child, direction))
3330 return TRUE(!(0));
3331
3332 iter = CHILD_PRIV (focus_child)((CtkFlowBoxChildPrivate*)ctk_flow_box_child_get_instance_private
((CtkFlowBoxChild*)(focus_child)))
->iter;
3333
3334 if (direction == CTK_DIR_LEFT || direction == CTK_DIR_TAB_BACKWARD)
3335 iter = ctk_flow_box_get_previous_focusable (box, iter);
3336 else if (direction == CTK_DIR_RIGHT || direction == CTK_DIR_TAB_FORWARD)
3337 iter = ctk_flow_box_get_next_focusable (box, iter);
3338 else if (direction == CTK_DIR_UP)
3339 iter = ctk_flow_box_get_above_focusable (box, iter);
3340 else if (direction == CTK_DIR_DOWN)
3341 iter = ctk_flow_box_get_below_focusable (box, iter);
3342
3343 if (iter != NULL((void*)0))
3344 next_focus_child = g_sequence_get (iter);
3345 }
3346 else
3347 {
3348 if (BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
->selected_child)
3349 next_focus_child = BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
->selected_child;
3350 else
3351 {
3352 if (direction == CTK_DIR_UP || direction == CTK_DIR_TAB_BACKWARD)
3353 iter = ctk_flow_box_get_last_focusable (box);
3354 else
3355 iter = ctk_flow_box_get_first_focusable (box);
3356
3357 if (iter != NULL((void*)0))
3358 next_focus_child = g_sequence_get (iter);
3359 }
3360 }
3361
3362 if (next_focus_child == NULL((void*)0))
3363 {
3364 if (direction == CTK_DIR_UP || direction == CTK_DIR_DOWN ||
3365 direction == CTK_DIR_LEFT || direction == CTK_DIR_RIGHT)
3366 {
3367 if (ctk_widget_keynav_failed (CTK_WIDGET (box)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_widget_get_type ()))))))
, direction))
3368 return TRUE(!(0));
3369 }
3370
3371 return FALSE(0);
3372 }
3373
3374 if (ctk_widget_child_focus (CTK_WIDGET (next_focus_child)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((next_focus_child)), ((ctk_widget_get_type ()))))))
, direction))
3375 return TRUE(!(0));
3376
3377 return TRUE(!(0));
3378}
3379
3380static void
3381ctk_flow_box_add_move_binding (CtkBindingSet *binding_set,
3382 guint keyval,
3383 CdkModifierType modmask,
3384 CtkMovementStep step,
3385 gint count)
3386{
3387 CdkDisplay *display;
3388 CdkModifierType extend_mod_mask = CDK_SHIFT_MASK;
3389 CdkModifierType modify_mod_mask = CDK_CONTROL_MASK;
3390
3391 display = cdk_display_get_default ();
3392 if (display)
3393 {
3394 extend_mod_mask = cdk_keymap_get_modifier_mask (cdk_keymap_get_for_display (display),
3395 CDK_MODIFIER_INTENT_EXTEND_SELECTION);
3396 modify_mod_mask = cdk_keymap_get_modifier_mask (cdk_keymap_get_for_display (display),
3397 CDK_MODIFIER_INTENT_MODIFY_SELECTION);
3398 }
3399
3400 ctk_binding_entry_add_signal (binding_set, keyval, modmask,
3401 "move-cursor", 2,
3402 CTK_TYPE_MOVEMENT_STEP(ctk_movement_step_get_type ()), step,
3403 G_TYPE_INT((GType) ((6) << (2))), count,
3404 NULL((void*)0));
3405 ctk_binding_entry_add_signal (binding_set, keyval, modmask | extend_mod_mask,
3406 "move-cursor", 2,
3407 CTK_TYPE_MOVEMENT_STEP(ctk_movement_step_get_type ()), step,
3408 G_TYPE_INT((GType) ((6) << (2))), count,
3409 NULL((void*)0));
3410 ctk_binding_entry_add_signal (binding_set, keyval, modmask | modify_mod_mask,
3411 "move-cursor", 2,
3412 CTK_TYPE_MOVEMENT_STEP(ctk_movement_step_get_type ()), step,
3413 G_TYPE_INT((GType) ((6) << (2))), count,
3414 NULL((void*)0));
3415 ctk_binding_entry_add_signal (binding_set, keyval, modmask | extend_mod_mask | modify_mod_mask,
3416 "move-cursor", 2,
3417 CTK_TYPE_MOVEMENT_STEP(ctk_movement_step_get_type ()), step,
3418 G_TYPE_INT((GType) ((6) << (2))), count,
3419 NULL((void*)0));
3420}
3421
3422static void
3423ctk_flow_box_activate_cursor_child (CtkFlowBox *box)
3424{
3425 ctk_flow_box_select_and_activate (box, BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
->cursor_child);
3426}
3427
3428static void
3429ctk_flow_box_toggle_cursor_child (CtkFlowBox *box)
3430{
3431 CtkFlowBoxPrivate *priv = BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
;
3432
3433 if (priv->cursor_child == NULL((void*)0))
3434 return;
3435
3436 if ((priv->selection_mode == CTK_SELECTION_SINGLE ||
3437 priv->selection_mode == CTK_SELECTION_MULTIPLE) &&
3438 CHILD_PRIV (priv->cursor_child)((CtkFlowBoxChildPrivate*)ctk_flow_box_child_get_instance_private
((CtkFlowBoxChild*)(priv->cursor_child)))
->selected)
3439 ctk_flow_box_unselect_child_internal (box, priv->cursor_child);
3440 else
3441 ctk_flow_box_select_and_activate (box, priv->cursor_child);
3442}
3443
3444static gboolean
3445ctk_flow_box_move_cursor (CtkFlowBox *box,
3446 CtkMovementStep step,
3447 gint count)
3448{
3449 CtkFlowBoxPrivate *priv = BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
;
3450 gboolean modify;
3451 gboolean extend;
3452 CtkFlowBoxChild *child;
3453 CtkFlowBoxChild *prev;
3454 CtkFlowBoxChild *next;
3455 CtkAllocation allocation;
3456 gint page_size;
3457 GSequenceIter *iter;
3458 gint start;
3459 CtkAdjustment *adjustment;
3460 gboolean vertical;
3461
3462 /* Without "can-focus" flag fall back to the default behavior immediately */
3463 if (!ctk_widget_get_can_focus (CTK_WIDGET (box)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_widget_get_type ()))))))
))
3464 return FALSE(0);
3465
3466 vertical = priv->orientation == CTK_ORIENTATION_VERTICAL;
3467
3468 if (vertical)
3469 {
3470 switch (step)
3471 {
3472 case CTK_MOVEMENT_VISUAL_POSITIONS:
3473 step = CTK_MOVEMENT_DISPLAY_LINES;
3474 break;
3475 case CTK_MOVEMENT_DISPLAY_LINES:
3476 step = CTK_MOVEMENT_VISUAL_POSITIONS;
3477 break;
3478 default: ;
3479 }
3480 }
3481
3482 child = NULL((void*)0);
3483 switch (step)
3484 {
3485 case CTK_MOVEMENT_VISUAL_POSITIONS:
3486 if (priv->cursor_child != NULL((void*)0))
3487 {
3488 iter = CHILD_PRIV (priv->cursor_child)((CtkFlowBoxChildPrivate*)ctk_flow_box_child_get_instance_private
((CtkFlowBoxChild*)(priv->cursor_child)))
->iter;
3489 if (ctk_widget_get_direction (CTK_WIDGET (box)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_widget_get_type ()))))))
) == CTK_TEXT_DIR_RTL)
3490 count = - count;
3491
3492 while (count < 0 && iter != NULL((void*)0))
3493 {
3494 iter = ctk_flow_box_get_previous_focusable (box, iter);
3495 count = count + 1;
3496 }
3497 while (count > 0 && iter != NULL((void*)0))
3498 {
3499 iter = ctk_flow_box_get_next_focusable (box, iter);
3500 count = count - 1;
3501 }
3502
3503 if (iter != NULL((void*)0) && !g_sequence_iter_is_end (iter))
3504 child = g_sequence_get (iter);
3505 }
3506 break;
3507
3508 case CTK_MOVEMENT_BUFFER_ENDS:
3509 if (count < 0)
3510 iter = ctk_flow_box_get_first_focusable (box);
3511 else
3512 iter = ctk_flow_box_get_last_focusable (box);
3513 if (iter != NULL((void*)0))
3514 child = g_sequence_get (iter);
3515 break;
3516
3517 case CTK_MOVEMENT_DISPLAY_LINES:
3518 if (priv->cursor_child != NULL((void*)0))
3519 {
3520 iter = CHILD_PRIV (priv->cursor_child)((CtkFlowBoxChildPrivate*)ctk_flow_box_child_get_instance_private
((CtkFlowBoxChild*)(priv->cursor_child)))
->iter;
3521
3522 while (count < 0 && iter != NULL((void*)0))
3523 {
3524 iter = ctk_flow_box_get_above_focusable (box, iter);
3525 count = count + 1;
3526 }
3527 while (count > 0 && iter != NULL((void*)0))
3528 {
3529 iter = ctk_flow_box_get_below_focusable (box, iter);
3530 count = count - 1;
3531 }
3532
3533 if (iter != NULL((void*)0))
3534 child = g_sequence_get (iter);
3535 }
3536 break;
3537
3538 case CTK_MOVEMENT_PAGES:
3539 page_size = 100;
3540 adjustment = vertical ? priv->hadjustment : priv->vadjustment;
3541 if (adjustment)
3542 page_size = ctk_adjustment_get_page_increment (adjustment);
3543
3544 if (priv->cursor_child != NULL((void*)0))
3545 {
3546 child = priv->cursor_child;
3547 iter = CHILD_PRIV (child)((CtkFlowBoxChildPrivate*)ctk_flow_box_child_get_instance_private
((CtkFlowBoxChild*)(child)))
->iter;
3548 ctk_widget_get_allocation (CTK_WIDGET (child)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((child)), ((ctk_widget_get_type ()))))))
, &allocation);
3549 start = vertical ? allocation.x : allocation.y;
3550
3551 if (count < 0)
3552 {
3553 gint i = 0;
3554
3555 /* Up */
3556 while (iter != NULL((void*)0))
3557 {
3558 iter = ctk_flow_box_get_previous_focusable (box, iter);
3559 if (iter == NULL((void*)0))
3560 break;
3561
3562 prev = g_sequence_get (iter);
3563
3564 /* go up an even number of rows */
3565 if (i % priv->cur_children_per_line == 0)
3566 {
3567 ctk_widget_get_allocation (CTK_WIDGET (prev)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((prev)), ((ctk_widget_get_type ()))))))
, &allocation);
3568 if ((vertical ? allocation.x : allocation.y) < start - page_size)
3569 break;
3570 }
3571
3572 child = prev;
3573 i++;
3574 }
3575 }
3576 else
3577 {
3578 gint i = 0;
3579
3580 /* Down */
3581 while (!g_sequence_iter_is_end (iter))
3582 {
3583 iter = ctk_flow_box_get_next_focusable (box, iter);
3584 if (iter == NULL((void*)0) || g_sequence_iter_is_end (iter))
3585 break;
3586
3587 next = g_sequence_get (iter);
3588
3589 if (i % priv->cur_children_per_line == 0)
3590 {
3591 ctk_widget_get_allocation (CTK_WIDGET (next)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((next)), ((ctk_widget_get_type ()))))))
, &allocation);
3592 if ((vertical ? allocation.x : allocation.y) > start + page_size)
3593 break;
3594 }
3595
3596 child = next;
3597 i++;
3598 }
3599 }
3600 ctk_widget_get_allocation (CTK_WIDGET (child)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((child)), ((ctk_widget_get_type ()))))))
, &allocation);
3601 }
3602 break;
3603
3604 default:
3605 g_assert_not_reached ()do { g_assertion_message_expr ("Ctk", "ctkflowbox.c", 3605, (
(const char*) (__func__)), ((void*)0)); } while (0)
;
3606 }
3607
3608 if (child == NULL((void*)0) || child == priv->cursor_child)
3609 {
3610 CtkDirectionType direction = count < 0 ? CTK_DIR_UP : CTK_DIR_DOWN;
3611
3612 if (!ctk_widget_keynav_failed (CTK_WIDGET (box)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_widget_get_type ()))))))
, direction))
3613 {
3614 return FALSE(0);
3615 }
3616
3617 return TRUE(!(0));
3618 }
3619
3620 /* If the child has its "can-focus" property set to FALSE then it will
3621 * not grab the focus. We must pass the focus to its child directly.
3622 */
3623 if (!ctk_widget_get_can_focus (CTK_WIDGET (child)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((child)), ((ctk_widget_get_type ()))))))
))
3624 {
3625 CtkWidget *subchild;
3626
3627 subchild = ctk_bin_get_child (CTK_BIN (child)((((CtkBin*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((child)), ((ctk_bin_get_type ()))))))
);
3628 if (subchild)
3629 {
3630 CtkDirectionType direction = count < 0 ? CTK_DIR_TAB_BACKWARD : CTK_DIR_TAB_FORWARD;
3631 ctk_widget_child_focus (subchild, direction);
3632 }
3633 }
3634
3635 get_current_selection_modifiers (CTK_WIDGET (box)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_widget_get_type ()))))))
, &modify, &extend);
3636
3637 ctk_flow_box_update_cursor (box, child);
3638 if (!modify)
3639 ctk_flow_box_update_selection (box, child, FALSE(0), extend);
3640 return TRUE(!(0));
3641}
3642
3643/* Selection {{{2 */
3644
3645static void
3646ctk_flow_box_selected_children_changed (CtkFlowBox *box)
3647{
3648 _ctk_flow_box_accessible_selection_changed (CTK_WIDGET (box)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_widget_get_type ()))))))
);
3649}
3650
3651/* GObject implementation {{{2 */
3652
3653static void
3654ctk_flow_box_get_property (GObject *object,
3655 guint prop_id,
3656 GValue *value,
3657 GParamSpec *pspec)
3658{
3659 CtkFlowBox *box = CTK_FLOW_BOX (object)((((CtkFlowBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((object)), ((ctk_flow_box_get_type ()))))))
;
3660 CtkFlowBoxPrivate *priv = BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
;
3661
3662 switch (prop_id)
3663 {
3664 case PROP_ORIENTATION:
3665 g_value_set_enum (value, priv->orientation);
3666 break;
3667 case PROP_HOMOGENEOUS:
3668 g_value_set_boolean (value, priv->homogeneous);
3669 break;
3670 case PROP_COLUMN_SPACING:
3671 g_value_set_uint (value, priv->column_spacing);
3672 break;
3673 case PROP_ROW_SPACING:
3674 g_value_set_uint (value, priv->row_spacing);
3675 break;
3676 case PROP_MIN_CHILDREN_PER_LINE:
3677 g_value_set_uint (value, priv->min_children_per_line);
3678 break;
3679 case PROP_MAX_CHILDREN_PER_LINE:
3680 g_value_set_uint (value, priv->max_children_per_line);
3681 break;
3682 case PROP_SELECTION_MODE:
3683 g_value_set_enum (value, priv->selection_mode);
3684 break;
3685 case PROP_ACTIVATE_ON_SINGLE_CLICK:
3686 g_value_set_boolean (value, priv->activate_on_single_click);
3687 break;
3688 default:
3689 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec)do { GObject *_glib__object = (GObject*) ((object)); GParamSpec
*_glib__pspec = (GParamSpec*) ((pspec)); guint _glib__property_id
= ((prop_id)); g_warning ("%s:%d: invalid %s id %u for \"%s\" of type '%s' in '%s'"
, "ctkflowbox.c", 3689, ("property"), _glib__property_id, _glib__pspec
->name, g_type_name ((((((GTypeClass*) (((GTypeInstance*) (
_glib__pspec))->g_class))->g_type)))), (g_type_name (((
(((GTypeClass*) (((GTypeInstance*) (_glib__object))->g_class
))->g_type)))))); } while (0)
;
3690 break;
3691 }
3692}
3693
3694static void
3695ctk_flow_box_set_property (GObject *object,
3696 guint prop_id,
3697 const GValue *value,
3698 GParamSpec *pspec)
3699{
3700 CtkFlowBox *box = CTK_FLOW_BOX (object)((((CtkFlowBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((object)), ((ctk_flow_box_get_type ()))))))
;
3701 CtkFlowBoxPrivate *priv = BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
;
3702
3703 switch (prop_id)
3704 {
3705 case PROP_ORIENTATION:
3706 if (priv->orientation != g_value_get_enum (value))
3707 {
3708 priv->orientation = g_value_get_enum (value);
3709 _ctk_orientable_set_style_classes (CTK_ORIENTABLE (box)((((CtkOrientable*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_orientable_get_type ()))))))
);
3710 /* Re-box the children in the new orientation */
3711 ctk_widget_queue_resize (CTK_WIDGET (box)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_widget_get_type ()))))))
);
3712 g_object_notify_by_pspec (object, pspec);
3713 }
3714 break;
3715 case PROP_HOMOGENEOUS:
3716 ctk_flow_box_set_homogeneous (box, g_value_get_boolean (value));
3717 break;
3718 case PROP_COLUMN_SPACING:
3719 ctk_flow_box_set_column_spacing (box, g_value_get_uint (value));
3720 break;
3721 case PROP_ROW_SPACING:
3722 ctk_flow_box_set_row_spacing (box, g_value_get_uint (value));
3723 break;
3724 case PROP_MIN_CHILDREN_PER_LINE:
3725 ctk_flow_box_set_min_children_per_line (box, g_value_get_uint (value));
3726 break;
3727 case PROP_MAX_CHILDREN_PER_LINE:
3728 ctk_flow_box_set_max_children_per_line (box, g_value_get_uint (value));
3729 break;
3730 case PROP_SELECTION_MODE:
3731 ctk_flow_box_set_selection_mode (box, g_value_get_enum (value));
3732 break;
3733 case PROP_ACTIVATE_ON_SINGLE_CLICK:
3734 ctk_flow_box_set_activate_on_single_click (box, g_value_get_boolean (value));
3735 break;
3736 default:
3737 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec)do { GObject *_glib__object = (GObject*) ((object)); GParamSpec
*_glib__pspec = (GParamSpec*) ((pspec)); guint _glib__property_id
= ((prop_id)); g_warning ("%s:%d: invalid %s id %u for \"%s\" of type '%s' in '%s'"
, "ctkflowbox.c", 3737, ("property"), _glib__property_id, _glib__pspec
->name, g_type_name ((((((GTypeClass*) (((GTypeInstance*) (
_glib__pspec))->g_class))->g_type)))), (g_type_name (((
(((GTypeClass*) (((GTypeInstance*) (_glib__object))->g_class
))->g_type)))))); } while (0)
;
3738 break;
3739 }
3740}
3741
3742static void
3743ctk_flow_box_finalize (GObject *obj)
3744{
3745 CtkFlowBoxPrivate *priv = BOX_PRIV (obj)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(obj)))
;
3746
3747 if (priv->filter_destroy != NULL((void*)0))
3748 priv->filter_destroy (priv->filter_data);
3749 if (priv->sort_destroy != NULL((void*)0))
3750 priv->sort_destroy (priv->sort_data);
3751
3752 g_sequence_free (priv->children);
3753 g_clear_object (&priv->hadjustment)do { _Static_assert (sizeof *((&priv->hadjustment)) ==
sizeof (gpointer), "Expression evaluates to false"); __typeof__
(((&priv->hadjustment))) _pp = ((&priv->hadjustment
)); __typeof__ (*((&priv->hadjustment))) _ptr = *_pp; *
_pp = ((void*)0); if (_ptr) (g_object_unref) (_ptr); } while (
0)
;
3754 g_clear_object (&priv->vadjustment)do { _Static_assert (sizeof *((&priv->vadjustment)) ==
sizeof (gpointer), "Expression evaluates to false"); __typeof__
(((&priv->vadjustment))) _pp = ((&priv->vadjustment
)); __typeof__ (*((&priv->vadjustment))) _ptr = *_pp; *
_pp = ((void*)0); if (_ptr) (g_object_unref) (_ptr); } while (
0)
;
3755
3756 g_object_unref (priv->drag_gesture);
3757 g_object_unref (priv->multipress_gesture);
3758
3759 if (priv->bound_model)
3760 {
3761 if (priv->create_widget_func_data_destroy)
3762 priv->create_widget_func_data_destroy (priv->create_widget_func_data);
3763
3764 g_signal_handlers_disconnect_by_func (priv->bound_model, ctk_flow_box_bound_model_changed, obj)g_signal_handlers_disconnect_matched ((priv->bound_model),
(GSignalMatchType) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA
), 0, 0, ((void*)0), (ctk_flow_box_bound_model_changed), (obj
))
;
3765 g_clear_object (&priv->bound_model)do { _Static_assert (sizeof *((&priv->bound_model)) ==
sizeof (gpointer), "Expression evaluates to false"); __typeof__
(((&priv->bound_model))) _pp = ((&priv->bound_model
)); __typeof__ (*((&priv->bound_model))) _ptr = *_pp; *
_pp = ((void*)0); if (_ptr) (g_object_unref) (_ptr); } while (
0)
;
3766 }
3767
3768 g_clear_object (&priv->gadget)do { _Static_assert (sizeof *((&priv->gadget)) == sizeof
(gpointer), "Expression evaluates to false"); __typeof__ (((
&priv->gadget))) _pp = ((&priv->gadget)); __typeof__
(*((&priv->gadget))) _ptr = *_pp; *_pp = ((void*)0); if
(_ptr) (g_object_unref) (_ptr); } while (0)
;
3769
3770 G_OBJECT_CLASS (ctk_flow_box_parent_class)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((ctk_flow_box_parent_class)), (((GType) ((20) << (2
))))))))
->finalize (obj);
3771}
3772
3773static void
3774ctk_flow_box_class_init (CtkFlowBoxClass *class)
3775{
3776 GObjectClass *object_class = G_OBJECT_CLASS (class)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((class)), (((GType) ((20) << (2))))))))
;
3777 CtkWidgetClass *widget_class = CTK_WIDGET_CLASS (class)((((CtkWidgetClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((class)), ((ctk_widget_get_type ()))))))
;
3778 CtkContainerClass *container_class = CTK_CONTAINER_CLASS (class)((((CtkContainerClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((class)), ((ctk_container_get_type ()))))))
;
3779 CtkBindingSet *binding_set;
3780
3781 object_class->finalize = ctk_flow_box_finalize;
3782 object_class->get_property = ctk_flow_box_get_property;
3783 object_class->set_property = ctk_flow_box_set_property;
3784
3785 widget_class->enter_notify_event = ctk_flow_box_enter_notify_event;
3786 widget_class->leave_notify_event = ctk_flow_box_leave_notify_event;
3787 widget_class->motion_notify_event = ctk_flow_box_motion_notify_event;
3788 widget_class->size_allocate = ctk_flow_box_size_allocate;
3789 widget_class->realize = ctk_flow_box_realize;
3790 widget_class->unmap = ctk_flow_box_unmap;
3791 widget_class->focus = ctk_flow_box_focus;
3792 widget_class->draw = ctk_flow_box_draw;
3793 widget_class->key_press_event = ctk_flow_box_key_press_event;
3794 widget_class->get_request_mode = ctk_flow_box_get_request_mode;
3795 widget_class->get_preferred_width = ctk_flow_box_get_preferred_width;
3796 widget_class->get_preferred_height = ctk_flow_box_get_preferred_height;
3797 widget_class->get_preferred_height_for_width = ctk_flow_box_get_preferred_height_for_width;
3798 widget_class->get_preferred_width_for_height = ctk_flow_box_get_preferred_width_for_height;
3799
3800 container_class->add = ctk_flow_box_add;
3801 container_class->remove = ctk_flow_box_remove;
3802 container_class->forall = ctk_flow_box_forall;
3803 container_class->child_type = ctk_flow_box_child_type;
3804 ctk_container_class_handle_border_width (container_class);
3805
3806 class->activate_cursor_child = ctk_flow_box_activate_cursor_child;
3807 class->toggle_cursor_child = ctk_flow_box_toggle_cursor_child;
3808 class->move_cursor = ctk_flow_box_move_cursor;
3809 class->select_all = ctk_flow_box_select_all;
3810 class->unselect_all = ctk_flow_box_unselect_all;
3811 class->selected_children_changed = ctk_flow_box_selected_children_changed;
3812
3813 g_object_class_override_property (object_class, PROP_ORIENTATION, "orientation");
3814
3815 /**
3816 * CtkFlowBox:selection-mode:
3817 *
3818 * The selection mode used by the flow box.
3819 */
3820 props[PROP_SELECTION_MODE] =
3821 g_param_spec_enum ("selection-mode",
3822 P_("Selection mode")g_dgettext("ctk30" "-properties","Selection mode"),
3823 P_("The selection mode")g_dgettext("ctk30" "-properties","The selection mode"),
3824 CTK_TYPE_SELECTION_MODE(ctk_selection_mode_get_type ()),
3825 CTK_SELECTION_SINGLE,
3826 G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
3827
3828 /**
3829 * CtkFlowBox:activate-on-single-click:
3830 *
3831 * Determines whether children can be activated with a single
3832 * click, or require a double-click.
3833 */
3834 props[PROP_ACTIVATE_ON_SINGLE_CLICK] =
3835 g_param_spec_boolean ("activate-on-single-click",
3836 P_("Activate on Single Click")g_dgettext("ctk30" "-properties","Activate on Single Click"),
3837 P_("Activate row on a single click")g_dgettext("ctk30" "-properties","Activate row on a single click"
)
,
3838 TRUE(!(0)),
3839 G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
3840
3841 /**
3842 * CtkFlowBox:homogeneous:
3843 *
3844 * Determines whether all children should be allocated the
3845 * same size.
3846 */
3847 props[PROP_HOMOGENEOUS] =
3848 g_param_spec_boolean ("homogeneous",
3849 P_("Homogeneous")g_dgettext("ctk30" "-properties","Homogeneous"),
3850 P_("Whether the children should all be the same size")g_dgettext("ctk30" "-properties","Whether the children should all be the same size"
)
,
3851 FALSE(0),
3852 G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
3853
3854 /**
3855 * CtkFlowBox:min-children-per-line:
3856 *
3857 * The minimum number of children to allocate consecutively
3858 * in the given orientation.
3859 *
3860 * Setting the minimum children per line ensures
3861 * that a reasonably small height will be requested
3862 * for the overall minimum width of the box.
3863 */
3864 props[PROP_MIN_CHILDREN_PER_LINE] =
3865 g_param_spec_uint ("min-children-per-line",
3866 P_("Minimum Children Per Line")g_dgettext("ctk30" "-properties","Minimum Children Per Line"),
3867 P_("The minimum number of children to allocate "g_dgettext("ctk30" "-properties","The minimum number of children to allocate "
"consecutively in the given orientation.")
3868 "consecutively in the given orientation.")g_dgettext("ctk30" "-properties","The minimum number of children to allocate "
"consecutively in the given orientation.")
,
3869 0, G_MAXUINT(2147483647 *2U +1U), 0,
3870 G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
3871
3872 /**
3873 * CtkFlowBox:max-children-per-line:
3874 *
3875 * The maximum amount of children to request space for consecutively
3876 * in the given orientation.
3877 */
3878 props[PROP_MAX_CHILDREN_PER_LINE] =
3879 g_param_spec_uint ("max-children-per-line",
3880 P_("Maximum Children Per Line")g_dgettext("ctk30" "-properties","Maximum Children Per Line"),
3881 P_("The maximum amount of children to request space for "g_dgettext("ctk30" "-properties","The maximum amount of children to request space for "
"consecutively in the given orientation.")
3882 "consecutively in the given orientation.")g_dgettext("ctk30" "-properties","The maximum amount of children to request space for "
"consecutively in the given orientation.")
,
3883 1, G_MAXUINT(2147483647 *2U +1U), DEFAULT_MAX_CHILDREN_PER_LINE7,
3884 G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
3885
3886 /**
3887 * CtkFlowBox:row-spacing:
3888 *
3889 * The amount of vertical space between two children.
3890 */
3891 props[PROP_ROW_SPACING] =
3892 g_param_spec_uint ("row-spacing",
3893 P_("Vertical spacing")g_dgettext("ctk30" "-properties","Vertical spacing"),
3894 P_("The amount of vertical space between two children")g_dgettext("ctk30" "-properties","The amount of vertical space between two children"
)
,
3895 0, G_MAXUINT(2147483647 *2U +1U), 0,
3896 G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
3897
3898 /**
3899 * CtkFlowBox:column-spacing:
3900 *
3901 * The amount of horizontal space between two children.
3902 */
3903 props[PROP_COLUMN_SPACING] =
3904 g_param_spec_uint ("column-spacing",
3905 P_("Horizontal spacing")g_dgettext("ctk30" "-properties","Horizontal spacing"),
3906 P_("The amount of horizontal space between two children")g_dgettext("ctk30" "-properties","The amount of horizontal space between two children"
)
,
3907 0, G_MAXUINT(2147483647 *2U +1U), 0,
3908 G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
3909
3910 g_object_class_install_properties (object_class, LAST_PROP, props);
3911
3912 /**
3913 * CtkFlowBox::child-activated:
3914 * @box: the #CtkFlowBox on which the signal is emitted
3915 * @child: the child that is activated
3916 *
3917 * The ::child-activated signal is emitted when a child has been
3918 * activated by the user.
3919 */
3920 signals[CHILD_ACTIVATED] = g_signal_new (I_("child-activated")g_intern_static_string ("child-activated"),
3921 CTK_TYPE_FLOW_BOX(ctk_flow_box_get_type ()),
3922 G_SIGNAL_RUN_LAST,
3923 G_STRUCT_OFFSET (CtkFlowBoxClass, child_activated)((glong) __builtin_offsetof(CtkFlowBoxClass, child_activated)
)
,
3924 NULL((void*)0), NULL((void*)0),
3925 NULL((void*)0),
3926 G_TYPE_NONE((GType) ((1) << (2))), 1,
3927 CTK_TYPE_FLOW_BOX_CHILD(ctk_flow_box_child_get_type ()));
3928
3929 /**
3930 * CtkFlowBox::selected-children-changed:
3931 * @box: the #CtkFlowBox on wich the signal is emitted
3932 *
3933 * The ::selected-children-changed signal is emitted when the
3934 * set of selected children changes.
3935 *
3936 * Use ctk_flow_box_selected_foreach() or
3937 * ctk_flow_box_get_selected_children() to obtain the
3938 * selected children.
3939 */
3940 signals[SELECTED_CHILDREN_CHANGED] = g_signal_new (I_("selected-children-changed")g_intern_static_string ("selected-children-changed"),
3941 CTK_TYPE_FLOW_BOX(ctk_flow_box_get_type ()),
3942 G_SIGNAL_RUN_FIRST,
3943 G_STRUCT_OFFSET (CtkFlowBoxClass, selected_children_changed)((glong) __builtin_offsetof(CtkFlowBoxClass, selected_children_changed
))
,
3944 NULL((void*)0), NULL((void*)0),
3945 NULL((void*)0),
3946 G_TYPE_NONE((GType) ((1) << (2))), 0);
3947
3948 /**
3949 * CtkFlowBox::activate-cursor-child:
3950 * @box: the #CtkFlowBox on which the signal is emitted
3951 *
3952 * The ::activate-cursor-child signal is a
3953 * [keybinding signal][CtkBindingSignal]
3954 * which gets emitted when the user activates the @box.
3955 */
3956 signals[ACTIVATE_CURSOR_CHILD] = g_signal_new (I_("activate-cursor-child")g_intern_static_string ("activate-cursor-child"),
3957 CTK_TYPE_FLOW_BOX(ctk_flow_box_get_type ()),
3958 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
3959 G_STRUCT_OFFSET (CtkFlowBoxClass, activate_cursor_child)((glong) __builtin_offsetof(CtkFlowBoxClass, activate_cursor_child
))
,
3960 NULL((void*)0), NULL((void*)0),
3961 NULL((void*)0),
3962 G_TYPE_NONE((GType) ((1) << (2))), 0);
3963
3964 /**
3965 * CtkFlowBox::toggle-cursor-child:
3966 * @box: the #CtkFlowBox on which the signal is emitted
3967 *
3968 * The ::toggle-cursor-child signal is a
3969 * [keybinding signal][CtkBindingSignal]
3970 * which toggles the selection of the child that has the focus.
3971 *
3972 * The default binding for this signal is Ctrl-Space.
3973 */
3974 signals[TOGGLE_CURSOR_CHILD] = g_signal_new (I_("toggle-cursor-child")g_intern_static_string ("toggle-cursor-child"),
3975 CTK_TYPE_FLOW_BOX(ctk_flow_box_get_type ()),
3976 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
3977 G_STRUCT_OFFSET (CtkFlowBoxClass, toggle_cursor_child)((glong) __builtin_offsetof(CtkFlowBoxClass, toggle_cursor_child
))
,
3978 NULL((void*)0), NULL((void*)0),
3979 NULL((void*)0),
3980 G_TYPE_NONE((GType) ((1) << (2))), 0);
3981
3982 /**
3983 * CtkFlowBox::move-cursor:
3984 * @box: the #CtkFlowBox on which the signal is emitted
3985 * @step: the granularity fo the move, as a #CtkMovementStep
3986 * @count: the number of @step units to move
3987 *
3988 * The ::move-cursor signal is a
3989 * [keybinding signal][CtkBindingSignal]
3990 * which gets emitted when the user initiates a cursor movement.
3991 *
3992 * Applications should not connect to it, but may emit it with
3993 * g_signal_emit_by_name() if they need to control the cursor
3994 * programmatically.
3995 *
3996 * The default bindings for this signal come in two variants,
3997 * the variant with the Shift modifier extends the selection,
3998 * the variant without the Shift modifer does not.
3999 * There are too many key combinations to list them all here.
4000 * - Arrow keys move by individual children
4001 * - Home/End keys move to the ends of the box
4002 * - PageUp/PageDown keys move vertically by pages
4003 *
4004 * Returns: %TRUE to stop other handlers from being invoked for the event.
4005 * %FALSE to propagate the event further.
4006 */
4007 signals[MOVE_CURSOR] = g_signal_new (I_("move-cursor")g_intern_static_string ("move-cursor"),
4008 CTK_TYPE_FLOW_BOX(ctk_flow_box_get_type ()),
4009 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
4010 G_STRUCT_OFFSET (CtkFlowBoxClass, move_cursor)((glong) __builtin_offsetof(CtkFlowBoxClass, move_cursor)),
4011 NULL((void*)0), NULL((void*)0),
4012 _ctk_marshal_BOOLEAN__ENUM_INT,
4013 G_TYPE_BOOLEAN((GType) ((5) << (2))), 2,
4014 CTK_TYPE_MOVEMENT_STEP(ctk_movement_step_get_type ()), G_TYPE_INT((GType) ((6) << (2))));
4015 g_signal_set_va_marshaller (signals[MOVE_CURSOR],
4016 G_TYPE_FROM_CLASS (class)(((GTypeClass*) (class))->g_type),
4017 _ctk_marshal_BOOLEAN__ENUM_INTv);
4018 /**
4019 * CtkFlowBox::select-all:
4020 * @box: the #CtkFlowBox on which the signal is emitted
4021 *
4022 * The ::select-all signal is a
4023 * [keybinding signal][CtkBindingSignal]
4024 * which gets emitted to select all children of the box, if
4025 * the selection mode permits it.
4026 *
4027 * The default bindings for this signal is Ctrl-a.
4028 */
4029 signals[SELECT_ALL] = g_signal_new (I_("select-all")g_intern_static_string ("select-all"),
4030 CTK_TYPE_FLOW_BOX(ctk_flow_box_get_type ()),
4031 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
4032 G_STRUCT_OFFSET (CtkFlowBoxClass, select_all)((glong) __builtin_offsetof(CtkFlowBoxClass, select_all)),
4033 NULL((void*)0), NULL((void*)0),
4034 NULL((void*)0),
4035 G_TYPE_NONE((GType) ((1) << (2))), 0);
4036
4037 /**
4038 * CtkFlowBox::unselect-all:
4039 * @box: the #CtkFlowBox on which the signal is emitted
4040 *
4041 * The ::unselect-all signal is a
4042 * [keybinding signal][CtkBindingSignal]
4043 * which gets emitted to unselect all children of the box, if
4044 * the selection mode permits it.
4045 *
4046 * The default bindings for this signal is Ctrl-Shift-a.
4047 */
4048 signals[UNSELECT_ALL] = g_signal_new (I_("unselect-all")g_intern_static_string ("unselect-all"),
4049 CTK_TYPE_FLOW_BOX(ctk_flow_box_get_type ()),
4050 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
4051 G_STRUCT_OFFSET (CtkFlowBoxClass, unselect_all)((glong) __builtin_offsetof(CtkFlowBoxClass, unselect_all)),
4052 NULL((void*)0), NULL((void*)0),
4053 NULL((void*)0),
4054 G_TYPE_NONE((GType) ((1) << (2))), 0);
4055
4056 widget_class->activate_signal = signals[ACTIVATE_CURSOR_CHILD];
4057
4058 binding_set = ctk_binding_set_by_class (class);
4059 ctk_flow_box_add_move_binding (binding_set, CDK_KEY_Home0xff50, 0,
4060 CTK_MOVEMENT_BUFFER_ENDS, -1);
4061 ctk_flow_box_add_move_binding (binding_set, CDK_KEY_KP_Home0xff95, 0,
4062 CTK_MOVEMENT_BUFFER_ENDS, -1);
4063 ctk_flow_box_add_move_binding (binding_set, CDK_KEY_End0xff57, 0,
4064 CTK_MOVEMENT_BUFFER_ENDS, 1);
4065 ctk_flow_box_add_move_binding (binding_set, CDK_KEY_KP_End0xff9c, 0,
4066 CTK_MOVEMENT_BUFFER_ENDS, 1);
4067 ctk_flow_box_add_move_binding (binding_set, CDK_KEY_Up0xff52, 0,
4068 CTK_MOVEMENT_DISPLAY_LINES, -1);
4069 ctk_flow_box_add_move_binding (binding_set, CDK_KEY_KP_Up0xff97, 0,
4070 CTK_MOVEMENT_DISPLAY_LINES, -1);
4071 ctk_flow_box_add_move_binding (binding_set, CDK_KEY_Down0xff54, 0,
4072 CTK_MOVEMENT_DISPLAY_LINES, 1);
4073 ctk_flow_box_add_move_binding (binding_set, CDK_KEY_KP_Down0xff99, 0,
4074 CTK_MOVEMENT_DISPLAY_LINES, 1);
4075 ctk_flow_box_add_move_binding (binding_set, CDK_KEY_Page_Up0xff55, 0,
4076 CTK_MOVEMENT_PAGES, -1);
4077 ctk_flow_box_add_move_binding (binding_set, CDK_KEY_KP_Page_Up0xff9a, 0,
4078 CTK_MOVEMENT_PAGES, -1);
4079 ctk_flow_box_add_move_binding (binding_set, CDK_KEY_Page_Down0xff56, 0,
4080 CTK_MOVEMENT_PAGES, 1);
4081 ctk_flow_box_add_move_binding (binding_set, CDK_KEY_KP_Page_Down0xff9b, 0,
4082 CTK_MOVEMENT_PAGES, 1);
4083
4084 ctk_flow_box_add_move_binding (binding_set, CDK_KEY_Right0xff53, 0,
4085 CTK_MOVEMENT_VISUAL_POSITIONS, 1);
4086 ctk_flow_box_add_move_binding (binding_set, CDK_KEY_KP_Right0xff98, 0,
4087 CTK_MOVEMENT_VISUAL_POSITIONS, 1);
4088 ctk_flow_box_add_move_binding (binding_set, CDK_KEY_Left0xff51, 0,
4089 CTK_MOVEMENT_VISUAL_POSITIONS, -1);
4090 ctk_flow_box_add_move_binding (binding_set, CDK_KEY_KP_Left0xff96, 0,
4091 CTK_MOVEMENT_VISUAL_POSITIONS, -1);
4092
4093 ctk_binding_entry_add_signal (binding_set, CDK_KEY_space0x020, CDK_CONTROL_MASK,
4094 "toggle-cursor-child", 0, NULL((void*)0));
4095 ctk_binding_entry_add_signal (binding_set, CDK_KEY_KP_Space0xff80, CDK_CONTROL_MASK,
4096 "toggle-cursor-child", 0, NULL((void*)0));
4097
4098 ctk_binding_entry_add_signal (binding_set, CDK_KEY_a0x061, CDK_CONTROL_MASK,
4099 "select-all", 0);
4100 ctk_binding_entry_add_signal (binding_set, CDK_KEY_a0x061, CDK_CONTROL_MASK | CDK_SHIFT_MASK,
4101 "unselect-all", 0);
4102
4103 ctk_widget_class_set_accessible_type (widget_class, CTK_TYPE_FLOW_BOX_ACCESSIBLE(ctk_flow_box_accessible_get_type ()));
4104 ctk_widget_class_set_css_name (widget_class, "flowbox");
4105}
4106
4107static void
4108ctk_flow_box_init (CtkFlowBox *box)
4109{
4110 CtkFlowBoxPrivate *priv = BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
;
4111 CtkCssNode *widget_node;
4112
4113 ctk_widget_set_has_window (CTK_WIDGET (box)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_widget_get_type ()))))))
, TRUE(!(0)));
4114
4115 priv->orientation = CTK_ORIENTATION_HORIZONTAL;
4116 priv->selection_mode = CTK_SELECTION_SINGLE;
4117 priv->max_children_per_line = DEFAULT_MAX_CHILDREN_PER_LINE7;
4118 priv->column_spacing = 0;
4119 priv->row_spacing = 0;
4120 priv->activate_on_single_click = TRUE(!(0));
4121
4122 _ctk_orientable_set_style_classes (CTK_ORIENTABLE (box)((((CtkOrientable*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_orientable_get_type ()))))))
);
4123
4124 priv->children = g_sequence_new (NULL((void*)0));
4125
4126 priv->multipress_gesture = ctk_gesture_multi_press_new (CTK_WIDGET (box)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_widget_get_type ()))))))
);
4127 ctk_gesture_single_set_touch_only (CTK_GESTURE_SINGLE (priv->multipress_gesture)((((CtkGestureSingle*) (void *) g_type_check_instance_cast ((
GTypeInstance*) ((priv->multipress_gesture)), ((ctk_gesture_single_get_type
()))))))
,
4128 FALSE(0));
4129 ctk_gesture_single_set_button (CTK_GESTURE_SINGLE (priv->multipress_gesture)((((CtkGestureSingle*) (void *) g_type_check_instance_cast ((
GTypeInstance*) ((priv->multipress_gesture)), ((ctk_gesture_single_get_type
()))))))
,
4130 CDK_BUTTON_PRIMARY(1));
4131 ctk_event_controller_set_propagation_phase (CTK_EVENT_CONTROLLER (priv->multipress_gesture)((((CtkEventController*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((priv->multipress_gesture)), ((ctk_event_controller_get_type
()))))))
,
4132 CTK_PHASE_BUBBLE);
4133 g_signal_connect (priv->multipress_gesture, "pressed",g_signal_connect_data ((priv->multipress_gesture), ("pressed"
), (((GCallback) (ctk_flow_box_multipress_gesture_pressed))),
(box), ((void*)0), (GConnectFlags) 0)
4134 G_CALLBACK (ctk_flow_box_multipress_gesture_pressed), box)g_signal_connect_data ((priv->multipress_gesture), ("pressed"
), (((GCallback) (ctk_flow_box_multipress_gesture_pressed))),
(box), ((void*)0), (GConnectFlags) 0)
;
4135 g_signal_connect (priv->multipress_gesture, "released",g_signal_connect_data ((priv->multipress_gesture), ("released"
), (((GCallback) (ctk_flow_box_multipress_gesture_released)))
, (box), ((void*)0), (GConnectFlags) 0)
4136 G_CALLBACK (ctk_flow_box_multipress_gesture_released), box)g_signal_connect_data ((priv->multipress_gesture), ("released"
), (((GCallback) (ctk_flow_box_multipress_gesture_released)))
, (box), ((void*)0), (GConnectFlags) 0)
;
4137 g_signal_connect (priv->multipress_gesture, "stopped",g_signal_connect_data ((priv->multipress_gesture), ("stopped"
), (((GCallback) (ctk_flow_box_multipress_gesture_stopped))),
(box), ((void*)0), (GConnectFlags) 0)
4138 G_CALLBACK (ctk_flow_box_multipress_gesture_stopped), box)g_signal_connect_data ((priv->multipress_gesture), ("stopped"
), (((GCallback) (ctk_flow_box_multipress_gesture_stopped))),
(box), ((void*)0), (GConnectFlags) 0)
;
4139
4140 priv->drag_gesture = ctk_gesture_drag_new (CTK_WIDGET (box)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_widget_get_type ()))))))
);
4141 ctk_gesture_single_set_touch_only (CTK_GESTURE_SINGLE (priv->drag_gesture)((((CtkGestureSingle*) (void *) g_type_check_instance_cast ((
GTypeInstance*) ((priv->drag_gesture)), ((ctk_gesture_single_get_type
()))))))
,
4142 FALSE(0));
4143 ctk_gesture_single_set_button (CTK_GESTURE_SINGLE (priv->drag_gesture)((((CtkGestureSingle*) (void *) g_type_check_instance_cast ((
GTypeInstance*) ((priv->drag_gesture)), ((ctk_gesture_single_get_type
()))))))
,
4144 CDK_BUTTON_PRIMARY(1));
4145 ctk_event_controller_set_propagation_phase (CTK_EVENT_CONTROLLER (priv->drag_gesture)((((CtkEventController*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((priv->drag_gesture)), ((ctk_event_controller_get_type
()))))))
,
4146 CTK_PHASE_CAPTURE);
4147 g_signal_connect (priv->drag_gesture, "drag-begin",g_signal_connect_data ((priv->drag_gesture), ("drag-begin"
), (((GCallback) (ctk_flow_box_drag_gesture_begin))), (box), (
(void*)0), (GConnectFlags) 0)
4148 G_CALLBACK (ctk_flow_box_drag_gesture_begin), box)g_signal_connect_data ((priv->drag_gesture), ("drag-begin"
), (((GCallback) (ctk_flow_box_drag_gesture_begin))), (box), (
(void*)0), (GConnectFlags) 0)
;
4149 g_signal_connect (priv->drag_gesture, "drag-update",g_signal_connect_data ((priv->drag_gesture), ("drag-update"
), (((GCallback) (ctk_flow_box_drag_gesture_update))), (box),
((void*)0), (GConnectFlags) 0)
4150 G_CALLBACK (ctk_flow_box_drag_gesture_update), box)g_signal_connect_data ((priv->drag_gesture), ("drag-update"
), (((GCallback) (ctk_flow_box_drag_gesture_update))), (box),
((void*)0), (GConnectFlags) 0)
;
4151 g_signal_connect (priv->drag_gesture, "drag-end",g_signal_connect_data ((priv->drag_gesture), ("drag-end"),
(((GCallback) (ctk_flow_box_drag_gesture_end))), (box), ((void
*)0), (GConnectFlags) 0)
4152 G_CALLBACK (ctk_flow_box_drag_gesture_end), box)g_signal_connect_data ((priv->drag_gesture), ("drag-end"),
(((GCallback) (ctk_flow_box_drag_gesture_end))), (box), ((void
*)0), (GConnectFlags) 0)
;
4153
4154 widget_node = ctk_widget_get_css_node (CTK_WIDGET (box)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_widget_get_type ()))))))
);
4155 priv->gadget = ctk_css_custom_gadget_new_for_node (widget_node,
4156 CTK_WIDGET (box)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_widget_get_type ()))))))
,
4157 ctk_flow_box_measure,
4158 ctk_flow_box_allocate,
4159 ctk_flow_box_render,
4160 NULL((void*)0),
4161 NULL((void*)0));
4162}
4163
4164static void
4165ctk_flow_box_bound_model_changed (GListModel *list,
4166 guint position,
4167 guint removed,
4168 guint added,
4169 gpointer user_data)
4170{
4171 CtkFlowBox *box = user_data;
4172 CtkFlowBoxPrivate *priv = BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
;
4173 gint i;
4174
4175 while (removed--)
4176 {
4177 CtkFlowBoxChild *child;
4178
4179 child = ctk_flow_box_get_child_at_index (box, position);
4180 ctk_widget_destroy (CTK_WIDGET (child)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((child)), ((ctk_widget_get_type ()))))))
);
4181 }
4182
4183 for (i = 0; i < added; i++)
4184 {
4185 GObject *item;
4186 CtkWidget *widget;
4187
4188 item = g_list_model_get_item (list, position + i);
4189 widget = priv->create_widget_func (item, priv->create_widget_func_data);
4190
4191 /* We need to sink the floating reference here, so that we can accept
4192 * both instances created with a floating reference (e.g. C functions
4193 * that just return the result of g_object_new()) and without (e.g.
4194 * from language bindings which will automatically sink the floating
4195 * reference).
4196 *
4197 * See the similar code in ctklistbox.c:ctk_list_box_bound_model_changed.
4198 */
4199 if (g_object_is_floating (widget))
4200 g_object_ref_sink (widget)((__typeof__ (widget)) (g_object_ref_sink) (widget));
4201
4202 ctk_widget_show (widget);
4203 ctk_flow_box_insert (box, widget, position + i);
4204
4205 g_object_unref (widget);
4206 g_object_unref (item);
4207 }
4208}
4209
4210 /* Public API {{{2 */
4211
4212/**
4213 * ctk_flow_box_new:
4214 *
4215 * Creates a CtkFlowBox.
4216 *
4217 * Returns: a new #CtkFlowBox container
4218 *
4219 * Since: 3.12
4220 */
4221CtkWidget *
4222ctk_flow_box_new (void)
4223{
4224 return (CtkWidget *)g_object_new (CTK_TYPE_FLOW_BOX(ctk_flow_box_get_type ()), NULL((void*)0));
4225}
4226
4227static void
4228ctk_flow_box_insert_css_node (CtkFlowBox *box,
4229 CtkWidget *child,
4230 GSequenceIter *iter)
4231{
4232 GSequenceIter *prev_iter;
4233 CtkWidget *sibling;
4234
4235 prev_iter = g_sequence_iter_prev (iter);
4236
4237 if (prev_iter != iter)
4238 {
4239 sibling = g_sequence_get (prev_iter);
4240 ctk_css_node_insert_after (ctk_widget_get_css_node (CTK_WIDGET (box)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_widget_get_type ()))))))
),
4241 ctk_widget_get_css_node (child),
4242 ctk_widget_get_css_node (sibling));
4243 }
4244}
4245
4246/**
4247 * ctk_flow_box_insert:
4248 * @box: a #CtkFlowBox
4249 * @widget: the #CtkWidget to add
4250 * @position: the position to insert @child in
4251 *
4252 * Inserts the @widget into @box at @position.
4253 *
4254 * If a sort function is set, the widget will actually be inserted
4255 * at the calculated position and this function has the same effect
4256 * as ctk_container_add().
4257 *
4258 * If @position is -1, or larger than the total number of children
4259 * in the @box, then the @widget will be appended to the end.
4260 *
4261 * Since: 3.12
4262 */
4263void
4264ctk_flow_box_insert (CtkFlowBox *box,
4265 CtkWidget *widget,
4266 gint position)
4267{
4268 CtkFlowBoxPrivate *priv;
4269 CtkFlowBoxChild *child;
4270 GSequenceIter *iter;
4271
4272 g_return_if_fail (CTK_IS_FLOW_BOX (box))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((box)); GType __t = ((ctk_flow_box_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__
)), "CTK_IS_FLOW_BOX (box)"); return; } } while (0)
;
4273 g_return_if_fail (CTK_IS_WIDGET (widget))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((widget)); GType __t = ((ctk_widget_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__
)), "CTK_IS_WIDGET (widget)"); return; } } while (0)
;
4274
4275 priv = BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
;
4276
4277 if (CTK_IS_FLOW_BOX_CHILD (widget)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(widget)); GType __t = ((ctk_flow_box_child_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
4278 child = CTK_FLOW_BOX_CHILD (widget)((((CtkFlowBoxChild*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_flow_box_child_get_type ()))))))
;
4279 else
4280 {
4281 child = CTK_FLOW_BOX_CHILD (ctk_flow_box_child_new ())((((CtkFlowBoxChild*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((ctk_flow_box_child_new ())), ((ctk_flow_box_child_get_type
()))))))
;
4282 ctk_widget_show (CTK_WIDGET (child)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((child)), ((ctk_widget_get_type ()))))))
);
4283 ctk_container_add (CTK_CONTAINER (child)((((CtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((child)), ((ctk_container_get_type ()))))))
, widget);
4284 }
4285
4286 if (priv->sort_func != NULL((void*)0))
4287 iter = g_sequence_insert_sorted (priv->children, child,
4288 (GCompareDataFunc)ctk_flow_box_sort, box);
4289 else if (position == 0)
4290 iter = g_sequence_prepend (priv->children, child);
4291 else if (position == -1)
4292 iter = g_sequence_append (priv->children, child);
4293 else
4294 {
4295 GSequenceIter *pos;
4296 pos = g_sequence_get_iter_at_pos (priv->children, position);
4297 iter = g_sequence_insert_before (pos, child);
4298 }
4299
4300 ctk_flow_box_insert_css_node (box, CTK_WIDGET (child)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((child)), ((ctk_widget_get_type ()))))))
, iter);
4301
4302 CHILD_PRIV (child)((CtkFlowBoxChildPrivate*)ctk_flow_box_child_get_instance_private
((CtkFlowBoxChild*)(child)))
->iter = iter;
4303 ctk_widget_set_parent (CTK_WIDGET (child)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((child)), ((ctk_widget_get_type ()))))))
, CTK_WIDGET (box)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_widget_get_type ()))))))
);
4304 ctk_flow_box_apply_filter (box, child);
4305}
4306
4307/**
4308 * ctk_flow_box_get_child_at_index:
4309 * @box: a #CtkFlowBox
4310 * @idx: the position of the child
4311 *
4312 * Gets the nth child in the @box.
4313 *
4314 * Returns: (transfer none) (nullable): the child widget, which will
4315 * always be a #CtkFlowBoxChild or %NULL in case no child widget
4316 * with the given index exists.
4317 *
4318 * Since: 3.12
4319 */
4320CtkFlowBoxChild *
4321ctk_flow_box_get_child_at_index (CtkFlowBox *box,
4322 gint idx)
4323{
4324 GSequenceIter *iter;
4325
4326 g_return_val_if_fail (CTK_IS_FLOW_BOX (box), NULL)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((box)); GType __t = ((ctk_flow_box_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__
)), "CTK_IS_FLOW_BOX (box)"); return (((void*)0)); } } while (
0)
;
4327
4328 iter = g_sequence_get_iter_at_pos (BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
->children, idx);
4329 if (!g_sequence_iter_is_end (iter))
4330 return g_sequence_get (iter);
4331
4332 return NULL((void*)0);
4333}
4334
4335/**
4336 * ctk_flow_box_get_child_at_pos:
4337 * @box: a #CtkFlowBox
4338 * @x: the x coordinate of the child
4339 * @y: the y coordinate of the child
4340 *
4341 * Gets the child in the (@x, @y) position.
4342 *
4343 * Returns: (transfer none) (nullable): the child widget, which will
4344 * always be a #CtkFlowBoxChild or %NULL in case no child widget
4345 * exists for the given x and y coordinates.
4346 *
4347 * Since: 3.22.6
4348 */
4349CtkFlowBoxChild *
4350ctk_flow_box_get_child_at_pos (CtkFlowBox *box,
4351 gint x,
4352 gint y)
4353{
4354 CtkWidget *child;
4355 GSequenceIter *iter;
4356 CtkAllocation allocation;
4357
4358 for (iter = g_sequence_get_begin_iter (BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
->children);
4359 !g_sequence_iter_is_end (iter);
4360 iter = g_sequence_iter_next (iter))
4361 {
4362 child = g_sequence_get (iter);
4363 if (!child_is_visible (child))
4364 continue;
4365 ctk_widget_get_allocation (child, &allocation);
4366 if (x >= allocation.x && x < (allocation.x + allocation.width) &&
4367 y >= allocation.y && y < (allocation.y + allocation.height))
4368 return CTK_FLOW_BOX_CHILD (child)((((CtkFlowBoxChild*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((child)), ((ctk_flow_box_child_get_type ()))))))
;
4369 }
4370
4371 return NULL((void*)0);
4372}
4373
4374/**
4375 * ctk_flow_box_set_hadjustment:
4376 * @box: a #CtkFlowBox
4377 * @adjustment: an adjustment which should be adjusted
4378 * when the focus is moved among the descendents of @container
4379 *
4380 * Hooks up an adjustment to focus handling in @box.
4381 * The adjustment is also used for autoscrolling during
4382 * rubberband selection. See ctk_scrolled_window_get_hadjustment()
4383 * for a typical way of obtaining the adjustment, and
4384 * ctk_flow_box_set_vadjustment()for setting the vertical
4385 * adjustment.
4386 *
4387 * The adjustments have to be in pixel units and in the same
4388 * coordinate system as the allocation for immediate children
4389 * of the box.
4390 *
4391 * Since: 3.12
4392 */
4393void
4394ctk_flow_box_set_hadjustment (CtkFlowBox *box,
4395 CtkAdjustment *adjustment)
4396{
4397 CtkFlowBoxPrivate *priv;
4398
4399 g_return_if_fail (CTK_IS_FLOW_BOX (box))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((box)); GType __t = ((ctk_flow_box_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__
)), "CTK_IS_FLOW_BOX (box)"); return; } } while (0)
;
4400 g_return_if_fail (CTK_IS_ADJUSTMENT (adjustment))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((adjustment)); GType __t = ((ctk_adjustment_get_type ()))
; gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class
&& __inst->g_class->g_type == __t) __r = (!(0)
); else __r = g_type_check_instance_is_a (__inst, __t); __r; }
)))))) { } else { g_return_if_fail_warning ("Ctk", ((const char
*) (__func__)), "CTK_IS_ADJUSTMENT (adjustment)"); return; } }
while (0)
;
4401
4402 priv = BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
;
4403
4404 g_object_ref (adjustment)((__typeof__ (adjustment)) (g_object_ref) (adjustment));
4405 if (priv->hadjustment)
4406 g_object_unref (priv->hadjustment);
4407 priv->hadjustment = adjustment;
4408 ctk_container_set_focus_hadjustment (CTK_CONTAINER (box)((((CtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_container_get_type ()))))))
, adjustment);
4409}
4410
4411/**
4412 * ctk_flow_box_set_vadjustment:
4413 * @box: a #CtkFlowBox
4414 * @adjustment: an adjustment which should be adjusted
4415 * when the focus is moved among the descendents of @container
4416 *
4417 * Hooks up an adjustment to focus handling in @box.
4418 * The adjustment is also used for autoscrolling during
4419 * rubberband selection. See ctk_scrolled_window_get_vadjustment()
4420 * for a typical way of obtaining the adjustment, and
4421 * ctk_flow_box_set_hadjustment()for setting the horizontal
4422 * adjustment.
4423 *
4424 * The adjustments have to be in pixel units and in the same
4425 * coordinate system as the allocation for immediate children
4426 * of the box.
4427 *
4428 * Since: 3.12
4429 */
4430void
4431ctk_flow_box_set_vadjustment (CtkFlowBox *box,
4432 CtkAdjustment *adjustment)
4433{
4434 CtkFlowBoxPrivate *priv;
4435
4436 g_return_if_fail (CTK_IS_FLOW_BOX (box))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((box)); GType __t = ((ctk_flow_box_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__
)), "CTK_IS_FLOW_BOX (box)"); return; } } while (0)
;
4437 g_return_if_fail (CTK_IS_ADJUSTMENT (adjustment))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((adjustment)); GType __t = ((ctk_adjustment_get_type ()))
; gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class
&& __inst->g_class->g_type == __t) __r = (!(0)
); else __r = g_type_check_instance_is_a (__inst, __t); __r; }
)))))) { } else { g_return_if_fail_warning ("Ctk", ((const char
*) (__func__)), "CTK_IS_ADJUSTMENT (adjustment)"); return; } }
while (0)
;
4438
4439 priv = BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
;
4440
4441 g_object_ref (adjustment)((__typeof__ (adjustment)) (g_object_ref) (adjustment));
4442 if (priv->vadjustment)
4443 g_object_unref (priv->vadjustment);
4444 priv->vadjustment = adjustment;
4445 ctk_container_set_focus_vadjustment (CTK_CONTAINER (box)((((CtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_container_get_type ()))))))
, adjustment);
4446}
4447
4448static void
4449ctk_flow_box_check_model_compat (CtkFlowBox *box)
4450{
4451 CtkFlowBoxPrivate *priv = BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
;
4452
4453 if (priv->bound_model &&
4454 (priv->sort_func || priv->filter_func))
4455 g_warning ("CtkFlowBox with a model will ignore sort and filter functions");
4456}
4457
4458/**
4459 * ctk_flow_box_bind_model:
4460 * @box: a #CtkFlowBox
4461 * @model: (allow-none): the #GListModel to be bound to @box
4462 * @create_widget_func: a function that creates widgets for items
4463 * @user_data: user data passed to @create_widget_func
4464 * @user_data_free_func: function for freeing @user_data
4465 *
4466 * Binds @model to @box.
4467 *
4468 * If @box was already bound to a model, that previous binding is
4469 * destroyed.
4470 *
4471 * The contents of @box are cleared and then filled with widgets that
4472 * represent items from @model. @box is updated whenever @model changes.
4473 * If @model is %NULL, @box is left empty.
4474 *
4475 * It is undefined to add or remove widgets directly (for example, with
4476 * ctk_flow_box_insert() or ctk_container_add()) while @box is bound to a
4477 * model.
4478 *
4479 * Note that using a model is incompatible with the filtering and sorting
4480 * functionality in CtkFlowBox. When using a model, filtering and sorting
4481 * should be implemented by the model.
4482 *
4483 * Since: 3.18
4484 */
4485void
4486ctk_flow_box_bind_model (CtkFlowBox *box,
4487 GListModel *model,
4488 CtkFlowBoxCreateWidgetFunc create_widget_func,
4489 gpointer user_data,
4490 GDestroyNotify user_data_free_func)
4491{
4492 CtkFlowBoxPrivate *priv = BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
;
4493
4494 g_return_if_fail (CTK_IS_FLOW_BOX (box))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((box)); GType __t = ((ctk_flow_box_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__
)), "CTK_IS_FLOW_BOX (box)"); return; } } while (0)
;
4495 g_return_if_fail (model == NULL || G_IS_LIST_MODEL (model))do { if ((model == ((void*)0) || G_IS_LIST_MODEL (model))) { }
else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__
)), "model == NULL || G_IS_LIST_MODEL (model)"); return; } } while
(0)
;
4496 g_return_if_fail (model == NULL || create_widget_func != NULL)do { if ((model == ((void*)0) || create_widget_func != ((void
*)0))) { } else { g_return_if_fail_warning ("Ctk", ((const char
*) (__func__)), "model == NULL || create_widget_func != NULL"
); return; } } while (0)
;
4497
4498 if (priv->bound_model)
4499 {
4500 if (priv->create_widget_func_data_destroy)
4501 priv->create_widget_func_data_destroy (priv->create_widget_func_data);
4502
4503 g_signal_handlers_disconnect_by_func (priv->bound_model, ctk_flow_box_bound_model_changed, box)g_signal_handlers_disconnect_matched ((priv->bound_model),
(GSignalMatchType) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA
), 0, 0, ((void*)0), (ctk_flow_box_bound_model_changed), (box
))
;
4504 g_clear_object (&priv->bound_model)do { _Static_assert (sizeof *((&priv->bound_model)) ==
sizeof (gpointer), "Expression evaluates to false"); __typeof__
(((&priv->bound_model))) _pp = ((&priv->bound_model
)); __typeof__ (*((&priv->bound_model))) _ptr = *_pp; *
_pp = ((void*)0); if (_ptr) (g_object_unref) (_ptr); } while (
0)
;
4505 }
4506
4507 ctk_flow_box_forall (CTK_CONTAINER (box)((((CtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_container_get_type ()))))))
, FALSE(0), (CtkCallback) ctk_widget_destroy, NULL((void*)0));
4508
4509 if (model == NULL((void*)0))
4510 return;
4511
4512 priv->bound_model = g_object_ref (model)((__typeof__ (model)) (g_object_ref) (model));
4513 priv->create_widget_func = create_widget_func;
4514 priv->create_widget_func_data = user_data;
4515 priv->create_widget_func_data_destroy = user_data_free_func;
4516
4517 ctk_flow_box_check_model_compat (box);
4518
4519 g_signal_connect (priv->bound_model, "items-changed", G_CALLBACK (ctk_flow_box_bound_model_changed), box)g_signal_connect_data ((priv->bound_model), ("items-changed"
), (((GCallback) (ctk_flow_box_bound_model_changed))), (box),
((void*)0), (GConnectFlags) 0)
;
4520 ctk_flow_box_bound_model_changed (model, 0, 0, g_list_model_get_n_items (model), box);
4521}
4522
4523/* Setters and getters {{{2 */
4524
4525/**
4526 * ctk_flow_box_get_homogeneous:
4527 * @box: a #CtkFlowBox
4528 *
4529 * Returns whether the box is homogeneous (all children are the
4530 * same size). See ctk_box_set_homogeneous().
4531 *
4532 * Returns: %TRUE if the box is homogeneous.
4533 *
4534 * Since: 3.12
4535 */
4536gboolean
4537ctk_flow_box_get_homogeneous (CtkFlowBox *box)
4538{
4539 g_return_val_if_fail (CTK_IS_FLOW_BOX (box), FALSE)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((box)); GType __t = ((ctk_flow_box_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__
)), "CTK_IS_FLOW_BOX (box)"); return ((0)); } } while (0)
;
4540
4541 return BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
->homogeneous;
4542}
4543
4544/**
4545 * ctk_flow_box_set_homogeneous:
4546 * @box: a #CtkFlowBox
4547 * @homogeneous: %TRUE to create equal allotments,
4548 * %FALSE for variable allotments
4549 *
4550 * Sets the #CtkFlowBox:homogeneous property of @box, controlling
4551 * whether or not all children of @box are given equal space
4552 * in the box.
4553 *
4554 * Since: 3.12
4555 */
4556void
4557ctk_flow_box_set_homogeneous (CtkFlowBox *box,
4558 gboolean homogeneous)
4559{
4560 g_return_if_fail (CTK_IS_FLOW_BOX (box))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((box)); GType __t = ((ctk_flow_box_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__
)), "CTK_IS_FLOW_BOX (box)"); return; } } while (0)
;
4561
4562 homogeneous = homogeneous != FALSE(0);
4563
4564 if (BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
->homogeneous != homogeneous)
4565 {
4566 BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
->homogeneous = homogeneous;
4567
4568 g_object_notify_by_pspec (G_OBJECT (box)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), (((GType) ((20) << (2))))))))
, props[PROP_HOMOGENEOUS]);
4569 ctk_widget_queue_resize (CTK_WIDGET (box)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_widget_get_type ()))))))
);
4570 }
4571}
4572
4573/**
4574 * ctk_flow_box_set_row_spacing:
4575 * @box: a #CtkFlowBox
4576 * @spacing: the spacing to use
4577 *
4578 * Sets the vertical space to add between children.
4579 * See the #CtkFlowBox:row-spacing property.
4580 *
4581 * Since: 3.12
4582 */
4583void
4584ctk_flow_box_set_row_spacing (CtkFlowBox *box,
4585 guint spacing)
4586{
4587 g_return_if_fail (CTK_IS_FLOW_BOX (box))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((box)); GType __t = ((ctk_flow_box_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__
)), "CTK_IS_FLOW_BOX (box)"); return; } } while (0)
;
4588
4589 if (BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
->row_spacing != spacing)
4590 {
4591 BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
->row_spacing = spacing;
4592
4593 ctk_widget_queue_resize (CTK_WIDGET (box)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_widget_get_type ()))))))
);
4594 g_object_notify_by_pspec (G_OBJECT (box)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), (((GType) ((20) << (2))))))))
, props[PROP_ROW_SPACING]);
4595 }
4596}
4597
4598/**
4599 * ctk_flow_box_get_row_spacing:
4600 * @box: a #CtkFlowBox
4601 *
4602 * Gets the vertical spacing.
4603 *
4604 * Returns: the vertical spacing
4605 *
4606 * Since: 3.12
4607 */
4608guint
4609ctk_flow_box_get_row_spacing (CtkFlowBox *box)
4610{
4611 g_return_val_if_fail (CTK_IS_FLOW_BOX (box), FALSE)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((box)); GType __t = ((ctk_flow_box_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__
)), "CTK_IS_FLOW_BOX (box)"); return ((0)); } } while (0)
;
4612
4613 return BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
->row_spacing;
4614}
4615
4616/**
4617 * ctk_flow_box_set_column_spacing:
4618 * @box: a #CtkFlowBox
4619 * @spacing: the spacing to use
4620 *
4621 * Sets the horizontal space to add between children.
4622 * See the #CtkFlowBox:column-spacing property.
4623 *
4624 * Since: 3.12
4625 */
4626void
4627ctk_flow_box_set_column_spacing (CtkFlowBox *box,
4628 guint spacing)
4629{
4630 g_return_if_fail (CTK_IS_FLOW_BOX (box))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((box)); GType __t = ((ctk_flow_box_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__
)), "CTK_IS_FLOW_BOX (box)"); return; } } while (0)
;
4631
4632 if (BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
->column_spacing != spacing)
4633 {
4634 BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
->column_spacing = spacing;
4635
4636 ctk_widget_queue_resize (CTK_WIDGET (box)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_widget_get_type ()))))))
);
4637 g_object_notify_by_pspec (G_OBJECT (box)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), (((GType) ((20) << (2))))))))
, props[PROP_COLUMN_SPACING]);
4638 }
4639}
4640
4641/**
4642 * ctk_flow_box_get_column_spacing:
4643 * @box: a #CtkFlowBox
4644 *
4645 * Gets the horizontal spacing.
4646 *
4647 * Returns: the horizontal spacing
4648 *
4649 * Since: 3.12
4650 */
4651guint
4652ctk_flow_box_get_column_spacing (CtkFlowBox *box)
4653{
4654 g_return_val_if_fail (CTK_IS_FLOW_BOX (box), FALSE)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((box)); GType __t = ((ctk_flow_box_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__
)), "CTK_IS_FLOW_BOX (box)"); return ((0)); } } while (0)
;
4655
4656 return BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
->column_spacing;
4657}
4658
4659/**
4660 * ctk_flow_box_set_min_children_per_line:
4661 * @box: a #CtkFlowBox
4662 * @n_children: the minimum number of children per line
4663 *
4664 * Sets the minimum number of children to line up
4665 * in @box’s orientation before flowing.
4666 *
4667 * Since: 3.12
4668 */
4669void
4670ctk_flow_box_set_min_children_per_line (CtkFlowBox *box,
4671 guint n_children)
4672{
4673 g_return_if_fail (CTK_IS_FLOW_BOX (box))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((box)); GType __t = ((ctk_flow_box_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__
)), "CTK_IS_FLOW_BOX (box)"); return; } } while (0)
;
4674
4675 if (BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
->min_children_per_line != n_children)
4676 {
4677 BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
->min_children_per_line = n_children;
4678
4679 ctk_widget_queue_resize (CTK_WIDGET (box)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_widget_get_type ()))))))
);
4680 g_object_notify_by_pspec (G_OBJECT (box)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), (((GType) ((20) << (2))))))))
, props[PROP_MIN_CHILDREN_PER_LINE]);
4681 }
4682}
4683
4684/**
4685 * ctk_flow_box_get_min_children_per_line:
4686 * @box: a #CtkFlowBox
4687 *
4688 * Gets the minimum number of children per line.
4689 *
4690 * Returns: the minimum number of children per line
4691 *
4692 * Since: 3.12
4693 */
4694guint
4695ctk_flow_box_get_min_children_per_line (CtkFlowBox *box)
4696{
4697 g_return_val_if_fail (CTK_IS_FLOW_BOX (box), FALSE)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((box)); GType __t = ((ctk_flow_box_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__
)), "CTK_IS_FLOW_BOX (box)"); return ((0)); } } while (0)
;
4698
4699 return BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
->min_children_per_line;
4700}
4701
4702/**
4703 * ctk_flow_box_set_max_children_per_line:
4704 * @box: a #CtkFlowBox
4705 * @n_children: the maximum number of children per line
4706 *
4707 * Sets the maximum number of children to request and
4708 * allocate space for in @box’s orientation.
4709 *
4710 * Setting the maximum number of children per line
4711 * limits the overall natural size request to be no more
4712 * than @n_children children long in the given orientation.
4713 *
4714 * Since: 3.12
4715 */
4716void
4717ctk_flow_box_set_max_children_per_line (CtkFlowBox *box,
4718 guint n_children)
4719{
4720 g_return_if_fail (CTK_IS_FLOW_BOX (box))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((box)); GType __t = ((ctk_flow_box_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__
)), "CTK_IS_FLOW_BOX (box)"); return; } } while (0)
;
4721 g_return_if_fail (n_children > 0)do { if ((n_children > 0)) { } else { g_return_if_fail_warning
("Ctk", ((const char*) (__func__)), "n_children > 0"); return
; } } while (0)
;
4722
4723 if (BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
->max_children_per_line != n_children)
4724 {
4725 BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
->max_children_per_line = n_children;
4726
4727 ctk_widget_queue_resize (CTK_WIDGET (box)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_widget_get_type ()))))))
);
4728 g_object_notify_by_pspec (G_OBJECT (box)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), (((GType) ((20) << (2))))))))
, props[PROP_MAX_CHILDREN_PER_LINE]);
4729 }
4730}
4731
4732/**
4733 * ctk_flow_box_get_max_children_per_line:
4734 * @box: a #CtkFlowBox
4735 *
4736 * Gets the maximum number of children per line.
4737 *
4738 * Returns: the maximum number of children per line
4739 *
4740 * Since: 3.12
4741 */
4742guint
4743ctk_flow_box_get_max_children_per_line (CtkFlowBox *box)
4744{
4745 g_return_val_if_fail (CTK_IS_FLOW_BOX (box), FALSE)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((box)); GType __t = ((ctk_flow_box_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__
)), "CTK_IS_FLOW_BOX (box)"); return ((0)); } } while (0)
;
4746
4747 return BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
->max_children_per_line;
4748}
4749
4750/**
4751 * ctk_flow_box_set_activate_on_single_click:
4752 * @box: a #CtkFlowBox
4753 * @single: %TRUE to emit child-activated on a single click
4754 *
4755 * If @single is %TRUE, children will be activated when you click
4756 * on them, otherwise you need to double-click.
4757 *
4758 * Since: 3.12
4759 */
4760void
4761ctk_flow_box_set_activate_on_single_click (CtkFlowBox *box,
4762 gboolean single)
4763{
4764 g_return_if_fail (CTK_IS_FLOW_BOX (box))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((box)); GType __t = ((ctk_flow_box_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__
)), "CTK_IS_FLOW_BOX (box)"); return; } } while (0)
;
4765
4766 single = single != FALSE(0);
4767
4768 if (BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
->activate_on_single_click != single)
4769 {
4770 BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
->activate_on_single_click = single;
4771 g_object_notify_by_pspec (G_OBJECT (box)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), (((GType) ((20) << (2))))))))
, props[PROP_ACTIVATE_ON_SINGLE_CLICK]);
4772 }
4773}
4774
4775/**
4776 * ctk_flow_box_get_activate_on_single_click:
4777 * @box: a #CtkFlowBox
4778 *
4779 * Returns whether children activate on single clicks.
4780 *
4781 * Returns: %TRUE if children are activated on single click,
4782 * %FALSE otherwise
4783 *
4784 * Since: 3.12
4785 */
4786gboolean
4787ctk_flow_box_get_activate_on_single_click (CtkFlowBox *box)
4788{
4789 g_return_val_if_fail (CTK_IS_FLOW_BOX (box), FALSE)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((box)); GType __t = ((ctk_flow_box_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__
)), "CTK_IS_FLOW_BOX (box)"); return ((0)); } } while (0)
;
4790
4791 return BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
->activate_on_single_click;
4792}
4793
4794 /* Selection handling {{{2 */
4795
4796/**
4797 * ctk_flow_box_get_selected_children:
4798 * @box: a #CtkFlowBox
4799 *
4800 * Creates a list of all selected children.
4801 *
4802 * Returns: (element-type CtkFlowBoxChild) (transfer container):
4803 * A #GList containing the #CtkWidget for each selected child.
4804 * Free with g_list_free() when done.
4805 *
4806 * Since: 3.12
4807 */
4808GList *
4809ctk_flow_box_get_selected_children (CtkFlowBox *box)
4810{
4811 CtkFlowBoxChild *child;
4812 GSequenceIter *iter;
4813 GList *selected = NULL((void*)0);
4814
4815 g_return_val_if_fail (CTK_IS_FLOW_BOX (box), NULL)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((box)); GType __t = ((ctk_flow_box_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__
)), "CTK_IS_FLOW_BOX (box)"); return (((void*)0)); } } while (
0)
;
4816
4817 for (iter = g_sequence_get_begin_iter (BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
->children);
4818 !g_sequence_iter_is_end (iter);
4819 iter = g_sequence_iter_next (iter))
4820 {
4821 child = g_sequence_get (iter);
4822 if (CHILD_PRIV (child)((CtkFlowBoxChildPrivate*)ctk_flow_box_child_get_instance_private
((CtkFlowBoxChild*)(child)))
->selected)
4823 selected = g_list_prepend (selected, child);
4824 }
4825
4826 return g_list_reverse (selected);
4827}
4828
4829/**
4830 * ctk_flow_box_select_child:
4831 * @box: a #CtkFlowBox
4832 * @child: a child of @box
4833 *
4834 * Selects a single child of @box, if the selection
4835 * mode allows it.
4836 *
4837 * Since: 3.12
4838 */
4839void
4840ctk_flow_box_select_child (CtkFlowBox *box,
4841 CtkFlowBoxChild *child)
4842{
4843 g_return_if_fail (CTK_IS_FLOW_BOX (box))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((box)); GType __t = ((ctk_flow_box_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__
)), "CTK_IS_FLOW_BOX (box)"); return; } } while (0)
;
4844 g_return_if_fail (CTK_IS_FLOW_BOX_CHILD (child))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((child)); GType __t = ((ctk_flow_box_child_get_type ()));
gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class
&& __inst->g_class->g_type == __t) __r = (!(0)
); else __r = g_type_check_instance_is_a (__inst, __t); __r; }
)))))) { } else { g_return_if_fail_warning ("Ctk", ((const char
*) (__func__)), "CTK_IS_FLOW_BOX_CHILD (child)"); return; } }
while (0)
;
4845
4846 ctk_flow_box_select_child_internal (box, child);
4847}
4848
4849/**
4850 * ctk_flow_box_unselect_child:
4851 * @box: a #CtkFlowBox
4852 * @child: a child of @box
4853 *
4854 * Unselects a single child of @box, if the selection
4855 * mode allows it.
4856 *
4857 * Since: 3.12
4858 */
4859void
4860ctk_flow_box_unselect_child (CtkFlowBox *box,
4861 CtkFlowBoxChild *child)
4862{
4863 g_return_if_fail (CTK_IS_FLOW_BOX (box))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((box)); GType __t = ((ctk_flow_box_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__
)), "CTK_IS_FLOW_BOX (box)"); return; } } while (0)
;
4864 g_return_if_fail (CTK_IS_FLOW_BOX_CHILD (child))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((child)); GType __t = ((ctk_flow_box_child_get_type ()));
gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class
&& __inst->g_class->g_type == __t) __r = (!(0)
); else __r = g_type_check_instance_is_a (__inst, __t); __r; }
)))))) { } else { g_return_if_fail_warning ("Ctk", ((const char
*) (__func__)), "CTK_IS_FLOW_BOX_CHILD (child)"); return; } }
while (0)
;
4865
4866 ctk_flow_box_unselect_child_internal (box, child);
4867}
4868
4869/**
4870 * ctk_flow_box_select_all:
4871 * @box: a #CtkFlowBox
4872 *
4873 * Select all children of @box, if the selection
4874 * mode allows it.
4875 *
4876 * Since: 3.12
4877 */
4878void
4879ctk_flow_box_select_all (CtkFlowBox *box)
4880{
4881 g_return_if_fail (CTK_IS_FLOW_BOX (box))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((box)); GType __t = ((ctk_flow_box_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__
)), "CTK_IS_FLOW_BOX (box)"); return; } } while (0)
;
4882
4883 if (BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
->selection_mode != CTK_SELECTION_MULTIPLE)
4884 return;
4885
4886 if (g_sequence_get_length (BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
->children) > 0)
4887 {
4888 ctk_flow_box_select_all_between (box, NULL((void*)0), NULL((void*)0), FALSE(0));
4889 g_signal_emit (box, signals[SELECTED_CHILDREN_CHANGED], 0);
4890 }
4891}
4892
4893/**
4894 * ctk_flow_box_unselect_all:
4895 * @box: a #CtkFlowBox
4896 *
4897 * Unselect all children of @box, if the selection
4898 * mode allows it.
4899 *
4900 * Since: 3.12
4901 */
4902void
4903ctk_flow_box_unselect_all (CtkFlowBox *box)
4904{
4905 gboolean dirty = FALSE(0);
4906
4907 g_return_if_fail (CTK_IS_FLOW_BOX (box))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((box)); GType __t = ((ctk_flow_box_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__
)), "CTK_IS_FLOW_BOX (box)"); return; } } while (0)
;
4908
4909 if (BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
->selection_mode == CTK_SELECTION_BROWSE)
4910 return;
4911
4912 dirty = ctk_flow_box_unselect_all_internal (box);
4913
4914 if (dirty)
4915 g_signal_emit (box, signals[SELECTED_CHILDREN_CHANGED], 0);
4916}
4917
4918/**
4919 * CtkFlowBoxForeachFunc:
4920 * @box: a #CtkFlowBox
4921 * @child: a #CtkFlowBoxChild
4922 * @user_data: (closure): user data
4923 *
4924 * A function used by ctk_flow_box_selected_foreach().
4925 * It will be called on every selected child of the @box.
4926 *
4927 * Since: 3.12
4928 */
4929
4930/**
4931 * ctk_flow_box_selected_foreach:
4932 * @box: a #CtkFlowBox
4933 * @func: (scope call): the function to call for each selected child
4934 * @data: user data to pass to the function
4935 *
4936 * Calls a function for each selected child.
4937 *
4938 * Note that the selection cannot be modified from within
4939 * this function.
4940 *
4941 * Since: 3.12
4942 */
4943void
4944ctk_flow_box_selected_foreach (CtkFlowBox *box,
4945 CtkFlowBoxForeachFunc func,
4946 gpointer data)
4947{
4948 CtkFlowBoxChild *child;
4949 GSequenceIter *iter;
4950
4951 g_return_if_fail (CTK_IS_FLOW_BOX (box))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((box)); GType __t = ((ctk_flow_box_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__
)), "CTK_IS_FLOW_BOX (box)"); return; } } while (0)
;
4952
4953 for (iter = g_sequence_get_begin_iter (BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
->children);
4954 !g_sequence_iter_is_end (iter);
4955 iter = g_sequence_iter_next (iter))
4956 {
4957 child = g_sequence_get (iter);
4958 if (CHILD_PRIV (child)((CtkFlowBoxChildPrivate*)ctk_flow_box_child_get_instance_private
((CtkFlowBoxChild*)(child)))
->selected)
4959 (*func) (box, child, data);
4960 }
4961}
4962
4963/**
4964 * ctk_flow_box_set_selection_mode:
4965 * @box: a #CtkFlowBox
4966 * @mode: the new selection mode
4967 *
4968 * Sets how selection works in @box.
4969 * See #CtkSelectionMode for details.
4970 *
4971 * Since: 3.12
4972 */
4973void
4974ctk_flow_box_set_selection_mode (CtkFlowBox *box,
4975 CtkSelectionMode mode)
4976{
4977 gboolean dirty = FALSE(0);
4978
4979 g_return_if_fail (CTK_IS_FLOW_BOX (box))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((box)); GType __t = ((ctk_flow_box_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__
)), "CTK_IS_FLOW_BOX (box)"); return; } } while (0)
;
4980
4981 if (mode == BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
->selection_mode)
4982 return;
4983
4984 if (mode == CTK_SELECTION_NONE ||
4985 BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
->selection_mode == CTK_SELECTION_MULTIPLE)
4986 {
4987 dirty = ctk_flow_box_unselect_all_internal (box);
4988 BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
->selected_child = NULL((void*)0);
4989 }
4990
4991 BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
->selection_mode = mode;
4992
4993 g_object_notify_by_pspec (G_OBJECT (box)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), (((GType) ((20) << (2))))))))
, props[PROP_SELECTION_MODE]);
4994
4995 if (dirty)
4996 g_signal_emit (box, signals[SELECTED_CHILDREN_CHANGED], 0);
4997}
4998
4999/**
5000 * ctk_flow_box_get_selection_mode:
5001 * @box: a #CtkFlowBox
5002 *
5003 * Gets the selection mode of @box.
5004 *
5005 * Returns: the #CtkSelectionMode
5006 *
5007 * Since: 3.12
5008 */
5009CtkSelectionMode
5010ctk_flow_box_get_selection_mode (CtkFlowBox *box)
5011{
5012 g_return_val_if_fail (CTK_IS_FLOW_BOX (box), CTK_SELECTION_SINGLE)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((box)); GType __t = ((ctk_flow_box_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__
)), "CTK_IS_FLOW_BOX (box)"); return (CTK_SELECTION_SINGLE); }
} while (0)
;
5013
5014 return BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
->selection_mode;
5015}
5016
5017/* Filtering {{{2 */
5018
5019/**
5020 * CtkFlowBoxFilterFunc:
5021 * @child: a #CtkFlowBoxChild that may be filtered
5022 * @user_data: (closure): user data
5023 *
5024 * A function that will be called whenrever a child changes
5025 * or is added. It lets you control if the child should be
5026 * visible or not.
5027 *
5028 * Returns: %TRUE if the row should be visible, %FALSE otherwise
5029 *
5030 * Since: 3.12
5031 */
5032
5033/**
5034 * ctk_flow_box_set_filter_func:
5035 * @box: a #CtkFlowBox
5036 * @filter_func: (closure user_data) (allow-none): callback that
5037 * lets you filter which children to show
5038 * @user_data: user data passed to @filter_func
5039 * @destroy: destroy notifier for @user_data
5040 *
5041 * By setting a filter function on the @box one can decide dynamically
5042 * which of the children to show. For instance, to implement a search
5043 * function that only shows the children matching the search terms.
5044 *
5045 * The @filter_func will be called for each child after the call, and
5046 * it will continue to be called each time a child changes (via
5047 * ctk_flow_box_child_changed()) or when ctk_flow_box_invalidate_filter()
5048 * is called.
5049 *
5050 * Note that using a filter function is incompatible with using a model
5051 * (see ctk_flow_box_bind_model()).
5052 *
5053 * Since: 3.12
5054 */
5055void
5056ctk_flow_box_set_filter_func (CtkFlowBox *box,
5057 CtkFlowBoxFilterFunc filter_func,
5058 gpointer user_data,
5059 GDestroyNotify destroy)
5060{
5061 CtkFlowBoxPrivate *priv;
5062
5063 g_return_if_fail (CTK_IS_FLOW_BOX (box))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((box)); GType __t = ((ctk_flow_box_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__
)), "CTK_IS_FLOW_BOX (box)"); return; } } while (0)
;
5064
5065 priv = BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
;
5066
5067 if (priv->filter_destroy != NULL((void*)0))
5068 priv->filter_destroy (priv->filter_data);
5069
5070 priv->filter_func = filter_func;
5071 priv->filter_data = user_data;
5072 priv->filter_destroy = destroy;
5073
5074 ctk_flow_box_check_model_compat (box);
5075
5076 ctk_flow_box_apply_filter_all (box);
5077}
5078
5079/**
5080 * ctk_flow_box_invalidate_filter:
5081 * @box: a #CtkFlowBox
5082 *
5083 * Updates the filtering for all children.
5084 *
5085 * Call this function when the result of the filter
5086 * function on the @box is changed due ot an external
5087 * factor. For instance, this would be used if the
5088 * filter function just looked for a specific search
5089 * term, and the entry with the string has changed.
5090 *
5091 * Since: 3.12
5092 */
5093void
5094ctk_flow_box_invalidate_filter (CtkFlowBox *box)
5095{
5096 g_return_if_fail (CTK_IS_FLOW_BOX (box))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((box)); GType __t = ((ctk_flow_box_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__
)), "CTK_IS_FLOW_BOX (box)"); return; } } while (0)
;
5097
5098 if (BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
->filter_func != NULL((void*)0))
5099 ctk_flow_box_apply_filter_all (box);
5100}
5101
5102/* Sorting {{{2 */
5103
5104/**
5105 * CtkFlowBoxSortFunc:
5106 * @child1: the first child
5107 * @child2: the second child
5108 * @user_data: (closure): user data
5109 *
5110 * A function to compare two children to determine which
5111 * should come first.
5112 *
5113 * Returns: < 0 if @child1 should be before @child2, 0 if
5114 * the are equal, and > 0 otherwise
5115 *
5116 * Since: 3.12
5117 */
5118
5119/**
5120 * ctk_flow_box_set_sort_func:
5121 * @box: a #CtkFlowBox
5122 * @sort_func: (closure user_data) (allow-none): the sort function
5123 * @user_data: user data passed to @sort_func
5124 * @destroy: destroy notifier for @user_data
5125 *
5126 * By setting a sort function on the @box, one can dynamically
5127 * reorder the children of the box, based on the contents of
5128 * the children.
5129 *
5130 * The @sort_func will be called for each child after the call,
5131 * and will continue to be called each time a child changes (via
5132 * ctk_flow_box_child_changed()) and when ctk_flow_box_invalidate_sort()
5133 * is called.
5134 *
5135 * Note that using a sort function is incompatible with using a model
5136 * (see ctk_flow_box_bind_model()).
5137 *
5138 * Since: 3.12
5139 */
5140void
5141ctk_flow_box_set_sort_func (CtkFlowBox *box,
5142 CtkFlowBoxSortFunc sort_func,
5143 gpointer user_data,
5144 GDestroyNotify destroy)
5145{
5146 CtkFlowBoxPrivate *priv;
5147
5148 g_return_if_fail (CTK_IS_FLOW_BOX (box))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((box)); GType __t = ((ctk_flow_box_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__
)), "CTK_IS_FLOW_BOX (box)"); return; } } while (0)
;
5149
5150 priv = BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
;
5151
5152 if (priv->sort_destroy != NULL((void*)0))
5153 priv->sort_destroy (priv->sort_data);
5154
5155 priv->sort_func = sort_func;
5156 priv->sort_data = user_data;
5157 priv->sort_destroy = destroy;
5158
5159 ctk_flow_box_check_model_compat (box);
5160
5161 ctk_flow_box_invalidate_sort (box);
5162}
5163
5164static gint
5165ctk_flow_box_sort (CtkFlowBoxChild *a,
5166 CtkFlowBoxChild *b,
5167 CtkFlowBox *box)
5168{
5169 CtkFlowBoxPrivate *priv = BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
;
5170
5171 return priv->sort_func (a, b, priv->sort_data);
5172}
5173
5174static void
5175ctk_flow_box_css_node_foreach (gpointer data,
5176 gpointer user_data)
5177{
5178 CtkWidget **previous = user_data;
5179 CtkWidget *row = data;
5180 CtkCssNode *row_node;
5181 CtkCssNode *prev_node;
5182
5183 if (*previous)
5184 {
5185 prev_node = ctk_widget_get_css_node (*previous);
5186 row_node = ctk_widget_get_css_node (row);
5187 ctk_css_node_insert_after (ctk_css_node_get_parent (row_node),
5188 row_node,
5189 prev_node);
5190 }
5191
5192 *previous = row;
5193}
5194
5195/**
5196 * ctk_flow_box_invalidate_sort:
5197 * @box: a #CtkFlowBox
5198 *
5199 * Updates the sorting for all children.
5200 *
5201 * Call this when the result of the sort function on
5202 * @box is changed due to an external factor.
5203 *
5204 * Since: 3.12
5205 */
5206void
5207ctk_flow_box_invalidate_sort (CtkFlowBox *box)
5208{
5209 CtkFlowBoxPrivate *priv;
5210 CtkWidget *previous = NULL((void*)0);
5211
5212 g_return_if_fail (CTK_IS_FLOW_BOX (box))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((box)); GType __t = ((ctk_flow_box_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__
)), "CTK_IS_FLOW_BOX (box)"); return; } } while (0)
;
5213
5214 priv = BOX_PRIV (box)((CtkFlowBoxPrivate*)ctk_flow_box_get_instance_private ((CtkFlowBox
*)(box)))
;
5215
5216 if (priv->sort_func != NULL((void*)0))
5217 {
5218 g_sequence_sort (priv->children, (GCompareDataFunc)ctk_flow_box_sort, box);
5219 g_sequence_foreach (priv->children, ctk_flow_box_css_node_foreach, &previous);
5220 ctk_widget_queue_resize (CTK_WIDGET (box)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_widget_get_type ()))))))
);
5221 }
5222}
5223
5224/* vim:set foldmethod=marker expandtab: */