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 "controllers.h"
22
23#include "gtkbinlayout.h"
24#include "gtkdropdown.h"
25#include "gtkbox.h"
26#include "gtkcustomsorter.h"
27#include "gtkgesture.h"
28#include "gtklabel.h"
29#include "gtkscrolledwindow.h"
30#include "gtksortlistmodel.h"
31#include "gtkstack.h"
32#include "gtkwidgetprivate.h"
33#include "window.h"
34#include "gtksignallistitemfactory.h"
35#include "gtkcolumnview.h"
36#include "gtkcolumnviewcolumn.h"
37#include "gtklistitem.h"
38#include "gtknoselection.h"
39
40struct _GtkInspectorControllers
41{
42 GtkWidget parent_instance;
43
44 GtkWidget *view;
45};
46
47struct _GtkInspectorControllersClass
48{
49 GtkWidgetClass parent_class;
50};
51
52G_DEFINE_TYPE (GtkInspectorControllers, gtk_inspector_controllers, GTK_TYPE_WIDGET)
53
54static void
55row_activated (GtkColumnView *view,
56 guint position,
57 GtkInspectorControllers *self)
58{
59 GtkInspectorWindow *iw;
60 GListModel *model;
61 GObject *controller;
62
63 iw = GTK_INSPECTOR_WINDOW (gtk_widget_get_ancestor (GTK_WIDGET (self), GTK_TYPE_INSPECTOR_WINDOW));
64
65 model = G_LIST_MODEL (ptr: gtk_column_view_get_model (self: view));
66 controller = g_list_model_get_item (list: model, position);
67 gtk_inspector_window_push_object (iw, object: controller, kind: CHILD_KIND_CONTROLLER, position: 0);
68 g_object_unref (object: controller);
69}
70
71static void
72setup_row (GtkSignalListItemFactory *factory,
73 GtkListItem *list_item,
74 gpointer data)
75{
76 GtkWidget *label;
77
78 label = gtk_label_new (str: "");
79 gtk_label_set_xalign (GTK_LABEL (label), xalign: 0);
80 gtk_list_item_set_child (self: list_item, child: label);
81}
82
83static void
84bind_type (GtkSignalListItemFactory *factory,
85 GtkListItem *list_item,
86 gpointer data)
87{
88 GtkWidget *label;
89 GtkEventController *controller;
90
91 label = gtk_list_item_get_child (self: list_item);
92 controller = gtk_list_item_get_item (self: list_item);
93
94 gtk_label_set_label (GTK_LABEL (label), G_OBJECT_TYPE_NAME (controller));
95}
96
97static void
98bind_name (GtkSignalListItemFactory *factory,
99 GtkListItem *list_item,
100 gpointer data)
101{
102 GtkWidget *label;
103 GtkEventController *controller;
104
105 label = gtk_list_item_get_child (self: list_item);
106 controller = gtk_list_item_get_item (self: list_item);
107
108 gtk_label_set_label (GTK_LABEL (label), str: gtk_event_controller_get_name (controller));
109}
110
111static void
112bind_phase (GtkSignalListItemFactory *factory,
113 GtkListItem *list_item,
114 gpointer data)
115{
116 GtkWidget *label;
117 GtkEventController *controller;
118 const char *name;
119
120 label = gtk_list_item_get_child (self: list_item);
121 controller = gtk_list_item_get_item (self: list_item);
122
123 switch (gtk_event_controller_get_propagation_phase (controller))
124 {
125 case GTK_PHASE_NONE:
126 name = C_("event phase", "None");
127 break;
128 case GTK_PHASE_CAPTURE:
129 name = C_("event phase", "Capture");
130 break;
131 case GTK_PHASE_BUBBLE:
132 name = C_("event phase", "Bubble");
133 break;
134 case GTK_PHASE_TARGET:
135 name = C_("event phase", "Target");
136 break;
137 default:
138 g_assert_not_reached ();
139 }
140
141 gtk_label_set_label (GTK_LABEL (label), str: name);
142}
143
144static void
145bind_limit (GtkSignalListItemFactory *factory,
146 GtkListItem *list_item,
147 gpointer data)
148{
149 GtkWidget *label;
150 GtkEventController *controller;
151
152 label = gtk_list_item_get_child (self: list_item);
153 controller = gtk_list_item_get_item (self: list_item);
154
155 if (gtk_event_controller_get_propagation_limit (controller) == GTK_LIMIT_SAME_NATIVE)
156 gtk_label_set_label (GTK_LABEL (label), C_("propagation limit", "Native"));
157 else
158 gtk_label_set_label (GTK_LABEL (label), str: "");
159}
160
161static void
162gtk_inspector_controllers_init (GtkInspectorControllers *self)
163{
164 GtkWidget *sw;
165 GtkListItemFactory *factory;
166 GtkColumnViewColumn *column;
167
168 sw = gtk_scrolled_window_new ();
169
170 self->view = gtk_column_view_new (NULL);
171
172 factory = gtk_signal_list_item_factory_new ();
173 g_signal_connect (factory, "setup", G_CALLBACK (setup_row), NULL);
174 g_signal_connect (factory, "bind", G_CALLBACK (bind_type), NULL);
175
176 column = gtk_column_view_column_new (title: "Type", factory);
177 gtk_column_view_append_column (GTK_COLUMN_VIEW (self->view), column);
178 g_object_unref (object: column);
179
180 factory = gtk_signal_list_item_factory_new ();
181 g_signal_connect (factory, "setup", G_CALLBACK (setup_row), NULL);
182 g_signal_connect (factory, "bind", G_CALLBACK (bind_name), NULL);
183
184 column = gtk_column_view_column_new (title: "Name", factory);
185 gtk_column_view_column_set_expand (self: column, TRUE);
186 gtk_column_view_append_column (GTK_COLUMN_VIEW (self->view), column);
187 g_object_unref (object: column);
188
189 factory = gtk_signal_list_item_factory_new ();
190 g_signal_connect (factory, "setup", G_CALLBACK (setup_row), NULL);
191 g_signal_connect (factory, "bind", G_CALLBACK (bind_phase), NULL);
192
193 column = gtk_column_view_column_new (title: "Phase", factory);
194 gtk_column_view_append_column (GTK_COLUMN_VIEW (self->view), column);
195 g_object_unref (object: column);
196
197 factory = gtk_signal_list_item_factory_new ();
198 g_signal_connect (factory, "setup", G_CALLBACK (setup_row), NULL);
199 g_signal_connect (factory, "bind", G_CALLBACK (bind_limit), NULL);
200
201 column = gtk_column_view_column_new (title: "Limit", factory);
202 gtk_column_view_append_column (GTK_COLUMN_VIEW (self->view), column);
203 g_object_unref (object: column);
204
205 g_signal_connect (self->view, "activate", G_CALLBACK (row_activated), self);
206
207 gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), child: self->view);
208
209 gtk_widget_set_parent (widget: sw, GTK_WIDGET (self));
210}
211
212static int
213compare_phases (GtkPropagationPhase first,
214 GtkPropagationPhase second)
215{
216 int priorities[] = {
217 [GTK_PHASE_NONE] = 0,
218 [GTK_PHASE_CAPTURE] = 1,
219 [GTK_PHASE_BUBBLE] = 3,
220 [GTK_PHASE_TARGET] = 2
221 };
222
223 return priorities[first] - priorities[second];
224}
225
226static int
227compare_controllers (gconstpointer _first,
228 gconstpointer _second,
229 gpointer unused)
230{
231 GtkEventController *first = GTK_EVENT_CONTROLLER (_first);
232 GtkEventController *second = GTK_EVENT_CONTROLLER (_second);
233 GtkPropagationPhase first_phase, second_phase;
234 GtkWidget *first_widget, *second_widget;
235 int result;
236
237
238 first_phase = gtk_event_controller_get_propagation_phase (controller: first);
239 second_phase = gtk_event_controller_get_propagation_phase (controller: second);
240 result = compare_phases (first: first_phase, second: second_phase);
241 if (result != 0)
242 return result;
243
244 first_widget = gtk_event_controller_get_widget (controller: first);
245 second_widget = gtk_event_controller_get_widget (controller: second);
246 if (first_widget == second_widget)
247 return 0;
248
249 if (gtk_widget_is_ancestor (widget: first_widget, ancestor: second_widget))
250 result = -1;
251 else
252 result = 1;
253
254 if (first_phase == GTK_PHASE_BUBBLE)
255 result = -result;
256
257 return result;
258}
259
260void
261gtk_inspector_controllers_set_object (GtkInspectorControllers *self,
262 GObject *object)
263{
264 GtkWidget *stack;
265 GtkStackPage *page;
266 GListModel *model;
267 GtkSortListModel *sort_model;
268 GtkSorter *sorter;
269 GtkNoSelection *no_selection;
270
271 stack = gtk_widget_get_parent (GTK_WIDGET (self));
272 page = gtk_stack_get_page (GTK_STACK (stack), GTK_WIDGET (self));
273
274 if (!GTK_IS_WIDGET (object))
275 {
276 gtk_column_view_set_model (GTK_COLUMN_VIEW (self->view), NULL);
277 g_object_set (object: page, first_property_name: "visible", FALSE, NULL);
278 return;
279 }
280
281 g_object_set (object: page, first_property_name: "visible", TRUE, NULL);
282
283 model = gtk_widget_observe_controllers (GTK_WIDGET (object));
284 sorter = GTK_SORTER (ptr: gtk_custom_sorter_new (sort_func: compare_controllers, NULL, NULL));
285 sort_model = gtk_sort_list_model_new (model, sorter);
286 no_selection = gtk_no_selection_new (model: G_LIST_MODEL (ptr: sort_model));
287
288 gtk_column_view_set_model (GTK_COLUMN_VIEW (self->view), model: GTK_SELECTION_MODEL (ptr: no_selection));
289
290 g_object_unref (object: no_selection);
291}
292
293static void
294gtk_inspector_controllers_dispose (GObject *object)
295{
296 GtkInspectorControllers *self = GTK_INSPECTOR_CONTROLLERS (ptr: object);
297
298 gtk_widget_unparent (widget: gtk_widget_get_first_child (GTK_WIDGET (self)));
299
300 G_OBJECT_CLASS (gtk_inspector_controllers_parent_class)->dispose (object);
301}
302
303static void
304gtk_inspector_controllers_class_init (GtkInspectorControllersClass *klass)
305{
306 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
307 GObjectClass *object_class = G_OBJECT_CLASS (klass);
308
309 object_class->dispose = gtk_inspector_controllers_dispose;
310
311 gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT);
312}
313
314// vim: set et sw=2 ts=2:
315

source code of gtk/gtk/inspector/controllers.c