~ubuntu-branches/ubuntu/gutsy/kdebase-workspace/gutsy-backports

« back to all changes in this revision

Viewing changes to kwin/events.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Jonathan Riddell
  • Date: 2007-09-05 20:45:14 UTC
  • Revision ID: james.westby@ubuntu.com-20070905204514-632hhspl0nvrc84i
Tags: upstream-3.93.0
ImportĀ upstreamĀ versionĀ 3.93.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*****************************************************************
 
2
 KWin - the KDE window manager
 
3
 This file is part of the KDE project.
 
4
 
 
5
Copyright (C) 1999, 2000 Matthias Ettrich <ettrich@kde.org>
 
6
Copyright (C) 2003 Lubos Lunak <l.lunak@kde.org>
 
7
 
 
8
You can Freely distribute this program under the GNU General Public
 
9
License. See the file "COPYING" for the exact licensing terms.
 
10
******************************************************************/
 
11
 
 
12
/*
 
13
 
 
14
 This file contains things relevant to handling incoming events.
 
15
 
 
16
*/
 
17
 
 
18
#include <config-X11.h>
 
19
 
 
20
#include "client.h"
 
21
#include "workspace.h"
 
22
#include "atoms.h"
 
23
#include "tabbox.h"
 
24
#include "group.h"
 
25
#include "rules.h"
 
26
#include "unmanaged.h"
 
27
#include "scene.h"
 
28
#include "effects.h"
 
29
 
 
30
#include <QWhatsThis>
 
31
#include <QApplication>
 
32
 
 
33
#include <kkeyserver.h>
 
34
 
 
35
#include <X11/extensions/shape.h>
 
36
#include <X11/Xatom.h>
 
37
#include <QX11Info>
 
38
 
 
39
#ifdef HAVE_XRANDR
 
40
#include <X11/extensions/Xrandr.h>
 
41
#endif
 
42
 
 
43
namespace KWin
 
