self->window, newx, newy, self->area.width, self->area.height);
client_apply_startup_state(self, newx, newy);
- keyboard_grab_for_client(self, TRUE);
mouse_grab_for_client(self, TRUE);
if (activate) {
/* flush to send the hide to the server quickly */
XFlush(ob_display);
- if (focus_client == self) {
- /* ignore enter events from the unmap so it doesnt mess with the focus
- */
- event_ignore_queued_enters();
- }
+ /* ignore enter events from the unmap so it doesnt mess with the focus */
+ event_ignore_queued_enters();
- keyboard_grab_for_client(self, FALSE);
mouse_grab_for_client(self, FALSE);
/* remove the window from our save set */
/* update the focus lists */
focus_order_remove(self);
- /* don't leave an invalid focus_client */
- if (self == focus_client)
- focus_client = NULL;
+ if (client_focused(self)) {
+ /* we have to fall back here because we might not get a focus out.
+ 1. we need to xselectinput off the window before we unmap it because
+ otherwise we end up getting unmapnotifies we don't want and they
+ can mess up mapping it again quickly
+ 2. this means that if we unmanage from a synthetic unmapnotify, we
+ are the ones unmapped it, and causing the focusout. so we won't
+ get the focusout event.
+ 3. we can't handle focusin events on the root window because they
+ come from all screens, so the focus change gets lost
+
+ if this ever gets removed in the future MAKE SURE to replace it
+ with:
+ /- don't leave an invalid focus_client -/
+ focus_client = NULL;
+ */
+ focus_fallback(FALSE);
+ }
client_list = g_list_remove(client_list, self);
stacking_remove(self);
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;
- frame_client_gravity(self->frame, x, y); /* get where the frame
- would be */
+ 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);
+
+ /* 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;
- /* XXX watch for xinerama dead areas */
/* 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;
- }
-
- /* This here doesn't let windows even a pixel outside the screen,
- * when called from client_manage, programs placing themselves are
+ 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, and the position isn't changing by
+ request, and it is enlarging, then be rude even though it wasn't
+ requested */
+ if (!rude) {
+ 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;
}
- frame_frame_gravity(self->frame, x, y); /* get where the client
- should be */
+ /* get where the client should be */
+ frame_frame_gravity(self->frame, x, y, w, h);
return ox != *x || oy != *y;
}
/* remove from old parents */
for (it = self->group->members; it; it = g_slist_next(it)) {
ObClient *c = it->data;
- if (c != self && !c->transient_for)
+ if (c != self && (!c->transient_for ||
+ c->transient_for != OB_TRAN_GROUP))
c->transients = g_slist_remove(c->transients, self);
}
} else if (self->transient_for != NULL) { /* transient of window */
/* add to new parents */
for (it = self->group->members; it; it = g_slist_next(it)) {
ObClient *c = it->data;
- if (c != self && !c->transient_for)
+ if (c != self && (!c->transient_for ||
+ c->transient_for != OB_TRAN_GROUP))
c->transients = g_slist_append(c->transients, self);
}
if (self->frame && self->gravity != oldgravity) {
/* move our idea of the client's position based on its new
gravity */
- self->area.x = self->frame->area.x;
- self->area.y = self->frame->area.y;
- frame_frame_gravity(self->frame, &self->area.x, &self->area.y);
+ client_convert_gravity(self, oldgravity,
+ &self->area.x, &self->area.y,
+ self->area.width, self->area.height);
}
}
/* by making this pass FALSE for user, we avoid the emacs event storm where
every configurenotify causes an update in its normal hints, i think this
is generally what we want anyways... */
- client_configure(self, OB_CORNER_TOPLEFT, self->area.x, self->area.y,
+ client_configure(self, self->area.x, self->area.y,
self->area.width, self->area.height, FALSE, TRUE);
}
RrPixel32 *icon = ob_rr_theme->def_win_icon;
gulong *data;
- data = g_new(guint32, 48*48+2);
+ data = g_new(gulong, 48*48+2);
data[0] = data[1] = 48;
for (i = 0; i < 48*48; ++i)
data[i+2] = (((icon[i] >> RrDefaultAlphaOffset) & 0xff) << 24) +
*/
}
-void client_try_configure(ObClient *self, ObCorner anchor,
- gint *x, gint *y, gint *w, gint *h,
+void client_convert_gravity(ObClient *self, gint gravity, gint *x, gint *y,
+ gint w, gint h)
+{
+ gint oldg = self->gravity;
+
+ /* get the frame's position from the requested stuff */
+ self->gravity = gravity;
+ frame_client_gravity(self->frame, x, y, w, h);
+ self->gravity = oldg;
+
+ /* get the client's position in its true gravity from that */
+ frame_frame_gravity(self->frame, x, y, w, h);
+}
+
+void client_try_configure(ObClient *self, gint *x, gint *y, gint *w, gint *h,
gint *logicalw, gint *logicalh,
gboolean user)
{
}
/* gets the frame's position */
- frame_client_gravity(self->frame, x, y);
+ frame_client_gravity(self->frame, x, y, *w, *h);
/* these positions are frame positions, not client positions */
}
/* gets the client's position */
- frame_frame_gravity(self->frame, x, y);
+ frame_frame_gravity(self->frame, x, y, *w, *h);
/* these override the above states! if you cant move you can't move! */
if (user) {
g_assert(*w > 0);
g_assert(*h > 0);
-
- switch (anchor) {
- case OB_CORNER_TOPLEFT:
- break;
- case OB_CORNER_TOPRIGHT:
- *x -= *w - self->area.width;
- break;
- case OB_CORNER_BOTTOMLEFT:
- *y -= *h - self->area.height;
- break;
- case OB_CORNER_BOTTOMRIGHT:
- *x -= *w - self->area.width;
- *y -= *h - self->area.height;
- break;
- }
}
-void client_configure_full(ObClient *self, ObCorner anchor,
- gint x, gint y, gint w, gint h,
+void client_configure_full(ObClient *self, gint x, gint y, gint w, gint h,
gboolean user, gboolean final,
gboolean force_reply)
{
gint logicalw, logicalh;
/* find the new x, y, width, and height (and logical size) */
- client_try_configure(self, anchor, &x, &y, &w, &h,
- &logicalw, &logicalh, user);
+ client_try_configure(self, &x, &y, &w, &h, &logicalw, &logicalh, user);
/* set the logical size if things changed */
if (!(w == self->area.width && h == self->area.height))
/* if the client is enlarging, then resize the client before the frame */
if (send_resize_client && user && (w > oldw || h > oldh)) {
XResizeWindow(ob_display, self->window, MAX(w, oldw), MAX(h, oldh));
+ /* resize the plate to show the client padding color underneath */
frame_adjust_client_area(self->frame);
}
/* if the client is shrinking, then resize the frame before the client */
if (send_resize_client && (!user || (w <= oldw || h <= oldh))) {
+ /* resize the plate to show the client padding color underneath */
frame_adjust_client_area(self->frame);
+
XResizeWindow(ob_display, self->window, w, h);
}
{
client_hilite(self, TRUE);
} else {
+ if (event_curtime != CurrentTime)
+ self->user_time = event_curtime;
+
/* if using focus_delay, stop the timer now so that focus doesn't
go moving on us */
event_halt_focus_delay();
* since 125 of these are sent per second when moving the window (with
* user = FALSE) i doubt it matters much.
*/
- client_configure(self, OB_CORNER_TOPLEFT, self->area.x, self->area.y,
+ client_configure(self, self->area.x, self->area.y,
self->area.width, self->area.height, TRUE, TRUE);
client_change_state(self); /* reflect this in the state hints */
}