~ubuntu-branches/ubuntu/precise/xfwm4/precise-updates

« back to all changes in this revision

Viewing changes to src/cycle.c

  • Committer: Bazaar Package Importer
  • Author(s): Jérôme Guelfucci, Jérôme Guelfucci, Lionel Le Folgoc
  • Date: 2009-01-30 18:28:59 UTC
  • mfrom: (1.1.21 upstream)
  • Revision ID: james.westby@ubuntu.com-20090130182859-1tci3n1f1hhppvc2
Tags: 4.5.99.1-0ubuntu1
[ Jérôme Guelfucci ]
* Merge with Debian Xfce UNRELEASED, remaining Ubuntu changes:
  - debian/xfwm4.1: update bug reporting address (LP instead of Debian BTS).

[ Lionel Le Folgoc ]
* debian/control: use our Vcs-* fields.
* Bugs fixed by this new release:
  - "User interface of focused application is covered by another application's
    new window in Xfce" (LP: #250101)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*      $Id$
 
2
 
 
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)
 
6
        any later version.
 
7
 
 
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.
 
12
 
 
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,
 
16
        MA 02110-1301, USA.
 
17
 
 
18
 
 
19
        oroborus - (c) 2001 Ken Lynch
 
20
        xfwm4    - (c) 2002-2009 Olivier Fourdan
 
21
 
 
22
 */
 
23
 
 
24
#ifdef HAVE_CONFIG_H
 
25
#include "config.h"
 
26
#endif
 
27
 
 
28
#include <X11/X.h>
 
29
#include <X11/Xlib.h>
 
30
#include <X11/Xutil.h>
 
31
#include <X11/Xatom.h>
 
32
#include <X11/extensions/shape.h>
 
33
 
 
34
#include <glib.h>
 
35
#include <gdk/gdk.h>
 
36
#include <gdk/gdkx.h>
 
37
#include <gtk/gtk.h>
 
38
#include <libxfce4util/libxfce4util.h>
 
39
 
 
40
#include "client.h"
 
41
#include "focus.h"
 
42
#include "frame.h"
 
43
#include "settings.h"
 
44
#include "stacking.h"
 
45
#include "tabwin.h"
 
46
#include "transients.h"
 
47
#include "wireframe.h"
 
48
#include "workspaces.h"
 
49
#include "event_filter.h"
 
50
 
 
51
typedef struct _ClientCycleData ClientCycleData;
 
52
struct _ClientCycleData
 
53
{
 
54
    Client *c;
 
55
    Tabwin *tabwin;
 
56
    Window wireframe;
 
57
    int cycle_range;
 
58
};
 
59
 
 
60
static eventFilterStatus
 
61
clientCycleEventFilter (XEvent * xevent, gpointer data)
 
