gnome-control-center/panels/keyboard/wm-common.c
Georges Basile Stavracas Neto 9a611e0d69 keyboard: Remove deprecated gdk_error_trap_push|pop calls
Instead, implement custom error push and pop functions that mimic
what GDK used to do, but using only non-deprecated functions.
2018-03-16 14:56:28 -03:00

261 lines
6.4 KiB
C

#include <X11/Xatom.h>
#include <gdk/gdkx.h>
#include <gdk/gdk.h>
#include <string.h>
#include <glib.h>
#include <glib-object.h>
#include "wm-common.h"
typedef struct _WMCallbackData
{
GFunc func;
gpointer data;
} WMCallbackData;
/* Our WM Window */
static Window wm_window = None;
/*
* These push/pop implementations are based on the GDK versions, except that they
* use only non-deprecated API.
*/
static GPtrArray*
push_error_traps (void)
{
GdkDisplayManager *manager;
g_autoptr(GPtrArray) trapped_displays = NULL;
g_autoptr(GSList) displays = NULL;
GSList *l;
manager = gdk_display_manager_get ();
displays = gdk_display_manager_list_displays (manager);
trapped_displays = g_ptr_array_new ();
for (l = displays; l != NULL; l = l->next)
{
GdkDisplay *display = l->data;
#ifdef GDK_WINDOWING_X11
if (GDK_IS_X11_DISPLAY (display))
{
gdk_x11_display_error_trap_push (display);
g_ptr_array_add (trapped_displays, display);
}
#endif
}
return g_steal_pointer (&trapped_displays);
}
static gint
pop_error_traps (GPtrArray *displays)
{
guint i;
gint result;
result = 0;
for (i = 0; displays && i < displays->len; i++)
{
GdkDisplay *display;
gint code = 0;
display = g_ptr_array_index (displays, i);
#ifdef GDK_WINDOWING_X11
code = gdk_x11_display_error_trap_pop (display);
#endif
if (code != 0)
result = code;
}
return result;
}
static char *
wm_common_get_window_manager_property (Atom atom)
{
g_autoptr(GPtrArray) trapped_displays = NULL;
Atom utf8_string, type;
int result;
char *retval;
int format;
gulong nitems;
gulong bytes_after;
gchar *val;
if (wm_window == None)
return NULL;
utf8_string = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), "UTF8_STRING", False);
trapped_displays = push_error_traps ();
val = NULL;
result = XGetWindowProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
wm_window,
atom,
0, G_MAXLONG,
False, utf8_string,
&type, &format, &nitems,
&bytes_after, (guchar **) &val);
if (pop_error_traps (trapped_displays) ||
result != Success ||
type != utf8_string ||
format != 8 ||
nitems == 0 ||
!g_utf8_validate (val, nitems, NULL))
{
retval = NULL;
}
else
{
retval = g_strndup (val, nitems);
}
g_clear_pointer (&val, XFree);
return retval;
}
static gchar*
wm_common_get_current_window_manager (void)
{
Atom atom = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), "_NET_WM_NAME", False);
char *result;
result = wm_common_get_window_manager_property (atom);
if (result)
return result;
else
return g_strdup (WM_COMMON_UNKNOWN);
}
GStrv
wm_common_get_current_keybindings (void)
{
g_autofree gchar* keybindings = NULL;
g_auto(GStrv) results = NULL;
Atom keybindings_atom;
keybindings_atom = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), "_GNOME_WM_KEYBINDINGS", False);
keybindings = wm_common_get_window_manager_property (keybindings_atom);
if (keybindings)
{
GStrv p;
results = g_strsplit (keybindings, ",", -1);
for (p = results; p && *p; p++)
g_strstrip (*p);
}
else
{
g_autofree gchar *wm_name = NULL;
Atom wm_atom;
gchar *to_copy[2] = { NULL, NULL };
wm_atom = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), "_NET_WM_NAME", False);
wm_name = wm_common_get_window_manager_property (wm_atom);
to_copy[0] = wm_name ? wm_name : WM_COMMON_UNKNOWN;
results = g_strdupv (to_copy);
}
return g_steal_pointer (&results);
}
static void
update_wm_window (void)
{
g_autoptr(GPtrArray) trapped_displays = NULL;
Window *xwindow;
Atom type;
gint format;
gulong nitems;
gulong bytes_after;
XGetWindowProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), GDK_ROOT_WINDOW (),
XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), "_NET_SUPPORTING_WM_CHECK", False),
0, G_MAXLONG, False, XA_WINDOW, &type, &format,
&nitems, &bytes_after, (guchar **) &xwindow);
if (type != XA_WINDOW)
{
wm_window = None;
return;
}
trapped_displays = push_error_traps ();
XSelectInput (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), *xwindow, StructureNotifyMask | PropertyChangeMask);
XSync (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), False);
if (pop_error_traps (trapped_displays))
{
XFree (xwindow);
wm_window = None;
return;
}
wm_window = *xwindow;
XFree (xwindow);
}
static GdkFilterReturn
wm_window_event_filter (GdkXEvent *xev,
GdkEvent *event,
gpointer data)
{
WMCallbackData *ncb_data = (WMCallbackData*) data;
XEvent *xevent = (XEvent *)xev;
if ((xevent->type == DestroyNotify &&
wm_window != None && xevent->xany.window == wm_window) ||
(xevent->type == PropertyNotify &&
xevent->xany.window == GDK_ROOT_WINDOW () &&
xevent->xproperty.atom == (XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), "_NET_SUPPORTING_WM_CHECK", False))) ||
(xevent->type == PropertyNotify &&
wm_window != None && xevent->xany.window == wm_window &&
xevent->xproperty.atom == (XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), "_NET_WM_NAME", False))))
{
update_wm_window ();
(* ncb_data->func) ((gpointer) wm_common_get_current_window_manager (), ncb_data->data);
}
return GDK_FILTER_CONTINUE;
}
gpointer
wm_common_register_window_manager_change (GFunc func,
gpointer data)
{
WMCallbackData *ncb_data;
ncb_data = g_new0 (WMCallbackData, 1);
ncb_data->func = func;
ncb_data->data = data;
gdk_window_add_filter (NULL, wm_window_event_filter, ncb_data);
update_wm_window ();
XSelectInput (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), GDK_ROOT_WINDOW (), PropertyChangeMask);
XSync (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), False);
return ncb_data;
}
void
wm_common_unregister_window_manager_change (gpointer id)
{
g_return_if_fail (id != NULL);
gdk_window_remove_filter (NULL, wm_window_event_filter, id);
g_free (id);
}