diff options
author | Vito Caputo <vcaputo@pengaru.com> | 2020-12-23 01:12:51 -0800 |
---|---|---|
committer | Vito Caputo <vcaputo@pengaru.com> | 2020-12-23 16:58:42 -0800 |
commit | 3161db573424a554b536aaa492397341b84683ce (patch) | |
tree | 1f72d7aa908dbb484bb8907b17bf493f551e2b85 /src | |
parent | a6998186a3546f9f871e2cab3e994c782bd98a98 (diff) |
*: introduce and use direction parameter
This adds a direction parameter to vwm_desktop_next{_mru}() and
vwm_win_focus_next(), deprecating _prev() variants in favor of
a vwm_direction_t parameter.
XK_r has been wired up as a modifier for reversing the direction
of actions like Mod1+Tab (window next MRU cycle) and Mod1+Space
(desktop next MRU cycle). So now if you overshoot, simply hold
the "r" key and repeat the operation to go back, much like how
Shift is often used for reversing alt+tab in i.e. Windows.
Diffstat (limited to 'src')
-rw-r--r-- | src/desktop.c | 60 | ||||
-rw-r--r-- | src/desktop.h | 6 | ||||
-rw-r--r-- | src/key.c | 29 | ||||
-rw-r--r-- | src/window.c | 68 | ||||
-rw-r--r-- | src/window.h | 3 |
5 files changed, 114 insertions, 52 deletions
diff --git a/src/desktop.c b/src/desktop.c index 1fcce8c..e6130e0 100644 --- a/src/desktop.c +++ b/src/desktop.c @@ -17,6 +17,7 @@ */ /* virtual desktops */ +#include <assert.h> #include <X11/Xlib.h> #include <stdlib.h> #include <string.h> @@ -80,39 +81,58 @@ int vwm_desktop_focus(vwm_t *vwm, vwm_desktop_t *desktop) return 1; } -/* return next MRU desktop relative to the supplied desktop */ -vwm_desktop_t * vwm_desktop_next_mru(vwm_t *vwm, vwm_desktop_t *desktop) + +/* return next MRU desktop relative to the supplied desktop, wraps-around */ +vwm_desktop_t * vwm_desktop_next_mru(vwm_t *vwm, vwm_desktop_t *desktop, vwm_direction_t direction) { - list_head_t *next; + vwm_desktop_t *next = desktop; /* this dance is necessary because the list head @ vwm->desktops_mru has no vwm_desktop_t container, * and we're exploiting the circular nature of the doubly linked lists, so we need to take care to skip * past the container-less head. */ - if (desktop->desktops_mru.next == &vwm->desktops_mru) { - next = desktop->desktops_mru.next->next; - } else { - next = desktop->desktops_mru.next; - } + switch (direction) { + case VWM_DIRECTION_FORWARD: + if (next->desktops_mru.next == &vwm->desktops_mru) { + next = list_entry(next->desktops_mru.next->next, vwm_desktop_t, desktops_mru); + } else { + next = list_entry(next->desktops_mru.next, vwm_desktop_t, desktops_mru); + } + break; - return list_entry(next, vwm_desktop_t, desktops_mru); -} + case VWM_DIRECTION_REVERSE: + if (next->desktops_mru.prev == &vwm->desktops_mru) { + next = list_entry(next->desktops_mru.prev->prev, vwm_desktop_t, desktops_mru); + } else { + next = list_entry(next->desktops_mru.prev, vwm_desktop_t, desktops_mru); + } + break; -/* return next desktop spatially relative to the supplied desktop, no wrap-around */ -vwm_desktop_t * vwm_desktop_next(vwm_t *vwm, vwm_desktop_t *desktop) -{ - if (desktop->desktops.next != &vwm->desktops) - desktop = list_entry(desktop->desktops.next, vwm_desktop_t, desktops); + default: + assert(0); + } - return desktop; + return next; } -/* return previous desktop spatially relative to the supplied desktop, no wrap-around */ -vwm_desktop_t * vwm_desktop_prev(vwm_t *vwm, vwm_desktop_t *desktop) +/* return next desktop spatially relative to the supplied desktop, no wrap-around */ +vwm_desktop_t * vwm_desktop_next(vwm_t *vwm, vwm_desktop_t *desktop, vwm_direction_t direction) { - if (desktop->desktops.prev != &vwm->desktops) - desktop = list_entry(desktop->desktops.prev, vwm_desktop_t, desktops); + switch (direction) { + case VWM_DIRECTION_FORWARD: + if (desktop->desktops.next != &vwm->desktops) + return list_entry(desktop->desktops.next, vwm_desktop_t, desktops); + break; + + case VWM_DIRECTION_REVERSE: + if (desktop->desktops.prev != &vwm->desktops) + return list_entry(desktop->desktops.prev, vwm_desktop_t, desktops); + break; + + default: + assert(0); + } return desktop; } diff --git a/src/desktop.h b/src/desktop.h index cc6df38..c231ca5 100644 --- a/src/desktop.h +++ b/src/desktop.h @@ -1,6 +1,7 @@ #ifndef _DESKTOP_H #define _DESKTOP_H +#include "direction.h" #include "list.h" #include "window.h" @@ -18,8 +19,7 @@ void vwm_desktop_mru(vwm_t *vwm, vwm_desktop_t *desktop); int vwm_desktop_focus(vwm_t *vwm, vwm_desktop_t *desktop); vwm_desktop_t * vwm_desktop_create(vwm_t *vwm, char *name); void vwm_desktop_destroy(vwm_t *vwm, vwm_desktop_t *desktop); -vwm_desktop_t * vwm_desktop_next_mru(vwm_t *vwm, vwm_desktop_t *desktop); -vwm_desktop_t * vwm_desktop_next(vwm_t *vwm, vwm_desktop_t *desktop); -vwm_desktop_t * vwm_desktop_prev(vwm_t *vwm, vwm_desktop_t *desktop); +vwm_desktop_t * vwm_desktop_next_mru(vwm_t *vwm, vwm_desktop_t *desktop, vwm_direction_t direction); +vwm_desktop_t * vwm_desktop_next(vwm_t *vwm, vwm_desktop_t *desktop, vwm_direction_t direction); #endif @@ -29,7 +29,8 @@ #include "window.h" #include "xwindow.h" -static int key_is_grabbed; /* flag for tracking keyboard grab state */ +static int key_is_grabbed; /* flag for tracking keyboard grab state */ +static vwm_direction_t direction = VWM_DIRECTION_FORWARD; /* flag for reversing directional actions */ /* Poll the keyboard state to see if _any_ keys are pressed */ static int keys_pressed(vwm_t *vwm) @@ -79,6 +80,11 @@ void vwm_key_released(vwm_t *vwm, Window win, XKeyReleasedEvent *keyrelease) break; + case XK_r: + VWM_TRACE("XK_r released with direction=%i", direction); + direction = VWM_DIRECTION_FORWARD; + break; + default: VWM_TRACE("Unhandled keycode: %x", (unsigned int)sym); break; @@ -133,6 +139,11 @@ void vwm_key_pressed(vwm_t *vwm, Window win, XKeyPressedEvent *keypress) VWM_TRACE("aborting with origin %p", vwm->focused_origin); break; + case XK_r: /* reverse directional actions */ + VWM_TRACE("XK_r pressed with direction=%i", direction); + direction = VWM_DIRECTION_REVERSE; + break; + case XK_grave: /* toggle shelf visibility */ vwm_context_focus(vwm, VWM_CONTEXT_OTHER); break; @@ -143,15 +154,17 @@ void vwm_key_pressed(vwm_t *vwm, Window win, XKeyPressedEvent *keypress) /* focus the next window, note this doesn't affect MRU yet, that happens on Mod1 release */ if (vwin) { if (keypress->state & ShiftMask) { - vwm_win_focus_next(vwm, vwin, VWM_FENCE_MASKED_VIOLATE); + vwm_win_focus_next(vwm, vwin, direction, VWM_FENCE_MASKED_VIOLATE); } else { - vwm_win_focus_next(vwm, vwin, VWM_FENCE_RESPECT); + vwm_win_focus_next(vwm, vwin, direction, VWM_FENCE_RESPECT); } } break; case XK_space: { /* cycle focused desktop utilizing MRU */ - vwm_desktop_t *next_desktop = vwm_desktop_next_mru(vwm, vwm->focused_desktop); + vwm_desktop_t *next_desktop; + + next_desktop = vwm_desktop_next_mru(vwm, vwm->focused_desktop, direction); do_grab = 1; /* update MRU desktop on commit (Mod1 release) */ @@ -205,7 +218,7 @@ void vwm_key_pressed(vwm_t *vwm, Window win, XKeyPressedEvent *keypress) if (keypress->state & ShiftMask) { if (vwin) { /* migrate the focused window with the desktop focus to the previous desktop */ - vwm_win_migrate(vwm, vwin, vwm_desktop_prev(vwm, vwin->desktop)); + vwm_win_migrate(vwm, vwin, vwm_desktop_next(vwm, vwin->desktop, VWM_DIRECTION_REVERSE)); } } else { if (vwm->focused_context == VWM_CONTEXT_SHELF) { @@ -213,7 +226,7 @@ void vwm_key_pressed(vwm_t *vwm, Window win, XKeyPressedEvent *keypress) vwm_context_focus(vwm, VWM_CONTEXT_DESKTOP); } else { /* focus the previous desktop */ - vwm_desktop_focus(vwm, vwm_desktop_prev(vwm, vwm->focused_desktop)); + vwm_desktop_focus(vwm, vwm_desktop_next(vwm, vwm->focused_desktop, VWM_DIRECTION_REVERSE)); } } break; @@ -224,7 +237,7 @@ void vwm_key_pressed(vwm_t *vwm, Window win, XKeyPressedEvent *keypress) if (keypress->state & ShiftMask) { if (vwin) { /* migrate the focused window with the desktop focus to the next desktop */ - vwm_win_migrate(vwm, vwin, vwm_desktop_next(vwm, vwin->desktop)); + vwm_win_migrate(vwm, vwin, vwm_desktop_next(vwm, vwin->desktop, VWM_DIRECTION_FORWARD)); } } else { if (vwm->focused_context == VWM_CONTEXT_SHELF) { @@ -232,7 +245,7 @@ void vwm_key_pressed(vwm_t *vwm, Window win, XKeyPressedEvent *keypress) vwm_context_focus(vwm, VWM_CONTEXT_DESKTOP); } else { /* focus the next desktop */ - vwm_desktop_focus(vwm, vwm_desktop_next(vwm, vwm->focused_desktop)); + vwm_desktop_focus(vwm, vwm_desktop_next(vwm, vwm->focused_desktop, VWM_DIRECTION_FORWARD)); } } break; diff --git a/src/window.c b/src/window.c index 4fee538..cfcdd36 100644 --- a/src/window.c +++ b/src/window.c @@ -256,7 +256,7 @@ void vwm_win_focus(vwm_t *vwm, vwm_window_t *vwin) /* focus the next window on a virtual desktop relative to the supplied window, in the specified context, respecting screen boundaries according to fence. */ -vwm_window_t * vwm_win_focus_next(vwm_t *vwm, vwm_window_t *vwin, vwm_fence_t fence) +vwm_window_t * vwm_win_focus_next(vwm_t *vwm, vwm_window_t *vwin, vwm_direction_t direction, vwm_fence_t fence) { const vwm_screen_t *scr = vwm_screen_find(vwm, VWM_SCREEN_REL_XWIN, vwin->xwindow), *next_scr = NULL; vwm_window_t *next; @@ -264,23 +264,51 @@ vwm_window_t * vwm_win_focus_next(vwm_t *vwm, vwm_window_t *vwin, vwm_fence_t fe _retry: visited_mask = 0; - list_for_each_entry(next, &vwin->windows_mru, windows_mru) { - /* searching for the next mapped window in this context, using vwin->windows as the head */ - if (&next->windows_mru == &vwm->windows_mru) - continue; /* XXX: skip the containerless head, we're leveraging the circular list implementation */ - - if ((vwin->shelved && next->shelved) || - ((!vwin->shelved && !next->shelved && next->desktop == vwin->desktop) && - (fence == VWM_FENCE_IGNORE || - ((fence == VWM_FENCE_RESPECT || fence == VWM_FENCE_TRY_RESPECT) && vwm_screen_find(vwm, VWM_SCREEN_REL_XWIN, next->xwindow) == scr) || - (fence == VWM_FENCE_VIOLATE && vwm_screen_find(vwm, VWM_SCREEN_REL_XWIN, next->xwindow) != scr) || - (fence == VWM_FENCE_MASKED_VIOLATE && (next_scr = vwm_screen_find(vwm, VWM_SCREEN_REL_XWIN, next->xwindow)) != scr && - !((1UL << next_scr->screen_number) & vwm->fence_mask)) - ))) - break; - if (fence == VWM_FENCE_MASKED_VIOLATE && next_scr && next_scr != scr) - visited_mask |= (1UL << next_scr->screen_number); + switch (direction) { + case VWM_DIRECTION_FORWARD: + list_for_each_entry(next, &vwin->windows_mru, windows_mru) { + /* searching for the next mapped window in this context, using vwin->windows as the head */ + if (&next->windows_mru == &vwm->windows_mru) + continue; /* XXX: skip the containerless head, we're leveraging the circular list implementation */ + + if ( ((next->desktop == vwin->desktop) && + (fence == VWM_FENCE_IGNORE || + ((fence == VWM_FENCE_RESPECT || fence == VWM_FENCE_TRY_RESPECT) && vwm_screen_find(vwm, VWM_SCREEN_REL_XWIN, next->xwindow) == scr) || + (fence == VWM_FENCE_VIOLATE && vwm_screen_find(vwm, VWM_SCREEN_REL_XWIN, next->xwindow) != scr) || + (fence == VWM_FENCE_MASKED_VIOLATE && (next_scr = vwm_screen_find(vwm, VWM_SCREEN_REL_XWIN, next->xwindow)) != scr && + !((1UL << next_scr->screen_number) & vwm->fence_mask)) + ))) + break; + + if (fence == VWM_FENCE_MASKED_VIOLATE && next_scr && next_scr != scr) + visited_mask |= (1UL << next_scr->screen_number); + } + break; + + case VWM_DIRECTION_REVERSE: + list_for_each_entry_prev(next, &vwin->windows_mru, windows_mru) { + /* searching for the next mapped window in this context, using vwin->windows as the head */ + if (&next->windows_mru == &vwm->windows_mru) + continue; /* XXX: skip the containerless head, we're leveraging the circular list implementation */ + + /* TODO: move most of this into a function shared by both direction cases */ + if ( ((next->desktop == vwin->desktop) && + (fence == VWM_FENCE_IGNORE || + ((fence == VWM_FENCE_RESPECT || fence == VWM_FENCE_TRY_RESPECT) && vwm_screen_find(vwm, VWM_SCREEN_REL_XWIN, next->xwindow) == scr) || + (fence == VWM_FENCE_VIOLATE && vwm_screen_find(vwm, VWM_SCREEN_REL_XWIN, next->xwindow) != scr) || + (fence == VWM_FENCE_MASKED_VIOLATE && (next_scr = vwm_screen_find(vwm, VWM_SCREEN_REL_XWIN, next->xwindow)) != scr && + !((1UL << next_scr->screen_number) & vwm->fence_mask)) + ))) + break; + + if (fence == VWM_FENCE_MASKED_VIOLATE && next_scr && next_scr != scr) + visited_mask |= (1UL << next_scr->screen_number); + } + break; + + default: + assert(0); } if (fence == VWM_FENCE_TRY_RESPECT && next == vwin) { @@ -331,7 +359,7 @@ void vwm_win_shelve(vwm_t *vwm, vwm_window_t *vwin) /* shelving focused window, focus the next window */ if (vwin == vwin->desktop->focused_window) - vwm_win_mru(vwm, vwm_win_focus_next(vwm, vwin, VWM_FENCE_RESPECT)); + vwm_win_mru(vwm, vwm_win_focus_next(vwm, vwin, VWM_DIRECTION_FORWARD, VWM_FENCE_RESPECT)); if (vwin == vwin->desktop->focused_window) /* TODO: we can probably put this into vwm_win_focus_next() and have it always handled there... */ @@ -354,7 +382,7 @@ void vwm_win_unfocus(vwm_t *vwm, vwm_window_t *vwin) /* TODO: there's probably some icky behaviors for focused windows unmapping/destroying in unfocused contexts, we probably jump contexts suddenly. */ if (vwin == vwm->focused_shelf) { VWM_TRACE("unfocusing focused shelf"); - vwm_win_focus_next(vwm, vwin, VWM_FENCE_IGNORE); + vwm_win_focus_next(vwm, vwin, VWM_DIRECTION_FORWARD, VWM_FENCE_IGNORE); if (vwin == vwm->focused_shelf) { VWM_TRACE("shelf empty, leaving"); @@ -367,7 +395,7 @@ void vwm_win_unfocus(vwm_t *vwm, vwm_window_t *vwin) /* if we're the focused window cycle the focus to the next window on the desktop if possible */ if (vwin->desktop->focused_window == vwin) { VWM_TRACE("unfocusing focused window"); - vwm_win_focus_next(vwm, vwin, VWM_FENCE_TRY_RESPECT); + vwm_win_focus_next(vwm, vwin, VWM_DIRECTION_FORWARD, VWM_FENCE_TRY_RESPECT); } if (vwin->desktop->focused_window == vwin) { diff --git a/src/window.h b/src/window.h index c142d89..00ebc72 100644 --- a/src/window.h +++ b/src/window.h @@ -4,6 +4,7 @@ #include <X11/Xlib.h> #include <X11/Xutil.h> +#include "direction.h" #include "list.h" #include "screen.h" @@ -71,7 +72,7 @@ typedef enum _vwm_fence_t { VWM_FENCE_MASKED_VIOLATE /* leave the screen for any other not masked */ } vwm_fence_t; -vwm_window_t * vwm_win_focus_next(vwm_t *vwm, vwm_window_t *vwin, vwm_fence_t fence); +vwm_window_t * vwm_win_focus_next(vwm_t *vwm, vwm_window_t *vwin, vwm_direction_t direction, vwm_fence_t fence); void vwm_win_shelve(vwm_t *vwm, vwm_window_t *vwin); void vwm_win_unfocus(vwm_t *vwm, vwm_window_t *vwin); vwm_xwindow_t * vwm_win_unmanage(vwm_t *vwm, vwm_window_t *vwin); |