62
{
 
63
    ScreenInfo *screen_info;
 
64
    DisplayInfo *display_info;
 
65
    ClientCycleData *passdata;
 
66
    Client *c, *removed;
 
67
    eventFilterStatus status;
 
68
    KeyCode cancel;
 
69
    int key, modifier;
 
70
    gboolean key_pressed, cycling, gone;
 
71
 
 
72
    TRACE ("entering clientCycleEventFilter");
 
73
 
 
74
    passdata = (ClientCycleData *) data;
 
75
    if (passdata->c == NULL)
 
76
    {
 
77
        return EVENT_FILTER_CONTINUE;
 
78
    }
 
79
 
 
80
    c = passdata->c;
 
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;
 
86
    cycling = TRUE;
 
87
    gone = FALSE;
 
88
 
 
89
    /* Update the display time */
 
90
    myDisplayUpdateCurrentTime (display_info, xevent);
 
91
 
 
92
    switch (xevent->type)
 
93
    {
 
94
        case DestroyNotify:
 
95
            removed = myScreenGetClientFromWindow (screen_info, ((XDestroyWindowEvent *) xevent)->window, SEARCH_WINDOW);
 
96
            gone |= (c == removed);
 
97
            c = tabwinRemoveClient(passdata->tabwin, removed);
 
98
            passdata->c = c;
 
99
            status = EVENT_FILTER_CONTINUE;
 
100
            /* Walk through */
 
101
        case UnmapNotify:
 
102
            removed = myScreenGetClientFromWindow (screen_info, ((XUnmapEvent *) xevent)->window, SEARCH_WINDOW);
 
103
            gone |= (c == removed);
 
104
            c = tabwinRemoveClient(passdata->tabwin, removed);
 
105
            passdata->c = c;
 
106
            status = EVENT_FILTER_CONTINUE;
 
107
            /* Walk through */
 
108
        case KeyPress:
 
109
            key_pressed = (xevent->type == KeyPress);
 
110
            if (gone || key_pressed)
 
111
            {
 
112
                if (key_pressed)
 
113
                {
 
114
                    Client *c2 = NULL;
 
115
                    key = myScreenGetKeyPressed (screen_info, (XKeyEvent *) xevent);
 
116
                    /*
 
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.
 
119
                     */
 
120
                    if (xevent->xkey.keycode == cancel)
 
121
                    {
 
122
                        c2 = tabwinGetHead (passdata->tabwin);
 
123
                        cycling = FALSE;
 
124
                    }
 
125
                    else if (key == KEY_CYCLE_REVERSE_WINDOWS)
 
126
                    {
 
127
                        TRACE ("Cycle: previous");
 
128
                        c2 = tabwinSelectPrev(passdata->tabwin);
 
129
                    }
 
130
                    else if (key == KEY_CYCLE_WINDOWS)
 
131
                    {
 
132
                        TRACE ("Cycle: next");
 
133
                        c2 = tabwinSelectNext(passdata->tabwin);
 
134
                    }
 
135
                    if (c2)
 
136
                    {
 
137
                        c = c2;
 
138
                        passdata->c = c;
 
139
                    }
 
140
 
 
141
                    /* If last key press event had not our modifier pressed, finish cycling */
 
142
                    if (!(xevent->xkey.state & modifier))
 
143
                    {
 
144
                        cycling = FALSE;
 
145
                    }
 
146
                }
 
147
 
 
148
                if (cycling)
 
149
                {
 
150
                    if (c)
 
151
                    {
 
152
                        if (passdata->wireframe)
 
153
                        {
 
154
                            wireframeUpdate (c, passdata->wireframe);
 
155
                        }
 
156
                    }
 
157
                    else
 
158
                    {
 
159
                        cycling = FALSE;
 
160
                    }
 
161
                }
 
162
            }
 
163
            break;
 
164
        case KeyRelease:
 
165
            {
 
166
                int keysym = XLookupKeysym (&xevent->xkey, 0);
 
167
 
 
168
                if (!(xevent->xkey.state & modifier) ||
 
169
                    (IsModifierKey(keysym) && (keysym != XK_Shift_L) && (keysym != XK_Shift_R)))
 
170
                {
 
171
                    cycling = FALSE;
 
172
                }
 
173
            }
 
174
            break;
 
175
        case ButtonPress:
 
176
        case ButtonRelease:
 
177
        case EnterNotify:
 
178
        case MotionNotify:
 
179
            break;
 
180
        default:
 
181
            status = EVENT_FILTER_CONTINUE;
 
182
            break;
 
183
    }
 
184
 
 
185
    if (!cycling)
 
186
    {
 
187
        TRACE ("event loop now finished");
 
188
        gtk_main_quit ();
 
189
    }
 
190
 
 
191
    return status;
 
192
}
 
193
 
 
194
void
 
195
clientCycle (Client * c, XKeyEvent * ev)
 
