1
0
mirror of https://github.com/gryf/wmaker.git synced 2025-12-19 12:28:22 +01:00

Add support for _NET_WM_FULLSCREEN_MONITORS

This patch adds the _NET_WM_FULLSCREEN_MONITORS hint as defined in EWMH which is based on Xinerama.
It's allowing a window to be displayed fullscreen on multiple monitors.

Issue mentioned at https://github.com/window-maker/wmaker/issues/8
Specs at https://specifications.freedesktop.org/wm-spec/1.5/ar01s06.html#idm45763309187776
GTK test program used https://bugzilla.gnome.org/show_bug.cgi?id=414476
This commit is contained in:
David Maciejak
2023-02-18 14:53:14 +08:00
committed by Carlos R. Mafra
parent ac75047aef
commit 4d658341d2
7 changed files with 139 additions and 2 deletions

View File

@@ -912,6 +912,54 @@ void wUnmaximizeWindow(WWindow *wwin)
WMPostNotificationName(WMNChangedState, wwin, "maximize"); WMPostNotificationName(WMNChangedState, wwin, "maximize");
} }
#ifdef USE_XINERAMA
void wFullscreenMonitorsWindow(WWindow *wwin, unsigned long top, unsigned long bottom,
unsigned long left, unsigned long right)
{
int i;
long monitor;
WMRect rect1, rect2;
if ((int)top < wwin->screen_ptr->xine_info.count &&
(int)bottom < wwin->screen_ptr->xine_info.count &&
(int)left < wwin->screen_ptr->xine_info.count &&
(int)right < wwin->screen_ptr->xine_info.count) {
wwin->flags.fullscreen_monitors[0] = top;
wwin->flags.fullscreen_monitors[1] = bottom;
wwin->flags.fullscreen_monitors[2] = left;
wwin->flags.fullscreen_monitors[3] = right;
} else {
wwin->flags.fullscreen_monitors[0] = -1;
return;
}
wwin->flags.fullscreen = True;
wWindowConfigureBorders(wwin);
ChangeStackingLevel(wwin->frame->core, WMFullscreenLevel);
wwin->bfs_geometry.x = wwin->frame_x;
wwin->bfs_geometry.y = wwin->frame_y;
wwin->bfs_geometry.width = wwin->frame->core->width;
wwin->bfs_geometry.height = wwin->frame->core->height;
i = 0;
monitor = wwin->flags.fullscreen_monitors[i];
rect1 = wwin->screen_ptr->xine_info.screens[monitor];
for (i = 1; i <= 3; i++) {
monitor = wwin->flags.fullscreen_monitors[i];
rect2 = wwin->screen_ptr->xine_info.screens[monitor];
wGetRectUnion(&rect1, &rect2, &rect1);
}
wWindowConfigure(wwin, rect1.pos.x, rect1.pos.y, rect1.size.width, rect1.size.height);
wwin->screen_ptr->bfs_focused_window = wwin->screen_ptr->focused_window;
wSetFocusTo(wwin->screen_ptr, wwin);
WMPostNotificationName(WMNChangedState, wwin, "fullscreen");
}
#endif
void wFullscreenWindow(WWindow *wwin) void wFullscreenWindow(WWindow *wwin)
{ {
int head; int head;

View File

@@ -75,6 +75,9 @@ void wArrangeIcons(WScreen *scr, Bool arrangeAll);
void wMakeWindowVisible(WWindow *wwin); void wMakeWindowVisible(WWindow *wwin);
void wFullscreenMonitorsWindow(WWindow *wwin, unsigned long top, unsigned long bottom,
unsigned long left, unsigned long right);
void wFullscreenWindow(WWindow *wwin); void wFullscreenWindow(WWindow *wwin);
void wUnfullscreenWindow(WWindow *wwin); void wUnfullscreenWindow(WWindow *wwin);

View File

@@ -688,6 +688,9 @@ WWindow *wManageWindow(WScreen *scr, Window window)
XChangeWindowAttributes(dpy, window, CWEventMask | CWDontPropagate | CWSaveUnder, &attribs); XChangeWindowAttributes(dpy, window, CWEventMask | CWDontPropagate | CWSaveUnder, &attribs);
XSetWindowBorderWidth(dpy, window, 0); XSetWindowBorderWidth(dpy, window, 0);
if (wwin->wm_class != NULL && strcmp(wwin->wm_class, "DockApp") != 0)
wwin->flags.fullscreen_monitors[0] = -1;
/* get hints from GNUstep app */ /* get hints from GNUstep app */
if (wwin->wm_class != NULL && strcmp(wwin->wm_class, "GNUstep") == 0) if (wwin->wm_class != NULL && strcmp(wwin->wm_class, "GNUstep") == 0)
wwin->flags.is_gnustep = 1; wwin->flags.is_gnustep = 1;

View File

@@ -254,6 +254,7 @@ typedef struct WWindow {
unsigned int maximized:7; unsigned int maximized:7;
unsigned int old_maximized:7; unsigned int old_maximized:7;
unsigned int fullscreen:1; unsigned int fullscreen:1;
long fullscreen_monitors[4];
unsigned int omnipresent:1; unsigned int omnipresent:1;
unsigned int semi_focused:1; unsigned int semi_focused:1;
/* window type flags */ /* window type flags */

View File

@@ -77,6 +77,9 @@ static Atom net_wm_visible_name; /* TODO (unnecessary?) */
static Atom net_wm_icon_name; static Atom net_wm_icon_name;
static Atom net_wm_visible_icon_name; /* TODO (unnecessary?) */ static Atom net_wm_visible_icon_name; /* TODO (unnecessary?) */
static Atom net_wm_desktop; static Atom net_wm_desktop;
#ifdef USE_XINERAMA
static Atom net_wm_fullscreen_monitors;
#endif
static Atom net_wm_window_type; static Atom net_wm_window_type;
static Atom net_wm_window_type_desktop; static Atom net_wm_window_type_desktop;
static Atom net_wm_window_type_dock; static Atom net_wm_window_type_dock;
@@ -161,6 +164,9 @@ static atomitem_t atomNames[] = {
{"_NET_WM_ICON_NAME", &net_wm_icon_name}, {"_NET_WM_ICON_NAME", &net_wm_icon_name},
{"_NET_WM_VISIBLE_ICON_NAME", &net_wm_visible_icon_name}, {"_NET_WM_VISIBLE_ICON_NAME", &net_wm_visible_icon_name},
{"_NET_WM_DESKTOP", &net_wm_desktop}, {"_NET_WM_DESKTOP", &net_wm_desktop},
#ifdef USE_XINERAMA
{"_NET_WM_FULLSCREEN_MONITORS", &net_wm_fullscreen_monitors},
#endif
{"_NET_WM_WINDOW_TYPE", &net_wm_window_type}, {"_NET_WM_WINDOW_TYPE", &net_wm_window_type},
{"_NET_WM_WINDOW_TYPE_DESKTOP", &net_wm_window_type_desktop}, {"_NET_WM_WINDOW_TYPE_DESKTOP", &net_wm_window_type_desktop},
{"_NET_WM_WINDOW_TYPE_DOCK", &net_wm_window_type_dock}, {"_NET_WM_WINDOW_TYPE_DOCK", &net_wm_window_type_dock},
@@ -287,6 +293,9 @@ static void setSupportedHints(WScreen *scr)
atom[i++] = net_wm_moveresize; atom[i++] = net_wm_moveresize;
#endif #endif
atom[i++] = net_wm_desktop; atom[i++] = net_wm_desktop;
#ifdef USE_XINERAMA
atom[i++] = net_wm_fullscreen_monitors;
#endif
atom[i++] = net_wm_window_type; atom[i++] = net_wm_window_type;
atom[i++] = net_wm_window_type_desktop; atom[i++] = net_wm_window_type_desktop;
atom[i++] = net_wm_window_type_dock; atom[i++] = net_wm_window_type_dock;
@@ -1027,6 +1036,9 @@ static void updateStateHint(WWindow *wwin, Bool changedWorkspace, Bool del)
{ /* changeable */ { /* changeable */
if (del) { if (del) {
XDeleteProperty(dpy, wwin->client_win, net_wm_state); XDeleteProperty(dpy, wwin->client_win, net_wm_state);
#ifdef USE_XINERAMA
XDeleteProperty(dpy, wwin->client_win, net_wm_fullscreen_monitors);
#endif
} else { } else {
Atom state[15]; /* nr of defined state atoms */ Atom state[15]; /* nr of defined state atoms */
int i = 0; int i = 0;
@@ -1067,6 +1079,20 @@ static void updateStateHint(WWindow *wwin, Bool changedWorkspace, Bool del)
XChangeProperty(dpy, wwin->client_win, net_wm_state, XA_ATOM, 32, XChangeProperty(dpy, wwin->client_win, net_wm_state, XA_ATOM, 32,
PropModeReplace, (unsigned char *)state, i); PropModeReplace, (unsigned char *)state, i);
#ifdef USE_XINERAMA
if (wwin->flags.fullscreen && (wwin->flags.fullscreen_monitors[0] != -1)) {
unsigned long data[4];
data[0] = wwin->flags.fullscreen_monitors[0];
data[1] = wwin->flags.fullscreen_monitors[1];
data[2] = wwin->flags.fullscreen_monitors[2];
data[3] = wwin->flags.fullscreen_monitors[3];
XChangeProperty(dpy, wwin->client_win, net_wm_fullscreen_monitors, XA_CARDINAL, 32,
PropModeReplace, (unsigned char *)data, 4);
}
#endif
} }
} }
@@ -1260,8 +1286,10 @@ static void doStateAtom(WWindow *wwin, Atom state, int set, Bool init)
} else { } else {
if (set) if (set)
wFullscreenWindow(wwin); wFullscreenWindow(wwin);
else else {
wUnfullscreenWindow(wwin); wUnfullscreenWindow(wwin);
wwin->flags.fullscreen_monitors[0] = -1;
}
} }
} else if (state == net_wm_state_above) { } else if (state == net_wm_state_above) {
if (set == _NET_WM_STATE_TOGGLE) if (set == _NET_WM_STATE_TOGGLE)
@@ -1759,8 +1787,30 @@ Bool wNETWMProcessClientMessage(XClientMessageEvent *event)
wWindowChangeWorkspace(wwin, desktop); wWindowChangeWorkspace(wwin, desktop);
} }
return True; return True;
}
#ifdef USE_XINERAMA
} else if (event->message_type == net_wm_fullscreen_monitors) {
unsigned long top, bottom, left, right, src_indication;
top = event->data.l[0];
bottom = event->data.l[1];
left = event->data.l[2];
right = event->data.l[3];
src_indication = event->data.l[4];
if (src_indication > 1)
wwarning("_NET_WM_FULLSCREEN_MONITORS source indication %ld not supported", src_indication);
wFullscreenMonitorsWindow(wwin, top, bottom, left, right);
return True;
}
#else
}
#endif
#ifdef DEBUG_WMSPEC
wmessage("processClientMessage unsupported type %s", XGetAtomName(dpy, event->message_type));
#endif
return False; return False;
} }

