]> Dogcows Code - chaz/openbox/commitdiff
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 9d0f9c739b76ed6d049cc8638632ee620e81ab41..6ba52c8959f13d140fbea9a3f5f0e1a7ae3adb08 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 1ead992c2d22ed9fedfa6d7b854c12136a71c02b..d10134023e6e42ad783c62ebf3061a64825677ff 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 c456ea7598d6c5e528fe8bd09e59a213a5fd7d40..c128e4704464fe08608446a4bb4699c1680e81c4 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 463eb9be6b97cfb44d8c8396e2012f52e8912fb4..477619f557c37afc448cc2abba1961cbb2d9672a 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 19ead3b991e4ff41d9380fbff31fe1f8997c5732..6aae7a2a15c8d56738ac80df9973b5bff93eff90 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 c71dbc239a79d2af83b21793d63e85ff612526a6..43eb8ea3ab128b598174cb2e4948af7e6b5e4d21 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 7780753d4ff4435a5f19f5c84c64d14924e26284..7fdd18704eee5cfed3483054d070b2446474b1ed 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 f74063edbbffc394bf8db31fb42dc889a4236b31..9e7ac6489843689eff3bad0b74e2ee5e290afce2 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 b6ede657f3c4711937a26b5d583be280c5889d75..6f7d490ddb79983f2622e9df3ee8392c8a5d257b 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 590c294666753c98ccd81a0b487f195029bef99a..f5072748734953f70dff767858596bab3ea6f232 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 e4596840f79ed7b93338d1c6c75a53acccf9160c..3ab04a98d5bc031f2446e4611adb945d276b1712 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 9f92efc8eacb88e67deebe2b1bcb6f772f68fda8..0563148e95a4e0ce56fcf57338d74e24e8720166 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 d6435fef12e93c630f8162e7ea517d529afb1a67..6ad181953bfe6f3e6b3edb07158f0504ce6aac71 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
This page took 0.059478 seconds and 4 git commands to generate.