New setting: history_aware_focus

This commit is contained in:
Bastien Dejean 2013-06-24 16:25:50 +02:00
parent 7fb314a3d4
commit d5d8805ad2
10 changed files with 143 additions and 51 deletions

View file

@ -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`.

View 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=()

View file

@ -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

View 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

View 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;
}

View 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];

140
tree.c
View file

@ -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,20 +137,97 @@ 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;
if (dir == DIR_UP || dir == DIR_LEFT)
return second_extrema(fence->first_child);
else if (dir == DIR_DOWN || dir == DIR_RIGHT)
return first_extrema(fence->second_child);
node_t *nearest = NULL;
return NULL;
if (dir == DIR_UP || dir == DIR_LEFT)
nearest = second_extrema(fence->first_child);
else if (dir == DIR_DOWN || dir == DIR_RIGHT)
nearest = first_extrema(fence->second_child);
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)
{
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)
{
if (n == NULL)
return NULL;
node_t *target = NULL;
if (is_tiled(n->client)) {
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;
} else {
target = d->root;
}
node_t *nearest = NULL;
direction_t dir2;
xcb_point_t pt;
xcb_point_t pt2;
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)
|| (is_tiled(a->client) && !is_adjacent(a, target))
|| a == n)
continue;
get_side_handle(a->client, dir2, &pt2);
double ds2 = distance(pt, pt2);
if (ds2 < ds) {
ds = ds2;
nearest = a;
}
}
return nearest;
}
void get_opposite(direction_t src, direction_t *dst)
{
switch (src) {
case DIR_RIGHT:
@ -154,43 +245,6 @@ void get_opposite(direction_t src, direction_t* dst)
}
}
node_t *nearest_neighbor(desktop_t *d, node_t *n, direction_t dir)
{
if (n == NULL)
return NULL;
node_t *target = NULL;
if (is_tiled(n->client)) {
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;
} else {
target = d->root;
}
node_t *nearest = NULL;
direction_t dir2;
xcb_point_t pt;
xcb_point_t pt2;
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)
continue;
get_side_handle(a->client, dir2, &pt2);
double ds2 = distance(pt, pt2);
if (ds2 < ds) {
ds = ds2;
nearest = a;
}
}
return nearest;
}
int tiled_area(node_t *n)
{
if (n == NULL)

4
tree.h
View file

@ -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);

14
types.c
View file

@ -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;
}

View file

@ -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