diff --git a/docs/reference/gdk/gdk3-sections.txt b/docs/reference/gdk/gdk3-sections.txt index 365244cb05..634c2c1888 100644 --- a/docs/reference/gdk/gdk3-sections.txt +++ b/docs/reference/gdk/gdk3-sections.txt @@ -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 diff --git a/gdk/x11/gdkscreen-x11.c b/gdk/x11/gdkscreen-x11.c index 9f2f833f71..c2d7c881a7 100644 --- a/gdk/x11/gdkscreen-x11.c +++ b/gdk/x11/gdkscreen-x11.c @@ -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 Extended + * Window Manager Hints. + * + * 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 Extended + * Window Manager Hints. + * + * 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"); +} diff --git a/gdk/x11/gdkwindow-x11.c b/gdk/x11/gdkwindow-x11.c index d4ce45ce45..4dc632f0d6 100644 --- a/gdk/x11/gdkwindow-x11.c +++ b/gdk/x11/gdkwindow-x11.c @@ -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 Extended + * Window Manager Hints. + * + * 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 diff --git a/gdk/x11/gdkx11screen.h b/gdk/x11/gdkx11screen.h index efc7d3837e..8f91d64e96 100644 --- a/gdk/x11/gdkx11screen.h +++ b/gdk/x11/gdkx11screen.h @@ -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__ */ diff --git a/gdk/x11/gdkx11window.h b/gdk/x11/gdkx11window.h index 24bb853f75..8e8290c161 100644 --- a/gdk/x11/gdkx11window.h +++ b/gdk/x11/gdkx11window.h @@ -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);