1/*
2 * Copyright © 2018 Benjamin Otte
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
16 *
17 * Authors: Benjamin Otte <otte@gnome.org>
18 */
19
20#include "config.h"
21
22#include "gtklistitemwidgetprivate.h"
23
24#include "gtkbinlayout.h"
25#include "gtkeventcontrollerfocus.h"
26#include "gtkeventcontrollermotion.h"
27#include "gtkgestureclick.h"
28#include "gtkintl.h"
29#include "gtklistitemfactoryprivate.h"
30#include "gtklistitemprivate.h"
31#include "gtklistbaseprivate.h"
32#include "gtkmain.h"
33#include "gtkselectionmodel.h"
34#include "gtkwidget.h"
35#include "gtkwidgetprivate.h"
36
37typedef struct _GtkListItemWidgetPrivate GtkListItemWidgetPrivate;
38struct _GtkListItemWidgetPrivate
39{
40 GtkListItemFactory *factory;
41 GtkListItem *list_item;
42
43 GObject *item;
44 guint position;
45 gboolean selected;
46 gboolean single_click_activate;
47};
48
49enum {
50 PROP_0,
51 PROP_FACTORY,
52 PROP_SINGLE_CLICK_ACTIVATE,
53
54 N_PROPS
55};
56
57enum
58{
59 ACTIVATE_SIGNAL,
60 LAST_SIGNAL
61};
62
63G_DEFINE_TYPE_WITH_PRIVATE (GtkListItemWidget, gtk_list_item_widget, GTK_TYPE_WIDGET)
64
65static GParamSpec *properties[N_PROPS] = { NULL, };
66static guint signals[LAST_SIGNAL] = { 0 };
67
68static void
69gtk_list_item_widget_activate_signal (GtkListItemWidget *self)
70{
71 GtkListItemWidgetPrivate *priv = gtk_list_item_widget_get_instance_private (self);
72
73 if (priv->list_item && !priv->list_item->activatable)
74 return;
75
76 gtk_widget_activate_action (GTK_WIDGET (self),
77 name: "list.activate-item",
78 format_string: "u",
79 priv->position);
80}
81
82static gboolean
83gtk_list_item_widget_focus (GtkWidget *widget,
84 GtkDirectionType direction)
85{
86 GtkWidget *child, *focus_child;
87
88 /* The idea of this function is the following:
89 * 1. If any child can take focus, do not ever attempt
90 * to take focus.
91 * 2. Otherwise, if this item is selectable or activatable,
92 * allow focusing this widget.
93 *
94 * This makes sure every item in a list is focusable for
95 * activation and selection handling, but no useless widgets
96 * get focused and moving focus is as fast as possible.
97 */
98
99 focus_child = gtk_widget_get_focus_child (widget);
100 if (focus_child && gtk_widget_child_focus (widget: focus_child, direction))
101 return TRUE;
102
103 for (child = focus_child ? gtk_widget_get_next_sibling (widget: focus_child)
104 : gtk_widget_get_first_child (widget);
105 child;
106 child = gtk_widget_get_next_sibling (widget: child))
107 {
108 if (gtk_widget_child_focus (widget: child, direction))
109 return TRUE;
110 }
111
112 if (focus_child)
113 return FALSE;
114
115 if (gtk_widget_is_focus (widget))
116 return FALSE;
117
118 return gtk_widget_grab_focus (widget);
119}
120
121static gboolean
122gtk_list_item_widget_grab_focus (GtkWidget *widget)
123{
124 GtkListItemWidget *self = GTK_LIST_ITEM_WIDGET (widget);
125 GtkListItemWidgetPrivate *priv = gtk_list_item_widget_get_instance_private (self);
126 GtkWidget *child;
127
128 for (child = gtk_widget_get_first_child (widget);
129 child;
130 child = gtk_widget_get_next_sibling (widget: child))
131 {
132 if (gtk_widget_grab_focus (widget: child))
133 return TRUE;
134 }
135
136 if (priv->list_item == NULL ||
137 !priv->list_item->selectable)
138 return FALSE;
139
140 return GTK_WIDGET_CLASS (gtk_list_item_widget_parent_class)->grab_focus (widget);
141}
142
143static void
144gtk_list_item_widget_root (GtkWidget *widget)
145{
146 GtkListItemWidget *self = GTK_LIST_ITEM_WIDGET (widget);
147 GtkListItemWidgetPrivate *priv = gtk_list_item_widget_get_instance_private (self);
148
149 GTK_WIDGET_CLASS (gtk_list_item_widget_parent_class)->root (widget);
150
151 if (priv->factory)
152 gtk_list_item_factory_setup (self: priv->factory, widget: self);
153}
154
155static void
156gtk_list_item_widget_unroot (GtkWidget *widget)
157{
158 GtkListItemWidget *self = GTK_LIST_ITEM_WIDGET (widget);
159 GtkListItemWidgetPrivate *priv = gtk_list_item_widget_get_instance_private (self);
160
161 GTK_WIDGET_CLASS (gtk_list_item_widget_parent_class)->unroot (widget);
162
163 if (priv->list_item)
164 gtk_list_item_factory_teardown (self: priv->factory, widget: self);
165}
166
167static void
168gtk_list_item_widget_set_property (GObject *object,
169 guint property_id,
170 const GValue *value,
171 GParamSpec *pspec)
172{
173 GtkListItemWidget *self = GTK_LIST_ITEM_WIDGET (object);
174
175 switch (property_id)
176 {
177 case PROP_FACTORY:
178 gtk_list_item_widget_set_factory (self, factory: g_value_get_object (value));
179 break;
180
181 case PROP_SINGLE_CLICK_ACTIVATE:
182 gtk_list_item_widget_set_single_click_activate (self, single_click_activate: g_value_get_boolean (value));
183 break;
184
185 default:
186 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
187 break;
188 }
189}
190
191static void
192gtk_list_item_widget_dispose (GObject *object)
193{
194 GtkListItemWidget *self = GTK_LIST_ITEM_WIDGET (object);
195 GtkListItemWidgetPrivate *priv = gtk_list_item_widget_get_instance_private (self);
196
197 g_assert (priv->list_item == NULL);
198
199 g_clear_object (&priv->item);
200 g_clear_object (&priv->factory);
201
202 G_OBJECT_CLASS (gtk_list_item_widget_parent_class)->dispose (object);
203}
204
205static void
206gtk_list_item_widget_select_action (GtkWidget *widget,
207 const char *action_name,
208 GVariant *parameter)
209{
210 GtkListItemWidget *self = GTK_LIST_ITEM_WIDGET (widget);
211 GtkListItemWidgetPrivate *priv = gtk_list_item_widget_get_instance_private (self);
212 gboolean modify, extend;
213
214 if (priv->list_item && !priv->list_item->selectable)
215 return;
216
217 g_variant_get (value: parameter, format_string: "(bb)", &modify, &extend);
218
219 gtk_widget_activate_action (GTK_WIDGET (self),
220 name: "list.select-item",
221 format_string: "(ubb)",
222 priv->position, modify, extend);
223}
224
225static void
226gtk_list_item_widget_class_init (GtkListItemWidgetClass *klass)
227{
228 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
229 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
230
231 klass->activate_signal = gtk_list_item_widget_activate_signal;
232
233 widget_class->focus = gtk_list_item_widget_focus;
234 widget_class->grab_focus = gtk_list_item_widget_grab_focus;
235 widget_class->root = gtk_list_item_widget_root;
236 widget_class->unroot = gtk_list_item_widget_unroot;
237
238 gobject_class->set_property = gtk_list_item_widget_set_property;
239 gobject_class->dispose = gtk_list_item_widget_dispose;
240
241 properties[PROP_FACTORY] =
242 g_param_spec_object (name: "factory",
243 nick: "Factory",
244 blurb: "Factory managing this list item",
245 GTK_TYPE_LIST_ITEM_FACTORY,
246 flags: G_PARAM_WRITABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
247
248 properties[PROP_SINGLE_CLICK_ACTIVATE] =
249 g_param_spec_boolean (name: "single-click-activate",
250 nick: "Single click activate",
251 blurb: "Activate on single click",
252 FALSE,
253 flags: G_PARAM_WRITABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
254
255 g_object_class_install_properties (oclass: gobject_class, n_pspecs: N_PROPS, pspecs: properties);
256
257 signals[ACTIVATE_SIGNAL] =
258 g_signal_new (I_("activate-keybinding"),
259 G_OBJECT_CLASS_TYPE (gobject_class),
260 signal_flags: G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
261 G_STRUCT_OFFSET (GtkListItemWidgetClass, activate_signal),
262 NULL, NULL,
263 NULL,
264 G_TYPE_NONE, n_params: 0);
265
266 gtk_widget_class_set_activate_signal (widget_class, signal_id: signals[ACTIVATE_SIGNAL]);
267
268 /**
269 * GtkListItem|listitem.select:
270 * @modify: %TRUE to toggle the existing selection, %FALSE to select
271 * @extend: %TRUE to extend the selection
272 *
273 * Changes selection if the item is selectable.
274 * If the item is not selectable, nothing happens.
275 *
276 * This function will emit the list.select-item action and the resulting
277 * behavior, in particular the interpretation of @modify and @extend
278 * depends on the view containing this listitem. See for example
279 * GtkListView|list.select-item or GtkGridView|list.select-item.
280 */
281 gtk_widget_class_install_action (widget_class,
282 action_name: "listitem.select",
283 parameter_type: "(bb)",
284 activate: gtk_list_item_widget_select_action);
285
286 gtk_widget_class_add_binding_signal (widget_class, GDK_KEY_Return, mods: 0,
287 signal: "activate-keybinding", format_string: 0);
288 gtk_widget_class_add_binding_signal (widget_class, GDK_KEY_ISO_Enter, mods: 0,
289 signal: "activate-keybinding", format_string: 0);
290 gtk_widget_class_add_binding_signal (widget_class, GDK_KEY_KP_Enter, mods: 0,
291 signal: "activate-keybinding", format_string: 0);
292
293 /* note that some of these may get overwritten by child widgets,
294 * such as GtkTreeExpander */
295 gtk_widget_class_add_binding_action (widget_class, GDK_KEY_space, mods: 0,
296 action_name: "listitem.select", format_string: "(bb)", TRUE, FALSE);
297 gtk_widget_class_add_binding_action (widget_class, GDK_KEY_space, mods: GDK_CONTROL_MASK,
298 action_name: "listitem.select", format_string: "(bb)", TRUE, FALSE);
299 gtk_widget_class_add_binding_action (widget_class, GDK_KEY_space, mods: GDK_SHIFT_MASK,
300 action_name: "listitem.select", format_string: "(bb)", TRUE, FALSE);
301 gtk_widget_class_add_binding_action (widget_class, GDK_KEY_space, mods: GDK_CONTROL_MASK | GDK_SHIFT_MASK,
302 action_name: "listitem.select", format_string: "(bb)", TRUE, FALSE);
303 gtk_widget_class_add_binding_action (widget_class, GDK_KEY_KP_Space, mods: 0,
304 action_name: "listitem.select", format_string: "(bb)", TRUE, FALSE);
305 gtk_widget_class_add_binding_action (widget_class, GDK_KEY_KP_Space, mods: GDK_CONTROL_MASK,
306 action_name: "listitem.select", format_string: "(bb)", TRUE, FALSE);
307 gtk_widget_class_add_binding_action (widget_class, GDK_KEY_KP_Space, mods: GDK_SHIFT_MASK,
308 action_name: "listitem.select", format_string: "(bb)", TRUE, FALSE);
309 gtk_widget_class_add_binding_action (widget_class, GDK_KEY_KP_Space, mods: GDK_CONTROL_MASK | GDK_SHIFT_MASK,
310 action_name: "listitem.select", format_string: "(bb)", TRUE, FALSE);
311
312 /* This gets overwritten by gtk_list_item_widget_new() but better safe than sorry */
313 gtk_widget_class_set_css_name (widget_class, I_("row"));
314 gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT);
315}
316
317static void
318gtk_list_item_widget_click_gesture_pressed (GtkGestureClick *gesture,
319 int n_press,
320 double x,
321 double y,
322 GtkListItemWidget *self)
323{
324 GtkListItemWidgetPrivate *priv = gtk_list_item_widget_get_instance_private (self);
325 GtkWidget *widget = GTK_WIDGET (self);
326
327 if (priv->list_item && !priv->list_item->selectable && !priv->list_item->activatable)
328 {
329 gtk_gesture_set_state (GTK_GESTURE (gesture), state: GTK_EVENT_SEQUENCE_DENIED);
330 return;
331 }
332
333 if (!priv->list_item || priv->list_item->activatable)
334 {
335 if (n_press == 2 && !priv->single_click_activate)
336 {
337 gtk_gesture_set_state (GTK_GESTURE (gesture), state: GTK_EVENT_SEQUENCE_CLAIMED);
338 gtk_widget_activate_action (GTK_WIDGET (self),
339 name: "list.activate-item",
340 format_string: "u",
341 priv->position);
342 }
343 }
344
345 gtk_widget_set_state_flags (widget, flags: GTK_STATE_FLAG_ACTIVE, FALSE);
346
347 if (gtk_widget_get_focus_on_click (widget))
348 gtk_widget_grab_focus (widget);
349}
350
351static void
352gtk_list_item_widget_click_gesture_released (GtkGestureClick *gesture,
353 int n_press,
354 double x,
355 double y,
356 GtkListItemWidget *self)
357{
358 GtkListItemWidgetPrivate *priv = gtk_list_item_widget_get_instance_private (self);
359
360 if (!priv->list_item || priv->list_item->activatable)
361 {
362 if (n_press == 1 && priv->single_click_activate)
363 {
364 gtk_gesture_set_state (GTK_GESTURE (gesture), state: GTK_EVENT_SEQUENCE_CLAIMED);
365 gtk_widget_activate_action (GTK_WIDGET (self),
366 name: "list.activate-item",
367 format_string: "u",
368 priv->position);
369 return;
370 }
371 }
372
373 if (!priv->list_item || priv->list_item->selectable)
374 {
375 GdkModifierType state;
376 GdkEvent *event;
377 gboolean extend, modify;
378
379 event = gtk_gesture_get_last_event (GTK_GESTURE (gesture),
380 sequence: gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture)));
381 state = gdk_event_get_modifier_state (event);
382 extend = (state & GDK_SHIFT_MASK) != 0;
383 modify = (state & GDK_CONTROL_MASK) != 0;
384
385 gtk_widget_activate_action (GTK_WIDGET (self),
386 name: "list.select-item",
387 format_string: "(ubb)",
388 priv->position, modify, extend);
389 }
390
391 gtk_widget_unset_state_flags (GTK_WIDGET (self), flags: GTK_STATE_FLAG_ACTIVE);
392}
393
394static void
395gtk_list_item_widget_enter_cb (GtkEventControllerFocus *controller,
396 GtkListItemWidget *self)
397{
398 GtkWidget *widget = GTK_WIDGET (self);
399 GtkListItemWidgetPrivate *priv = gtk_list_item_widget_get_instance_private (self);
400
401 gtk_widget_activate_action (widget,
402 name: "list.scroll-to-item",
403 format_string: "u",
404 priv->position);
405}
406
407static void
408gtk_list_item_widget_hover_cb (GtkEventControllerMotion *controller,
409 double x,
410 double y,
411 GtkListItemWidget *self)
412{
413 GtkListItemWidgetPrivate *priv = gtk_list_item_widget_get_instance_private (self);
414
415 if (!priv->single_click_activate)
416 return;
417
418 if (!priv->list_item || priv->list_item->selectable)
419 {
420 gtk_widget_activate_action (GTK_WIDGET (self),
421 name: "list.select-item",
422 format_string: "(ubb)",
423 priv->position, FALSE, FALSE);
424 }
425}
426
427static void
428gtk_list_item_widget_click_gesture_canceled (GtkGestureClick *gesture,
429 GdkEventSequence *sequence,
430 GtkListItemWidget *self)
431{
432 gtk_widget_unset_state_flags (GTK_WIDGET (self), flags: GTK_STATE_FLAG_ACTIVE);
433}
434
435static void
436gtk_list_item_widget_init (GtkListItemWidget *self)
437{
438 GtkEventController *controller;
439 GtkGesture *gesture;
440
441 gtk_widget_set_focusable (GTK_WIDGET (self), TRUE);
442
443 gesture = gtk_gesture_click_new ();
444 gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER (gesture),
445 phase: GTK_PHASE_BUBBLE);
446 gtk_gesture_single_set_touch_only (GTK_GESTURE_SINGLE (gesture),
447 FALSE);
448 gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (gesture),
449 GDK_BUTTON_PRIMARY);
450 g_signal_connect (gesture, "pressed",
451 G_CALLBACK (gtk_list_item_widget_click_gesture_pressed), self);
452 g_signal_connect (gesture, "released",
453 G_CALLBACK (gtk_list_item_widget_click_gesture_released), self);
454 g_signal_connect (gesture, "cancel",
455 G_CALLBACK (gtk_list_item_widget_click_gesture_canceled), self);
456 gtk_widget_add_controller (GTK_WIDGET (self), GTK_EVENT_CONTROLLER (gesture));
457
458 controller = gtk_event_controller_focus_new ();
459 g_signal_connect (controller, "enter", G_CALLBACK (gtk_list_item_widget_enter_cb), self);
460 gtk_widget_add_controller (GTK_WIDGET (self), controller);
461
462 controller = gtk_event_controller_motion_new ();
463 g_signal_connect (controller, "enter", G_CALLBACK (gtk_list_item_widget_hover_cb), self);
464 gtk_widget_add_controller (GTK_WIDGET (self), controller);
465}
466
467GtkWidget *
468gtk_list_item_widget_new (GtkListItemFactory *factory,
469 const char *css_name,
470 GtkAccessibleRole role)
471{
472 g_return_val_if_fail (css_name != NULL, NULL);
473
474 return g_object_new (GTK_TYPE_LIST_ITEM_WIDGET,
475 first_property_name: "css-name", css_name,
476 "accessible-role", role,
477 "factory", factory,
478 NULL);
479}
480
481void
482gtk_list_item_widget_update (GtkListItemWidget *self,
483 guint position,
484 gpointer item,
485 gboolean selected)
486{
487 GtkListItemWidgetPrivate *priv = gtk_list_item_widget_get_instance_private (self);
488 gboolean was_selected;
489
490 was_selected = priv->selected;
491
492 if (priv->list_item)
493 gtk_list_item_factory_update (self: priv->factory, widget: self, position, item, selected);
494 else
495 gtk_list_item_widget_default_update (self, NULL, position, item, selected);
496
497 /* don't look at selected variable, it's not reentrancy safe */
498 if (was_selected != priv->selected)
499 {
500 if (priv->selected)
501 gtk_widget_set_state_flags (GTK_WIDGET (self), flags: GTK_STATE_FLAG_SELECTED, FALSE);
502 else
503 gtk_widget_unset_state_flags (GTK_WIDGET (self), flags: GTK_STATE_FLAG_SELECTED);
504
505 gtk_accessible_update_state (self: GTK_ACCESSIBLE (ptr: self),
506 first_state: GTK_ACCESSIBLE_STATE_SELECTED, priv->selected,
507 -1);
508 }
509}
510
511void
512gtk_list_item_widget_default_setup (GtkListItemWidget *self,
513 GtkListItem *list_item)
514{
515 GtkListItemWidgetPrivate *priv = gtk_list_item_widget_get_instance_private (self);
516
517 priv->list_item = list_item;
518 list_item->owner = self;
519
520 if (list_item->child)
521 gtk_list_item_widget_add_child (self, child: list_item->child);
522
523 gtk_list_item_widget_set_activatable (self, activatable: list_item->activatable);
524
525 if (priv->item)
526 g_object_notify (G_OBJECT (list_item), property_name: "item");
527 if (priv->position != GTK_INVALID_LIST_POSITION)
528 g_object_notify (G_OBJECT (list_item), property_name: "position");
529 if (priv->selected)
530 g_object_notify (G_OBJECT (list_item), property_name: "selected");
531}
532
533void
534gtk_list_item_widget_default_teardown (GtkListItemWidget *self,
535 GtkListItem *list_item)
536{
537 GtkListItemWidgetPrivate *priv = gtk_list_item_widget_get_instance_private (self);
538
539 g_assert (priv->list_item == list_item);
540
541 priv->list_item = NULL;
542 list_item->owner = NULL;
543
544 if (list_item->child)
545 gtk_list_item_widget_remove_child (self, child: list_item->child);
546
547 gtk_list_item_widget_set_activatable (self, FALSE);
548
549 if (priv->item)
550 g_object_notify (G_OBJECT (list_item), property_name: "item");
551 if (priv->position != GTK_INVALID_LIST_POSITION)
552 g_object_notify (G_OBJECT (list_item), property_name: "position");
553 if (priv->selected)
554 g_object_notify (G_OBJECT (list_item), property_name: "selected");
555}
556
557void
558gtk_list_item_widget_default_update (GtkListItemWidget *self,
559 GtkListItem *list_item,
560 guint position,
561 gpointer item,
562 gboolean selected)
563{
564 /* Track notify manually instead of freeze/thaw_notify for performance reasons. */
565 gboolean notify_item = FALSE, notify_position = FALSE, notify_selected = FALSE;
566 GtkListItemWidgetPrivate *priv = gtk_list_item_widget_get_instance_private (self);
567
568 /* FIXME: It's kinda evil to notify external objects from here... */
569
570 if (g_set_object (&priv->item, item))
571 notify_item = TRUE;
572
573 if (priv->position != position)
574 {
575 priv->position = position;
576 notify_position = TRUE;
577 }
578
579 if (priv->selected != selected)
580 {
581 priv->selected = selected;
582 notify_selected = TRUE;
583 }
584
585 if (list_item)
586 gtk_list_item_do_notify (list_item, notify_item, notify_position, notify_selected);
587}
588
589void
590gtk_list_item_widget_set_factory (GtkListItemWidget *self,
591 GtkListItemFactory *factory)
592{
593 GtkListItemWidgetPrivate *priv = gtk_list_item_widget_get_instance_private (self);
594
595 if (priv->factory == factory)
596 return;
597
598 if (priv->factory)
599 {
600 if (priv->list_item)
601 gtk_list_item_factory_teardown (self: factory, widget: self);
602 g_clear_object (&priv->factory);
603 }
604
605 if (factory)
606 {
607 priv->factory = g_object_ref (factory);
608
609 if (gtk_widget_get_root (GTK_WIDGET (self)))
610 gtk_list_item_factory_setup (self: factory, widget: self);
611 }
612
613 g_object_notify_by_pspec (G_OBJECT (self), pspec: properties[PROP_FACTORY]);
614}
615
616void
617gtk_list_item_widget_set_single_click_activate (GtkListItemWidget *self,
618 gboolean single_click_activate)
619{
620 GtkListItemWidgetPrivate *priv = gtk_list_item_widget_get_instance_private (self);
621
622 if (priv->single_click_activate == single_click_activate)
623 return;
624
625 priv->single_click_activate = single_click_activate;
626
627 g_object_notify_by_pspec (G_OBJECT (self), pspec: properties[PROP_SINGLE_CLICK_ACTIVATE]);
628}
629
630void
631gtk_list_item_widget_set_activatable (GtkListItemWidget *self,
632 gboolean activatable)
633{
634 if (activatable)
635 gtk_widget_add_css_class (GTK_WIDGET (self), css_class: "activatable");
636 else
637 gtk_widget_remove_css_class (GTK_WIDGET (self), css_class: "activatable");
638}
639
640void
641gtk_list_item_widget_add_child (GtkListItemWidget *self,
642 GtkWidget *child)
643{
644 gtk_widget_set_parent (widget: child, GTK_WIDGET (self));
645}
646
647void
648gtk_list_item_widget_reorder_child (GtkListItemWidget *self,
649 GtkWidget *child,
650 guint position)
651{
652 GtkWidget *widget = GTK_WIDGET (self);
653 GtkWidget *sibling = NULL;
654
655 if (position > 0)
656 {
657 GtkWidget *c;
658 guint i;
659
660 for (c = gtk_widget_get_first_child (widget), i = 0;
661 c;
662 c = gtk_widget_get_next_sibling (widget: c), i++)
663 {
664 if (i + 1 == position)
665 {
666 sibling = c;
667 break;
668 }
669 }
670 }
671
672 if (child != sibling)
673 gtk_widget_insert_after (widget: child, parent: widget, previous_sibling: sibling);
674}
675
676void
677gtk_list_item_widget_remove_child (GtkListItemWidget *self,
678 GtkWidget *child)
679{
680 gtk_widget_unparent (widget: child);
681}
682
683GtkListItem *
684gtk_list_item_widget_get_list_item (GtkListItemWidget *self)
685{
686 GtkListItemWidgetPrivate *priv = gtk_list_item_widget_get_instance_private (self);
687
688 return priv->list_item;
689}
690
691guint
692gtk_list_item_widget_get_position (GtkListItemWidget *self)
693{
694 GtkListItemWidgetPrivate *priv = gtk_list_item_widget_get_instance_private (self);
695
696 return priv->position;
697}
698
699gpointer
700gtk_list_item_widget_get_item (GtkListItemWidget *self)
701{
702 GtkListItemWidgetPrivate *priv = gtk_list_item_widget_get_instance_private (self);
703
704 return priv->item;
705}
706
707gboolean
708gtk_list_item_widget_get_selected (GtkListItemWidget *self)
709{
710 GtkListItemWidgetPrivate *priv = gtk_list_item_widget_get_instance_private (self);
711
712 return priv->selected;
713}
714
715

source code of gtk/gtk/gtklistitemwidget.c