]> Dogcows Code - chaz/openbox/blobdiff - openbox/focus.c
debug print in focus.c
[chaz/openbox] / openbox / focus.c
index 058ad9beab5ad8653f5ffc25f3cff09b05f4078d..0f399be73e02a21e2817df2ec8fe4ea570a21b17 100644 (file)
+/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
+
+   focus.c for the Openbox window manager
+   Copyright (c) 2006        Mikael Magnusson
+   Copyright (c) 2003-2007   Dana Jansens
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   See the COPYING file for a copy of the GNU General Public License.
+*/
+
+#include "debug.h"
 #include "event.h"
 #include "openbox.h"
+#include "grab.h"
 #include "client.h"
-#include "frame.h"
+#include "config.h"
+#include "focus_cycle.h"
 #include "screen.h"
 #include "prop.h"
-#include "dispatch.h"
+#include "keyboard.h"
 #include "focus.h"
-#include "parse.h"
-#include "engine.h"
+#include "stacking.h"
 
 #include <X11/Xlib.h>
 #include <glib.h>
 
-Client *focus_client = NULL;
-GList **focus_order = NULL; /* these lists are created when screen_startup
-                               sets the number of desktops */
-
-Window focus_backup = None;
-gboolean focus_new = TRUE;
-gboolean focus_follow = TRUE;
+#define FOCUS_INDICATOR_WIDTH 6
 
-static gboolean noreorder = 0;
+ObClient *focus_client = NULL;
+GList *focus_order = NULL;
 
-static void parse_assign(char *name, ParseToken *value)
+void focus_startup(gboolean reconfig)
 {
-    if (!g_ascii_strcasecmp(name, "focusnew")) {
-        if (value->type != TOKEN_BOOL)
-            yyerror("invalid value");
-        else {
-            focus_new = value->data.bool;
-        }
-    } else if (!g_ascii_strcasecmp(name, "followmouse")) {
-        if (value->type != TOKEN_BOOL)
-            yyerror("invalid value");
-        else {
-            focus_follow = value->data.bool;
-        }
-    } else
-        yyerror("invalid option");
-    parse_free_token(value);
-}
-
-void focus_startup()
-{
-    /* create the window which gets focus when no clients get it. Have to
-       make it override-redirect so we don't try manage it, since it is
-       mapped. */
-    XSetWindowAttributes attrib;
-
-    focus_client = NULL;
-    focus_new = TRUE;
-    focus_follow = TRUE;
-
-    attrib.override_redirect = TRUE;
-    focus_backup = XCreateWindow(ob_display, ob_root,
-                                -100, -100, 1, 1, 0,
-                                 CopyFromParent, InputOutput, CopyFromParent,
-                                 CWOverrideRedirect, &attrib);
-    XMapRaised(ob_display, focus_backup);
+    if (reconfig) return;
 
     /* start with nothing focused */
-    focus_set_client(NULL);
-
-    parse_reg_section("focus", NULL, parse_assign);
+    focus_nothing();
 }
 
-void focus_shutdown()
+void focus_shutdown(gboolean reconfig)
 {
-    guint i;
-
-    for (i = 0; i < screen_num_desktops; ++i)
-        g_list_free(focus_order[i]);
-    g_free(focus_order);
-    focus_order = NULL;
-
-    XDestroyWindow(ob_display, focus_backup);
+    if (reconfig) return;
 
     /* reset focus to root */
-    XSetInputFocus(ob_display, PointerRoot, RevertToPointerRoot,
-                   event_lasttime);
+    XSetInputFocus(ob_display, PointerRoot, RevertToNone, CurrentTime);
 }
 
-static void push_to_top(Client *client)
+static void push_to_top(ObClient *client)
 {
-    guint desktop;
-
-    desktop = client->desktop;
-    if (desktop == DESKTOP_ALL) desktop = screen_desktop;
-    focus_order[desktop] = g_list_remove(focus_order[desktop], client);
-    focus_order[desktop] = g_list_prepend(focus_order[desktop], client);
+    focus_order = g_list_remove(focus_order, client);
+    focus_order = g_list_prepend(focus_order, client);
 }
 
