]> Dogcows Code - chaz/openbox/blobdiff - openbox/screen.c
check for damage and render extensions if going to use composite. require them for...
[chaz/openbox] / openbox / screen.c
index 613f774f71d03e2b2cafd8c6e8710d75f814d12a..1ef080752dbfdb50a885b10e27f83d7b3a39a23a 100644 (file)
@@ -66,11 +66,12 @@ Window   screen_support_win;
 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;
+static Rect  *monitor_area = NULL;
+/*! An array of desktops, holding an array of struts */
+static GSList *struts_top = NULL;
+static GSList *struts_left = NULL;
+static GSList *struts_right = NULL;
+static GSList *struts_bottom = NULL;
 
 static ObPagerPopup *desktop_cycle_popup;
 
@@ -363,6 +364,15 @@ void screen_startup(gboolean reconfig)
         return;
     }
 
+#ifdef USE_XCOMPOSITE
+    if (extensions_comp) {
+        /* Redirect window contents to offscreen pixmaps */
+        XCompositeRedirectSubwindows(ob_display,
+                                     RootWindow(ob_display, ob_screen),
+                                     CompositeRedirectAutomatic);
+    }
+#endif
+
     /* get the initial size */
     screen_resize();
 
@@ -495,7 +505,7 @@ void screen_set_num_desktops(guint num)
 {
     guint old;
     gulong *viewport;
-    GList *it;
+    GList *it, *stacking_copy;
 
     g_assert(num > 0);
 
@@ -515,11 +525,21 @@ void screen_set_num_desktops(guint num)
     /* the number of rows/columns will differ */
     screen_update_layout();
 
-    /* move windows on desktops that will no longer exist! */
-    for (it = client_list; it; it = g_list_next(it)) {
-        ObClient *c = it->data;
-        if (c->desktop >= num && c->desktop != DESKTOP_ALL)
-            client_set_desktop(c, num - 1, FALSE);
+    /* move windows on desktops that will no longer exist!
+       make a copy of the list cuz we're changing it */
+    stacking_copy = g_list_copy(stacking_list);
+    for (it = g_list_last(stacking_copy); it; it = g_list_previous(it)) {
+        if (WINDOW_IS_CLIENT(it->data)) {
+            ObClient *c = it->data;
+            if (c->desktop != DESKTOP_ALL && c->desktop >= num)
+                client_set_desktop(c, num - 1, FALSE, TRUE);
+            /* raise all the windows that are on the current desktop which
+               is being merged */
+            else if (screen_desktop == num - 1 &&
+                     (c->desktop == DESKTOP_ALL ||
+                      c->desktop == screen_desktop))
+                stacking_raise(WINDOW_AS_CLIENT(c));
+        }
     }
  
     /* change our struts/area to match (after moving windows) */
@@ -560,7 +580,7 @@ void screen_set_desktop(guint num, gboolean dofocus)
     ignore_start = event_start_ignore_all_enters();
 
     if (moveresize_client)
-        client_set_desktop(moveresize_client, num, TRUE);
+        client_set_desktop(moveresize_client, num, TRUE, FALSE);
 
     /* show windows before hiding the rest to lessen the enter/leave events */
 
@@ -578,6 +598,11 @@ void screen_set_desktop(guint num, gboolean dofocus)
     allow_omni = focus_client && (client_normal(focus_client) &&
                                   focus_client->desktop == DESKTOP_ALL);
 
+    /* the client moved there already so don't move focus. prevent flicker
+       on sendtodesktop + follow */
+    if (focus_client && focus_client->desktop == screen_desktop)
+        dofocus = FALSE;
+
     /* have to try focus here because when you leave an empty desktop
        there is no focus out to watch for. also, we have different rules
        here. we always allow it to look under the mouse pointer if
@@ -730,7 +755,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 +1108,35 @@ 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))
+
+typedef struct {
+    guint desktop;
+    StrutPartial *strut;
+} ObScreenStrut;
+
+#define RESET_STRUT_LIST(sl) \
+    (g_slist_free(sl), sl = NULL)
+
+#define ADD_STRUT_TO_LIST(sl, d, s) \
+{ \
+    ObScreenStrut *ss = g_new(ObScreenStrut, 1); \
+    ss->desktop = d; \
+    ss->strut = s;  \
+    sl = g_slist_prepend(sl, ss); \
+}
+
 void screen_update_areas()
 {
     guint i, j;
@@ -1097,39 +1151,39 @@ 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)
         for (j = 0; j < screen_num_desktops; ++j) {
-            dims[i * j + 0] = monitor_area[i].x;
-            dims[i * j + 1] = monitor_area[i].y;
-            dims[i * j + 2] = monitor_area[i].width;
-            dims[i * j + 3] = monitor_area[i].height;
+            dims[(i * screen_num_desktops + j) * 4+0] = monitor_area[i].x;
+            dims[(i * screen_num_desktops + j) * 4+1] = monitor_area[i].y;
+            dims[(i * screen_num_desktops + j) * 4+2] = monitor_area[i].width;
+            dims[(i * screen_num_desktops + j) * 4+3] = monitor_area[i].height;
         }
 
     /* calculate the work areas from the struts */
@@ -1140,74 +1194,59 @@ 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)) {
-                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))
-                    l = MAX(l, s->left);
+                ObScreenStrut *s = sit->data;
+                if ((s->desktop == j || s->desktop == DESKTOP_ALL) &&
+                    STRUT_LEFT_ON_MONITOR(s->strut, i))
+                    l = MAX(l, s->strut->left);
             }
             for (sit = struts_top; 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))
