From a06d96316e046e5298a54b8eff13081560ca0cda Mon Sep 17 00:00:00 2001 From: Thomas James Alexander Thurman Date: Mon, 17 Nov 2008 02:57:20 +0000 Subject: [PATCH] This change adds support for the new _NET_WM_FULLSCREEN_MONITORS property and client message. This allows client applications to request that a fullscreen window cover more than one monitor. * src/include/boxes.h: * src/core/boxes.c: Add meta_rectangle_union * src/core/window-private.h: * src/core/window.c: (meta_window_new_with_attrs, meta_window_free, set_net_wm_state, meta_window_update_fullscreen_monitors, meta_window_client_message): Add MetaWindow property to store fullscreen monitors field, update _NET_WM_FULLSCREEN_MONITORS property on windows, and handle client message. * src/core/atomnames.h: Add _NET_WM_FULLSCREEN_MONITORS atom. * src/core/constraints.c (setup_constraint_info): If _NET_WM_FULLSCREEN_MONITORS is interesting, use the data stored in MetaWindow::fullscreen_monitors to determine the fullscreen area instead of the basic xinerama_info area. svn path=/trunk/; revision=4021 --- ChangeLog | 24 ++++++++++++++ src/core/atomnames.h | 1 + src/core/boxes.c | 34 +++++++++++++++++++ src/core/constraints.c | 24 +++++++++++++- src/core/window-private.h | 11 +++++++ src/core/window.c | 69 ++++++++++++++++++++++++++++++++++++++- src/include/boxes.h | 5 +++ 7 files changed, 166 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 7734129c7..b653c33d4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,27 @@ +2008-11-16 David Trowbridge + + This change adds support for the new _NET_WM_FULLSCREEN_MONITORS + property and client message. This allows client applications to request + that a fullscreen window cover more than one monitor. + + * src/include/boxes.h: + * src/core/boxes.c: Add meta_rectangle_union + + * src/core/window-private.h: + * src/core/window.c: + (meta_window_new_with_attrs, meta_window_free, set_net_wm_state, + meta_window_update_fullscreen_monitors, meta_window_client_message): Add + MetaWindow property to store fullscreen monitors field, update + _NET_WM_FULLSCREEN_MONITORS property on windows, and handle client + message. + + * src/core/atomnames.h: Add _NET_WM_FULLSCREEN_MONITORS atom. + + * src/core/constraints.c (setup_constraint_info): If + _NET_WM_FULLSCREEN_MONITORS is interesting, use the data stored in + MetaWindow::fullscreen_monitors to determine the fullscreen area instead + of the basic xinerama_info area. + 2008-11-11 Thomas Thurman Removed deprecated calls. Closes #560445. diff --git a/src/core/atomnames.h b/src/core/atomnames.h index f198b7a92..43710f379 100644 --- a/src/core/atomnames.h +++ b/src/core/atomnames.h @@ -155,6 +155,7 @@ item(_NET_WM_USER_TIME_WINDOW) item(_NET_WM_ACTION_ABOVE) item(_NET_WM_ACTION_BELOW) item(_NET_WM_STATE_STICKY) +item(_NET_WM_FULLSCREEN_MONITORS) #if 0 /* We apparently never use: */ diff --git a/src/core/boxes.c b/src/core/boxes.c index 21a9e2bea..139f1736d 100644 --- a/src/core/boxes.c +++ b/src/core/boxes.c @@ -197,6 +197,40 @@ meta_rectangle_equal (const MetaRectangle *src1, (src1->height == src2->height)); } +void +meta_rectangle_union (const MetaRectangle *rect1, + const MetaRectangle *rect2, + MetaRectangle *dest) +{ + int dest_x, dest_y; + int dest_w, dest_h; + + dest_x = rect1->x; + dest_y = rect1->y; + dest_w = rect1->width; + dest_h = rect1->height; + + if (rect2->x < dest_x) + { + dest_w += dest_x - rect2->x; + dest_x = rect2->x; + } + if (rect2->y < dest_y) + { + dest_h += dest_y - rect2->y; + dest_y = rect2->y; + } + if (rect2->x + rect2->width > dest_x + dest_w) + dest_w = rect2->x + rect2->width - dest_x; + if (rect2->y + rect2->height > dest_y + dest_h) + dest_h = rect2->y + rect2->height - dest_y; + + dest->x = dest_x; + dest->y = dest_y; + dest->width = dest_w; + dest->height = dest_h; +} + gboolean meta_rectangle_overlap (const MetaRectangle *rect1, const MetaRectangle *rect2) diff --git a/src/core/constraints.c b/src/core/constraints.c index a7601a775..800b293af 100644 --- a/src/core/constraints.c +++ b/src/core/constraints.c @@ -392,7 +392,27 @@ setup_constraint_info (ConstraintInfo *info, meta_window_get_work_area_for_xinerama (window, xinerama_info->number, &info->work_area_xinerama); - info->entire_xinerama = xinerama_info->rect; + + if (!window->fullscreen || window->fullscreen_monitors[0] == -1) + { + info->entire_xinerama = xinerama_info->rect; + } + else + { + int i = 0; + long monitor; + + monitor = window->fullscreen_monitors[i]; + info->entire_xinerama = + window->screen->xinerama_infos[monitor].rect; + for (i = 1; i <= 3; i++) + { + monitor = window->fullscreen_monitors[i]; + meta_rectangle_union (&info->entire_xinerama, + &window->screen->xinerama_infos[monitor].rect, + &info->entire_xinerama); + } + } cur_workspace = window->screen->active_workspace; info->usable_screen_region = @@ -784,7 +804,9 @@ constrain_fullscreen (MetaWindow *window, /* Determine whether constraint applies; exit if it doesn't */ if (!window->fullscreen) return TRUE; + xinerama = info->entire_xinerama; + get_size_limits (window, info->fgeom, FALSE, &min_size, &max_size); too_big = !meta_rectangle_could_fit_rect (&xinerama, &min_size); too_small = !meta_rectangle_could_fit_rect (&max_size, &xinerama); diff --git a/src/core/window-private.h b/src/core/window-private.h index 73b780237..f55471228 100644 --- a/src/core/window-private.h +++ b/src/core/window-private.h @@ -143,6 +143,12 @@ struct _MetaWindow /* Whether we're fullscreen */ guint fullscreen : 1; + + /* Area to cover when in fullscreen mode. If _NET_WM_FULLSCREEN_MONITORS has + * been overridden (via a client message), the window will cover the union of + * these monitors. If not, this is the single monitor which the window's + * origin is on. */ + long fullscreen_monitors[4]; /* Whether we're trying to constrain the window to be fully onscreen */ guint require_fully_onscreen : 1; @@ -420,6 +426,11 @@ void meta_window_activate_with_workspace (MetaWindow *window, void meta_window_make_fullscreen_internal (MetaWindow *window); void meta_window_make_fullscreen (MetaWindow *window); void meta_window_unmake_fullscreen (MetaWindow *window); +void meta_window_update_fullscreen_monitors (MetaWindow *window, + unsigned long top, + unsigned long bottom, + unsigned long left, + unsigned long right); /* args to move are window pos, not frame pos */ void meta_window_move (MetaWindow *window, diff --git a/src/core/window.c b/src/core/window.c index a99eb1546..d098285cd 100644 --- a/src/core/window.c +++ b/src/core/window.c @@ -249,7 +249,7 @@ meta_window_new_with_attrs (MetaDisplay *display, gulong existing_wm_state; gulong event_mask; MetaMoveResizeFlags flags; -#define N_INITIAL_PROPS 18 +#define N_INITIAL_PROPS 19 Atom initial_props[N_INITIAL_PROPS]; int i; gboolean has_shape; @@ -461,6 +461,7 @@ meta_window_new_with_attrs (MetaDisplay *display, window->maximize_vertically_after_placement = FALSE; window->minimize_after_placement = FALSE; window->fullscreen = FALSE; + window->fullscreen_monitors[0] = -1; window->require_fully_onscreen = TRUE; window->require_on_single_xinerama = TRUE; window->require_titlebar_visible = TRUE; @@ -591,6 +592,7 @@ meta_window_new_with_attrs (MetaDisplay *display, initial_props[i++] = display->atom__MOTIF_WM_HINTS; initial_props[i++] = XA_WM_TRANSIENT_FOR; initial_props[i++] = display->atom__NET_WM_USER_TIME_WINDOW; + initial_props[i++] = display->atom__NET_WM_FULLSCREEN_MONITORS; g_assert (N_INITIAL_PROPS == i); meta_window_reload_properties (window, initial_props, N_INITIAL_PROPS); @@ -1115,6 +1117,9 @@ meta_window_free (MetaWindow *window, XDeleteProperty (window->display->xdisplay, window->xwindow, window->display->atom__NET_WM_STATE); + XDeleteProperty (window->display->xdisplay, + window->xwindow, + window->display->atom__NET_WM_FULLSCREEN_MONITORS); set_wm_state (window, WithdrawnState); meta_error_trap_pop (window->display, FALSE); } @@ -1300,6 +1305,23 @@ set_net_wm_state (MetaWindow *window) XA_ATOM, 32, PropModeReplace, (guchar*) data, i); meta_error_trap_pop (window->display, FALSE); + + if (window->fullscreen) + { + data[0] = window->fullscreen_monitors[0]; + data[1] = window->fullscreen_monitors[1]; + data[2] = window->fullscreen_monitors[2]; + data[3] = window->fullscreen_monitors[3]; + + meta_verbose ("Setting _NET_WM_FULLSCREEN_MONITORS\n"); + meta_error_trap_push (window->display); + XChangeProperty (window->display->xdisplay, + window->xwindow, + window->display->atom__NET_WM_FULLSCREEN_MONITORS, + XA_CARDINAL, 32, PropModeReplace, + (guchar*) data, 4); + meta_error_trap_pop (window->display, FALSE); + } } gboolean @@ -2794,6 +2816,34 @@ meta_window_unmake_fullscreen (MetaWindow *window) } } +void +meta_window_update_fullscreen_monitors (MetaWindow *window, + unsigned long top, + unsigned long bottom, + unsigned long left, + unsigned long right) +{ + if ((int)top < window->screen->n_xinerama_infos && + (int)bottom < window->screen->n_xinerama_infos && + (int)left < window->screen->n_xinerama_infos && + (int)right < window->screen->n_xinerama_infos) + { + window->fullscreen_monitors[0] = top; + window->fullscreen_monitors[1] = bottom; + window->fullscreen_monitors[2] = left; + window->fullscreen_monitors[3] = right; + } + else + { + window->fullscreen_monitors[0] = -1; + } + + if (window->fullscreen) + { + meta_window_queue(window, META_QUEUE_MOVE_RESIZE); + } +} + void meta_window_shade (MetaWindow *window, guint32 timestamp) @@ -5144,6 +5194,23 @@ meta_window_client_message (MetaWindow *window, window_activate (window, timestamp, source_indication, NULL); return TRUE; } + else if (event->xclient.message_type == + display->atom__NET_WM_FULLSCREEN_MONITORS) + { + MetaClientType source_indication; + gulong top, bottom, left, right; + + meta_verbose ("_NET_WM_FULLSCREEN_MONITORS request for window '%s'\n", + window->desc); + + top = event->xclient.data.l[0]; + bottom = event->xclient.data.l[1]; + left = event->xclient.data.l[2]; + right = event->xclient.data.l[3]; + source_indication = event->xclient.data.l[4]; + + meta_window_update_fullscreen_monitors (window, top, bottom, left, right); + } return FALSE; } diff --git a/src/include/boxes.h b/src/include/boxes.h index 145dbb055..54b94ea9b 100644 --- a/src/include/boxes.h +++ b/src/include/boxes.h @@ -103,6 +103,11 @@ gboolean meta_rectangle_intersect (const MetaRectangle *src1, gboolean meta_rectangle_equal (const MetaRectangle *src1, const MetaRectangle *src2); +/* Find the bounding box of the union of two rectangles */ +void meta_rectangle_union (const MetaRectangle *rect1, + const MetaRectangle *rect2, + MetaRectangle *dest); + /* overlap is similar to intersect but doesn't provide location of * intersection information. */