-void focus_set_client(Client *client)
+void focus_set_client(ObClient *client)
 {
     Window active;
-    Client *old;
+
+    ob_debug_type(OB_DEBUG_FOCUS,
+                  "focus_set_client 0x%lx\n", client ? client->window : 0);
+
+    if (focus_client == client)
+        return;
 
     /* uninstall the old colormap, and install the new one */
     screen_install_colormap(focus_client, FALSE);
     screen_install_colormap(client, TRUE);
 
-    if (client == NULL) {
-       /* when nothing will be focused, send focus to the backup target */
-       XSetInputFocus(ob_display, focus_backup, RevertToPointerRoot,
-                       event_lasttime);
-        XSync(ob_display, FALSE);
-    }
+    /* in the middle of cycling..? kill it. */
+    focus_cycle_stop();
 
-    old = focus_client;
     focus_client = client;
 
-    /* move to the top of the list */
-    if (noreorder)
-        --noreorder;
-    else if (client != NULL)
+    if (client != NULL) {
+        /* move to the top of the list */
         push_to_top(client);
+        /* remove hiliting from the window when it gets focused */
+        client_hilite(client, FALSE);
+    }
 
-    /* set the NET_ACTIVE_WINDOW hint */
-    active = client ? client->window : None;
-    PROP_SET32(ob_root, net_active_window, window, active);
-
-    if (focus_client != NULL)
-        dispatch_client(Event_Client_Focus, focus_client, 0, 0);
-    if (old != NULL)
-        dispatch_client(Event_Client_Unfocus, old, 0, 0);
+    /* 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);
+    }
 }
 
-static gboolean focus_under_pointer()
+static ObClient* focus_fallback_target(gboolean allow_refocus, ObClient *old,
+                                       gboolean send_focus)
 {
-    Window w;
-    int i, x, y;
-    guint u;
     GList *it;
+    ObClient *c;
+
+    ob_debug_type(OB_DEBUG_FOCUS, "trying pointer stuff\n");
+    if (config_focus_follow && !config_focus_last)
+        if ((c = client_under_pointer()) &&
+            (allow_refocus || c != old) &&
+            client_normal(c) &&
+            /* if we're sending focus then try to */
+            ((send_focus && client_focus(c)) ||
+             /* if not just see if we could try, or it's already focused */
+             (!send_focus && (c == old || client_can_focus(c)))))
+        {
+            ob_debug_type(OB_DEBUG_FOCUS, "found in pointer stuff (%d)\n",
+                          send_focus);
+            return c;
+        }
 
-    if (XQueryPointer(ob_display, ob_root, &w, &w, &x, &y, &i, &i, &u)) {
-        for (it = stacking_list; it != NULL; it = it->next) {
-            Client *c = it->data;
-            if (c->desktop == screen_desktop &&
-                RECT_CONTAINS(c->frame->area, x, y))
-                break;
+    ob_debug_type(OB_DEBUG_FOCUS, "trying omnipresentness\n");
+    if (allow_refocus && old &&
+        old->desktop == DESKTOP_ALL &&
+        client_normal(old) &&
+        /* this one is only for when not sending focus, to keep it there */
+        !send_focus)
+    {
+        ob_debug_type(OB_DEBUG_FOCUS, "found in omnipresentness (%d)\n",
+                      send_focus);
+        return old;
+    }
+
+
+    ob_debug_type(OB_DEBUG_FOCUS, "trying the focus order\n");
+    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 (c->desktop == screen_desktop &&
+            client_normal(c) &&
+            (allow_refocus || c != old) &&
+            /* if we're sending focus then try to */
+            ((send_focus && client_focus(c)) ||
+             /* if not just see if we could try, or it's already focused */
+             (!send_focus && (c == old || client_can_focus(c)))))
+        {
+            ob_debug_type(OB_DEBUG_FOCUS, "found in focus order (%d) 0x%x "
+                          "from 0x%x\n",
+                          send_focus, c, old);
+            return c;
         }
-        if (it != NULL)
-            return client_normal(it->data) && client_focus(it->data);
     }
-    return FALSE;
+
+    ob_debug_type(OB_DEBUG_FOCUS, "trying a desktop window\n");
+    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 (c->type == OB_CLIENT_TYPE_DESKTOP &&
+            (allow_refocus || c != old) &&
+            /* if we're sending focus then try to */
+            ((send_focus && client_focus(c)) ||
+             /* if not just see if we could try, or it's already focused */
+             (!send_focus && (c == old || client_can_focus(c)))))
+        {
+            ob_debug_type(OB_DEBUG_FOCUS, "found a desktop window (%d)\n",
+                          send_focus);
+            return c;
+        }
+    }
+
+    return NULL;
 }
 