196
{
 
197
    ScreenInfo *screen_info;
 
198
    DisplayInfo *display_info;
 
199
    ClientCycleData passdata;
 
200
    gboolean g1, g2;
 
201
    int key;
 
202
 
 
203
    g_return_if_fail (c != NULL);
 
204
    TRACE ("entering clientCycle");
 
205
 
 
206
    screen_info = c->screen_info;
 
207
    display_info = screen_info->display_info;
 
208
 
 
209
    g1 = myScreenGrabKeyboard (screen_info, ev->time);
 
210
    g2 = myScreenGrabPointer (screen_info, LeaveWindowMask,  None, ev->time);
 
211
 
 
212
    if (!g1 || !g2)
 
213
    {
 
214
        TRACE ("grab failed in clientCycle");
 
215
 
 
216
        gdk_beep ();
 
217
        myScreenUngrabKeyboard (screen_info, ev->time);
 
218
        myScreenUngrabPointer (screen_info, ev->time);
 
219
 
 
220
        return;
 
221
    }
 
222
 
 
223
    if (screen_info->params->cycle_hidden)
 
224
    {
 
225
        passdata.cycle_range = INCLUDE_HIDDEN;
 
226
    }
 
227
    else
 
228
    {
 
229
        passdata.cycle_range = 0;
 
230
    }
 
231
    if (!screen_info->params->cycle_minimum)
 
232
    {
 
233
        passdata.cycle_range |= INCLUDE_SKIP_TASKBAR | INCLUDE_SKIP_PAGER;
 
234
    }
 
235
    if (screen_info->params->cycle_workspaces)
 
236
    {
 
237
        passdata.cycle_range |= INCLUDE_ALL_WORKSPACES;
 
238
    }
 
239
    key = myScreenGetKeyPressed (screen_info, ev);
 
240
    if (key == KEY_CYCLE_REVERSE_WINDOWS)
 
241
    {
 
242
        passdata.c = clientGetPrevious (c, passdata.cycle_range);
 
243
    }
 
244
    else
 
245
    {
 
246
        passdata.c = clientGetNext (c, passdata.cycle_range);
 
247
    }
 
248
    passdata.wireframe = None;
 
249
 
 
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))
 
253
    {
 
254
        passdata.c = c;
 
255
    }
 
256
 
 
257
    if (passdata.c)
 
258
    {
 
259
        TRACE ("entering cycle loop");
 
260
        if (screen_info->params->cycle_draw_frame)
 
261
        {
 
262
            passdata.wireframe = wireframeCreate (passdata.c);
 
263
        }
 
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);
 
268
        gtk_main ();
 
269
        eventFilterPop (display_info->xfilter);
 
270
        TRACE ("leaving cycle loop");
 
271
        tabwinDestroy (passdata.tabwin);
 
272
        g_free (passdata.tabwin);
 
273
        if (passdata.wireframe)
 
274
        {
 
275
            wireframeDelete (screen_info, passdata.wireframe);
 
276
        }
 
277
        updateXserverTime (display_info);
 
278
    }
 
279
 
 
280
    if (passdata.c)
 
281
    {
 
282
        Client *focused;
 
283
        Client *sibling;
 
284
        int workspace;
 
285
 
 
286
        c = passdata.c;
 
287
        workspace = c->win_workspace;
 
288
        focused = clientGetFocus ();
 
289
 
 
290
        if (workspace != screen_info->current_ws)
 
291
        {
 
292
            workspaceSwitch (screen_info, workspace, c, FALSE, myDisplayGetCurrentTime (display_info));
 
293
        }
 
294
 
 
295
        if ((focused) && (passdata.c != focused))
 
296
        {
 
297
            clientClearAllShowDesktop (screen_info);
 
298
            clientAdjustFullscreenLayer (focused, FALSE);
 
299
        }
 
300
 
 
301
        sibling = clientGetTransientFor(c);
 
302
        clientRaise (sibling, None);
 
303
        clientShow (sibling, TRUE);
 
304
        clientSetFocus (screen_info, c, myDisplayGetCurrentTime (display_info), NO_FOCUS_FLAG);
 
305
    }
 
306
 
 
307
    myScreenUngrabKeyboard (screen_info, myDisplayGetCurrentTime (display_info));
 
308
    myScreenUngrabPointer (screen_info, myDisplayGetCurrentTime (display_info));
 
309
}