static ObAppSettings *client_get_settings_state(ObClient *self);
static void client_update_transient_tree(ObClient *self,
ObGroup *oldgroup, ObGroup *newgroup,
+ gboolean oldgtran, gboolean newgtran,
ObClient* oldparent,
ObClient *newparent);
static void client_present(ObClient *self, gboolean here, gboolean raise);
self->type == OB_CLIENT_TYPE_UTILITY ||
self->type == OB_CLIENT_TYPE_DIALOG))
{
+ /* XXX use focus_cycle_valid_target instead... */
activate = TRUE;
}
/* this has to happen before we try focus the window, but we want it to
happen after the client's stacking has been determined or it looks bad
*/
- client_show(self);
+ {
+ gulong ignore_start;
+ if (!config_focus_under_mouse)
+ ignore_start = event_start_ignore_all_enters();
+
+ client_show(self);
+
+ if (!config_focus_under_mouse)
+ event_end_ignore_all_enters(ignore_start);
+ }
if (activate) {
gboolean stacked = client_restore_session_stacking(self);
XSelectInput(ob_display, self->window, NoEventMask);
/* ignore enter events from the unmap so it doesnt mess with the focus */
- if (!client_focused(self) || !config_focus_under_mouse)
+ if (!config_focus_under_mouse)
ignore_start = event_start_ignore_all_enters();
frame_hide(self->frame);
/* flush to send the hide to the server quickly */
XFlush(ob_display);
- if (!client_focused(self) || !config_focus_under_mouse)
+ if (!config_focus_under_mouse)
event_end_ignore_all_enters(ignore_start);
mouse_grab_for_client(self, FALSE);
client_update_wmhints(self);
/* this may have already been called from client_update_wmhints */
- if (self->transient_for == NULL)
+ if (!self->parents && !self->transient_for_group)
client_update_transient_for(self);
client_get_startup_id(self);
self->desktop = d;
ob_debug("client requested desktop 0x%x\n", self->desktop);
} else {
- gboolean trdesk = FALSE;
-
- if (self->transient_for) {
- /* if they are all on one desktop, then open it on the
- same desktop */
- GSList *it;
- gboolean first = TRUE;
- guint all = screen_num_desktops; /* not a valid value */
+ GSList *it;
+ gboolean first = TRUE;
+ guint all = screen_num_desktops; /* not a valid value */
- for (it = self->parents; it; it = g_slist_next(it)) {
- ObClient *c = it->data;
+ /* if they are all on one desktop, then open it on the
+ same desktop */
+ for (it = self->parents; it; it = g_slist_next(it)) {
+ ObClient *c = it->data;
- if (c->desktop == DESKTOP_ALL) continue;
+ if (c->desktop == DESKTOP_ALL) continue;
- 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 (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;
- if (!trdesk) {
- /* try get from the startup-notification protocol */
- if (sn_get_desktop(self->startup_id, &self->desktop)) {
- if (self->desktop >= screen_num_desktops &&
- self->desktop != DESKTOP_ALL)
- self->desktop = screen_num_desktops - 1;
- } else
- /* defaults to the current desktop */
- self->desktop = screen_desktop;
+ ob_debug("client desktop set from parents: 0x%x\n",
+ self->desktop);
+ }
+ /* try get from the startup-notification protocol */
+ else if (sn_get_desktop(self->startup_id, &self->desktop)) {
+ if (self->desktop >= screen_num_desktops &&
+ self->desktop != DESKTOP_ALL)
+ self->desktop = screen_num_desktops - 1;
+ ob_debug("client desktop set from startup-notification: 0x%x\n",
+ self->desktop);
+ }
+ /* defaults to the current desktop */
+ else {
+ self->desktop = screen_desktop;
+ ob_debug("client desktop set to the current desktop: %d\n",
+ self->desktop);
}
}
}
{
Window t = None;
ObClient *target = NULL;
+ gboolean trangroup = FALSE;
if (XGetTransientForHint(ob_display, self->window, &t)) {
if (t != self->window) { /* cant be transient to itself! */
a dockapp, for example */
target = NULL;
}
-
- /* Setting the transient_for to Root is actually illegal, however
- applications from time have done this to specify transient for
- their group */
- if (!target && self->group) {
- /* not transient to a client, see if it is transient for a
- group */
- if (t == RootWindow(ob_display, ob_screen)) {
- /* window is a transient for its group! */
- target = OB_TRAN_GROUP;
- }
- }
}
- } else if (self->transient && self->group)
- target = OB_TRAN_GROUP;
+
+ /* Setting the transient_for to Root is actually illegal, however
+ applications from time have done this to specify transient for
+ their group */
+ if (!target && self->group && t == RootWindow(ob_display, ob_screen))
+ trangroup = TRUE;
+ } else if (self->group && self->transient)
+ trangroup = TRUE;
client_update_transient_tree(self, self->group, self->group,
- self->transient_for, target);
- self->transient_for = target;
+ self->transient_for_group, trangroup,
+ client_direct_parent(self), target);
+ self->transient_for_group = trangroup;
}
static void client_update_transient_tree(ObClient *self,
ObGroup *oldgroup, ObGroup *newgroup,
+ gboolean oldgtran, gboolean newgtran,
ObClient* oldparent,
ObClient *newparent)
{
GSList *it, *next;
ObClient *c;
+ g_assert(!oldgtran || oldgroup);
+ g_assert(!newgtran || newgroup);
+ g_assert((!oldgtran && !oldparent) ||
+ (oldgtran && !oldparent) ||
+ (!oldgtran && oldparent));
+ g_assert((!newgtran && !newparent) ||
+ (newgtran && !newparent) ||
+ (!newgtran && newparent));
+
/* * *
Group transient windows are not allowed to have other group
transient windows as their children.
/* No change has occured */
- if (oldgroup == newgroup && oldparent == newparent) return;
+ if (oldgroup == newgroup &&
+ oldgtran == newgtran &&
+ oldparent == newparent) return;
/** Remove the client from the transient tree wherever it has changed **/
we could have any number of direct parents above up, any of which could
be transient for the group, and we need to remove it from our children.
*/
- if (oldparent != newparent &&
- newparent != NULL && newparent != OB_TRAN_GROUP &&
- newgroup != NULL && newgroup == oldgroup && client_normal(newparent))
+ if (!oldgtran && oldparent != newparent && newparent != NULL &&
+ newgroup != NULL && newgroup == oldgroup &&
+ client_normal(newparent))
{
- ObClient *look = newparent;
- do {
- self->transients = g_slist_remove(self->transients, look);
- look->parents = g_slist_remove(look->parents, self);
- look = look->transient_for;
- } while (look != NULL && look != OB_TRAN_GROUP && client_normal(look));
+ ObClient *look = client_search_top_direct_parent(newparent);
+ self->transients = g_slist_remove(self->transients, look);
+ look->parents = g_slist_remove(look->parents, self);
}
group, then we need to remove any old group transient windows
from our children. But if we were already transient for the group, then
other group transients are not our children. */
- if ((oldgroup != newgroup ||
- (newparent == OB_TRAN_GROUP && oldparent != newparent)) &&
- oldgroup != NULL && oldparent != OB_TRAN_GROUP)
+ if ((oldgroup != newgroup || (newgtran && oldgtran != newgtran)) &&
+ oldgroup != NULL && !oldgtran)
{
for (it = self->transients; it; it = next) {
next = g_slist_next(it);
/* If we used to be transient for a group and now we are not, or we're
transient for a new group, then we need to remove ourselves from all
our ex-parents */
- if (oldparent == OB_TRAN_GROUP && (oldgroup != newgroup ||
- oldparent != newparent))
+ if (oldgtran && (oldgroup != newgroup || oldgtran != newgtran))
{
for (it = self->parents; it; it = next) {
next = g_slist_next(it);
c = it->data;
- if ((!c->transient_for || c->transient_for != OB_TRAN_GROUP) &&
- client_normal(c))
- {
+ if (!c->transient_for_group && client_normal(c)) {
c->transients = g_slist_remove(c->transients, self);
self->parents = g_slist_delete_link(self->parents, it);
}
}
/* If we used to be transient for a single window and we are no longer
transient for it, then we need to remove ourself from its children */
- else if (oldparent != NULL && oldparent != OB_TRAN_GROUP &&
- oldparent != newparent && client_normal(oldparent))
+ else if (oldparent && oldparent != newparent &&
+ client_normal(oldparent))
{
oldparent->transients = g_slist_remove(oldparent->transients, self);
self->parents = g_slist_remove(self->parents, oldparent);
/* If we're now transient for a group and we weren't transient for it
before then we need to add ourselves to all our new parents */
- if (newparent == OB_TRAN_GROUP && (oldgroup != newgroup ||
- oldparent != newparent))
+ if (newgtran && (oldgroup != newgroup || oldgtran != newgtran))
{
for (it = oldgroup->members; it; it = g_slist_next(it)) {
c = it->data;
- if (c != self &&
- (!c->transient_for ||
- c->transient_for != OB_TRAN_GROUP) &&
- client_normal(c))
+ if (c != self && !c->transient_for_group && client_normal(c))
{
c->transients = g_slist_prepend(c->transients, self);
self->parents = g_slist_prepend(self->parents, c);
WARNING: Cyclical transient ness is possible if two windows are
transient for eachother.
*/
- else if (newparent != NULL && newparent != OB_TRAN_GROUP &&
- newparent != oldparent &&
+ else if (newparent && newparent != oldparent &&
/* don't make ourself its child if it is already our child */
!client_is_direct_child(self, newparent) &&
client_normal(newparent))
C is transient for B
A can't be transient for C or we have a cycle
*/
- if (oldgroup != newgroup && newgroup != NULL &&
- newparent != OB_TRAN_GROUP)
+ if (oldgroup != newgroup && newgroup != NULL && !newgtran &&
+ client_normal(self))
{
for (it = newgroup->members; it; it = g_slist_next(it)) {
c = it->data;
- if (c != self && c->transient_for == OB_TRAN_GROUP &&
+ if (c != self && c->transient_for_group &&
/* Don't make it our child if it is already our parent */
- !client_is_direct_child(c, self) &&
- client_normal(self))
+ !client_is_direct_child(c, self))
{
self->transients = g_slist_prepend(self->transients, c);
c->parents = g_slist_prepend(c->parents, self);
if (size.flags & PResizeInc && size.width_inc && size.height_inc)
SIZE_SET(self->size_inc, size.width_inc, size.height_inc);
+
+ ob_debug("Normal hints: min size (%d %d) max size (%d %d)\n "
+ "size inc (%d %d) base size (%d %d)\n",
+ self->min_size.width, self->min_size.height,
+ self->max_size.width, self->max_size.height,
+ self->size_inc.width, self->size_inc.height,
+ self->base_size.width, self->base_size.height);
}
+ else
+ ob_debug("Normal hints: not set\n");
}
void client_setup_decor_and_functions(ObClient *self, gboolean reconfig)
/* finally, the user can have requested no decorations, which overrides
everything (but doesnt give it a border if it doesnt have one) */
- if (self->undecorated) {
- if (config_theme_keepborder)
- self->decorations &= OB_FRAME_DECOR_BORDER;
- else
- self->decorations = 0;
- }
+ if (self->undecorated)
+ self->decorations = 0;
/* if we don't have a titlebar, then we cannot shade! */
if (!(self->decorations & OB_FRAME_DECOR_TITLEBAR))
/* Put ourselves into the new group's transient tree, and remove
ourselves from the old group's */
client_update_transient_tree(self, oldgroup, self->group,
- self->transient_for,
- self->transient_for);
+ self->transient_for_group,
+ self->transient_for_group,
+ client_direct_parent(self),
+ client_direct_parent(self));
/* Lastly, being in a group, or not, can change if the window is
transient for anything.
transient for something, even if transient_for was NULL because
it wasn't in a group before.
- If transient_for was NULL and oldgroup was NULL we can assume
+ If parents was NULL and oldgroup was NULL we can assume
that when we add the new group, it will become transient for
something.
- If transient_for was OB_TRAN_GROUP, then it must have already
+ If transient_for_group is TRUE, then it must have already
had a group. If it is getting a new group, the above call to
client_update_transient_tree has already taken care of
everything ! If it is losing all group status then it will
updated.
*/
if (self->transient &&
- ((self->transient_for == NULL && oldgroup == NULL) ||
- (self->transient_for == OB_TRAN_GROUP && !self->group)))
+ ((self->parents == NULL && oldgroup == NULL) ||
+ (self->transient_for_group && !self->group)))
client_update_transient_for(self);
}
if ((hints = XGetWMHints(ob_display, self->window))) {
if (hints->flags & IconPixmapHint) {
- self->nicons++;
+ self->nicons = 1;
self->icons = g_new(ObClientIcon, self->nicons);
xerror_set_ignore(TRUE);
if (!RrPixmapToRGBA(ob_rr_inst,
hints->icon_pixmap,
(hints->flags & IconMaskHint ?
hints->icon_mask : None),
- &self->icons[self->nicons-1].width,
- &self->icons[self->nicons-1].height,
- &self->icons[self->nicons-1].data)){
- g_free(&self->icons[self->nicons-1]);
- self->nicons--;
+ &self->icons[0].width,
+ &self->icons[0].height,
+ &self->icons[0].data))
+ {
+ g_free(self->icons);
+ self->nicons = 0;
}
xerror_set_ignore(FALSE);
}
event_cancel_all_key_grabs();
}
+ /* We don't need to ignore enter events here.
+ The window can hide/iconify in 3 different ways:
+ 1 - through an x message. in this case we ignore all enter events
+ caused by responding to the x message (unless underMouse)
+ 2 - by a keyboard action. in this case we ignore all enter events
+ caused by the action
+ 3 - by a mouse action. in this case they are doing stuff with the
+ mouse and focus _should_ move.
+
+ Also in action_end, we simulate an enter event that can't be ignored
+ so trying to ignore them is futile in case 3 anyways
+ */
+
frame_hide(self->frame);
hide = TRUE;
*/
client_try_configure(self, &x, &y, &w, &h, &l, &l, FALSE);
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);
- oldarea = self->area; /* save the area */
- RECT_SET(self->area, x, y, w, h); /* put where it should be for the premax stuff */
+ self->window, x, y, w, h);
+ /* save the area, and make it where it should be for the premax stuff */
+ oldarea = self->area;
+ RECT_SET(self->area, x, y, w, h);
/* apply the states. these are in a carefully crafted order.. */
the updated frame dimensions. */
frame_adjust_area(self->frame, FALSE, TRUE, TRUE);
+ /* gets the frame's position */
+ frame_client_gravity(self->frame, x, y, *w, *h);
+
+ /* these positions are frame positions, not client positions */
+
+ /* set the size and position if fullscreen */
+ if (self->fullscreen) {
+ Rect *a;
+ guint i;
+
+ i = screen_find_monitor(&desired_area);
+ a = screen_physical_area_monitor(i);
+
+ *x = a->x;
+ *y = a->y;
+ *w = a->width;
+ *h = a->height;
+
+ user = FALSE; /* ignore if the client can't be moved/resized when it
+ is fullscreening */
+ } else if (self->max_horz || self->max_vert) {
+ Rect *a;
+ guint i;
+
+ i = screen_find_monitor(&desired_area);
+ a = screen_area_monitor(self->desktop, i);
+
+ /* set the size and position if maximized */
+ if (self->max_horz) {
+ *x = a->x;
+ *w = a->width - self->frame->size.left - self->frame->size.right;
+ }
+ if (self->max_vert) {
+ *y = a->y;
+ *h = a->height - self->frame->size.top - self->frame->size.bottom;
+ }
+
+ user = FALSE; /* ignore if the client can't be moved/resized when it
+ is maximizing */
+ }
+
+ /* gets the client's position */
+ frame_frame_gravity(self->frame, x, y, *w, *h);
+
/* work within the prefered sizes given by the window */
if (!(*w == self->area.width && *h == self->area.height)) {
gint basew, baseh, minw, minh;
+ gint incw, inch, minratio, maxratio;
+
+ incw = self->fullscreen || self->max_horz ? 1 : self->size_inc.width;
+ inch = self->fullscreen || self->max_vert ? 1 : self->size_inc.height;
+ minratio = self->fullscreen || (self->max_horz && self->max_vert) ?
+ 0 : self->min_ratio;
+ maxratio = self->fullscreen || (self->max_horz && self->max_vert) ?
+ 0 : self->max_ratio;
/* base size is substituted with min size if not specified */
if (self->base_size.width || self->base_size.height) {
*h -= baseh;
/* keep to the increments */
- *w /= self->size_inc.width;
- *h /= self->size_inc.height;
+ *w /= incw;
+ *h /= inch;
/* you cannot resize to nothing */
if (basew + *w < 1) *w = 1 - basew;
if (baseh + *h < 1) *h = 1 - baseh;
/* save the logical size */
- *logicalw = self->size_inc.width > 1 ? *w : *w + basew;
- *logicalh = self->size_inc.height > 1 ? *h : *h + baseh;
+ *logicalw = incw > 1 ? *w : *w + basew;
+ *logicalh = inch > 1 ? *h : *h + baseh;
- *w *= self->size_inc.width;
- *h *= self->size_inc.height;
+ *w *= incw;
+ *h *= inch;
*w += basew;
*h += baseh;
*w -= self->base_size.width;
*h -= self->base_size.height;
- if (!self->fullscreen) {
- if (self->min_ratio)
- if (*h * self->min_ratio > *w) {
- *h = (gint)(*w / self->min_ratio);
+ if (minratio)
+ if (*h * minratio > *w) {
+ *h = (gint)(*w / minratio);
- /* you cannot resize to nothing */
- if (*h < 1) {
- *h = 1;
- *w = (gint)(*h * self->min_ratio);
- }
+ /* you cannot resize to nothing */
+ if (*h < 1) {
+ *h = 1;
+ *w = (gint)(*h * minratio);
}
- if (self->max_ratio)
- if (*h * self->max_ratio < *w) {
- *h = (gint)(*w / self->max_ratio);
-
- /* you cannot resize to nothing */
- if (*h < 1) {
- *h = 1;
- *w = (gint)(*h * self->min_ratio);
- }
+ }
+ if (maxratio)
+ if (*h * maxratio < *w) {
+ *h = (gint)(*w / maxratio);
+
+ /* you cannot resize to nothing */
+ if (*h < 1) {
+ *h = 1;
+ *w = (gint)(*h * minratio);
}
- }
+ }
*w += self->base_size.width;
*h += self->base_size.height;
}
- /* gets the frame's position */
- frame_client_gravity(self->frame, x, y, *w, *h);
-
- /* these positions are frame positions, not client positions */
-
- /* set the size and position if fullscreen */
- if (self->fullscreen) {
- Rect *a;
- guint i;
-
- i = screen_find_monitor(&desired_area);
- a = screen_physical_area_monitor(i);
-
- *x = a->x;
- *y = a->y;
- *w = a->width;
- *h = a->height;
-
- user = FALSE; /* ignore if the client can't be moved/resized when it
- is fullscreening */
- } else if (self->max_horz || self->max_vert) {
- Rect *a;
- guint i;
-
- i = screen_find_monitor(&desired_area);
- a = screen_area_monitor(self->desktop, i);
-
- /* set the size and position if maximized */
- if (self->max_horz) {
- *x = a->x;
- *w = a->width - self->frame->size.left - self->frame->size.right;
- }
- if (self->max_vert) {
- *y = a->y;
- *h = a->height - self->frame->size.top - self->frame->size.bottom;
- }
-
- user = FALSE; /* ignore if the client can't be moved/resized when it
- is maximizing */
- }
-
- /* gets the client's position */
- frame_frame_gravity(self->frame, x, y, *w, *h);
-
/* these override the above states! if you cant move you can't move! */
if (user) {
if (!(self->functions & OB_CLIENT_FUNC_MOVE)) {
/* raise if it was not already on the desktop */
if (old != DESKTOP_ALL)
stacking_raise(CLIENT_AS_WINDOW(self));
+ /* the new desktop's geometry may be different, so we may need to
+ resize, for example if we are maximized */
+ client_reconfigure(self);
if (STRUT_EXISTS(self->strut))
screen_update_areas();
}
guint32 last_time = focus_client ? focus_client->user_time : CurrentTime;
gboolean allow = FALSE;
- /* if the request came from the user, or if nothing is focused, then grant
- the request.
- if the currently focused app doesn't set a user_time, then it can't
+ /* if the currently focused app doesn't set a user_time, then it can't
benefit from any focus stealing prevention.
+
+ if the timestamp is missing in the request then let it go through
+ even if it is source=app, because EVERY APPLICATION DOES THIS because
+ GTK IS VERY BUGGY AND HARDCODES source=application... WHY!?
*/
- if (user || !focus_client || !last_time)
+ if (!last_time || !event_curtime)
allow = TRUE;
/* otherwise, if they didn't give a time stamp or if it is too old, they
don't get focus */
else
- allow = event_curtime && event_time_after(event_curtime, last_time);
+ allow = event_time_after(event_curtime, last_time);
ob_debug_type(OB_DEBUG_FOCUS,
"Want to activate window 0x%x with time %u (last time %u), "
ObClient *client_direct_parent(ObClient *self)
{
if (!self->parents) return NULL;
- if (self->transient_for == OB_TRAN_GROUP) return NULL;
+ if (self->transient_for_group) return NULL;
return self->parents->data;
}
if (WINDOW_IS_CLIENT(it->data)) {
ObClient *c = WINDOW_AS_CLIENT(it->data);
if (c->frame->visible &&
+ /* check the desktop, this is done during desktop
+ switching and windows are shown/hidden status is not
+ reliable */
+ (c->desktop == screen_desktop ||
+ c->desktop == DESKTOP_ALL) &&
/* ignore all animating windows */
!frame_iconify_animating(c->frame) &&
RECT_CONTAINS(c->frame->area, x, y))