make keeping windows on screen much more clever

This commit is contained in:
Dana Jansens 2007-05-02 02:03:06 +00:00
parent 0da9aa2660
commit 97cbacd9e4
3 changed files with 67 additions and 38 deletions

View 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 client_find_onscreen(ObClient *self, gint *x, gint *y, gint w, gint h,
gboolean rude) gboolean rude)
{ {
Rect *a; Rect *mon_a, *all_a;
gint ox = *x, oy = *y; 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 */ /* get where the frame would be */
frame_client_gravity(self->frame, x, y, w, h); 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 /* This makes sure windows aren't entirely outside of the screen so you
can't see them at all. can't see them at all.
It makes sure 10% of the window is on the screen at least. At don't let 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 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 on you. (The user can still do this if they want too, it's only limiting
the application. the application.
XXX watch for xinerama dead areas...
*/ */
if (client_normal(self)) { if (client_normal(self)) {
a = screen_area(self->desktop); if (!self->strut.right && *x + fw/10 >= all_a->x + all_a->width - 1)
if (!self->strut.right && *x = all_a->x + all_a->width - fw/10;
*x + self->frame->area.width/10 >= a->x + a->width - 1) if (!self->strut.bottom && *y + fh/10 >= all_a->y + all_a->height - 1)
*x = a->x + a->width - self->frame->area.width/10; *y = all_a->y + all_a->height - fh/10;
if (!self->strut.bottom && if (!self->strut.left && *x + fw*9/10 - 1 < all_a->x)
*y + self->frame->area.height/10 >= a->y + a->height - 1) *x = all_a->x - fw*9/10;
*y = a->y + a->height - self->frame->area.height/10; if (!self->strut.top && *y + fh*9/10 - 1 < all_a->y)
if (!self->strut.left && *x + self->frame->area.width*9/10 - 1 < a->x) *y = all_a->y - fw*9/10;
*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 rudeness wasn't requested, then figure out of the client is currently /* 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 */ requested */
if (!rude) { if (!rude) {
a = screen_area_monitor(self->desktop, client_monitor(self)); Point oldtl, oldtr, oldbl, oldbr;
if (RECT_CONTAINS_RECT(*a, self->area)) Point newtl, newtr, newbl, newbr;
rude = TRUE; 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 screen, /* This here doesn't let windows even a pixel outside the struts/screen.
* when called from client_manage, programs placing themselves are * When called from client_manage, programs placing themselves are
* forced completely onscreen, while things like * forced completely onscreen, while things like
* xterm -geometry resolution-width/2 will work fine. Trying to * xterm -geometry resolution-width/2 will work fine. Trying to
* place it completely offscreen will be handled in the above code. * place it completely offscreen will be handled in the above code.
* Sorry for this confused comment, i am tired. */ * Sorry for this confused comment, i am tired. */
if (rude) { if (fw <= mon_a->width) {
/* avoid the xinerama monitor divide while we're at it, if (rudel && !self->strut.left && *x < mon_a->x) *x = mon_a->x;
* remember to fix the placement stuff to avoid it also and if (ruder && !self->strut.right && *x + fw > mon_a->x + mon_a->width)
* then remove this XXX */ *x = mon_a->x + mon_a->width - fw;
a = screen_area_monitor(self->desktop, client_monitor(self)); }
/* dont let windows map into the strut unless they if (fh <= mon_a->height) {
are bigger than the available area */ if (rudet && !self->strut.top && *y < mon_a->y) *y = mon_a->y;
if (w <= a->width) { if (rudeb && !self->strut.bottom && *y + fh > mon_a->y + mon_a->height)
if (!self->strut.left && *x < a->x) *x = a->x; *y = mon_a->y + mon_a->height - fh;
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;
}
} }
/* get where the client should be */ /* get where the client should be */

View file

@ -886,7 +886,7 @@ static void event_handle_client(ObClient *client, XEvent *e)
h = (e->xconfigurerequest.value_mask & CWHeight) ? h = (e->xconfigurerequest.value_mask & CWHeight) ?
e->xconfigurerequest.height : client->area.height; 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); 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; h = client->area.height;
client_convert_gravity(client, grav, &x, &y, w, h); 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); client_configure(client, x, y, w, h, FALSE, TRUE);
} }
break; break;

View file

@ -26,6 +26,7 @@ typedef struct _Point {
} Point; } Point;
#define POINT_SET(pt, nx, ny) (pt).x = (nx), (pt).y = (ny) #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 { typedef struct _Size {
int width; int width;