more bug fixes..
[wmaker-crm.git] / src / cycling.c
blobe11f91b7a2bbde194ca07627348d7522837031a5
1 /* cycling.c- window cycling
3 * Window Maker window manager
5 * Copyright (c) 2000-2003 Alfredo K. Kojima
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>
27 #include <X11/keysym.h>
29 // TODO: remove non-MOX_CYCLING junk
30 // fix the stacking/window raising during alt-tabbing
31 // allow selection of icons with mouse
33 #define MOX_CYCLING
35 #include "WindowMaker.h"
36 #include "GNUstep.h"
37 #include "screen.h"
38 #include "wcore.h"
39 #include "window.h"
40 #include "framewin.h"
41 #include "keybind.h"
42 #include "actions.h"
43 #include "stacking.h"
44 #include "funcs.h"
45 #include "xinerama.h"
46 #include "switchpanel.h"
48 /* Globals */
49 extern WPreferences wPreferences;
51 extern WShortKey wKeyBindings[WKBD_LAST];
57 #ifndef MOX_CYCLING
58 static WWindow*
59 nextToFocusAfter(WWindow *wwin)
61 WWindow *tmp = wwin->prev;
63 while (tmp) {
64 if (wWindowCanReceiveFocus(tmp) && !WFLAGP(tmp, skip_window_list)) {
65 return tmp;
67 tmp = tmp->prev;
70 tmp = wwin;
71 /* start over from the beginning of the list */
72 while (tmp->next)
73 tmp = tmp->next;
75 while (tmp && tmp != wwin) {
76 if (wWindowCanReceiveFocus(tmp) && !WFLAGP(tmp, skip_window_list)) {
77 return tmp;
79 tmp = tmp->prev;
82 return wwin;
86 static WWindow*
87 nextToFocusBefore(WWindow *wwin)
89 WWindow *tmp = wwin->next;
91 while (tmp) {
92 if (wWindowCanReceiveFocus(tmp) && !WFLAGP(tmp, skip_window_list)) {
93 return tmp;
95 tmp = tmp->next;
98 /* start over from the beginning of the list */
99 tmp = wwin;
100 while (tmp->prev)
101 tmp = tmp->prev;
103 while (tmp && tmp != wwin) {
104 if (wWindowCanReceiveFocus(tmp) && !WFLAGP(tmp, skip_window_list)) {
106 return tmp;
108 tmp = tmp->next;
111 return wwin;
117 static WWindow*
118 nextFocusWindow(WWindow *wwin)
120 WWindow *tmp, *closest, *min;
121 Window d;
123 if (!wwin)
124 return NULL;
125 tmp = wwin->prev;
126 closest = NULL;
127 min = wwin;
128 d = 0xffffffff;
129 while (tmp) {
130 if (wWindowCanReceiveFocus(tmp)
131 && (!WFLAGP(tmp, skip_window_list)|| tmp->flags.internal_window)) {
132 if (min->client_win > tmp->client_win)
133 min = tmp;
134 if (tmp->client_win > wwin->client_win
135 && (!closest
136 || (tmp->client_win - wwin->client_win) < d)) {
137 closest = tmp;
138 d = tmp->client_win - wwin->client_win;
141 tmp = tmp->prev;
143 if (!closest||closest==wwin)
144 return min;
145 return closest;
149 static WWindow*
150 prevFocusWindow(WWindow *wwin)
152 WWindow *tmp, *closest, *max;
153 Window d;
155 if (!wwin)
156 return NULL;
157 tmp = wwin->prev;
158 closest = NULL;
159 max = wwin;
160 d = 0xffffffff;
161 while (tmp) {
162 if (wWindowCanReceiveFocus(tmp) &&
163 (!WFLAGP(tmp, skip_window_list) || tmp->flags.internal_window)) {
164 if (max->client_win < tmp->client_win)
165 max = tmp;
166 if (tmp->client_win < wwin->client_win
167 && (!closest
168 || (wwin->client_win - tmp->client_win) < d)) {
169 closest = tmp;
170 d = wwin->client_win - tmp->client_win;
173 tmp = tmp->prev;
175 if (!closest||closest==wwin)
176 return max;
177 return closest;
179 #endif /* !MOX_CYCLING */
182 void
183 StartWindozeCycle(WWindow *wwin, XEvent *event, Bool next)
185 WScreen *scr = wScreenForRootWindow(event->xkey.root);
186 Bool done = False;
187 WWindow *newFocused;
188 WWindow *oldFocused;
189 int modifiers;
190 XModifierKeymap *keymap = NULL;
191 Bool hasModifier;
192 Bool somethingElse = False;
193 XEvent ev;
194 #ifdef MOX_CYCLING
195 WSwitchPanel *swpanel = NULL;
196 #endif
197 KeyCode leftKey, rightKey, homeKey, endKey;
199 if (!wwin)
200 return;
202 leftKey = XKeysymToKeycode(dpy, XK_Left);
203 rightKey = XKeysymToKeycode(dpy, XK_Right);
204 homeKey = XKeysymToKeycode(dpy, XK_Home);
205 endKey = XKeysymToKeycode(dpy, XK_End);
207 if (next)
208 hasModifier = (wKeyBindings[WKBD_FOCUSNEXT].modifier != 0);
209 else
210 hasModifier = (wKeyBindings[WKBD_FOCUSPREV].modifier != 0);
212 if (hasModifier) {
213 keymap = XGetModifierMapping(dpy);
215 #ifdef DEBUG
216 printf("Grabbing keyboard\n");
217 #endif
218 XGrabKeyboard(dpy, scr->root_win, False, GrabModeAsync, GrabModeAsync,
219 CurrentTime);
222 scr->flags.doing_alt_tab = 1;
224 #ifdef MOX_CYCLING
225 swpanel = wInitSwitchPanel(scr, wwin, scr->current_workspace);
226 oldFocused = wwin;
228 if (swpanel) {
229 newFocused = wSwitchPanelSelectNext(swpanel, !next);
230 if (newFocused) {
231 wWindowFocus(newFocused, oldFocused);
232 oldFocused = newFocused;
235 else
236 newFocused= wwin;
237 #else /* !MOX_CYCLING */
238 if (next) {
239 if (wPreferences.windows_cycling)
240 newFocused = nextToFocusAfter(wwin);
241 else
242 newFocused = nextFocusWindow(wwin);
243 } else {
244 if (wPreferences.windows_cycling)
245 newFocused = nextToFocusBefore(wwin);
246 else
247 newFocused = prevFocusWindow(wwin);
250 if (wPreferences.circ_raise)
251 XRaiseWindow(dpy, newFocused->frame->core->window);
252 wWindowFocus(newFocused, scr->focused_window);
253 oldFocused = newFocused;
254 #endif /* !MOX_CYCLING */
256 while (hasModifier && !done) {
257 WMMaskEvent(dpy, KeyPressMask|KeyReleaseMask|ExposureMask|PointerMotionMask, &ev);
259 if (ev.type != KeyRelease && ev.type != KeyPress) {
260 WMHandleEvent(&ev);
261 continue;
263 /* ignore CapsLock */
264 modifiers = ev.xkey.state & ValidModMask;
266 if (ev.type == KeyPress) {
267 #ifdef DEBUG
268 printf("Got key press\n");
269 #endif
270 if ((wKeyBindings[WKBD_FOCUSNEXT].keycode == ev.xkey.keycode
271 && wKeyBindings[WKBD_FOCUSNEXT].modifier == modifiers)
272 || ev.xkey.keycode == rightKey) {
274 #ifdef MOX_CYCLING
275 if (swpanel) {
276 newFocused = wSwitchPanelSelectNext(swpanel, False);
277 if (newFocused) {
278 wWindowFocus(newFocused, oldFocused);
279 oldFocused = newFocused;
282 #else /* !MOX_CYCLING */
283 newFocused = nextToFocusAfter(newFocused);
284 wWindowFocus(newFocused, oldFocused);
285 oldFocused = newFocused;
287 if (wPreferences.circ_raise) {
288 /* restore order */
289 CommitStacking(scr);
290 XRaiseWindow(dpy, newFocused->frame->core->window);
292 #endif /* !MOX_CYCLING */
293 } else if ((wKeyBindings[WKBD_FOCUSPREV].keycode == ev.xkey.keycode
294 && wKeyBindings[WKBD_FOCUSPREV].modifier == modifiers)
295 || ev.xkey.keycode == leftKey) {
297 #ifdef MOX_CYCLING
298 if (swpanel) {
299 newFocused = wSwitchPanelSelectNext(swpanel, True);
300 if (newFocused) {
301 wWindowFocus(newFocused, oldFocused);
302 oldFocused = newFocused;
305 #else /* !MOX_CYCLING */
306 newFocused = nextToFocusBefore(newFocused);
307 wWindowFocus(newFocused, oldFocused);
308 oldFocused = newFocused;
310 if (wPreferences.circ_raise) {
311 /* restore order */
312 CommitStacking(scr);
313 XRaiseWindow(dpy, newFocused->frame->core->window);
315 #endif /* !MOX_CYCLING */
316 } else if (ev.xkey.keycode == homeKey || ev.xkey.keycode == endKey) {
317 if (swpanel) {
318 newFocused = wSwitchPanelSelectFirst(swpanel, ev.xkey.keycode != homeKey);
319 if (newFocused) {
320 wWindowFocus(newFocused, oldFocused);
321 oldFocused = newFocused;
324 } else if (ev.type == MotionNotify) {
325 WWindow *tmp;
326 if (swpanel) {
327 tmp = wSwitchPanelHandleEvent(swpanel, &ev);
328 if (tmp) {
329 newFocused = tmp;
330 wWindowFocus(newFocused, oldFocused);
331 oldFocused = newFocused;
334 } else {
335 #ifdef DEBUG
336 printf("Got something else\n");
337 #endif
338 somethingElse = True;
339 done = True;
341 } else if (ev.type == KeyRelease) {
342 int i;
344 #ifdef DEBUG
345 printf("Got key release\n");
346 #endif
347 for (i = 0; i < 8 * keymap->max_keypermod; i++) {
348 if (keymap->modifiermap[i] == ev.xkey.keycode &&
349 wKeyBindings[WKBD_FOCUSNEXT].modifier
350 & 1<<(i/keymap->max_keypermod)) {
351 done = True;
352 break;
357 if (keymap)
358 XFreeModifiermap(keymap);
360 if (hasModifier) {
361 #ifdef DEBUG
362 printf("Ungrabbing keyboard\n");
363 #endif
364 XUngrabKeyboard(dpy, CurrentTime);
367 if (newFocused) {
368 wSetFocusTo(scr, newFocused);
369 wMakeWindowVisible(newFocused);
372 #ifdef MOX_CYCLING
373 if (swpanel)
374 wSwitchPanelDestroy(swpanel);
375 #endif
377 if (wPreferences.circ_raise && newFocused) {
378 wRaiseFrame(newFocused->frame->core);
379 CommitStacking(scr);
382 scr->flags.doing_alt_tab = 0;
384 if (somethingElse) {
385 WMHandleEvent(&ev);