From eb6a2e9c4b334f53d714a2e7f10f73c63c3d2edd Mon Sep 17 00:00:00 2001 From: Dana Jansens Date: Wed, 13 Jun 2007 11:15:51 +0000 Subject: [PATCH] xinerama support like crazy for struts and everything else too. this probably crashes but its been way too long without a commit. --- openbox/action.c | 4 +- openbox/client.c | 117 ++++++++-------- openbox/dock.c | 2 +- openbox/focus_cycle_popup.c | 4 +- openbox/frame.c | 3 +- openbox/geom.h | 2 +- openbox/keyboard.c | 2 +- openbox/mouse.c | 3 + openbox/place.c | 8 +- openbox/popup.c | 5 +- openbox/resist.c | 6 +- openbox/screen.c | 258 +++++++++++++++++++++++++----------- openbox/screen.h | 17 ++- 13 files changed, 274 insertions(+), 157 deletions(-) diff --git a/openbox/action.c b/openbox/action.c index 9d0f9c73..6ba52c89 100644 --- a/openbox/action.c +++ b/openbox/action.c @@ -1430,7 +1430,7 @@ void action_move_to_center(union ActionData *data) { ObClient *c = data->client.any.c; Rect *area; - area = screen_area_monitor(c->desktop, 0, NULL); + area = screen_area(c->desktop, client_monitor(c), NULL); client_action_start(data); client_move(c, area->width / 2 - c->area.width / 2, area->height / 2 - c->area.height / 2); @@ -1898,7 +1898,7 @@ void action_growtoedge(union ActionData *data) ObClient *c = data->diraction.any.c; Rect *a; - a = screen_area(c->desktop, NULL); + a = screen_area(c->desktop, SCREEN_AREA_ALL_MONITORS, &c->frame->area); x = c->frame->area.x; y = c->frame->area.y; /* get the unshaded frame's dimensions..if it is shaded */ diff --git a/openbox/client.c b/openbox/client.c index 1ead992c..d1013402 100644 --- a/openbox/client.c +++ b/openbox/client.c @@ -403,8 +403,7 @@ void client_manage(Window window) RECT_SET(placer, placex, placey, placew, placeh); frame_rect_to_frame(self->frame, &placer); - Rect *a = screen_area_monitor(self->desktop, client_monitor(self), - &placer); + Rect *a = screen_area(self->desktop, SCREEN_AREA_ONE_MONITOR, &placer); /* shrink by the frame's area */ a->width -= self->frame->size.left + self->frame->size.right; @@ -923,19 +922,15 @@ void client_move_onscreen(ObClient *self, gboolean rude) gboolean client_find_onscreen(ObClient *self, gint *x, gint *y, gint w, gint h, gboolean rude) { - Rect *mon_a, *all_a; gint ox = *x, oy = *y; gboolean rudel = rude, ruder = rude, rudet = rude, rudeb = rude; gint fw, fh; Rect desired; + guint i; RECT_SET(desired, *x, *y, w, h); frame_rect_to_frame(self->frame, &desired); - all_a = screen_area(self->desktop, &desired); - mon_a = screen_area_monitor(self->desktop, screen_find_monitor(&desired), - &desired); - /* get where the frame would be */ frame_client_gravity(self->frame, x, y, w, h); @@ -943,30 +938,8 @@ gboolean client_find_onscreen(ObClient *self, gint *x, gint *y, gint w, gint h, fw = self->frame->size.left + w + self->frame->size.right; fh = self->frame->size.top + h + self->frame->size.bottom; - /* This makes sure windows aren't entirely outside of the screen so you - can't see them at all. - It makes sure 10% of the window is on the screen at least. At don't let - it move itself off the top of the screen, which would hide the titlebar - on you. (The user can still do this if they want too, it's only limiting - the application. - - XXX watch for xinerama dead areas... - */ - if (client_normal(self)) { - if (!self->strut.right && *x + fw/10 >= all_a->x + all_a->width - 1) - *x = all_a->x + all_a->width - fw/10; - if (!self->strut.bottom && *y + fh/10 >= all_a->y + all_a->height - 1) - *y = all_a->y + all_a->height - fh/10; - if (!self->strut.left && *x + fw*9/10 - 1 < all_a->x) - *x = all_a->x - fw*9/10; - if (!self->strut.top && *y + fh*9/10 - 1 < all_a->y) - *y = all_a->y - fw*9/10; - } - - /* If rudeness wasn't requested, then figure out of the client is currently - entirely on the screen. If it is, and the position isn't changing by - request, and it is enlarging, then be rude even though it wasn't - requested */ + /* If rudeness wasn't requested, then still be rude in a given direction + if the client is not moving, only resizing in that direction */ if (!rude) { Point oldtl, oldtr, oldbl, oldbr; Point newtl, newtr, newbl, newbr; @@ -1003,26 +976,52 @@ gboolean client_find_onscreen(ObClient *self, gint *x, gint *y, gint w, gint h, rudeb = TRUE; } - /* This here doesn't let windows even a pixel outside the struts/screen. - * When called from client_manage, programs placing themselves are - * forced completely onscreen, while things like - * xterm -geometry resolution-width/2 will work fine. Trying to - * place it completely offscreen will be handled in the above code. - * Sorry for this confused comment, i am tired. */ - if (rudel && !self->strut.left && *x < mon_a->x) *x = mon_a->x; - if (ruder && !self->strut.right && *x + fw > mon_a->x + mon_a->width) - *x = mon_a->x + MAX(0, mon_a->width - fw); + for (i = 0; i < screen_num_monitors; ++i) { + Rect *a; + + if (!screen_physical_area_monitor_contains(i, &desired)) + continue; + + a = screen_area(self->desktop, SCREEN_AREA_ONE_MONITOR, &desired); - if (rudet && !self->strut.top && *y < mon_a->y) *y = mon_a->y; - if (rudeb && !self->strut.bottom && *y + fh > mon_a->y + mon_a->height) - *y = mon_a->y + MAX(0, mon_a->height - fh); + /* This makes sure windows aren't entirely outside of the screen so you + can't see them at all. + It makes sure 10% of the window is on the screen at least. At don't + let it move itself off the top of the screen, which would hide the + titlebar on you. (The user can still do this if they want too, it's + only limiting the application. + */ + if (client_normal(self)) { + if (!self->strut.right && *x + fw/10 >= a->x + a->width - 1) + *x = a->x + a->width - fw/10; + if (!self->strut.bottom && *y + fh/10 >= a->y + a->height - 1) + *y = a->y + a->height - fh/10; + if (!self->strut.left && *x + fw*9/10 - 1 < a->x) + *x = a->x - fw*9/10; + if (!self->strut.top && *y + fh*9/10 - 1 < a->y) + *y = a->y - fw*9/10; + } + + /* This here doesn't let windows even a pixel outside the + struts/screen. When called from client_manage, programs placing + themselves are forced completely onscreen, while things like + xterm -geometry resolution-width/2 will work fine. Trying to + place it completely offscreen will be handled in the above code. + Sorry for this confused comment, i am tired. */ + if (rudel && !self->strut.left && *x < a->x) *x = a->x; + if (ruder && !self->strut.right && *x + fw > a->x + a->width) + *x = a->x + MAX(0, a->width - fw); + + if (rudet && !self->strut.top && *y < a->y) *y = a->y; + if (rudeb && !self->strut.bottom && *y + fh > a->y + a->height) + *y = a->y + MAX(0, a->height - fh); + + g_free(a); + } /* get where the client should be */ frame_frame_gravity(self->frame, x, y, w, h); - g_free(all_a); - g_free(mon_a); - return ox != *x || oy != *y; } @@ -1985,7 +1984,7 @@ void client_update_strut(ObClient *self) got = TRUE; /* use the screen's width/height */ - a = screen_physical_area(); + a = screen_physical_area_all_monitors(); STRUT_PARTIAL_SET(strut, data[0], data[2], data[1], data[3], @@ -2730,11 +2729,10 @@ void client_try_configure(ObClient *self, gint *x, gint *y, gint *w, gint *h, Rect *a; guint i; - i = screen_find_monitor(&desired); /* use all possible struts when maximizing to the full screen */ - a = screen_area_monitor(self->desktop, i, - (self->max_horz && self->max_vert ? - NULL : &desired)); + i = screen_find_monitor(&desired); + a = screen_area(self->desktop, i, + (self->max_horz && self->max_vert ? NULL : &desired)); /* set the size and position if maximized */ if (self->max_horz) { @@ -3876,14 +3874,13 @@ gint client_directional_edge_search(ObClient *c, ObDirection dir, gboolean hang) gint dest, monitor_dest; gint my_edge_start, my_edge_end, my_offset; GList *it; - Rect *a, *monitor; + Rect *a, *mon; if(!client_list) return -1; - a = screen_area(c->desktop, &c->frame->area); - monitor = screen_area_monitor(c->desktop, client_monitor(c), - &c->frame->area); + a = screen_area(c->desktop, SCREEN_AREA_ALL_MONITORS, &c->frame->area); + mon = screen_area(c->desktop, SCREEN_AREA_ONE_MONITOR, &c->frame->area); switch(dir) { case OB_DIRECTION_NORTH: @@ -3893,7 +3890,7 @@ gint client_directional_edge_search(ObClient *c, ObDirection dir, gboolean hang) /* default: top of screen */ dest = a->y + (hang ? c->frame->area.height : 0); - monitor_dest = monitor->y + (hang ? c->frame->area.height : 0); + monitor_dest = mon->y + (hang ? c->frame->area.height : 0); /* if the monitor edge comes before the screen edge, */ /* use that as the destination instead. (For xinerama) */ if (monitor_dest != dest && my_offset > monitor_dest) @@ -3926,7 +3923,7 @@ gint client_directional_edge_search(ObClient *c, ObDirection dir, gboolean hang) /* default: bottom of screen */ dest = a->y + a->height - (hang ? c->frame->area.height : 0); - monitor_dest = monitor->y + monitor->height - + monitor_dest = mon->y + mon->height - (hang ? c->frame->area.height : 0); /* if the monitor edge comes before the screen edge, */ /* use that as the destination instead. (For xinerama) */ @@ -3961,7 +3958,7 @@ gint client_directional_edge_search(ObClient *c, ObDirection dir, gboolean hang) /* default: leftmost egde of screen */ dest = a->x + (hang ? c->frame->area.width : 0); - monitor_dest = monitor->x + (hang ? c->frame->area.width : 0); + monitor_dest = mon->x + (hang ? c->frame->area.width : 0); /* if the monitor edge comes before the screen edge, */ /* use that as the destination instead. (For xinerama) */ if (monitor_dest != dest && my_offset > monitor_dest) @@ -3994,7 +3991,7 @@ gint client_directional_edge_search(ObClient *c, ObDirection dir, gboolean hang) /* default: rightmost edge of screen */ dest = a->x + a->width - (hang ? c->frame->area.width : 0); - monitor_dest = monitor->x + monitor->width - + monitor_dest = mon->x + mon->width - (hang ? c->frame->area.width : 0); /* if the monitor edge comes before the screen edge, */ /* use that as the destination instead. (For xinerama) */ @@ -4032,7 +4029,7 @@ gint client_directional_edge_search(ObClient *c, ObDirection dir, gboolean hang) } g_free(a); - g_free(monitor); + g_free(mon); return dest; } diff --git a/openbox/dock.c b/openbox/dock.c index c456ea75..c128e470 100644 --- a/openbox/dock.c +++ b/openbox/dock.c @@ -272,7 +272,7 @@ void dock_configure() dock->w += ob_rr_theme->obwidth * 2; dock->h += ob_rr_theme->obwidth * 2; - a = screen_physical_area(); + a = screen_physical_area_all_monitors(); /* calculate position */ if (config_dock_floating) { diff --git a/openbox/focus_cycle_popup.c b/openbox/focus_cycle_popup.c index 463eb9be..477619f5 100644 --- a/openbox/focus_cycle_popup.c +++ b/openbox/focus_cycle_popup.c @@ -251,7 +251,7 @@ static void popup_render(ObFocusCyclePopup *p, const ObClient *c) const ObFocusCyclePopupTarget *newtarget; gint newtargetx, newtargety; - screen_area = screen_physical_area_monitor_active(); + screen_area = screen_physical_area_active(); /* get the outside margins */ RrMargins(p->a_bg, &ml, &mt, &mr, &mb); @@ -506,7 +506,7 @@ void focus_cycle_popup_single_show(struct _ObClient *c, g_assert(popup.targets == NULL); /* position the popup */ - a = screen_physical_area_monitor_active(); + a = screen_physical_area_active(); icon_popup_position(single_popup, CenterGravity, a->x + a->width / 2, a->y + a->height / 2); icon_popup_height(single_popup, POPUP_HEIGHT); diff --git a/openbox/frame.c b/openbox/frame.c index 19ead3b9..6aae7a2a 100644 --- a/openbox/frame.c +++ b/openbox/frame.c @@ -1577,7 +1577,8 @@ static gboolean frame_animate_iconify(gpointer p) if (self->client->icon_geometry.width == 0) { /* there is no icon geometry set so just go straight down */ - Rect *a = screen_physical_area(); + Rect *a = screen_physical_area_monitor + (screen_find_monitor(&self->area)); iconx = self->area.x + self->area.width / 2 + 32; icony = a->y + a->width; iconw = 64; diff --git a/openbox/geom.h b/openbox/geom.h index c71dbc23..43eb8ea3 100644 --- a/openbox/geom.h +++ b/openbox/geom.h @@ -142,7 +142,7 @@ typedef struct _StrutPartial { (s1).bottom_start == (s2).bottom_start && \ (s1).bottom_end == (s2).bottom_end) -#define RANGE_INTERSECT(r1x, r1w, r2x, r2w) \ +#define RANGES_INTERSECT(r1x, r1w, r2x, r2w) \ (r1x < r2x + r2w && r1x + r1w > r2x) #endif diff --git a/openbox/keyboard.c b/openbox/keyboard.c index 7780753d..7fdd1870 100644 --- a/openbox/keyboard.c +++ b/openbox/keyboard.c @@ -98,7 +98,7 @@ static void set_curpos(KeyBindingTree *newpos) g_free(oldtext); } - a = screen_physical_area_monitor_active(); + a = screen_physical_area_active(); popup_position(popup, NorthWestGravity, a->x + 10, a->y + 10); /* 1 second delay for the popup to show */ popup_delay_show(popup, G_USEC_PER_SEC, text); diff --git a/openbox/mouse.c b/openbox/mouse.c index f74063ed..9e7ac648 100644 --- a/openbox/mouse.c +++ b/openbox/mouse.c @@ -210,6 +210,9 @@ void mouse_event(ObClient *client, XEvent *e) button = e->xbutton.button; state = e->xbutton.state; + if (CLIENT_CONTEXT(context, client)) + XAllowEvents(ob_display, ReplayPointer, event_curtime); + fire_binding(OB_MOUSE_ACTION_PRESS, context, client, e->xbutton.state, e->xbutton.button, diff --git a/openbox/place.c b/openbox/place.c index b6ede657..6f7d490d 100644 --- a/openbox/place.c +++ b/openbox/place.c @@ -53,7 +53,7 @@ static Rect *pick_pointer_head(ObClient *c) gboolean contain = RECT_CONTAINS(*monitor, px, py); g_free(monitor); if (contain) - return screen_area_monitor(c->desktop, i, NULL); + return screen_area(c->desktop, i, NULL); } g_assert_not_reached(); } @@ -131,7 +131,7 @@ static Rect **pick_head(ObClient *c) add_choice(choice, i); for (i = 0; i < screen_num_monitors; ++i) - area[i] = screen_area_monitor(c->desktop, choice[i], NULL); + area[i] = screen_area(c->desktop, choice[i], NULL); return area; } @@ -380,8 +380,8 @@ static gboolean place_per_app_setting(ObClient *client, gint *x, gint *y, screen = pick_pointer_head(client); else if (settings->monitor > 0 && (guint)settings->monitor <= screen_num_monitors) - screen = screen_area_monitor(client->desktop, - (guint)settings->monitor - 1, NULL); + screen = screen_area(client->desktop, (guint)settings->monitor - 1, + NULL); else { Rect **areas; guint i; diff --git a/openbox/popup.c b/openbox/popup.c index 590c2946..f5072748 100644 --- a/openbox/popup.c +++ b/openbox/popup.c @@ -154,9 +154,10 @@ void popup_delay_show(ObPopup *self, gulong usec, gchar *text) gint emptyx, emptyy; /* empty space between elements */ gint textx, texty, textw, texth; gint iconx, icony, iconw, iconh; - Rect *area; + Rect *area, mon; - area = screen_physical_area(); + RECT_SET(mon, self->x, self->y, 1, 1); + area = screen_physical_area_monitor(screen_find_monitor(&mon)); /* when there is no icon and the text is not parent relative, then fill the whole dialog with the text appearance, don't use the bg at all diff --git a/openbox/resist.c b/openbox/resist.c index e4596840..3ab04a98 100644 --- a/openbox/resist.c +++ b/openbox/resist.c @@ -152,7 +152,8 @@ void resist_move_monitors(ObClient *c, gint resist, gint *x, gint *y) continue; } - area = screen_area_monitor(c->desktop, i, &desired_area); + area = screen_area(c->desktop, SCREEN_AREA_ALL_MONITORS, + &desired_area); al = RECT_LEFT(*area); at = RECT_TOP(*area); @@ -307,7 +308,8 @@ void resist_size_monitors(ObClient *c, gint resist, gint *w, gint *h, continue; } - area = screen_area_monitor(c->desktop, i, &desired_area); + area = screen_area(c->desktop, SCREEN_AREA_ALL_MONITORS, + &desired_area); /* get the screen boundaries */ al = RECT_LEFT(*area); diff --git a/openbox/screen.c b/openbox/screen.c index 9f92efc8..0563148e 100644 --- a/openbox/screen.c +++ b/openbox/screen.c @@ -67,10 +67,11 @@ Time screen_desktop_user_time = CurrentTime; /*! An array of desktops, holding array of areas per monitor */ static Rect *monitor_area; -static GSList *struts_top; -static GSList *struts_left; -static GSList *struts_right; -static GSList *struts_bottom; +/*! An array of desktops, holding an array of struts */ +static GSList **struts_top; +static GSList **struts_left; +static GSList **struts_right; +static GSList **struts_bottom; static ObPagerPopup *desktop_cycle_popup; @@ -730,7 +731,7 @@ void screen_desktop_popup(guint d, gboolean show) if (!show) { pager_popup_hide(desktop_cycle_popup); } else { - a = screen_physical_area_monitor_active(); + a = screen_physical_area_active(); pager_popup_position(desktop_cycle_popup, CenterGravity, a->x + a->width / 2, a->y + a->height / 2); pager_popup_icon_size_multiplier(desktop_cycle_popup, @@ -1083,6 +1084,30 @@ void screen_install_colormap(ObClient *client, gboolean install) } } +#define STRUT_LEFT_ON_MONITOR(s, i) \ + (RANGES_INTERSECT(s->left_start, s->left_end - s->left_start + 1, \ + monitor_area[i].y, monitor_area[i].height)) +#define STRUT_RIGHT_ON_MONITOR(s, i) \ + (RANGES_INTERSECT(s->right_start, s->right_end - s->right_start + 1, \ + monitor_area[i].y, monitor_area[i].height)) +#define STRUT_TOP_ON_MONITOR(s, i) \ + (RANGES_INTERSECT(s->top_start, s->top_end - s->top_start + 1, \ + monitor_area[i].x, monitor_area[i].width)) +#define STRUT_BOTTOM_ON_MONITOR(s, i) \ + (RANGES_INTERSECT(s->bottom_start, s->bottom_end - s->bottom_start + 1, \ + monitor_area[i].x, monitor_area[i].width)) + +#define RESET_STRUT_LIST(sl) \ + {for (i = 0; sl[i]; ++i) \ + g_slist_free(sl[i]); \ + sl = g_renew(GSList*, sl, screen_num_desktops + 1); \ + sl[screen_num_desktops] = NULL;} /* null terminated */ + +#define ADD_STRUT_TO_LIST(sl, d, s) \ + {for (i = 0; i < screen_num_desktops; ++i) \ + if (i == d || d == DESKTOP_ALL) \ + sl[i] = g_slist_prepend(sl[i], s);} + void screen_update_areas() { guint i, j; @@ -1097,31 +1122,31 @@ void screen_update_areas() dims = g_new(gulong, 4 * screen_num_desktops * screen_num_monitors); - g_slist_free(struts_left); struts_left = NULL; - g_slist_free(struts_top); struts_top = NULL; - g_slist_free(struts_right); struts_right = NULL; - g_slist_free(struts_bottom); struts_bottom = NULL; + RESET_STRUT_LIST(struts_left); + RESET_STRUT_LIST(struts_top); + RESET_STRUT_LIST(struts_right); + RESET_STRUT_LIST(struts_bottom); /* collect the struts */ for (it = client_list; it; it = g_list_next(it)) { ObClient *c = it->data; if (c->strut.left) - struts_left = g_slist_prepend(struts_left, &c->strut); + ADD_STRUT_TO_LIST(struts_left, c->desktop, &c->strut); if (c->strut.top) - struts_top = g_slist_prepend(struts_top, &c->strut); + ADD_STRUT_TO_LIST(struts_top, c->desktop, &c->strut); if (c->strut.right) - struts_right = g_slist_prepend(struts_right, &c->strut); + ADD_STRUT_TO_LIST(struts_right, c->desktop, &c->strut); if (c->strut.bottom) - struts_bottom = g_slist_prepend(struts_bottom, &c->strut); + ADD_STRUT_TO_LIST(struts_bottom, c->desktop, &c->strut); } if (dock_strut.left) - struts_left = g_slist_prepend(struts_left, &dock_strut); + ADD_STRUT_TO_LIST(struts_left, DESKTOP_ALL, &dock_strut); if (dock_strut.top) - struts_top = g_slist_prepend(struts_top, &dock_strut); + ADD_STRUT_TO_LIST(struts_top, DESKTOP_ALL, &dock_strut); if (dock_strut.right) - struts_right = g_slist_prepend(struts_right, &dock_strut); + ADD_STRUT_TO_LIST(struts_right, DESKTOP_ALL, &dock_strut); if (dock_strut.bottom) - struts_bottom = g_slist_prepend(struts_bottom, &dock_strut); + ADD_STRUT_TO_LIST(struts_bottom, DESKTOP_ALL, &dock_strut); /* set up the work areas to be full screen */ for (i = 0; i < screen_num_monitors; ++i) @@ -1139,32 +1164,24 @@ void screen_update_areas() /* only add the strut to the area if it touches the monitor */ - for (sit = struts_left; sit; sit = g_slist_next(sit)) { + for (sit = struts_left[j]; sit; sit = g_slist_next(sit)) { StrutPartial *s = sit->data; - if (RANGE_INTERSECT - (s->left_start, s->left_end - s->left_start + 1, - monitor_area[i].y, monitor_area[i].height)) + if (STRUT_LEFT_ON_MONITOR(s, i)) l = MAX(l, s->left); } - for (sit = struts_top; sit; sit = g_slist_next(sit)) { + for (sit = struts_top[j]; sit; sit = g_slist_next(sit)) { StrutPartial *s = sit->data; - if (RANGE_INTERSECT - (s->top_start, s->top_end - s->top_start + 1, - monitor_area[i].x, monitor_area[i].width)) + if (STRUT_TOP_ON_MONITOR(s, i)) t = MAX(t, s->top); } - for (sit = struts_right; sit; sit = g_slist_next(sit)) { + for (sit = struts_right[j]; sit; sit = g_slist_next(sit)) { StrutPartial *s = sit->data; - if (RANGE_INTERSECT - (s->right_start, s->right_end - s->right_start + 1, - monitor_area[i].y, monitor_area[i].height)) + if (STRUT_RIGHT_ON_MONITOR(s, i)) r = MAX(r, s->right); } - for (sit = struts_bottom; sit; sit = g_slist_next(sit)) { + for (sit = struts_bottom[j]; sit; sit = g_slist_next(sit)) { StrutPartial *s = sit->data; - if (RANGE_INTERSECT - (s->bottom_start, s->bottom_end - s->bottom_start + 1, - monitor_area[i].x, monitor_area[i].width)) + if (STRUT_BOTTOM_ON_MONITOR(s, i)) b = MAX(b, s->bottom); } @@ -1198,16 +1215,17 @@ void screen_update_areas() g_free(dims); } -Rect* screen_area(guint desktop, Rect *search) +#if 0 +Rect* screen_area_all_monitors(guint desktop) { guint i; Rect *a; - a = screen_area_monitor(desktop, 0, search); + a = screen_area_monitor(desktop, 0); /* combine all the monitors together */ - for (i = 0; i < screen_num_monitors; ++i) { - Rect *m = screen_area_monitor(desktop, i, search); + for (i = 1; i < screen_num_monitors; ++i) { + Rect *m = screen_area_monitor(desktop, i); gint l, r, t, b; l = MIN(RECT_LEFT(*a), RECT_LEFT(*m)); @@ -1222,55 +1240,134 @@ Rect* screen_area(guint desktop, Rect *search) return a; } +#endif -Rect* screen_area_monitor(guint desktop, guint head, Rect *search) +#define STRUT_LEFT_IN_SEARCH(s, search) \ + (RANGES_INTERSECT(search->y, search->height, \ + s->left_start, s->left_end - s->left_start + 1)) +#define STRUT_RIGHT_IN_SEARCH(s, search) \ + (RANGES_INTERSECT(search->y, search->height, \ + s->right_start, s->right_end - s->right_start + 1)) +#define STRUT_TOP_IN_SEARCH(s, search) \ + (RANGES_INTERSECT(search->x, search->width, \ + s->top_start, s->top_end - s->top_start + 1)) +#define STRUT_BOTTOM_IN_SEARCH(s, search) \ + (RANGES_INTERSECT(search->x, search->width, \ + s->bottom_start, s->bottom_end - s->bottom_start + 1)) + +#define STRUT_LEFT_IGNORE(s, us, search) \ + (head != SCREEN_AREA_ALL_MONITORS || !us || \ + RECT_LEFT(monitor_area[i]) + s->left > RECT_LEFT(*search)) +#define STRUT_RIGHT_IGNORE(s, us, search) \ + (head != SCREEN_AREA_ALL_MONITORS || !us || \ + RECT_RIGHT(monitor_area[i]) - s->right < RECT_RIGHT(*search)) +#define STRUT_TOP_IGNORE(s, us, search) \ + (head != SCREEN_AREA_ALL_MONITORS || !us || \ + RECT_TOP(monitor_area[i]) + s->top > RECT_TOP(*search)) +#define STRUT_BOTTOM_IGNORE(s, us, search) \ + (head != SCREEN_AREA_ALL_MONITORS || !us || \ + RECT_BOTTOM(monitor_area[i]) - s->bottom < RECT_BOTTOM(*search)) + +Rect* screen_area(guint desktop, guint head, Rect *search) { Rect *a; GSList *it; - gint l, r, t, b; + gint l, r, t, b, al, ar, at, ab; + guint i, d; + gboolean us = search != NULL; /* user provided search */ - g_assert(head < screen_num_monitors); + g_assert(desktop < screen_num_desktops || desktop == DESKTOP_ALL); + g_assert(head < screen_num_monitors || head == SCREEN_AREA_ONE_MONITOR || + head == SCREEN_AREA_ALL_MONITORS); + g_assert(!(head == SCREEN_AREA_ONE_MONITOR && search == NULL)); - /* get the base area for the monitor */ - a = g_new(Rect, 1); - *a = monitor_area[head]; + /* find any struts for this monitor + which will be affecting the search area. + */ - /* remove any struts which will be affecting the search area */ - l = t = r = b = 0; - for (it = struts_left; it; it = g_slist_next(it)) { - StrutPartial *s = it->data; - if (!search || - RANGE_INTERSECT(search->y, search->height, - s->left_start, s->left_end - s->left_start + 1)) - l = MAX(l, s->left); - } - for (it = struts_right; it; it = g_slist_next(it)) { - StrutPartial *s = it->data; - if (!search || - RANGE_INTERSECT(search->y, search->height, - s->right_start, s->right_end - s->right_start + 1)) - r = MAX(r, s->right); + /* search everything if search is null */ + if (!search) { + if (head < screen_num_monitors) search = &monitor_area[head]; + else search = &monitor_area[screen_num_monitors]; } - for (it = struts_top; it; it = g_slist_next(it)) { - StrutPartial *s = it->data; - if (!search || - RANGE_INTERSECT(search->x, search->width, - s->top_start, s->top_end - s->top_start + 1)) - t = MAX(t, s->top); + if (head == SCREEN_AREA_ONE_MONITOR) head = screen_find_monitor(search); + + /* al is "all left" meaning the furthest left you can get, l is our + "working left" meaning our current strut edge which we're calculating + */ + + /* only include monitors which the search area lines up with */ + if (RECT_INTERSECTS_RECT(monitor_area[screen_num_monitors], *search)) { + al = l = RECT_RIGHT(monitor_area[screen_num_monitors]); + at = t = RECT_BOTTOM(monitor_area[screen_num_monitors]); + ar = r = RECT_LEFT(monitor_area[screen_num_monitors]); + ab = b = RECT_TOP(monitor_area[screen_num_monitors]); + for (i = 0; i < screen_num_monitors; ++i) { + if (RANGES_INTERSECT(search->x, search->width, + monitor_area[i].x, monitor_area[i].width) || + RANGES_INTERSECT(search->y, search->height, + monitor_area[i].y, monitor_area[i].height)) + { + /* add the monitor */ + al = l = MIN(l, RECT_LEFT(monitor_area[i])); + at = t = MIN(t, RECT_TOP(monitor_area[i])); + ar = r = MAX(r, RECT_RIGHT(monitor_area[i])); + ab = b = MAX(b, RECT_BOTTOM(monitor_area[i])); + } + } + } else { + al = l = RECT_LEFT(monitor_area[screen_num_monitors]); + at = t = RECT_TOP(monitor_area[screen_num_monitors]); + ar = r = RECT_RIGHT(monitor_area[screen_num_monitors]); + ab = b = RECT_BOTTOM(monitor_area[screen_num_monitors]); } - for (it = struts_bottom; it; it = g_slist_next(it)) { - StrutPartial *s = it->data; - if (!search || - RANGE_INTERSECT(search->x, search->width, - s->bottom_start, - s->bottom_end - s->bottom_start + 1)) - b = MAX(b, s->bottom); + + for (d = 0; d < screen_num_desktops; ++d) { + if (d != desktop && desktop != DESKTOP_ALL) continue; + + for (i = 0; i < screen_num_monitors; ++i) { + if (head != SCREEN_AREA_ALL_MONITORS && head != i) continue; + + for (it = struts_left[d]; it; it = g_slist_next(it)) { + StrutPartial *s = it->data; + if (STRUT_LEFT_IN_SEARCH(s, search) && + !STRUT_LEFT_IGNORE(s, us, search)) + l = MAX(l, al + s->left); + } + for (it = struts_top[d]; it; it = g_slist_next(it)) { + StrutPartial *s = it->data; + if (STRUT_TOP_IN_SEARCH(s, search) && + !STRUT_TOP_IGNORE(s, us, search)) + t = MAX(t, al + s->top); + } + for (it = struts_right[d]; it; it = g_slist_next(it)) { + StrutPartial *s = it->data; + if (STRUT_RIGHT_IN_SEARCH(s, search) && + !STRUT_RIGHT_IGNORE(s, us, search)) + r = MIN(r, ar - s->right); + } + for (it = struts_bottom[d]; it; it = g_slist_next(it)) { + StrutPartial *s = it->data; + if (STRUT_BOTTOM_IN_SEARCH(s, search) && + !STRUT_BOTTOM_IGNORE(s, us, search)) + r = MIN(r, ar - s->bottom); + } + + /* limit to this monitor */ + if (head == i) { + l = MAX(l, RECT_LEFT(monitor_area[i])); + t = MAX(t, RECT_TOP(monitor_area[i])); + r = MIN(r, RECT_RIGHT(monitor_area[i])); + b = MIN(b, RECT_BOTTOM(monitor_area[i])); + } + } } - a->x += l; - a->y += t; - a->width -= l + r; - a->height -= t + b; + a = g_new(Rect, 1); + a->x = l; + a->y = t; + a->width = r - l + 1; + a->height = b - t + 1; return a; } @@ -1299,7 +1396,7 @@ guint screen_find_monitor(Rect *search) return most; } -Rect* screen_physical_area() +Rect* screen_physical_area_all_monitors() { return screen_physical_area_monitor(screen_num_monitors); } @@ -1314,7 +1411,14 @@ Rect* screen_physical_area_monitor(guint head) return a; } -Rect* screen_physical_area_monitor_active() +gboolean screen_physical_area_monitor_contains(guint head, Rect *search) +{ + g_assert(head <= screen_num_monitors); + g_assert(search); + return RECT_INTERSECTS_RECT(monitor_area[head], *search); +} + +Rect* screen_physical_area_active() { Rect *a; gint x, y; diff --git a/openbox/screen.h b/openbox/screen.h index d6435fef..6ad18195 100644 --- a/openbox/screen.h +++ b/openbox/screen.h @@ -94,15 +94,24 @@ void screen_install_colormap(struct _ObClient *client, gboolean install); void screen_update_areas(); -Rect *screen_physical_area(); +Rect *screen_physical_area_all_monitors(); Rect *screen_physical_area_monitor(guint head); -Rect *screen_physical_area_monitor_active(); +Rect *screen_physical_area_active(); -Rect *screen_area(guint desktop, Rect *search); +/* doesn't include struts which the search area is already outside of when + 'search' is not NULL */ +#define SCREEN_AREA_ALL_MONITORS ((unsigned)-1) +#define SCREEN_AREA_ONE_MONITOR ((unsigned)-2) -Rect *screen_area_monitor(guint desktop, guint head, Rect *search); +/*! @param head is the number of the head or one of SCREEN_AREA_ALL_MONITORS, + SCREEN_AREA_ONE_MONITOR + @param search NULL or the whole monitor(s) + */ +Rect* screen_area(guint desktop, guint head, Rect *search); + +gboolean screen_physical_area_monitor_contains(guint head, Rect *search); /*! Determines which physical monitor a rectangle is on by calculating the area of the part of the rectable on each monitor. The number of the -- 2.39.2