make keeping windows on screen much more clever
This commit is contained in:
parent
0da9aa2660
commit
97cbacd9e4
3 changed files with 67 additions and 38 deletions
100
openbox/client.c
100
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 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 */
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in a new issue