44
{
 
45
 
 
46
// ****************************************
 
47
// WinInfo
 
48
// ****************************************
 
49
 
 
50
WinInfo::WinInfo( Client * c, Display * display, Window window,
 
51
    Window rwin, const unsigned long pr[], int pr_size )
 
52
    : NETWinInfo( display, window, rwin, pr, pr_size, NET::WindowManager ), m_client( c )
 
53
    {
 
54
    }
 
55
 
 
56
void WinInfo::changeDesktop(int desktop)
 
57
    {
 
58
    m_client->workspace()->sendClientToDesktop( m_client, desktop, true );
 
59
    }
 
60
 
 
61
void WinInfo::changeState( unsigned long state, unsigned long mask )
 
62
    {
 
63
    mask &= ~NET::Sticky; // KWin doesn't support large desktops, ignore
 
64
    mask &= ~NET::Hidden; // clients are not allowed to change this directly
 
65
    state &= mask; // for safety, clear all other bits
 
66
 
 
67
    if(( mask & NET::FullScreen ) != 0 && ( state & NET::FullScreen ) == 0 )
 
68
        m_client->setFullScreen( false, false );
 
69
    if ( (mask & NET::Max) == NET::Max )
 
70
        m_client->setMaximize( state & NET::MaxVert, state & NET::MaxHoriz );
 
71
    else if ( mask & NET::MaxVert )
 
72
        m_client->setMaximize( state & NET::MaxVert, m_client->maximizeMode() & Client::MaximizeHorizontal );
 
73
    else if ( mask & NET::MaxHoriz )
 
74
        m_client->setMaximize( m_client->maximizeMode() & Client::MaximizeVertical, state & NET::MaxHoriz );
 
75
 
 
76
    if ( mask & NET::Shaded )
 
77
        m_client->setShade( state & NET::Shaded ? ShadeNormal : ShadeNone );
 
78
    if ( mask & NET::KeepAbove)
 
79
        m_client->setKeepAbove( (state & NET::KeepAbove) != 0 );
 
80
    if ( mask & NET::KeepBelow)
 
81
        m_client->setKeepBelow( (state & NET::KeepBelow) != 0 );
 
82
    if( mask & NET::SkipTaskbar )
 
83
        m_client->setSkipTaskbar( ( state & NET::SkipTaskbar ) != 0, true );
 
84
    if( mask & NET::SkipPager )
 
85
        m_client->setSkipPager( ( state & NET::SkipPager ) != 0 );
 
86
    if( mask & NET::DemandsAttention )
 
87
        m_client->demandAttention(( state & NET::DemandsAttention ) != 0 );
 
88
    if( mask & NET::Modal )
 
89
        m_client->setModal( ( state & NET::Modal ) != 0 );
 
90
    // unsetting fullscreen first, setting it last (because e.g. maximize works only for !isFullScreen() )
 
91
    if(( mask & NET::FullScreen ) != 0 && ( state & NET::FullScreen ) != 0 )
 
92
        m_client->setFullScreen( true, false );
 
93
    }
 
94
 
 
95
void WinInfo::disable()
 
96
    {
 
97
    m_client = NULL; // only used when the object is passed to Deleted
 
98
    }
 
99
 
 
100
// ****************************************
 
101
// RootInfo
 
102
// ****************************************
 
103
 
 
104
RootInfo::RootInfo( Workspace* ws, Display *dpy, Window w, const char *name, unsigned long pr[], int pr_num, int scr )
 
105
    : NETRootInfo( dpy, w, name, pr, pr_num, scr )
 
106
    {
 
107
    workspace = ws;
 
108
    }
 
109
 
 
110
void RootInfo::changeNumberOfDesktops(int n)
 
111
    {
 
112
    workspace->setNumberOfDesktops( n );
 
113
    }
 
114
 
 
115
void RootInfo::changeCurrentDesktop(int d)
 
116
    {
 
117
    workspace->setCurrentDesktop( d );
 
118
    }
 
119
 
 
120
void RootInfo::changeActiveWindow( Window w, NET::RequestSource src, Time timestamp, Window active_window )
 
121
    {
 
122
    if( Client* c = workspace->findClient( WindowMatchPredicate( w )))
 
123
        {
 
124
        if( timestamp == CurrentTime )
 
125
            timestamp = c->userTime();
 
126
        if( src != NET::FromApplication && src != FromTool )
 
127
            src = NET::FromTool;
 
128
        if( src == NET::FromTool )
 
129
            workspace->activateClient( c, true ); // force
 
130
        else // NET::FromApplication
 
131
            {
 
132
            Client* c2;
 
133
            if( workspace->allowClientActivation( c, timestamp ))
 
134
                workspace->activateClient( c );
 
135
            // if activation of the requestor's window would be allowed, allow activation too
 
136
            else if( active_window != None
 
137
                && ( c2 = workspace->findClient( WindowMatchPredicate( active_window ))) != NULL
 
138
                && workspace->allowClientActivation( c2,
 
139
                    timestampCompare( timestamp, c2->userTime() > 0 ? timestamp : c2->userTime())))
 
140
                workspace->activateClient( c );
 
141
            else
 
142
                c->demandAttention();
 
143
            }
 
144
        }
 
145
    }
 
146
 
 
147
void RootInfo::restackWindow( Window w, RequestSource src, Window above, int detail, Time timestamp )
 
148
    {
 
149
    if( Client* c = workspace->findClient( WindowMatchPredicate( w )))
 
150
        {
 
151
        if( timestamp == CurrentTime )
 
152
            timestamp = c->userTime();
 
153
        if( src != NET::FromApplication && src != FromTool )
 
154
            src = NET::FromTool;
 
155
        c->restackWindow( above, detail, src, timestamp, true );
 
156
        }
 
157
    }
 
158
 
 
159
void RootInfo::gotTakeActivity( Window w, Time timestamp, long flags )
 
160
    {
 
161
    if( Client* c = workspace->findClient( WindowMatchPredicate( w )))
 
162
        workspace->handleTakeActivity( c, timestamp, flags );
 
163
    }
 
164
 
 
165
void RootInfo::closeWindow(Window w)
 
166
    {
 
167
    Client* c = workspace->findClient( WindowMatchPredicate( w ));
 
168
    if ( c )
 
169
        c->closeWindow();
 
170
    }
 
171
 
 
172
void RootInfo::moveResize(Window w, int x_root, int y_root, unsigned long direction)
 
173
    {
 
174
    Client* c = workspace->findClient( WindowMatchPredicate( w ));
 
175
    if ( c )
 
176
        {
 
177
        updateXTime(); // otherwise grabbing may have old timestamp - this message should include timestamp
 
178
        c->NETMoveResize( x_root, y_root, (Direction)direction);
 
179
        }
 
180
    }
 
181
 
 
182
void RootInfo::moveResizeWindow(Window w, int flags, int x, int y, int width, int height )
 
183
    {
 
184
    Client* c = workspace->findClient( WindowMatchPredicate( w ));
 
185
    if ( c )
 
186
        c->NETMoveResizeWindow( flags, x, y, width, height );
 
187
    }
 
188
 
 
189
void RootInfo::gotPing( Window w, Time timestamp )
 
190
    {
 
191
    if( Client* c = workspace->findClient( WindowMatchPredicate( w )))
 
192
        c->gotPing( timestamp );
 
193
    }
 
194
 
 
195
void RootInfo::changeShowingDesktop( bool showing )
 
196
    {
 
197
    workspace->setShowingDesktop( showing );
 
198
    }
 
199
 
 
200
// ****************************************
 
201
// Workspace
 
202
// ****************************************
 
203
 
 
204
/*!
 
205
  Handles workspace specific XEvents
 
206
 */
 
207
bool Workspace::workspaceEvent( XEvent * e )
 
208
    {
 
209
    if ( mouse_emulation && (e->type == ButtonPress || e->type == ButtonRelease ) ) 
 
210
        {
 
211
        mouse_emulation = false;
 
212
        ungrabXKeyboard();
 
213
        }
 
214
    if( effects && static_cast< EffectsHandlerImpl* >( effects )->hasKeyboardGrab()
 
215
        && ( e->type == KeyPress || e->type == KeyRelease ))
 
216
        return false; // let Qt process it, it'll be intercepted again in eventFilter()
 
217
 
 
218
    if( e->type == PropertyNotify || e->type == ClientMessage )
 
219
        {
 
220
        unsigned long dirty[ NETRootInfo::PROPERTIES_SIZE ];
 
221
        rootInfo->event( e, dirty, NETRootInfo::PROPERTIES_SIZE );
 
222
        if( dirty[ NETRootInfo::PROTOCOLS ] & NET::DesktopNames )
 
223
            saveDesktopSettings();
 
224
        if( dirty[ NETRootInfo::PROTOCOLS2 ] & NET::WM2DesktopLayout )
 
225
            updateDesktopLayout();
 
226
        }
 
227
 
 
228
    // events that should be handled before Clients can get them
 
229
    switch (e->type) 
 
230
        {
 
231
        case ButtonPress:
 
232
        case ButtonRelease:
 
233
            was_user_interaction = true;
 
234
        // fallthrough
 
235
        case MotionNotify:
 
236
            if ( tab_grab || control_grab )
 
237
                {
 
238
                tab_box->handleMouseEvent( e );
 
239
                return true;
 
240
                }
 
241
            if( effects && static_cast<EffectsHandlerImpl*>(effects)->checkInputWindowEvent( e ))
 
242
                return true;
 
243
            break;
 
244
        case KeyPress:
 
245
            {
 
246
            was_user_interaction = true;
 
247
            int keyQt;
 
248
            KKeyServer::xEventToQt(e, &keyQt);
 
249
            kDebug(125) << "Workspace::keyPress( " << keyQt << " )";
 
250
            if (movingClient)
 
251
                {
 
252
                movingClient->keyPressEvent(keyQt);
 
253
                return true;
 
254
                }
 
255
            if( tab_grab || control_grab )
 
256
                {
 
257
                tabBoxKeyPress( keyQt );
 
258
                return true;
 
259
                }
 
260
            break;
 
261
            }
 
262
        case KeyRelease:
 
263
            was_user_interaction = true;
 
264
            if( tab_grab || control_grab )
 
265
                {
 
266
                tabBoxKeyRelease( e->xkey );
 
267
                return true;
 
268
                }
 
269
            break;
 
270
        };
 
271
 
 
272
    if( Client* c = findClient( WindowMatchPredicate( e->xany.window )))
 
273
        {
 
274
        if( c->windowEvent( e ))
 
275
            return true;
 
276
        }
 
277
    else if( Client* c = findClient( WrapperIdMatchPredicate( e->xany.window )))
 
278
        {
 
279
        if( c->windowEvent( e ))
 
280
            return true;
 
281
        }
 
282
    else if( Client* c = findClient( FrameIdMatchPredicate( e->xany.window )))
 
283
        {
 
284
        if( c->windowEvent( e ))
 
285
            return true;
 
286
        }
 
287
    else if( Unmanaged* c = findUnmanaged( WindowMatchPredicate( e->xany.window )))
 
288
        {
 
289
        if( c->windowEvent( e ))
 
290
            return true;
 
291
        }
 
292
    else
 
293
        {
 
294
        Window special = findSpecialEventWindow( e );
 
295
        if( special != None )
 
296
            if( Client* c = findClient( WindowMatchPredicate( special )))
 
297
                {
 
298
                if( c->windowEvent( e ))
 
299
                    return true;
 
300
                }
 
301
        }
 
302
    if( movingClient != NULL && movingClient->moveResizeGrabWindow() == e->xany.window
 
303
        && ( e->type == MotionNotify || e->type == ButtonPress || e->type == ButtonRelease ))
 
304
        {
 
305
        if( movingClient->windowEvent( e ))
 
306
            return true;
 
307
        }
 
308
 
 
309
    switch (e->type) 
 
310
        {
 
311
        case CreateNotify:
 
312
            if ( e->xcreatewindow.parent == rootWindow() &&
 
313
                 !QWidget::find( e->xcreatewindow.window) &&
 
314
                 !e->xcreatewindow.override_redirect )
 
315
            {
 
316
        // see comments for allowClientActivation()
 
317
            Time t = xTime();
 
318
            XChangeProperty(display(), e->xcreatewindow.window,
 
319
                            atoms->kde_net_wm_user_creation_time, XA_CARDINAL,
 
320
                            32, PropModeReplace, (unsigned char *)&t, 1);
 
321
            }
 
322
        break;
 
323
 
 
324
    case UnmapNotify:
 
325
            {
 
326
            return ( e->xunmap.event != e->xunmap.window ); // hide wm typical event from Qt
 
327
            }
 
328
        case ReparentNotify:
 
329
            {
 
330
        //do not confuse Qt with these events. After all, _we_ are the
 
331
        //window manager who does the reparenting.
 
332
            return true;
 
333
            }
 
334
        case DestroyNotify:
 
335
            {
 
336
            return false;
 
337
            }
 
338
        case MapRequest:
 
339
            {
 
340
            updateXTime();
 
341
 
 
342
            // e->xmaprequest.window is different from e->xany.window
 
343
            // TODO this shouldn't be necessary now
 
344
            Client* c = findClient( WindowMatchPredicate( e->xmaprequest.window ));
 
345
            if ( !c ) 
 
346
                {
 
347
// don't check for the parent being the root window, this breaks when some app unmaps
 
348
// a window, changes something and immediately maps it back, without giving KWin
 
349
// a chance to reparent it back to root
 
350
// since KWin can get MapRequest only for root window children and
 
351
// children of WindowWrapper (=clients), the check is AFAIK useless anyway
 
352
// Note: Now the save-set support in Client::mapRequestEvent() actually requires that
 
353
// this code doesn't check the parent to be root.
 
354
//            if ( e->xmaprequest.parent == root ) {
 
355
                c = createClient( e->xmaprequest.window, false );
 
356
                if( c == NULL ) // refused to manage, simply map it (most probably override redirect)
 
357
                    XMapRaised( display(), e->xmaprequest.window );
 
358
                return true;
 
359
                }
 
360
            if( c )
 
361
                {
 
362
                c->windowEvent( e );
 
363
                updateFocusChains( c, FocusChainUpdate );
 
364
                return true;
 
365
                }
 
366
            break;
 
367
            }
 
368
        case MapNotify:
 
369
            {
 
370
            if( e->xmap.override_redirect )
 
371
                {
 
372
                Unmanaged* c = findUnmanaged( WindowMatchPredicate( e->xmap.window ));
 
373
                if( c == NULL )
 
374
                    c = createUnmanaged( e->xmap.window );
 
375
                if( c )
 
376
                    return c->windowEvent( e );
 
377
                }
 
378
            return ( e->xmap.event != e->xmap.window ); // hide wm typical event from Qt
 
379
            }
 
380
 
 
381
        case EnterNotify:
 
382
            {
 
383
            if ( QWhatsThis::inWhatsThisMode() )
 
384
                {
 
385
                QWidget* w = QWidget::find( e->xcrossing.window );
 
386
                if ( w )
 
387
                    QWhatsThis::leaveWhatsThisMode();
 
388
                }
 
389
            if( electricBorderEvent(e))
 
390
                return true;
 
391
            break;
 
392
            }
 
393
        case LeaveNotify:
 
394
            {
 
395
            if ( !QWhatsThis::inWhatsThisMode() )
 
396
                break;
 
397
            // TODO is this cliente ever found, given that client events are searched above?
 
398
            Client* c = findClient( FrameIdMatchPredicate( e->xcrossing.window ));
 
399
            if ( c && e->xcrossing.detail != NotifyInferior )
 
400
                QWhatsThis::leaveWhatsThisMode();
 
401
            break;
 
402
            }
 
403
        case ConfigureRequest:
 
404
            {
 
405
            if ( e->xconfigurerequest.parent == rootWindow()) 
 
406
                {
 
407
                XWindowChanges wc;
 
408
                wc.border_width = e->xconfigurerequest.border_width;
 
409
                wc.x = e->xconfigurerequest.x;
 
410
                wc.y = e->xconfigurerequest.y;
 
411
                wc.width = e->xconfigurerequest.width;
 
412
                wc.height = e->xconfigurerequest.height;
 
413
                wc.sibling = None;
 
414
                wc.stack_mode = Above;
 
415
                unsigned int value_mask = e->xconfigurerequest.value_mask
 
416
                    & ( CWX | CWY | CWWidth | CWHeight | CWBorderWidth );
 
417
                XConfigureWindow( display(), e->xconfigurerequest.window, value_mask, &wc );
 
418
                return true;
 
419
                }
 
420
            break;
 
421
            }
 
422
        case KeyPress:
 
423
            if ( mouse_emulation )
 
424
                return keyPressMouseEmulation( e->xkey );
 
425
            break;
 
426
        case KeyRelease:
 
427
            if ( mouse_emulation )
 
428
                return false;
 
429
            break;
 
430
        case FocusIn:
 
431
            if( e->xfocus.window == rootWindow()
 
432
                && ( e->xfocus.detail == NotifyDetailNone || e->xfocus.detail == NotifyPointerRoot ))
 
433
                {
 
434
                updateXTime(); // focusToNull() uses xTime(), which is old now (FocusIn has no timestamp)
 
435
                Window focus;
 
436
                int revert;
 
437
                XGetInputFocus( display(), &focus, &revert );
 
438
                if( focus == None || focus == PointerRoot )
 
439
                    {
 
440
                    //kWarning( 1212 ) << "X focus set to None/PointerRoot, reseting focus" ;
 
441
                    Client *c = mostRecentlyActivatedClient();
 
442
                    if( c != NULL )
 
443
                        requestFocus( c, true );
 
444
                    else if( activateNextClient( NULL ))
 
445
                        ; // ok, activated
 
446
                    else
 
447
                        focusToNull();
 
448
                    }
 
449
                }
 
450
            // fall through
 
451
        case FocusOut:
 
452
            return true; // always eat these, they would tell Qt that KWin is the active app
 
453
        case ClientMessage:
 
454
            if( electricBorderEvent( e ))
 
455
                return true;
 
456
            break;
 
457
        case Expose:
 
458
            if( e->xexpose.window == rootWindow() && compositing())  // root window needs repainting
 
459
                addRepaint( e->xexpose.x, e->xexpose.y, e->xexpose.width, e->xexpose.height );
 
460
            break;
 
461
        default:
 
462
            if( e->type == Extensions::randrNotifyEvent() && Extensions::randrAvailable() )
 
463
                {
 
464
#ifdef HAVE_XRANDR
 
465
                XRRUpdateConfiguration( e );
 
466
#endif
 
467
                if( compositing() )
 
468
                    {
 
469
                    // desktopResized() should take care of when the size or
 
470
                    // shape of the desktop has changed, but we also want to
 
471
                    // catch refresh rate changes
 
472
                    finishCompositing();
 
473
                    QTimer::singleShot( 0, this, SLOT( setupCompositing() ) );
 
474
                    }
 
475
                }
 
476
            else if( e->type == Extensions::syncAlarmNotifyEvent() && Extensions::syncAvailable())
 
477
                {
 
478
#ifdef HAVE_XSYNC
 
479
                foreach( Client* c, clients )
 
480
                    c->syncEvent( reinterpret_cast< XSyncAlarmNotifyEvent* >( e ));
 
481
                foreach( Client* c, desktops )
 
482
                    c->syncEvent( reinterpret_cast< XSyncAlarmNotifyEvent* >( e ));
 
483
#endif
 
484
                }
 
485
            break;
 
486
        }
 
487
    return false;
 
488
    }
 
489
 
 
490
// Used only to filter events that need to be processed by Qt first
 
491
// (e.g. keyboard input to be composed), otherwise events are
 
492
// handle by the XEvent filter above
 
493
bool Workspace::workspaceEvent( QEvent* e )
 
494
    {
 
495
    if(( e->type() == QEvent::KeyPress || e->type() == QEvent::KeyRelease || e->type() == QEvent::ShortcutOverride )
 
496
        && effects && static_cast< EffectsHandlerImpl* >( effects )->hasKeyboardGrab())
 
497
        {
 
498
        static_cast< EffectsHandlerImpl* >( effects )->grabbedKeyboardEvent( static_cast< QKeyEvent* >( e ));
 
499
        return true;
 
500
        }
 
501
    return false;
 
502
    }
 
503
 
 
504
// Some events don't have the actual window which caused the event
 
505
// as e->xany.window (e.g. ConfigureRequest), but as some other
 
506
// field in the XEvent structure.
 
507
Window Workspace::findSpecialEventWindow( XEvent* e )
 
508
    {
 
509
    switch( e->type )
 
510
        {
 
511
        case CreateNotify:
 
512
            return e->xcreatewindow.window;
 
513
        case DestroyNotify:
 
514
            return e->xdestroywindow.window;
 
515
        case UnmapNotify:
 
516
            return e->xunmap.window;
 
517
        case MapNotify:
 
518
            return e->xmap.window;
 
519
        case MapRequest:
 
520
            return e->xmaprequest.window;
 
521
        case ReparentNotify:
 
522
            return e->xreparent.window;
 
523
        case ConfigureNotify:
 
524
            return e->xconfigure.window;
 
525
        case GravityNotify:
 
526
            return e->xgravity.window;
 
527
        case ConfigureRequest:
 
528
            return e->xconfigurerequest.window;
 
529
        case CirculateNotify:
 
530
            return e->xcirculate.window;
 
531
        case CirculateRequest:
 
532
            return e->xcirculaterequest.window;
 
533
        default:
 
534
            return None;
 
535
        };
 
536
    }
 
537
 
 
538
// ****************************************
 
539
// Client
 
540
// ****************************************
 
541
 
 
542
/*!
 
543
  General handler for XEvents concerning the client window
 
544
 */
 
545
bool Client::windowEvent( XEvent* e )
 
546
    {
 
547
    if( e->xany.window == window()) // avoid doing stuff on frame or wrapper
 
548
        {
 
549
        unsigned long dirty[ 2 ];
 
550
        double old_opacity = opacity();
 
551
        info->event( e, dirty, 2 ); // pass through the NET stuff
 
552
 
 
553
        if ( ( dirty[ WinInfo::PROTOCOLS ] & NET::WMName ) != 0 )
 
554
            fetchName();
 
555
        if ( ( dirty[ WinInfo::PROTOCOLS ] & NET::WMIconName ) != 0 )
 
556
            fetchIconicName();
 
557
        if ( ( dirty[ WinInfo::PROTOCOLS ] & NET::WMStrut ) != 0
 
558
            || ( dirty[ WinInfo::PROTOCOLS2 ] & NET::WM2ExtendedStrut ) != 0 )
 
559
            {
 
560
            if( isTopMenu())  // the fallback mode of KMenuBar may alter the strut
 
561
                checkWorkspacePosition();  // restore it
 
562
            workspace()->updateClientArea();
 
563
            }
 
564
        if ( ( dirty[ WinInfo::PROTOCOLS ] & NET::WMIcon) != 0 )
 
565
            getIcons();
 
566
        // Note there's a difference between userTime() and info->userTime()
 
567
        // info->userTime() is the value of the property, userTime() also includes
 
568
        // updates of the time done by KWin (ButtonPress on windowrapper etc.).
 
569
        if(( dirty[ WinInfo::PROTOCOLS2 ] & NET::WM2UserTime ) != 0 )
 
570
            {
 
571
            workspace()->setWasUserInteraction();
 
572
            updateUserTime( info->userTime());
 
573
            }
 
574
        if(( dirty[ WinInfo::PROTOCOLS2 ] & NET::WM2StartupId ) != 0 )
 
575
            startupIdChanged();
 
576
        if( dirty[ WinInfo::PROTOCOLS ] & NET::WMIconGeometry )
 
577
            {
 
578
            if( demandAttentionKNotifyTimer != NULL )
 
579
                demandAttentionKNotify();
 
580
            }
 
581
        if( dirty[ WinInfo::PROTOCOLS2 ] & NET::WM2Opacity )
 
582
            {
 
583
            if( compositing())
 
584
                {
 
585
                addRepaintFull();
 
586
                scene->windowOpacityChanged( this );
 
587
                if( effects )
 
588
                    static_cast<EffectsHandlerImpl*>(effects)->windowOpacityChanged( effectWindow(), old_opacity );
 
589
                }
 
590
            else
 
591
                { // forward to the frame if there's possibly another compositing manager running
 
592
                NETWinInfo i( display(), frameId(), rootWindow(), 0 );
 
593
                i.setOpacity( info->opacity());
 
594
                }
 
595
            }
 
596
        }
 
597
 
 
598
    switch (e->type) 
 
599
        {
 
600
        case UnmapNotify:
 
601
            unmapNotifyEvent( &e->xunmap );
 
602
            break;
 
603
        case DestroyNotify:
 
604
            destroyNotifyEvent( &e->xdestroywindow );
 
605
            break;
 
606
        case MapRequest:
 
607
            // this one may pass the event to workspace
 
608
            return mapRequestEvent( &e->xmaprequest );
 
609
        case ConfigureRequest:
 
610
            configureRequestEvent( &e->xconfigurerequest );
 
611
            break;
 
612
        case PropertyNotify:
 
613
            propertyNotifyEvent( &e->xproperty );
 
614
            break;
 
615
        case KeyPress:
 
616
            updateUserTime();
 
617
            workspace()->setWasUserInteraction();
 
618
            break;
 
619
        case ButtonPress:
 
620
            updateUserTime();
 
621
            workspace()->setWasUserInteraction();
 
622
            buttonPressEvent( e->xbutton.window, e->xbutton.button, e->xbutton.state,
 
623
                e->xbutton.x, e->xbutton.y, e->xbutton.x_root, e->xbutton.y_root );
 
624
            break;
 
625
        case KeyRelease:
 
626
    // don't update user time on releases
 
627
    // e.g. if the user presses Alt+F2, the Alt release
 
628
    // would appear as user input to the currently active window
 
629
            break;
 
630
        case ButtonRelease:
 
631
    // don't update user time on releases
 
632
    // e.g. if the user presses Alt+F2, the Alt release
 
633
    // would appear as user input to the currently active window
 
634
            buttonReleaseEvent( e->xbutton.window, e->xbutton.button, e->xbutton.state,
 
635
                e->xbutton.x, e->xbutton.y, e->xbutton.x_root, e->xbutton.y_root );
 
636
            break;
 
637
        case MotionNotify:
 
638
            motionNotifyEvent( e->xmotion.window, e->xmotion.state,
 
639
                e->xmotion.x, e->xmotion.y, e->xmotion.x_root, e->xmotion.y_root );
 
640
            workspace()->updateFocusMousePosition( QPoint( e->xmotion.x_root, e->xmotion.y_root ));
 
641
            break;
 
642
        case EnterNotify:
 
643
            enterNotifyEvent( &e->xcrossing );
 
644
            // MotionNotify is guaranteed to be generated only if the mouse
 
645
            // move start and ends in the window; for cases when it only
 
646
            // starts or only ends there, Enter/LeaveNotify are generated.
 
647
            // Fake a MotionEvent in such cases to make handle of mouse
 
648
            // events simpler (Qt does that too).
 
649
            motionNotifyEvent( e->xcrossing.window, e->xcrossing.state,
 
650
                e->xcrossing.x, e->xcrossing.y, e->xcrossing.x_root, e->xcrossing.y_root );
 
651
            workspace()->updateFocusMousePosition( QPoint( e->xcrossing.x_root, e->xcrossing.y_root ));
 
652
            break;
 
653
        case LeaveNotify:
 
654
            motionNotifyEvent( e->xcrossing.window, e->xcrossing.state,
 
655
                e->xcrossing.x, e->xcrossing.y, e->xcrossing.x_root, e->xcrossing.y_root );
 
656
            leaveNotifyEvent( &e->xcrossing );
 
657
            // not here, it'd break following enter notify handling
 
658
            // workspace()->updateFocusMousePosition( QPoint( e->xcrossing.x_root, e->xcrossing.y_root ));
 
659
            break;
 
660
        case FocusIn:
 
661
            focusInEvent( &e->xfocus );
 
662
            break;
 
663
        case FocusOut:
 
664
            focusOutEvent( &e->xfocus );
 
665
            break;
 
666
        case ReparentNotify:
 
667
            break;
 
668
        case ClientMessage:
 
669
            clientMessageEvent( &e->xclient );
 
670
            break;
 
671
        case ColormapChangeMask:
 
672
            if( e->xany.window == window())
 
673
            {
 
674
            cmap = e->xcolormap.colormap;
 
675
            if ( isActive() )
 
676
                workspace()->updateColormap();
 
677
            }
 
678
            break;
 
679
        default:
 
680
            if( e->xany.window == window())
 
681
                {
 
682
                if( e->type == Extensions::shapeNotifyEvent() )
 
683
                    {
 
684
                    detectShape( window()); // workaround for #19644
 
685
                    updateShape();
 
686
                    }
 
687
                }
 
688
            if( e->xany.window == frameId())
 
689
                {
 
690
#ifdef HAVE_XDAMAGE
 
691
                if( e->type == Extensions::damageNotifyEvent())
 
692
                    damageNotifyEvent( reinterpret_cast< XDamageNotifyEvent* >( e ));
 
693
#endif
 
694
                }
 
695
            break;
 
696
        }
 
697
    return true; // eat all events
 
698
    }
 
699
 
 
700
/*!
 
701
  Handles map requests of the client window
 
702
 */
 
703
bool Client::mapRequestEvent( XMapRequestEvent* e )
 
704
    {
 
705
    if( e->window != window())
 
706
        {
 
707
        // Special support for the save-set feature, which is a bit broken.
 
708
        // If there's a window from one client embedded in another one,
 
709
        // e.g. using XEMBED, and the embedder suddenly looses its X connection,
 
710
        // save-set will reparent the embedded window to its closest ancestor
 
711
        // that will remains. Unfortunately, with reparenting window managers,
 
712
        // this is not the root window, but the frame (or in KWin's case,
 
713
        // it's the wrapper for the client window). In this case,
 
714
        // the wrapper will get ReparentNotify for a window it won't know,
 
715
        // which will be ignored, and then it gets MapRequest, as save-set
 
716
        // always maps. Returning true here means that Workspace::workspaceEvent()
 
717
        // will handle this MapRequest and manage this window (i.e. act as if
 
718
        // it was reparented to root window).
 
719
        if( e->parent == wrapperId())
 
720
            return false;
 
721
        return true; // no messing with frame etc.
 
722
        }
 
723
    if( isTopMenu() && workspace()->managingTopMenus())
 
724
        return true; // kwin controls these
 
725
    switch ( mappingState() )
 
726
        {
 
727
        case WithdrawnState:
 
728
            assert( false ); // WMs are not supposed to manage clients in Withdrawn state,
 
729
//        manage();      // after initial mapping manage() is called from createClient()
 
730
            break;
 
731
        case IconicState:
 
732
        // also copied in clientMessage()
 
733
            if( isMinimized())
 
734
                unminimize();
 
735
            if( isShade())
 
736
                setShade( ShadeNone );
 
737
            if( !isOnCurrentDesktop())
 
738
                {
 
739
                if( workspace()->allowClientActivation( this ))
 
740
                    workspace()->activateClient( this );
 
741
                else
 
742
                    demandAttention();
 
743
                }
 
744
            break;
 
745
        case NormalState:
 
746
            // TODO fake MapNotify?
 
747
            break;
 
748
        }
 
749
    return true;
 
750
    }
 
751
 
 
752
/*!
 
753
  Handles unmap notify events of the client window
 
754
 */
 
755
void Client::unmapNotifyEvent( XUnmapEvent* e )
 
756
    {
 
757
    if( e->window != window())
 
758
        return;
 
759
    if( e->event != wrapperId())
 
760
        { // most probably event from root window when initially reparenting
 
761
        bool ignore = true;
 
762
        if( e->event == rootWindow() && e->send_event )
 
763
            ignore = false; // XWithdrawWindow()
 
764
        if( ignore )
 
765
            return;
 
766
        }
 
767
    switch( mappingState())
 
768
        {
 
769
        case IconicState:
 
770
            releaseWindow();
 
771
          return;
 
772
        case NormalState:
 
773
            // maybe we will be destroyed soon. Check this first.
 
774
            XEvent ev;
 
775
            if( XCheckTypedWindowEvent (display(), window(),
 
776
                DestroyNotify, &ev) ) // TODO I don't like this much
 
777
                {
 
778
                destroyClient(); // deletes this
 
779
                return;
 
780
                }
 
781
            releaseWindow();
 
782
          break;
 
783
    default:
 
784
        assert( false );
 
785
        }
 
786
    }
 
787
 
 
788
void Client::destroyNotifyEvent( XDestroyWindowEvent* e )
 
789
    {
 
790
    if( e->window != window())
 
791
        return;
 
792
    destroyClient();
 
793
    }
 
794
    
 
795
    
 
796
/*!
 
797
   Handles client messages for the client window
 
798
*/
 
799
void Client::clientMessageEvent( XClientMessageEvent* e )
 
800
    {
 
801
    if( e->window != window())
 
802
        return; // ignore frame/wrapper
 
803
    // WM_STATE
 
804
    if ( e->message_type == atoms->kde_wm_change_state )
 
805
        {
 
806
        if( isTopMenu() && workspace()->managingTopMenus())
 
807
            return; // kwin controls these
 
808
        bool avoid_animation = ( e->data.l[ 1 ] );
 
809
        if( e->data.l[ 0 ] == IconicState )
 
810
            minimize();
 
811
        else if( e->data.l[ 0 ] == NormalState )
 
812
            { // copied from mapRequest()
 
813
            if( isMinimized())
 
814
                unminimize( avoid_animation );
 
815
            if( isShade())
 
816
                setShade( ShadeNone );
 
817
            if( !isOnCurrentDesktop())
 
818
                {
 
819
                if( workspace()->allowClientActivation( this ))
 
820
                    workspace()->activateClient( this );
 
821
                else
 
822
                    demandAttention();
 
823
                }
 
824
            }
 
825
        }
 
826
    else if ( e->message_type == atoms->wm_change_state)
 
827
        {
 
828
        if( isTopMenu() && workspace()->managingTopMenus())
 
829
            return; // kwin controls these
 
830
        if ( e->data.l[0] == IconicState )
 
831
            minimize();
 
832
        return;
 
833
        }
 
834
    }
 
835
 
 
836
 
 
837
/*!
 
838
  Handles configure  requests of the client window
 
839
 */
 
840
void Client::configureRequestEvent( XConfigureRequestEvent* e )
 
841
    {
 
842
    if( e->window != window())
 
843
        return; // ignore frame/wrapper
 
844
    if ( isResize() || isMove())
 
845
        return; // we have better things to do right now
 
846
 
 
847
    if( fullscreen_mode == FullScreenNormal ) // refuse resizing of fullscreen windows
 
848
        { // but allow resizing fullscreen hacks in order to let them cancel fullscreen mode
 
849
        sendSyntheticConfigureNotify();
 
850
        return;
 
851
        }
 
852
    if( isSplash() // no manipulations with splashscreens either
 
853
        || isTopMenu()) // topmenus neither
 
854
        {
 
855
        sendSyntheticConfigureNotify();
 
856
        return;
 
857
        }
 
858
 
 
859
    if ( e->value_mask & CWBorderWidth ) 
 
860
        {
 
861
        // first, get rid of a window border
 
862
        XWindowChanges wc;
 
863
        unsigned int value_mask = 0;
 
864
 
 
865
        wc.border_width = 0;
 
866
        value_mask = CWBorderWidth;
 
867
        XConfigureWindow( display(), window(), value_mask, & wc );
 
868
        }
 
869
 
 
870
    if( e->value_mask & ( CWX | CWY | CWHeight | CWWidth ))
 
871
        configureRequest( e->value_mask, e->x, e->y, e->width, e->height, 0, false );
 
872
 
 
873
    if ( e->value_mask & CWStackMode )
 
874
        restackWindow( e->above, e->detail, NET::FromApplication, userTime(), false );
 
875
 
 
876
    // Sending a synthetic configure notify always is fine, even in cases where
 
877
    // the ICCCM doesn't require this - it can be though of as 'the WM decided to move
 
878
    // the window later'. The client should not cause that many configure request,
 
879
    // so this should not have any significant impact. With user moving/resizing
 
880
    // the it should be optimized though (see also Client::setGeometry()/plainResize()/move()).
 
881
    sendSyntheticConfigureNotify();
 
882
 
 
883
    // SELI TODO accept configure requests for isDesktop windows (because kdesktop
 
884
    // may get XRANDR resize event before kwin), but check it's still at the bottom?
 
885
    }
 
886
 
 
887
 
 
888
/*!
 
889
  Handles property changes of the client window
 
890
 */
 
891
void Client::propertyNotifyEvent( XPropertyEvent* e )
 
892
    {
 
893
    Toplevel::propertyNotifyEvent( e );
 
894
    if( e->window != window())
 
895
        return; // ignore frame/wrapper
 
896
    switch ( e->atom ) 
 
897
        {
 
898
        case XA_WM_NORMAL_HINTS:
 
899
            getWmNormalHints();
 
900
            break;
 
901
        case XA_WM_NAME:
 
902
            fetchName();
 
903
            break;
 
904
        case XA_WM_ICON_NAME:
 
905
            fetchIconicName();
 
906
            break;
 
907
        case XA_WM_TRANSIENT_FOR:
 
908
            readTransient();
 
909
            break;
 
910
        case XA_WM_HINTS:
 
911
            getWMHints();
 
912
            getIcons(); // because KWin::icon() uses WMHints as fallback
 
913
            break;
 
914
        default:
 
915
            if ( e->atom == atoms->wm_protocols )
 
916
                getWindowProtocols();
 
917
            else if( e->atom == atoms->motif_wm_hints )
 
918
                getMotifHints();
 
919
            else if( e->atom == atoms->net_wm_sync_request_counter )
 
920
                getSyncCounter();
 
921
            break;
 
922
        }
 
923
    }
 
924
 
 
925
 
 
926
void Client::enterNotifyEvent( XCrossingEvent* e )
 
927
    {
 
928
    if( e->window != frameId())
 
929
        return; // care only about entering the whole frame
 
930
    if( e->mode == NotifyNormal ||
 
931
         ( !options->focusPolicyIsReasonable() &&
 
932
             e->mode == NotifyUngrab ) ) 
 
933
        {
 
934
 
 
935
        if (options->shadeHover && isShade()) 
 
936
            {
 
937
            delete shadeHoverTimer;
 
938
            shadeHoverTimer = new QTimer( this );
 
939
            connect( shadeHoverTimer, SIGNAL( timeout() ), this, SLOT( shadeHover() ));
 
940
            shadeHoverTimer->setSingleShot( true );
 
941
            shadeHoverTimer->start( options->shadeHoverInterval );
 
942
            }
 
943
 
 
944
        if ( options->focusPolicy == Options::ClickToFocus )
 
945
            return;
 
946
 
 
947
        if ( options->autoRaise && !isDesktop() &&
 
948
             !isDock() && !isTopMenu() && workspace()->focusChangeEnabled() &&
 
949
             workspace()->topClientOnDesktop( workspace()->currentDesktop()) != this ) 
 
950
            {
 
951
            delete autoRaiseTimer;
 
952
            autoRaiseTimer = new QTimer( this );
 
953
            connect( autoRaiseTimer, SIGNAL( timeout() ), this, SLOT( autoRaise() ) );
 
954
            autoRaiseTimer->setSingleShot( true );
 
955
            autoRaiseTimer->start( options->autoRaiseInterval );
 
956
            }
 
957
 
 
958
        QPoint currentPos( e->x_root, e->y_root );
 
959
        if ( options->focusPolicy != Options::FocusStrictlyUnderMouse && ( isDesktop() || isDock() || isTopMenu() ) )
 
960
            return;
 
961
        // for FocusFollowsMouse, change focus only if the mouse has actually been moved, not if the focus
 
962
        // change came because of window changes (e.g. closing a window) - #92290
 
963
        if( options->focusPolicy != Options::FocusFollowsMouse
 
964
            || currentPos != workspace()->focusMousePosition())
 
965
            {
 
966
            if ( options->delayFocus )
 
967
                workspace()->requestDelayFocus( this );
 
968
            else
 
969
                workspace()->requestFocus( this );
 
970
            }
 
971
        return;
 
972
        }
 
973
    }
 
974
 
 
975
void Client::leaveNotifyEvent( XCrossingEvent* e )
 
976
    {
 
977
    if( e->window != frameId())
 
978
        return; // care only about leaving the whole frame
 
979
    if ( e->mode == NotifyNormal ) 
 
980
        {
 
981
        if ( !buttonDown ) 
 
982
            {
 
983
            mode = PositionCenter;
 
984
            updateCursor();
 
985
            }
 
986
        bool lostMouse = !rect().contains( QPoint( e->x, e->y ) );
 
987
        // 'lostMouse' wouldn't work with e.g. B2 or Keramik, which have non-rectangular decorations
 
988
        // (i.e. the LeaveNotify event comes before leaving the rect and no LeaveNotify event
 
989
        // comes after leaving the rect) - so lets check if the pointer is really outside the window
 
990
 
 
991
        // TODO this still sucks if a window appears above this one - it should lose the mouse
 
992
        // if this window is another client, but not if it's a popup ... maybe after KDE3.1 :(
 
993
        // (repeat after me 'AARGHL!')
 
994
        if ( !lostMouse && e->detail != NotifyInferior ) 
 
995
            {
 
996
            int d1, d2, d3, d4;
 
997
            unsigned int d5;
 
998
            Window w, child;
 
999
            if( XQueryPointer( display(), frameId(), &w, &child, &d1, &d2, &d3, &d4, &d5 ) == False
 
1000
                || child == None )
 
1001
                lostMouse = true; // really lost the mouse
 
1002
            }
 
1003
        if ( lostMouse ) 
 
1004
            {
 
1005
            cancelAutoRaise();
 
1006
            workspace()->cancelDelayFocus();
 
1007
            cancelShadeHover();
 
1008
            if ( shade_mode == ShadeHover && !moveResizeMode && !buttonDown )
 
1009
               setShade( ShadeNormal );
 
1010
            }
 
1011
        if ( options->focusPolicy == Options::FocusStrictlyUnderMouse )
 
1012
            if ( isActive() && lostMouse )
 
1013
                workspace()->requestFocus( 0 ) ;
 
1014
        return;
 
1015
        }
 
1016
    }
 
1017
 
 
1018
#define XCapL KKeyServer::modXLock()
 
1019
#define XNumL KKeyServer::modXNumLock()
 
1020
#define XScrL KKeyServer::modXScrollLock()
 
1021
void Client::grabButton( int modifier )
 
1022
    {
 
1023
    unsigned int mods[ 8 ] = 
 
1024
        {
 
1025
        0, XCapL, XNumL, XNumL | XCapL,
 
1026
        XScrL, XScrL | XCapL,
 
1027
        XScrL | XNumL, XScrL | XNumL | XCapL
 
1028
        };
 
1029
    for( int i = 0;
 
1030
         i < 8;
 
1031
         ++i )
 
1032
        XGrabButton( display(), AnyButton,
 
1033
            modifier | mods[ i ],
 
1034
            wrapperId(), false, ButtonPressMask,
 
1035
            GrabModeSync, GrabModeAsync, None, None );
 
1036
    }
 
1037
 
 
1038
void Client::ungrabButton( int modifier )
 
1039
    {
 
1040
    unsigned int mods[ 8 ] = 
 
1041
        {
 
1042
        0, XCapL, XNumL, XNumL | XCapL,
 
1043
        XScrL, XScrL | XCapL,
 
1044
        XScrL | XNumL, XScrL | XNumL | XCapL
 
1045
        };
 
1046
    for( int i = 0;
 
1047
         i < 8;
 
1048
         ++i )
 
1049
        XUngrabButton( display(), AnyButton,
 
1050
            modifier | mods[ i ], wrapperId());
 
1051
    }
 
1052
#undef XCapL
 
1053
#undef XNumL
 
1054
#undef XScrL
 
1055
 
 
1056
/*
 
1057
  Releases the passive grab for some modifier combinations when a
 
1058
  window becomes active. This helps broken X programs that
 
1059
  missinterpret LeaveNotify events in grab mode to work properly
 
1060
  (Motif, AWT, Tk, ...)
 
1061
 */
 
1062
void Client::updateMouseGrab()
 
1063
    {
 
1064
    if( workspace()->globalShortcutsDisabled())
 
1065
        {
 
1066
        XUngrabButton( display(), AnyButton, AnyModifier, wrapperId());
 
1067
        // keep grab for the simple click without modifiers if needed (see below)
 
1068
        bool not_obscured = workspace()->topClientOnDesktop( workspace()->currentDesktop(), true, false ) == this;
 
1069
        if( !( !options->clickRaise || not_obscured ))
 
1070
            grabButton( None );
 
1071
        return;
 
1072
        }
 
1073
    if( isActive() && !workspace()->forcedGlobalMouseGrab()) // see Workspace::establishTabBoxGrab()
 
1074
        {
 
1075
        // first grab all modifier combinations
 
1076
        XGrabButton( display(), AnyButton, AnyModifier, wrapperId(), false,
 
1077
            ButtonPressMask,
 
1078
            GrabModeSync, GrabModeAsync,
 
1079
            None, None );
 
1080
        // remove the grab for no modifiers only if the window
 
1081
        // is unobscured or if the user doesn't want click raise
 
1082
        // (it is unobscured if it the topmost in the unconstrained stacking order, i.e. it is
 
1083
        // the most recently raised window)
 
1084
        bool not_obscured = workspace()->topClientOnDesktop( workspace()->currentDesktop(), true, false ) == this;
 
1085
        if( !options->clickRaise || not_obscured )
 
1086
            ungrabButton( None );
 
1087
        else
 
1088
            grabButton( None );
 
1089
        ungrabButton( ShiftMask );
 
1090
        ungrabButton( ControlMask );
 
1091
        ungrabButton( ControlMask | ShiftMask );
 
1092
        }
 
1093
    else
 
1094
        {
 
1095
        XUngrabButton( display(), AnyButton, AnyModifier, wrapperId());
 
1096
        // simply grab all modifier combinations
 
1097
        XGrabButton(display(), AnyButton, AnyModifier, wrapperId(), false,
 
1098
            ButtonPressMask,
 
1099
            GrabModeSync, GrabModeAsync,
 
1100
            None, None );
 
1101
        }
 
1102
    }
 
1103
 
 
1104
// Qt propagates mouse events up the widget hierachy, which means events
 
1105
// for the decoration window cannot be (easily) intercepted as X11 events
 
1106
bool Client::eventFilter( QObject* o, QEvent* e )
 
1107
    {
 
1108
    if( decoration == NULL
 
1109
        || o != decoration->widget())
 
1110
        return false;
 
1111
    if( e->type() == QEvent::MouseButtonPress )
 
1112
        {
 
1113
        QMouseEvent* ev = static_cast< QMouseEvent* >( e );
 
1114
        return buttonPressEvent( decorationId(), qtToX11Button( ev->button()), qtToX11State( ev->buttons(), ev->modifiers() ),
 
1115
            ev->x(), ev->y(), ev->globalX(), ev->globalY() );
 
1116
        }
 
1117
    if( e->type() == QEvent::MouseButtonRelease )
 
1118
        {
 
1119
        QMouseEvent* ev = static_cast< QMouseEvent* >( e );
 
1120
        return buttonReleaseEvent( decorationId(), qtToX11Button( ev->button()), qtToX11State( ev->buttons(), ev->modifiers() ),
 
1121
            ev->x(), ev->y(), ev->globalX(), ev->globalY() );
 
1122
        }
 
1123
    if( e->type() == QEvent::MouseMove ) // FRAME i fake z enter/leave?
 
1124
        {
 
1125
        QMouseEvent* ev = static_cast< QMouseEvent* >( e );
 
1126
        return motionNotifyEvent( decorationId(), qtToX11State( ev->buttons(), ev->modifiers() ),
 
1127
            ev->x(), ev->y(), ev->globalX(), ev->globalY() );
 
1128
        }
 
1129
    if( e->type() == QEvent::Wheel )
 
1130
        {
 
1131
        QWheelEvent* ev = static_cast< QWheelEvent* >( e );
 
1132
        bool r = buttonPressEvent( decorationId(), ev->delta() > 0 ? Button4 : Button5, qtToX11State( ev->buttons(), ev->modifiers() ),
 
1133
            ev->x(), ev->y(), ev->globalX(), ev->globalY() );
 
1134
        r = r || buttonReleaseEvent( decorationId(), ev->delta() > 0 ? Button4 : Button5, qtToX11State( ev->buttons(), ev->modifiers() ),
 
1135
            ev->x(), ev->y(), ev->globalX(), ev->globalY() );
 
1136
        return r;
 
1137
        }
 
1138
    if( e->type() == QEvent::Resize )
 
1139
        {
 
1140
        QResizeEvent* ev = static_cast< QResizeEvent* >( e );
 
1141
        // Filter out resize events that inform about size different than frame size.
 
1142
        // This will ensure that decoration->width() etc. and decoration->widget()->width() will be in sync.
 
1143
        // These events only seem to be delayed events from initial resizing before show() was called
 
1144
        // on the decoration widget.
 
1145
        if( ev->size() != size())
 
1146
            return true;
 
1147
        // HACK: Avoid decoration redraw delays. On resize Qt sets WA_WStateConfigPending
 
1148
        // which delays all painting until a matching ConfigureNotify event comes.
 
1149
        // But this process itself is the window manager, so it's not needed
 
1150
        // to wait for that event, the geometry is known.
 
1151
        // Note that if Qt in the future changes how this flag is handled and what it
 
1152
        // triggers then this may potentionally break things. See mainly QETWidget::translateConfigEvent().
 
1153
        decoration->widget()->setAttribute( Qt::WA_WState_ConfigPending, false );
 
1154
        decoration->widget()->update();
 
1155
        return false;
 
1156
        }
 
1157
    return false;
 
1158
    }
 
1159
 
 
1160
// return value matters only when filtering events before decoration gets them
 
1161
bool Client::buttonPressEvent( Window w, int button, int state, int x, int y, int x_root, int y_root )
 
1162
    {
 
1163
    if (buttonDown)
 
1164
        {
 
1165
        if( w == wrapperId())
 
1166
            XAllowEvents(display(), SyncPointer, CurrentTime ); //xTime());
 
1167
        return true;
 
1168
        }
 
1169
 
 
1170
    if( w == wrapperId() || w == frameId() || w == decorationId())
 
1171
        { // FRAME neco s tohohle by se melo zpracovat, nez to dostane dekorace
 
1172
        updateUserTime();
 
1173
        workspace()->setWasUserInteraction();
 
1174
        uint keyModX = (options->keyCmdAllModKey() == Qt::Key_Meta) ?
 
1175
            KKeyServer::modXMeta() :
 
1176
            KKeyServer::modXAlt();
 
1177
        bool bModKeyHeld = keyModX != 0 && ( state & KKeyServer::accelModMaskX()) == keyModX;
 
1178
 
 
1179
        if( isSplash()
 
1180
            && button == Button1 && !bModKeyHeld )
 
1181
            { // hide splashwindow if the user clicks on it
 
1182
            hideClient( true );
 
1183
            if( w == wrapperId())
 
1184
                    XAllowEvents(display(), SyncPointer, CurrentTime ); //xTime());
 
1185
            return true;
 
1186
            }
 
1187
 
 
1188
        Options::MouseCommand com = Options::MouseNothing;
 
1189
        bool was_action = false;
 
1190
        bool perform_handled = false;
 
1191
        if ( bModKeyHeld )
 
1192
            {
 
1193
            was_action = true;
 
1194
            switch (button) 
 
1195
                {
 
1196
                case Button1:
 
1197
                    com = options->commandAll1();
 
1198
                    break;
 
1199
                case Button2:
 
1200
                    com = options->commandAll2();
 
1201
                    break;
 
1202
                case Button3:
 
1203
                    com = options->commandAll3();
 
1204
                    break;
 
1205
                case Button4:
 
1206
                case Button5:
 
1207
                    com = options->operationWindowMouseWheel( button == Button4 ? 120 : -120 );
 
1208
                    break;
 
1209
                }
 
1210
            }
 
1211
        else
 
1212
            { // inactive inner window
 
1213
            if( !isActive() && w == wrapperId())
 
1214
                {
 
1215
                was_action = true;
 
1216
                perform_handled = true;
 
1217
                switch (button) 
 
1218
                    {
 
1219
                    case Button1:
 
1220
                        com = options->commandWindow1();
 
1221
                        break;
 
1222
                    case Button2:
 
1223
                        com = options->commandWindow2();
 
1224
                        break;
 
1225
                    case Button3:
 
1226
                        com = options->commandWindow3();
 
1227
                        break;
 
1228
                    default:
 
1229
                        com = Options::MouseActivateAndPassClick;
 
1230
                    }
 
1231
                }
 
1232
            // active inner window
 
1233
            if( isActive() && w == wrapperId()
 
1234
                && options->clickRaise && button < 4 ) // exclude wheel
 
1235
                {
 
1236
                com = Options::MouseActivateRaiseAndPassClick;
 
1237
                was_action = true;
 
1238
                perform_handled = true;
 
1239
                }
 
1240
            }
 
1241
        if( was_action )
 
1242
            {
 
1243
            bool replay = performMouseCommand( com, QPoint( x_root, y_root), perform_handled );
 
1244
 
 
1245
            if ( isSpecialWindow())
 
1246
                replay = true;
 
1247
 
 
1248
            if( w == wrapperId()) // these can come only from a grab
 
1249
                XAllowEvents(display(), replay? ReplayPointer : SyncPointer, CurrentTime ); //xTime());
 
1250
            return true;
 
1251
            }
 
1252
        }
 
1253
 
 
1254
    if( w == wrapperId()) // these can come only from a grab
 
1255
        {
 
1256
        XAllowEvents(display(), ReplayPointer, CurrentTime ); //xTime());
 
1257
        return true;
 
1258
        }
 
1259
    if( w == decorationId())
 
1260
        return false; // don't eat decoration events
 
1261
    if( w == frameId())
 
1262
        processDecorationButtonPress( button, state, x, y, x_root, y_root );
 
1263
    return true;
 
1264
    }
 
1265
 
 
1266
 
 
1267
// this function processes button press events only after decoration decides not to handle them,
 
1268
// unlike buttonPressEvent(), which (when the window is decoration) filters events before decoration gets them
 
1269
void Client::processDecorationButtonPress( int button, int /*state*/, int x, int y, int x_root, int y_root )
 
1270
    {
 
1271
    Options::MouseCommand com = Options::MouseNothing;
 
1272
    bool active = isActive();
 
1273
    if ( !wantsInput() ) // we cannot be active, use it anyway
 
1274
        active = true;
 
1275
 
 
1276
    if ( button == Button1 )
 
1277
        com = active ? options->commandActiveTitlebar1() : options->commandInactiveTitlebar1();
 
1278
    else if ( button == Button2 )
 
1279
        com = active ? options->commandActiveTitlebar2() : options->commandInactiveTitlebar2();
 
1280
    else if ( button == Button3 )
 
1281
        com = active ? options->commandActiveTitlebar3() : options->commandInactiveTitlebar3();
 
1282
    if( button == Button1
 
1283
        && com != Options::MouseOperationsMenu // actions where it's not possible to get the matching
 
1284
        && com != Options::MouseMinimize )  // mouse release event
 
1285
        {
 
1286
        mode = mousePosition( QPoint( x, y ));
 
1287
        buttonDown = true;
 
1288
        moveOffset = QPoint( x, y );
 
1289
        invertedMoveOffset = rect().bottomRight() - moveOffset;
 
1290
        unrestrictedMoveResize = false;
 
1291
        startDelayedMoveResize();
 
1292
        updateCursor();
 
1293
        }
 
1294
    performMouseCommand( com, QPoint( x_root, y_root ));
 
1295
    }
 
1296
 
 
1297
// called from decoration
 
1298
void Client::processMousePressEvent( QMouseEvent* e )
 
1299
    {
 
1300
    if( e->type() != QEvent::MouseButtonPress )
 
1301
        {
 
1302
        kWarning() << "processMousePressEvent()" ;
 
1303
        return;
 
1304
        }
 
1305
    int button;
 
1306
    switch( e->button())
 
1307
        {
 
1308
        case Qt::LeftButton:
 
1309
            button = Button1;
 
1310
          break;
 
1311
        case Qt::MidButton:
 
1312
            button = Button2;
 
1313
          break;
 
1314
        case Qt::RightButton:
 
1315
            button = Button3;
 
1316
          break;
 
1317
        default:
 
1318
            return;
 
1319
        }
 
1320
    processDecorationButtonPress( button, e->buttons(), e->x(), e->y(), e->globalX(), e->globalY());
 
1321
    }
 
1322
 
 
1323
// return value matters only when filtering events before decoration gets them
 
1324
bool Client::buttonReleaseEvent( Window w, int /*button*/, int state, int x, int y, int x_root, int y_root )
 
1325
    {
 
1326
    if( w == decorationId() && !buttonDown)
 
1327
        return false;
 
1328
    if( w == wrapperId())
 
1329
        {
 
1330
        XAllowEvents(display(), SyncPointer, CurrentTime ); //xTime());
 
1331
        return true;
 
1332
        }
 
1333
    if( w != frameId() && w != decorationId() && w != moveResizeGrabWindow())
 
1334
        return true;
 
1335
    x = this->x(); // translate from grab window to local coords
 
1336
    y = this->y();
 
1337
    if ( (state & ( Button1Mask & Button2Mask & Button3Mask )) == 0 )
 
1338
        {
 
1339
        buttonDown = false;
 
1340
        stopDelayedMoveResize();
 
1341
        if ( moveResizeMode ) 
 
1342
            {
 
1343
            finishMoveResize( false );
 
1344
            // mouse position is still relative to old Client position, adjust it
 
1345
            QPoint mousepos( x_root - x, y_root - y );
 
1346
            mode = mousePosition( mousepos );
 
1347
            }
 
1348
        updateCursor();
 
1349
        }
 
1350
    return true;
 
1351
    }
 
1352
 
 
1353
static bool was_motion = false;
 
1354
static Time next_motion_time = CurrentTime;
 
1355
// Check whole incoming X queue for MotionNotify events
 
1356
// checking whole queue is done by always returning False in the predicate.
 
1357
// If there are more MotionNotify events in the queue, all until the last
 
1358
// one may be safely discarded (if a ButtonRelease event comes, a MotionNotify
 
1359
// will be faked from it, so there's no need to check other events).
 
1360
// This helps avoiding being overloaded by being flooded from many events
 
1361
// from the XServer.
 
1362
static Bool motion_predicate( Display*, XEvent* ev, XPointer )
 
1363
{
 
1364
    if( ev->type == MotionNotify )
 
1365
        {
 
1366
        was_motion = true;
 
1367
        next_motion_time = ev->xmotion.time;  // for setting time
 
1368
        }
 
1369
    return False;
 
1370
}
 
1371
 
 
1372
static bool waitingMotionEvent()
 
1373
    {
 
1374
// The queue doesn't need to be checked until the X timestamp
 
1375
// of processes events reaches the timestamp of the last suitable
 
1376
// MotionNotify event in the queue.
 
1377
    if( next_motion_time != CurrentTime
 
1378
        && timestampCompare( xTime(), next_motion_time ) < 0 )
 
1379
        return true;
 
1380
    was_motion = false;
 
1381
    XSync( display(), False ); // this helps to discard more MotionNotify events
 
1382
    XEvent dummy;
 
1383
    XCheckIfEvent( display(), &dummy, motion_predicate, NULL );
 
1384
    return was_motion;
 
1385
    }
 
1386
 
 
1387
// return value matters only when filtering events before decoration gets them
 
1388
bool Client::motionNotifyEvent( Window w, int /*state*/, int x, int y, int x_root, int y_root )
 
1389
    {
 
1390
    if( w != frameId() && w != decorationId() && w != moveResizeGrabWindow())
 
1391
        return true; // care only about the whole frame
 
1392
    if ( !buttonDown ) 
 
1393
        {
 
1394
        Position newmode = mousePosition( QPoint( x, y ));
 
1395
        if( newmode != mode )
 
1396
            {
 
1397
            mode = newmode;
 
1398
            updateCursor();
 
1399
            }
 
1400
        // reset the timestamp for the optimization, otherwise with long passivity
 
1401
        // the option in waitingMotionEvent() may be always true
 
1402
        next_motion_time = CurrentTime;
 
1403
        return false;
 
1404
        }
 
1405
    if( w == moveResizeGrabWindow())
 
1406
        {
 
1407
        x = this->x(); // translate from grab window to local coords
 
1408
        y = this->y();
 
1409
        }
 
1410
    if( !waitingMotionEvent())
 
1411
        handleMoveResize( x, y, x_root, y_root );
 
1412
    return true;
 
1413
    }
 
1414
    
 
1415
void Client::focusInEvent( XFocusInEvent* e )
 
1416
    {
 
1417
    if( e->window != window())
 
1418
        return; // only window gets focus
 
1419
    if ( e->mode == NotifyUngrab )
 
1420
        return; // we don't care
 
1421
    if ( e->detail == NotifyPointer )
 
1422
        return;  // we don't care
 
1423
    if( !isShown( false ) || !isOnCurrentDesktop()) // we unmapped it, but it got focus meanwhile ->
 
1424
        return;            // activateNextClient() already transferred focus elsewhere
 
1425
    // check if this client is in should_get_focus list or if activation is allowed
 
1426
    bool activate =  workspace()->allowClientActivation( this, -1U, true );
 
1427
    workspace()->gotFocusIn( this ); // remove from should_get_focus list
 
1428
    if( activate )
 
1429
        setActive( true );
 
1430
    else
 
1431
        {
 
1432
        workspace()->restoreFocus();
 
1433
        demandAttention();
 
1434
        }
 
1435
    }
 
1436
 
 
1437
// When a client loses focus, FocusOut events are usually immediatelly
 
1438
// followed by FocusIn events for another client that gains the focus
 
1439
// (unless the focus goes to another screen, or to the nofocus widget).
 
1440
// Without this check, the former focused client would have to be
 
1441
// deactivated, and after that, the new one would be activated, with
 
1442
// a short time when there would be no active client. This can cause
 
1443
// flicker sometimes, e.g. when a fullscreen is shown, and focus is transferred
 
1444
// from it to its transient, the fullscreen would be kept in the Active layer
 
1445
// at the beginning and at the end, but not in the middle, when the active
 
1446
// client would be temporarily none (see Client::belongToLayer() ).
 
1447
// Therefore, the events queue is checked, whether it contains the matching
 
1448
// FocusIn event, and if yes, deactivation of the previous client will
 
1449
// be skipped, as activation of the new one will automatically deactivate
 
1450
// previously active client.
 
1451
static bool follows_focusin = false;
 
1452
static bool follows_focusin_failed = false;
 
1453
static Bool predicate_follows_focusin( Display*, XEvent* e, XPointer arg )
 
1454
    {
 
1455
    if( follows_focusin || follows_focusin_failed )
 
1456
        return False;
 
1457
    Client* c = ( Client* ) arg;
 
1458
    if( e->type == FocusIn && c->workspace()->findClient( WindowMatchPredicate( e->xfocus.window )))
 
1459
        { // found FocusIn
 
1460
        follows_focusin = true;
 
1461
        return False;
 
1462
        }
 
1463
    // events that may be in the queue before the FocusIn event that's being
 
1464
    // searched for
 
1465
    if( e->type == FocusIn || e->type == FocusOut || e->type == KeymapNotify )
 
1466
        return False;
 
1467
    follows_focusin_failed = true; // a different event - stop search
 
1468
    return False;
 
1469
    }
 
1470
 
 
1471
static bool check_follows_focusin( Client* c )
 
1472
    {
 
1473
    follows_focusin = follows_focusin_failed = false;
 
1474
    XEvent dummy;
 
1475
    // XCheckIfEvent() is used to make the search non-blocking, the predicate
 
1476
    // always returns False, so nothing is removed from the events queue.
 
1477
    // XPeekIfEvent() would block.
 
1478
    XCheckIfEvent( display(), &dummy, predicate_follows_focusin, (XPointer)c );
 
1479
    return follows_focusin;
 
1480
    }
 
1481
 
 
1482
 
 
1483
void Client::focusOutEvent( XFocusOutEvent* e )
 
1484
    {
 
1485
    if( e->window != window())
 
1486
        return; // only window gets focus
 
1487
    if ( e->mode == NotifyGrab )
 
1488
        return; // we don't care
 
1489
    if ( isShade() )
 
1490
        return; // here neither
 
1491
    if ( e->detail != NotifyNonlinear
 
1492
        && e->detail != NotifyNonlinearVirtual )
 
1493
        // SELI check all this
 
1494
        return; // hack for motif apps like netscape
 
1495
    if ( QApplication::activePopupWidget() )
 
1496
        return;
 
1497
    if( !check_follows_focusin( this ))
 
1498
        setActive( false );
 
1499
    }
 
1500
 
 
1501
// performs _NET_WM_MOVERESIZE
 
1502
void Client::NETMoveResize( int x_root, int y_root, NET::Direction direction )
 
1503
    {
 
1504
    if( direction == NET::Move )
 
1505
        performMouseCommand( Options::MouseMove, QPoint( x_root, y_root ));
 
1506
    else if( moveResizeMode && direction == NET::MoveResizeCancel)
 
1507
    {
 
1508
        finishMoveResize( true );
 
1509
        buttonDown = false;
 
1510
        updateCursor();
 
1511
    }
 
1512
    else if( direction >= NET::TopLeft && direction <= NET::Left ) 
 
1513
        {
 
1514
        static const Position convert[] =
 
1515
            {
 
1516
            PositionTopLeft,
 
1517
            PositionTop,
 
1518
            PositionTopRight,
 
1519
            PositionRight,
 
1520
            PositionBottomRight,
 
1521
            PositionBottom,
 
1522
            PositionBottomLeft,
 
1523
            PositionLeft
 
1524
            };
 
1525
        if(!isResizable() || isShade())
 
1526
            return;
 
1527
        if( moveResizeMode )
 
1528
            finishMoveResize( false );
 
1529
        buttonDown = true;
 
1530
        moveOffset = QPoint( x_root - x(), y_root - y()); // map from global
 
1531
        invertedMoveOffset = rect().bottomRight() - moveOffset;
 
1532
        unrestrictedMoveResize = false;
 
1533
        mode = convert[ direction ];
 
1534
        if( !startMoveResize())
 
1535
            buttonDown = false;
 
1536
        updateCursor();
 
1537
        }
 
1538
    else if( direction == NET::KeyboardMove )
 
1539
        { // ignore mouse coordinates given in the message, mouse position is used by the moving algorithm
 
1540
        QCursor::setPos( geometry().center() );
 
1541
        performMouseCommand( Options::MouseUnrestrictedMove, geometry().center());
 
1542
        }
 
1543
    else if( direction == NET::KeyboardSize )
 
1544
        { // ignore mouse coordinates given in the message, mouse position is used by the resizing algorithm
 
1545
        QCursor::setPos( geometry().bottomRight());
 
1546
        performMouseCommand( Options::MouseUnrestrictedResize, geometry().bottomRight());
 
1547
        }
 
1548
    }
 
1549
 
 
1550
void Client::keyPressEvent( uint key_code )
 
1551
    {
 
1552
    updateUserTime();
 
1553
    if ( !isMove() && !isResize() )
 
1554
        return;
 
1555
    bool is_control = key_code & Qt::CTRL;
 
1556
    bool is_alt = key_code & Qt::ALT;
 
1557
    key_code = key_code & ~Qt::KeyboardModifierMask;
 
1558
    int delta = is_control?1:is_alt?32:8;
 
1559
    QPoint pos = cursorPos();
 
1560
    switch ( key_code ) 
 
1561
        {
 
1562
    case Qt::Key_Left:
 
1563
            pos.rx() -= delta;
 
1564
            break;
 
1565
    case Qt::Key_Right:
 
1566
            pos.rx() += delta;
 
1567
            break;
 
1568
    case Qt::Key_Up:
 
1569
            pos.ry() -= delta;
 
1570
            break;
 
1571
    case Qt::Key_Down:
 
1572
            pos.ry() += delta;
 
1573
            break;
 
1574
    case Qt::Key_Space:
 
1575
    case Qt::Key_Return:
 
1576
    case Qt::Key_Enter:
 
1577
            finishMoveResize( false );
 
1578
            buttonDown = false;
 
1579
            updateCursor();
 
1580
            break;
 
1581
    case Qt::Key_Escape:
 
1582
            finishMoveResize( true );
 
1583
            buttonDown = false;
 
1584
            updateCursor();
 
1585
            break;
 
1586
        default:
 
1587
            return;
 
1588
        }
 
1589
    QCursor::setPos( pos );
 
1590
    }
 
1591
 
 
1592
#ifdef HAVE_XSYNC
 
1593
void Client::syncEvent( XSyncAlarmNotifyEvent* e )
 
1594
    {
 
1595
    if( e->alarm == sync_alarm && XSyncValueEqual( e->counter_value, sync_counter_value ))
 
1596
        {
 
1597
        ready_for_painting = true;
 
1598
        if( isResize())
 
1599
            {
 
1600
            delete sync_timeout;
 
1601
            sync_timeout = NULL;
 
1602
            if( sync_resize_pending )
 
1603
                performMoveResize();
 
1604
            }
 
1605
        }
 
1606
    }
 
1607
#endif
 
1608
 
 
1609
// ****************************************
 
1610
// Unmanaged
 
1611
// ****************************************
 
1612
 
 
1613
bool Unmanaged::windowEvent( XEvent* e )
 
1614
    {
 
1615
    double old_opacity = opacity();
 
1616
    unsigned long dirty[ 2 ];
 
1617
    info->event( e, dirty, 2 ); // pass through the NET stuff
 
1618
    if( dirty[ NETWinInfo::PROTOCOLS2 ] & NET::WM2Opacity )
 
1619
        {
 
1620
        if( compositing())
 
1621
            {
 
1622
            addRepaintFull();
 
1623
            scene->windowOpacityChanged( this );
 
1624
            if( effects )
 
1625
                static_cast<EffectsHandlerImpl*>(effects)->windowOpacityChanged( effectWindow(), old_opacity );
 
1626
            }
 
1627
        }
 
1628
    switch (e->type) 
 
1629
        {
 
1630
        case UnmapNotify:
 
1631
            unmapNotifyEvent( &e->xunmap );
 
1632
            break;
 
1633
        case MapNotify:
 
1634
            mapNotifyEvent( &e->xmap );
 
1635
            break;
 
1636
        case ConfigureNotify:
 
1637
            configureNotifyEvent( &e->xconfigure );
 
1638
            break;
 
1639
        case PropertyNotify:
 
1640
            propertyNotifyEvent( &e->xproperty );
 
1641
        default:
 
1642
            {
 
1643
            if( e->type == Extensions::shapeNotifyEvent() )
 
1644
                {
 
1645
                detectShape( window());
 
1646
                addDamageFull();
 
1647
                if( scene != NULL )
 
1648
                    scene->windowGeometryShapeChanged( this );
 
1649
                if( effects != NULL )
 
1650
                    static_cast<EffectsHandlerImpl*>(effects)->windowGeometryShapeChanged( effectWindow(), geometry());
 
1651
                }
 
1652
#ifdef HAVE_XDAMAGE
 
1653
            if( e->type == Extensions::damageNotifyEvent())
 
1654
                damageNotifyEvent( reinterpret_cast< XDamageNotifyEvent* >( e ));
 
1655
#endif
 
1656
            break;
 
1657
            }
 
1658
        }
 
1659
    return false; // don't eat events, even our own unmanaged widgets are tracked
 
1660
    }
 
1661
 
 
1662
void Unmanaged::mapNotifyEvent( XMapEvent* )
 
1663
    {
 
1664
    }
 
1665
 
 
1666
void Unmanaged::unmapNotifyEvent( XUnmapEvent* )
 
1667
    {
 
1668
    release();
 
1669
    }
 
1670
 
 
1671
void Unmanaged::configureNotifyEvent( XConfigureEvent* e )
 
1672
    {
 
1673
    if( effects )
 
1674
        static_cast<EffectsHandlerImpl*>(effects)->checkInputWindowStacking(); // keep them on top
 
1675
    QRect newgeom( e->x, e->y, e->width, e->height );
 
1676
    if( newgeom != geom )
 
1677
        {
 
1678
        addWorkspaceRepaint( geometry()); // damage old area
 
1679
        QRect old = geom;
 
1680
        geom = newgeom;
 
1681
        discardWindowPixmap();
 
1682
        if( scene != NULL )
 
1683
            scene->windowGeometryShapeChanged( this );
 
1684
        if( effects != NULL )
 
1685
            static_cast<EffectsHandlerImpl*>(effects)->windowGeometryShapeChanged( effectWindow(), old );
 
1686
        }
 
1687
    workspace()->restackUnmanaged( this, e->above );
 
1688
    }
 
1689
 
 
1690
// ****************************************
 
1691
// Toplevel
 
1692
// ****************************************
 
1693
 
 
1694
void Toplevel::propertyNotifyEvent( XPropertyEvent* e )
 
1695
    {
 
1696
    if( e->window != window())
 
1697
        return; // ignore frame/wrapper
 
1698
    switch ( e->atom ) 
 
1699
        {
 
1700
        default:
 
1701
            if (e->atom == atoms->wm_client_leader )
 
1702
                getWmClientLeader();
 
1703
            else if( e->atom == atoms->wm_window_role )
 
1704
                getWindowRole();
 
1705
            break;
 
1706
        }
 
1707
    }
 
1708
 
 
1709
// ****************************************
 
1710
// Group
 
1711
// ****************************************
 
1712
 
 
1713
bool Group::groupEvent( XEvent* e )
 
1714
    {
 
1715
    unsigned long dirty[ 2 ];
 
1716
    leader_info->event( e, dirty, 2 ); // pass through the NET stuff
 
1717
    if ( ( dirty[ WinInfo::PROTOCOLS ] & NET::WMIcon) != 0 )
 
1718
        getIcons();
 
1719
    if(( dirty[ WinInfo::PROTOCOLS2 ] & NET::WM2StartupId ) != 0 )
 
1720
        startupIdChanged();
 
1721
    return false;
 
1722
    }
 
1723
 
 
1724
 
 
1725
} // namespace