1 /*
2 * Copyright (c) 2014 Red Hat, Inc.
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 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
18 #include "config.h"
19 #include <glib/gi18n-lib.h>
20
21 #include "resource-list.h"
22
23 #include "gtklabel.h"
24 #include "gtkstack.h"
25 #include "gtktextbuffer.h"
26 #include "gtktreestore.h"
27 #include "gtktreeselection.h"
28 #include "gtksearchbar.h"
29 #include "gtksearchentry.h"
30 #include "treewalk.h"
31
32 enum
33 {
34 PROP_0,
35 PROP_BUTTONS
36 };
37
38 enum
39 {
40 COLUMN_NAME,
41 COLUMN_PATH,
42 COLUMN_COUNT,
43 COLUMN_SIZE
44 };
45
46 struct _GtkInspectorResourceListPrivate
47 {
48 GtkTreeStore *model;
49 GtkTextBuffer *buffer;
50 GtkWidget *image;
51 GtkWidget *content;
52 GtkWidget *name_label;
53 GtkWidget *type;
54 GtkWidget *type_label;
55 GtkWidget *size_label;
56 GtkWidget *info_grid;
57 GtkWidget *stack;
58 GtkWidget *tree;
59 GtkWidget *buttons;
60 GtkWidget *open_details_button;
61 GtkWidget *close_details_button;
62 GtkTreeViewColumn *path_column;
63 GtkTreeViewColumn *count_column;
64 GtkCellRenderer *count_renderer;
65 GtkTreeViewColumn *size_column;
66 GtkCellRenderer *size_renderer;
67 GtkWidget *search_bar;
68 GtkWidget *search_entry;
69 GtkTreeWalk *walk;
70 gint search_length;
71 };
72
73
G_DEFINE_TYPE_WITH_PRIVATE(GtkInspectorResourceList,gtk_inspector_resource_list,GTK_TYPE_BOX)74 G_DEFINE_TYPE_WITH_PRIVATE (GtkInspectorResourceList, gtk_inspector_resource_list, GTK_TYPE_BOX)
75
76 static void
77 load_resources_recurse (GtkInspectorResourceList *sl,
78 GtkTreeIter *parent,
79 const gchar *path,
80 gint *count_out,
81 gsize *size_out)
82 {
83 gchar **names;
84 gint i;
85 GtkTreeIter iter;
86 guint64 stored_size;
87
88 names = g_resources_enumerate_children (path, 0, NULL);
89 for (i = 0; names[i]; i++)
90 {
91 gint len;
92 gchar *p;
93 gboolean has_slash;
94 gint count;
95 gsize size;
96
97 p = g_strconcat (path, names[i], NULL);
98
99 len = strlen (names[i]);
100 has_slash = names[i][len - 1] == '/';
101
102 if (has_slash)
103 names[i][len - 1] = '\0';
104
105 gtk_tree_store_append (sl->priv->model, &iter, parent);
106 gtk_tree_store_set (sl->priv->model, &iter,
107 COLUMN_NAME, names[i],
108 COLUMN_PATH, p,
109 -1);
110
111 count = 0;
112 size = 0;
113
114 if (has_slash)
115 {
116 load_resources_recurse (sl, &iter, p, &count, &size);
117 *count_out += count;
118 *size_out += size;
119 }
120 else
121 {
122 count = 0;
123 if (g_resources_get_info (p, 0, &size, NULL, NULL))
124 {
125 *count_out += 1;
126 *size_out += size;
127 }
128 }
129
130 stored_size = size;
131 gtk_tree_store_set (sl->priv->model, &iter,
132 COLUMN_COUNT, count,
133 COLUMN_SIZE, stored_size,
134 -1);
135
136 g_free (p);
137 }
138 g_strfreev (names);
139
140 }
141
142 static gboolean
populate_details(GtkInspectorResourceList * rl,GtkTreePath * tree_path)143 populate_details (GtkInspectorResourceList *rl,
144 GtkTreePath *tree_path)
145 {
146 GtkTreeIter iter;
147 gchar *path;
148 gchar *name;
149 GBytes *bytes;
150 gchar *type;
151 gconstpointer data;
152 gint count;
153 gsize size;
154 guint64 stored_size;
155 GError *error = NULL;
156 gchar *markup;
157
158
159 gtk_tree_model_get_iter (GTK_TREE_MODEL (rl->priv->model), &iter, tree_path);
160
161 gtk_tree_model_get (GTK_TREE_MODEL (rl->priv->model), &iter,
162 COLUMN_PATH, &path,
163 COLUMN_NAME, &name,
164 COLUMN_COUNT, &count,
165 COLUMN_SIZE, &stored_size,
166 -1);
167 size = stored_size;
168
169 if (g_str_has_suffix (path, "/"))
170 {
171 g_free (path);
172 g_free (name);
173 return FALSE;
174 }
175
176 markup = g_strconcat ("<span face='Monospace' size='small'>", path, "</span>", NULL);
177 gtk_label_set_markup (GTK_LABEL (rl->priv->name_label), markup);
178 g_free (markup);
179
180 bytes = g_resources_lookup_data (path, 0, &error);
181 if (bytes == NULL)
182 {
183 gtk_text_buffer_set_text (rl->priv->buffer, error->message, -1);
184 g_error_free (error);
185 gtk_stack_set_visible_child_name (GTK_STACK (rl->priv->content), "text");
186 }
187 else
188 {
189 gchar *text;
190 gchar *content_image;
191 gchar *content_text;
192
193 content_image = g_content_type_from_mime_type ("image/*");
194 content_text = g_content_type_from_mime_type ("text/*");
195
196 data = g_bytes_get_data (bytes, &size);
197 type = g_content_type_guess (name, data, size, NULL);
198
199 text = g_content_type_get_description (type);
200 gtk_label_set_text (GTK_LABEL (rl->priv->type_label), text);
201 g_free (text);
202
203 text = g_format_size (size);
204 gtk_label_set_text (GTK_LABEL (rl->priv->size_label), text);
205 g_free (text);
206
207 if (g_content_type_is_a (type, content_text))
208 {
209 gtk_text_buffer_set_text (rl->priv->buffer, data, -1);
210 gtk_stack_set_visible_child_name (GTK_STACK (rl->priv->content), "text");
211 }
212 else if (g_content_type_is_a (type, content_image))
213 {
214 gtk_image_set_from_resource (GTK_IMAGE (rl->priv->image), path);
215 gtk_stack_set_visible_child_name (GTK_STACK (rl->priv->content), "image");
216 }
217 else
218 {
219 gtk_text_buffer_set_text (rl->priv->buffer, "", 0);
220 gtk_stack_set_visible_child_name (GTK_STACK (rl->priv->content), "text");
221 }
222
223 g_free (type);
224 g_bytes_unref (bytes);
225
226 g_free (content_image);
227 g_free (content_text);
228 }
229
230 g_free (path);
231 g_free (name);
232
233 return TRUE;
234 }
235
236 static void
row_activated(GtkTreeView * treeview,GtkTreePath * path,GtkTreeViewColumn * column,GtkInspectorResourceList * sl)237 row_activated (GtkTreeView *treeview,
238 GtkTreePath *path,
239 GtkTreeViewColumn *column,
240 GtkInspectorResourceList *sl)
241 {
242 if (!populate_details (sl, path))
243 return;
244
245 gtk_stack_set_visible_child_name (GTK_STACK (sl->priv->stack), "details");
246 gtk_stack_set_visible_child_name (GTK_STACK (sl->priv->buttons), "details");
247 }
248
249 static gboolean
can_show_details(GtkInspectorResourceList * rl)250 can_show_details (GtkInspectorResourceList *rl)
251 {
252 GtkTreeSelection *selection;
253 GtkTreeModel *model;
254 GtkTreeIter iter;
255 gchar *path;
256
257 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (rl->priv->tree));
258 if (!gtk_tree_selection_get_selected (selection, &model, &iter))
259 return FALSE;
260
261 gtk_tree_model_get (GTK_TREE_MODEL (rl->priv->model), &iter,
262 COLUMN_PATH, &path,
263 -1);
264
265 if (g_str_has_suffix (path, "/"))
266 {
267 g_free (path);
268 return FALSE;
269 }
270
271 g_free (path);
272 return TRUE;
273 }
274
275 static void
on_selection_changed(GtkTreeSelection * selection,GtkInspectorResourceList * rl)276 on_selection_changed (GtkTreeSelection *selection,
277 GtkInspectorResourceList *rl)
278 {
279 GtkTreeIter iter;
280
281 if (gtk_tree_selection_get_selected (selection, NULL, &iter))
282 gtk_tree_walk_reset (rl->priv->walk, &iter);
283 else
284 gtk_tree_walk_reset (rl->priv->walk, NULL);
285
286 gtk_widget_set_sensitive (rl->priv->open_details_button, can_show_details (rl));
287 }
288
289 static void
open_details(GtkWidget * button,GtkInspectorResourceList * sl)290 open_details (GtkWidget *button,
291 GtkInspectorResourceList *sl)
292 {
293 GtkTreeSelection *selection;
294 GtkTreeModel *model;
295 GtkTreeIter iter;
296 GtkTreePath *path;
297
298 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (sl->priv->tree));
299 if (!gtk_tree_selection_get_selected (selection, &model, &iter))
300 return;
301
302 path = gtk_tree_model_get_path (model, &iter);
303 if (populate_details (sl, path))
304 {
305 gtk_stack_set_visible_child_name (GTK_STACK (sl->priv->stack), "details");
306 gtk_stack_set_visible_child_name (GTK_STACK (sl->priv->buttons), "details");
307 }
308
309 gtk_tree_path_free (path);
310 }
311
312 static void
close_details(GtkWidget * button,GtkInspectorResourceList * sl)313 close_details (GtkWidget *button,
314 GtkInspectorResourceList *sl)
315 {
316 gtk_stack_set_visible_child_name (GTK_STACK (sl->priv->stack), "list");
317 gtk_stack_set_visible_child_name (GTK_STACK (sl->priv->buttons), "list");
318 }
319
320 static void
load_resources(GtkInspectorResourceList * sl)321 load_resources (GtkInspectorResourceList *sl)
322 {
323 gint count = 0;
324 gsize size = 0;
325
326 load_resources_recurse (sl, NULL, "/", &count, &size);
327 }
328
329 static void
count_data_func(GtkTreeViewColumn * col,GtkCellRenderer * cell,GtkTreeModel * model,GtkTreeIter * iter,gpointer data)330 count_data_func (GtkTreeViewColumn *col,
331 GtkCellRenderer *cell,
332 GtkTreeModel *model,
333 GtkTreeIter *iter,
334 gpointer data)
335 {
336 gint count;
337 gchar *text;
338
339 gtk_tree_model_get (model, iter, COLUMN_COUNT, &count, -1);
340 if (count > 0)
341 {
342 text = g_strdup_printf ("%d", count);
343 g_object_set (cell, "text", text, NULL);
344 g_free (text);
345 }
346 else
347 g_object_set (cell, "text", "", NULL);
348 }
349
350 static void
size_data_func(GtkTreeViewColumn * col,GtkCellRenderer * cell,GtkTreeModel * model,GtkTreeIter * iter,gpointer data)351 size_data_func (GtkTreeViewColumn *col,
352 GtkCellRenderer *cell,
353 GtkTreeModel *model,
354 GtkTreeIter *iter,
355 gpointer data)
356 {
357 gsize size;
358 guint64 stored_size;
359 gchar *text;
360
361 gtk_tree_model_get (model, iter, COLUMN_SIZE, &stored_size, -1);
362 size = stored_size;
363 text = g_format_size (size);
364 g_object_set (cell, "text", text, NULL);
365 g_free (text);
366 }
367
368 static void
on_map(GtkWidget * widget)369 on_map (GtkWidget *widget)
370 {
371 GtkInspectorResourceList *sl = GTK_INSPECTOR_RESOURCE_LIST (widget);
372
373 gtk_tree_view_expand_all (GTK_TREE_VIEW (sl->priv->tree));
374 gtk_stack_set_visible_child_name (GTK_STACK (sl->priv->stack), "list");
375 gtk_widget_set_sensitive (sl->priv->open_details_button, can_show_details (sl));
376 }
377
378 static void
move_search_to_row(GtkInspectorResourceList * sl,GtkTreeIter * iter)379 move_search_to_row (GtkInspectorResourceList *sl,
380 GtkTreeIter *iter)
381 {
382 GtkTreeSelection *selection;
383 GtkTreePath *path;
384
385 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (sl->priv->tree));
386 path = gtk_tree_model_get_path (GTK_TREE_MODEL (sl->priv->model), iter);
387 gtk_tree_view_expand_to_path (GTK_TREE_VIEW (sl->priv->tree), path);
388 gtk_tree_selection_select_path (selection, path);
389 gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (sl->priv->tree), path, NULL, TRUE, 0.5, 0.0);
390 gtk_tree_path_free (path);
391 }
392
393 static gboolean
key_press_event(GtkWidget * window,GdkEvent * event,GtkInspectorResourceList * sl)394 key_press_event (GtkWidget *window,
395 GdkEvent *event,
396 GtkInspectorResourceList *sl)
397 {
398 if (gtk_widget_get_mapped (GTK_WIDGET (sl)))
399 {
400 GdkModifierType default_accel;
401 gboolean search_started;
402
403 search_started = gtk_search_bar_get_search_mode (GTK_SEARCH_BAR (sl->priv->search_bar));
404 default_accel = gtk_widget_get_modifier_mask (GTK_WIDGET (sl), GDK_MODIFIER_INTENT_PRIMARY_ACCELERATOR);
405
406 if (search_started &&
407 (event->key.keyval == GDK_KEY_Return ||
408 event->key.keyval == GDK_KEY_ISO_Enter ||
409 event->key.keyval == GDK_KEY_KP_Enter))
410 {
411 GtkTreeSelection *selection;
412 GtkTreeModel *model;
413 GtkTreeIter iter;
414 GtkTreePath *path;
415
416 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (sl->priv->tree));
417 if (gtk_tree_selection_get_selected (selection, &model, &iter))
418 {
419 path = gtk_tree_model_get_path (model, &iter);
420 gtk_tree_view_row_activated (GTK_TREE_VIEW (sl->priv->tree),
421 path,
422 sl->priv->path_column);
423 gtk_tree_path_free (path);
424
425 return GDK_EVENT_STOP;
426 }
427 else
428 return GDK_EVENT_PROPAGATE;
429 }
430 else if (search_started &&
431 (event->key.keyval == GDK_KEY_Escape))
432 {
433 gtk_search_bar_set_search_mode (GTK_SEARCH_BAR (sl->priv->search_bar), FALSE);
434 return GDK_EVENT_STOP;
435 }
436 else if (search_started &&
437 ((event->key.state & (default_accel | GDK_SHIFT_MASK)) == (default_accel | GDK_SHIFT_MASK)) &&
438 (event->key.keyval == GDK_KEY_g || event->key.keyval == GDK_KEY_G))
439 {
440 GtkTreeIter iter;
441 if (gtk_tree_walk_next_match (sl->priv->walk, TRUE, TRUE, &iter))
442 move_search_to_row (sl, &iter);
443 else
444 gtk_widget_error_bell (GTK_WIDGET (sl));
445
446 return GDK_EVENT_STOP;
447 }
448 else if (search_started &&
449 ((event->key.state & (default_accel | GDK_SHIFT_MASK)) == default_accel) &&
450 (event->key.keyval == GDK_KEY_g || event->key.keyval == GDK_KEY_G))
451 {
452 GtkTreeIter iter;
453
454 if (gtk_tree_walk_next_match (sl->priv->walk, TRUE, FALSE, &iter))
455 move_search_to_row (sl, &iter);
456 else
457 gtk_widget_error_bell (GTK_WIDGET (sl));
458
459 return GDK_EVENT_STOP;
460 }
461
462 return gtk_search_bar_handle_event (GTK_SEARCH_BAR (sl->priv->search_bar), event);
463 }
464 else
465 return GDK_EVENT_PROPAGATE;
466 }
467
468 static void
on_hierarchy_changed(GtkWidget * widget,GtkWidget * previous_toplevel)469 on_hierarchy_changed (GtkWidget *widget,
470 GtkWidget *previous_toplevel)
471 {
472 if (previous_toplevel)
473 g_signal_handlers_disconnect_by_func (previous_toplevel, key_press_event, widget);
474 g_signal_connect (gtk_widget_get_toplevel (widget), "key-press-event",
475 G_CALLBACK (key_press_event), widget);
476 }
477
478 static void
on_search_changed(GtkSearchEntry * entry,GtkInspectorResourceList * sl)479 on_search_changed (GtkSearchEntry *entry,
480 GtkInspectorResourceList *sl)
481 {
482 GtkTreeIter iter;
483 gint length;
484 gboolean backwards;
485
486 length = strlen (gtk_entry_get_text (GTK_ENTRY (entry)));
487 backwards = length < sl->priv->search_length;
488 sl->priv->search_length = length;
489
490 if (length == 0)
491 return;
492
493 if (gtk_tree_walk_next_match (sl->priv->walk, backwards, backwards, &iter))
494 move_search_to_row (sl, &iter);
495 else if (!backwards)
496 gtk_widget_error_bell (GTK_WIDGET (sl));
497 }
498
499 static gboolean
match_string(const gchar * string,const gchar * text)500 match_string (const gchar *string,
501 const gchar *text)
502 {
503 gchar *lower;
504 gboolean match = FALSE;
505
506 if (string)
507 {
508 lower = g_ascii_strdown (string, -1);
509 match = g_str_has_prefix (lower, text);
510 g_free (lower);
511 }
512
513 return match;
514 }
515
516 static gboolean
match_row(GtkTreeModel * model,GtkTreeIter * iter,gpointer data)517 match_row (GtkTreeModel *model,
518 GtkTreeIter *iter,
519 gpointer data)
520 {
521 GtkInspectorResourceList *sl = data;
522 gchar *name, *path;
523 const gchar *text;
524 gboolean match;
525
526 text = gtk_entry_get_text (GTK_ENTRY (sl->priv->search_entry));
527 gtk_tree_model_get (model, iter,
528 COLUMN_NAME, &name,
529 COLUMN_PATH, &path,
530 -1);
531
532 match = (match_string (name, text) ||
533 match_string (path, text));
534
535 g_free (name);
536 g_free (path);
537
538 return match;
539 }
540
541 static void
search_mode_changed(GObject * search_bar,GParamSpec * pspec,GtkInspectorResourceList * sl)542 search_mode_changed (GObject *search_bar,
543 GParamSpec *pspec,
544 GtkInspectorResourceList *sl)
545 {
546 if (!gtk_search_bar_get_search_mode (GTK_SEARCH_BAR (search_bar)))
547 {
548 gtk_tree_walk_reset (sl->priv->walk, NULL);
549 sl->priv->search_length = 0;
550 }
551 }
552
553 static void
next_match(GtkButton * button,GtkInspectorResourceList * sl)554 next_match (GtkButton *button,
555 GtkInspectorResourceList *sl)
556 {
557 if (gtk_search_bar_get_search_mode (GTK_SEARCH_BAR (sl->priv->search_bar)))
558 {
559 GtkTreeIter iter;
560
561 if (gtk_tree_walk_next_match (sl->priv->walk, TRUE, FALSE, &iter))
562 move_search_to_row (sl, &iter);
563 else
564 gtk_widget_error_bell (GTK_WIDGET (sl));
565 }
566 }
567
568 static void
previous_match(GtkButton * button,GtkInspectorResourceList * sl)569 previous_match (GtkButton *button,
570 GtkInspectorResourceList *sl)
571 {
572 if (gtk_search_bar_get_search_mode (GTK_SEARCH_BAR (sl->priv->search_bar)))
573 {
574 GtkTreeIter iter;
575
576 if (gtk_tree_walk_next_match (sl->priv->walk, TRUE, TRUE, &iter))
577 move_search_to_row (sl, &iter);
578 else
579 gtk_widget_error_bell (GTK_WIDGET (sl));
580 }
581 }
582
583 static void
gtk_inspector_resource_list_init(GtkInspectorResourceList * sl)584 gtk_inspector_resource_list_init (GtkInspectorResourceList *sl)
585 {
586 sl->priv = gtk_inspector_resource_list_get_instance_private (sl);
587
588 gtk_widget_init_template (GTK_WIDGET (sl));
589
590 gtk_tree_view_column_set_cell_data_func (sl->priv->count_column,
591 sl->priv->count_renderer,
592 count_data_func, sl, NULL);
593 gtk_tree_view_column_set_cell_data_func (sl->priv->size_column,
594 sl->priv->size_renderer,
595 size_data_func, sl, NULL);
596
597 g_signal_connect (sl, "map", G_CALLBACK (on_map), NULL);
598
599 gtk_search_bar_connect_entry (GTK_SEARCH_BAR (sl->priv->search_bar),
600 GTK_ENTRY (sl->priv->search_entry));
601
602 g_signal_connect (sl->priv->search_bar, "notify::search-mode-enabled",
603 G_CALLBACK (search_mode_changed), sl);
604 sl->priv->walk = gtk_tree_walk_new (GTK_TREE_MODEL (sl->priv->model), match_row, sl, NULL);
605 }
606
607 static void
constructed(GObject * object)608 constructed (GObject *object)
609 {
610 GtkInspectorResourceList *rl = GTK_INSPECTOR_RESOURCE_LIST (object);
611
612 g_signal_connect (rl->priv->open_details_button, "clicked",
613 G_CALLBACK (open_details), rl);
614 g_signal_connect (rl->priv->close_details_button, "clicked",
615 G_CALLBACK (close_details), rl);
616
617 load_resources (rl);
618 }
619
620 static void
get_property(GObject * object,guint param_id,GValue * value,GParamSpec * pspec)621 get_property (GObject *object,
622 guint param_id,
623 GValue *value,
624 GParamSpec *pspec)
625 {
626 GtkInspectorResourceList *rl = GTK_INSPECTOR_RESOURCE_LIST (object);
627
628 switch (param_id)
629 {
630 case PROP_BUTTONS:
631 g_value_take_object (value, rl->priv->buttons);
632 break;
633
634 default:
635 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
636 break;
637 }
638 }
639
640 static void
set_property(GObject * object,guint param_id,const GValue * value,GParamSpec * pspec)641 set_property (GObject *object,
642 guint param_id,
643 const GValue *value,
644 GParamSpec *pspec)
645 {
646 GtkInspectorResourceList *rl = GTK_INSPECTOR_RESOURCE_LIST (object);
647
648 switch (param_id)
649 {
650 case PROP_BUTTONS:
651 rl->priv->buttons = g_value_get_object (value);
652 rl->priv->open_details_button = gtk_stack_get_child_by_name (GTK_STACK (rl->priv->buttons), "list");
653 rl->priv->close_details_button = gtk_stack_get_child_by_name (GTK_STACK (rl->priv->buttons), "details");
654 break;
655
656 default:
657 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
658 break;
659 }
660 }
661
662 static void
finalize(GObject * object)663 finalize (GObject *object)
664 {
665 GtkInspectorResourceList *sl = GTK_INSPECTOR_RESOURCE_LIST (object);
666
667 gtk_tree_walk_free (sl->priv->walk);
668
669 G_OBJECT_CLASS (gtk_inspector_resource_list_parent_class)->finalize (object);
670 }
671
672 static void
gtk_inspector_resource_list_class_init(GtkInspectorResourceListClass * klass)673 gtk_inspector_resource_list_class_init (GtkInspectorResourceListClass *klass)
674 {
675 GObjectClass *object_class = G_OBJECT_CLASS (klass);
676 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
677
678 object_class->get_property = get_property;
679 object_class->set_property = set_property;
680 object_class->constructed = constructed;
681 object_class->finalize = finalize;
682
683 g_object_class_install_property (object_class, PROP_BUTTONS,
684 g_param_spec_object ("buttons", NULL, NULL,
685 GTK_TYPE_WIDGET, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
686
687 gtk_widget_class_set_template_from_resource (widget_class, "/org/gtk/libgtk/inspector/resource-list.ui");
688 gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorResourceList, model);
689 gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorResourceList, buffer);
690 gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorResourceList, content);
691 gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorResourceList, image);
692 gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorResourceList, name_label);
693 gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorResourceList, type_label);
694 gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorResourceList, type);
695 gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorResourceList, size_label);
696 gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorResourceList, info_grid);
697 gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorResourceList, count_column);
698 gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorResourceList, count_renderer);
699 gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorResourceList, size_column);
700 gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorResourceList, size_renderer);
701 gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorResourceList, stack);
702 gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorResourceList, tree);
703 gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorResourceList, search_bar);
704 gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorResourceList, search_entry);
705 gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorResourceList, path_column);
706
707 gtk_widget_class_bind_template_callback (widget_class, row_activated);
708 gtk_widget_class_bind_template_callback (widget_class, on_selection_changed);
709 gtk_widget_class_bind_template_callback (widget_class, on_hierarchy_changed);
710 gtk_widget_class_bind_template_callback (widget_class, on_search_changed);
711 gtk_widget_class_bind_template_callback (widget_class, next_match);
712 gtk_widget_class_bind_template_callback (widget_class, previous_match);
713 }
714
715 // vim: set et sw=2 ts=2:
716