x11: add support for _GTK_WORKAREAS_Dn

If window manager supports _GTK_WORKAREAS use per-monitor work areas.

https://mail.gnome.org/archives/wm-spec-list/2018-December/msg00000.html
https://gitlab.freedesktop.org/xdg/xdg-specs/merge_requests/22

https://gitlab.gnome.org/GNOME/gtk/merge_requests/478
This commit is contained in:
Alberts Muktupāvels 2018-12-31 17:12:24 +02:00
parent cb1c16021e
commit 6609a9f061
3 changed files with 121 additions and 10 deletions

View File

@ -66,19 +66,27 @@ gdk_x11_monitor_get_workarea (GdkMonitor *monitor,
gdk_monitor_get_geometry (monitor, dest);
/* The EWMH constrains workarea to be a rectangle, so it
* can't adequately deal with L-shaped monitor arrangements.
* As a workaround, we ignore the workarea for anything
* but the primary monitor. Since that is where the 'desktop
* chrome' usually lives, this works ok in practice.
*/
if (gdk_monitor_is_primary (monitor) &&
!gdk_monitor_has_fullscreen_window (monitor))
if (_gdk_x11_screen_get_monitor_work_area (screen, monitor, &workarea))
{
gdk_x11_screen_get_work_area (screen, &workarea);
if (gdk_rectangle_intersect (dest, &workarea, &workarea))
if (!gdk_monitor_has_fullscreen_window (monitor))
*dest = workarea;
}
else
{
/* The EWMH constrains workarea to be a rectangle, so it
* can't adequately deal with L-shaped monitor arrangements.
* As a workaround, we ignore the workarea for anything
* but the primary monitor. Since that is where the 'desktop
* chrome' usually lives, this works ok in practice.
*/
if (gdk_monitor_is_primary (monitor) &&
!gdk_monitor_has_fullscreen_window (monitor))
{
gdk_x11_screen_get_work_area (screen, &workarea);
if (gdk_rectangle_intersect (dest, &workarea, &workarea))
*dest = workarea;
}
}
}
static void

View File

@ -234,6 +234,106 @@ get_current_desktop (GdkScreen *screen)
return workspace;
}
gboolean
_gdk_x11_screen_get_monitor_work_area (GdkScreen *screen,
GdkMonitor *monitor,
GdkRectangle *area)
{
GdkX11Screen *x11_screen;
GdkAtom net_workareas;
GdkDisplay *display;
Display *xdisplay;
int current_desktop;
char *workareas_dn_name;
Atom workareas_dn;
int screen_number;
Window xroot;
int result;
Atom type;
int format;
gulong num;
gulong leftovers;
guchar *ret_workarea;
long *workareas;
GdkRectangle geometry;
int i;
x11_screen = GDK_X11_SCREEN (screen);
net_workareas = gdk_atom_intern_static_string ("_GTK_WORKAREAS");
if (!gdk_x11_screen_supports_net_wm_hint (screen, net_workareas))
return FALSE;
display = gdk_screen_get_display (screen);
xdisplay = gdk_x11_display_get_xdisplay (display);
current_desktop = get_current_desktop (screen);
workareas_dn_name = g_strdup_printf ("_GTK_WORKAREAS_D%d", current_desktop);
workareas_dn = XInternAtom (xdisplay, workareas_dn_name, True);
g_free (workareas_dn_name);
if (workareas_dn == None)
return FALSE;
screen_number = gdk_x11_screen_get_screen_number (screen);
xroot = XRootWindow (xdisplay, screen_number);
gdk_x11_display_error_trap_push (display);
ret_workarea = NULL;
result = XGetWindowProperty (xdisplay,
xroot,
workareas_dn,
0,
G_MAXLONG,
False,
AnyPropertyType,
&type,
&format,
&num,
&leftovers,
&ret_workarea);
gdk_x11_display_error_trap_pop_ignored (display);
if (result != Success ||
type == None ||
format == 0 ||
leftovers ||
num % 4 != 0)
{
XFree (ret_workarea);
return FALSE;
}
workareas = (long *) ret_workarea;
gdk_monitor_get_geometry (monitor, &geometry);
*area = geometry;
for (i = 0; i < num / 4; i++)
{
GdkRectangle work_area;
work_area = (GdkRectangle) {
.x = workareas[0] / x11_screen->window_scale,
.y = workareas[1] / x11_screen->window_scale,
.width = workareas[2] / x11_screen->window_scale,
.height = workareas[3] / x11_screen->window_scale,
};
if (gdk_rectangle_intersect (area, &work_area, &work_area))
*area = work_area;
workareas += 4;
}
XFree (ret_workarea);
return TRUE;
}
void
gdk_x11_screen_get_work_area (GdkScreen *screen,
GdkRectangle *area)

View File

@ -119,6 +119,9 @@ void _gdk_x11_screen_get_edge_monitors (GdkScreen *screen,
gint *right);
void _gdk_x11_screen_set_window_scale (GdkX11Screen *x11_screen,
int scale);
gboolean _gdk_x11_screen_get_monitor_work_area (GdkScreen *screen,
GdkMonitor *monitor,
GdkRectangle *area);
void gdk_x11_screen_get_work_area (GdkScreen *screen,
GdkRectangle *area);
gint gdk_x11_screen_get_width (GdkScreen *screen);