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