]> git.lizzy.rs Git - bspwm.git/commitdiff
New setting: `history_aware_focus`
authorBastien Dejean <nihilhill@gmail.com>
Mon, 24 Jun 2013 14:25:50 +0000 (16:25 +0200)
committerBastien Dejean <nihilhill@gmail.com>
Mon, 24 Jun 2013 14:25:50 +0000 (16:25 +0200)
README.md
bash_completion
bspwm.1
messages.c
settings.c
settings.h
tree.c
tree.h
types.c
types.h

index b39f1465507589ddb9955bd6dd8c44d99bf6491a..f24ba1e027036d5a750837637d7a606c190bb635 100644 (file)
--- a/README.md
+++ b/README.md
@@ -247,6 +247,8 @@ All the boolean settings are *false* by default.
 
 - `focus_by_distance` — Use window or leaf distance for focus movement.
 
+- `history_aware_focus` — Give priority to the focus history when focusing nodes.
+
 ## Environment Variables
 
 - `BSPWM_SOCKET` — The path of the socket used for the communication between `bspc` and `bspwm`.
index f51024714201f6e68e606919a95a930dfadbec6f..396574447db9f57fa29168aa064abc8979a03962 100644 (file)
@@ -2,7 +2,7 @@ _bspc()
 {
     local messages='get set list list_desktops list_monitors list_windows list_rules list_history presel cancel ratio pad focus shift swap push pull fence_ratio cycle nearest biggest circulate grab_pointer track_pointer ungrab_pointer toggle_fullscreen toggle_floating toggle_locked toggle_visibility close kill send_to drop_to send_to_monitor drop_to_monitor use use_monitor alternate alternate_desktop alternate_monitor add add_in rename_monitor rename remove_desktop send_desktop_to cycle_monitor cycle_desktop layout cycle_layout rotate flip balance rule remove_rule put_status adopt_orphans restore_layout restore_history quit'
 
-    local settings='focused_border_color active_border_color normal_border_color presel_border_color focused_locked_border_color active_locked_border_color normal_locked_border_color urgent_border_color border_width window_gap split_ratio top_padding right_padding bottom_padding left_padding wm_name borderless_monocle gapless_monocle focus_follows_pointer pointer_follows_monitor adaptative_raise apply_shadow_property auto_alternate focus_by_distance'
+    local settings='focused_border_color active_border_color normal_border_color presel_border_color focused_locked_border_color active_locked_border_color normal_locked_border_color urgent_border_color border_width window_gap split_ratio top_padding right_padding bottom_padding left_padding wm_name borderless_monocle gapless_monocle focus_follows_pointer pointer_follows_monitor adaptative_raise apply_shadow_property auto_alternate focus_by_distance history_aware_focus'
 
     COMPREPLY=()
 
diff --git a/bspwm.1 b/bspwm.1
index 388b234aaf5e752ba47c2a0aa96ffccc794b87d8..973908408dc78d87f578ba1d68ee6f383de761c5 100644 (file)
--- a/bspwm.1
+++ b/bspwm.1
@@ -372,6 +372,9 @@ message.
 .TP
 .I focus_by_distance
 Use window or leaf distance for focus movement.
+.TP
+.I history_aware_focus
+Give priority to the focus history when focusing nodes.
 .SH ENVIRONMENT VARIABLES
 .TP
 .I BSPWM_SOCKET
index c22431047f99389fb83bc1af63dff78f3152e25d..2675a3cd1186e15ccac543b704f6af099b1ce5a2 100644 (file)
@@ -445,17 +445,23 @@ void process_message(char *msg, char *rsp)
             }
         }
     } else if (strcmp(cmd, "focus") == 0) {
-        if (mon->desk->focus == NULL || mon->desk->focus->client->fullscreen)
+        node_t *f = mon->desk->focus;
+        if (f == NULL || f->client->fullscreen)
             return;
         char *dir = strtok(NULL, TOK_SEP);
         if (dir != NULL) {
             direction_t d;
             if (parse_direction(dir, &d)) {
-                node_t *n;
-                if (focus_by_distance)
-                    n = nearest_neighbor(mon->desk, mon->desk->focus, d);
-                else
-                    n = find_neighbor(mon->desk->focus, d);
+                node_t *n = NULL;
+                if (history_aware_focus)
+                    n = nearest_from_history(mon->desk->history, f, d);
+                if (n == NULL) {
+                    if (focus_by_distance) {
+                        n = nearest_neighbor(mon->desk, f, d);
+                    } else {
+                        n = find_neighbor(f, d);
+                    }
+                }
                 focus_node(mon, mon->desk, n);
             }
         }
@@ -570,6 +576,11 @@ void set_setting(char *name, char *value, char *rsp)
         if (parse_bool(value, &b))
             focus_by_distance = b;
         return;
+    } else if (strcmp(name, "history_aware_focus") == 0) {
+        bool b;
+        if (parse_bool(value, &b))
+            history_aware_focus = b;
+        return;
     } else if (strcmp(name, "wm_name") == 0) {
         strncpy(wm_name, value, sizeof(wm_name));
         ewmh_update_wm_name();
@@ -635,6 +646,8 @@ void get_setting(char *name, char* rsp)
         snprintf(rsp, BUFSIZ, "%s", BOOLSTR(auto_alternate));
     else if (strcmp(name, "focus_by_distance") == 0)
         snprintf(rsp, BUFSIZ, "%s", BOOLSTR(focus_by_distance));
+    else if (strcmp(name, "history_aware_focus") == 0)
+        snprintf(rsp, BUFSIZ, "%s", BOOLSTR(history_aware_focus));
     else if (strcmp(name, "wm_name") == 0)
         snprintf(rsp, BUFSIZ, "%s", wm_name);
     else
index 8852740226cb7dc009e09afb13daefb681849279..33266557d9db37dcb802950943c5b9e6a3f0df03 100644 (file)
@@ -68,4 +68,5 @@ void load_settings(void)
     apply_shadow_property = APPLY_SHADOW_PROPERTY;
     auto_alternate = AUTO_ALTERNATE;
     focus_by_distance = FOCUS_BY_DISTANCE;
+    history_aware_focus = HISTORY_AWARE_FOCUS;
 }