-void focus_fallback(gboolean switching_desks)
+ObClient* focus_fallback(gboolean allow_refocus)
 {
-    GList *it;
-    gboolean under = FALSE;
-    Client *old = NULL;
+    ObClient *new;
+    ObClient *old = focus_client;
 
-    old = focus_client;
+    new = focus_fallback_target(allow_refocus, old, FALSE);
+    if (new == old) return;
 
     /* unfocus any focused clients.. they can be focused by Pointer events
-       and such, and then when I try focus them, I won't get a FocusIn event
-       at all for them.
-    */
-    focus_set_client(NULL);
+       and such, and then when we try focus them, we won't get a FocusIn
+       event at all for them. */
+    focus_nothing();
 
-    if (switching_desks) {
-        /* don't skip any windows when switching desktops */
-        old = NULL;
-    } else {
-        if (focus_follow)
-            under = focus_under_pointer();
-    }
+    new = focus_fallback_target(allow_refocus, old, TRUE);
+
+    return new;
+}
 
-    if (!under) {
-        for (it = focus_order[screen_desktop]; it != NULL; it = it->next)
-            if (it->data != old && client_normal(it->data))
-                if (client_focus(it->data))
-                    break;
-        if (it == NULL) /* nothing to focus */
-            focus_set_client(NULL);
+void focus_nothing()
+{
+    /* Install our own colormap */
+    if (focus_client != NULL) {
+        screen_install_colormap(focus_client, FALSE);
+        screen_install_colormap(NULL, TRUE);
     }
+
+    /* nothing is focused, update the colormap and _the root property_ */
+    focus_set_client(NULL);
+
+    /* 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
+       and ignore them !
+
+       actions should not rely on being able to move focus during an
+       interactive grab.
+    */
+    if (keyboard_interactively_grabbed())
+        keyboard_interactive_cancel();
+
+    /* when nothing will be focused, send focus to the backup target */
+    XSetInputFocus(ob_display, screen_support_win, RevertToPointerRoot,
+                   event_curtime);
 }
 
-void focus_cycle(gboolean forward, gboolean linear, gboolean done,
-                 gboolean cancel)
+void focus_order_remove(ObClient *c)
 {
-    static Client *first = NULL;
-    static Client *t = NULL;
-    static GList *order = NULL;
-    GList *it, *start, *list;
-    Client *ft;
-
-    if (cancel) {
-        if (first) client_focus(first);
-        goto done_cycle;
-    } else if (done) {
-        if (focus_client) {
-            push_to_top(focus_client); /* move to top of focus_order */
-            stacking_raise(focus_client);
-        }
-        goto done_cycle;
+    focus_order = g_list_remove(focus_order, 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;
+
+        /* insert before first iconic window */
+        for (it = focus_order;
+             it && !((ObClient*)it->data)->iconic; it = g_list_next(it));
+        focus_order = g_list_insert_before(focus_order, it, c);
     }
-    if (!first) first = focus_client;
+}
 
-    if (linear) list = client_list;
-    else        list = focus_order[screen_desktop];
+void focus_order_to_bottom(ObClient *c)
+{
+    focus_order = g_list_remove(focus_order, c);
+    if (c->iconic) {
+        focus_order = g_list_append(focus_order, c);
+    } else {
+        GList *it;
 
-    start = it = g_list_find(list, focus_client);
-    if (!start) goto done_cycle; /* switched desktops or something? */
+        /* insert before first iconic window */
+        for (it = focus_order;
+             it && !((ObClient*)it->data)->iconic; it = g_list_next(it));
+        focus_order = g_list_insert_before(focus_order, it, c);
+    }
+}
 
-    do {
-        if (forward) {
-            it = it->next;
-            if (it == NULL) it = list;
-        } else {
-            it = it->prev;
-            if (it == NULL) it = g_list_last(list);
-        }
-        ft = client_focus_target(it->data);
-        if (ft == it->data && focus_client != ft && client_focusable(ft)) {
-            if (client_focus(ft)) {
-                noreorder++; /* avoid reordering the focus_order */
-                break;
-            }
-        }
-    } while (it != start);
-    return;
-
-done_cycle:
-    t = NULL;
-    first = NULL;
-    g_list_free(order);
-    order = NULL;
+ObClient *focus_order_find_first(guint desktop)
+{
+    GList *it;
+    for (it = focus_order; it; it = g_list_next(it)) {
+        ObClient *c = it->data;
+        if (c->desktop == desktop || c->desktop == DESKTOP_ALL)
+            return c;
+    }
+    return NULL;
 }
This page took 0.0318 seconds and 4 git commands to generate.