diff --git a/src/actions.c b/src/actions.c index b684ecbe..c1d61424 100644 --- a/src/actions.c +++ b/src/actions.c @@ -912,6 +912,54 @@ void wUnmaximizeWindow(WWindow *wwin) 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) { int head; diff --git a/src/actions.h b/src/actions.h index 1ef40b45..966626b9 100644 --- a/src/actions.h +++ b/src/actions.h @@ -75,6 +75,9 @@ void wArrangeIcons(WScreen *scr, Bool arrangeAll); 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 wUnfullscreenWindow(WWindow *wwin); diff --git a/src/window.c b/src/window.c index 2305bd32..59721b39 100644 --- a/src/window.c +++ b/src/window.c @@ -688,6 +688,9 @@ WWindow *wManageWindow(WScreen *scr, Window window) XChangeWindowAttributes(dpy, window, CWEventMask | CWDontPropagate | CWSaveUnder, &attribs); 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 */ if (wwin->wm_class != NULL && strcmp(wwin->wm_class, "GNUstep") == 0) wwin->flags.is_gnustep = 1; diff --git a/src/window.h b/src/window.h index fcef149f..a19101fb 100644 --- a/src/window.h +++ b/src/window.h @@ -254,6 +254,7 @@ typedef struct WWindow { unsigned int maximized:7; unsigned int old_maximized:7; unsigned int fullscreen:1; + long fullscreen_monitors[4]; unsigned int omnipresent:1; unsigned int semi_focused:1; /* window type flags */ diff --git a/src/wmspec.c b/src/wmspec.c index 64eaa05c..5faf3025 100644 --- a/src/wmspec.c +++ b/src/wmspec.c @@ -77,6 +77,9 @@ static Atom net_wm_visible_name; /* TODO (unnecessary?) */ static Atom net_wm_icon_name; static Atom net_wm_visible_icon_name; /* TODO (unnecessary?) */ 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_desktop; 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_VISIBLE_ICON_NAME", &net_wm_visible_icon_name}, {"_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_DESKTOP", &net_wm_window_type_desktop}, {"_NET_WM_WINDOW_TYPE_DOCK", &net_wm_window_type_dock}, @@ -287,6 +293,9 @@ static void setSupportedHints(WScreen *scr) atom[i++] = net_wm_moveresize; #endif 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_desktop; atom[i++] = net_wm_window_type_dock; @@ -1027,6 +1036,9 @@ static void updateStateHint(WWindow *wwin, Bool changedWorkspace, Bool del) { /* changeable */ if (del) { XDeleteProperty(dpy, wwin->client_win, net_wm_state); +#ifdef USE_XINERAMA + XDeleteProperty(dpy, wwin->client_win, net_wm_fullscreen_monitors); +#endif } else { Atom state[15]; /* nr of defined state atoms */ 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, 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 { if (set) wFullscreenWindow(wwin); - else + else { wUnfullscreenWindow(wwin); + wwin->flags.fullscreen_monitors[0] = -1; + } } } else if (state == net_wm_state_above) { if (set == _NET_WM_STATE_TOGGLE) @@ -1759,8 +1787,30 @@ Bool wNETWMProcessClientMessage(XClientMessageEvent *event) wWindowChangeWorkspace(wwin, desktop); } 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; } diff --git a/src/xinerama.c b/src/xinerama.c index 4c0beb2f..bb7412f9 100644 --- a/src/xinerama.c +++ b/src/xinerama.c @@ -410,3 +410,33 @@ WMPoint wGetPointToCenterRectInHead(WScreen * scr, int head, int width, int heig 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; +} diff --git a/src/xinerama.h b/src/xinerama.h index 29103258..e606b5a9 100644 --- a/src/xinerama.h +++ b/src/xinerama.h @@ -60,6 +60,8 @@ WArea wGetUsableAreaForHead(WScreen *scr, int head, WArea *totalAreaPtr, Bool no 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 wAppIconTouchesHead(WAppIcon *aicon, int head);