diff options
-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); |