index f38924e91355e0a2b2e3172f356b6227c3b826ef..aa72cefbbf7a3a5ed3d42bb1957ca35ba59bd413 100644 (file)
@@ -28,6 +28,7 @@
 #define APPLY_SHADOW_PROPERTY    false
 #define AUTO_ALTERNATE           false
 #define FOCUS_BY_DISTANCE        false
+#define HISTORY_AWARE_FOCUS      false
 
 char focused_border_color[MAXLEN];
 char active_border_color[MAXLEN];
@@ -59,6 +60,7 @@ bool adaptative_raise;
 bool apply_shadow_property;
 bool auto_alternate;
 bool focus_by_distance;
+bool history_aware_focus;
 
 char wm_name[MAXLEN];
 
diff --git a/tree.c b/tree.c
index 3128ddda2407a1176eb20a432956d120e5b69332..a6041a92546b11bad8603093d7ad3c33353c64e2 100644 (file)
--- a/tree.c
+++ b/tree.c
@@ -2,6 +2,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <ctype.h>
+#include <limits.h>
 #include <math.h>
 #include <float.h>
 #include <xcb/xcb.h>
@@ -100,6 +101,19 @@ node_t *prev_leaf(node_t *n, node_t *r)
     return second_extrema(p->parent->first_child);
 }
 
+bool is_adjacent(node_t *a, node_t *r)
+{
+    node_t *f = r->parent;
+    node_t *p = a;
+    bool first_child = is_first_child(r);
+    while (p != r) {
+        if (p->parent->split_type == f->split_type && is_first_child(p) == first_child)
+            return false;
+        p = p->parent;
+    }
+    return true;
+}
+
 node_t *find_fence(node_t *n, direction_t dir)
 {
     node_t *p;
@@ -123,35 +137,51 @@ node_t *find_fence(node_t *n, direction_t dir)
 
 node_t *find_neighbor(node_t *n, direction_t dir)
 {
+    if (n == NULL)
+        return NULL;
+
     node_t *fence = find_fence(n, dir);
 
     if (fence == NULL)
         return NULL;
 
+    node_t *nearest = NULL;
+
     if (dir == DIR_UP || dir == DIR_LEFT)
-        return second_extrema(fence->first_child);
+        nearest = second_extrema(fence->first_child);
     else if (dir == DIR_DOWN || dir == DIR_RIGHT)
-        return first_extrema(fence->second_child);
+        nearest = first_extrema(fence->second_child);
 
-    return NULL;
+    return nearest;
 }
 
-void get_opposite(direction_t src, direction_t* dst)
+node_t *nearest_from_history(focus_history_t *f, node_t *n, direction_t dir)
 {
-    switch (src) {
-        case DIR_RIGHT:
-            *dst = DIR_LEFT;
-            break;
-        case DIR_DOWN:
-            *dst = DIR_UP;
-            break;
-        case DIR_LEFT:
-            *dst = DIR_RIGHT;
-            break;
-        case DIR_UP:
-            *dst = DIR_DOWN;
-            break;
+    if (n == NULL || !is_tiled(n->client))
+        return NULL;
+
+    node_t *target = find_fence(n, dir);
+    if (target == NULL)
+        return NULL;
+    if (dir == DIR_UP || dir == DIR_LEFT)
+        target = target->first_child;
+    else if (dir == DIR_DOWN || dir == DIR_RIGHT)
+        target = target->second_child;
+
+    node_t *nearest = NULL;
+    int min_rank = INT_MAX;
+
+    for (node_t *a = first_extrema(target); a != NULL; a = next_leaf(a, target)) {
+        if (!is_tiled(a->client) || !is_adjacent(a, target) || a == n)
+            continue;
+        int rank = history_rank(f, a);
+        if (rank >= 0 && rank < min_rank) {
+            nearest = a;
+            min_rank = rank;
+        }
     }
+
+    return nearest;
 }
 
 node_t *nearest_neighbor(desktop_t *d, node_t *n, direction_t dir)
@@ -160,6 +190,7 @@ node_t *nearest_neighbor(desktop_t *d, node_t *n, direction_t dir)
         return NULL;
 
     node_t *target = NULL;
+
     if (is_tiled(n->client)) {
         target = find_fence(n, dir);
         if (target == NULL)
@@ -171,6 +202,7 @@ node_t *nearest_neighbor(desktop_t *d, node_t *n, direction_t dir)
     } else {
         target = d->root;
     }
+
     node_t *nearest = NULL;
     direction_t dir2;
     xcb_point_t pt;
@@ -178,8 +210,11 @@ node_t *nearest_neighbor(desktop_t *d, node_t *n, direction_t dir)
     get_side_handle(n->client, dir, &pt);
     get_opposite(dir, &dir2);
     double ds = DBL_MAX;
+
     for (node_t *a = first_extrema(target); a != NULL; a = next_leaf(a, target)) {
-        if (is_tiled(a->client) != is_tiled(n->client) || a == n)
+        if (is_tiled(a->client) != is_tiled(n->client)
+                || (is_tiled(a->client) && !is_adjacent(a, target))
+                || a == n)
             continue;
         get_side_handle(a->client, dir2, &pt2);
         double ds2 = distance(pt, pt2);
@@ -188,9 +223,28 @@ node_t *nearest_neighbor(desktop_t *d, node_t *n, direction_t dir)
             nearest = a;
         }
     }
+
     return nearest;
 }
 
