[gnome-flashback] wm: set _GNOME_WM_KEYBINDINGS property
- From: Alberts Muktupāvels <muktupavels src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-flashback] wm: set _GNOME_WM_KEYBINDINGS property
- Date: Mon, 7 Mar 2022 20:15:57 +0000 (UTC)
commit 87a28b85a89a1af941546d399ce5848794a107f0
Author: Alberts Muktupāvels <alberts muktupavels gmail com>
Date: Mon Mar 7 22:06:48 2022 +0200
wm: set _GNOME_WM_KEYBINDINGS property
This property is used by GNOME Control Center to show Keyboard
Shortcuts for current WM.
gnome-flashback/Makefile.am | 2 +
gnome-flashback/gf-application.c | 6 +
gnome-flashback/gf-wm.c | 299 +++++++++++++++++++++++++++++++++++++++
gnome-flashback/gf-wm.h | 32 +++++
4 files changed, 339 insertions(+)
---
diff --git a/gnome-flashback/Makefile.am b/gnome-flashback/Makefile.am
index f026b89..3b8c87f 100644
--- a/gnome-flashback/Makefile.am
+++ b/gnome-flashback/Makefile.am
@@ -47,6 +47,8 @@ gnome_flashback_SOURCES = \
gf-main.c \
gf-session.c \
gf-session.h \
+ gf-wm.c \
+ gf-wm.h \
$(BUILT_SOURCES) \
$(NULL)
diff --git a/gnome-flashback/gf-application.c b/gnome-flashback/gf-application.c
index 5769e50..c3981bd 100644
--- a/gnome-flashback/gf-application.c
+++ b/gnome-flashback/gf-application.c
@@ -22,6 +22,7 @@
#include "gf-application.h"
#include "gf-confirm-display-change-dialog.h"
+#include "gf-wm.h"
#include "backends/gf-backend.h"
#include "liba11y-keyboard/gf-a11y-keyboard.h"
#include "libaudio-device-selection/gf-audio-device-selection.h"
@@ -44,6 +45,8 @@ struct _GfApplication
{
GObject parent;
+ GfWm *wm;
+
GfBackend *backend;
gint bus_name;
@@ -285,6 +288,7 @@ gf_application_dispose (GObject *object)
g_clear_pointer (&application->display_change_dialog, gtk_widget_destroy);
g_clear_object (&application->backend);
+ g_clear_object (&application->wm);
G_OBJECT_CLASS (gf_application_parent_class)->dispose (object);
}
@@ -325,6 +329,8 @@ gf_application_init (GfApplication *application)
GtkSettings *settings;
GfMonitorManager *monitor_manager;
+ application->wm = gf_wm_new ();
+
application->backend = gf_backend_new (GF_BACKEND_TYPE_X11_CM);
monitor_manager = gf_backend_get_monitor_manager (application->backend);
diff --git a/gnome-flashback/gf-wm.c b/gnome-flashback/gf-wm.c
new file mode 100644
index 0000000..f96ec0a
--- /dev/null
+++ b/gnome-flashback/gf-wm.c
@@ -0,0 +1,299 @@
+/*
+ * Copyright (C) 2022 Alberts Muktupāvels
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+#include "gf-wm.h"
+
+#include <gdk/gdk.h>
+#include <gdk/gdkx.h>
+#include <X11/Xatom.h>
+
+struct _GfWm
+{
+ GObject parent;
+
+ Atom wm_check_atom;
+ Atom wm_name_atom;
+ Atom utf8_string_atom;
+
+ Window wm_check;
+};
+
+G_DEFINE_TYPE (GfWm, gf_wm, G_TYPE_OBJECT)
+
+static char *
+get_wm_name (GfWm *self)
+{
+ GdkDisplay *display;
+ Display *xdisplay;
+ int result;
+ Atom actual_type;
+ int actual_format;
+ unsigned long n_items;
+ unsigned long bytes_after;
+ unsigned char *prop;
+ char *wm_name;
+
+ display = gdk_display_get_default ();
+ xdisplay = gdk_x11_display_get_xdisplay (display);
+
+ gdk_x11_display_error_trap_push (display);
+
+ result = XGetWindowProperty (xdisplay,
+ self->wm_check,
+ self->wm_name_atom,
+ 0,
+ G_MAXLONG,
+ False,
+ self->utf8_string_atom,
+ &actual_type,
+ &actual_format,
+ &n_items,
+ &bytes_after,
+ &prop);
+
+ gdk_x11_display_error_trap_pop_ignored (display);
+
+ if (result != Success ||
+ actual_type != self->utf8_string_atom ||
+ actual_format != 8 ||
+ n_items == 0)
+ {
+ XFree (prop);
+ return NULL;
+ }
+
+ wm_name = g_strndup ((const char *) prop, n_items);
+ XFree (prop);
+
+ if (!g_utf8_validate (wm_name, -1, NULL))
+ {
+ g_free (wm_name);
+ return NULL;
+ }
+
+ return wm_name;
+}
+
+static void
+update_gnome_wm_keybindings (GfWm *self)
+{
+ GdkDisplay *display;
+ Display *xdisplay;
+ char *wm_name;
+ char *gnome_wm_keybindings;
+
+ display = gdk_display_get_default ();
+ xdisplay = gdk_x11_display_get_xdisplay (display);
+
+ wm_name = get_wm_name (self);
+ gnome_wm_keybindings = g_strdup_printf ("%s,GNOME Flashback",
+ wm_name ? wm_name : "Unknown");
+
+ gdk_x11_display_error_trap_push (display);
+
+ XChangeProperty (xdisplay,
+ self->wm_check,
+ XInternAtom (xdisplay, "_GNOME_WM_KEYBINDINGS", False),
+ self->utf8_string_atom,
+ 8,
+ PropModeReplace,
+ (guchar *) gnome_wm_keybindings,
+ strlen (gnome_wm_keybindings));
+
+ gdk_x11_display_error_trap_pop_ignored (display);
+
+ g_free (gnome_wm_keybindings);
+ g_free (wm_name);
+}
+
+static Window
+get_net_supporting_wm_check (GfWm *self,
+ GdkDisplay *display,
+ Window window)
+{
+ Display *xdisplay;
+ int result;
+ Atom actual_type;
+ int actual_format;
+ unsigned long n_items;
+ unsigned long bytes_after;
+ unsigned char *prop;
+ Window wm_check;
+
+ xdisplay = gdk_x11_display_get_xdisplay (display);
+
+ gdk_x11_display_error_trap_push (display);
+
+ result = XGetWindowProperty (xdisplay,
+ window,
+ self->wm_check_atom,
+ 0,
+ G_MAXLONG,
+ False,
+ XA_WINDOW,
+ &actual_type,
+ &actual_format,
+ &n_items,
+ &bytes_after,
+ &prop);
+
+ gdk_x11_display_error_trap_pop_ignored (display);
+
+ if (result != Success ||
+ actual_type != XA_WINDOW ||
+ n_items == 0)
+ {
+ XFree (prop);
+ return None;
+ }
+
+ wm_check = *(Window *) prop;
+ XFree (prop);
+
+ return wm_check;
+}
+
+static void
+update_wm_check (GfWm *self)
+{
+ GdkDisplay *display;
+ Display *xdisplay;
+ Window wm_check;
+
+ display = gdk_display_get_default ();
+ xdisplay = gdk_x11_display_get_xdisplay (display);
+
+ wm_check = get_net_supporting_wm_check (self,
+ display,
+ XDefaultRootWindow (xdisplay));
+
+ if (wm_check == None)
+ return;
+
+ if (wm_check != get_net_supporting_wm_check (self, display, wm_check))
+ return;
+
+ self->wm_check = wm_check;
+
+ gdk_x11_display_error_trap_push (display);
+ XSelectInput (xdisplay, self->wm_check, StructureNotifyMask);
+
+ if (gdk_x11_display_error_trap_pop (display) != 0)
+ {
+ self->wm_check = None;
+ }
+
+ update_gnome_wm_keybindings (self);
+}
+
+static GdkFilterReturn
+event_filter_cb (GdkXEvent *xevent,
+ GdkEvent *event,
+ gpointer data)
+{
+ GfWm *self;
+ XEvent *e;
+
+ self = GF_WM (data);
+ e = (XEvent *) xevent;
+
+ if (self->wm_check != None)
+ {
+ if (e->type == DestroyNotify &&
+ e->xdestroywindow.window == self->wm_check)
+ {
+ update_wm_check (self);
+ }
+ else if (e->type == PropertyNotify &&
+ e->xproperty.window == self->wm_check)
+ {
+ if (e->xproperty.atom == self->wm_check_atom)
+ update_wm_check (self);
+ else if (e->xproperty.atom == self->wm_name_atom)
+ update_gnome_wm_keybindings (self);
+ }
+ }
+ else
+ {
+ GdkDisplay *display;
+ Display *xdisplay;
+
+ display = gdk_display_get_default ();
+ xdisplay = gdk_x11_display_get_xdisplay (display);
+
+ if (e->type == PropertyNotify &&
+ e->xproperty.window == XDefaultRootWindow (xdisplay) &&
+ e->xproperty.atom == self->wm_check_atom)
+ {
+ update_wm_check (self);
+ }
+ }
+
+ return GDK_FILTER_CONTINUE;
+}
+
+static void
+gf_wm_finalize (GObject *object)
+{
+ GfWm *self;
+
+ self = GF_WM (object);
+
+ gdk_window_remove_filter (NULL, event_filter_cb, self);
+
+ G_OBJECT_CLASS (gf_wm_parent_class)->finalize (object);
+}
+
+static void
+gf_wm_class_init (GfWmClass *self_class)
+{
+ GObjectClass *object_class;
+
+ object_class = G_OBJECT_CLASS (self_class);
+
+ object_class->finalize = gf_wm_finalize;
+}
+
+static void
+gf_wm_init (GfWm *self)
+{
+ GdkDisplay *display;
+ Display *xdisplay;
+
+ display = gdk_display_get_default ();
+ xdisplay = gdk_x11_display_get_xdisplay (display);
+
+ self->wm_check_atom = XInternAtom (xdisplay,
+ "_NET_SUPPORTING_WM_CHECK",
+ False);
+
+ self->wm_name_atom = XInternAtom (xdisplay, "_NET_WM_NAME", False);
+ self->utf8_string_atom = XInternAtom (xdisplay, "UTF8_STRING", False);
+
+ gdk_window_add_filter (NULL, event_filter_cb, self);
+ XSelectInput (xdisplay, GDK_ROOT_WINDOW (), PropertyChangeMask);
+ XSync (xdisplay, False);
+
+ update_wm_check (self);
+}
+
+GfWm *
+gf_wm_new (void)
+{
+ return g_object_new (GF_TYPE_WM, NULL);
+}
diff --git a/gnome-flashback/gf-wm.h b/gnome-flashback/gf-wm.h
new file mode 100644
index 0000000..e40b7c3
--- /dev/null
+++ b/gnome-flashback/gf-wm.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2022 Alberts Muktupāvels
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GF_WM_H
+#define GF_WM_H
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define GF_TYPE_WM (gf_wm_get_type ())
+G_DECLARE_FINAL_TYPE (GfWm, gf_wm, GF, WM, GObject)
+
+GfWm *gf_wm_new (void);
+
+G_END_DECLS
+
+#endif
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]