3
This program is free software; you can redistribute it and/or modify
4
it under the terms of the GNU General Public License as published by
5
the Free Software Foundation; either version 2, or (at your option)
8
This program is distributed in the hope that it will be useful,
9
but WITHOUT ANY WARRANTY; without even the implied warranty of
10
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
GNU General Public License for more details.
13
You should have received a copy of the GNU General Public License
14
along with this program; if not, write to the Free Software
15
Foundation, Inc., Inc., 51 Franklin Street, Fifth Floor, Boston,
19
oroborus - (c) 2001 Ken Lynch
20
xfwm4 - (c) 2002-2009 Olivier Fourdan
30
#include <X11/Xutil.h>
31
#include <X11/Xatom.h>
32
#include <X11/extensions/shape.h>
38
#include <libxfce4util/libxfce4util.h>
46
#include "transients.h"
47
#include "wireframe.h"
48
#include "workspaces.h"
49
#include "event_filter.h"
51
typedef struct _ClientCycleData ClientCycleData;
52
struct _ClientCycleData
60
static eventFilterStatus
61
clientCycleEventFilter (XEvent * xevent, gpointer data)
63
ScreenInfo *screen_info;
64
DisplayInfo *display_info;
65
ClientCycleData *passdata;
67
eventFilterStatus status;
70
gboolean key_pressed, cycling, gone;
72
TRACE ("entering clientCycleEventFilter");
74
passdata = (ClientCycleData *) data;
75
if (passdata->c == NULL)
77
return EVENT_FILTER_CONTINUE;
81
screen_info = c->screen_info;
82
display_info = screen_info->display_info;
83
cancel = screen_info->params->keys[KEY_CANCEL].keycode;
84
modifier = screen_info->params->keys[KEY_CYCLE_WINDOWS].modifier;
85
status = EVENT_FILTER_STOP;
89
/* Update the display time */
90
myDisplayUpdateCurrentTime (display_info, xevent);
95
removed = myScreenGetClientFromWindow (screen_info, ((XDestroyWindowEvent *) xevent)->window, SEARCH_WINDOW);
96
gone |= (c == removed);
97
c = tabwinRemoveClient(passdata->tabwin, removed);
99
status = EVENT_FILTER_CONTINUE;
102
removed = myScreenGetClientFromWindow (screen_info, ((XUnmapEvent *) xevent)->window, SEARCH_WINDOW);
103
gone |= (c == removed);
104
c = tabwinRemoveClient(passdata->tabwin, removed);
106
status = EVENT_FILTER_CONTINUE;
109
key_pressed = (xevent->type == KeyPress);
110
if (gone || key_pressed)
115
key = myScreenGetKeyPressed (screen_info, (XKeyEvent *) xevent);
117
* We cannot simply check for key == KEY_CANCEL here because of the
118
* mofidier being pressed, so we need to look at the keycode directly.
120
if (xevent->xkey.keycode == cancel)
122
c2 = tabwinGetHead (passdata->tabwin);
125
else if (key == KEY_CYCLE_REVERSE_WINDOWS)
127
TRACE ("Cycle: previous");
128
c2 = tabwinSelectPrev(passdata->tabwin);
130
else if (key == KEY_CYCLE_WINDOWS)
132
TRACE ("Cycle: next");
133
c2 = tabwinSelectNext(passdata->tabwin);
141
/* If last key press event had not our modifier pressed, finish cycling */
142
if (!(xevent->xkey.state & modifier))
152
if (passdata->wireframe)
154
wireframeUpdate (c, passdata->wireframe);
166
int keysym = XLookupKeysym (&xevent->xkey, 0);
168
if (!(xevent->xkey.state & modifier) ||
169
(IsModifierKey(keysym) && (keysym != XK_Shift_L) && (keysym != XK_Shift_R)))
181
status = EVENT_FILTER_CONTINUE;
187
TRACE ("event loop now finished");
195
clientCycle (Client * c, XKeyEvent * ev)
197
ScreenInfo *screen_info;
198
DisplayInfo *display_info;
199
ClientCycleData passdata;
203
g_return_if_fail (c != NULL);
204
TRACE ("entering clientCycle");
206
screen_info = c->screen_info;
207
display_info = screen_info->display_info;
209
g1 = myScreenGrabKeyboard (screen_info, ev->time);
210
g2 = myScreenGrabPointer (screen_info, LeaveWindowMask, None, ev->time);
214
TRACE ("grab failed in clientCycle");
217
myScreenUngrabKeyboard (screen_info, ev->time);
218
myScreenUngrabPointer (screen_info, ev->time);
223
if (screen_info->params->cycle_hidden)
225
passdata.cycle_range = INCLUDE_HIDDEN;
229
passdata.cycle_range = 0;
231
if (!screen_info->params->cycle_minimum)
233
passdata.cycle_range |= INCLUDE_SKIP_TASKBAR | INCLUDE_SKIP_PAGER;
235
if (screen_info->params->cycle_workspaces)
237
passdata.cycle_range |= INCLUDE_ALL_WORKSPACES;
239
key = myScreenGetKeyPressed (screen_info, ev);
240
if (key == KEY_CYCLE_REVERSE_WINDOWS)
242
passdata.c = clientGetPrevious (c, passdata.cycle_range);
246
passdata.c = clientGetNext (c, passdata.cycle_range);
248
passdata.wireframe = None;
250
/* If there is one single client, and if it's eligible for focus, use it */
251
if ((passdata.c == NULL) && (c != clientGetFocus()) &&
252
clientSelectMask (c, passdata.cycle_range, WINDOW_REGULAR_FOCUSABLE))
259
TRACE ("entering cycle loop");
260
if (screen_info->params->cycle_draw_frame)
262
passdata.wireframe = wireframeCreate (passdata.c);
264
passdata.tabwin = tabwinCreate (passdata.c->screen_info->gscr, c,
265
passdata.c, passdata.cycle_range,
266
screen_info->params->cycle_workspaces);
267
eventFilterPush (display_info->xfilter, clientCycleEventFilter, &passdata);
269
eventFilterPop (display_info->xfilter);
270
TRACE ("leaving cycle loop");
271
tabwinDestroy (passdata.tabwin);
272
g_free (passdata.tabwin);
273
if (passdata.wireframe)
275
wireframeDelete (screen_info, passdata.wireframe);
277
updateXserverTime (display_info);
287
workspace = c->win_workspace;
288
focused = clientGetFocus ();
290
if (workspace != screen_info->current_ws)
292
workspaceSwitch (screen_info, workspace, c, FALSE, myDisplayGetCurrentTime (display_info));
295
if ((focused) && (passdata.c != focused))
297
clientClearAllShowDesktop (screen_info);
298
clientAdjustFullscreenLayer (focused, FALSE);
301
sibling = clientGetTransientFor(c);
302
clientRaise (sibling, None);
303
clientShow (sibling, TRUE);
304
clientSetFocus (screen_info, c, myDisplayGetCurrentTime (display_info), NO_FOCUS_FLAG);
307
myScreenUngrabKeyboard (screen_info, myDisplayGetCurrentTime (display_info));
308
myScreenUngrabPointer (screen_info, myDisplayGetCurrentTime (display_info));