x11: Add EWMH workspace handling api

Add a few functions that give access to the EWMH workspace
properties.
This commit is contained in:
Matthias Clasen
2013-08-24 00:51:01 -04:00
parent 8f69721ed4
commit 13f6552a7e
5 changed files with 176 additions and 51 deletions

View File

@@ -998,6 +998,8 @@ gdk_x11_screen_get_window_manager_name
gdk_x11_screen_get_monitor_output
gdk_x11_screen_lookup_visual
gdk_x11_screen_supports_net_wm_hint
gdk_x11_screen_get_number_of_desktops
gdk_x11_screen_get_current_desktop
gdk_x11_window_foreign_new_for_display
gdk_x11_window_lookup_for_display
gdk_x11_window_get_xid
@@ -1005,6 +1007,8 @@ gdk_x11_window_set_hide_titlebar_when_maximized
gdk_x11_window_set_theme_variant
gdk_x11_window_set_user_time
gdk_x11_window_move_to_current_desktop
gdk_x11_window_move_to_desktop
gdk_x11_window_get_desktop
gdk_x11_window_set_utf8_property
gdk_x11_get_default_root_xwindow
gdk_x11_get_default_screen

View File

@@ -1722,3 +1722,74 @@ gdk_x11_screen_class_init (GdkX11ScreenClass *klass)
G_TYPE_NONE,
0);
}
static guint32
get_netwm_cardinal_property (GdkScreen *screen,
const gchar *name)
{
GdkX11Screen *x11_screen = GDK_X11_SCREEN (screen);
GdkAtom atom;
guint32 prop = 0;
Atom type;
gint format;
gulong nitems;
gulong bytes_after;
guchar *data;
atom = gdk_atom_intern_static_string (name);
if (!gdk_x11_screen_supports_net_wm_hint (screen, atom))
return 0;
XGetWindowProperty (x11_screen->xdisplay,
x11_screen->xroot_window,
gdk_x11_get_xatom_by_name_for_display (GDK_SCREEN_DISPLAY (screen), name),
0, G_MAXLONG,
False, XA_CARDINAL, &type, &format, &nitems,
&bytes_after, &data);
if (type == XA_CARDINAL)
{
prop = *(gulong *)data;
XFree (data);
}
return prop;
}
/**
* gdk_x11_screen_get_number_of_desktops:
* @screen: a #GdkScreen
*
* Returns the number of workspaces for @screen when running under a
* window manager that supports multiple workspaces, as described
* in the <ulink url="http://www.freedesktop.org/Standards/wm-spec">Extended
* Window Manager Hints</ulink>.
*
* Returns: the number of workspaces, or 0 if workspaces are not supported
*
* Since: 3.10
*/
guint32
gdk_x11_screen_get_number_of_desktops (GdkScreen *screen)
{
return get_netwm_cardinal_property (screen, "_NET_NUMBER_OF_DESKTOPS");
}
/**
* gdk_x11_screen_get_current_desktop:
* @screen: a #GdkScreen
*
* Returns the current workspace for @screen when running under a
* window manager that supports multiple workspaces, as described
* in the <ulink url="http://www.freedesktop.org/Standards/wm-spec">Extended
* Window Manager Hints</ulink>.
*
* Returns: the current workspace, or 0 if workspaces are not supported
*
* Since: 3.10
*/
guint32
gdk_x11_screen_get_current_desktop (GdkScreen *screen)
{
return get_netwm_cardinal_property (screen, "_NET_CURRENT_DESKTOP");
}

View File

