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 "general.h"
22
23 #include "gtkdebug.h"
24 #include "gtklabel.h"
25 #include "gtkscale.h"
26 #include "gtkswitch.h"
27 #include "gtklistbox.h"
28 #include "gtkprivate.h"
29 #include "gtksizegroup.h"
30 #include "gtkimage.h"
31 #include "gtkadjustment.h"
32 #include "gtkbox.h"
33
34 #ifdef GDK_WINDOWING_X11
35 #include "x11/gdkx.h"
36 #include <epoxy/glx.h>
37 #endif
38
39 #ifdef GDK_WINDOWING_WIN32
40 #include "win32/gdkwin32.h"
41 #endif
42
43 #ifdef GDK_WINDOWING_QUARTZ
44 #include "quartz/gdkquartz.h"
45 #endif
46
47 #ifdef GDK_WINDOWING_WAYLAND
48 #include "wayland/gdkwayland.h"
49 #include <epoxy/egl.h>
50 #endif
51
52 #ifdef GDK_WINDOWING_BROADWAY
53 #include "broadway/gdkbroadway.h"
54 #endif
55
56 struct _GtkInspectorGeneralPrivate
57 {
58 GtkWidget *version_box;
59 GtkWidget *env_box;
60 GtkWidget *display_box;
61 GtkWidget *gl_box;
62 GtkWidget *device_box;
63 GtkWidget *gtk_version;
64 GtkWidget *gdk_backend;
65 GtkWidget *gl_version;
66 GtkWidget *gl_vendor;
67 GtkWidget *prefix;
68 GtkWidget *xdg_data_home;
69 GtkWidget *xdg_data_dirs;
70 GtkWidget *gtk_path;
71 GtkWidget *gtk_exe_prefix;
72 GtkWidget *gtk_data_prefix;
73 GtkWidget *gsettings_schema_dir;
74 GtkWidget *display_name;
75 GtkWidget *display_rgba;
76 GtkWidget *display_composited;
77 GtkSizeGroup *labels;
78 GtkAdjustment *focus_adjustment;
79 };
80
G_DEFINE_TYPE_WITH_PRIVATE(GtkInspectorGeneral,gtk_inspector_general,GTK_TYPE_SCROLLED_WINDOW)81 G_DEFINE_TYPE_WITH_PRIVATE (GtkInspectorGeneral, gtk_inspector_general, GTK_TYPE_SCROLLED_WINDOW)
82
83 static void
84 init_version (GtkInspectorGeneral *gen)
85 {
86 const gchar *backend;
87 GdkDisplay *display;
88
89 display = gdk_display_get_default ();
90
91 #ifdef GDK_WINDOWING_X11
92 if (GDK_IS_X11_DISPLAY (display))
93 backend = "X11";
94 else
95 #endif
96 #ifdef GDK_WINDOWING_WAYLAND
97 if (GDK_IS_WAYLAND_DISPLAY (display))
98 backend = "Wayland";
99 else
100 #endif
101 #ifdef GDK_WINDOWING_BROADWAY
102 if (GDK_IS_BROADWAY_DISPLAY (display))
103 backend = "Broadway";
104 else
105 #endif
106 #ifdef GDK_WINDOWING_WIN32
107 if (GDK_IS_WIN32_DISPLAY (display))
108 backend = "Windows";
109 else
110 #endif
111 #ifdef GDK_WINDOWING_QUARTZ
112 if (GDK_IS_QUARTZ_DISPLAY (display))
113 backend = "Quartz";
114 else
115 #endif
116 backend = "Unknown";
117
118 gtk_label_set_text (GTK_LABEL (gen->priv->gtk_version), GTK_VERSION);
119 gtk_label_set_text (GTK_LABEL (gen->priv->gdk_backend), backend);
120 }
121
122 static G_GNUC_UNUSED void
add_check_row(GtkInspectorGeneral * gen,GtkListBox * list,const gchar * name,gboolean value,gint indent)123 add_check_row (GtkInspectorGeneral *gen,
124 GtkListBox *list,
125 const gchar *name,
126 gboolean value,
127 gint indent)
128 {
129 GtkWidget *row, *box, *label, *check;
130
131 box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 40);
132 g_object_set (box,
133 "margin", 10,
134 "margin-start", 10 + indent,
135 NULL);
136
137 label = gtk_label_new (name);
138 gtk_widget_set_halign (label, GTK_ALIGN_START);
139 gtk_widget_set_valign (label, GTK_ALIGN_BASELINE);
140 gtk_label_set_xalign (GTK_LABEL (label), 0.0);
141 gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 0);
142
143 check = gtk_image_new_from_icon_name ("object-select-symbolic", GTK_ICON_SIZE_MENU);
144 gtk_widget_set_halign (check, GTK_ALIGN_END);
145 gtk_widget_set_valign (check, GTK_ALIGN_BASELINE);
146 gtk_widget_set_opacity (check, value ? 1.0 : 0.0);
147 gtk_box_pack_start (GTK_BOX (box), check, TRUE, TRUE, 0);
148
149 row = gtk_list_box_row_new ();
150 gtk_container_add (GTK_CONTAINER (row), box);
151 gtk_list_box_row_set_activatable (GTK_LIST_BOX_ROW (row), FALSE);
152 gtk_widget_show_all (row);
153
154 gtk_list_box_insert (list, row, -1);
155
156 gtk_size_group_add_widget (GTK_SIZE_GROUP (gen->priv->labels), label);
157 }
158
159 static void
add_label_row(GtkInspectorGeneral * gen,GtkListBox * list,const char * name,const char * value,gint indent)160 add_label_row (GtkInspectorGeneral *gen,
161 GtkListBox *list,
162 const char *name,
163 const char *value,
164 gint indent)
165 {
166 GtkWidget *box;
167 GtkWidget *label;
168 GtkWidget *row;
169
170 box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 40);
171 g_object_set (box,
172 "margin", 10,
173 "margin-start", 10 + indent,
174 NULL);
175
176 label = gtk_label_new (name);
177 gtk_widget_set_halign (label, GTK_ALIGN_START);
178 gtk_widget_set_valign (label, GTK_ALIGN_BASELINE);
179 gtk_label_set_xalign (GTK_LABEL (label), 0.0);
180 gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 0);
181
182 label = gtk_label_new (value);
183 gtk_label_set_selectable (GTK_LABEL (label), TRUE);
184 gtk_widget_set_halign (label, GTK_ALIGN_END);
185 gtk_widget_set_valign (label, GTK_ALIGN_BASELINE);
186 gtk_label_set_xalign (GTK_LABEL (label), 1.0);
187 gtk_box_pack_start (GTK_BOX (box), label, TRUE, TRUE, 0);
188
189 row = gtk_list_box_row_new ();
190 gtk_container_add (GTK_CONTAINER (row), box);
191 gtk_list_box_row_set_activatable (GTK_LIST_BOX_ROW (row), FALSE);
192 gtk_widget_show_all (row);
193
194 gtk_list_box_insert (GTK_LIST_BOX (list), row, -1);
195
196 gtk_size_group_add_widget (GTK_SIZE_GROUP (gen->priv->labels), label);
197 }
198
199 #ifdef GDK_WINDOWING_X11
200 static void
append_glx_extension_row(GtkInspectorGeneral * gen,Display * dpy,const gchar * ext)201 append_glx_extension_row (GtkInspectorGeneral *gen,
202 Display *dpy,
203 const gchar *ext)
204 {
205 add_check_row (gen, GTK_LIST_BOX (gen->priv->gl_box), ext, epoxy_has_glx_extension (dpy, 0, ext), 0);
206 }
207 #endif
208
209 #ifdef GDK_WINDOWING_WAYLAND
210 static void
append_egl_extension_row(GtkInspectorGeneral * gen,EGLDisplay dpy,const gchar * ext)211 append_egl_extension_row (GtkInspectorGeneral *gen,
212 EGLDisplay dpy,
213 const gchar *ext)
214 {
215 add_check_row (gen, GTK_LIST_BOX (gen->priv->gl_box), ext, epoxy_has_egl_extension (dpy, ext), 0);
216 }
217
218 static EGLDisplay
wayland_get_display(struct wl_display * wl_display)219 wayland_get_display (struct wl_display *wl_display)
220 {
221 EGLDisplay dpy = NULL;
222
223 if (epoxy_has_egl_extension (NULL, "EGL_KHR_platform_base"))
224 {
225 PFNEGLGETPLATFORMDISPLAYPROC getPlatformDisplay =
226 (void *) eglGetProcAddress ("eglGetPlatformDisplay");
227
228 if (getPlatformDisplay)
229 dpy = getPlatformDisplay (EGL_PLATFORM_WAYLAND_EXT,
230 wl_display,
231 NULL);
232 if (dpy)
233 return dpy;
234 }
235
236 if (epoxy_has_egl_extension (NULL, "EGL_EXT_platform_base"))
237 {
238 PFNEGLGETPLATFORMDISPLAYEXTPROC getPlatformDisplay =
239 (void *) eglGetProcAddress ("eglGetPlatformDisplayEXT");
240
241 if (getPlatformDisplay)
242 dpy = getPlatformDisplay (EGL_PLATFORM_WAYLAND_EXT,
243 wl_display,
244 NULL);
245 if (dpy)
246 return dpy;
247 }
248
249 return eglGetDisplay ((EGLNativeDisplayType)wl_display);
250 }
251 #endif
252
253
254 static void
init_gl(GtkInspectorGeneral * gen)255 init_gl (GtkInspectorGeneral *gen)
256 {
257 #ifdef GDK_WINDOWING_X11
258 if (GDK_IS_X11_DISPLAY (gdk_display_get_default ()))
259 {
260 GdkDisplay *display = gdk_display_get_default ();
261 Display *dpy = GDK_DISPLAY_XDISPLAY (display);
262 int error_base, event_base;
263 gchar *version;
264 if (!glXQueryExtension (dpy, &error_base, &event_base))
265 return;
266
267 version = g_strconcat ("GLX ", glXGetClientString (dpy, GLX_VERSION), NULL);
268 gtk_label_set_text (GTK_LABEL (gen->priv->gl_version), version);
269 g_free (version);
270 gtk_label_set_text (GTK_LABEL (gen->priv->gl_vendor), glXGetClientString (dpy, GLX_VENDOR));
271
272 append_glx_extension_row (gen, dpy, "GLX_ARB_create_context_profile");
273 append_glx_extension_row (gen, dpy, "GLX_SGI_swap_control");
274 append_glx_extension_row (gen, dpy, "GLX_EXT_texture_from_pixmap");
275 append_glx_extension_row (gen, dpy, "GLX_SGI_video_sync");
276 append_glx_extension_row (gen, dpy, "GLX_EXT_buffer_age");
277 append_glx_extension_row (gen, dpy, "GLX_OML_sync_control");
278 append_glx_extension_row (gen, dpy, "GLX_ARB_multisample");
279 append_glx_extension_row (gen, dpy, "GLX_EXT_visual_rating");
280 }
281 else
282 #endif
283 #ifdef GDK_WINDOWING_WAYLAND
284 if (GDK_IS_WAYLAND_DISPLAY (gdk_display_get_default ()))
285 {
286 GdkDisplay *display = gdk_display_get_default ();
287 EGLDisplay dpy;
288 EGLint major, minor;
289 gchar *version;
290
291 dpy = wayland_get_display (gdk_wayland_display_get_wl_display (display));
292
293 if (!eglInitialize (dpy, &major, &minor))
294 return;
295
296 version = g_strconcat ("EGL ", eglQueryString (dpy, EGL_VERSION), NULL);
297 gtk_label_set_text (GTK_LABEL (gen->priv->gl_version), version);
298 g_free (version);
299 gtk_label_set_text (GTK_LABEL (gen->priv->gl_vendor), eglQueryString (dpy, EGL_VENDOR));
300
301 append_egl_extension_row (gen, dpy, "EGL_KHR_create_context");
302 append_egl_extension_row (gen, dpy, "EGL_EXT_buffer_age");
303 append_egl_extension_row (gen, dpy, "EGL_EXT_swap_buffers_with_damage");
304 append_egl_extension_row (gen, dpy, "EGL_KHR_surfaceless_context");
305 }
306 else
307 #endif
308 {
309 gtk_label_set_text (GTK_LABEL (gen->priv->gl_version), C_("GL version", "None"));
310 gtk_label_set_text (GTK_LABEL (gen->priv->gl_vendor), C_("GL vendor", "None"));
311 }
312 }
313
314 static void
set_monospace_font(GtkWidget * w)315 set_monospace_font (GtkWidget *w)
316 {
317 PangoAttrList *attrs;
318
319 attrs = pango_attr_list_new ();
320 pango_attr_list_insert (attrs, pango_attr_fallback_new (FALSE));
321 pango_attr_list_insert (attrs, pango_attr_family_new ("Monospace"));
322 gtk_label_set_attributes (GTK_LABEL (w), attrs);
323 pango_attr_list_unref (attrs);
324 }
325
326 static void
set_path_label(GtkWidget * w,const gchar * var)327 set_path_label (GtkWidget *w,
328 const gchar *var)
329 {
330 const gchar *v;
331
332 v = g_getenv (var);
333 if (v != NULL)
334 {
335 set_monospace_font (w);
336 gtk_label_set_text (GTK_LABEL (w), v);
337 }
338 else
339 {
340 GtkWidget *r;
341 r = gtk_widget_get_ancestor (w, GTK_TYPE_LIST_BOX_ROW);
342 gtk_widget_hide (r);
343 }
344 }
345
346 static void
init_env(GtkInspectorGeneral * gen)347 init_env (GtkInspectorGeneral *gen)
348 {
349 set_monospace_font (gen->priv->prefix);
350 gtk_label_set_text (GTK_LABEL (gen->priv->prefix), _gtk_get_data_prefix ());
351 set_path_label (gen->priv->xdg_data_home, "XDG_DATA_HOME");
352 set_path_label (gen->priv->xdg_data_dirs, "XDG_DATA_DIRS");
353 set_path_label (gen->priv->gtk_path, "GTK_PATH");
354 set_path_label (gen->priv->gtk_exe_prefix, "GTK_EXE_PREFIX");
355 set_path_label (gen->priv->gtk_data_prefix, "GTK_DATA_PREFIX");
356 set_path_label (gen->priv->gsettings_schema_dir, "GSETTINGS_SCHEMA_DIR");
357 }
358
359 static const char *
translate_subpixel_layout(GdkSubpixelLayout subpixel)360 translate_subpixel_layout (GdkSubpixelLayout subpixel)
361 {
362 switch (subpixel)
363 {
364 case GDK_SUBPIXEL_LAYOUT_NONE: return "none";
365 case GDK_SUBPIXEL_LAYOUT_UNKNOWN: return "unknown";
366 case GDK_SUBPIXEL_LAYOUT_HORIZONTAL_RGB: return "horizontal rgb";
367 case GDK_SUBPIXEL_LAYOUT_HORIZONTAL_BGR: return "horizontal bgr";
368 case GDK_SUBPIXEL_LAYOUT_VERTICAL_RGB: return "vertical rgb";
369 case GDK_SUBPIXEL_LAYOUT_VERTICAL_BGR: return "vertical bgr";
370 default: g_assert_not_reached ();
371 }
372 }
373
374 static void
populate_display(GdkScreen * screen,GtkInspectorGeneral * gen)375 populate_display (GdkScreen *screen, GtkInspectorGeneral *gen)
376 {
377 gchar *name;
378 gint i;
379 GList *children, *l;
380 GtkWidget *child;
381 GdkDisplay *display;
382 int n_monitors;
383 GtkListBox *list;
384
385 list = GTK_LIST_BOX (gen->priv->display_box);
386 children = gtk_container_get_children (GTK_CONTAINER (list));
387 for (l = children; l; l = l->next)
388 {
389 child = l->data;
390 if (gtk_widget_is_ancestor (gen->priv->display_name, child) ||
391 gtk_widget_is_ancestor (gen->priv->display_rgba, child) ||
392 gtk_widget_is_ancestor (gen->priv->display_composited, child))
393 continue;
394
395 gtk_widget_destroy (child);
396 }
397 g_list_free (children);
398
399 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
400 name = gdk_screen_make_display_name (screen);
401 G_GNUC_END_IGNORE_DEPRECATIONS
402 gtk_label_set_label (GTK_LABEL (gen->priv->display_name), name);
403 g_free (name);
404
405 if (gdk_screen_get_rgba_visual (screen) != NULL)
406 gtk_widget_show (gen->priv->display_rgba);
407
408 if (gdk_screen_is_composited (screen))
409 gtk_widget_show (gen->priv->display_composited);
410
411 display = gdk_screen_get_display (screen);
412 n_monitors = gdk_display_get_n_monitors (display);
413 for (i = 0; i < n_monitors; i++)
414 {
415 gchar *name;
416 gchar *value;
417 GdkRectangle rect;
418 gint scale;
419 const char *manufacturer;
420 const char *model;
421 GdkMonitor *monitor;
422
423 monitor = gdk_display_get_monitor (display, i);
424
425 name = g_strdup_printf ("Monitor %d", i);
426 manufacturer = gdk_monitor_get_manufacturer (monitor);
427 model = gdk_monitor_get_model (monitor);
428 value = g_strdup_printf ("%s%s%s",
429 manufacturer ? manufacturer : "",
430 manufacturer || model ? " " : "",
431 model ? model : "");
432 add_label_row (gen, list, name, value, 0);
433 g_free (name);
434 g_free (value);
435
436 gdk_monitor_get_geometry (monitor, &rect);
437 scale = gdk_monitor_get_scale_factor (monitor);
438
439 value = g_strdup_printf ("%d × %d%s at %d, %d",
440 rect.width, rect.height,
441 scale == 2 ? " @ 2" : "",
442 rect.x, rect.y);
443 add_label_row (gen, list, "Geometry", value, 10);
444 g_free (value);
445
446 value = g_strdup_printf ("%d × %d mm²",
447 gdk_monitor_get_width_mm (monitor),
448 gdk_monitor_get_height_mm (monitor));
449 add_label_row (gen, list, "Size", value, 10);
450 g_free (value);
451
452 add_check_row (gen, list, "Primary", gdk_monitor_is_primary (monitor), 10);
453
454 if (gdk_monitor_get_refresh_rate (monitor) != 0)
455 value = g_strdup_printf ("%.2f Hz",
456 0.001 * gdk_monitor_get_refresh_rate (monitor));
457 else
458 value = g_strdup ("unknown");
459 add_label_row (gen, list, "Refresh rate", value, 10);
460 g_free (value);
461
462 value = g_strdup (translate_subpixel_layout (gdk_monitor_get_subpixel_layout (monitor)));
463 add_label_row (gen, list, "Subpixel layout", value, 10);
464 g_free (value);
465 }
466 }
467
468 static void
init_display(GtkInspectorGeneral * gen)469 init_display (GtkInspectorGeneral *gen)
470 {
471 GdkScreen *screen;
472
473 screen = gdk_screen_get_default ();
474
475 g_signal_connect (screen, "size-changed", G_CALLBACK (populate_display), gen);
476 g_signal_connect (screen, "composited-changed", G_CALLBACK (populate_display), gen);
477 g_signal_connect (screen, "monitors-changed", G_CALLBACK (populate_display), gen);
478
479 populate_display (screen, gen);
480 }
481
482 static void populate_seats (GtkInspectorGeneral *gen);
483
484 static void
add_device(GtkInspectorGeneral * gen,GdkDevice * device)485 add_device (GtkInspectorGeneral *gen,
486 GdkDevice *device)
487 {
488 const gchar *name, *value;
489 GString *str;
490 int i;
491 guint n_touches;
492 gchar *text;
493 GdkAxisFlags axes;
494 const char *axis_name[] = {
495 "Ignore",
496 "X",
497 "Y",
498 "Pressure",
499 "X Tilt",
500 "Y Tilt",
501 "Wheel",
502 "Distance",
503 "Rotation",
504 "Slider"
505 };
506 const char *source_name[] = {
507 "Mouse",
508 "Pen",
509 "Eraser",
510 "Cursor",
511 "Keyboard",
512 "Touchscreen",
513 "Touchpad",
514 "Trackpoint",
515 "Pad"
516 };
517
518 name = gdk_device_get_name (device);
519 value = source_name[gdk_device_get_source (device)];
520 add_label_row (gen, GTK_LIST_BOX (gen->priv->device_box), name, value, 10);
521
522 str = g_string_new ("");
523
524 axes = gdk_device_get_axes (device);
525 for (i = GDK_AXIS_X; i < GDK_AXIS_LAST; i++)
526 {
527 if ((axes & (1 << i)) != 0)
528 {
529 if (str->len > 0)
530 g_string_append (str, ", ");
531 g_string_append (str, axis_name[i]);
532 }
533 }
534
535 if (str->len > 0)
536 add_label_row (gen, GTK_LIST_BOX (gen->priv->device_box), "Axes", str->str, 20);
537
538 g_string_free (str, TRUE);
539
540 g_object_get (device, "num-touches", &n_touches, NULL);
541 if (n_touches > 0)
542 {
543 text = g_strdup_printf ("%d", n_touches);
544 add_label_row (gen, GTK_LIST_BOX (gen->priv->device_box), "Touches", text, 20);
545 g_free (text);
546 }
547 }
548
549 static char *
get_seat_capabilities(GdkSeat * seat)550 get_seat_capabilities (GdkSeat *seat)
551 {
552 struct {
553 GdkSeatCapabilities cap;
554 const char *name;
555 } caps[] = {
556 { GDK_SEAT_CAPABILITY_POINTER, "Pointer" },
557 { GDK_SEAT_CAPABILITY_TOUCH, "Touch" },
558 { GDK_SEAT_CAPABILITY_TABLET_STYLUS, "Tablet" },
559 { GDK_SEAT_CAPABILITY_KEYBOARD, "Keyboard" },
560 { 0, NULL }
561 };
562 GString *str;
563 GdkSeatCapabilities capabilities;
564 int i;
565
566 str = g_string_new ("");
567 capabilities = gdk_seat_get_capabilities (seat);
568 for (i = 0; caps[i].cap != 0; i++)
569 {
570 if (capabilities & caps[i].cap)
571 {
572 if (str->len > 0)
573 g_string_append (str, ", ");
574 g_string_append (str, caps[i].name);
575 }
576 }
577
578 return g_string_free (str, FALSE);
579 }
580
581 static void
add_seat(GtkInspectorGeneral * gen,GdkSeat * seat,int num)582 add_seat (GtkInspectorGeneral *gen,
583 GdkSeat *seat,
584 int num)
585 {
586 char *text;
587 char *caps;
588 GList *list, *l;
589
590 if (!g_object_get_data (G_OBJECT (seat), "inspector-connected"))
591 {
592 g_object_set_data (G_OBJECT (seat), "inspector-connected", GINT_TO_POINTER (1));
593 g_signal_connect_swapped (seat, "device-added", G_CALLBACK (populate_seats), gen);
594 g_signal_connect_swapped (seat, "device-removed", G_CALLBACK (populate_seats), gen);
595 }
596
597 text = g_strdup_printf ("Seat %d", num);
598 caps = get_seat_capabilities (seat);
599
600 add_label_row (gen, GTK_LIST_BOX (gen->priv->device_box), text, caps, 0);
601 g_free (text);
602 g_free (caps);
603
604 list = gdk_seat_get_slaves (seat, GDK_SEAT_CAPABILITY_ALL);
605
606 for (l = list; l; l = l->next)
607 add_device (gen, GDK_DEVICE (l->data));
608
609 g_list_free (list);
610 }
611
612 static void
populate_seats(GtkInspectorGeneral * gen)613 populate_seats (GtkInspectorGeneral *gen)
614 {
615 GdkDisplay *display = gdk_display_get_default ();
616 GList *list, *l;
617 int i;
618
619 list = gtk_container_get_children (GTK_CONTAINER (gen->priv->device_box));
620 for (l = list; l; l = l->next)
621 gtk_widget_destroy (GTK_WIDGET (l->data));
622 g_list_free (list);
623
624 list = gdk_display_list_seats (display);
625
626 for (l = list, i = 0; l; l = l->next, i++)
627 add_seat (gen, GDK_SEAT (l->data), i);
628
629 g_list_free (list);
630 }
631
632 static void
init_device(GtkInspectorGeneral * gen)633 init_device (GtkInspectorGeneral *gen)
634 {
635 GdkDisplay *display = gdk_display_get_default ();
636
637 g_signal_connect_swapped (display, "seat-added", G_CALLBACK (populate_seats), gen);
638 g_signal_connect_swapped (display, "seat-removed", G_CALLBACK (populate_seats), gen);
639
640 populate_seats (gen);
641 }
642
643 static void
gtk_inspector_general_init(GtkInspectorGeneral * gen)644 gtk_inspector_general_init (GtkInspectorGeneral *gen)
645 {
646 gen->priv = gtk_inspector_general_get_instance_private (gen);
647 gtk_widget_init_template (GTK_WIDGET (gen));
648 init_version (gen);
649 init_env (gen);
650 init_display (gen);
651 init_gl (gen);
652 init_device (gen);
653 }
654
655 static gboolean
keynav_failed(GtkWidget * widget,GtkDirectionType direction,GtkInspectorGeneral * gen)656 keynav_failed (GtkWidget *widget, GtkDirectionType direction, GtkInspectorGeneral *gen)
657 {
658 GtkWidget *next;
659 gdouble value, lower, upper, page;
660
661 if (direction == GTK_DIR_DOWN && widget == gen->priv->version_box)
662 next = gen->priv->env_box;
663 else if (direction == GTK_DIR_DOWN && widget == gen->priv->env_box)
664 next = gen->priv->display_box;
665 else if (direction == GTK_DIR_DOWN && widget == gen->priv->display_box)
666 next = gen->priv->gl_box;
667 else if (direction == GTK_DIR_DOWN && widget == gen->priv->gl_box)
668 next = gen->priv->device_box;
669 else if (direction == GTK_DIR_UP && widget == gen->priv->device_box)
670 next = gen->priv->gl_box;
671 else if (direction == GTK_DIR_UP && widget == gen->priv->gl_box)
672 next = gen->priv->display_box;
673 else if (direction == GTK_DIR_UP && widget == gen->priv->display_box)
674 next = gen->priv->env_box;
675 else if (direction == GTK_DIR_UP && widget == gen->priv->env_box)
676 next = gen->priv->version_box;
677 else
678 next = NULL;
679
680 if (next)
681 {
682 gtk_widget_child_focus (next, direction);
683 return TRUE;
684 }
685
686 value = gtk_adjustment_get_value (gen->priv->focus_adjustment);
687 lower = gtk_adjustment_get_lower (gen->priv->focus_adjustment);
688 upper = gtk_adjustment_get_upper (gen->priv->focus_adjustment);
689 page = gtk_adjustment_get_page_size (gen->priv->focus_adjustment);
690
691 if (direction == GTK_DIR_UP && value > lower)
692 {
693 gtk_adjustment_set_value (gen->priv->focus_adjustment, lower);
694 return TRUE;
695 }
696 else if (direction == GTK_DIR_DOWN && value < upper - page)
697 {
698 gtk_adjustment_set_value (gen->priv->focus_adjustment, upper - page);
699 return TRUE;
700 }
701
702 return FALSE;
703 }
704
705 static void
gtk_inspector_general_constructed(GObject * object)706 gtk_inspector_general_constructed (GObject *object)
707 {
708 GtkInspectorGeneral *gen = GTK_INSPECTOR_GENERAL (object);
709
710 G_OBJECT_CLASS (gtk_inspector_general_parent_class)->constructed (object);
711
712 gen->priv->focus_adjustment = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (gen));
713 gtk_container_set_focus_vadjustment (GTK_CONTAINER (gtk_bin_get_child (GTK_BIN (gen))),
714 gen->priv->focus_adjustment);
715
716 g_signal_connect (gen->priv->version_box, "keynav-failed", G_CALLBACK (keynav_failed), gen);
717 g_signal_connect (gen->priv->env_box, "keynav-failed", G_CALLBACK (keynav_failed), gen);
718 g_signal_connect (gen->priv->display_box, "keynav-failed", G_CALLBACK (keynav_failed), gen);
719 g_signal_connect (gen->priv->gl_box, "keynav-failed", G_CALLBACK (keynav_failed), gen);
720 g_signal_connect (gen->priv->device_box, "keynav-failed", G_CALLBACK (keynav_failed), gen);
721 }
722
723 static void
gtk_inspector_general_class_init(GtkInspectorGeneralClass * klass)724 gtk_inspector_general_class_init (GtkInspectorGeneralClass *klass)
725 {
726 GObjectClass *object_class = G_OBJECT_CLASS (klass);
727 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
728
729 object_class->constructed = gtk_inspector_general_constructed;
730
731 gtk_widget_class_set_template_from_resource (widget_class, "/org/gtk/libgtk/inspector/general.ui");
732 gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorGeneral, version_box);
733 gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorGeneral, env_box);
734 gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorGeneral, display_box);
735 gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorGeneral, gl_box);
736 gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorGeneral, gtk_version);
737 gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorGeneral, gdk_backend);
738 gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorGeneral, gl_version);
739 gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorGeneral, gl_vendor);
740 gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorGeneral, prefix);
741 gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorGeneral, xdg_data_home);
742 gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorGeneral, xdg_data_dirs);
743 gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorGeneral, gtk_path);
744 gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorGeneral, gtk_exe_prefix);
745 gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorGeneral, gtk_data_prefix);
746 gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorGeneral, gsettings_schema_dir);
747 gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorGeneral, labels);
748 gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorGeneral, display_name);
749 gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorGeneral, display_composited);
750 gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorGeneral, display_rgba);
751 gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorGeneral, device_box);
752 }
753
754 // vim: set et sw=2 ts=2:
755