/*
* Copyright ( c ) 2014 Red Hat , Inc .
*
* This library is free software ; you can redistribute it and / or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation ; either
* version 2 of the License , or ( at your option ) any later version .
*
* This library is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library . If not , see < http : //www.gnu.org/licenses/>.
*/
#include "config.h"
#include <glib/gi18n-lib.h>
#include "general.h"
#include "window.h"
#include "gtkdebug.h"
#include "gtklabel.h"
#include "gtkscale.h"
#include "gtkswitch.h"
#include "gtklistbox.h"
#include "gtkprivate.h"
#include "gtksizegroup.h"
#include "gtkimage.h"
#include "gtkadjustment.h"
#include "gtkbox.h"
#include "gtkbinlayout.h"
#include "gtkmediafileprivate.h"
#include "gtkimmoduleprivate.h"
#include "gtkstringpairprivate.h"
#include "gdk/gdkdebugprivate.h"
#include "gdk/gdkdisplayprivate.h"
#include "gdk/gdkmonitorprivate.h"
#include "gdk/gdkglcontextprivate.h"
#include "gdk/gdkvulkancontextprivate.h"
#include "profile_conf.h"
#include <epoxy/gl.h>
#ifdef GDK_WINDOWING_X11
#include "x11/gdkx.h"
#include <epoxy/glx.h>
#include <epoxy/egl.h>
#endif
#ifdef GDK_WINDOWING_WIN32
#include "win32/gdkwin32.h"
#include "gdkglcontextprivate.h"
#include <epoxy/wgl.h>
#ifdef GDK_WIN32_ENABLE_EGL
#include <epoxy/egl.h>
#endif
#endif
#ifdef GDK_WINDOWING_MACOS
#include "macos/gdkmacos.h"
#endif
#ifdef GDK_WINDOWING_WAYLAND
#include "wayland/gdkwayland.h"
#include <epoxy/egl.h>
#include <xkbcommon/xkbcommon.h>
#include "wayland/gdkdisplay-wayland.h"
#include "wayland/gdkwaylandcolor-private.h"
#include "gtk/gtkimcontextwaylandprivate.h"
#endif
#ifdef GDK_WINDOWING_BROADWAY
#include "broadway/gdkbroadway.h"
#endif
#ifdef GDK_RENDERING_VULKAN
#include <vulkan/vulkan.h>
#endif
static void gtk_inspector_general_clip (GtkButton *button, GtkInspectorGeneral *gen);
struct _GtkInspectorGeneral
{
GtkWidget parent;
GtkWidget *swin;
GtkWidget *box;
GtkWidget *version_box;
GtkWidget *env_box;
GtkWidget *display_box;
GtkWidget *display_extensions_row;
GtkWidget *display_extensions_box;
GtkWidget *monitor_box;
GtkWidget *gl_box;
GtkWidget *gl_features_row;
GtkWidget *gl_features_box;
GtkWidget *gl_extensions_row;
GtkStringList *gl_extensions_list;
GtkWidget *egl_extensions_row;
GtkWidget *egl_extensions_row_name;
GtkStringList *egl_extensions_list;
GtkWidget *vulkan_box;
GtkWidget *vulkan_features_row;
GtkWidget *vulkan_features_box;
GtkWidget *vulkan_extensions_row;
GtkStringList *vulkan_extensions_list;
GtkWidget *vulkan_layers_row;
GtkStringList *vulkan_layers_list;
GtkWidget *device_box;
GtkWidget *os_info;
GtkWidget *gtk_version;
GtkWidget *gdk_backend;
GtkWidget *gsk_renderer;
GtkWidget *pango_fontmap;
GtkWidget *media_backend;
GtkWidget *im_module;
GtkWidget *a11y_backend;
GtkWidget *gl_backend_version;
GtkWidget *gl_backend_version_row;
GtkWidget *gl_backend_vendor;
GtkWidget *gl_backend_vendor_row;
GtkWidget *gl_error;
GtkWidget *gl_error_row;
GtkWidget *gl_version;
GtkWidget *gl_version_row;
GtkWidget *gl_vendor;
GtkWidget *gl_vendor_row;
GtkWidget *gl_renderer;
GtkWidget *gl_renderer_row;
GtkWidget *gl_full_version;
GtkWidget *gl_full_version_row;
GtkWidget *glsl_version;
GtkWidget *glsl_version_row;
GtkWidget *vk_device;
GtkWidget *vk_api_version;
GtkWidget *vk_api_version_row;
GtkWidget *vk_driver_version;
GtkWidget *vk_driver_version_row;
GtkWidget *vk_error;
GtkWidget *vk_error_row;
GtkWidget *app_id_box;
GtkWidget *app_id;
GtkWidget *resource_path;
GtkWidget *prefix;
GtkWidget *environment_row;
GListStore *environment_list;
GtkWidget *display_name;
GtkWidget *display_rgba;
GtkWidget *display_composited;
GtkWidget *overlay;
GdkDisplay *display;
};
typedef struct _GtkInspectorGeneralClass
{
GtkWidgetClass parent_class;
} GtkInspectorGeneralClass;
G_DEFINE_TYPE (GtkInspectorGeneral, gtk_inspector_general, GTK_TYPE_WIDGET)
/* Note that all the information collection functions come in two variants:
* init_foo ( ) and dump_foo ( ) . The former updates the widgets of the inspector
* page , the latter creates a markdown dump , to copy - pasted into a gitlab
* issue .
*
* Please keep the two in sync when making changes .
*/
/* {{{ Utilities */
static G_GNUC_UNUSED void
add_check_row (GtkInspectorGeneral *gen,
GtkListBox *list,
const char *name,
gboolean value,
int indent)
{
GtkWidget *row, *box, *label, *check;
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 40 );
g_object_set (box, "margin-start" , indent, NULL);
label = gtk_label_new (name);
gtk_widget_set_halign (label, GTK_ALIGN_START);
gtk_widget_set_valign (label, GTK_ALIGN_BASELINE_FILL);
gtk_label_set_xalign (GTK_LABEL (label), 0 .0 );
gtk_widget_set_hexpand (label, TRUE );
gtk_box_append (GTK_BOX (box), label);
check = gtk_image_new_from_icon_name ("object-select-symbolic" );
gtk_widget_set_halign (check, GTK_ALIGN_END);
gtk_widget_set_valign (check, GTK_ALIGN_BASELINE_FILL);
gtk_widget_set_opacity (check, value ? 1 .0 : 0 .0 );
gtk_box_append (GTK_BOX (box), check);
row = gtk_list_box_row_new ();
gtk_list_box_row_set_child (GTK_LIST_BOX_ROW (row), box);
gtk_list_box_row_set_activatable (GTK_LIST_BOX_ROW (row), FALSE );
gtk_widget_set_hexpand (box, FALSE );
gtk_list_box_insert (list, row, -1 );
}
static GtkWidget *
add_label_row (GtkInspectorGeneral *gen,
GtkListBox *list,
const char *name,
const char *value,
int indent)
{
GtkWidget *box;
GtkWidget *label;
GtkWidget *row;
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 40 );
g_object_set (box, "margin-start" , indent, NULL);
label = gtk_label_new (name);
gtk_widget_set_halign (label, GTK_ALIGN_START);
gtk_widget_set_valign (label, GTK_ALIGN_BASELINE_FILL);
gtk_label_set_xalign (GTK_LABEL (label), 0 .0 );
gtk_widget_set_hexpand (label, TRUE );
gtk_box_append (GTK_BOX (box), label);
label = gtk_label_new (value);
gtk_label_set_selectable (GTK_LABEL (label), TRUE );
gtk_widget_set_halign (label, GTK_ALIGN_END);
gtk_widget_set_valign (label, GTK_ALIGN_BASELINE_FILL);
gtk_label_set_xalign (GTK_LABEL (label), 1 .0 );
gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_END);
gtk_label_set_width_chars (GTK_LABEL (label), 25 );
gtk_box_append (GTK_BOX (box), label);
row = gtk_list_box_row_new ();
gtk_list_box_row_set_child (GTK_LIST_BOX_ROW (row), box);
gtk_list_box_row_set_activatable (GTK_LIST_BOX_ROW (row), FALSE );
gtk_widget_set_hexpand (box, FALSE );
gtk_list_box_insert (GTK_LIST_BOX (list), row, -1 );
return label;
}
static void
set_monospace_font (GtkWidget *w)
{
PangoAttrList *attrs;
attrs = pango_attr_list_new ();
pango_attr_list_insert (attrs, pango_attr_fallback_new (FALSE ));
pango_attr_list_insert (attrs, pango_attr_family_new ("Monospace" ));
gtk_label_set_attributes (GTK_LABEL (w), attrs);
pango_attr_list_unref (attrs);
}
/* }}} */
/* {{{ OS Info */
static void
init_os_info (GtkInspectorGeneral *gen)
{
char *os_info = g_get_os_info (G_OS_INFO_KEY_PRETTY_NAME);
gtk_label_set_text (GTK_LABEL (gen->os_info), os_info);
g_free (os_info);
}
static void
dump_os_info (GdkDisplay *display,
GString *string)
{
char *os_info = g_get_os_info (G_OS_INFO_KEY_PRETTY_NAME);
g_string_append_printf (string, "| Operating System | %s |\n" , os_info);
g_free (os_info);
}
/* }}} */
/* {{{ Version */
static const char *
get_display_kind (GdkDisplay *display)
{
#ifdef GDK_WINDOWING_X11
if (GDK_IS_X11_DISPLAY (display))
return "X11" ;
else
#endif
#ifdef GDK_WINDOWING_WAYLAND
if (GDK_IS_WAYLAND_DISPLAY (display))
return "Wayland" ;
else
#endif
#ifdef GDK_WINDOWING_BROADWAY
if (GDK_IS_BROADWAY_DISPLAY (display))
return "Broadway" ;
else
#endif
#ifdef GDK_WINDOWING_WIN32
if (GDK_IS_WIN32_DISPLAY (display))
return "Windows" ;
else
#endif
#ifdef GDK_WINDOWING_MACOS
if (GDK_IS_MACOS_DISPLAY (display))
return "MacOS" ;
else
#endif
return "Unknown" ;
}
static const char *
get_renderer_kind (GdkDisplay *display)
{
GdkSurface *surface;
GskRenderer *gsk_renderer;
const char *renderer;
surface = gdk_surface_new_toplevel (display);
gsk_renderer = gsk_renderer_new_for_surface (surface);
if (strcmp (G_OBJECT_TYPE_NAME (gsk_renderer), "GskVulkanRenderer" ) == 0 )
renderer = "Vulkan" ;
else if (strcmp (G_OBJECT_TYPE_NAME (gsk_renderer), "GskGLRenderer" ) == 0 )
renderer = "GL" ;
else if (strcmp (G_OBJECT_TYPE_NAME (gsk_renderer), "GskCairoRenderer" ) == 0 )
renderer = "Cairo" ;
else if (strcmp (G_OBJECT_TYPE_NAME (gsk_renderer), "GskNglRenderer" ) == 0 )
renderer = "GL (new)" ;
else
renderer = "Unknown" ;
gsk_renderer_unrealize (gsk_renderer);
g_object_unref (gsk_renderer);
gdk_surface_destroy (surface);
return renderer;
}
static char *
get_version_string (void )
{
if (g_strcmp0 (PROFILE, "devel" ) == 0 )
return g_strdup_printf ("%s-%s" , GTK_VERSION, VCS_TAG);
else
return g_strdup (GTK_VERSION);
}
static void
init_version (GtkInspectorGeneral *gen)
{
char *version;
version = get_version_string ();
gtk_label_set_text (GTK_LABEL (gen->gtk_version), version);
g_free (version);
gtk_label_set_text (GTK_LABEL (gen->gdk_backend), get_display_kind (gen->display));
gtk_label_set_text (GTK_LABEL (gen->gsk_renderer), get_renderer_kind (gen->display));
}
static void
dump_version (GdkDisplay *display,
GString *string)
{
char *version;
version = get_version_string ();
g_string_append_printf (string, "| GTK Version | %s |\n" , version);
g_free (version);
g_string_append_printf (string, "| GDK Backend | %s |\n" , get_display_kind (display));
g_string_append_printf (string, "| GSK Renderer | %s |\n" , get_renderer_kind (display));
}
/* }}} */
/* {{{ Pango */
static const char *
get_fontmap_kind (void )
{
PangoFontMap *fontmap;
const char *type;
fontmap = pango_cairo_font_map_get_default ();
type = G_OBJECT_TYPE_NAME (fontmap);
if (strcmp (type, "PangoCairoFcFontMap" ) == 0 )
return "fontconfig" ;
else if (strcmp (type, "PangoCairoCoreTextFontMap" ) == 0 )
return "coretext" ;
else if (strcmp (type, "PangoCairoWin32FontMap" ) == 0 )
return "win32" ;
else
return type;
}
static void
init_pango (GtkInspectorGeneral *gen)
{
gtk_label_set_label (GTK_LABEL (gen->pango_fontmap), get_fontmap_kind ());
}
static void
dump_pango (GdkDisplay *display,
GString *string)
{
g_string_append_printf (string, "| Pango Fontmap | %s |\n" , get_fontmap_kind ());
}
/* }}} */
/* {{{ Media */
static char *
get_media_backend_description (void )
{
GIOExtension *e;
const char *name;
e = gtk_media_file_get_extension ();
name = g_io_extension_get_name (e);
#ifdef HAVE_GSTREAMER
if (g_str_equal (name, "gstreamer" ))
{
return gst_version_string ();
}
else
#endif
{
return g_strdup (name);
}
}
static void
init_media (GtkInspectorGeneral *gen)
{
char *backend = get_media_backend_description ();
gtk_label_set_label (GTK_LABEL (gen->media_backend), backend);
g_free (backend);
}
static void
dump_media (GdkDisplay *display,
GString *string)
{
char *backend = get_media_backend_description ();
g_string_append_printf (string, "| Media Backend | %s |\n" , backend);
g_free (backend);
}
/* }}} */
/* {{{ Input Method */
static void
im_module_changed (GtkSettings *settings,
GParamSpec *pspec,
GtkInspectorGeneral *gen)
{
if (!gen->display)
return ;
gtk_label_set_label (GTK_LABEL (gen->im_module),
_gtk_im_module_get_default_context_id (gen->display));
}
static const char *
get_im_module_kind (GdkDisplay *display)
{
return _gtk_im_module_get_default_context_id (display);
}
static void
init_im_module (GtkInspectorGeneral *gen)
{
GtkSettings *settings = gtk_settings_get_for_display (gen->display);
gtk_label_set_label (GTK_LABEL (gen->im_module), get_im_module_kind (gen->display));
if (g_getenv ("GTK_IM_MODULE" ) != NULL)
{
/* This can't update if GTK_IM_MODULE envvar is set */
gtk_widget_set_tooltip_text (gen->im_module,
_("IM Context is hardcoded by GTK_IM_MODULE" ));
gtk_widget_set_sensitive (gen->im_module, FALSE );
return ;
}
g_signal_connect_object (settings,
"notify::gtk-im-module" ,
G_CALLBACK (im_module_changed),
gen, 0 );
}
static void
dump_im_module (GdkDisplay *display,
GString *string)
{
g_string_append_printf (string, "| Input Method | %s |\n" , get_im_module_kind (display));
}
/* }}} */
/* {{{ Accessibility */
static const char *
get_a11y_backend (GdkDisplay *display)
{
GtkWidget *widget;
GtkATContext *ctx;
const char *backend;
widget = gtk_label_new ("" );
g_object_ref_sink (widget);
ctx = gtk_at_context_create (GTK_ACCESSIBLE_ROLE_LABEL, GTK_ACCESSIBLE (widget), display);
if (ctx == NULL)
backend = "none" ;
else if (strcmp (G_OBJECT_TYPE_NAME (ctx), "GtkAtSpiContext" ) == 0 )
backend = "atspi" ;
else if (strcmp (G_OBJECT_TYPE_NAME (ctx), "GtkAccessKitContext" ) == 0 )
backend = "accesskit" ;
else if (strcmp (G_OBJECT_TYPE_NAME (ctx), "GtkTestATContext" ) == 0 )
backend = "test" ;
else
backend = "unknown" ;
g_clear_object (&ctx);
g_clear_object (&widget);
return backend;
}
static void
init_a11y_backend (GtkInspectorGeneral *gen)
{
gtk_label_set_label (GTK_LABEL (gen->a11y_backend), get_a11y_backend (gen->display));
}
static void
dump_a11y_backend (GdkDisplay *display,
GString *string)
{
g_string_append_printf (string, "| Accessibility backend | %s |\n" , get_a11y_backend (display));
}
/* }}} */
/* {{{ Application data */
static void
init_app_id (GtkInspectorGeneral *gen)
{
GApplication *app;
app = g_application_get_default ();
if (!app)
{
gtk_widget_set_visible (gen->app_id_box, FALSE );
return ;
}
gtk_label_set_text (GTK_LABEL (gen->app_id),
g_application_get_application_id (app));
gtk_label_set_text (GTK_LABEL (gen->resource_path),
g_application_get_resource_base_path (app));
}
static void
dump_app_id (GdkDisplay *display,
GString *string)
{
GApplication *app;
app = g_application_get_default ();
if (!app)
return ;
g_string_append_printf (string, "| Application ID | %s |\n" , g_application_get_application_id (app));
g_string_append_printf (string, "| Resource Path | %s |\n" , g_application_get_resource_base_path (app));
}
/* }}} */
/* {{{ GL */
static void
add_gl_features (GtkInspectorGeneral *gen)
{
GdkGLContext *context;
context = gdk_display_get_gl_context (gen->display);
for (int i = 0 ; i < GDK_GL_N_FEATURES; i++)
{
add_check_row (gen, GTK_LIST_BOX (gen->gl_features_box),
gdk_gl_feature_keys[i].key,
gdk_gl_context_has_feature (context, gdk_gl_feature_keys[i].value),
0 );
}
}
/* unused on some setup, like Mac */
static void G_GNUC_UNUSED
append_extensions (GtkStringList *list,
const char *extensions)
{
char **items;
gsize i;
if (extensions == NULL)
return ;
items = g_strsplit (extensions, " " , -1 );
for (i = 0 ; items[i]; i++)
{
if (items[i] == NULL || items[i][0 ] == 0 )
continue ;
gtk_string_list_append (list, items[i]);
}
g_strfreev (items);
}
#if defined (GDK_WINDOWING_X11) || defined (GDK_WINDOWING_WAYLAND) || (defined (GDK_WINDOWING_WIN32) && defined (GDK_WIN32_ENABLE_EGL))
static EGLDisplay
get_egl_display (GdkDisplay *display)
{
#ifdef GDK_WINDOWING_WAYLAND
if (GDK_IS_WAYLAND_DISPLAY (display))
return gdk_wayland_display_get_egl_display (display);
else
#endif
#ifdef GDK_WINDOWING_X11
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
if (GDK_IS_X11_DISPLAY (display))
return gdk_x11_display_get_egl_display (display);
else
G_GNUC_END_IGNORE_DEPRECATIONS
#endif
#ifdef GDK_WINDOWING_WIN32
if (GDK_IS_WIN32_DISPLAY (display))
return gdk_win32_display_get_egl_display (display);
else
#endif
return NULL;
}
#endif
static void
init_gl (GtkInspectorGeneral *gen)
{
GdkGLContext *context;
GError *error = NULL;
int major, minor;
int num_extensions, i;
char *s;
if (!gdk_display_prepare_gl (gen->display, &error))
{
gtk_label_set_text (GTK_LABEL (gen->gl_renderer), C_("GL renderer" , "None" ));
gtk_widget_set_visible (gen->gl_error_row, TRUE );
gtk_widget_set_visible (gen->gl_version_row, FALSE );
gtk_widget_set_visible (gen->gl_backend_version_row, FALSE );
gtk_widget_set_visible (gen->gl_backend_vendor_row, FALSE );
gtk_widget_set_visible (gen->gl_vendor_row, FALSE );
gtk_widget_set_visible (gen->gl_full_version_row, FALSE );
gtk_widget_set_visible (gen->glsl_version_row, FALSE );
gtk_widget_set_visible (gen->gl_features_row, FALSE );
gtk_widget_set_visible (gen->gl_extensions_row, FALSE );
gtk_widget_set_visible (gen->egl_extensions_row, FALSE );
gtk_label_set_text (GTK_LABEL (gen->gl_error), error->message);
g_error_free (error);
return ;
}
gdk_gl_context_make_current (gdk_display_get_gl_context (gen->display));
glGetIntegerv (GL_NUM_EXTENSIONS, &num_extensions);
for (i = 0 ; i < num_extensions; i++)
{
const char *gl_ext = (const char *) glGetStringi (GL_EXTENSIONS, i);
if (!gl_ext)
break ;
gtk_string_list_append (GTK_STRING_LIST (gen->gl_extensions_list), gl_ext);
}
#if defined (GDK_WINDOWING_X11) || defined (GDK_WINDOWING_WAYLAND) || (defined (GDK_WINDOWING_WIN32) && defined (GDK_WIN32_ENABLE_EGL))
EGLDisplay egl_display = get_egl_display (gen->display);
if (egl_display)
{
char *version;
version = g_strconcat ("EGL " , eglQueryString (egl_display, EGL_VERSION), NULL);
gtk_label_set_text (GTK_LABEL (gen->gl_backend_version), version);
g_free (version);
gtk_label_set_text (GTK_LABEL (gen->gl_backend_vendor), eglQueryString (egl_display, EGL_VENDOR));
gtk_label_set_text (GTK_LABEL (gen->egl_extensions_row_name), _("EGL extensions" ));
append_extensions (gen->egl_extensions_list, eglQueryString (egl_display, EGL_EXTENSIONS));
}
else
#endif
#ifdef GDK_WINDOWING_X11
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
if (GDK_IS_X11_DISPLAY (gen->display))
{
Display *dpy = GDK_DISPLAY_XDISPLAY (gen->display);
int error_base, event_base, screen;
char *version;
if (!glXQueryExtension (dpy, &error_base, &event_base))
return ;
version = g_strconcat ("GLX " , glXGetClientString (dpy, GLX_VERSION), NULL);
gtk_label_set_text (GTK_LABEL (gen->gl_backend_version), version);
g_free (version);
gtk_label_set_text (GTK_LABEL (gen->gl_backend_vendor), glXGetClientString (dpy, GLX_VENDOR));
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
screen = XScreenNumberOfScreen (gdk_x11_display_get_xscreen (gen->display));
G_GNUC_END_IGNORE_DEPRECATIONS
gtk_label_set_text (GTK_LABEL (gen->egl_extensions_row_name), _("GLX extensions" ));
append_extensions (gen->egl_extensions_list, glXQueryExtensionsString (dpy, screen));
}
else
G_GNUC_END_IGNORE_DEPRECATIONS
#endif
#ifdef GDK_WINDOWING_WIN32
if (GDK_IS_WIN32_DISPLAY (gen->display) &&
gdk_gl_backend_can_be_used (GDK_GL_WGL, NULL))
{
PFNWGLGETEXTENSIONSSTRINGARBPROC my_wglGetExtensionsStringARB;
gtk_label_set_text (GTK_LABEL (gen->gl_backend_vendor), _("Microsoft WGL" ));
gtk_widget_set_visible (gen->gl_backend_version, FALSE );
my_wglGetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC) wglGetProcAddress("wglGetExtensionsStringARB" );
if (my_wglGetExtensionsStringARB)
{
gtk_label_set_text (GTK_LABEL (gen->egl_extensions_row_name), _("WGL extensions" ));
append_extensions (gen->egl_extensions_list, my_wglGetExtensionsStringARB (wglGetCurrentDC ()));
}
else
{
gtk_label_set_text (GTK_LABEL (gen->egl_extensions_row_name), _("WGL extensions: none" ));
}
}
else
#endif
{
gtk_label_set_text (GTK_LABEL (gen->gl_backend_version), C_("GL version" , "Unknown" ));
gtk_widget_set_visible (gen->egl_extensions_row, FALSE );
}
context = gdk_display_get_gl_context (gen->display);
gdk_gl_context_make_current (context);
gdk_gl_context_get_version (context, &major, &minor);
s = g_strdup_printf ("%s %u.%u" ,
gdk_gl_context_get_use_es (context) ? "GLES " : "OpenGL " ,
major, minor);
gtk_label_set_text (GTK_LABEL (gen->gl_version), s);
g_free (s);
gtk_label_set_text (GTK_LABEL (gen->gl_vendor), (const char *) glGetString (GL_VENDOR));
gtk_label_set_text (GTK_LABEL (gen->gl_renderer), (const char *) glGetString (GL_RENDERER));
gtk_label_set_text (GTK_LABEL (gen->gl_full_version), (const char *) glGetString (GL_VERSION));
gtk_label_set_text (GTK_LABEL (gen->glsl_version), (const char *) glGetString (GL_SHADING_LANGUAGE_VERSION));
add_gl_features (gen);
}
static void
dump_gl (GdkDisplay *display,
GString *string)
{
GdkGLContext *context;
GError *error = NULL;
int major, minor;
int num_extensions;
char *s;
GString *ext;
if (!gdk_display_prepare_gl (display, &error))
{
g_string_append (string, "| GL Renderer | None |\n" );
g_string_append_printf (string, "| | %s |\n" , error->message);
g_error_free (error);
return ;
}
gdk_gl_context_make_current (gdk_display_get_gl_context (display));
ext = g_string_new ("" );
#if defined (GDK_WINDOWING_X11) || defined (GDK_WINDOWING_WAYLAND) || (defined (GDK_WINDOWING_WIN32) && defined (GDK_WIN32_ENABLE_EGL))
EGLDisplay egl_display = get_egl_display (display);
if (egl_display)
{
char *version;
guint count;
char *prefix;
version = g_strconcat ("EGL " , eglQueryString (egl_display, EGL_VERSION), NULL);
g_string_append_printf (string, "| GL Backend Version | %s |\n" , version);
g_free (version);
g_string_append_printf (string, "| GL Backend Vendor | %s |\n" , eglQueryString (egl_display, EGL_VENDOR));
g_string_assign (ext, eglQueryString (egl_display, EGL_EXTENSIONS));
count = g_string_replace (ext, " " , "<br>" , 0 );
prefix = g_strdup_printf ("| EGL Extensions | <details><summary>%u Extensions</summary>" , count + 1 );
g_string_prepend (ext, prefix);
g_string_append (ext, "</details> |\n" );
g_free (prefix);
}
else
#endif
#ifdef GDK_WINDOWING_X11
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
if (GDK_IS_X11_DISPLAY (display))
{
Display *dpy = GDK_DISPLAY_XDISPLAY (display);
int error_base, event_base, screen;
char *version;
guint count;
char *prefix;
if (!glXQueryExtension (dpy, &error_base, &event_base))
return ;
version = g_strconcat ("GLX " , glXGetClientString (dpy, GLX_VERSION), NULL);
g_string_append_printf (string, "| GL Backend Version | %s |\n" , version);
g_free (version);
g_string_append_printf (string, "| GL Backend Vendor | %s |\n" , glXGetClientString (dpy, GLX_VENDOR));
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
screen = XScreenNumberOfScreen (gdk_x11_display_get_xscreen (display));
G_GNUC_END_IGNORE_DEPRECATIONS
g_string_assign (ext, glXQueryExtensionsString (dpy, screen));
count = g_string_replace (ext, " " , "<br>" , 0 );
prefix = g_strdup_printf ("| GLX Extensions | <details><summary>%u Extensions</summary>" , count + 1 );
g_string_prepend (ext, prefix);
g_string_append (ext, "</details> |\n" );
g_free (prefix);
}
else
G_GNUC_END_IGNORE_DEPRECATIONS
#endif
#ifdef GDK_WINDOWING_WIN32
if (GDK_IS_WIN32_DISPLAY (display) &&
gdk_gl_backend_can_be_used (GDK_GL_WGL, NULL))
{
PFNWGLGETEXTENSIONSSTRINGARBPROC my_wglGetExtensionsStringARB;
g_string_append (string, "| GL Backend Vendor | Microsoft WGL |\n" );
my_wglGetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC) wglGetProcAddress("wglGetExtensionsStringARB" );
if (my_wglGetExtensionsStringARB)
{
guint count;
char *prefix;
g_string_assign (ext, my_wglGetExtensionsStringARB (wglGetCurrentDC ()));
count = g_string_replace (ext, " " , "<br>" , 0 );
prefix = g_strdup_printf ("| WGL Extensions | <details><summary>%u Extensions</summary>" , count + 1 );
g_string_prepend (ext, prefix);
g_string_append (ext, "</details> |\n" );
g_free (prefix);
}
else
{
g_string_append (ext, "| WGL Extensions | None |\n" );
}
}
else
#endif
{
g_string_append (string, "| GL Backend Version | Unknown |\n" );
}
context = gdk_display_get_gl_context (display);
gdk_gl_context_make_current (context);
gdk_gl_context_get_version (context, &major, &minor);
s = g_strdup_printf ("%s %u.%u" ,
gdk_gl_context_get_use_es (context) ? "GLES " : "OpenGL " ,
major, minor);
g_string_append_printf (string, "| GL Version | %s |\n" , s);
g_free (s);
g_string_append_printf (string, "| GL Vendor | %s |\n" , (const char *) glGetString (GL_VENDOR));
g_string_append_printf (string, "| GL Renderer | %s |\n" , (const char *) glGetString (GL_RENDERER));
g_string_append_printf (string, "| GL Full Version | %s |\n" , (const char *) glGetString (GL_VERSION));
g_string_append_printf (string, "| GLSL Version | %s |\n" , (const char *) glGetString (GL_SHADING_LANGUAGE_VERSION));
glGetIntegerv (GL_NUM_EXTENSIONS, &num_extensions);
g_string_append_printf (string, "| GL Extensions | <details><summary>%d Extensions</summary>" , num_extensions);
for (int i = 0 ; i < num_extensions; i++)
{
const char *gl_ext = (const char *) glGetStringi (GL_EXTENSIONS, i);
if (gl_ext)
g_string_append_printf (string, "%s%s" , i > 0 ? "<br>" : "" , gl_ext);
}
g_string_append (string, "</details> |\n" );
g_string_append (string, ext->str);
g_string_free (ext, TRUE );
g_string_append (string, "| Features | " );
for (int i = 0 ; i < GDK_GL_N_FEATURES; i++)
{
if (gdk_gl_context_has_feature (context, gdk_gl_feature_keys[i].value))
g_string_append_printf (string, "%s%s" , i > 0 ? "<br>" : "" , gdk_gl_feature_keys[i].key);
}
g_string_append (string, " |\n" );
}
/* }}} */
/* {{{ Vulkan */
#ifdef GDK_RENDERING_VULKAN
static gboolean
gdk_vulkan_has_feature (GdkDisplay *display,
GdkVulkanFeatures feature)
{
return (display->vulkan_features & feature) ? TRUE : FALSE ;
}
static void
add_vulkan_features (GtkInspectorGeneral *gen)
{
for (int i = 0 ; i < GDK_VULKAN_N_FEATURES; i++)
{
add_check_row (gen, GTK_LIST_BOX (gen->vulkan_features_box),
gdk_vulkan_feature_keys[i].key,
gdk_vulkan_has_feature (gen->display, gdk_vulkan_feature_keys[i].value),
0 );
}
}
static void
add_instance_extensions (GtkStringList *list)
{
uint32_t i;
uint32_t n_extensions;
VkExtensionProperties *extensions;
vkEnumerateInstanceExtensionProperties (NULL, &n_extensions, NULL);
extensions = g_newa (VkExtensionProperties, n_extensions);
vkEnumerateInstanceExtensionProperties (NULL, &n_extensions, extensions);
for (i = 0 ; i < n_extensions; i++)
gtk_string_list_append (list, extensions[i].extensionName);
}
static void
add_device_extensions (VkPhysicalDevice device,
GtkStringList *list)
{
uint32_t i;
uint32_t n_extensions;
VkExtensionProperties *extensions;
vkEnumerateDeviceExtensionProperties (device, NULL, &n_extensions, NULL);
extensions = g_newa (VkExtensionProperties, n_extensions);
vkEnumerateDeviceExtensionProperties (device, NULL, &n_extensions, extensions);
for (i = 0 ; i < n_extensions; i++)
gtk_string_list_append (list, extensions[i].extensionName);
}
static void
add_layers (GtkStringList *list)
{
uint32_t i;
uint32_t n_layers;
VkLayerProperties *layers;
vkEnumerateInstanceLayerProperties (&n_layers, NULL);
layers = g_newa (VkLayerProperties, n_layers);
vkEnumerateInstanceLayerProperties (&n_layers, layers);
for (i = 0 ; i < n_layers; i++)
gtk_string_list_append (list, layers[i].layerName);
}
#endif
static void
init_vulkan (GtkInspectorGeneral *gen)
{
#ifdef GDK_RENDERING_VULKAN
VkPhysicalDevice vk_device;
VkPhysicalDeviceProperties props;
char *device_name;
char *api_version;
char *driver_version;
const char *types[] = { "other" , "integrated GPU" , "discrete GPU" , "virtual GPU" , "CPU" };
GError *error = NULL;
if (!gdk_display_prepare_vulkan (gen->display, &error))
{
gtk_label_set_text (GTK_LABEL (gen->vk_device), C_("Vulkan device" , "None" ));
gtk_widget_set_visible (gen->vk_error_row, TRUE );
gtk_label_set_text (GTK_LABEL (gen->vk_error), error->message);
g_error_free (error);
gtk_widget_set_visible (gen->vk_api_version_row, FALSE );
gtk_widget_set_visible (gen->vk_driver_version_row, FALSE );
gtk_widget_set_visible (gen->vulkan_features_row, FALSE );
gtk_widget_set_visible (gen->vulkan_layers_row, FALSE );
gtk_widget_set_visible (gen->vulkan_extensions_row, FALSE );
return ;
}
vk_device = gen->display->vk_physical_device;
vkGetPhysicalDeviceProperties (vk_device, &props);
device_name = g_strdup_printf ("%s (%s)" , props.deviceName, types[props.deviceType]);
api_version = g_strdup_printf ("%d.%d.%d" ,
VK_VERSION_MAJOR (props.apiVersion),
VK_VERSION_MINOR (props.apiVersion),
VK_VERSION_PATCH (props.apiVersion));
driver_version = g_strdup_printf ("%d.%d.%d" ,
VK_VERSION_MAJOR (props.driverVersion),
VK_VERSION_MINOR (props.driverVersion),
VK_VERSION_PATCH (props.driverVersion));
gtk_label_set_text (GTK_LABEL (gen->vk_device), device_name);
gtk_label_set_text (GTK_LABEL (gen->vk_api_version), api_version);
gtk_label_set_text (GTK_LABEL (gen->vk_driver_version), driver_version);
g_free (device_name);
g_free (api_version);
g_free (driver_version);
add_vulkan_features (gen);
add_instance_extensions (gen->vulkan_extensions_list);
add_device_extensions (gen->display->vk_physical_device, gen->vulkan_extensions_list);
add_layers (gen->vulkan_layers_list);
#else
gtk_label_set_text (GTK_LABEL (gen->vk_device), C_("Vulkan device" , "None" ));
gtk_widget_set_visible (gen->vk_api_version_row, FALSE );
gtk_widget_set_visible (gen->vk_driver_version_row, FALSE );
gtk_widget_set_visible (gen->vulkan_layers_row, FALSE );
gtk_widget_set_visible (gen->vulkan_extensions_row, FALSE );
#endif
}
static void
dump_vulkan (GdkDisplay *display,
GString *string)
{
#ifdef GDK_RENDERING_VULKAN
VkPhysicalDevice vk_device;
VkPhysicalDeviceProperties props;
char *device_name;
char *api_version;
char *driver_version;
const char *types[] = { "other" , "integrated GPU" , "discrete GPU" , "virtual GPU" , "CPU" };
GError *error = NULL;
uint32_t n_layers;
VkLayerProperties *layers;
uint32_t n_instance_extensions;
uint32_t n_device_extensions;
VkExtensionProperties *instance_extensions;
VkExtensionProperties *device_extensions;
if (!gdk_display_prepare_vulkan (display, &error))
{
g_string_append (string, "| Vulkan Device | None |\n" );
g_string_append_printf (string, "| | %s |\n" , error->message);
g_error_free (error);
return ;
}
vk_device = display->vk_physical_device;
vkGetPhysicalDeviceProperties (vk_device, &props);
device_name = g_strdup_printf ("%s (%s)" , props.deviceName, types[props.deviceType]);
api_version = g_strdup_printf ("%d.%d.%d" ,
VK_VERSION_MAJOR (props.apiVersion),
VK_VERSION_MINOR (props.apiVersion),
VK_VERSION_PATCH (props.apiVersion));
driver_version = g_strdup_printf ("%d.%d.%d" ,
VK_VERSION_MAJOR (props.driverVersion),
VK_VERSION_MINOR (props.driverVersion),
VK_VERSION_PATCH (props.driverVersion));
g_string_append_printf (string, "| Vulkan Device | %s |\n" , device_name);
g_string_append_printf (string, "| Vulkan API Version | %s |\n" , api_version);
g_string_append_printf (string, "| Vulkan Driver Version | %s |\n" , driver_version);
g_free (device_name);
g_free (api_version);
g_free (driver_version);
vkEnumerateInstanceLayerProperties (&n_layers, NULL);
layers = g_newa (VkLayerProperties, n_layers);
vkEnumerateInstanceLayerProperties (&n_layers, layers);
g_string_append (string, "| Layers | " );
for (uint32_t i = 0 ; i < n_layers; i++)
g_string_append_printf (string, "%s%s" , i > 0 ? "<br>" : "" , layers[i].layerName);
g_string_append (string, " |\n" );
vkEnumerateInstanceExtensionProperties (NULL, &n_instance_extensions, NULL);
instance_extensions = g_newa (VkExtensionProperties, n_instance_extensions);
vkEnumerateInstanceExtensionProperties (NULL, &n_instance_extensions, instance_extensions);
vkEnumerateDeviceExtensionProperties (vk_device, NULL, &n_device_extensions, NULL);
device_extensions = g_newa (VkExtensionProperties, n_device_extensions);
vkEnumerateDeviceExtensionProperties (vk_device, NULL, &n_device_extensions, device_extensions);
g_string_append_printf (string, "| Vulkan Extensions | <details><summary>%u Extensions</summary>" , n_instance_extensions + n_device_extensions);
for (uint32_t i = 0 ; i < n_instance_extensions; i++)
g_string_append_printf (string, "%s%s" , i > 0 ? "<br>" : "" , instance_extensions[i].extensionName);
for (uint32_t i = 0 ; i < n_device_extensions; i++)
g_string_append_printf (string, "%s%s" , i > 0 ? "<br>" : "" , device_extensions[i].extensionName);
g_string_append (string, "</details> |\n" );
g_string_append (string, "| Features | " );
for (int i = 0 ; i < GDK_VULKAN_N_FEATURES; i++)
{
if (gdk_vulkan_has_feature (display, gdk_vulkan_feature_keys[i].value))
g_string_append_printf (string, "%s%s" , i > 0 ? "<br>" : "" , gdk_vulkan_feature_keys[i].key);
}
g_string_append (string, " |\n" );
#endif
}
/* }}} */
/* {{{ Environment */
static const char *env_list[] = {
"AT_SPI_BUS_ADDRESS" ,
"BROADWAY_DISPLAY" ,
"DESKTOP_AUTOSTART_ID" ,
"DISPLAY" ,
"GDK_BACKEND" ,
"GDK_DEBUG" ,
"GDK_DISABLE" ,
"GDK_GL_DISABLE" ,
"GDK_SCALE" ,
"GDK_SYNCHRONIZE" ,
"GDK_VULKAN_DISABLE" ,
"GDK_WAYLAND_DISABLE" ,
"GDK_WIN32_CAIRO_DB" ,
"GDK_WIN32_DISABLE_HIDPI" ,
"GDK_WIN32_PER_MONITOR_HIDPI" ,
"GDK_WIN32_TABLET_INPUT_API" ,
"GOBJECT_DEBUG" ,
"GSETINGS_SCHEMA_DIR" ,
"GSK_CACHE_TIMEOUT" ,
"GSK_DEBUG" ,
"GSK_GPU_DISABLE" ,
"GSK_RENDERER" ,
"GSK_SUBSET_FONTS" ,
"GTK_A11Y" ,
"GTK_CSD" ,
"GTK_CSS_DEBUG" ,
"GTK_DATA_PREFIX" ,
"GTK_DEBUG" ,
"GTK_DEBUG_AUTO_QUIT" ,
"GTK_EXE_PREFIX" ,
"GTK_IM_MODULE" ,
"GTK_INSPECTOR_DISPLAY" ,
"GTK_INSPECTOR_RENDERER" ,
"GTK_MEDIA" ,
"GTK_PATH" ,
"GTK_RTL" ,
"GTK_SLOWDOWN" ,
"GTK_THEME" ,
"GTK_WIDGET_ASSERT_COMPONENTS" ,
"LANG" ,
"LANGUAGE" ,
"LC_ALL" ,
"LC_CTYPE" ,
"LIBGL_ALWAYS_SOFTWARE" ,
"LPDEST" ,
"MESA_VK_DEVICE_SELECT" ,
"PANGOCAIRO_BACKEND" ,
"PANGO_LANGUAGE" ,
"PRINTER" ,
"SECMEM_FORCE_FALLBACK" ,
"WAYLAND_DISPLAY" ,
"XDG_ACTIVATION_TOKEN" ,
"XDG_DATA_HOME" ,
"XDG_DATA_DIRS" ,
"XDG_RUNTIME_DIR" ,
};
static void
init_env (GtkInspectorGeneral *gen)
{
set_monospace_font (gen->prefix);
gtk_label_set_text (GTK_LABEL (gen->prefix), _gtk_get_data_prefix ());
for (guint i = 0 ; i < G_N_ELEMENTS (env_list); i++)
{
const char *val = g_getenv (env_list[i]);
if (val)
{
GtkStringPair *pair = gtk_string_pair_new (env_list[i], val);
g_list_store_append (gen->environment_list, pair);
g_object_unref (pair);
}
}
}
static void
dump_env (GdkDisplay *display,
GString *s)
{
g_string_append_printf (s, "| Prefix | %s |\n" , _gtk_get_data_prefix ());
g_string_append (s, "| Environment| " );
for (guint i = 0 ; i < G_N_ELEMENTS (env_list); i++)
{
const char *val = g_getenv (env_list[i]);
if (val)
g_string_append_printf (s, "%s%s=%s" , i > 0 ? "<br>" : "" , env_list[i], val);
}
g_string_append (s, " |\n" );
}
/* }}} */
/* {{{ Display */
static const char *
translate_subpixel_layout (GdkSubpixelLayout subpixel)
{
switch (subpixel)
{
case GDK_SUBPIXEL_LAYOUT_NONE: return "none" ;
case GDK_SUBPIXEL_LAYOUT_UNKNOWN: return "unknown" ;
case GDK_SUBPIXEL_LAYOUT_HORIZONTAL_RGB: return "horizontal rgb" ;
case GDK_SUBPIXEL_LAYOUT_HORIZONTAL_BGR: return "horizontal bgr" ;
case GDK_SUBPIXEL_LAYOUT_VERTICAL_RGB: return "vertical rgb" ;
case GDK_SUBPIXEL_LAYOUT_VERTICAL_BGR: return "vertical bgr" ;
default : g_assert_not_reached (); return "none" ;
}
}
#ifdef GDK_WINDOWING_WAYLAND
static void
append_wayland_protocol_row (GtkInspectorGeneral *gen,
struct wl_proxy *proxy)
{
const char *id;
unsigned int version;
char buf[64 ];
GtkListBox *list;
if (proxy == NULL)
return ;
list = GTK_LIST_BOX (gen->display_extensions_box);
id = wl_proxy_get_class (proxy);
version = wl_proxy_get_version (proxy);
g_snprintf (buf, sizeof (buf), "%u" , version);
add_label_row (gen, list, id, buf, 10 );
}
static void
append_wayland_protocol (GString *string,
struct wl_proxy *proxy,
guint *count)
{
if (proxy == NULL)
return ;
g_string_append_printf (string, "%s%s (%u)" ,
*count == 0 ? "" : "<br>" ,
wl_proxy_get_class (proxy),
wl_proxy_get_version (proxy));
(*count)++;
}
static void
add_wayland_protocols (GdkDisplay *display,
GtkInspectorGeneral *gen)
{
if (GDK_IS_WAYLAND_DISPLAY (display))
{
GdkWaylandDisplay *d = (GdkWaylandDisplay *) display;
append_wayland_protocol_row (gen, (struct wl_proxy *)d->compositor);
append_wayland_protocol_row (gen, (struct wl_proxy *)d->shm);
append_wayland_protocol_row (gen, (struct wl_proxy *)d->linux_dmabuf);
append_wayland_protocol_row (gen, (struct wl_proxy *)d->xdg_wm_base);
append_wayland_protocol_row (gen, (struct wl_proxy *)d->zxdg_shell_v6);
append_wayland_protocol_row (gen, (struct wl_proxy *)d->gtk_shell);
append_wayland_protocol_row (gen, (struct wl_proxy *)d->data_device_manager);
append_wayland_protocol_row (gen, (struct wl_proxy *)d->subcompositor);
append_wayland_protocol_row (gen, (struct wl_proxy *)d->pointer_gestures);
append_wayland_protocol_row (gen, (struct wl_proxy *)d->primary_selection_manager);
append_wayland_protocol_row (gen, (struct wl_proxy *)d->tablet_manager);
append_wayland_protocol_row (gen, (struct wl_proxy *)d->xdg_exporter);
append_wayland_protocol_row (gen, (struct wl_proxy *)d->xdg_exporter_v2);
append_wayland_protocol_row (gen, (struct wl_proxy *)d->xdg_importer);
append_wayland_protocol_row (gen, (struct wl_proxy *)d->xdg_importer_v2);
append_wayland_protocol_row (gen, (struct wl_proxy *)d->keyboard_shortcuts_inhibit);
append_wayland_protocol_row (gen, (struct wl_proxy *)d->server_decoration_manager);
append_wayland_protocol_row (gen, (struct wl_proxy *)d->xdg_output_manager);
append_wayland_protocol_row (gen, (struct wl_proxy *)d->idle_inhibit_manager);
append_wayland_protocol_row (gen, (struct wl_proxy *)d->xdg_activation);
append_wayland_protocol_row (gen, (struct wl_proxy *)d->fractional_scale);
append_wayland_protocol_row (gen, (struct wl_proxy *)d->viewporter);
append_wayland_protocol_row (gen, (struct wl_proxy *)d->presentation);
append_wayland_protocol_row (gen, (struct wl_proxy *)d->single_pixel_buffer);
append_wayland_protocol_row (gen, d->color ? gdk_wayland_color_get_color_manager (d->color) : NULL);
append_wayland_protocol_row (gen, d->color ? gdk_wayland_color_get_color_representation_manager (d->color) : NULL);
append_wayland_protocol_row (gen, (struct wl_proxy *)d->system_bell);
append_wayland_protocol_row (gen, (struct wl_proxy *)d->cursor_shape);
append_wayland_protocol_row (gen, (struct wl_proxy *)d->toplevel_icon);
append_wayland_protocol_row (gen, (struct wl_proxy *)d->session_manager);
append_wayland_protocol_row (gen, gtk_im_context_wayland_get_text_protocol (display));
}
}
static void
dump_wayland_protocols (GdkDisplay *display,
GString *string)
{
if (GDK_IS_WAYLAND_DISPLAY (display))
{
GdkWaylandDisplay *d = (GdkWaylandDisplay *) display;
guint count = 0 ;
g_string_append (string, "| Protocols | " );
append_wayland_protocol (string, (struct wl_proxy *)d->compositor, &count);
append_wayland_protocol (string, (struct wl_proxy *)d->shm, &count);
append_wayland_protocol (string, (struct wl_proxy *)d->linux_dmabuf, &count);
append_wayland_protocol (string, (struct wl_proxy *)d->xdg_wm_base, &count);
append_wayland_protocol (string, (struct wl_proxy *)d->zxdg_shell_v6, &count);
append_wayland_protocol (string, (struct wl_proxy *)d->gtk_shell, &count);
append_wayland_protocol (string, (struct wl_proxy *)d->data_device_manager, &count);
append_wayland_protocol (string, (struct wl_proxy *)d->subcompositor, &count);
append_wayland_protocol (string, (struct wl_proxy *)d->pointer_gestures, &count);
append_wayland_protocol (string, (struct wl_proxy *)d->primary_selection_manager, &count);
append_wayland_protocol (string, (struct wl_proxy *)d->tablet_manager, &count);
append_wayland_protocol (string, (struct wl_proxy *)d->xdg_exporter, &count);
append_wayland_protocol (string, (struct wl_proxy *)d->xdg_exporter_v2, &count);
append_wayland_protocol (string, (struct wl_proxy *)d->xdg_importer, &count);
append_wayland_protocol (string, (struct wl_proxy *)d->xdg_importer_v2, &count);
append_wayland_protocol (string, (struct wl_proxy *)d->keyboard_shortcuts_inhibit, &count);
append_wayland_protocol (string, (struct wl_proxy *)d->server_decoration_manager, &count);
append_wayland_protocol (string, (struct wl_proxy *)d->xdg_output_manager, &count);
append_wayland_protocol (string, (struct wl_proxy *)d->idle_inhibit_manager, &count);
append_wayland_protocol (string, (struct wl_proxy *)d->xdg_activation, &count);
append_wayland_protocol (string, (struct wl_proxy *)d->fractional_scale, &count);
append_wayland_protocol (string, (struct wl_proxy *)d->viewporter, &count);
append_wayland_protocol (string, (struct wl_proxy *)d->presentation, &count);
append_wayland_protocol (string, (struct wl_proxy *)d->single_pixel_buffer, &count);
append_wayland_protocol (string, d->color ? gdk_wayland_color_get_color_manager (d->color) : NULL, &count);
append_wayland_protocol (string, d->color ? gdk_wayland_color_get_color_representation_manager (d->color) : NULL, &count);
append_wayland_protocol (string, (struct wl_proxy *)d->system_bell, &count);
append_wayland_protocol (string, (struct wl_proxy *)d->cursor_shape, &count);
append_wayland_protocol (string, (struct wl_proxy *)d->toplevel_icon, &count);
append_wayland_protocol (string, (struct wl_proxy *)d->session_manager, &count);
append_wayland_protocol (string , gtk_im_context_wayland_get_text_protocol (display), &count);
g_string_append (string, " |\n" );
}
}
#endif
static void
populate_display (GdkDisplay *display, GtkInspectorGeneral *gen)
{
GList *children, *l;
GtkWidget *child;
GtkListBox *list;
list = GTK_LIST_BOX (gen->display_box);
children = NULL;
for (child = gtk_widget_get_first_child (GTK_WIDGET (list));
child != NULL;
child = gtk_widget_get_next_sibling (child))
{
if (GTK_IS_LIST_BOX_ROW (child))
children = g_list_prepend (children, child);
}
for (l = children; l; l = l->next)
{
child = l->data;
if (gtk_widget_is_ancestor (gen->display_name, child) ||
gtk_widget_is_ancestor (gen->display_rgba, child) ||
gtk_widget_is_ancestor (gen->display_composited, child) ||
child == gen->display_extensions_row)
continue ;
gtk_list_box_remove (list, child);
}
g_list_free (children);
gtk_label_set_label (GTK_LABEL (gen->display_name), gdk_display_get_name (display));
gtk_widget_set_visible (gen->display_rgba,
gdk_display_is_rgba (display));
gtk_widget_set_visible (gen->display_composited,
gdk_display_is_composited (display));
list = GTK_LIST_BOX (gen->display_extensions_box);
while ((child = gtk_widget_get_first_child (GTK_WIDGET (list))) != NULL)
gtk_list_box_remove (list, child);
#ifdef GDK_WINDOWING_WAYLAND
add_wayland_protocols (display, gen);
#endif
gtk_widget_set_visible (gen->display_extensions_row,
gtk_widget_get_first_child (gen->display_extensions_box) != NULL);
}
static void
populate_display_notify_cb (GdkDisplay *display,
GParamSpec *pspec,
GtkInspectorGeneral *gen)
{
populate_display (display, gen);
}
static void
init_display (GtkInspectorGeneral *gen)
{
g_signal_connect (gen->display, "notify" , G_CALLBACK (populate_display_notify_cb), gen);
populate_display (gen->display, gen);
}
static void
dump_display (GdkDisplay *display,
GString *string)
{
g_string_append_printf (string, "| Display | %s |\n" , gdk_display_get_name (display));
g_string_append_printf (string, "| RGBA Visual | %s |\n" , gdk_display_is_rgba (display) ? "✓" : "✗" );
g_string_append_printf (string, "| Composited | %s |\n" , gdk_display_is_composited (display) ? "✓" : "✗" );
#ifdef GDK_WINDOWING_WAYLAND
dump_wayland_protocols (display, string);
#endif
}
/* }}} */
/* {{{ Monitors */
static void
add_monitor (GtkInspectorGeneral *gen,
GdkMonitor *monitor,
guint i)
{
GtkListBox *list;
char *value;
GdkRectangle rect;
double scale;
char *name;
char *scale_str = NULL;
const char *manufacturer;
const char *model;
list = GTK_LIST_BOX (gen->monitor_box);
name = g_strdup_printf ("Monitor %u" , i);
manufacturer = gdk_monitor_get_manufacturer (monitor);
model = gdk_monitor_get_model (monitor);
value = g_strdup_printf ("%s%s%s" ,
manufacturer ? manufacturer : "" ,
manufacturer || model ? " " : "" ,
model ? model : "" );
add_label_row (gen, list, name, value, 0 );
g_free (value);
g_free (name);
add_label_row (gen, list, "Description" , gdk_monitor_get_description (monitor), 10 );
add_label_row (gen, list, "Connector" , gdk_monitor_get_connector (monitor), 10 );
gdk_monitor_get_geometry (monitor, &rect);
scale = gdk_monitor_get_scale (monitor);
if (scale != 1 .0 )
scale_str = g_strdup_printf (" @ %.2f" , scale);
value = g_strdup_printf ("%d × %d%s at %d, %d" ,
rect.width, rect.height,
scale_str ? scale_str : "" ,
rect.x, rect.y);
add_label_row (gen, list, "Geometry" , value, 10 );
g_free (value);
g_free (scale_str);
value = g_strdup_printf ("%d × %d" ,
(int ) (rect.width * scale),
(int ) (rect.height * scale));
add_label_row (gen, list, "Pixels" , value, 10 );
g_free (value);
value = g_strdup_printf ("%d × %d mm²" ,
gdk_monitor_get_width_mm (monitor),
gdk_monitor_get_height_mm (monitor));
add_label_row (gen, list, "Size" , value, 10 );
g_free (value);
value = g_strdup_printf ("%.1f dpi" , gdk_monitor_get_dpi (monitor));
add_label_row (gen, list, "Resolution" , value, 10 );
g_free (value);
if (gdk_monitor_get_refresh_rate (monitor) != 0 )
{
value = g_strdup_printf ("%.2f Hz" ,
0 .001 * gdk_monitor_get_refresh_rate (monitor));
add_label_row (gen, list, "Refresh rate" , value, 10 );
g_free (value);
}
if (gdk_monitor_get_subpixel_layout (monitor) != GDK_SUBPIXEL_LAYOUT_UNKNOWN)
{
add_label_row (gen, list, "Subpixel layout" ,
translate_subpixel_layout (gdk_monitor_get_subpixel_layout (monitor)),
10 );
}
}
static void
dump_monitor (GdkMonitor *monitor,
guint i,
GString *string)
{
const char *manufacturer;
const char *model;
char *value;
GdkRectangle rect;
double scale;
char *scale_str = NULL;
manufacturer = gdk_monitor_get_manufacturer (monitor);
model = gdk_monitor_get_model (monitor);
value = g_strdup_printf ("%s%s%s" ,
manufacturer ? manufacturer : "" ,
manufacturer || model ? " " : "" ,
model ? model : "" );
g_string_append_printf (string, "| Monitor %u | %s |\n" , i, value);
g_free (value);
g_string_append_printf (string, "| Description | %s |\n" , gdk_monitor_get_description (monitor));
g_string_append_printf (string, "| Connector | %s |\n" , gdk_monitor_get_connector (monitor));
gdk_monitor_get_geometry (monitor, &rect);
scale = gdk_monitor_get_scale (monitor);
if (scale != 1 .0 )
scale_str = g_strdup_printf (" @ %.2f" , scale);
value = g_strdup_printf ("%d × %d%s at %d, %d" ,
rect.width, rect.height,
scale_str ? scale_str : "" ,
rect.x, rect.y);
g_string_append_printf (string, "| Geometry | %s |\n" , value);
g_free (value);
g_free (scale_str);
value = g_strdup_printf ("%d × %d" ,
(int ) (rect.width * scale),
(int ) (rect.height * scale));
g_string_append_printf (string, "| Pixels | %s |\n" , value);
g_free (value);
value = g_strdup_printf ("%d × %d mm²" ,
gdk_monitor_get_width_mm (monitor),
gdk_monitor_get_height_mm (monitor));
g_string_append_printf (string, "| Size | %s |\n" , value);
g_free (value);
value = g_strdup_printf ("%.1f dpi" , gdk_monitor_get_dpi (monitor));
g_string_append_printf (string, "| Resolution | %s |\n" , value);
g_free (value);
if (gdk_monitor_get_refresh_rate (monitor) != 0 )
{
value = g_strdup_printf ("%.2f Hz" ,
0 .001 * gdk_monitor_get_refresh_rate (monitor));
g_string_append_printf (string, "| Refresh Rate | %s |\n" , value);
g_free (value);
}
if (gdk_monitor_get_subpixel_layout (monitor) != GDK_SUBPIXEL_LAYOUT_UNKNOWN)
{
g_string_append_printf (string, "| Subpixel Layout | %s |\n" ,
translate_subpixel_layout (gdk_monitor_get_subpixel_layout (monitor)));
}
}
static void
populate_monitors (GdkDisplay *display,
GtkInspectorGeneral *gen)
{
GtkWidget *child;
GListModel *list;
while ((child = gtk_widget_get_first_child (gen->monitor_box)))
gtk_list_box_remove (GTK_LIST_BOX (gen->monitor_box), child);
list = gdk_display_get_monitors (gen->display);
for (guint i = 0 ; i < g_list_model_get_n_items (list); i++)
{
GdkMonitor *monitor = g_list_model_get_item (list, i);
add_monitor (gen, monitor, i);
g_object_unref (monitor);
}
}
static void
dump_monitors (GdkDisplay *display,
GString *string)
{
GListModel *list;
list = gdk_display_get_monitors (display);
for (guint i = 0 ; i < g_list_model_get_n_items (list); i++)
{
GdkMonitor *monitor = g_list_model_get_item (list, i);
dump_monitor (monitor, i, string);
g_object_unref (monitor);
}
}
static void
monitors_changed_cb (GListModel *monitors,
guint position,
guint removed,
guint added,
GtkInspectorGeneral *gen)
{
populate_monitors (gen->display, gen);
}
static void
init_monitors (GtkInspectorGeneral *gen)
{
g_signal_connect (gdk_display_get_monitors (gen->display), "items-changed" ,
G_CALLBACK (monitors_changed_cb), gen);
populate_monitors (gen->display, gen);
}
/* }}} */
/* {{{ Seats */
static void populate_seats (GtkInspectorGeneral *gen);
static void
add_tool (GtkInspectorGeneral *gen,
GdkDeviceTool *tool)
{
GdkAxisFlags axes;
GString *str;
char *val;
GEnumClass *eclass;
GEnumValue *evalue;
GFlagsClass *fclass;
GFlagsValue *fvalue;
val = g_strdup_printf ("Serial %" G_GUINT64_FORMAT, gdk_device_tool_get_serial (tool));
add_label_row (gen, GTK_LIST_BOX (gen->device_box), "Tool" , val, 10 );
g_free (val);
eclass = g_type_class_ref (GDK_TYPE_DEVICE_TOOL_TYPE);
evalue = g_enum_get_value (eclass, gdk_device_tool_get_tool_type (tool));
add_label_row (gen, GTK_LIST_BOX (gen->device_box), "Type" , evalue->value_nick, 20 );
g_type_class_unref (eclass);
fclass = g_type_class_ref (GDK_TYPE_AXIS_FLAGS);
str = g_string_new ("" );
axes = gdk_device_tool_get_axes (tool);
while ((fvalue = g_flags_get_first_value (fclass, axes)))
{
if (str->len > 0 )
g_string_append (str, ", " );
g_string_append (str, fvalue->value_nick);
axes &= ~fvalue->value;
}
g_type_class_unref (fclass);
if (str->len > 0 )
add_label_row (gen, GTK_LIST_BOX (gen->device_box), "Axes" , str->str, 20 );
g_string_free (str, TRUE );
}
static void
dump_tool (GdkDeviceTool *tool,
GString *string)
{
GdkAxisFlags axes;
GString *str;
char *val;
GEnumClass *eclass;
GEnumValue *evalue;
GFlagsClass *fclass;
GFlagsValue *fvalue;
val = g_strdup_printf ("Serial %" G_GUINT64_FORMAT, gdk_device_tool_get_serial (tool));
g_string_append_printf (string, "| Tool | %s |\n" , val);
g_free (val);
eclass = g_type_class_ref (GDK_TYPE_DEVICE_TOOL_TYPE);
evalue = g_enum_get_value (eclass, gdk_device_tool_get_tool_type (tool));
g_string_append_printf (string, "| Type | %s |\n" , evalue->value_nick);
g_type_class_unref (eclass);
fclass = g_type_class_ref (GDK_TYPE_AXIS_FLAGS);
str = g_string_new ("" );
axes = gdk_device_tool_get_axes (tool);
while ((fvalue = g_flags_get_first_value (fclass, axes)))
{
if (str->len > 0 )
g_string_append (str, "<br>" );
g_string_append (str, fvalue->value_nick);
axes &= ~fvalue->value;
}
g_type_class_unref (fclass);
if (str->len > 0 )
g_string_append_printf (string, "| Axes | %s |\n" , str->str);
g_string_free (str, TRUE );
}
static char *
layout_names_from_device (GdkDevice *device)
{
GString *s = g_string_new ("" );
char **layout_names = gdk_device_get_layout_names (device);
if (layout_names)
{
int n_layouts, active_layout;
active_layout = gdk_device_get_active_layout_index (device);
n_layouts = g_strv_length (layout_names);
for (int i = 0 ; i < n_layouts; i++)
{
if (s->len > 0 )
g_string_append (s, ", " );
g_string_append (s, layout_names[i]);
if (i == active_layout)
g_string_append (s, "*" );
}
}
else
{
g_string_append (s, "Unknown" );
}
return g_string_free_and_steal (s);
}
static void
on_keyboard_device_notify (GdkDevice *keyboard,
GParamSpec *pspec,
GtkWidget *label)
{
if (g_strcmp0 (pspec->name, "layout-names" ) == 0 || g_strcmp0 (pspec->name, "active-layout-index" ) == 0 )
{
gchar *layouts = layout_names_from_device (keyboard);
gtk_label_set_label (GTK_LABEL (label), layouts);
g_free (layouts);
}
}
static void
add_device (GtkInspectorGeneral *gen,
GdkDevice *device)
{
const char *name;
guint n_touches;
char *text;
GEnumClass *class ;
GEnumValue *value;
name = gdk_device_get_name (device);
class = g_type_class_ref (GDK_TYPE_INPUT_SOURCE);
value = g_enum_get_value (class , gdk_device_get_source (device));
add_label_row (gen, GTK_LIST_BOX (gen->device_box), name, value->value_nick, 10 );
g_object_get (device, "num-touches" , &n_touches, NULL);
if (n_touches > 0 )
{
text = g_strdup_printf ("%d" , n_touches);
add_label_row (gen, GTK_LIST_BOX (gen->device_box), "Touches" , text, 20 );
g_free (text);
}
if (gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD)
{
GtkWidget *label;
text = layout_names_from_device (device);
label = add_label_row (gen, GTK_LIST_BOX (gen->device_box), "Layouts" , text, 20 );
g_free (text);
/* Connect to associated device if exists to get layout changes */
/* NOTE: there is no public or private API to get the associated device */
g_signal_connect_object (device->associated ? device->associated : device,
"notify" ,
G_CALLBACK (on_keyboard_device_notify),
label,
G_CONNECT_DEFAULT);
}
g_type_class_unref (class );
}
static void
dump_device (GdkDevice *device,
GString *string)
{
const char *name;
guint n_touches;
GEnumClass *class ;
GEnumValue *value;
name = gdk_device_get_name (device);
class = g_type_class_ref (GDK_TYPE_INPUT_SOURCE);
value = g_enum_get_value (class , gdk_device_get_source (device));
g_string_append_printf (string, "| %s | %s |\n" , name, value->value_nick);
g_object_get (device, "num-touches" , &n_touches, NULL);
if (n_touches > 0 )
g_string_append_printf (string, "| Touches | %d |\n" , n_touches);
if (gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD)
{
char **layout_names;
int n_layouts, active_layout;
GString *s;
layout_names = gdk_device_get_layout_names (device);
active_layout = gdk_device_get_active_layout_index (device);
n_layouts = g_strv_length (layout_names);
s = g_string_new ("" );
for (int i = 0 ; i < n_layouts; i++)
{
if (s->len > 0 )
g_string_append (s, "<br>" );
g_string_append (s, layout_names[i]);
if (i == active_layout)
g_string_append (s, "*" );
}
g_string_append_printf (string, "| Layouts | %s |\n" , s->str);
g_string_free (s, TRUE );
}
g_type_class_unref (class );
}
static char *
get_seat_capabilities (GdkSeat *seat)
{
struct {
GdkSeatCapabilities cap;
const char *name;
} caps[] = {
{ GDK_SEAT_CAPABILITY_POINTER, "Pointer" },
{ GDK_SEAT_CAPABILITY_TOUCH, "Touch" },
{ GDK_SEAT_CAPABILITY_TABLET_STYLUS, "Tablet" },
{ GDK_SEAT_CAPABILITY_KEYBOARD, "Keyboard" },
{ 0 , NULL }
};
GString *str;
GdkSeatCapabilities capabilities;
int i;
str = g_string_new ("" );
capabilities = gdk_seat_get_capabilities (seat);
for (i = 0 ; caps[i].cap != 0 ; i++)
{
if (capabilities & caps[i].cap)
{
if (str->len > 0 )
g_string_append (str, ", " );
g_string_append (str, caps[i].name);
}
}
return g_string_free (str, FALSE );
}
static void
add_seat (GtkInspectorGeneral *gen,
GdkSeat *seat,
int num)
{
char *text;
char *caps;
GList *list, *l;
if (!g_object_get_data (G_OBJECT (seat), "inspector-connected" ))
{
g_object_set_data (G_OBJECT (seat), "inspector-connected" , GINT_TO_POINTER (1 ));
g_signal_connect_swapped (seat, "device-added" , G_CALLBACK (populate_seats), gen);
g_signal_connect_swapped (seat, "device-removed" , G_CALLBACK (populate_seats), gen);
g_signal_connect_swapped (seat, "tool-added" , G_CALLBACK (populate_seats), gen);
g_signal_connect_swapped (seat, "tool-removed" , G_CALLBACK (populate_seats), gen);
}
text = g_strdup_printf ("Seat %d" , num);
caps = get_seat_capabilities (seat);
add_label_row (gen, GTK_LIST_BOX (gen->device_box), text, caps, 0 );
g_free (text);
g_free (caps);
list = gdk_seat_get_devices (seat, GDK_SEAT_CAPABILITY_ALL);
for (l = list; l; l = l->next)
add_device (gen, GDK_DEVICE (l->data));
g_list_free (list);
list = gdk_seat_get_tools (seat);
for (l = list; l; l = l->next)
add_tool (gen, l->data);
g_list_free (list);
}
static void
dump_seat (GdkSeat *seat,
int i,
GString *string)
{
char *caps;
GList *list, *l;
caps = get_seat_capabilities (seat);
g_string_append_printf (string, "| Seat %d | %s |\n" , i, caps);
g_free (caps);
list = gdk_seat_get_devices (seat, GDK_SEAT_CAPABILITY_ALL);
for (l = list; l; l = l->next)
dump_device (GDK_DEVICE (l->data), string);
g_list_free (list);
list = gdk_seat_get_tools (seat);
for (l = list; l; l = l->next)
dump_tool (l->data, string);
g_list_free (list);
}
static void
disconnect_seat (GtkInspectorGeneral *gen,
GdkSeat *seat)
{
g_signal_handlers_disconnect_by_func (seat, G_CALLBACK (populate_seats), gen);
}
static void
populate_seats (GtkInspectorGeneral *gen)
{
GtkWidget *child;
GList *list, *l;
int i;
while ((child = gtk_widget_get_first_child (gen->device_box)))
gtk_list_box_remove (GTK_LIST_BOX (gen->device_box), child);
list = gdk_display_list_seats (gen->display);
for (l = list, i = 0 ; l; l = l->next, i++)
add_seat (gen, GDK_SEAT (l->data), i);
g_list_free (list);
}
static void
dump_seats (GdkDisplay *display,
GString *string)
{
GList *list, *l;
int i;
list = gdk_display_list_seats (display);
for (l = list, i = 0 ; l; l = l->next, i++)
dump_seat (GDK_SEAT (l->data), i, string);
g_list_free (list);
}
static void
seat_added (GdkDisplay *display,
GdkSeat *seat,
GtkInspectorGeneral *gen)
{
populate_seats (gen);
}
static void
seat_removed (GdkDisplay *display,
GdkSeat *seat,
GtkInspectorGeneral *gen)
{
disconnect_seat (gen, seat);
populate_seats (gen);
}
static void
init_seats (GtkInspectorGeneral *gen)
{
g_signal_connect (gen->display, "seat-added" , G_CALLBACK (seat_added), gen);
g_signal_connect (gen->display, "seat-removed" , G_CALLBACK (seat_removed), gen);
populate_seats (gen);
}
/* }}} */
static void
gtk_inspector_general_init (GtkInspectorGeneral *gen)
{
gtk_widget_init_template (GTK_WIDGET (gen));
}
static gboolean
keynav_failed (GtkWidget *widget, GtkDirectionType direction, GtkInspectorGeneral *gen)
{
GtkWidget *next;
if (direction == GTK_DIR_DOWN && widget == gen->version_box)
next = gen->env_box;
else if (direction == GTK_DIR_DOWN && widget == gen->env_box)
next = gen->display_box;
else if (direction == GTK_DIR_DOWN && widget == gen->display_box)
next = gen->monitor_box;
else if (direction == GTK_DIR_DOWN && widget == gen->monitor_box)
next = gen->device_box;
else if (direction == GTK_DIR_DOWN && widget == gen->device_box)
next = gen->gl_box;
else if (direction == GTK_DIR_DOWN && widget == gen->gl_box)
next = gen->vulkan_box;
else if (direction == GTK_DIR_UP && widget == gen->vulkan_box)
next = gen->gl_box;
else if (direction == GTK_DIR_UP && widget == gen->gl_box)
next = gen->device_box;
else if (direction == GTK_DIR_UP && widget == gen->device_box)
next = gen->monitor_box;
else if (direction == GTK_DIR_UP && widget == gen->monitor_box)
next = gen->display_box;
else if (direction == GTK_DIR_UP && widget == gen->display_box)
next = gen->env_box;
else if (direction == GTK_DIR_UP && widget == gen->env_box)
next = gen->version_box;
else
next = NULL;
if (next)
{
gtk_widget_child_focus (next, direction);
return TRUE ;
}
return FALSE ;
}
static void
gtk_inspector_general_constructed (GObject *object)
{
GtkInspectorGeneral *gen = GTK_INSPECTOR_GENERAL (object);
G_OBJECT_CLASS (gtk_inspector_general_parent_class)->constructed (object);
g_signal_connect (gen->version_box, "keynav-failed" , G_CALLBACK (keynav_failed), gen);
g_signal_connect (gen->env_box, "keynav-failed" , G_CALLBACK (keynav_failed), gen);
g_signal_connect (gen->display_box, "keynav-failed" , G_CALLBACK (keynav_failed), gen);
g_signal_connect (gen->monitor_box, "keynav-failed" , G_CALLBACK (keynav_failed), gen);
g_signal_connect (gen->gl_box, "keynav-failed" , G_CALLBACK (keynav_failed), gen);
g_signal_connect (gen->vulkan_box, "keynav-failed" , G_CALLBACK (keynav_failed), gen);
g_signal_connect (gen->device_box, "keynav-failed" , G_CALLBACK (keynav_failed), gen);
}
static void
gtk_inspector_general_dispose (GObject *object)
{
GtkInspectorGeneral *gen = GTK_INSPECTOR_GENERAL (object);
GList *list, *l;
g_signal_handlers_disconnect_by_func (gen->display, G_CALLBACK (seat_added), gen);
g_signal_handlers_disconnect_by_func (gen->display, G_CALLBACK (seat_removed), gen);
g_signal_handlers_disconnect_by_func (gen->display, G_CALLBACK (populate_display_notify_cb), gen);
g_signal_handlers_disconnect_by_func (gdk_display_get_monitors (gen->display), G_CALLBACK (monitors_changed_cb), gen);
list = gdk_display_list_seats (gen->display);
for (l = list; l; l = l->next)
disconnect_seat (gen, GDK_SEAT (l->data));
g_list_free (list);
gtk_widget_dispose_template (GTK_WIDGET (gen), GTK_TYPE_INSPECTOR_GENERAL);
G_OBJECT_CLASS (gtk_inspector_general_parent_class)->dispose (object);
}
static void
gtk_inspector_general_class_init (GtkInspectorGeneralClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
g_type_ensure (GTK_TYPE_STRING_PAIR);
object_class->constructed = gtk_inspector_general_constructed;
object_class->dispose = gtk_inspector_general_dispose;
gtk_widget_class_set_template_from_resource (widget_class, "/org/gtk/libgtk/inspector/general.ui" );
gtk_widget_class_bind_template_child (widget_class, GtkInspectorGeneral, swin);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorGeneral, box);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorGeneral, version_box);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorGeneral, env_box);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorGeneral, display_box);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorGeneral, display_extensions_row);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorGeneral, display_extensions_box);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorGeneral, monitor_box);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorGeneral, gl_box);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorGeneral, gl_features_row);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorGeneral, gl_features_box);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorGeneral, gl_extensions_row);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorGeneral, gl_extensions_list);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorGeneral, egl_extensions_row);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorGeneral, egl_extensions_row_name);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorGeneral, egl_extensions_list);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorGeneral, vulkan_box);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorGeneral, vulkan_features_row);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorGeneral, vulkan_features_box);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorGeneral, vulkan_extensions_row);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorGeneral, vulkan_extensions_list);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorGeneral, vulkan_layers_row);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorGeneral, vulkan_layers_list);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorGeneral, os_info);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorGeneral, gtk_version);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorGeneral, gdk_backend);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorGeneral, gsk_renderer);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorGeneral, pango_fontmap);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorGeneral, media_backend);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorGeneral, im_module);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorGeneral, a11y_backend);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorGeneral, gl_error);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorGeneral, gl_error_row);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorGeneral, gl_version);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorGeneral, gl_version_row);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorGeneral, gl_backend_version);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorGeneral, gl_backend_version_row);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorGeneral, gl_backend_vendor);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorGeneral, gl_backend_vendor_row);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorGeneral, gl_vendor);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorGeneral, gl_vendor_row);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorGeneral, gl_renderer);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorGeneral, gl_renderer_row);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorGeneral, gl_full_version);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorGeneral, gl_full_version_row);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorGeneral, glsl_version);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorGeneral, glsl_version_row);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorGeneral, vk_device);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorGeneral, vk_api_version);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorGeneral, vk_api_version_row);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorGeneral, vk_driver_version);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorGeneral, vk_driver_version_row);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorGeneral, vk_error);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorGeneral, vk_error_row);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorGeneral, app_id_box);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorGeneral, app_id);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorGeneral, resource_path);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorGeneral, prefix);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorGeneral, environment_row);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorGeneral, environment_list);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorGeneral, display_name);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorGeneral, display_composited);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorGeneral, display_rgba);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorGeneral, device_box);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorGeneral, overlay);
gtk_widget_class_bind_template_callback (widget_class, gtk_inspector_general_clip);
gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT);
}
void
gtk_inspector_general_set_display (GtkInspectorGeneral *gen,
GdkDisplay *display)
{
gen->display = display;
init_os_info (gen);
init_version (gen);
init_pango (gen);
init_media (gen);
init_im_module (gen);
init_a11y_backend (gen);
init_app_id (gen);
init_env (gen);
init_display (gen);
init_monitors (gen);
init_seats (gen);
init_gl (gen);
init_vulkan (gen);
}
static char *
generate_dump (GdkDisplay *display)
{
GString *string;
string = g_string_new ("" );
g_string_append (string, "\n<details open=\" true \"><summary>General Information</summary>\n\n" );
g_string_append (string, "| Name | Value |\n" );
g_string_append (string, "| - | - |\n" );
dump_os_info (display, string);
dump_version (display, string);
dump_pango (display, string);
dump_media (display, string);
dump_im_module (display, string);
dump_a11y_backend (display, string);
g_string_append (string, "\n</details>\n" );
g_string_append (string, "\n<details><summary>Application</summary>\n\n" );
g_string_append (string, "| Name | Value |\n" );
g_string_append (string, "| - | - |\n" );
dump_app_id (display, string);
g_string_append (string, "\n</details>\n" );
g_string_append (string, "<details><summary>Environment</summary>\n\n" );
g_string_append (string, "| Name | Value |\n" );
g_string_append (string, "| - | - |\n" );
dump_env (display, string);
g_string_append (string, "\n</details>\n" );
g_string_append (string, "<details><summary>Display</summary>\n\n" );
g_string_append (string, "| Name | Value |\n" );
g_string_append (string, "| - | - |\n" );
dump_display (display, string);
g_string_append (string, "\n</details>\n" );
g_string_append (string, "<details><summary>Monitors</summary>\n\n" );
g_string_append (string, "| Name | Value |\n" );
g_string_append (string, "| - | - |\n" );
dump_monitors (display, string);
g_string_append (string, "\n</details>\n" );
g_string_append (string, "<details><summary>Seats</summary>\n\n" );
g_string_append (string, "| Name | Value |\n" );
g_string_append (string, "| - | - |\n" );
dump_seats (display, string);
g_string_append (string, "\n</details>\n" );
g_string_append (string, "<details><summary>OpenGL</summary>\n\n" );
g_string_append (string, "| Name | Value |\n" );
g_string_append (string, "| - | - |\n" );
dump_gl (display, string);
g_string_append (string, "\n</details>\n" );
g_string_append (string, "<details><summary>Vulkan</summary>\n\n" );
g_string_append (string, "| Name | Value |\n" );
g_string_append (string, "| - | - |\n" );
dump_vulkan (display, string);
g_string_append (string, "\n</details>\n" );
return g_string_free (string, FALSE );
}
static void
gtk_inspector_general_clip (GtkButton *button,
GtkInspectorGeneral *gen)
{
char *text;
GdkClipboard *clipboard;
text = generate_dump (gen->display);
clipboard = gtk_widget_get_clipboard (GTK_WIDGET (gen));
gdk_clipboard_set_text (clipboard, text);
g_free (text);
}
void
gtk_inspector_print_general_info (GdkDisplay *display)
{
char *text;
const char *file;
text = generate_dump (display);
file = g_getenv ("GTK_INSPECTOR_GENERAL_INFO_FILE" );
if (file)
g_file_set_contents (file, text, strlen (text), NULL);
else
g_print ("%s\n" , text);
g_free (text);
}
/* vim:set foldmethod=marker: */
Messung V0.5 in Prozent C=97 H=91 G=93
¤ Dauer der Verarbeitung: 0.29 Sekunden
(vorverarbeitet am 2026-07-03)
¤
*© Formatika GbR, Deutschland