1 /*
2  * Copyright (c) 2008-2009  Christian Hammond
3  * Copyright (c) 2008-2009  David Trowbridge
4  * Copyright (c) 2013 Intel Corporation
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the "Software"),
8  * to deal in the Software without restriction, including without limitation
9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10  * and/or sell copies of the Software, and to permit persons to whom the
11  * Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included
14  * in all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  */
24 
25 #include "config.h"
26 #include <glib/gi18n-lib.h>
27 
28 #include <stdlib.h>
29 
30 #include "window.h"
31 #include "prop-list.h"
32 #include "css-editor.h"
33 #include "css-node-tree.h"
34 #include "object-hierarchy.h"
35 #include "object-tree.h"
36 #include "selector.h"
37 #include "size-groups.h"
38 #include "data-list.h"
39 #include "signals-list.h"
40 #include "actions.h"
41 #include "menu.h"
42 #include "misc-info.h"
43 #include "gestures.h"
44 #include "magnifier.h"
45 
46 #include "gtklabel.h"
47 #include "gtkbutton.h"
48 #include "gtkstack.h"
49 #include "gtktreeviewcolumn.h"
50 #include "gtkmodulesprivate.h"
51 #include "gtkwindow.h"
52 #include "gtkwindowgroup.h"
53 
G_DEFINE_TYPE(GtkInspectorWindow,gtk_inspector_window,GTK_TYPE_WINDOW)54 G_DEFINE_TYPE (GtkInspectorWindow, gtk_inspector_window, GTK_TYPE_WINDOW)
55 
56 static gboolean
57 set_selected_object (GtkInspectorWindow *iw,
58                      GObject            *selected)
59 {
60   GList *l;
61   const char *title;
62 
63   if (!gtk_inspector_prop_list_set_object (GTK_INSPECTOR_PROP_LIST (iw->prop_list), selected))
64     return FALSE;
65 
66   title = (const char *)g_object_get_data (selected, "gtk-inspector-object-title");
67   gtk_label_set_label (GTK_LABEL (iw->object_title), title);
68 
69   gtk_inspector_prop_list_set_object (GTK_INSPECTOR_PROP_LIST (iw->child_prop_list), selected);
70   gtk_inspector_signals_list_set_object (GTK_INSPECTOR_SIGNALS_LIST (iw->signals_list), selected);
71   gtk_inspector_object_hierarchy_set_object (GTK_INSPECTOR_OBJECT_HIERARCHY (iw->object_hierarchy), selected);
72   gtk_inspector_selector_set_object (GTK_INSPECTOR_SELECTOR (iw->selector), selected);
73   gtk_inspector_misc_info_set_object (GTK_INSPECTOR_MISC_INFO (iw->misc_info), selected);
74   gtk_inspector_css_node_tree_set_object (GTK_INSPECTOR_CSS_NODE_TREE (iw->widget_css_node_tree), selected);
75   gtk_inspector_size_groups_set_object (GTK_INSPECTOR_SIZE_GROUPS (iw->size_groups), selected);
76   gtk_inspector_data_list_set_object (GTK_INSPECTOR_DATA_LIST (iw->data_list), selected);
77   gtk_inspector_actions_set_object (GTK_INSPECTOR_ACTIONS (iw->actions), selected);
78   gtk_inspector_menu_set_object (GTK_INSPECTOR_MENU (iw->menu), selected);
79   gtk_inspector_gestures_set_object (GTK_INSPECTOR_GESTURES (iw->gestures), selected);
80   gtk_inspector_magnifier_set_object (GTK_INSPECTOR_MAGNIFIER (iw->magnifier), selected);
81 
82   for (l = iw->extra_pages; l != NULL; l = l->next)
83     g_object_set (l->data, "object", selected, NULL);
84 
85   return TRUE;
86 }
87 
88 static void
on_object_activated(GtkInspectorObjectTree * wt,GObject * selected,const gchar * name,GtkInspectorWindow * iw)89 on_object_activated (GtkInspectorObjectTree *wt,
90                      GObject                *selected,
91                      const gchar            *name,
92                      GtkInspectorWindow     *iw)
93 {
94   const gchar *tab;
95 
96   if (!set_selected_object (iw, selected))
97     return;
98 
99   tab = g_object_get_data (G_OBJECT (wt), "next-tab");
100   if (tab)
101     gtk_stack_set_visible_child_name (GTK_STACK (iw->object_details), tab);
102 
103   gtk_stack_set_visible_child_name (GTK_STACK (iw->object_stack), "object-details");
104   gtk_stack_set_visible_child_name (GTK_STACK (iw->object_buttons), "details");
105 }
106 
107 static void
on_object_selected(GtkInspectorObjectTree * wt,GObject * selected,GtkInspectorWindow * iw)108 on_object_selected (GtkInspectorObjectTree *wt,
109                     GObject                *selected,
110                     GtkInspectorWindow     *iw)
111 {
112   gtk_widget_set_sensitive (iw->object_details_button, selected != NULL);
113   if (GTK_IS_WIDGET (selected))
114     gtk_inspector_flash_widget (iw, GTK_WIDGET (selected));
115 }
116 
117 static void
close_object_details(GtkWidget * button,GtkInspectorWindow * iw)118 close_object_details (GtkWidget *button, GtkInspectorWindow *iw)
119 {
120   gtk_stack_set_visible_child_name (GTK_STACK (iw->object_stack), "object-tree");
121   gtk_stack_set_visible_child_name (GTK_STACK (iw->object_buttons), "list");
122 }
123 
124 static void
open_object_details(GtkWidget * button,GtkInspectorWindow * iw)125 open_object_details (GtkWidget *button, GtkInspectorWindow *iw)
126 {
127   GObject *selected;
128 
129   selected = gtk_inspector_object_tree_get_selected (GTK_INSPECTOR_OBJECT_TREE (iw->object_tree));
130 
131   if (!set_selected_object (iw, selected))
132     return;
133 
134   gtk_stack_set_visible_child_name (GTK_STACK (iw->object_stack), "object-details");
135   gtk_stack_set_visible_child_name (GTK_STACK (iw->object_buttons), "details");
136 }
137 
138 static gboolean
translate_visible_child_name(GBinding * binding,const GValue * from,GValue * to,gpointer user_data)139 translate_visible_child_name (GBinding     *binding,
140                               const GValue *from,
141                               GValue       *to,
142                               gpointer      user_data)
143 {
144   GtkInspectorWindow *iw = user_data;
145   const char *name;
146 
147   name = g_value_get_string (from);
148 
149   if (gtk_stack_get_child_by_name (GTK_STACK (iw->object_start_stack), name))
150     g_value_set_string (to, name);
151   else
152     g_value_set_string (to, "empty");
153 
154   return TRUE;
155 }
156 
157 static void
gtk_inspector_window_init(GtkInspectorWindow * iw)158 gtk_inspector_window_init (GtkInspectorWindow *iw)
159 {
160   GIOExtensionPoint *extension_point;
161   GList *l, *extensions;
162 
163   gtk_widget_init_template (GTK_WIDGET (iw));
164 
165   g_object_bind_property_full (iw->object_details, "visible-child-name",
166                                iw->object_start_stack, "visible-child-name",
167                                G_BINDING_SYNC_CREATE,
168                                translate_visible_child_name,
169                                NULL,
170                                iw,
171                                NULL);
172 
173   gtk_window_group_add_window (gtk_window_group_new (), GTK_WINDOW (iw));
174 
175   extension_point = g_io_extension_point_lookup ("gtk-inspector-page");
176   extensions = g_io_extension_point_get_extensions (extension_point);
177 
178   for (l = extensions; l != NULL; l = l->next)
179     {
180       GIOExtension *extension = l->data;
181       GType type;
182       GtkWidget *widget;
183       const char *name;
184       char *title;
185       GtkWidget *button;
186       gboolean use_picker;
187 
188       type = g_io_extension_get_type (extension);
189 
190       widget = g_object_new (type, NULL);
191 
192       iw->extra_pages = g_list_prepend (iw->extra_pages, widget);
193 
194       name = g_io_extension_get_name (extension);
195       g_object_get (widget, "title", &title, NULL);
196 
197       if (g_object_class_find_property (G_OBJECT_GET_CLASS (widget), "use-picker"))
198         g_object_get (widget, "use-picker", &use_picker, NULL);
199       else
200         use_picker = FALSE;
201 
202       if (use_picker)
203         {
204           button = gtk_button_new_from_icon_name ("find-location-symbolic",
205                                                   GTK_ICON_SIZE_MENU);
206           gtk_widget_set_focus_on_click (button, FALSE);
207           gtk_widget_set_halign (button, GTK_ALIGN_START);
208           gtk_widget_set_valign (button, GTK_ALIGN_CENTER);
209           g_signal_connect (button, "clicked",
210                             G_CALLBACK (gtk_inspector_on_inspect), iw);
211         }
212       else
213         button = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
214 
215       gtk_stack_add_titled (GTK_STACK (iw->top_stack), widget, name, title);
216       gtk_stack_add_named (GTK_STACK (iw->button_stack), button, name);
217       gtk_widget_show (widget);
218       gtk_widget_show (button);
219 
220       g_free (title);
221     }
222 }
223 
224 static void
gtk_inspector_window_constructed(GObject * object)225 gtk_inspector_window_constructed (GObject *object)
226 {
227   GtkInspectorWindow *iw = GTK_INSPECTOR_WINDOW (object);
228 
229   G_OBJECT_CLASS (gtk_inspector_window_parent_class)->constructed (object);
230 
231   gtk_inspector_object_tree_scan (GTK_INSPECTOR_OBJECT_TREE (iw->object_tree), NULL);
232 }
233 
234 static void
object_details_changed(GtkWidget * combo,GParamSpec * pspec,GtkInspectorWindow * iw)235 object_details_changed (GtkWidget          *combo,
236                         GParamSpec         *pspec,
237                         GtkInspectorWindow *iw)
238 {
239   gtk_stack_set_visible_child_name (GTK_STACK (iw->object_center_stack), "title");
240 }
241 
242 static void
gtk_inspector_window_class_init(GtkInspectorWindowClass * klass)243 gtk_inspector_window_class_init (GtkInspectorWindowClass *klass)
244 {
245   GObjectClass *object_class = G_OBJECT_CLASS (klass);
246   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
247 
248   object_class->constructed = gtk_inspector_window_constructed;
249 
250   gtk_widget_class_set_template_from_resource (widget_class, "/org/gtk/libgtk/inspector/window.ui");
251 
252   gtk_widget_class_bind_template_child (widget_class, GtkInspectorWindow, top_stack);
253   gtk_widget_class_bind_template_child (widget_class, GtkInspectorWindow, button_stack);
254   gtk_widget_class_bind_template_child (widget_class, GtkInspectorWindow, object_stack);
255   gtk_widget_class_bind_template_child (widget_class, GtkInspectorWindow, object_tree);
256   gtk_widget_class_bind_template_child (widget_class, GtkInspectorWindow, object_details);
257   gtk_widget_class_bind_template_child (widget_class, GtkInspectorWindow, object_start_stack);
258   gtk_widget_class_bind_template_child (widget_class, GtkInspectorWindow, object_center_stack);
259   gtk_widget_class_bind_template_child (widget_class, GtkInspectorWindow, object_buttons);
260   gtk_widget_class_bind_template_child (widget_class, GtkInspectorWindow, object_details_button);
261   gtk_widget_class_bind_template_child (widget_class, GtkInspectorWindow, select_object);
262   gtk_widget_class_bind_template_child (widget_class, GtkInspectorWindow, prop_list);
263   gtk_widget_class_bind_template_child (widget_class, GtkInspectorWindow, child_prop_list);
264   gtk_widget_class_bind_template_child (widget_class, GtkInspectorWindow, signals_list);
265   gtk_widget_class_bind_template_child (widget_class, GtkInspectorWindow, widget_css_node_tree);
266   gtk_widget_class_bind_template_child (widget_class, GtkInspectorWindow, object_hierarchy);
267   gtk_widget_class_bind_template_child (widget_class, GtkInspectorWindow, object_title);
268   gtk_widget_class_bind_template_child (widget_class, GtkInspectorWindow, selector);
269   gtk_widget_class_bind_template_child (widget_class, GtkInspectorWindow, size_groups);
270   gtk_widget_class_bind_template_child (widget_class, GtkInspectorWindow, data_list);
271   gtk_widget_class_bind_template_child (widget_class, GtkInspectorWindow, actions);
272   gtk_widget_class_bind_template_child (widget_class, GtkInspectorWindow, menu);
273   gtk_widget_class_bind_template_child (widget_class, GtkInspectorWindow, misc_info);
274   gtk_widget_class_bind_template_child (widget_class, GtkInspectorWindow, gestures);
275   gtk_widget_class_bind_template_child (widget_class, GtkInspectorWindow, magnifier);
276 
277   gtk_widget_class_bind_template_callback (widget_class, gtk_inspector_on_inspect);
278   gtk_widget_class_bind_template_callback (widget_class, on_object_activated);
279   gtk_widget_class_bind_template_callback (widget_class, on_object_selected);
280   gtk_widget_class_bind_template_callback (widget_class, open_object_details);
281   gtk_widget_class_bind_template_callback (widget_class, close_object_details);
282   gtk_widget_class_bind_template_callback (widget_class, object_details_changed);
283 }
284 
285 static GdkScreen *
get_inspector_screen(void)286 get_inspector_screen (void)
287 {
288   static GdkDisplay *display = NULL;
289 
290   if (display == NULL)
291     {
292       const gchar *name;
293 
294       name = g_getenv ("GTK_INSPECTOR_DISPLAY");
295       display = gdk_display_open (name);
296 
297       if (display)
298         g_debug ("Using display %s for GtkInspector", name);
299       else
300         g_message ("Failed to open display %s", name);
301     }
302 
303   if (!display)
304     {
305       display = gdk_display_open (NULL);
306       if (display)
307         g_debug ("Using default display for GtkInspector");
308       else
309         g_message ("Failed to separate connection to default display");
310     }
311 
312   if (!display)
313     display = gdk_display_get_default ();
314 
315   return gdk_display_get_default_screen (display);
316 }
317 
318 GtkWidget *
gtk_inspector_window_new(void)319 gtk_inspector_window_new (void)
320 {
321   return GTK_WIDGET (g_object_new (GTK_TYPE_INSPECTOR_WINDOW,
322                                    "screen", get_inspector_screen (),
323                                    NULL));
324 }
325 
326 void
gtk_inspector_window_rescan(GtkWidget * widget)327 gtk_inspector_window_rescan (GtkWidget *widget)
328 {
329   GtkInspectorWindow *iw = GTK_INSPECTOR_WINDOW (widget);
330 
331   gtk_inspector_object_tree_scan (GTK_INSPECTOR_OBJECT_TREE (iw->object_tree), NULL);
332 }
333 
334 // vim: set et sw=2 ts=2:
335