xwm: Detect WM_NORMAL_HINTS fullscreen attempts
diff --git a/src/xwayland/window-manager.c b/src/xwayland/window-manager.c
index 8b2d780..5258197 100644
--- a/src/xwayland/window-manager.c
+++ b/src/xwayland/window-manager.c
@@ -40,6 +40,32 @@
#include "xserver-server-protocol.h"
#include "hash.h"
+struct wm_size_hints {
+ uint32_t flags;
+ int32_t x, y;
+ int32_t width, height; /* should set so old wm's don't mess up */
+ int32_t min_width, min_height;
+ int32_t max_width, max_height;
+ int32_t width_inc, height_inc;
+ struct {
+ int32_t x;
+ int32_t y;
+ } min_aspect, max_aspect;
+ int32_t base_width, base_height;
+ int32_t win_gravity;
+};
+
+#define USPosition (1L << 0)
+#define USSize (1L << 1)
+#define PPosition (1L << 2)
+#define PSize (1L << 3)
+#define PMinSize (1L << 4)
+#define PMaxSize (1L << 5)
+#define PResizeInc (1L << 6)
+#define PAspect (1L << 7)
+#define PBaseSize (1L << 8)
+#define PWinGravity (1L << 9)
+
struct motif_wm_hints {
uint32_t flags;
uint32_t functions;
@@ -117,6 +143,8 @@
int override_redirect;
int fullscreen;
int has_alpha;
+ struct wm_size_hints size_hints;
+ struct motif_wm_hints motif_hints;
};
static struct weston_wm_window *
@@ -332,6 +360,7 @@
#define TYPE_WM_PROTOCOLS XCB_ATOM_CUT_BUFFER0
#define TYPE_MOTIF_WM_HINTS XCB_ATOM_CUT_BUFFER1
#define TYPE_NET_WM_STATE XCB_ATOM_CUT_BUFFER2
+#define TYPE_WM_NORMAL_HINTS XCB_ATOM_CUT_BUFFER3
static void
weston_wm_window_read_properties(struct weston_wm_window *window)
@@ -348,6 +377,7 @@
{ XCB_ATOM_WM_NAME, XCB_ATOM_STRING, F(name) },
{ XCB_ATOM_WM_TRANSIENT_FOR, XCB_ATOM_WINDOW, F(transient_for) },
{ wm->atom.wm_protocols, TYPE_WM_PROTOCOLS, F(protocols) },
+ { wm->atom.wm_normal_hints, TYPE_WM_NORMAL_HINTS, F(protocols) },
{ wm->atom.net_wm_state, TYPE_NET_WM_STATE },
{ wm->atom.net_wm_window_type, XCB_ATOM_ATOM, F(type) },
{ wm->atom.net_wm_name, XCB_ATOM_STRING, F(name) },
@@ -363,7 +393,6 @@
uint32_t *xid;
xcb_atom_t *atom;
uint32_t i;
- struct motif_wm_hints *hints;
if (!window->properties_dirty)
return;
@@ -377,6 +406,9 @@
XCB_ATOM_ANY, 0, 2048);
window->decorate = !window->override_redirect;
+ window->size_hints.flags = 0;
+ window->motif_hints.flags = 0;
+
for (i = 0; i < ARRAY_LENGTH(props); i++) {
reply = xcb_get_property_reply(wm->conn, cookie[i], NULL);
if (!reply)
@@ -414,6 +446,11 @@
break;
case TYPE_WM_PROTOCOLS:
break;
+ case TYPE_WM_NORMAL_HINTS:
+ memcpy(&window->size_hints,
+ xcb_get_property_value(reply),
+ sizeof window->size_hints);
+ break;
case TYPE_NET_WM_STATE:
window->fullscreen = 0;
atom = xcb_get_property_value(reply);
@@ -422,9 +459,12 @@
window->fullscreen = 1;
break;
case TYPE_MOTIF_WM_HINTS:
- hints = xcb_get_property_value(reply);
- if (hints->flags & MWM_HINTS_DECORATIONS)
- window->decorate = hints->decorations > 0;
+ memcpy(&window->motif_hints,
+ xcb_get_property_value(reply),
+ sizeof window->motif_hints);
+ if (window->motif_hints.flags & MWM_HINTS_DECORATIONS)
+ window->decorate =
+ window->motif_hints.decorations > 0;
break;
default:
break;
@@ -1516,6 +1556,7 @@
static const struct { const char *name; int offset; } atoms[] = {
{ "WM_PROTOCOLS", F(atom.wm_protocols) },
+ { "WM_NORMAL_HINTS", F(atom.wm_normal_hints) },
{ "WM_TAKE_FOCUS", F(atom.wm_take_focus) },
{ "WM_DELETE_WINDOW", F(atom.wm_delete_window) },
{ "WM_STATE", F(atom.wm_state) },
@@ -1905,6 +1946,8 @@
{
struct weston_compositor *compositor = wm->server->compositor;
struct weston_output *output;
+ uint32_t minmax = PMinSize | PMaxSize;
+ int matching_size;
/* Heuristics for detecting legacy fullscreen windows... */
@@ -1917,6 +1960,26 @@
*output_ret = output;
return 1;
}
+
+ matching_size = 0;
+ if ((window->size_hints.flags & (USSize |PSize)) &&
+ window->size_hints.width == output->width &&
+ window->size_hints.height == output->height)
+ matching_size = 1;
+ if ((window->size_hints.flags & minmax) == minmax &&
+ window->size_hints.min_width == output->width &&
+ window->size_hints.min_height == output->height &&
+ window->size_hints.max_width == output->width &&
+ window->size_hints.max_height == output->height)
+ matching_size = 1;
+
+ if (matching_size && !window->decorate &&
+ (window->size_hints.flags & (USPosition | PPosition)) &&
+ window->size_hints.x == output->x &&
+ window->size_hints.y == output->y) {
+ *output_ret = output;
+ return 1;
+ }
}
return 0;
@@ -1944,14 +2007,14 @@
WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT,
0, NULL);
return;
- } else if (!window->override_redirect) {
- shell_interface->set_toplevel(window->shsurf);
- return;
} else if (legacy_fullscreen(wm, window, &output)) {
window->fullscreen = 1;
shell_interface->set_fullscreen(window->shsurf,
WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT,
0, output);
+ } else if (!window->override_redirect) {
+ shell_interface->set_toplevel(window->shsurf);
+ return;
} else {
shell_interface->set_xwayland(window->shsurf,
window->x,
diff --git a/src/xwayland/xwayland.h b/src/xwayland/xwayland.h
index 21b499e..1262afb 100644
--- a/src/xwayland/xwayland.h
+++ b/src/xwayland/xwayland.h
@@ -80,6 +80,7 @@
struct {
xcb_atom_t wm_protocols;
+ xcb_atom_t wm_normal_hints;
xcb_atom_t wm_take_focus;
xcb_atom_t wm_delete_window;
xcb_atom_t wm_state;