xinerama support like crazy for struts and everything else too. this probably crashes...
authorDana Jansens <danakj@orodu.net>
Wed, 13 Jun 2007 11:15:51 +0000 (11:15 +0000)
committerDana Jansens <danakj@orodu.net>
Wed, 13 Jun 2007 11:15:51 +0000 (11:15 +0000)
13 files changed:
openbox/action.c
openbox/client.c
openbox/dock.c
openbox/focus_cycle_popup.c
openbox/frame.c
openbox/geom.h
openbox/keyboard.c
openbox/mouse.c
openbox/place.c
openbox/popup.c
openbox/resist.c
openbox/screen.c
openbox/screen.h

index 9d0f9c7..6ba52c8 100644 (file)
@@ -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 */
index 1ead992..d101340 100644 (file)
@@ -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;
 }
 
index c456ea7..c128e47 100644 (file)
@@ -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) {
index 463eb9b..477619f 100644 (file)
@@ -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);
index 19ead3b..6aae7a2 100644 (file)
@@ -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;
index c71dbc2..43eb8ea 100644 (file)
@@ -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
index 7780753..7fdd187 100644 (file)
@@ -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);
index f74063e..9e7ac64 100644 (file)
@@ -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,
index b6ede65..6f7d490 100644 (file)
@@ -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;
index 590c294..f507274 100644 (file)
@@ -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
index e459684..3ab04a9 100644 (file)
@@ -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);
index 9f92efc..0563148 100644 (file)
@@ -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;
index d6435fe..6ad1819 100644 (file)
@@ -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