View File

@@ -410,3 +410,33 @@ WMPoint wGetPointToCenterRectInHead(WScreen * scr, int head, int width, int heig
return p; return p;
} }
/* Find the bounding rect of the union of two rectangles */
void wGetRectUnion(const WMRect *rect1, const WMRect *rect2, WMRect *dest)
{
int dest_x, dest_y;
int dest_w, dest_h;
dest_x = rect1->pos.x;
dest_y = rect1->pos.y;
dest_w = rect1->size.width;
dest_h = rect1->size.height;
if (rect2->pos.x < dest_x) {
dest_w += dest_x - rect2->pos.x;
dest_x = rect2->pos.x;
}
if (rect2->pos.y < dest_y) {
dest_h += dest_y - rect2->pos.y;
dest_y = rect2->pos.y;
}
if (rect2->pos.x + rect2->size.width > dest_x + dest_w)
dest_w = rect2->pos.x + rect2->size.width - dest_x;
if (rect2->pos.y + rect2->size.height > dest_y + dest_h)
dest_h = rect2->pos.y + rect2->size.height - dest_y;
dest->pos.x = dest_x;
dest->pos.y = dest_y;
dest->size.width = dest_w;
dest->size.height = dest_h;
}

View File

@@ -60,6 +60,8 @@ WArea wGetUsableAreaForHead(WScreen *scr, int head, WArea *totalAreaPtr, Bool no
WMPoint wGetPointToCenterRectInHead(WScreen *scr, int head, int width, int height); WMPoint wGetPointToCenterRectInHead(WScreen *scr, int head, int width, int height);
void wGetRectUnion(const WMRect *rect1, const WMRect *rect2, WMRect *dest);
Bool wWindowTouchesHead(WWindow *wwin, int head); Bool wWindowTouchesHead(WWindow *wwin, int head);
Bool wAppIconTouchesHead(WAppIcon *aicon, int head); Bool wAppIconTouchesHead(WAppIcon *aicon, int head);