From 97cbacd9e41ae2315434d6e83ce78502a881d54f Mon Sep 17 00:00:00 2001 From: Dana Jansens Date: Wed, 2 May 2007 02:03:06 +0000 Subject: [PATCH] make keeping windows on screen much more clever --- openbox/client.c | 104 ++++++++++++++++++++++++++++++----------------- openbox/event.c | 4 +- openbox/geom.h | 1 + 3 files changed, 69 insertions(+), 40 deletions(-) diff --git a/openbox/client.c b/openbox/client.c index 33967962..5e1a7851 100644 --- a/openbox/client.c +++ b/openbox/client.c @@ -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 */ diff --git a/openbox/event.c b/openbox/event.c index 5d6b62bb..6b7f4c53 100644 --- a/openbox/event.c +++ b/openbox/event.c @@ -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; diff --git a/openbox/geom.h b/openbox/geom.h index e9ecf9d2..39832e94 100644 --- a/openbox/geom.h +++ b/openbox/geom.h @@ -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; -- 2.44.0