+void get_opposite(direction_t src, direction_t *dst)
+{
+    switch (src) {
+        case DIR_RIGHT:
+            *dst = DIR_LEFT;
+            break;
+        case DIR_DOWN:
+            *dst = DIR_UP;
+            break;
+        case DIR_LEFT:
+            *dst = DIR_RIGHT;
+            break;
+        case DIR_UP:
+            *dst = DIR_DOWN;
+            break;
+    }
+}
+
 int tiled_area(node_t *n)
 {
     if (n == NULL)
diff --git a/tree.h b/tree.h
index 360b26924c66cd105b51a2f32d8b00ea1d14e483..9044bed150b917d203fd227fea0324aeb82fe339 100644 (file)
--- a/tree.h
+++ b/tree.h
@@ -15,10 +15,12 @@ node_t *first_extrema(node_t *);
 node_t *second_extrema(node_t *);
 node_t *next_leaf(node_t *, node_t *);
 node_t *prev_leaf(node_t *, node_t *);
+bool is_adjacent(node_t *, node_t *);
 node_t *find_fence(node_t *, direction_t);
 node_t *find_neighbor(node_t *, direction_t);
-void get_opposite(direction_t, direction_t*);
 node_t *nearest_neighbor(desktop_t *, node_t *, direction_t);
+node_t *nearest_from_history(focus_history_t *, node_t *, direction_t);
+void get_opposite(direction_t, direction_t *);
 int tiled_area(node_t *);
 node_t *find_biggest(desktop_t *);
 void move_fence(node_t *, direction_t, fence_move_t);
diff --git a/types.c b/types.c
index 3207c5b43d7f386f7d762489045fcdc4e5333bb4..262a7b8003e7b15eaf456896a9fa8a1dda831494 100644 (file)
--- a/types.c
+++ b/types.c
@@ -336,3 +336,17 @@ node_t *history_get(focus_history_t *f, int i)
     else
         return a->node;
 }
+
+int history_rank(focus_history_t *f, node_t *n)
+{
+    int i = 0;
+    node_list_t *a = f->head;
+    while (a != NULL && (!a->latest || a->node != n)) {
+        a = a->next;
+        i++;
+    }
+    if (a == NULL)
+        return -1;
+    else
+        return i;
+}
diff --git a/types.h b/types.h
index f908dae9126af8e6f33effdda7f714539a5b5f90..f22220d6d1f2b95fb9b439bb5c9a50fae4f598b1 100644 (file)
--- a/types.h
+++ b/types.h
@@ -267,5 +267,6 @@ void history_add(focus_history_t *, node_t *);
 void history_remove(focus_history_t *, node_t *);
 void empty_history(focus_history_t *);
 node_t *history_get(focus_history_t *, int);
+int history_rank(focus_history_t *, node_t *);
 
 #endif