+ /* set the NET_ACTIVE_WINDOW hint, but preserve it on shutdown */
+ if (ob_state() != OB_STATE_EXITING) {
+ active = client ? client->window : None;
+ OBT_PROP_SET32(obt_root(ob_screen), NET_ACTIVE_WINDOW, WINDOW, active);
+ }
+}
+
+static ObClient* focus_fallback_target(gboolean allow_refocus,
+ gboolean allow_pointer,
+ gboolean allow_omnipresent,
+ ObClient *old)
+{
+ GList *it;
+ ObClient *c;
+
+ ob_debug_type(OB_DEBUG_FOCUS, "trying pointer stuff");
+ if (allow_pointer && config_focus_follow)
+ if ((c = client_under_pointer()) &&
+ (allow_refocus || client_focus_target(c) != old) &&
+ (client_normal(c) &&
+ client_focus(c)))
+ {
+ ob_debug_type(OB_DEBUG_FOCUS, "found in pointer stuff");
+ return c;
+ }
+
+ ob_debug_type(OB_DEBUG_FOCUS, "trying the focus order");
+ for (it = focus_order; it; it = g_list_next(it)) {
+ c = it->data;
+ /* fallback focus to a window if:
+ 1. it is on the current desktop. this ignores omnipresent
+ windows, which are problematic in their own rite, unless they are
+ specifically allowed
+ 2. it is a valid auto-focus target
+ 3. it is not shaded
+ */
+ if ((allow_omnipresent || c->desktop == screen_desktop) &&
+ focus_valid_target(c, screen_desktop,
+ TRUE, FALSE, FALSE, TRUE, FALSE, FALSE,
+ FALSE) &&
+ !c->shaded &&
+ (allow_refocus || client_focus_target(c) != old) &&
+ client_focus(c))
+ {
+ ob_debug_type(OB_DEBUG_FOCUS, "found in focus order");
+ return c;
+ }
+ }
+
+ ob_debug_type(OB_DEBUG_FOCUS, "trying a desktop window");
+ for (it = focus_order; it; it = g_list_next(it)) {
+ c = it->data;
+ /* fallback focus to a window if:
+ 1. it is on the current desktop. this ignores omnipresent
+ windows, which are problematic in their own rite.
+ 2. it is a normal type window, don't fall back onto a dock or
+ a splashscreen or a desktop window (save the desktop as a
+ backup fallback though)
+ */
+ if (focus_valid_target(c, screen_desktop,
+ TRUE, FALSE, FALSE, TRUE, FALSE, TRUE, FALSE) &&
+ (allow_refocus || client_focus_target(c) != old) &&
+ client_focus(c))
+ {
+ ob_debug_type(OB_DEBUG_FOCUS, "found a desktop window");
+ return c;
+ }
+ }
+
+ return NULL;
+}
+
+ObClient* focus_fallback(gboolean allow_refocus, gboolean allow_pointer,
+ gboolean allow_omnipresent, gboolean focus_lost)
+{
+ ObClient *new;
+ ObClient *old = focus_client;
+
+ /* unfocus any focused clients.. they can be focused by Pointer events
+ and such, and then when we try focus them, we won't get a FocusIn
+ event at all for them. */
+ if (focus_lost)
+ focus_nothing();
+
+ new = focus_fallback_target(allow_refocus, allow_pointer,
+ allow_omnipresent, old);
+ /* get what was really focused */
+ if (new) new = client_focus_target(new);
+
+ return new;
+}
+
+void focus_nothing(void)
+{
+ /* nothing is focused, update the colormap and _the root property_ */
+ focus_set_client(NULL);
+
+ /* when nothing will be focused, send focus to the backup target */
+ XSetInputFocus(obt_display, screen_support_win, RevertToPointerRoot,
+ event_time());
+}
+
+void focus_order_add_new(ObClient *c)
+{
+ if (c->iconic)
+ focus_order_to_top(c);
+ else {
+ g_assert(!g_list_find(focus_order, c));
+ /* if there are only iconic windows, put this above them in the order,
+ but if there are not, then put it under the currently focused one */
+ if (focus_order && ((ObClient*)focus_order->data)->iconic)
+ focus_order = g_list_insert(focus_order, c, 0);
+ else
+ focus_order = g_list_insert(focus_order, c, 1);
+ }
+
+ focus_cycle_addremove(c, TRUE);
+}
+
+void focus_order_remove(ObClient *c)
+{
+ focus_order = g_list_remove(focus_order, c);
+
+ focus_cycle_addremove(c, TRUE);
+}
+
+void focus_order_like_new(struct _ObClient *c)
+{
+ focus_order = g_list_remove(focus_order, c);
+ focus_order_add_new(c);
+}
+
+void focus_order_to_top(ObClient *c)
+{
+ focus_order = g_list_remove(focus_order, c);
+ if (!c->iconic) {
+ focus_order = g_list_prepend(focus_order, c);
+ } else {
+ GList *it;