- Fixed sloppy focus bug (Pawel S. Veselov <pv76716@druid.SFBay.Sun.COM>)
[wmaker-crm.git] / src / cycling.c
blob182a3861e022e0cebdd569aab1a8077426468fe3
1 /* cycling.c- window cycling
2 *
3 * Window Maker window manager
4 *
5 * Copyright (c) 2000-2002 Alfredo K. Kojima
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
20 * USA.
23 #include "wconfig.h"
25 #include <X11/Xlib.h>
26 #include <X11/Xutil.h>
29 #include "WindowMaker.h"
30 #include "GNUstep.h"
31 #include "screen.h"
32 #include "wcore.h"
33 #include "window.h"
34 #include "framewin.h"
35 #include "keybind.h"
36 #include "actions.h"
37 #include "stacking.h"
38 #include "funcs.h"
39 #include "xinerama.h"
41 /* Globals */
42 extern WPreferences wPreferences;
44 extern WShortKey wKeyBindings[WKBD_LAST];
51 static WWindow*
52 nextToFocusAfter(WWindow *wwin)
54 WWindow *tmp = wwin->prev;
56 while (tmp) {
57 if (wWindowCanReceiveFocus(tmp) && !WFLAGP(tmp, skip_window_list)) {
58 return tmp;
60 tmp = tmp->prev;
63 tmp = wwin;
64 /* start over from the beginning of the list */
65 while (tmp->next)
66 tmp = tmp->next;
68 while (tmp && tmp != wwin) {
69 if (wWindowCanReceiveFocus(tmp) && !WFLAGP(tmp, skip_window_list)) {
70 return tmp;
72 tmp = tmp->prev;
75 return wwin;
79 static WWindow*
80 nextToFocusBefore(WWindow *wwin)
82 WWindow *tmp = wwin->next;
84 while (tmp) {
85 if (wWindowCanReceiveFocus(tmp) && !WFLAGP(tmp, skip_window_list)) {
86 return tmp;
88 tmp = tmp->next;
91 /* start over from the beginning of the list */
92 tmp = wwin;
93 while (tmp->prev)
94 tmp = tmp->prev;
96 while (tmp && tmp != wwin) {
97 if (wWindowCanReceiveFocus(tmp) && !WFLAGP(tmp, skip_window_list)) {
99 return tmp;
101 tmp = tmp->next;
104 return wwin;
110 static WWindow*
111 nextFocusWindow(WWindow *wwin)
113 WWindow *tmp, *closest, *min;
114 Window d;
116 if (!wwin)
117 return NULL;
118 tmp = wwin->prev;
119 closest = NULL;
120 min = wwin;
121 d = 0xffffffff;
122 while (tmp) {
123 if (wWindowCanReceiveFocus(tmp)
124 && (!WFLAGP(tmp, skip_window_list)|| tmp->flags.internal_window)) {
125 if (min->client_win > tmp->client_win)
126 min = tmp;
127 if (tmp->client_win > wwin->client_win
128 && (!closest
129 || (tmp->client_win - wwin->client_win) < d)) {
130 closest = tmp;
131 d = tmp->client_win - wwin->client_win;
134 tmp = tmp->prev;
136 if (!closest||closest==wwin)
137 return min;
138 return closest;
142 static WWindow*
143 prevFocusWindow(WWindow *wwin)
145 WWindow *tmp, *closest, *max;
146 Window d;
148 if (!wwin)
149 return NULL;
150 tmp = wwin->prev;
151 closest = NULL;
152 max = wwin;
153 d = 0xffffffff;
154 while (tmp) {
155 if (wWindowCanReceiveFocus(tmp) &&
156 (!WFLAGP(tmp, skip_window_list) || tmp->flags.internal_window)) {
157 if (max->client_win < tmp->client_win)
158 max = tmp;
159 if (tmp->client_win < wwin->client_win
160 && (!closest
161 || (wwin->client_win - tmp->client_win) < d)) {
162 closest = tmp;
163 d = wwin->client_win - tmp->client_win;
166 tmp = tmp->prev;
168 if (!closest||closest==wwin)
169 return max;
170 return closest;
176 void
177 StartWindozeCycle(WWindow *wwin, XEvent *event, Bool next)
179 WScreen *scr = wScreenForRootWindow(event->xkey.root);
180 Bool done = False;
181 Bool openedSwitchMenu = False;
182 WWindow *newFocused;
183 WWindow *oldFocused;
184 int modifiers;
185 XModifierKeymap *keymap = NULL;
186 Bool hasModifier;
187 Bool somethingElse = False;
188 XEvent ev;
190 if (!wwin)
191 return;
193 if (next)
194 hasModifier = (wKeyBindings[WKBD_FOCUSNEXT].modifier != 0);
195 else
196 hasModifier = (wKeyBindings[WKBD_FOCUSPREV].modifier != 0);
198 if (hasModifier) {
199 keymap = XGetModifierMapping(dpy);
202 XGrabKeyboard(dpy, scr->root_win, False, GrabModeAsync, GrabModeAsync,
203 CurrentTime);
206 if (next) {
207 if (wPreferences.windows_cycling)
208 newFocused = nextToFocusAfter(wwin);
209 else
210 newFocused = nextFocusWindow(wwin);
211 } else {
212 if (wPreferences.windows_cycling)
213 newFocused = nextToFocusBefore(wwin);
214 else
215 newFocused = prevFocusWindow(wwin);
218 scr->flags.doing_alt_tab = 1;
221 if (wPreferences.circ_raise)
222 XRaiseWindow(dpy, newFocused->frame->core->window);
223 wWindowFocus(newFocused, scr->focused_window);
224 oldFocused = newFocused;
226 if (hasModifier)
227 done = False;
228 else
229 done = True;
231 #if 0
232 if (wPreferences.popup_switchmenu &&
233 (!scr->switch_menu || !scr->switch_menu->flags.mapped)) {
235 OpenSwitchMenu(scr, scr->scr_width/2, scr->scr_height/2, False);
236 openedSwitchMenu = True;
238 #endif
239 while (!done) {
240 WMMaskEvent(dpy,KeyPressMask|KeyReleaseMask|ExposureMask, &ev);
242 if (ev.type != KeyRelease && ev.type != KeyPress) {
243 WMHandleEvent(&ev);
244 continue;
246 /* ignore CapsLock */
247 modifiers = ev.xkey.state & ValidModMask;
249 if (ev.type == KeyPress) {
250 if (wKeyBindings[WKBD_FOCUSNEXT].keycode == ev.xkey.keycode
251 && wKeyBindings[WKBD_FOCUSNEXT].modifier == modifiers) {
253 newFocused = nextToFocusAfter(newFocused);
254 wWindowFocus(newFocused, oldFocused);
255 oldFocused = newFocused;
257 if (wPreferences.circ_raise) {
258 /* restore order */
259 CommitStacking(scr);
260 XRaiseWindow(dpy, newFocused->frame->core->window);
263 } else if (wKeyBindings[WKBD_FOCUSPREV].keycode == ev.xkey.keycode
264 && wKeyBindings[WKBD_FOCUSPREV].modifier == modifiers) {
266 newFocused = nextToFocusBefore(newFocused);
267 wWindowFocus(newFocused, oldFocused);
268 oldFocused = newFocused;
270 if (wPreferences.circ_raise) {
271 /* restore order */
272 CommitStacking(scr);
273 XRaiseWindow(dpy, newFocused->frame->core->window);
276 } else {
277 somethingElse = True;
278 done = True;
280 } else if (ev.type == KeyRelease) {
281 int i;
283 for (i = 0; i < 8 * keymap->max_keypermod; i++) {
284 if (keymap->modifiermap[i] == ev.xkey.keycode &&
285 wKeyBindings[WKBD_FOCUSNEXT].modifier
286 & 1<<(i/keymap->max_keypermod)) {
287 done = True;
288 break;
293 if (keymap)
294 XFreeModifiermap(keymap);
296 if (hasModifier) {
297 XUngrabKeyboard(dpy, CurrentTime);
299 wSetFocusTo(scr, newFocused);
301 if (wPreferences.circ_raise) {
302 wRaiseFrame(newFocused->frame->core);
303 CommitStacking(scr);
306 scr->flags.doing_alt_tab = 0;
307 if (openedSwitchMenu) {
309 * place window in center of current head
311 WMPoint center = wGetPointToCenterRectInHead(scr,
312 wGetHeadForPointerLocation(scr),
313 0, 0);
314 OpenSwitchMenu(scr, center.x, center.y, False);
317 if (somethingElse) {
318 WMHandleEvent(&ev);