These patches make a bunch of changes to the switchpanel.
The first one fixes a minor irritation that had been bothering me for a while without my being able to pinpoint what it was that was annoying. If you hold down alt and press tab (assuming alt+tab is your focus next window shortcut, of course) the switchpanel remains open as long as you hold alt. But if you hold down alt and press shift+tab it closes as soon as you let go of shift even if alt remains pressed. That is not true in Windows so the inconsistency could be viewed as a bug.
We don't usually like to change behaviour without warning so the first patch makes the fix a configurable option. If the concensus is that it really is a bug the second patch may be applied, as it will set the default value of the new option to on. It should be noted that the subsequent patches work much better with the fix in place.
The third patch is a bit of code dedup.The fourth patch corrects a bit of faulty logic which probably never affected anyone in the first place.
The fifth patch tweaks the switchpanel so that the focus next/previous group shortcuts, ie the "OS X style" shortcuts which restrict cycling to windows of the same WM_CLASS, work as advertised even when the panel was already open. Previously you could press the focus next shortcut and build a switchpanel with all the open windows shown. Focus next group would work exactly the same as focus next for the lifetime of the panel, switching between all windows. With the patch it will skip over windows of a different WM_CLASS even if the panel was initially opened with focus next.
The sixth patch allows you to configure custom shortcuts when the switchpanel is open. Previously you could select windows with Left, Right, Home and End. With this patch those keys still work but you can additionally bind arbitrary shortcuts to select the previous, next, first and last windows respectively. There are also new shortcuts for class-specific selection.
The seventh patch teaches WPrefs how configure the new shortcut keys. The eighth patch documents all the above in NEWS.
From 9e5e4f2333d9d97eb64dc18446091a5caee517cc Mon Sep 17 00:00:00 2001 From: Iain Patterson <[email protected]> Date: Mon, 22 Apr 2013 10:49:45 +0100 Subject: [PATCH 1/8] Fix StartWindozeCycle() shift key behaviour. As the name implies, StartWindozeCycle() cycles windows in the same way that a popular commercially-available operating system does. However Window Maker's handling of the shift key in the switchpanel does not currently mirror that of its commercial counterpart. In the popular operating system: Holding alt and shift then pressing and releasing tab will highlight the previous window in the switcher. Releasing shift with alt still held will not close the switcher. The window change is commited when alt is released. In Window Maker: Holding alt and shift then pressing and releasing tab will highlight the previous window in the switchpanel. Releasing shift with alt still held will close the switchpanel and commit the window change. This patch adds the StrictWindozeCycle boolean preference. When it is set to YES the switchpanel will remain open as long as alt is held even if shift is pressed and released. --- src/WindowMaker.h | 1 + src/cycling.c | 4 ++++ src/defaults.c | 2 ++ 3 files changed, 7 insertions(+) diff --git a/src/WindowMaker.h b/src/WindowMaker.h index 50d5dc2..bc034d9 100644 --- a/src/WindowMaker.h +++ b/src/WindowMaker.h @@ -418,6 +418,7 @@ typedef struct WPreferences { int history_lines; /* history of "Run..." dialog */ char cycle_active_head_only; /* Cycle only windows on the active head */ char cycle_ignore_minimized; /* Ignore minimized windows when cycling */ + char strict_windoze_cycle; /* don't close switchpanel when shift is released */ /* All delays here are in ms. 0 means instant auto-action. */ int clip_auto_raise_delay; /* Delay after which the clip will be raised when entered */ diff --git a/src/cycling.c b/src/cycling.c index b2c7726..a2168d6 100644 --- a/src/cycling.c +++ b/src/cycling.c @@ -191,6 +191,10 @@ void StartWindozeCycle(WWindow * wwin, XEvent * event, Bool next, Bool class_onl case KeyRelease: + if (ev.xkey.keycode == shiftLKey || ev.xkey.keycode == shiftRKey) + if (wPreferences.strict_windoze_cycle) + break; + for (i = 0; i < 8 * keymap->max_keypermod; i++) { int mask = 1 << (i / keymap->max_keypermod); diff --git a/src/defaults.c b/src/defaults.c index 53d8173..748f839 100644 --- a/src/defaults.c +++ b/src/defaults.c @@ -474,6 +474,8 @@ WDefaultEntry optionList[] = { &wPreferences.dont_blink, getBool, NULL, NULL, NULL}, {"SingleClickLaunch", "NO", NULL, &wPreferences.single_click, getBool, NULL, NULL, NULL}, + {"StrictWindozeCycle", "NO", NULL, + &wPreferences.strict_windoze_cycle, getBool, NULL, NULL, NULL}, /* style options */ -- 1.8.1.4
From c7c7ffafea08809438a4bc4d6e13de9ce16df733 Mon Sep 17 00:00:00 2001 From: Iain Patterson <[email protected]> Date: Mon, 22 Apr 2013 10:56:38 +0100 Subject: [PATCH 2/8] Set StrictWindozeCycle by default. Window Maker's behaviour changes when StrictWindozeCycle is active. As a rule we try not to set the default value of new options such that they would change the behaviour expected by users. In this case, however, the switchpanel was not working as intended. Users who prefer the old method can set StrictWindozeCycle off with wdwrite WindowMaker StrictWindozeCycle NO --- src/defaults.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/defaults.c b/src/defaults.c index 748f839..a2d6e21 100644 --- a/src/defaults.c +++ b/src/defaults.c @@ -474,7 +474,7 @@ WDefaultEntry optionList[] = { &wPreferences.dont_blink, getBool, NULL, NULL, NULL}, {"SingleClickLaunch", "NO", NULL, &wPreferences.single_click, getBool, NULL, NULL, NULL}, - {"StrictWindozeCycle", "NO", NULL, + {"StrictWindozeCycle", "YES", NULL, &wPreferences.strict_windoze_cycle, getBool, NULL, NULL, NULL}, /* style options */ -- 1.8.1.4
From 9461f51c75a242c983b7b6f846416385f1338adb Mon Sep 17 00:00:00 2001 From: Iain Patterson <[email protected]> Date: Mon, 22 Apr 2013 13:46:22 +0100 Subject: [PATCH 3/8] Added sameWindowClass(). Avoid code duplication by moving check for windows of the same WM_CLASS to the new function sameWindowClass(). --- src/switchpanel.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/switchpanel.c b/src/switchpanel.c index 4ad9b8c..cd24f7b 100644 --- a/src/switchpanel.c +++ b/src/switchpanel.c @@ -95,6 +95,16 @@ static int canReceiveFocus(WWindow *wwin) return 1; } +static Bool sameWindowClass(WWindow *wwin, WWindow *curwin) +{ + if (!wwin->wm_class || !curwin->wm_class) + return False; + if (strcmp(wwin->wm_class, curwin->wm_class)) + return False; + + return True; +} + static void changeImage(WSwitchPanel *panel, int idecks, int selected) { WMFrame *icon = WMGetFromArray(panel->icons, idecks); @@ -338,12 +348,9 @@ static WMArray *makeWindowListArray(WWindow *curwin, int include_unmapped, Bool for (wwin = curwin; wwin; wwin = wwin->prev) { if (((!fl && canReceiveFocus(wwin) > 0) || (fl && canReceiveFocus(wwin) < 0)) && (wwin->flags.mapped || include_unmapped)) { - if (class_only) { - if (!wwin->wm_class || !curwin->wm_class) + if (class_only) + if (!sameWindowClass(wwin, curwin)) continue; - if (strcmp(wwin->wm_class, curwin->wm_class)) - continue; - } if (!WFLAGP(wwin, skip_switchpanel)) WMAddToArray(windows, wwin); @@ -357,13 +364,9 @@ static WMArray *makeWindowListArray(WWindow *curwin, int include_unmapped, Bool for (wwin = curwin; wwin && wwin != curwin; wwin = wwin->prev) { if (((!fl && canReceiveFocus(wwin) > 0) || (fl && canReceiveFocus(wwin) < 0)) && (wwin->flags.mapped || include_unmapped)) { - if (class_only) { - if (!wwin->wm_class || !curwin->wm_class) - continue; - if (strcmp(wwin->wm_class, curwin->wm_class)) + if (class_only) + if (!sameWindowClass(wwin, curwin)) continue; - } - if (!WFLAGP(wwin, skip_switchpanel)) WMAddToArray(windows, wwin); } -- 1.8.1.4
From 8352e6ca66743688c5e46ddfa5b990a56bad6cd5 Mon Sep 17 00:00:00 2001 From: Iain Patterson <[email protected]> Date: Mon, 22 Apr 2013 13:41:46 +0100 Subject: [PATCH 4/8] Correct check for modifier in class-specific cycle. The hasModifier flag was set if the FocusNextKey or FocusPrevKey shortcuts had modifiers, depending on which shortcut was used to open the switchpanel. The switchpanel can also be opened with the GroupNextKey or GroupPrevKey shortcuts, so we should account for those when setting hasModifier. --- src/cycling.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/cycling.c b/src/cycling.c index a2168d6..f989554 100644 --- a/src/cycling.c +++ b/src/cycling.c @@ -105,10 +105,17 @@ void StartWindozeCycle(WWindow * wwin, XEvent * event, Bool next, Bool class_onl if (!wwin) return; - if (next) - hasModifier = (wKeyBindings[WKBD_FOCUSNEXT].modifier != 0); - else - hasModifier = (wKeyBindings[WKBD_FOCUSPREV].modifier != 0); + if (next) { + if (class_only) + hasModifier = (wKeyBindings[WKBD_GROUPNEXT].modifier != 0); + else + hasModifier = (wKeyBindings[WKBD_FOCUSNEXT].modifier != 0); + } else { + if (class_only) + hasModifier = (wKeyBindings[WKBD_GROUPPREV].modifier != 0); + else + hasModifier = (wKeyBindings[WKBD_FOCUSPREV].modifier != 0); + } if (hasModifier) { keymap = XGetModifierMapping(dpy); -- 1.8.1.4
From a46d6917cff051349e6599480d033dadff3e124d Mon Sep 17 00:00:00 2001 From: Iain Patterson <[email protected]> Date: Mon, 22 Apr 2013 14:03:14 +0100 Subject: [PATCH 5/8] Support for same-class cycling in open switchpanel. If the switchpanel was opened with either FocusNextKey or FocusPrevKey shortcut, and the user presses GroupNextKey or GroupPrevKey, skip over windows of a different class when cycling through windows in the switchpanel. In the case where the switchpanel was opened with FocusNextKey or FocusPrevKey initially, the check can be skipped because all the available choices are necessarily of the same class already. --- src/cycling.c | 6 +++--- src/switchpanel.c | 24 ++++++++++++++++-------- src/switchpanel.h | 2 +- 3 files changed, 20 insertions(+), 12 deletions(-) diff --git a/src/cycling.c b/src/cycling.c index f989554..574e0f4 100644 --- a/src/cycling.c +++ b/src/cycling.c @@ -130,7 +130,7 @@ void StartWindozeCycle(WWindow * wwin, XEvent * event, Bool next, Bool class_onl if (swpanel) { if (wwin->flags.mapped) - newFocused = wSwitchPanelSelectNext(swpanel, !next, True); + newFocused = wSwitchPanelSelectNext(swpanel, !next, True, False); else newFocused = wSwitchPanelSelectFirst(swpanel, False); @@ -164,7 +164,7 @@ void StartWindozeCycle(WWindow * wwin, XEvent * event, Bool next, Bool class_onl && wKeyBindings[WKBD_GROUPNEXT].modifier == modifiers) || ev.xkey.keycode == rightKey) { - newFocused = wSwitchPanelSelectNext(swpanel, False, ev.xkey.keycode != rightKey); + newFocused = wSwitchPanelSelectNext(swpanel, False, ev.xkey.keycode != rightKey, (!class_only && wKeyBindings[WKBD_GROUPNEXT].keycode == ev.xkey.keycode && wKeyBindings[WKBD_GROUPNEXT].modifier == modifiers)); oldFocused = change_focus_and_raise(newFocused, oldFocused, swpanel, scr, False); } else if ((wKeyBindings[WKBD_FOCUSPREV].keycode == ev.xkey.keycode @@ -173,7 +173,7 @@ void StartWindozeCycle(WWindow * wwin, XEvent * event, Bool next, Bool class_onl && wKeyBindings[WKBD_GROUPPREV].modifier == modifiers) || ev.xkey.keycode == leftKey) { - newFocused = wSwitchPanelSelectNext(swpanel, True, ev.xkey.keycode != leftKey); + newFocused = wSwitchPanelSelectNext(swpanel, True, ev.xkey.keycode != leftKey, (!class_only && wKeyBindings[WKBD_GROUPPREV].keycode == ev.xkey.keycode && wKeyBindings[WKBD_GROUPPREV].modifier == modifiers)); oldFocused = change_focus_and_raise(newFocused, oldFocused, swpanel, scr, False); } else if (ev.xkey.keycode == homeKey || ev.xkey.keycode == endKey) { diff --git a/src/switchpanel.c b/src/switchpanel.c index cd24f7b..cedc487 100644 --- a/src/switchpanel.c +++ b/src/switchpanel.c @@ -562,9 +562,9 @@ void wSwitchPanelDestroy(WSwitchPanel *panel) wfree(panel); } -WWindow *wSwitchPanelSelectNext(WSwitchPanel *panel, int back, int ignore_minimized) +WWindow *wSwitchPanelSelectNext(WSwitchPanel *panel, int back, int ignore_minimized, Bool class_only) { - WWindow *wwin; + WWindow *wwin, *curwin; int count = WMGetArrayItemCount(panel->windows); int orig = panel->current; @@ -580,14 +580,22 @@ WWindow *wSwitchPanelSelectNext(WSwitchPanel *panel, int back, int ignore_minimi if (ignore_minimized && canReceiveFocus(WMGetFromArray(panel->windows, (count + panel->current) % count)) < 0) ignore_minimized = False; + curwin = WMGetFromArray(panel->windows, orig); do { - if (back) - panel->current--; - else - panel->current++; + do { + if (back) + panel->current--; + else + panel->current++; + + panel->current= (count + panel->current) % count; + wwin = WMGetFromArray(panel->windows, panel->current); - panel->current= (count + panel->current) % count; - wwin = WMGetFromArray(panel->windows, panel->current); + if (!class_only) + break; + if (panel->current == orig) + break; + } while (!sameWindowClass(wwin, curwin)); } while (ignore_minimized && panel->current != orig && canReceiveFocus(wwin) < 0); if (panel->current < panel->firstVisible) diff --git a/src/switchpanel.h b/src/switchpanel.h index 041d222..2c4e642 100644 --- a/src/switchpanel.h +++ b/src/switchpanel.h @@ -27,7 +27,7 @@ WSwitchPanel *wInitSwitchPanel(WScreen *scr, WWindow *curwin, Bool class_only); void wSwitchPanelDestroy(WSwitchPanel *panel); -WWindow *wSwitchPanelSelectNext(WSwitchPanel *panel, int back, int ignore_minimized); +WWindow *wSwitchPanelSelectNext(WSwitchPanel *panel, int back, int ignore_minimized, Bool class_only); WWindow *wSwitchPanelSelectFirst(WSwitchPanel *panel, int back); WWindow *wSwitchPanelHandleEvent(WSwitchPanel *panel, XEvent *event); -- 1.8.1.4
From c7144299216650b356b918a630a5d83212b1966a Mon Sep 17 00:00:00 2001 From: Iain Patterson <[email protected]> Date: Fri, 19 Apr 2013 17:33:56 +0100 Subject: [PATCH 6/8] Configurable shortcuts in the switchpanel. Allow configuring the next, previous, first and last window shortcuts when the switchpanel is open. The following new preferences are used for this purpose: SwitchPanelNextKey SwitchPanelPrevKey SwitchPanelFirstKey SwitchPanelLastKey The default keys Right, Left, Home and End are not removed and we try to ensure that they will always work by not allowing them to be assigned to the new shortcuts. They could still be assigned to the existing focus (group) next/previous shortcuts, however. Additionally, add group next and group previous shortcuts for the switchpanel. SwitchPanelGroupNextKey SwitchPanelGroupPrevKey --- src/cycling.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++----------- src/defaults.c | 42 +++++++++++++++++++++++++++++++++++++++ src/keybind.h | 8 ++++++++ src/window.c | 4 ++++ 4 files changed, 105 insertions(+), 12 deletions(-) diff --git a/src/cycling.c b/src/cycling.c index 574e0f4..74f2e58 100644 --- a/src/cycling.c +++ b/src/cycling.c @@ -79,6 +79,18 @@ static WWindow *change_focus_and_raise(WWindow *newFocused, WWindow *oldFocused, return oldFocused; } +static Bool isSwitchPanelShortcut(int binding, KeyCode keycode, int modifiers, int switchpanel_modifiers) +{ + if (!wKeyBindings[binding].keycode) + return False; + if (keycode != wKeyBindings[binding].keycode) + return False; + if (modifiers != (wKeyBindings[binding].modifier | switchpanel_modifiers)) + return False; + + return True; +} + void StartWindozeCycle(WWindow * wwin, XEvent * event, Bool next, Bool class_only) { @@ -97,6 +109,7 @@ void StartWindozeCycle(WWindow * wwin, XEvent * event, Bool next, Bool class_onl Bool done = False; Bool hasModifier; int modifiers; + int switchpanel_modifiers; WWindow *newFocused; WWindow *oldFocused; XEvent ev; @@ -117,6 +130,15 @@ void StartWindozeCycle(WWindow * wwin, XEvent * event, Bool next, Bool class_onl hasModifier = (wKeyBindings[WKBD_FOCUSPREV].modifier != 0); } + /* Find any modifiers common to all focus shortcuts. + * We assume that those modifiers will remain held for as long as the + * switchpanel is open, and filter them out when checking for + * switchpanel-specific shortcuts. */ + if (class_only) + switchpanel_modifiers = wKeyBindings[WKBD_GROUPNEXT].modifier & wKeyBindings[WKBD_GROUPPREV].modifier; + else + switchpanel_modifiers = wKeyBindings[WKBD_FOCUSNEXT].modifier & wKeyBindings[WKBD_FOCUSPREV].modifier; + if (hasModifier) { keymap = XGetModifierMapping(dpy); XGrabKeyboard(dpy, scr->root_win, False, GrabModeAsync, GrabModeAsync, CurrentTime); @@ -158,27 +180,44 @@ void StartWindozeCycle(WWindow * wwin, XEvent * event, Bool next, Bool class_onl case KeyPress: - if ((wKeyBindings[WKBD_FOCUSNEXT].keycode == ev.xkey.keycode - && wKeyBindings[WKBD_FOCUSNEXT].modifier == modifiers) - || (wKeyBindings[WKBD_GROUPNEXT].keycode == ev.xkey.keycode - && wKeyBindings[WKBD_GROUPNEXT].modifier == modifiers) + if (isSwitchPanelShortcut(WKBD_FOCUSNEXT, ev.xkey.keycode, modifiers, 0) + || isSwitchPanelShortcut(WKBD_GROUPNEXT, ev.xkey.keycode, modifiers, 0) || ev.xkey.keycode == rightKey) { - newFocused = wSwitchPanelSelectNext(swpanel, False, ev.xkey.keycode != rightKey, (!class_only && wKeyBindings[WKBD_GROUPNEXT].keycode == ev.xkey.keycode && wKeyBindings[WKBD_GROUPNEXT].modifier == modifiers)); + newFocused = wSwitchPanelSelectNext(swpanel, False, ev.xkey.keycode != rightKey, (!class_only && isSwitchPanelShortcut(WKBD_GROUPNEXT, ev.xkey.keycode, modifiers, 0))); oldFocused = change_focus_and_raise(newFocused, oldFocused, swpanel, scr, False); - } else if ((wKeyBindings[WKBD_FOCUSPREV].keycode == ev.xkey.keycode - && wKeyBindings[WKBD_FOCUSPREV].modifier == modifiers) - || (wKeyBindings[WKBD_GROUPPREV].keycode == ev.xkey.keycode - && wKeyBindings[WKBD_GROUPPREV].modifier == modifiers) + } else if (isSwitchPanelShortcut(WKBD_SWITCHPANEL_NEXT, ev.xkey.keycode, modifiers, switchpanel_modifiers) + || isSwitchPanelShortcut(WKBD_SWITCHPANEL_GROUPNEXT, ev.xkey.keycode, modifiers, switchpanel_modifiers)) { + + newFocused = wSwitchPanelSelectNext(swpanel, False, False, (!class_only && isSwitchPanelShortcut(WKBD_SWITCHPANEL_GROUPNEXT, ev.xkey.keycode, modifiers, switchpanel_modifiers))); + oldFocused = change_focus_and_raise(newFocused, oldFocused, swpanel, scr, False); + } else if (isSwitchPanelShortcut(WKBD_FOCUSPREV, ev.xkey.keycode, modifiers, 0) + || isSwitchPanelShortcut(WKBD_GROUPPREV, ev.xkey.keycode, modifiers, 0) || ev.xkey.keycode == leftKey) { - newFocused = wSwitchPanelSelectNext(swpanel, True, ev.xkey.keycode != leftKey, (!class_only && wKeyBindings[WKBD_GROUPPREV].keycode == ev.xkey.keycode && wKeyBindings[WKBD_GROUPPREV].modifier == modifiers)); + newFocused = wSwitchPanelSelectNext(swpanel, True, ev.xkey.keycode != leftKey, (!class_only && isSwitchPanelShortcut(WKBD_GROUPPREV, ev.xkey.keycode, modifiers, 0))); + oldFocused = change_focus_and_raise(newFocused, oldFocused, swpanel, scr, False); + + } else if (isSwitchPanelShortcut(WKBD_SWITCHPANEL_PREV, ev.xkey.keycode, modifiers, switchpanel_modifiers) + || isSwitchPanelShortcut(WKBD_SWITCHPANEL_GROUPPREV, ev.xkey.keycode, modifiers, switchpanel_modifiers)) { + + newFocused = wSwitchPanelSelectNext(swpanel, True, False, (!class_only && isSwitchPanelShortcut(WKBD_SWITCHPANEL_GROUPPREV, ev.xkey.keycode, modifiers, switchpanel_modifiers))); + oldFocused = change_focus_and_raise(newFocused, oldFocused, swpanel, scr, False); + } else if (ev.xkey.keycode == homeKey + || (wKeyBindings[WKBD_SWITCHPANEL_FIRST].keycode + && wKeyBindings[WKBD_SWITCHPANEL_FIRST].keycode == ev.xkey.keycode + && (wKeyBindings[WKBD_SWITCHPANEL_FIRST].modifier | switchpanel_modifiers) == modifiers)) { + + newFocused = wSwitchPanelSelectFirst(swpanel, False); oldFocused = change_focus_and_raise(newFocused, oldFocused, swpanel, scr, False); - } else if (ev.xkey.keycode == homeKey || ev.xkey.keycode == endKey) { + } else if (ev.xkey.keycode == endKey + || (wKeyBindings[WKBD_SWITCHPANEL_LAST].keycode + && wKeyBindings[WKBD_SWITCHPANEL_LAST].keycode == ev.xkey.keycode + && (wKeyBindings[WKBD_SWITCHPANEL_LAST].modifier | switchpanel_modifiers) == modifiers)) { - newFocused = wSwitchPanelSelectFirst(swpanel, ev.xkey.keycode != homeKey); + newFocused = wSwitchPanelSelectFirst(swpanel, True); oldFocused = change_focus_and_raise(newFocused, oldFocused, swpanel, scr, False); } else if (ev.xkey.keycode == escapeKey) { diff --git a/src/defaults.c b/src/defaults.c index a2d6e21..f4b7cf7 100644 --- a/src/defaults.c +++ b/src/defaults.c @@ -107,6 +107,7 @@ static int getWSSpecificBackground(); static int getFont(); static int getColor(); static int getKeybind(); +static int getSwitchpanelKeybind(); static int getModMask(); static int getPropList(); @@ -709,6 +710,18 @@ WDefaultEntry optionList[] = { NULL, getKeybind, setKeyGrab, NULL, NULL}, {"ScreenSwitchKey", "None", (void *)WKBD_SWITCH_SCREEN, NULL, getKeybind, setKeyGrab, NULL, NULL}, + {"SwitchPanelNextKey", "Right", (void *)WKBD_SWITCHPANEL_NEXT, + NULL, getSwitchpanelKeybind, setKeyGrab, NULL, NULL}, + {"SwitchPanelPrevKey", "Left", (void *)WKBD_SWITCHPANEL_PREV, + NULL, getSwitchpanelKeybind, setKeyGrab, NULL, NULL}, + {"SwitchPanelGroupNextKey", "None", (void *)WKBD_SWITCHPANEL_GROUPNEXT, + NULL, getSwitchpanelKeybind, setKeyGrab, NULL, NULL}, + {"SwitchPanelGroupPrevKey", "None", (void *)WKBD_SWITCHPANEL_GROUPPREV, + NULL, getSwitchpanelKeybind, setKeyGrab, NULL, NULL}, + {"SwitchPanelFirstKey", "Home", (void *)WKBD_SWITCHPANEL_FIRST, + NULL, getSwitchpanelKeybind, setKeyGrab, NULL, NULL}, + {"SwitchPanelLastKey", "End", (void *)WKBD_SWITCHPANEL_LAST, + NULL, getSwitchpanelKeybind, setKeyGrab, NULL, NULL}, #ifdef KEEP_XKB_LOCK_STATUS {"ToggleKbdModeKey", "None", (void *)WKBD_TOGGLE, @@ -2101,6 +2114,35 @@ static int getKeybind(WScreen * scr, WDefaultEntry * entry, WMPropList * value, return True; } +static int getSwitchpanelKeybind(WScreen * scr, WDefaultEntry * entry, WMPropList * value, void *addr, void **ret) +{ + static WShortKey *shortcut; + + if (!getKeybind(scr, entry, value, addr, ret)) + return False; + + if (ret) { + shortcut = (WShortKey *) *ret; + + /* Disallow default keys */ + if (shortcut->keycode == XKeysymToKeycode(dpy, XK_Left) + || shortcut->keycode == XKeysymToKeycode(dpy, XK_Right) + || shortcut->keycode == XKeysymToKeycode(dpy, XK_Home) + || shortcut->keycode == XKeysymToKeycode(dpy, XK_End) + || shortcut->keycode == XKeysymToKeycode(dpy, XK_Escape)) { + char *val; + + GET_STRING_OR_DEFAULT("Key spec", val); + + wwarning(_("%s:ignoring reserved value \"%s\""), entry->key, val); + memset(shortcut, 0, sizeof(WShortKey)); + return False; + } + } + + return True; +} + static int getModMask(WScreen * scr, WDefaultEntry * entry, WMPropList * value, void *addr, void **ret) { static int mask; diff --git a/src/keybind.h b/src/keybind.h index 4437950..74ab462 100644 --- a/src/keybind.h +++ b/src/keybind.h @@ -110,6 +110,14 @@ enum { /* screen */ WKBD_SWITCH_SCREEN, + /* switchpanel */ + WKBD_SWITCHPANEL_NEXT, + WKBD_SWITCHPANEL_PREV, + WKBD_SWITCHPANEL_GROUPNEXT, + WKBD_SWITCHPANEL_GROUPPREV, + WKBD_SWITCHPANEL_FIRST, + WKBD_SWITCHPANEL_LAST, + #ifdef KEEP_XKB_LOCK_STATUS WKBD_TOGGLE, #endif diff --git a/src/window.c b/src/window.c index 9ac5e78..855e520 100644 --- a/src/window.c +++ b/src/window.c @@ -2463,6 +2463,10 @@ void wWindowSetKeyGrabs(WWindow * wwin) WShortKey *key; for (i = 0; i < WKBD_LAST; i++) { + /* Don't grab switchpanel keys. */ + if (i >= WKBD_SWITCHPANEL_NEXT && i <= WKBD_SWITCHPANEL_LAST) + continue; + key = &wKeyBindings[i]; if (key->keycode == 0) -- 1.8.1.4
From b867c69cf61def921814ed9e0ab6d01bb1a3421a Mon Sep 17 00:00:00 2001 From: Iain Patterson <[email protected]> Date: Fri, 19 Apr 2013 17:34:17 +0100 Subject: [PATCH 7/8] Allow WPrefs to configure switchpanel shortcuts. Teach WPrefs about the new SwitchPanel*Key shortcuts. --- WPrefs.app/KeyboardShortcuts.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/WPrefs.app/KeyboardShortcuts.c b/WPrefs.app/KeyboardShortcuts.c index 61a49a1..3b87105 100644 --- a/WPrefs.app/KeyboardShortcuts.c +++ b/WPrefs.app/KeyboardShortcuts.c @@ -131,6 +131,12 @@ static char *keyOptions[] = { "WindowShortcut10Key", "WindowRelaunchKey", "ScreenSwitchKey", + "SwitchPanelNextKey", + "SwitchPanelPrevKey", + "SwitchPanelGroupNextKey", + "SwitchPanelGroupPrevKey", + "SwitchPanelFirstKey", + "SwitchPanelLastKey", "DockRaiseLowerKey", #ifndef XKB_MODELOCK "ClipRaiseLowerKey" @@ -535,6 +541,12 @@ static void createPanel(Panel * p) WMAddListItem(panel->actLs, _("Shortcut for window 10")); WMAddListItem(panel->actLs, _("Launch new instance of application")); WMAddListItem(panel->actLs, _("Switch to Next Screen/Monitor")); + WMAddListItem(panel->actLs, _("Switchpanel select next window")); + WMAddListItem(panel->actLs, _("Switchpanel select previous window")); + WMAddListItem(panel->actLs, _("Switchpanel select next group window")); + WMAddListItem(panel->actLs, _("Switchpanel select previous group window")); + WMAddListItem(panel->actLs, _("Switchpanel select first window")); + WMAddListItem(panel->actLs, _("Switchpanel select last window")); WMAddListItem(panel->actLs, _("Raise/Lower Dock")); WMAddListItem(panel->actLs, _("Raise/Lower Clip")); #ifdef XKB_MODELOCK -- 1.8.1.4
From f3d44f2c7afdcd8a8742df56227b2b15e2cb8e63 Mon Sep 17 00:00:00 2001 From: Iain Patterson <[email protected]> Date: Mon, 22 Apr 2013 15:14:09 +0100 Subject: [PATCH 8/8] Documentation on the new switchpanel shortcuts. Describe SwitchPanel*Key and StrictWindozeCycling in the NEWS file. --- NEWS | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/NEWS b/NEWS index f771101..8d407b7 100644 --- a/NEWS +++ b/NEWS @@ -55,6 +55,32 @@ a particular workspace or to the "next" or "previous" workspace. The new shortcuts can be configured in WPrefs. +Improved switchpanel functionality +---------------------------------- + +In addition to the default Left, Right, Home and End you can now bind custom +keyboard shortcuts to select windows within the switchpanel. You can +configure shortcuts to select the next window (Right), previous window (Left), +leftmost window (Home), rightmost window (End) or the next/previous window of +the same WM_CLASS (no default shortcut). + +The new shortcuts can be configured in WPrefs. + +To maintain consistency with other popular operating systems, the switchpanel +can be configured so that it no longer automatically closes when the shift key +is pressed and released. + +To configure the switchpanel so that it does NOT close on release of the shift +key, which is consistent with other operating systems, issue the following +command: + +$ wdwrite WindowMaker StrictWindozeCycling YES + +To configure Window Maker's traditional behaviour, run: + +$ wdwrite WindowMaker StrictWindozeCycling NO + + --- 0.95.2 New Resizing functionality -- 1.8.1.4