-                    t = MAX(t, s->top);
+                ObScreenStrut *s = sit->data;
+                if ((s->desktop == j || s->desktop == DESKTOP_ALL) &&
+                    STRUT_TOP_ON_MONITOR(s->strut, i))
+                    t = MAX(t, s->strut->top);
             }
             for (sit = struts_right; 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))
-                    r = MAX(r, s->right);
+                ObScreenStrut *s = sit->data;
+                if ((s->desktop == j || s->desktop == DESKTOP_ALL) &&
+                    STRUT_RIGHT_ON_MONITOR(s->strut, i))
+                    r = MAX(r, s->strut->right);
             }
             for (sit = struts_bottom; 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))
-                    b = MAX(b, s->bottom);
+                ObScreenStrut *s = sit->data;
+                if ((s->desktop == j || s->desktop == DESKTOP_ALL) &&
+                    STRUT_BOTTOM_ON_MONITOR(s->strut, i))
+                    b = MAX(b, s->strut->bottom);
             }
 
             /* based on these margins, set the work area for the
                monitor/desktop */
-            dims[i * j + 0] += l;
-            dims[i * j + 1] += t;
-            dims[i * j + 2] -= l + r;
-            dims[i * j + 3] -= t + b;
+            dims[(i * screen_num_desktops + j) * 4 + 0] += l;
+            dims[(i * screen_num_desktops + j) * 4 + 1] += t;
+            dims[(i * screen_num_desktops + j) * 4 + 2] -= l + r;
+            dims[(i * screen_num_desktops + j) * 4 + 3] -= t + b;
         }
 
     PROP_SETA32(RootWindow(ob_display, ob_screen), net_workarea, cardinal,
                 dims, 4 * screen_num_desktops * screen_num_monitors);
 
     /* the area has changed, adjust all the windows if they need it */
-    for (it = client_list; it; it = g_list_next(it)) {
-        gint x, y, w, h, lw, lh;
-        ObClient *client = it->data;
-
-        RECT_TO_DIMS(client->area, x, y, w, h);
-        client_try_configure(client, &x, &y, &w, &h, &lw, &lh, FALSE);
-        if (!RECT_EQUAL_DIMS(client->area, x, y, w, h)) {
-            gulong ignore_start;
-
-            ignore_start = event_start_ignore_all_enters();
-            client_configure(client, x, y, w, h, FALSE, TRUE);
-            event_end_ignore_all_enters(ignore_start);
-        }
-    }
+    for (it = client_list; it; it = g_list_next(it))
+        client_reconfigure(it->data, FALSE);
 
     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 +1261,140 @@ 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);
+    /* 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_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);
-    }
-    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) {
+            /* add the monitor if applicable */
+            if (RANGES_INTERSECT(search->x, search->width,
+                                 monitor_area[i].x, monitor_area[i].width))
+            {
+                at = t = MIN(t, RECT_TOP(monitor_area[i]));
+                ab = b = MAX(b, RECT_BOTTOM(monitor_area[i]));
+            }
+            if (RANGES_INTERSECT(search->y, search->height,
+                                 monitor_area[i].y, monitor_area[i].height))
+            {
+                al = l = MIN(l, RECT_LEFT(monitor_area[i]));
+                ar = r = MAX(r, RECT_RIGHT(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; it; it = g_slist_next(it)) {
+                ObScreenStrut *s = it->data;
+                if ((s->desktop == d || s->desktop == DESKTOP_ALL) &&
+                    STRUT_LEFT_IN_SEARCH(s->strut, search) &&
+                    !STRUT_LEFT_IGNORE(s->strut, us, search))
+                    l = MAX(l, al + s->strut->left);
+            }
+            for (it = struts_top; it; it = g_slist_next(it)) {
+                ObScreenStrut *s = it->data;
+                if ((s->desktop == d || s->desktop == DESKTOP_ALL) &&
+                    STRUT_TOP_IN_SEARCH(s->strut, search) &&
+                    !STRUT_TOP_IGNORE(s->strut, us, search))
+                    t = MAX(t, at + s->strut->top);
+            }
+            for (it = struts_right; it; it = g_slist_next(it)) {
+                ObScreenStrut *s = it->data;
+                if ((s->desktop == d || s->desktop == DESKTOP_ALL) &&
+                    STRUT_RIGHT_IN_SEARCH(s->strut, search) &&
+                    !STRUT_RIGHT_IGNORE(s->strut, us, search))
+                    r = MIN(r, ar - s->strut->right);
+            }
+            for (it = struts_bottom; it; it = g_slist_next(it)) {
+                ObScreenStrut *s = it->data;
+                if ((s->desktop == d || s->desktop == DESKTOP_ALL) &&
+                    STRUT_BOTTOM_IN_SEARCH(s->strut, search) &&
+                    !STRUT_BOTTOM_IGNORE(s->strut, us, search))
+                    b = MIN(b, ab - s->strut->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 +1423,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 +1438,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;
This page took 0.036905 seconds and 4 git commands to generate.