static void client_get_area(ObClient *self);
static void client_get_desktop(ObClient *self);
static void client_get_state(ObClient *self);
+static void client_get_layer(ObClient *self);
static void client_get_shaped(ObClient *self);
static void client_get_mwm_hints(ObClient *self);
static void client_get_gravity(ObClient *self);
client_get_all(self);
client_restore_session_state(self);
+ client_calc_layer(self);
+
{
Time t = sn_app_started(self->startup_id, self->class);
if (t) self->user_time = t;
mouse_grab_for_client(self, TRUE);
if (activate) {
- /* This is focus stealing prevention, if a user_time has been set */
+ /* This is focus stealing prevention */
ob_debug("Want to focus new window 0x%x with time %u (last time %u)\n",
self->window, self->user_time, client_last_user_time);
- if (!self->user_time || self->user_time >= client_last_user_time)
+
+ /* If a nothing at all, or a parent was focused, then focus this
+ always
+ */
+ if (!focus_client || client_search_focus_parent(self) != NULL)
+ {
+ activate = TRUE;
+ }
+ else
+ {
+ /* If time stamp is old, don't steal focus */
+ if (self->user_time && self->user_time < client_last_user_time)
+ activate = FALSE;
+ /* 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)
+ {
+ activate = FALSE;
+ }
+ }
+
+ if (activate)
{
/* since focus can change the stacking orders, if we focus the
window then the standard raise it gets is not enough, we need
/* if the client isn't focused, then hilite it so the user
knows it is there */
client_hilite(self, TRUE);
-
- /* don't focus it ! (focus stealing prevention) */
- activate = FALSE;
}
}
else {
work right (eg tsclient). */
client_update_transient_for(self);
client_get_type(self);/* this can change the mwmhints for special cases */
+ client_get_state(self);
client_update_transient_for(self);
client_update_wmhints(self);
desktop is not specified */
client_get_shaped(self);
- client_get_state(self);
+ client_get_layer(self); /* if layer hasn't been specified, get it from
+ other sources if possible */
{
/* a couple type-based defaults for new windows */
}
}
+static void client_get_layer(ObClient *self)
+{
+ if (!(self->above || self->below)) {
+ if (self->group) {
+ /* apply stuff from the group */
+ GSList *it;
+ gint layer = -2;
+
+ for (it = self->group->members; it; it = g_slist_next(it)) {
+ ObClient *c = it->data;
+ if (c != self && !client_search_transient(self, c) &&
+ client_normal(self) && client_normal(c))
+ {
+ layer = MAX(layer,
+ (c->above ? 1 : (c->below ? -1 : 0)));
+ }
+ }
+ switch (layer) {
+ case -1:
+ self->below = TRUE;
+ break;
+ case -2:
+ case 0:
+ break;
+ case 1:
+ self->above = TRUE;
+ break;
+ default:
+ g_assert_not_reached();
+ break;
+ }
+ }
+ }
+}
+
static void client_get_state(ObClient *self)
{
guint32 *state;
g_free(state);
}
-
- if (!(self->above || self->below)) {
- if (self->group) {
- /* apply stuff from the group */
- GSList *it;
- gint layer = -2;
-
- for (it = self->group->members; it; it = g_slist_next(it)) {
- ObClient *c = it->data;
- if (c != self && !client_search_transient(self, c) &&
- client_normal(self) && client_normal(c))
- {
- layer = MAX(layer,
- (c->above ? 1 : (c->below ? -1 : 0)));
- }
- }
- switch (layer) {
- case -1:
- self->below = TRUE;
- break;
- case -2:
- case 0:
- break;
- case 1:
- self->above = TRUE;
- break;
- default:
- g_assert_not_reached();
- break;
- }
- }
- }
}
static void client_get_shaped(ObClient *self)
target = NULL;
}
-#if 0
-/* we used to do this, but it violates the ICCCM and causes problems because
- toolkits seem to set transient_for = root rather arbitrarily (eg kicker's
- config dialogs), so it is being removed. the ewmh provides other ways to
- make things transient for their group. -dana
-*/
+ /* THIS IS SO ANNOYING ! ! ! ! Let me explain.... have a seat..
+
+ Setting the transient_for to Root is actually illegal, however
+ applications from time have done this to specify transient for
+ their group.
+
+ Now you can do that by being a TYPE_DIALOG and not setting
+ the transient_for hint at all on your window. But people still
+ use Root, and Kwin is very strange in this regard.
+
+ KWin 3.0 will not consider windows with transient_for set to
+ Root as transient for their group *UNLESS* they are also modal.
+ In that case, it will make them transient for the group. This
+ leads to all sorts of weird behavior from KDE apps which are
+ only tested in KWin. I'd like to follow their behavior just to
+ make this work right with KDE stuff, but that seems wrong.
+ */
if (!target && self->group) {
/* not transient to a client, see if it is transient for a
group */
- if (t == self->group->leader ||
- t == None ||
- t == RootWindow(ob_display, ob_screen))
- {
+ if (t == RootWindow(ob_display, ob_screen)) {
/* window is a transient for its group! */
target = OB_TRAN_GROUP;
}
}
-#endif
-
}
} else if (self->type == OB_CLIENT_TYPE_DIALOG && self->group) {
self->transient = TRUE;
*/
if (new_event)
client_last_user_time = time;
+
+ /*ob_debug("window 0x%x user time %u\n", self->window, time);*/
}
}
netstate[num++] = prop_atoms.ob_wm_state_undecorated;
PROP_SETA32(self->window, net_wm_state, atom, netstate, num);
- client_calc_layer(self);
-
if (self->frame)
frame_adjust_state(self->frame);
}
}
static void client_calc_layer_recursive(ObClient *self, ObClient *orig,
- ObStackingLayer l, gboolean raised)
+ ObStackingLayer min, gboolean raised)
{
ObStackingLayer old, own;
GSList *it;
old = self->layer;
own = calc_layer(self);
- self->layer = l > own ? l : own;
+ self->layer = MAX(own, min);
+
+ ob_debug("layer for %s: %d\n", self->title, self->layer);
for (it = self->transients; it; it = g_slist_next(it))
client_calc_layer_recursive(it->data, orig,
- l, raised ? raised : l != old);
+ self->layer,
+ raised ? raised : self->layer != old);
- if (!raised && l != old)
+ if (!raised && self->layer != old)
if (orig->frame) { /* only restack if the original window is managed */
stacking_remove(CLIENT_AS_WINDOW(self));
stacking_add(CLIENT_AS_WINDOW(self));
void client_calc_layer(ObClient *self)
{
- ObStackingLayer l;
ObClient *orig;
+ GSList *it;
orig = self;
/* transients take on the layer of their parents */
- self = client_search_top_transient(self);
+ it = client_search_top_transients(self);
- l = calc_layer(self);
-
- client_calc_layer_recursive(self, orig, l, FALSE);
+ for (; it; it = g_slist_next(it))
+ client_calc_layer_recursive(it->data, orig, 0, FALSE);
}
gboolean client_should_show(ObClient *self)
gboolean moved = FALSE, resized = FALSE;
guint fdecor = self->frame->decorations;
gboolean fhorz = self->frame->max_horz;
+ Rect desired_area = {x, y, w, h};
/* make the frame recalculate its dimentions n shit without changing
anything visible for real, this way the constraints below can work with
Rect *a;
guint i;
- i = client_monitor(self);
+ i = screen_find_monitor(&desired_area);
a = screen_physical_area_monitor(i);
x = a->x;
user = FALSE; /* ignore that increment etc shit when in fullscreen */
} else {
Rect *a;
+ guint i;
- a = screen_area_monitor(self->desktop, client_monitor(self));
+ i = screen_find_monitor(&desired_area);
+ a = screen_area_monitor(self->desktop, i);
/* set the size and position if maximized */
if (self->max_horz) {
self->fullscreen == fs) return; /* already done */
self->fullscreen = fs;
- client_change_state(self); /* change the state hints on the client,
- and adjust out layer/stacking */
+ client_change_state(self); /* change the state hints on the client */
+ client_calc_layer(self); /* and adjust out layer/stacking */
if (fs) {
if (savearea)
void client_iconify(ObClient *self, gboolean iconic, gboolean curdesk)
{
+ GSList *it;
+
/* move up the transient chain as far as possible first */
- self = client_search_top_transient(self);
+ it = client_search_top_transients(self);
- client_iconify_recursive(client_search_top_transient(self),
- iconic, curdesk);
+ for (; it; it = g_slist_next(it))
+ client_iconify_recursive(it->data, iconic, curdesk);
}
void client_maximize(ObClient *self, gboolean max, gint dir, gboolean savearea)
void client_set_desktop(ObClient *self, guint target, gboolean donthide)
{
- client_set_desktop_recursive(client_search_top_transient(self),
- target, donthide);
+ GSList *it;
+
+ it = client_search_top_transients(self);
+
+ for(; it; it = g_slist_next(it))
+ client_set_desktop_recursive(it->data, target, donthide);
}
ObClient *client_search_modal_child(ObClient *self)
if (demands_attention != self->demands_attention)
client_hilite(self, demands_attention);
- client_calc_layer(self);
client_change_state(self); /* change the hint to reflect these changes */
}
ObClient *client_focus_target(ObClient *self)
{
- ObClient *child;
-
- /* if we have a modal child, then focus it, not us */
- child = client_search_modal_child(client_search_top_transient(self));
+ ObClient *child = NULL;
+
+ child = client_search_modal_child(self);
if (child) return child;
return self;
}
}
}
-void client_activate(ObClient *self, gboolean here, gboolean user,
- Time timestamp)
+void client_activate(ObClient *self, gboolean here, gboolean user, Time time)
{
/* XXX do some stuff here if user is false to determine if we really want
to activate it or not (a parent or group member is currently
active)?
*/
- if (!user)
+ ob_debug("Want to activate window 0x%x with time %u (last time %u), "
+ "source=%s\n",
+ self->window, time, client_last_user_time,
+ (user ? "user" : "application"));
+ if (!user && time && time < client_last_user_time)
client_hilite(self, TRUE);
else {
if (client_normal(self) && screen_showing_desktop)
}
}
-/* Determines which physical monitor a client is on by calculating the
- area of the part of the client on each monitor. The number of the
- monitor containing the greatest area of the client is returned.*/
guint client_monitor(ObClient *self)
{
- guint i;
- guint most = 0;
- guint mostv = 0;
-
- for (i = 0; i < screen_num_monitors; ++i) {
- Rect *area = screen_physical_area_monitor(i);
- if (RECT_INTERSECTS_RECT(*area, self->frame->area)) {
- Rect r;
- guint v;
-
- RECT_SET_INTERSECTION(r, *area, self->frame->area);
- v = r.width * r.height;
-
- if (v > mostv) {
- mostv = v;
- most = i;
- }
- }
- }
- return most;
+ return screen_find_monitor(&self->frame->area);
}
-ObClient *client_search_top_transient(ObClient *self)
+GSList *client_search_top_transients(ObClient *self)
{
- /* move up the transient chain as far as possible */
- if (self->transient_for) {
- if (self->transient_for != OB_TRAN_GROUP) {
- return client_search_top_transient(self->transient_for);
- } else {
+ GSList *ret = NULL;
+
+ /* move up the direct transient chain as far as possible */
+ while (self->transient_for && self->transient_for != OB_TRAN_GROUP)
+ self = self->transient_for;
+
+ if (!self->transient_for)
+ ret = g_slist_prepend(ret, self);
+ else {
GSList *it;
g_assert(self->group);
for (it = self->group->members; it; it = g_slist_next(it)) {
ObClient *c = it->data;
- /* checking transient_for prevents infinate loops! */
- if (c != self && !c->transient_for)
- break;
+ if (!c->transient_for)
+ ret = g_slist_prepend(ret, c);
}
- if (it)
- return it->data;
- }
+
+ if (ret == NULL) /* no group parents */
+ ret = g_slist_prepend(ret, self);
}
- return self;
+ return ret;
}
ObClient *client_search_focus_parent(ObClient *self)