static GSList *client_destroy_notifies = NULL;
static void client_get_all(ObClient *self, gboolean real);
-static void client_toggle_border(ObClient *self, gboolean show);
static void client_get_startup_id(ObClient *self);
static void client_get_session_ids(ObClient *self);
static void client_get_area(ObClient *self);
static void client_change_allowed_actions(ObClient *self);
static void client_change_state(ObClient *self);
static void client_change_wm_state(ObClient *self);
-static void client_apply_startup_state(ObClient *self);
+static void client_apply_startup_state(ObClient *self,
+ gint x, gint y, gint w, gint h);
static void client_restore_session_state(ObClient *self);
static gboolean client_restore_session_stacking(ObClient *self);
static ObAppSettings *client_get_settings_state(ObClient *self);
XWMHints *wmhint;
gboolean activate = FALSE;
ObAppSettings *settings;
- gint placex, placey;
+ gint placex, placey, placew, placeh;
+ gboolean transient = FALSE;
grab_server(TRUE);
XFree(wmhint);
}
- ob_debug("Managing window: %lx\n", window);
+ ob_debug("Managing window: 0x%lx\n", window);
/* choose the events we want to receive on the CLIENT window */
attrib_set.event_mask = CLIENT_EVENTMASK;
client_restore_session_state(self);
/* now we have all of the window's information so we can set this up */
- client_setup_decor_and_functions(self);
+ client_setup_decor_and_functions(self, FALSE);
- /* remove the client's border (and adjust re gravity) */
- client_toggle_border(self, FALSE);
-
{
Time t = sn_app_started(self->startup_id, self->class);
if (t) self->user_time = t;
!self->iconic &&
/* this means focus=true for window is same as config_focus_new=true */
((config_focus_new || (settings && settings->focus == 1)) ||
- client_search_focus_parent(self)) &&
+ client_search_focus_tree_full(self)) &&
/* this checks for focus=false for the window */
(!settings || settings->focus != 0) &&
- /* note the check against Type_Normal/Dialog, not client_normal(self),
- which would also include other types. in this case we want more
- strict rules for focus */
+ /* note the check against type Normal/Dialog/Utility,
+ not client_normal(self), which would also include other types.
+ in this case we want more strict rules for focus */
(self->type == OB_CLIENT_TYPE_NORMAL ||
+ self->type == OB_CLIENT_TYPE_UTILITY ||
self->type == OB_CLIENT_TYPE_DIALOG))
{
activate = TRUE;
}
+ /* remove the client's border */
+ XSetWindowBorderWidth(ob_display, self->window, 0);
+
/* adjust the frame to the client's size before showing or placing
the window */
frame_adjust_area(self->frame, FALSE, TRUE, FALSE);
/* where the frame was placed is where the window was originally */
placex = self->area.x;
placey = self->area.y;
+ placew = self->area.width;
+ placeh = self->area.height;
- /* figure out placement for the window */
+ /* figure out placement for the window if the window is new */
if (ob_state() == OB_STATE_RUNNING) {
- gboolean transient;
-
ob_debug("Positioned: %s @ %d %d\n",
(!self->positioned ? "no" :
(self->positioned == PPosition ? "program specified" :
(self->positioned == USPosition ? "user specified" :
- "BADNESS !?"))), self->area.x, self->area.y);
-
+ (self->positioned == (PPosition | USPosition) ?
+ "program + user specified" :
+ "BADNESS !?")))), placex, placey);
+
+ ob_debug("Sized: %s @ %d %d\n",
+ (!self->sized ? "no" :
+ (self->sized == PSize ? "program specified" :
+ (self->sized == USSize ? "user specified" :
+ (self->sized == (PSize | USSize) ?
+ "program + user specified" :
+ "BADNESS !?")))), placew, placeh);
+
+ /* splash screens are also returned as TRUE for transient,
+ and so will be forced on screen below */
transient = place_client(self, &placex, &placey, settings);
/* make sure the window is visible. */
- client_find_onscreen(self, &placex, &placey,
- self->area.width, self->area.height,
+ client_find_onscreen(self, &placex, &placey, placew, placeh,
/* non-normal clients has less rules, and
windows that are being restored from a
session do also. we can assume you want
place.c or by the user are allowed partially
off-screen and on xinerama divides (ie,
it is up to the placement routines to avoid
- the xinerama divides) */
+ the xinerama divides)
+
+ splash screens get "transient" set to TRUE by
+ the place_client call
+ */
transient ||
- (((self->positioned & PPosition) &&
- !(self->positioned & USPosition)) &&
+ (!(self->positioned & USPosition) &&
client_normal(self) &&
!self->session));
}
- ob_debug("placing window 0x%x at %d, %d with size %d x %d\n",
- self->window, placex, placey,
- self->area.width, self->area.height);
- if (self->session)
- ob_debug(" but session requested %d %d instead, overriding\n",
- self->session->x, self->session->y);
+ /* if the window isn't user-sized, then make it fit inside
+ the visible screen area on its monitor. Use basically the same rules
+ for forcing the window on screen in the client_find_onscreen call.
- /* do this after the window is placed, so the premax/prefullscreen numbers
- won't be all wacko!!
- also, this moves the window to the position where it has been placed
+ do this after place_client, it chooses the monitor!
+
+ splash screens get "transient" set to TRUE by
+ the place_client call
*/
- client_apply_startup_state(self);
+ if (transient ||
+ (!(self->sized & USSize) &&
+ client_normal(self) &&
+ !self->session))
+ {
+ /* make a copy to modify */
+ Rect a = *screen_area_monitor(self->desktop, client_monitor(self));
- /* move the client to its placed position, or it it's already there,
- generate a ConfigureNotify telling the client where it is.
+ /* shrink by the frame's area */
+ a.width -= self->frame->size.left + self->frame->size.right;
+ a.height -= self->frame->size.top + self->frame->size.bottom;
- do this after adjusting the frame. otherwise it gets all weird and
- clients don't work right
+ /* fit the window inside the area */
+ if (placew > a.width || self->area.height > a.height) {
+ placew = MIN(self->area.width, a.width);
+ placeh = MIN(self->area.height, a.height);
- also do this after applying the startup state so maximize and fullscreen
- will get the right sizes and positions if the client is starting with
- those states
- */
- client_configure(self, placex, placey,
- self->area.width, self->area.height,
- FALSE, TRUE);
+ ob_debug("setting window size to %dx%d\n",
+ self->area.width, self->area.height);
+ }
+ }
+
+
+ ob_debug("placing window 0x%x at %d, %d with size %d x %d. "
+ "some restrictions may apply\n",
+ self->window, placex, placey, placew, placeh);
+ if (self->session)
+ ob_debug(" but session requested %d, %d %d x %d instead, "
+ "overriding\n",
+ self->session->x, self->session->y,
+ self->session->w, self->session->h);
+
+ /* do this after the window is placed, so the premax/prefullscreen numbers
+ won't be all wacko!!
+ this also places the window
+ */
+ client_apply_startup_state(self, placex, placey, placew, placeh);
if (activate) {
guint32 last_time = focus_client ?
"Not focusing the window because its on another "
"desktop\n");
}
- /* If something is focused, and it's not our parent... */
- else if (focus_client && client_search_focus_parent(self) == NULL)
+ /* If something is focused, and it's not our relative... */
+ else if (focus_client && client_search_focus_tree_full(self) == NULL)
{
/* If time stamp is old, don't steal focus */
if (self->user_time && last_time &&
"Not focusing the window because the time is "
"too old\n");
}
+ /* If its a transient (and parents aren't focused) and the time
+ is ambiguous (either the current focus target doesn't have
+ a timestamp, or they are the same (we probably inherited it
+ from them) */
+ else if (client_has_parent(self) &&
+ (!last_time || self->user_time == last_time))
+ {
+ activate = FALSE;
+ ob_debug_type(OB_DEBUG_FOCUS,
+ "Not focusing the window because it is a "
+ "transient, and the time is very ambiguous\n");
+ }
/* Don't steal focus from globally active clients.
I stole this idea from KWin. It seems nice.
*/
- if (!(focus_client->can_focus || focus_client->focus_notify)) {
+ else if (!(focus_client->can_focus ||
+ focus_client->focus_notify))
+ {
activate = FALSE;
ob_debug_type(OB_DEBUG_FOCUS,
"Not focusing the window because a globally "
"active client has focus\n");
}
+ /* Don't move focus if it's not going to go to this window
+ anyway */
+ else if (client_focus_target(self) != self) {
+ activate = FALSE;
+ ob_debug_type(OB_DEBUG_FOCUS,
+ "Not focusing the window because another window "
+ "would get the focus anyway\n");
+ }
}
if (!activate) {
g_free(settings);
ob_debug("Managed window 0x%lx plate 0x%x (%s)\n",
- window, self->frame->plate, self->class);
+ window, self->frame->window, self->class);
return;
}
uses too. this returns a shallow copy that needs to be freed */
settings = client_get_settings_state(self);
- client_setup_decor_and_functions(self);
+ client_setup_decor_and_functions(self, FALSE);
/* create the decoration frame for the client window and adjust its size */
self->frame = frame_new(self);
frame_adjust_area(self->frame, FALSE, TRUE, TRUE);
+ ob_debug("gave extents left %d right %d top %d bottom %d\n",
+ self->frame->size.left, self->frame->size.right,
+ self->frame->size.top, self->frame->size.bottom);
+
/* free the ObAppSettings shallow copy */
g_free(settings);
GSList *it;
ob_debug("Unmanaging window: 0x%x plate 0x%x (%s) (%s)\n",
- self->window, self->frame->plate,
+ self->window, self->frame->window,
self->class, self->title ? self->title : "");
g_assert(self != NULL);
{
Rect a;
- /* give the client its border back */
- client_toggle_border(self, TRUE);
-
a = self->area;
if (self->fullscreen)
self->functions = OB_CLIENT_FUNC_MOVE | OB_CLIENT_FUNC_RESIZE;
self->decorations = 0; /* unmanaged windows have no decor */
+ /* give the client its border back */
+ XSetWindowBorderWidth(ob_display, self->window, self->border_width);
+
client_move_resize(self, a.x, a.y, a.width, a.height);
}
RECT_SET_POINT(self->area, self->session->x, self->session->y);
self->positioned = USPosition;
+ self->sized = USSize;
if (self->session->w > 0)
self->area.width = self->session->w;
if (self->session->h > 0)
* 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 (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;
- }
+ 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 + MAX(0, mon_a->width - fw);
+
+ 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 + MAX(0, mon_a->height - fh);
/* get where the client should be */
frame_frame_gravity(self->frame, x, y, w, h);
return ox != *x || oy != *y;
}
-static void client_toggle_border(ObClient *self, gboolean show)
-{
- /* adjust our idea of where the client is, based on its border. When the
- border is removed, the client should now be considered to be in a
- different position.
- when re-adding the border to the client, the same operation needs to be
- reversed. */
- gint oldx = self->area.x, oldy = self->area.y;
- gint x = oldx, y = oldy;
- switch(self->gravity) {
- default:
- case NorthWestGravity:
- case WestGravity:
- case SouthWestGravity:
- break;
- case NorthEastGravity:
- case EastGravity:
- case SouthEastGravity:
- if (show) x -= self->border_width * 2;
- else x += self->border_width * 2;
- break;
- case NorthGravity:
- case SouthGravity:
- case CenterGravity:
- case ForgetGravity:
- case StaticGravity:
- if (show) x -= self->border_width;
- else x += self->border_width;
- break;
- }
- switch(self->gravity) {
- default:
- case NorthWestGravity:
- case NorthGravity:
- case NorthEastGravity:
- break;
- case SouthWestGravity:
- case SouthGravity:
- case SouthEastGravity:
- if (show) y -= self->border_width * 2;
- else y += self->border_width * 2;
- break;
- case WestGravity:
- case EastGravity:
- case CenterGravity:
- case ForgetGravity:
- case StaticGravity:
- if (show) y -= self->border_width;
- else y += self->border_width;
- break;
- }
- self->area.x = x;
- self->area.y = y;
-
- if (show) {
- XSetWindowBorderWidth(ob_display, self->window, self->border_width);
-
- /* set border_width to 0 because there is no border to add into
- calculations anymore */
- self->border_width = 0;
- } else
- XSetWindowBorderWidth(ob_display, self->window, 0);
-}
-
-
static void client_get_all(ObClient *self, gboolean real)
{
/* this is needed for the frame to set itself up */
POINT_SET(self->root_pos, wattrib.x, wattrib.y);
self->border_width = wattrib.border_width;
- ob_debug("client area: %d %d %d %d\n", wattrib.x, wattrib.y,
- wattrib.width, wattrib.height);
+ ob_debug("client area: %d %d %d %d bw %d\n", wattrib.x, wattrib.y,
+ wattrib.width, wattrib.height, wattrib.border_width);
}
static void client_get_desktop(ObClient *self)
self->desktop = screen_num_desktops - 1;
else
self->desktop = d;
+ ob_debug("client requested desktop 0x%x\n", self->desktop);
} else {
gboolean trdesk = FALSE;
if (self->transient_for) {
if (self->transient_for != OB_TRAN_GROUP) {
- self->desktop = self->transient_for->desktop;
- trdesk = TRUE;
+ if (self->transient_for->desktop != DESKTOP_ALL) {
+ self->desktop = self->transient_for->desktop;
+ trdesk = TRUE;
+ }
} else {
+ /* if all the group is on one desktop, then open it on the
+ same desktop */
GSList *it;
+ gboolean first = TRUE;
+ guint all = screen_num_desktops; /* not a valid value */
- for (it = self->group->members; it; it = g_slist_next(it))
- if (it->data != self &&
- !((ObClient*)it->data)->transient_for) {
- self->desktop = ((ObClient*)it->data)->desktop;
- trdesk = TRUE;
- break;
+ for (it = self->group->members; it; it = g_slist_next(it)) {
+ ObClient *c = it->data;
+ if (c != self) {
+ if (first) {
+ all = c->desktop;
+ first = FALSE;
+ }
+ else if (all != c->desktop)
+ all = screen_num_desktops; /* make it invalid */
}
+ }
+ if (all != screen_num_desktops) {
+ self->desktop = all;
+ trdesk = TRUE;
+ }
}
}
if (!trdesk) {
void client_update_colormap(ObClient *self, Colormap colormap)
{
- self->colormap = colormap;
+ if (colormap == self->colormap) return;
+
+ ob_debug("Setting client %s colormap: 0x%x\n", self->title, colormap);
+
+ if (client_focused(self)) {
+ screen_install_colormap(self, FALSE); /* uninstall old one */
+ self->colormap = colormap;
+ screen_install_colormap(self, FALSE); /* install new one */
+ } else
+ self->colormap = colormap;
}
void client_update_normal_hints(ObClient *self)
{
XSizeHints size;
glong ret;
- gint oldgravity = self->gravity;
/* defaults */
self->min_ratio = 0.0f;
if (!client_normal(self))
*/
self->positioned = (size.flags & (PPosition|USPosition));
+ self->sized = (size.flags & (PSize|USSize));
- if (size.flags & PWinGravity) {
+ if (size.flags & PWinGravity)
self->gravity = size.win_gravity;
-
- /* if the client has a frame, i.e. has already been mapped and
- is changing its gravity */
- if (self->frame && self->gravity != oldgravity) {
- /* move our idea of the client's position based on its new
- gravity */
- client_convert_gravity(self, oldgravity,
- &self->area.x, &self->area.y,
- self->area.width, self->area.height);
- }
- }
if (size.flags & PAspect) {
if (size.min_aspect.y)
}
}
-/*! This needs to be followed by a call to client_configure to make
- the changes show */
-void client_setup_decor_and_functions(ObClient *self)
+void client_setup_decor_and_functions(ObClient *self, gboolean reconfig)
{
/* start with everything (cept fullscreen) */
self->decorations =
case OB_CLIENT_TYPE_DIALOG:
case OB_CLIENT_TYPE_UTILITY:
- /* these windows cannot be maximized */
- self->functions &= ~OB_CLIENT_FUNC_MAXIMIZE;
+ /* these windows don't have anything added or removed by default */
break;
case OB_CLIENT_TYPE_MENU:
case OB_CLIENT_TYPE_TOOLBAR:
- /* these windows get less functionality */
- self->functions &= ~(OB_CLIENT_FUNC_ICONIFY | OB_CLIENT_FUNC_RESIZE);
+ /* these windows can't iconify or maximize */
+ self->decorations &= ~(OB_FRAME_DECOR_ICONIFY |
+ OB_FRAME_DECOR_MAXIMIZE);
+ self->functions &= ~(OB_CLIENT_FUNC_ICONIFY |
+ OB_CLIENT_FUNC_MAXIMIZE);
break;
case OB_CLIENT_TYPE_SPLASH:
self->decorations &= ~OB_FRAME_DECOR_MAXIMIZE;
}
- if (self->max_horz && self->max_vert)
+ if (self->max_horz && self->max_vert) {
+ /* you can't resize fully maximized windows */
+ self->functions &= ~OB_CLIENT_FUNC_RESIZE;
/* kill the handle on fully maxed windows */
self->decorations &= ~(OB_FRAME_DECOR_HANDLE | OB_FRAME_DECOR_GRIPS);
+ }
/* If there are no decorations to remove, don't allow the user to try
toggle the state */
}
client_change_allowed_actions(self);
+
+ if (reconfig)
+ client_reconfigure(self);
}
static void client_change_allowed_actions(ObClient *self)
void client_reconfigure(ObClient *self)
{
- /* 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, self->area.x, self->area.y,
- self->area.width, self->area.height, FALSE, TRUE);
+ self->area.width, self->area.height,
+ FALSE, TRUE);
}
void client_update_wmhints(ObClient *self)
}
/* the WM_HINTS can contain an icon */
- client_update_icons(self);
+ if (hints->flags & IconPixmapHint)
+ client_update_icons(self);
XFree(hints);
}
PROP_GETS(self->window, wm_icon_name, utf8, &data)))
data = g_strdup(self->title);
- PROP_SETS(self->window, net_wm_visible_icon_name, data);
- self->icon_title = data;
+ if (self->client_machine) {
+ visible = g_strdup_printf("%s (%s)", data, self->client_machine);
+ g_free(data);
+ } else
+ visible = data;
+
+ PROP_SETS(self->window, net_wm_visible_icon_name, visible);
+ self->icon_title = visible;
}
void client_update_strut(ObClient *self)
return client_search_focus_tree_full(self->transient_for);
} else {
GSList *it;
- gboolean recursed = FALSE;
- for (it = self->group->members; it; it = g_slist_next(it))
- if (!((ObClient*)it->data)->transient_for) {
- ObClient *c;
- if ((c = client_search_focus_tree_full(it->data)))
- return c;
- recursed = TRUE;
+ for (it = self->group->members; it; it = g_slist_next(it)) {
+ if (it->data != self) {
+ ObClient *c = it->data;
+
+ if (client_focused(c)) return c;
+ if ((c = client_search_focus_tree(it->data))) return c;
}
- if (recursed)
- return NULL;
+ }
}
}
- /* this function checks the whole tree, the client_search_focus_tree~
+ /* this function checks the whole tree, the client_search_focus_tree
does not, so we need to check this window */
if (client_focused(self))
return self;
return client_search_focus_tree(self);
}
+gboolean client_has_parent(ObClient *self)
+{
+ if (self->transient_for) {
+ if (self->transient_for != OB_TRAN_GROUP) {
+ if (client_normal(self->transient_for))
+ return TRUE;
+ }
+ else if (self->group) {
+ GSList *it;
+
+ for (it = self->group->members; it; it = g_slist_next(it)) {
+ if (it->data != self && client_normal(it->data))
+ return TRUE;
+ }
+ }
+ }
+ return FALSE;
+}
+
static ObStackingLayer calc_layer(ObClient *self)
{
ObStackingLayer l;
}
else if ((self->fullscreen ||
/* No decorations and fills the monitor = oldskool fullscreen.
- But not for undecorated windows, because the user can do that
+ But not for maximized windows.
*/
(self->decorations == 0 &&
- !self->undecorated &&
+ !(self->max_horz && self->max_vert) &&
RECT_EQUAL(self->area,
*screen_physical_area_monitor
(client_monitor(self))))) &&
actions should not rely on being able to move focus during an
interactive grab.
*/
- if (keyboard_interactively_grabbed())
- keyboard_interactive_cancel();
+ event_cancel_all_key_grabs();
}
frame_hide(self->frame);
}
-static void client_apply_startup_state(ObClient *self)
+static void client_apply_startup_state(ObClient *self,
+ gint x, gint y, gint w, gint h)
{
- /* set the desktop hint, to make sure that it always exists */
- PROP_SET32(self->window, net_wm_desktop, cardinal, self->desktop);
+ /* save the states that we are going to apply */
+ gboolean iconic = self->iconic;
+ gboolean fullscreen = self->fullscreen;
+ gboolean undecorated = self->undecorated;
+ gboolean shaded = self->shaded;
+ gboolean demands_attention = self->demands_attention;
+ gboolean max_horz = self->max_horz;
+ gboolean max_vert = self->max_vert;
- /* these are in a carefully crafted order.. */
+ /* turn them all off in the client, so they won't affect the window
+ being placed */
+ self->iconic = self->fullscreen = self->undecorated = self->shaded =
+ self->demands_attention = self->max_horz = self->max_vert = FALSE;
+
+ /* move the client to its placed position, or it it's already there,
+ generate a ConfigureNotify telling the client where it is.
+
+ do this after adjusting the frame. otherwise it gets all weird and
+ clients don't work right
- if (self->iconic) {
- self->iconic = FALSE;
+ do this before applying the states so they have the correct
+ pre-max/pre-fullscreen values
+ */
+ client_configure(self, x, y, w, h, FALSE, TRUE);
+ ob_debug("placed window 0x%x at %d, %d with size %d x %d\n",
+ self->window, self->area.x, self->area.y,
+ self->area.width, self->area.height);
+
+ /* apply the states. these are in a carefully crafted order.. */
+
+ if (iconic)
client_iconify(self, TRUE, FALSE, TRUE);
- }
- if (self->fullscreen) {
- self->fullscreen = FALSE;
+ if (fullscreen)
client_fullscreen(self, TRUE);
- }
- if (self->undecorated) {
- self->undecorated = FALSE;
+ if (undecorated)
client_set_undecorated(self, TRUE);
- }
- if (self->shaded) {
- self->shaded = FALSE;
+ if (shaded)
client_shade(self, TRUE);
- }
- if (self->demands_attention) {
- self->demands_attention = FALSE;
+ if (demands_attention)
client_hilite(self, TRUE);
- }
- if (self->max_vert && self->max_horz) {
- self->max_vert = self->max_horz = FALSE;
+ if (max_vert && max_horz)
client_maximize(self, TRUE, 0);
- } else if (self->max_vert) {
- self->max_vert = FALSE;
+ else if (max_vert)
client_maximize(self, TRUE, 2);
- } else if (self->max_horz) {
- self->max_horz = FALSE;
+ else if (max_horz)
client_maximize(self, TRUE, 1);
- }
+
+ /* set the desktop hint, to make sure that it always exists */
+ PROP_SET32(self->window, net_wm_desktop, cardinal, self->desktop);
/* nothing to do for the other states:
skip_taskbar
*/
}
-void client_convert_gravity(ObClient *self, gint gravity, gint *x, gint *y,
- gint w, gint h)
+void client_gravity_resize_w(ObClient *self, gint *x, gint oldw, gint neww)
{
- gint oldg = self->gravity;
+ /* these should be the current values. this is for when you're not moving,
+ just resizing */
+ g_assert(*x == self->area.x);
+ g_assert(oldw == self->area.width);
- /* get the frame's position from the requested stuff */
- self->gravity = gravity;
- frame_client_gravity(self->frame, x, y, w, h);
- self->gravity = oldg;
+ /* horizontal */
+ switch (self->gravity) {
+ default:
+ case NorthWestGravity:
+ case WestGravity:
+ case SouthWestGravity:
+ case StaticGravity:
+ case ForgetGravity:
+ break;
+ case NorthGravity:
+ case CenterGravity:
+ case SouthGravity:
+ *x -= (neww - oldw) / 2;
+ break;
+ case NorthEastGravity:
+ case EastGravity:
+ case SouthEastGravity:
+ *x -= neww - oldw;
+ break;
+ }
+}
- /* get the client's position in its true gravity from that */
- frame_frame_gravity(self->frame, x, y, w, h);
+void client_gravity_resize_h(ObClient *self, gint *y, gint oldh, gint newh)
+{
+ /* these should be the current values. this is for when you're not moving,
+ just resizing */
+ g_assert(*y == self->area.y);
+ g_assert(oldh == self->area.height);
+
+ /* vertical */
+ switch (self->gravity) {
+ default:
+ case NorthWestGravity:
+ case NorthGravity:
+ case NorthEastGravity:
+ case StaticGravity:
+ case ForgetGravity:
+ break;
+ case WestGravity:
+ case CenterGravity:
+ case EastGravity:
+ *y -= (newh - oldh) / 2;
+ break;
+ case SouthWestGravity:
+ case SouthGravity:
+ case SouthEastGravity:
+ *y -= newh - oldh;
+ break;
+ }
}
void client_try_configure(ObClient *self, gint *x, gint *y, gint *w, gint *h,
*h = a->height;
user = FALSE; /* ignore if the client can't be moved/resized when it
- is entering fullscreen */
+ is fullscreening */
} else if (self->max_horz || self->max_vert) {
Rect *a;
guint i;
*h = a->height - self->frame->size.top - self->frame->size.bottom;
}
- /* maximizing is not allowed if the user can't move+resize the window
- */
+ user = FALSE; /* ignore if the client can't be moved/resized when it
+ is maximizing */
}
/* gets the client's position */
SIZE_SET(self->logical_size, logicalw, logicalh);
/* figure out if we moved or resized or what */
- moved = x != self->area.x || y != self->area.y;
- resized = w != self->area.width || h != self->area.height;
+ moved = (x != self->area.x || y != self->area.y);
+ resized = (w != self->area.width || h != self->area.height);
oldw = self->area.width;
oldh = self->area.height;
/* if the client is enlarging, then resize the client before the frame */
if (send_resize_client && (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 */
+ XResizeWindow(ob_display, self->window, MAX(w, oldw), MAX(h, oldh));
frame_adjust_client_area(self->frame);
}
{
XEvent event;
+ /* we have reset the client to 0 border width, so don't include
+ it in these coords */
POINT_SET(self->root_pos,
self->frame->area.x + self->frame->size.left -
self->border_width,
event.xconfigure.y = self->root_pos.y;
event.xconfigure.width = w;
event.xconfigure.height = h;
- event.xconfigure.border_width = 0;
- event.xconfigure.above = self->frame->plate;
+ event.xconfigure.border_width = self->border_width;
+ event.xconfigure.above = None;
event.xconfigure.override_redirect = FALSE;
XSendEvent(event.xconfigure.display, event.xconfigure.window,
FALSE, StructureNotifyMask, &event);
}
- /* if the client is shrinking, then resize the frame before the client */
+ /* if the client is shrinking, then resize the frame before the client.
+
+ both of these resize sections may run, because the top one only resizes
+ in the direction that is growing
+ */
if (send_resize_client && (w <= oldw || h <= oldh)) {
- /* resize the plate to show the client padding color underneath */
frame_adjust_client_area(self->frame);
-
- if (send_resize_client)
- XResizeWindow(ob_display, self->window, w, h);
+ XResizeWindow(ob_display, self->window, w, h);
}
XFlush(ob_display);
RECT_SET(self->pre_fullscreen_area, 0, 0, 0, 0);
}
- client_setup_decor_and_functions(self);
-
+ client_setup_decor_and_functions(self, FALSE);
client_move_resize(self, x, y, w, h);
/* and adjust our layer/stacking. do this after resizing the window,
self->iconic = iconic;
/* update the focus lists.. iconic windows go to the bottom of
- the list, put the new iconic window at the 'top of the
- bottom'. */
- focus_order_to_top(self);
+ the list */
+ focus_order_to_bottom(self);
changed = TRUE;
}
client_change_state(self); /* change the state hints on the client */
- client_setup_decor_and_functions(self);
-
+ client_setup_decor_and_functions(self, FALSE);
client_move_resize(self, x, y, w, h);
}
gboolean client_focus(ObClient *self)
{
+ /* we might not focus this window, so if we have modal children which would
+ be focused instead, bring them to this desktop */
+ client_bring_modal_windows(self);
+
/* choose the correct target */
self = client_focus_target(self);
/* update the focus lists */
focus_order_to_top(self);
}
+ ob_debug_type(OB_DEBUG_FOCUS,
+ "Client %s can't be focused\n", self->title);
return FALSE;
}
ob_debug_type(OB_DEBUG_FOCUS,
- "Focusing client \"%s\" at time %u\n",
- self->title, event_curtime);
+ "Focusing client \"%s\" (0x%x) at time %u\n",
+ self->title, self->window, event_curtime);
/* if there is a grab going on, then we need to cancel it. if we move
focus during the grab, applications will get NotifyWhileGrabbed events
actions should not rely on being able to move focus during an
interactive grab.
*/
- if (keyboard_interactively_grabbed())
- keyboard_interactive_cancel();
+ event_cancel_all_key_grabs();
xerror_set_ignore(TRUE);
xerror_occured = FALSE;
xerror_set_ignore(FALSE);
+ ob_debug_type(OB_DEBUG_FOCUS, "Error focusing? %d\n", xerror_occured);
return !xerror_occured;
}
client_hilite(self, TRUE);
}
-static void client_bring_helper_windows_recursive(ObClient *self,
- guint desktop)
+static void client_bring_windows_recursive(ObClient *self,
+ guint desktop,
+ gboolean helpers,
+ gboolean modals,
+ gboolean iconic)
{
GSList *it;
for (it = self->transients; it; it = g_slist_next(it))
- client_bring_helper_windows_recursive(it->data, desktop);
+ client_bring_windows_recursive(it->data, desktop,
+ helpers, modals, iconic);
- if (client_helper(self) &&
- self->desktop != desktop && self->desktop != DESKTOP_ALL)
+ if (((helpers && client_helper(self)) ||
+ (modals && self->modal)) &&
+ ((self->desktop != desktop && self->desktop != DESKTOP_ALL) ||
+ (iconic && self->iconic)))
{
- client_set_desktop(self, desktop, FALSE);
+ if (iconic && self->iconic)
+ client_iconify(self, FALSE, TRUE, FALSE);
+ else
+ client_set_desktop(self, desktop, FALSE);
}
}
void client_bring_helper_windows(ObClient *self)
{
- client_bring_helper_windows_recursive(self, self->desktop);
+ client_bring_windows_recursive(self, self->desktop, TRUE, FALSE, FALSE);
+}
+
+void client_bring_modal_windows(ObClient *self)
+{
+ client_bring_windows_recursive(self, self->desktop, FALSE, TRUE, TRUE);
}
gboolean client_focused(ObClient *self)
for (i = 1; i < self->nicons; ++i) {
gulong diff;
- diff = ABS(self->icons[0].width - w) + ABS(self->icons[0].height - h);
+ diff = ABS(self->icons[i].width - w) + ABS(self->icons[i].height - h);
if (diff < min_diff) {
min_diff = diff;
min_i = i;
(self->functions & OB_CLIENT_FUNC_UNDECORATE || !undecorated))
{
self->undecorated = undecorated;
- client_setup_decor_and_functions(self);
- client_reconfigure(self); /* show the lack of decorations */
+ client_setup_decor_and_functions(self, TRUE);
client_change_state(self); /* reflect this in the state hints */
}
}