The switch panel was not being destroyed with the realease of FOCUSPREV, only with FOCUSNEXT. Fix this. One can reproduce this bug as follows. In the "Keyboard Shortcut Preferences" of WPrefs set "Focus next window" to e.g. "Alt+Tab" and "Focus previous window" to "Ctrl+Tab". The switchpanel is not destroyed if we release "Ctrl+Tab" but it is upon releasing of "Alt+Tab". Retrieved-from: http://git.altlinux.org/people/voins/packages/?p=WindowMaker.git;a=commit;h=51c95a55c9310f499b1fdeca138106ca7bf74423 [crmafra: Commit log]
254 lines
6.5 KiB
C
254 lines
6.5 KiB
C
/* cycling.c- window cycling
|
|
*
|
|
* Window Maker window manager
|
|
*
|
|
* Copyright (c) 2000-2003 Alfredo K. Kojima
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
|
* USA.
|
|
*/
|
|
|
|
#include "wconfig.h"
|
|
|
|
#include <X11/Xlib.h>
|
|
#include <X11/Xutil.h>
|
|
#include <X11/keysym.h>
|
|
|
|
#include "WindowMaker.h"
|
|
#include "GNUstep.h"
|
|
#include "screen.h"
|
|
#include "wcore.h"
|
|
#include "window.h"
|
|
#include "framewin.h"
|
|
#include "keybind.h"
|
|
#include "actions.h"
|
|
#include "stacking.h"
|
|
#include "funcs.h"
|
|
#include "xinerama.h"
|
|
#include "switchpanel.h"
|
|
|
|
/* Globals */
|
|
extern WPreferences wPreferences;
|
|
|
|
extern WShortKey wKeyBindings[WKBD_LAST];
|
|
|
|
static void raiseWindow(WSwitchPanel * swpanel, WWindow * wwin)
|
|
{
|
|
Window swwin = wSwitchPanelGetWindow(swpanel);
|
|
|
|
if (wwin->flags.mapped) {
|
|
if (swwin != None) {
|
|
Window win[2];
|
|
|
|
win[0] = swwin;
|
|
win[1] = wwin->frame->core->window;
|
|
|
|
XRestackWindows(dpy, win, 2);
|
|
} else
|
|
XRaiseWindow(dpy, wwin->frame->core->window);
|
|
}
|
|
}
|
|
|
|
static WWindow *change_focus_and_raise(WWindow *newFocused, WWindow *oldFocused,
|
|
WSwitchPanel *swpanel, WScreen *scr, Bool esc_cancel)
|
|
{
|
|
if (!newFocused)
|
|
return oldFocused;
|
|
|
|
wWindowFocus(newFocused, oldFocused);
|
|
oldFocused = newFocused;
|
|
|
|
if (wPreferences.circ_raise) {
|
|
CommitStacking(scr);
|
|
|
|
if (!esc_cancel)
|
|
raiseWindow(swpanel, newFocused);
|
|
}
|
|
|
|
return oldFocused;
|
|
}
|
|
|
|
void StartWindozeCycle(WWindow * wwin, XEvent * event, Bool next)
|
|
{
|
|
|
|
XModifierKeymap *keymap = NULL;
|
|
WSwitchPanel *swpanel = NULL;
|
|
WScreen *scr = wScreenForRootWindow(event->xkey.root);
|
|
KeyCode leftKey = XKeysymToKeycode(dpy, XK_Left);
|
|
KeyCode rightKey = XKeysymToKeycode(dpy, XK_Right);
|
|
KeyCode homeKey = XKeysymToKeycode(dpy, XK_Home);
|
|
KeyCode endKey = XKeysymToKeycode(dpy, XK_End);
|
|
KeyCode shiftLKey = XKeysymToKeycode(dpy, XK_Shift_L);
|
|
KeyCode shiftRKey = XKeysymToKeycode(dpy, XK_Shift_R);
|
|
KeyCode escapeKey = XKeysymToKeycode(dpy, XK_Escape);
|
|
Bool esc_cancel = False;
|
|
Bool somethingElse = False;
|
|
Bool done = False;
|
|
Bool hasModifier;
|
|
int modifiers;
|
|
WWindow *newFocused;
|
|
WWindow *oldFocused;
|
|
XEvent ev;
|
|
|
|
|
|
if (!wwin)
|
|
return;
|
|
|
|
if (next)
|
|
hasModifier = (wKeyBindings[WKBD_FOCUSNEXT].modifier != 0);
|
|
else
|
|
hasModifier = (wKeyBindings[WKBD_FOCUSPREV].modifier != 0);
|
|
|
|
if (hasModifier) {
|
|
keymap = XGetModifierMapping(dpy);
|
|
|
|
#ifdef DEBUG
|
|
printf("Grabbing keyboard\n");
|
|
#endif
|
|
XGrabKeyboard(dpy, scr->root_win, False, GrabModeAsync, GrabModeAsync, CurrentTime);
|
|
}
|
|
|
|
scr->flags.doing_alt_tab = 1;
|
|
|
|
swpanel = wInitSwitchPanel(scr, wwin, scr->current_workspace);
|
|
oldFocused = wwin;
|
|
|
|
if (swpanel) {
|
|
|
|
if (wwin->flags.mapped)
|
|
newFocused = wSwitchPanelSelectNext(swpanel, !next);
|
|
else
|
|
newFocused = wSwitchPanelSelectFirst(swpanel, False);
|
|
|
|
oldFocused = change_focus_and_raise(newFocused, oldFocused, swpanel, scr, False);
|
|
} else {
|
|
if (wwin->frame->workspace == scr->current_workspace)
|
|
newFocused = wwin;
|
|
else
|
|
newFocused = NULL;
|
|
}
|
|
|
|
while (hasModifier && !done) {
|
|
int i;
|
|
|
|
WMMaskEvent(dpy, KeyPressMask | KeyReleaseMask | ExposureMask
|
|
| PointerMotionMask | ButtonReleaseMask | EnterWindowMask, &ev);
|
|
|
|
/* ignore CapsLock */
|
|
modifiers = ev.xkey.state & ValidModMask;
|
|
|
|
if (!swpanel)
|
|
done = True;
|
|
|
|
switch (ev.type) {
|
|
|
|
case KeyPress:
|
|
|
|
if ((wKeyBindings[WKBD_FOCUSNEXT].keycode == ev.xkey.keycode
|
|
&& wKeyBindings[WKBD_FOCUSNEXT].modifier == modifiers)
|
|
|| ev.xkey.keycode == rightKey) {
|
|
|
|
newFocused = wSwitchPanelSelectNext(swpanel, False);
|
|
oldFocused = change_focus_and_raise(newFocused, oldFocused, swpanel, scr, False);
|
|
|
|
} else if ((wKeyBindings[WKBD_FOCUSPREV].keycode == ev.xkey.keycode
|
|
&& wKeyBindings[WKBD_FOCUSPREV].modifier == modifiers)
|
|
|| ev.xkey.keycode == leftKey) {
|
|
|
|
newFocused = wSwitchPanelSelectNext(swpanel, True);
|
|
oldFocused = change_focus_and_raise(newFocused, oldFocused, swpanel, scr, False);
|
|
|
|
} else if (ev.xkey.keycode == homeKey || ev.xkey.keycode == endKey) {
|
|
|
|
newFocused = wSwitchPanelSelectFirst(swpanel, ev.xkey.keycode != homeKey);
|
|
oldFocused = change_focus_and_raise(newFocused, oldFocused, swpanel, scr, False);
|
|
|
|
} else if (ev.xkey.keycode == escapeKey) {
|
|
|
|
/* Focus the first window of the swpanel, despite the 'False' */
|
|
newFocused = wSwitchPanelSelectFirst(swpanel, False);
|
|
oldFocused = change_focus_and_raise(newFocused, oldFocused, swpanel, scr, True);
|
|
esc_cancel = True;
|
|
done = True;
|
|
|
|
} else if (ev.xkey.keycode != shiftLKey && ev.xkey.keycode != shiftRKey) {
|
|
|
|
somethingElse = True;
|
|
done = True;
|
|
}
|
|
break;
|
|
|
|
case KeyRelease:
|
|
|
|
for (i = 0; i < 8 * keymap->max_keypermod; i++) {
|
|
|
|
int mask = 1 << (i / keymap->max_keypermod);
|
|
|
|
if (keymap->modifiermap[i] == ev.xkey.keycode &&
|
|
((wKeyBindings[WKBD_FOCUSNEXT].modifier & mask)
|
|
|| (wKeyBindings[WKBD_FOCUSPREV].modifier & mask))) {
|
|
done = True;
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case EnterNotify:
|
|
|
|
/* ignore unwanted EnterNotify's */
|
|
break;
|
|
|
|
case LeaveNotify:
|
|
case MotionNotify:
|
|
|
|
case ButtonRelease:
|
|
|
|
newFocused = wSwitchPanelHandleEvent(swpanel, &ev);
|
|
oldFocused = change_focus_and_raise(newFocused, oldFocused, swpanel, scr, False);
|
|
|
|
if (ev.type == ButtonRelease)
|
|
done = True;
|
|
break;
|
|
|
|
default:
|
|
WMHandleEvent(&ev);
|
|
break;
|
|
}
|
|
}
|
|
if (keymap)
|
|
XFreeModifiermap(keymap);
|
|
|
|
if (hasModifier) {
|
|
|
|
XUngrabKeyboard(dpy, CurrentTime);
|
|
}
|
|
|
|
if (swpanel)
|
|
wSwitchPanelDestroy(swpanel);
|
|
|
|
if (newFocused && !esc_cancel) {
|
|
wRaiseFrame(newFocused->frame->core);
|
|
CommitStacking(scr);
|
|
if (!newFocused->flags.mapped)
|
|
wMakeWindowVisible(newFocused);
|
|
wSetFocusTo(scr, newFocused);
|
|
}
|
|
|
|
scr->flags.doing_alt_tab = 0;
|
|
|
|
if (somethingElse)
|
|
WMHandleEvent(&ev);
|
|
}
|