{
ObStackingLayer l;
- if (self->fullscreen) l = OB_STACKING_LAYER_FULLSCREEN;
+ if (self->fullscreen &&
+ (client_focused(self) || client_search_focus_tree(self)))
+ l = OB_STACKING_LAYER_FULLSCREEN;
else if (self->type == OB_CLIENT_TYPE_DESKTOP)
l = OB_STACKING_LAYER_DESKTOP;
else if (self->type == OB_CLIENT_TYPE_DOCK) {
old = self->layer;
own = calc_layer(self);
- self->layer = l > own ? l : own;
+ self->layer = MAX(l, own);
+
+ g_message("calc for 0x%x %d %d", self->window, old, self->layer);
for (it = self->transients; it; it = it->next)
client_calc_layer_recursive(it->data, orig,
if (!raised && l != old)
if (orig->frame) { /* only restack if the original window is managed */
- /* XXX add_non_intrusive ever? */
stacking_remove(CLIENT_AS_WINDOW(self));
stacking_add(CLIENT_AS_WINDOW(self));
}
/* choose the correct target */
self = client_focus_target(self);
- if (!client_can_focus(self)) {
- if (!self->frame->visible) {
- /* update the focus lists */
- focus_order_to_top(self);
- }
+ if (!self->frame->visible) {
+ /* update the focus lists */
+ focus_order_to_top(self);
return FALSE;
}
+ if (!client_can_focus(self))
+ return FALSE;
+
if (self->can_focus) {
/* RevertToPointerRoot causes much more headache than RevertToNone, so
I choose to use it always, hopefully to find errors quicker, if any
XSendEvent(ob_display, self->window, FALSE, NoEventMask, &ce);
}
+ focus_set_client(self);
+
#ifdef DEBUG_FOCUS
ob_debug("%sively focusing %lx at %d\n",
(self->can_focus ? "act" : "pass"),
} ObEventData;
static void event_process(const XEvent *e, gpointer data);
+static void event_done(gpointer data);
static void event_handle_root(XEvent *e);
static void event_handle_menu(XEvent *e);
static void event_handle_dock(ObDock *s, XEvent *e);
}
}
- ob_main_loop_x_add(ob_main_loop, event_process, NULL, NULL);
+ ob_main_loop_x_add(ob_main_loop, event_process, event_done, NULL, NULL);
#ifdef USE_SM
IceAddConnectionWatch(ice_watch, NULL);
static gboolean event_ignore(XEvent *e, ObClient *client)
{
+ gboolean ignore = FALSE;
+ XEvent ce;
+
switch(e->type) {
case FocusIn:
+ while (XCheckTypedWindowEvent(ob_display, e->xfocus.window,
+ FocusIn, &ce))
+ {
+ if (!INVALID_FOCUSIN(&ce)) {
+ XPutBackEvent(ob_display, &ce);
+ ignore = TRUE;
+ break;
+ }
+ }
+
/* NotifyAncestor is not ignored in FocusIn like it is in FocusOut
because of RevertToPointerRoot. If the focus ends up reverting to
pointer root on a workspace change, then the FocusIn event that we
want will be of type NotifyAncestor. This situation does not occur
for FocusOut, so it is safely ignored there.
*/
- if (INVALID_FOCUSIN(e) ||
- client == NULL) {
+ if (ignore || INVALID_FOCUSIN(e) || client == NULL) {
#ifdef DEBUG_FOCUS
ob_debug("FocusIn on %lx mode %d detail %d IGNORED\n",
e->xfocus.window, e->xfocus.mode, e->xfocus.detail);
#endif
- /* says a client was not found for the event (or a valid FocusIn
- event was not found.
- */
- e->xfocus.window = None;
return TRUE;
}
#endif
break;
case FocusOut:
- if (INVALID_FOCUSOUT(e)) {
+ while (XCheckTypedWindowEvent(ob_display, e->xfocus.window,
+ FocusOut, &ce))
+ {
+ if (!INVALID_FOCUSOUT(&ce)) {
+ XPutBackEvent(ob_display, &ce);
+ ignore = TRUE;
+ break;
+ }
+ }
+
+ if (ignore || INVALID_FOCUSOUT(e)) {
#ifdef DEBUG_FOCUS
- ob_debug("FocusOut on %lx mode %d detail %d IGNORED\n",
- e->xfocus.window, e->xfocus.mode, e->xfocus.detail);
+ ob_debug("FocusOut on %lx mode %d detail %d IGNORED\n",
+ e->xfocus.window, e->xfocus.mode, e->xfocus.detail);
#endif
return TRUE;
}
ob_debug("FocusOut on %lx mode %d detail %d\n",
e->xfocus.window, e->xfocus.mode, e->xfocus.detail);
#endif
-
- {
- XEvent fe;
- gboolean fallback = TRUE;
-
- while (TRUE) {
- if (!XCheckTypedWindowEvent(ob_display, e->xfocus.window,
- FocusOut, &fe))
- if (!XCheckTypedEvent(ob_display, FocusIn, &fe))
- break;
- if (fe.type == FocusOut) {
-#ifdef DEBUG_FOCUS
- ob_debug("found pending FocusOut\n");
-#endif
- if (!INVALID_FOCUSOUT(&fe)) {
- /* if there is a VALID FocusOut still coming, don't
- fallback focus yet, we'll deal with it then */
- XPutBackEvent(ob_display, &fe);
- fallback = FALSE;
- break;
- }
- } else {
-#ifdef DEBUG_FOCUS
- ob_debug("found pending FocusIn\n");
-#endif
- /* is the focused window getting a FocusOut/In back to
- itself?
- */
- if (fe.xfocus.window == e->xfocus.window &&
- !event_ignore(&fe, client)) {
- /*
- if focus_client is not set, then we can't do
- this. we need the FocusIn. This happens in the
- case when the set_focus_client(NULL) in the
- focus_fallback function fires and then
- focus_fallback picks the currently focused
- window (such as on a SendToDesktop-esque action.
- */
- if (focus_client) {
-#ifdef DEBUG_FOCUS
- ob_debug("focused window got an Out/In back to "
- "itself IGNORED both\n");
-#endif
- return TRUE;
- } else {
- event_process(&fe, NULL);
-#ifdef DEBUG_FOCUS
- ob_debug("focused window got an Out/In back to "
- "itself but focus_client was null "
- "IGNORED just the Out\n");
-#endif
- return TRUE;
- }
- }
-
- {
- ObEventData d;
-
- /* once all the FocusOut's have been dealt with, if
- there is a FocusIn still left and it is valid, then
- use it */
- event_process(&fe, &d);
- if (!d.ignored) {
- ob_debug("FocusIn was OK, so don't fallback\n");
- fallback = FALSE;
- break;
- }
- }
- }
- }
- if (fallback) {
-#ifdef DEBUG_FOCUS
- ob_debug("no valid FocusIn and no FocusOut events found, "
- "falling back\n");
-#endif
- focus_fallback(OB_FOCUS_FALLBACK_NOFOCUS);
- }
- }
break;
case EnterNotify:
case LeaveNotify:
(e->xcrossing.detail == NotifyAncestor ||
e->xcrossing.detail == NotifyNonlinearVirtual ||
e->xcrossing.detail == NotifyVirtual))) {
-#ifdef DEBUG_FOCUS
+#ifdef aDEBUG_FOCUS
ob_debug("%sNotify mode %d detail %d on %lx IGNORED\n",
(e->type == EnterNotify ? "Enter" : "Leave"),
e->xcrossing.mode,
#endif
return TRUE;
}
-#ifdef DEBUG_FOCUS
+#ifdef aDEBUG_FOCUS
ob_debug("%sNotify mode %d detail %d on %lx\n",
(e->type == EnterNotify ? "Enter" : "Leave"),
e->xcrossing.mode,
}
}
+static void event_done(gpointer data)
+{
+ if (!focus_client)
+ focus_fallback(OB_FOCUS_FALLBACK_NOFOCUS);
+}
+
static void event_handle_root(XEvent *e)
{
Atom msgtype;
break;
case FocusIn:
#ifdef DEBUG_FOCUS
- ob_debug("FocusIn on client for %lx\n", client->window);
+ ob_debug("Focus%s on client for %lx\n", (e->type==FocusIn?"In":"Out"),
+ client->window);
#endif
- if (client != focus_client) {
+ if (client != focus_client)
focus_set_client(client);
- frame_adjust_focus(client->frame, TRUE);
- }
+ frame_adjust_focus(client->frame, e->type == FocusIn);
break;
case FocusOut:
#ifdef DEBUG_FOCUS
- ob_debug("FocusOut on client for %lx\n", client->window);
+ ob_debug("Focus%s on client for %lx\n", (e->type==FocusIn?"In":"Out"),
+ client->window);
#endif
- /* are we a fullscreen window or a transient of one? (checks layer)
- if we are then we need to be iconified since we are losing focus
- */
- if (client->layer == OB_STACKING_LAYER_FULLSCREEN && !client->iconic &&
- !client_search_focus_tree_full(client))
- /* iconify fullscreen windows when they and their transients
- aren't focused */
- client_iconify(client, TRUE, TRUE);
- frame_adjust_focus(client->frame, FALSE);
- break;
+ if (client == focus_client)
+ focus_client = NULL;
+ frame_adjust_focus(client->frame, e->type == FocusIn);
+ break;
case LeaveNotify:
con = frame_context(client, e->xcrossing.window);
switch (con) {
case OB_FRAME_CONTEXT_FRAME:
if (client_normal(client)) {
if (config_focus_follow) {
-#ifdef DEBUG_FOCUS
+#ifdef aDEBUG_FOCUS
ob_debug("EnterNotify on %lx, focusing window\n",
client->window);
#endif
screen_install_colormap(focus_client, FALSE);
screen_install_colormap(client, TRUE);
- if (client == NULL) {
+ if (!client) {
/* when nothing will be focused, send focus to the backup target */
XSetInputFocus(ob_display, screen_support_win, RevertToPointerRoot,
event_lasttime);
old = focus_client;
focus_client = client;
- /* move to the top of the list */
- if (client != NULL)
- push_to_top(client);
+ if (old) {
+ /* focus state can affect the stacking layer */
+ client_calc_layer(old);
+ }
+ if (client) {
+ /* focus state can affect the stacking layer */
+ client_calc_layer(client);
- /* set the NET_ACTIVE_WINDOW hint, but preserve it on shutdown */
- if (ob_state() != OB_STATE_EXITING) {
- active = client ? client->window : None;
- PROP_SET32(RootWindow(ob_display, ob_screen),
- net_active_window, window, active);
+ /* move to the top of the list */
+ push_to_top(client);
}
+
+ /* set the NET_ACTIVE_WINDOW hint */
+ active = client ? client->window : None;
+ PROP_SET32(RootWindow(ob_display, ob_screen),
+ net_active_window, window, active);
}
static gboolean focus_under_pointer()