]> Dogcows Code - chaz/openbox/commitdiff
make keeping windows on screen much more clever
authorDana Jansens <danakj@orodu.net>
Wed, 2 May 2007 02:03:06 +0000 (02:03 +0000)
committerDana Jansens <danakj@orodu.net>
Wed, 2 May 2007 02:03:06 +0000 (02:03 +0000)
openbox/client.c
openbox/event.c
openbox/geom.h

index 3396796201c0b2bcb4e45f748a6777823cbffa62..5e1a78513992929a178fb871bfbffa0b89a1b3b2 100644 (file)
@@ -751,66 +751,94 @@ 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 *a;
+    Rect *mon_a, *all_a;
     gint ox = *x, oy = *y;
+    gboolean rudel = rude, ruder = rude, rudet = rude, rudeb = rude;
+    gint fw, fh;
+
+    all_a = screen_area(self->desktop);
+    mon_a = screen_area_monitor(self->desktop, client_monitor(self));
 
     /* get where the frame would be */
     frame_client_gravity(self->frame, x, y, w, h);
 
-    /* XXX watch for xinerama dead areas */
+    /* get the requested size of the window with decorations */
+    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)) {
-        a = screen_area(self->desktop);
-        if (!self->strut.right &&
-            *x + self->frame->area.width/10 >= a->x + a->width - 1)
-            *x = a->x + a->width - self->frame->area.width/10;
-        if (!self->strut.bottom &&
-            *y + self->frame->area.height/10 >= a->y + a->height - 1)
-            *y = a->y + a->height - self->frame->area.height/10;
-        if (!self->strut.left && *x + self->frame->area.width*9/10 - 1 < a->x)
-            *x = a->x - self->frame->area.width*9/10;
-        if (!self->strut.top && *y + self->frame->area.height*9/10 - 1 < a->y)
-            *y = a->y - self->frame->area.width*9/10;
+        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, then be rude even though it wasn't
+       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 (!rude) {
-        a = screen_area_monitor(self->desktop, client_monitor(self));
-        if (RECT_CONTAINS_RECT(*a, self->area))
-            rude = TRUE;
-    }
-
-    /* This here doesn't let windows even a pixel outside the screen,
-     * when called from client_manage, programs placing themselves are
+        Point oldtl, oldtr, oldbl, oldbr;
+        Point newtl, newtr, newbl, newbr;
+        gboolean stationary;
+
+        POINT_SET(oldtl, self->frame->area.x, self->frame->area.y);
+        POINT_SET(oldbr, self->frame->area.x + self->frame->area.width - 1,
+                  self->frame->area.y + self->frame->area.height - 1);
+        POINT_SET(oldtr, oldbr.x, oldtl.y);
+        POINT_SET(oldbl, oldtl.x, oldbr.y);
+
+        POINT_SET(newtl, *x, *y);
+        POINT_SET(newbr, *x + fw - 1, *y + fh - 1);
+        POINT_SET(newtr, newbr.x, newtl.y);
+        POINT_SET(newbl, newtl.x, newbr.y);
+
+        /* is it moving or just resizing from some corner? */
+        stationary = (POINT_EQUAL(oldtl, newtl) || POINT_EQUAL(oldtr, newtr) ||
+                      POINT_EQUAL(oldbl, newbl) || POINT_EQUAL(oldbr, newbr));
+
+        /* if left edge is growing */
+        if (stationary && newtl.x < oldtl.x)
+            rudel = TRUE;
+        /* if right edge is growing */
+        if (stationary && newtr.x > oldtr.x)
+            ruder = TRUE;
+        /* if top edge is growing */
+        if (stationary && newtl.y < oldtl.y)
+            rudet = TRUE;
+        /* if bottom edge is growing */
+        if (stationary && newbl.y > oldbl.y)
+            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 (rude) {
-        /* avoid the xinerama monitor divide while we're at it,
-         * remember to fix the placement stuff to avoid it also and
-         * then remove this XXX */
-        a = screen_area_monitor(self->desktop, client_monitor(self));
-        /* dont let windows map into the strut unless they
-           are bigger than the available area */
-        if (w <= a->width) {
-            if (!self->strut.left && *x < a->x) *x = a->x;
-            if (!self->strut.right && *x + w > a->x + a->width)
-                *x = a->x + a->width - w;
-        }
-        if (h <= a->height) {
-            if (!self->strut.top && *y < a->y) *y = a->y;
-            if (!self->strut.bottom && *y + h > a->y + a->height)
-                *y = a->y + a->height - h;
-        }
+    if (fw <= mon_a->width) {
+        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 + mon_a->width - fw;
+    }
+    if (fh <= mon_a->height) {
+        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 + mon_a->height - fh;
     }
 
     /* get where the client should be */
index 5d6b62bb0eb82ef6d6192910ca7f90be9b2fbca1..6b7f4c532c77eff1f624e8a7f69429b2715abe0f 100644 (file)
@@ -886,7 +886,7 @@ static void event_handle_client(ObClient *client, XEvent *e)
             h = (e->xconfigurerequest.value_mask & CWHeight) ?
                 e->xconfigurerequest.height : client->area.height;
 
-            client_find_onscreen(client, &x, &y, w, h, client_normal(client));
+            client_find_onscreen(client, &x, &y, w, h, FALSE);
             client_configure_full(client, x, y, w, h, FALSE, TRUE, TRUE);
         }
 
@@ -1074,7 +1074,7 @@ static void event_handle_client(ObClient *client, XEvent *e)
                 h = client->area.height;
 
             client_convert_gravity(client, grav, &x, &y, w, h);
-            client_find_onscreen(client, &x, &y, w, h, client_normal(client));
+            client_find_onscreen(client, &x, &y, w, h, FALSE);
             client_configure(client, x, y, w, h, FALSE, TRUE);
         }
         break;
index e9ecf9d266a515c72bd2b9acbe87a3cfeeb54942..39832e949050c5cbb78ff1e73264945a2dd5108e 100644 (file)
@@ -26,6 +26,7 @@ typedef struct _Point {
 } Point;
 
 #define POINT_SET(pt, nx, ny) (pt).x = (nx), (pt).y = (ny)
+#define POINT_EQUAL(p1, p2) ((p1).x == (p2).x && (p1).y == (p2).y)
 
 typedef struct _Size {
     int width;
This page took 0.029199 seconds and 4 git commands to generate.