@@ -2116,59 +2116,98 @@ gdk_x11_window_move_to_current_desktop (GdkWindow *window)
static void
move_to_current_desktop (GdkWindow *window)
{
if (gdk_x11_screen_supports_net_wm_hint (GDK_WINDOW_SCREEN (window),
gdk_atom_intern_static_string ("_NET_WM_DESKTOP")) &&
gdk_x11_screen_supports_net_wm_hint (GDK_WINDOW_SCREEN (window),
gdk_atom_intern_static_string ("_NET_CURRENT_DESKTOP")))
guint32 desktop;
desktop = gdk_x11_screen_get_current_desktop (GDK_WINDOW_SCREEN (window));
gdk_x11_window_move_to_desktop (window, desktop);
}
static guint32
get_netwm_cardinal_property (GdkWindow *window,
const gchar *name)
{
GdkScreen *screen = GDK_WINDOW_SCREEN (window);
GdkX11Screen *x11_screen = GDK_X11_SCREEN (screen);
GdkAtom atom;
guint32 prop = 0;
Atom type;
gint format;
gulong nitems;
gulong bytes_after;
guchar *data;
atom = gdk_atom_intern_static_string (name);
if (!gdk_x11_screen_supports_net_wm_hint (screen, atom))
return 0;
XGetWindowProperty (x11_screen->xdisplay,
GDK_WINDOW_XID (window),
gdk_x11_get_xatom_by_name_for_display (GDK_WINDOW_DISPLAY (window), name),
0, G_MAXLONG,
False, XA_CARDINAL, &type, &format, &nitems,
&bytes_after, &data);
if (type == XA_CARDINAL)
{
Atom type;
gint format;
gulong nitems;
gulong bytes_after;
guchar *data;
gulong *current_desktop;
GdkDisplay *display;
display = gdk_window_get_display (window);
/* Get current desktop, then set it; this is a race, but not
* one that matters much in practice.
*/
XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display),
GDK_WINDOW_XROOTWIN (window),
gdk_x11_get_xatom_by_name_for_display (display, "_NET_CURRENT_DESKTOP"),
0, G_MAXLONG,
False, XA_CARDINAL, &type, &format, &nitems,
&bytes_after, &data);
if (type == XA_CARDINAL)
{
XClientMessageEvent xclient;
current_desktop = (gulong *)data;
memset (&xclient, 0, sizeof (xclient));
xclient.type = ClientMessage;
xclient.serial = 0;
xclient.send_event = True;
xclient.window = GDK_WINDOW_XID (window);
xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_DESKTOP");
xclient.format = 32;
xclient.data.l[0] = *current_desktop;
xclient.data.l[1] = 1; /* source indication */
xclient.data.l[2] = 0;
xclient.data.l[3] = 0;
xclient.data.l[4] = 0;
XSendEvent (GDK_DISPLAY_XDISPLAY (display),
GDK_WINDOW_XROOTWIN (window),
False,
SubstructureRedirectMask | SubstructureNotifyMask,
(XEvent *)&xclient);
XFree (current_desktop);
}
prop = *(gulong *)data;
XFree (data);
}
return prop;
}
guint32
gdk_x11_window_get_desktop (GdkWindow *window)
{
g_return_if_fail (GDK_IS_WINDOW (window));
return get_netwm_cardinal_property (window, "_NET_WM_DESKTOP");
}
/**
* gdk_x11_window_move_to_desktop:
* @window: a #GdkWindow
* @desktop: the number of the workspace to move the window to
*
* Moves the window to the given workspace when running unde a
* window manager that supports multiple workspaces, as described
* in the <ulink url="http://www.freedesktop.org/Standards/wm-spec">Extended
* Window Manager Hints</ulink>.
*
* Since: 3.10
*/
void
gdk_x11_window_move_to_desktop (GdkWindow *window,
guint32 desktop)
{
GdkAtom atom;
XClientMessageEvent xclient;
g_return_if_fail (GDK_IS_WINDOW (window));
atom = gdk_atom_intern_static_string ("_NET_WM_DESKTOP");
if (!gdk_x11_screen_supports_net_wm_hint (GDK_WINDOW_SCREEN (window), atom))
return;
memset (&xclient, 0, sizeof (xclient));
xclient.type = ClientMessage;
xclient.serial = 0;
xclient.send_event = True;
xclient.window = GDK_WINDOW_XID (window);
xclient.message_type = gdk_x11_atom_to_xatom_for_display (GDK_WINDOW_DISPLAY (window), atom);
xclient.format = 32;
xclient.data.l[0] = desktop;
xclient.data.l[1] = 1; /* source indication */
xclient.data.l[2] = 0;
xclient.data.l[3] = 0;
xclient.data.l[4] = 0;
XSendEvent (GDK_WINDOW_XDISPLAY (window),
GDK_WINDOW_XROOTWIN (window),
False,
SubstructureRedirectMask | SubstructureNotifyMask,
(XEvent *)&xclient);
}
static void

View File

@@ -104,6 +104,11 @@ GDK_AVAILABLE_IN_ALL
XID gdk_x11_screen_get_monitor_output (GdkScreen *screen,
gint monitor_num);
GDK_AVAILABLE_IN_3_10
guint32 gdk_x11_screen_get_number_of_desktops (GdkScreen *screen);
GDK_AVAILABLE_IN_3_10
guint32 gdk_x11_screen_get_current_desktop (GdkScreen *screen);
G_END_DECLS
#endif /* __GDK_X11_SCREEN_H__ */

View File

@@ -77,6 +77,12 @@ void gdk_x11_window_set_hide_titlebar_when_maximized (GdkWindow *window,
GDK_AVAILABLE_IN_ALL
void gdk_x11_window_move_to_current_desktop (GdkWindow *window);
GDK_AVAILABLE_IN_3_10
guint32 gdk_x11_window_get_desktop (GdkWindow *window);
GDK_AVAILABLE_IN_3_10
void gdk_x11_window_move_to_desktop (GdkWindow *window,
guint32 desktop);
GDK_AVAILABLE_IN_3_8
void gdk_x11_window_set_frame_sync_enabled (GdkWindow *window,
gboolean frame_sync_enabled);