1/*
2 * Copyright (c) 2008-2009 Christian Hammond
3 * Copyright (c) 2008-2009 David Trowbridge
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included
13 * in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 * THE SOFTWARE.
22 */
23
24#include "config.h"
25#include <glib/gi18n-lib.h>
26
27#include "prop-list.h"
28
29#include "prop-editor.h"
30
31#include "gtkcelllayout.h"
32#include "gtktreeview.h"
33#include "gtktreeselection.h"
34#include "gtkpopover.h"
35#include "gtksearchentry.h"
36#include "gtklabel.h"
37#include "gtkmain.h"
38#include "gtkstack.h"
39#include "gtkeventcontrollerkey.h"
40#include "gtklayoutmanager.h"
41#include "gtklistbox.h"
42#include "gtksizegroup.h"
43#include "gtkroot.h"
44#include "gtkgestureclick.h"
45#include "prop-holder.h"
46#include "window.h"
47
48enum
49{
50 PROP_0,
51 PROP_SEARCH_ENTRY
52};
53
54struct _GtkInspectorPropListPrivate
55{
56 GObject *object;
57 gulong notify_handler_id;
58 GtkWidget *search_entry;
59 GtkWidget *search_stack;
60 GtkWidget *list;
61 GtkStringFilter *filter;
62 GtkColumnViewColumn *name;
63 GtkColumnViewColumn *type;
64 GtkColumnViewColumn *origin;
65};
66
67G_DEFINE_TYPE_WITH_PRIVATE (GtkInspectorPropList, gtk_inspector_prop_list, GTK_TYPE_BOX)
68
69static void
70search_close_clicked (GtkWidget *button,
71 GtkInspectorPropList *pl)
72{
73 gtk_editable_set_text (GTK_EDITABLE (pl->priv->search_entry), text: "");
74 gtk_stack_set_visible_child_name (GTK_STACK (pl->priv->search_stack), name: "title");
75}
76
77static void
78show_search_entry (GtkInspectorPropList *pl)
79{
80 gtk_stack_set_visible_child (GTK_STACK (pl->priv->search_stack),
81 child: pl->priv->search_entry);
82}
83
84static char *
85holder_prop (gpointer item)
86{
87 GParamSpec *prop = prop_holder_get_pspec (holder: PROP_HOLDER (ptr: item));
88
89 return g_strdup (str: prop->name);
90}
91
92static char *
93holder_type (gpointer item)
94{
95 GParamSpec *prop = prop_holder_get_pspec (holder: PROP_HOLDER (ptr: item));
96
97 return g_strdup (str: g_type_name (type: prop->value_type));
98}
99
100static char *
101holder_origin (gpointer item)
102{
103 GParamSpec *prop = prop_holder_get_pspec (holder: PROP_HOLDER (ptr: item));
104
105 return g_strdup (str: g_type_name (type: prop->owner_type));
106}
107
108static void
109gtk_inspector_prop_list_init (GtkInspectorPropList *pl)
110{
111 GtkSorter *sorter;
112
113 pl->priv = gtk_inspector_prop_list_get_instance_private (self: pl);
114 gtk_widget_init_template (GTK_WIDGET (pl));
115 pl->priv->filter = gtk_string_filter_new (NULL);
116 gtk_string_filter_set_match_mode (self: pl->priv->filter, mode: GTK_STRING_FILTER_MATCH_MODE_SUBSTRING);
117
118 sorter = GTK_SORTER (ptr: gtk_string_sorter_new (expression: gtk_cclosure_expression_new (G_TYPE_STRING, NULL,
119 n_params: 0, NULL,
120 callback_func: (GCallback)holder_prop,
121 NULL, NULL)));
122
123 gtk_string_filter_set_expression (self: pl->priv->filter,
124 expression: gtk_string_sorter_get_expression (self: GTK_STRING_SORTER (ptr: sorter)));
125
126 gtk_column_view_column_set_sorter (self: pl->priv->name, sorter);
127 g_object_unref (object: sorter);
128
129 sorter = GTK_SORTER (ptr: gtk_string_sorter_new (expression: gtk_cclosure_expression_new (G_TYPE_STRING, NULL,
130 n_params: 0, NULL,
131 callback_func: (GCallback)holder_type,
132 NULL, NULL)));
133
134 gtk_column_view_column_set_sorter (self: pl->priv->type, sorter);
135 g_object_unref (object: sorter);
136
137 sorter = GTK_SORTER (ptr: gtk_string_sorter_new (expression: gtk_cclosure_expression_new (G_TYPE_STRING, NULL,
138 n_params: 0, NULL,
139 callback_func: (GCallback)holder_origin,
140 NULL, NULL)));
141
142 gtk_column_view_column_set_sorter (self: pl->priv->origin, sorter);
143 g_object_unref (object: sorter);
144}
145
146static void
147get_property (GObject *object,
148 guint param_id,
149 GValue *value,
150 GParamSpec *pspec)
151{
152 GtkInspectorPropList *pl = GTK_INSPECTOR_PROP_LIST (object);
153
154 switch (param_id)
155 {
156 case PROP_SEARCH_ENTRY:
157 g_value_take_object (value, v_object: pl->priv->search_entry);
158 break;
159
160 default:
161 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
162 break;
163 }
164}
165
166static void
167set_property (GObject *object,
168 guint param_id,
169 const GValue *value,
170 GParamSpec *pspec)
171{
172 GtkInspectorPropList *pl = GTK_INSPECTOR_PROP_LIST (object);
173
174 switch (param_id)
175 {
176 case PROP_SEARCH_ENTRY:
177 pl->priv->search_entry = g_value_get_object (value);
178 break;
179
180 default:
181 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
182 break;
183 }
184}
185
186static void
187show_object (GtkInspectorPropEditor *editor,
188 GObject *object,
189 const char *name,
190 const char *tab,
191 GtkInspectorPropList *pl)
192{
193 GtkInspectorWindow *iw;
194
195 iw = GTK_INSPECTOR_WINDOW (gtk_widget_get_ancestor (GTK_WIDGET (pl), GTK_TYPE_INSPECTOR_WINDOW));
196 gtk_inspector_window_push_object (iw, object, kind: CHILD_KIND_PROPERTY, position: 0);
197}
198
199
200static void cleanup_object (GtkInspectorPropList *pl);
201
202static void
203finalize (GObject *object)
204{
205 GtkInspectorPropList *pl = GTK_INSPECTOR_PROP_LIST (object);
206
207 cleanup_object (pl);
208
209 G_OBJECT_CLASS (gtk_inspector_prop_list_parent_class)->finalize (object);
210}
211
212static void
213update_filter (GtkInspectorPropList *pl,
214 GtkSearchEntry *entry)
215{
216 const char *text;
217
218 text = gtk_editable_get_text (GTK_EDITABLE (entry));
219 gtk_string_filter_set_search (self: pl->priv->filter, search: text);
220}
221
222static void
223constructed (GObject *object)
224{
225 GtkInspectorPropList *pl = GTK_INSPECTOR_PROP_LIST (object);
226
227 pl->priv->search_stack = gtk_widget_get_parent (widget: pl->priv->search_entry);
228
229 g_signal_connect (pl->priv->search_entry, "stop-search",
230 G_CALLBACK (search_close_clicked), pl);
231
232 g_signal_connect_swapped (pl->priv->search_entry, "search-started",
233 G_CALLBACK (show_search_entry), pl);
234 g_signal_connect_swapped (pl->priv->search_entry, "search-changed",
235 G_CALLBACK (update_filter), pl);
236}
237
238static void
239update_key_capture (GtkInspectorPropList *pl)
240{
241 GtkWidget *capture_widget;
242
243 if (gtk_widget_get_mapped (GTK_WIDGET (pl)))
244 {
245 GtkWidget *toplevel;
246 GtkWidget *focus;
247
248 toplevel = GTK_WIDGET (gtk_widget_get_root (GTK_WIDGET (pl)));
249 focus = gtk_root_get_focus (self: GTK_ROOT (ptr: toplevel));
250
251 if (GTK_IS_EDITABLE (focus) &&
252 gtk_widget_is_ancestor (widget: focus, ancestor: pl->priv->list))
253 capture_widget = NULL;
254 else
255 capture_widget = toplevel;
256 }
257 else
258 capture_widget = NULL;
259
260 gtk_search_entry_set_key_capture_widget (GTK_SEARCH_ENTRY (pl->priv->search_entry),
261 widget: capture_widget);
262}
263
264static void
265map (GtkWidget *widget)
266{
267 GTK_WIDGET_CLASS (gtk_inspector_prop_list_parent_class)->map (widget);
268
269 update_key_capture (GTK_INSPECTOR_PROP_LIST (widget));
270}
271
272static void
273unmap (GtkWidget *widget)
274{
275 GTK_WIDGET_CLASS (gtk_inspector_prop_list_parent_class)->unmap (widget);
276
277 update_key_capture (GTK_INSPECTOR_PROP_LIST (widget));
278}
279
280static void
281root (GtkWidget *widget)
282{
283 GTK_WIDGET_CLASS (gtk_inspector_prop_list_parent_class)->root (widget);
284
285 g_signal_connect_swapped (gtk_widget_get_root (widget), "notify::focus-widget",
286 G_CALLBACK (update_key_capture), widget);
287}
288
289static void
290unroot (GtkWidget *widget)
291{
292 g_signal_handlers_disconnect_by_func (gtk_widget_get_root (widget),
293 update_key_capture, widget);
294
295 GTK_WIDGET_CLASS (gtk_inspector_prop_list_parent_class)->unroot (widget);
296}
297
298static void
299setup_name_cb (GtkSignalListItemFactory *factory,
300 GtkListItem *list_item)
301{
302 GtkWidget *label;
303
304 label = gtk_label_new (NULL);
305 gtk_label_set_xalign (GTK_LABEL (label), xalign: 0.0);
306 gtk_list_item_set_child (self: list_item, child: label);
307 gtk_widget_add_css_class (widget: label, css_class: "cell");
308}
309
310static void
311bind_name_cb (GtkSignalListItemFactory *factory,
312 GtkListItem *list_item)
313{
314 GObject *item;
315 GtkWidget *label;
316
317 item = gtk_list_item_get_item (self: list_item);
318 label = gtk_list_item_get_child (self: list_item);
319
320 gtk_label_set_label (GTK_LABEL (label), str: prop_holder_get_name (holder: PROP_HOLDER (ptr: item)));
321}
322
323static void
324setup_type_cb (GtkSignalListItemFactory *factory,
325 GtkListItem *list_item)
326{
327 GtkWidget *label;
328
329 label = gtk_label_new (NULL);
330 gtk_label_set_xalign (GTK_LABEL (label), xalign: 0.0);
331 gtk_list_item_set_child (self: list_item, child: label);
332 gtk_widget_add_css_class (widget: label, css_class: "cell");
333}
334
335static void
336bind_type_cb (GtkSignalListItemFactory *factory,
337 GtkListItem *list_item)
338{
339 GObject *item;
340 GtkWidget *label;
341 GParamSpec *prop;
342 const char *type;
343
344 item = gtk_list_item_get_item (self: list_item);
345 label = gtk_list_item_get_child (self: list_item);
346
347 prop = prop_holder_get_pspec (holder: PROP_HOLDER (ptr: item));
348 type = g_type_name (G_PARAM_SPEC_VALUE_TYPE (prop));
349
350 gtk_label_set_label (GTK_LABEL (label), str: type);
351}
352
353static void
354setup_origin_cb (GtkSignalListItemFactory *factory,
355 GtkListItem *list_item)
356{
357 GtkWidget *label;
358
359 label = gtk_label_new (NULL);
360 gtk_label_set_xalign (GTK_LABEL (label), xalign: 0.0);
361 gtk_list_item_set_child (self: list_item, child: label);
362 gtk_widget_add_css_class (widget: label, css_class: "cell");
363}
364
365static void
366bind_origin_cb (GtkSignalListItemFactory *factory,
367 GtkListItem *list_item)
368{
369 GObject *item;
370 GtkWidget *label;
371 GParamSpec *prop;
372 const char *origin;
373
374 item = gtk_list_item_get_item (self: list_item);
375 label = gtk_list_item_get_child (self: list_item);
376
377 prop = prop_holder_get_pspec (holder: PROP_HOLDER (ptr: item));
378 origin = g_type_name (type: prop->owner_type);
379
380 gtk_label_set_label (GTK_LABEL (label), str: origin);
381}
382
383static void
384setup_value_cb (GtkSignalListItemFactory *factory,
385 GtkListItem *list_item,
386 gpointer data)
387{
388 GtkWidget *widget;
389
390 widget = gtk_box_new (orientation: GTK_ORIENTATION_HORIZONTAL, spacing: 0);
391 gtk_widget_add_css_class (widget, css_class: "cell");
392 gtk_list_item_set_child (self: list_item, child: widget);
393}
394
395static void
396bind_value_cb (GtkSignalListItemFactory *factory,
397 GtkListItem *list_item,
398 gpointer data)
399{
400 GObject *item;
401 GtkWidget *editor;
402 GtkWidget *widget;
403 GObject *object;
404 const char *name;
405
406 item = gtk_list_item_get_item (self: list_item);
407
408 object = prop_holder_get_object (holder: PROP_HOLDER (ptr: item));
409 name = prop_holder_get_name (holder: PROP_HOLDER (ptr: item));
410
411 editor = gtk_inspector_prop_editor_new (object, name, NULL);
412 g_signal_connect (editor, "show-object", G_CALLBACK (show_object), data);
413 widget = gtk_list_item_get_child (self: list_item);
414 gtk_box_append (GTK_BOX (widget), child: editor);
415}
416
417static void
418unbind_value_cb (GtkSignalListItemFactory *factory,
419 GtkListItem *list_item,
420 gpointer data)
421{
422 GtkWidget *widget;
423
424 widget = gtk_list_item_get_child (self: list_item);
425 gtk_box_remove (GTK_BOX (widget), child: gtk_widget_get_first_child (widget));
426}
427
428static void
429gtk_inspector_prop_list_class_init (GtkInspectorPropListClass *klass)
430{
431 GObjectClass *object_class = G_OBJECT_CLASS (klass);
432 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
433
434 object_class->finalize = finalize;
435 object_class->get_property = get_property;
436 object_class->set_property = set_property;
437 object_class->constructed = constructed;
438
439 widget_class->map = map;
440 widget_class->unmap = unmap;
441 widget_class->root = root;
442 widget_class->unroot = unroot;
443
444 g_object_class_install_property (oclass: object_class, property_id: PROP_SEARCH_ENTRY,
445 pspec: g_param_spec_object (name: "search-entry", nick: "Search Entry", blurb: "Search Entry",
446 GTK_TYPE_WIDGET, flags: G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
447
448 gtk_widget_class_set_template_from_resource (widget_class, resource_name: "/org/gtk/libgtk/inspector/prop-list.ui");
449 gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorPropList, list);
450 gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorPropList, name);
451 gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorPropList, type);
452 gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorPropList, origin);
453 gtk_widget_class_bind_template_callback (widget_class, setup_name_cb);
454 gtk_widget_class_bind_template_callback (widget_class, bind_name_cb);
455 gtk_widget_class_bind_template_callback (widget_class, setup_type_cb);
456 gtk_widget_class_bind_template_callback (widget_class, bind_type_cb);
457 gtk_widget_class_bind_template_callback (widget_class, setup_origin_cb);
458 gtk_widget_class_bind_template_callback (widget_class, bind_origin_cb);
459 gtk_widget_class_bind_template_callback (widget_class, setup_value_cb);
460 gtk_widget_class_bind_template_callback (widget_class, bind_value_cb);
461 gtk_widget_class_bind_template_callback (widget_class, unbind_value_cb);
462}
463
464/* Like g_strdup_value_contents, but keeps the type name separate */
465void
466strdup_value_contents (const GValue *value,
467 char **contents,
468 char **type)
469{
470 const char *src;
471
472 if (G_VALUE_HOLDS_STRING (value))
473 {
474 src = g_value_get_string (value);
475
476 *type = g_strdup (str: "char*");
477
478 if (!src)
479 {
480 *contents = g_strdup (str: "NULL");
481 }
482 else
483 {
484 char *s = g_strescape (source: src, NULL);
485 *contents = g_strdup_printf (format: "\"%s\"", s);
486 g_free (mem: s);
487 }
488 }
489 else if (g_value_type_transformable (G_VALUE_TYPE (value), G_TYPE_STRING))
490 {
491 GValue tmp_value = G_VALUE_INIT;
492
493 *type = g_strdup (str: g_type_name (G_VALUE_TYPE (value)));
494
495 g_value_init (value: &tmp_value, G_TYPE_STRING);
496 g_value_transform (src_value: value, dest_value: &tmp_value);
497 src = g_value_get_string (value: &tmp_value);
498 if (!src)
499 *contents = g_strdup (str: "NULL");
500 else
501 *contents = g_strescape (source: src, NULL);
502 g_value_unset (value: &tmp_value);
503 }
504 else if (g_value_fits_pointer (value))
505 {
506 gpointer p = g_value_peek_pointer (value);
507
508 if (!p)
509 {
510 *type = g_strdup (str: g_type_name (G_VALUE_TYPE (value)));
511 *contents = g_strdup (str: "NULL");
512 }
513 else if (G_VALUE_HOLDS_OBJECT (value))
514 {
515 *type = g_strdup (G_OBJECT_TYPE_NAME (p));
516 *contents = g_strdup_printf (format: "%p", p);
517 }
518 else if (G_VALUE_HOLDS_PARAM (value))
519 {
520 *type = g_strdup (G_PARAM_SPEC_TYPE_NAME (p));
521 *contents = g_strdup_printf (format: "%p", p);
522 }
523 else if (G_VALUE_HOLDS (value, G_TYPE_STRV))
524 {
525 GStrv strv = g_value_get_boxed (value);
526 GString *tmp = g_string_new (init: "[");
527
528 while (*strv != NULL)
529 {
530 char *escaped = g_strescape (source: *strv, NULL);
531
532 g_string_append_printf (string: tmp, format: "\"%s\"", escaped);
533 g_free (mem: escaped);
534
535 if (*++strv != NULL)
536 g_string_append (string: tmp, val: ", ");
537 }
538
539 g_string_append (string: tmp, val: "]");
540 *type = g_strdup (str: "char**");
541 *contents = g_string_free (string: tmp, FALSE);
542 }
543 else if (G_VALUE_HOLDS_BOXED (value))
544 {
545 *type = g_strdup (str: g_type_name (G_VALUE_TYPE (value)));
546 *contents = g_strdup_printf (format: "%p", p);
547 }
548 else if (G_VALUE_HOLDS_POINTER (value))
549 {
550 *type = g_strdup (str: "gpointer");
551 *contents = g_strdup_printf (format: "%p", p);
552 }
553 else
554 {
555 *type = g_strdup (str: "???");
556 *contents = g_strdup (str: "???");
557 }
558 }
559 else
560 {
561 *type = g_strdup (str: "???");
562 *contents = g_strdup (str: "???");
563 }
564}
565
566static void
567cleanup_object (GtkInspectorPropList *pl)
568{
569 if (pl->priv->object &&
570 g_signal_handler_is_connected (instance: pl->priv->object, handler_id: pl->priv->notify_handler_id))
571 g_signal_handler_disconnect (instance: pl->priv->object, handler_id: pl->priv->notify_handler_id);
572
573 pl->priv->object = NULL;
574 pl->priv->notify_handler_id = 0;
575}
576
577gboolean
578gtk_inspector_prop_list_set_object (GtkInspectorPropList *pl,
579 GObject *object)
580{
581 GParamSpec **props;
582 guint num_properties;
583 guint i;
584 GListStore *store;
585 GListModel *list;
586 GListModel *filtered;
587 GtkSortListModel *sorted;
588
589 if (!object)
590 return FALSE;
591
592 if (pl->priv->object == object)
593 return TRUE;
594
595 cleanup_object (pl);
596
597 gtk_editable_set_text (GTK_EDITABLE (pl->priv->search_entry), text: "");
598 gtk_stack_set_visible_child_name (GTK_STACK (pl->priv->search_stack), name: "title");
599
600 props = g_object_class_list_properties (G_OBJECT_GET_CLASS (object), n_properties: &num_properties);
601
602 pl->priv->object = object;
603
604 store = g_list_store_new (PROP_TYPE_HOLDER);
605
606 for (i = 0; i < num_properties; i++)
607 {
608 GParamSpec *prop = props[i];
609 PropHolder *holder;
610
611 if (! (prop->flags & G_PARAM_READABLE))
612 continue;
613
614 holder = prop_holder_new (object, pspeC: prop);
615 g_list_store_append (store, item: holder);
616 g_object_unref (object: holder);
617 }
618
619 g_free (mem: props);
620
621 if (GTK_IS_WIDGET (object))
622 g_signal_connect_object (instance: object, detailed_signal: "destroy", G_CALLBACK (cleanup_object), gobject: pl, connect_flags: G_CONNECT_SWAPPED);
623
624 filtered = G_LIST_MODEL (ptr: gtk_filter_list_model_new (model: G_LIST_MODEL (ptr: store), g_object_ref (GTK_FILTER (pl->priv->filter))));
625 sorted = gtk_sort_list_model_new (model: filtered, NULL);
626 list = G_LIST_MODEL (ptr: gtk_no_selection_new (model: G_LIST_MODEL (ptr: sorted)));
627
628 gtk_column_view_set_model (GTK_COLUMN_VIEW (pl->priv->list), model: GTK_SELECTION_MODEL (ptr: list));
629 gtk_sort_list_model_set_sorter (self: sorted, sorter: gtk_column_view_get_sorter (GTK_COLUMN_VIEW (pl->priv->list)));
630 gtk_column_view_sort_by_column (GTK_COLUMN_VIEW (pl->priv->list), column: pl->priv->name, direction: GTK_SORT_ASCENDING);
631
632 gtk_widget_show (GTK_WIDGET (pl));
633
634 g_object_unref (object: list);
635
636 return TRUE;
637}
638
639void
640gtk_inspector_prop_list_set_layout_child (GtkInspectorPropList *pl,
641 GObject *object)
642{
643 GtkWidget *stack;
644 GtkStackPage *page;
645 GtkWidget *parent;
646 GtkLayoutManager *layout_manager;
647 GtkLayoutChild *layout_child;
648
649 stack = gtk_widget_get_parent (GTK_WIDGET (pl));
650 page = gtk_stack_get_page (GTK_STACK (stack), GTK_WIDGET (pl));
651 g_object_set (object: page, first_property_name: "visible", FALSE, NULL);
652
653 if (!GTK_IS_WIDGET (object))
654 return;
655
656 parent = gtk_widget_get_parent (GTK_WIDGET (object));
657 if (!parent)
658 return;
659
660 layout_manager = gtk_widget_get_layout_manager (widget: parent);
661 if (!layout_manager)
662 return;
663
664 if (GTK_LAYOUT_MANAGER_GET_CLASS (ptr: layout_manager)->layout_child_type == G_TYPE_INVALID)
665 return;
666
667 layout_child = gtk_layout_manager_get_layout_child (manager: layout_manager, GTK_WIDGET (object));
668 if (!layout_child)
669 return;
670
671 if (!gtk_inspector_prop_list_set_object (pl, G_OBJECT (layout_child)))
672 return;
673
674 g_object_set (object: page, first_property_name: "visible", TRUE, NULL);
675}
676
677// vim: set et sw=2 ts=2:
678

source code of gtk/gtk/inspector/prop-list.c