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

« back to all changes in this revision

Viewing changes to kwin/manage.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 "client.h"
 
19
 
 
20
#include <kstartupinfo.h>
 
21
#include <kglobal.h>
 
22
#include <X11/extensions/shape.h>
 
23
 
 
24
#include "notifications.h"
 
25
#include <QX11Info>
 
26
#include "rules.h"
 
27
#include "group.h"
 
28
 
 
29
namespace KWin
 
30
{
 
31
 
 
32
/*!
 
33
  Manages the clients. This means handling the very first maprequest:
 
34
  reparenting, initial geometry, initial state, placement, etc.
 
35
  Returns false if KWin is not going to manage this window.
 
36
 */
 
37
bool Client::manage( Window w, bool isMapped )
 
38
    {
 
39
    StackingUpdatesBlocker stacking_blocker( workspace());
 
40
 
 
41
    grabXServer();
 
42
 
 
43
    XWindowAttributes attr;
 
44
    if( !XGetWindowAttributes(display(), w, &attr))
 
45
        {
 
46
        ungrabXServer();
 
47
        return false;
 
48
        }
 
49
 
 
50
    // from this place on, manage() mustn't return false
 
51
    block_geometry_updates = 1;
 
52
    pending_geometry_update = PendingGeometryForced; // force update when finishing with geometry changes
 
53
 
 
54
    embedClient( w, attr );
 
55
    
 
56
    vis = attr.visual;
 
57
    bit_depth = attr.depth;
 
58
 
 
59
    setupCompositing();
 
60
 
 
61
    // SELI order all these things in some sane manner
 
62
 
 
63
    bool init_minimize = false;
 
64
    XWMHints * hints = XGetWMHints(display(), w );
 
65
    if (hints && (hints->flags & StateHint) && hints->initial_state == IconicState)
 
66
        init_minimize = true;
 
67
    if (hints)
 
68
        XFree(hints);
 
69
    if( isMapped )
 
70
        init_minimize = false; // if it's already mapped, ignore hint
 
71
 
 
72
    unsigned long properties[ 2 ];
 
73
    properties[ WinInfo::PROTOCOLS ] =
 
74
        NET::WMDesktop |
 
75
        NET::WMState |
 
76
        NET::WMWindowType |
 
77
        NET::WMStrut |
 
78
        NET::WMName |
 
79
        NET::WMIconGeometry |
 
80
        NET::WMIcon |
 
81
        NET::WMPid |
 
82
        NET::WMIconName |
 
83
        0;
 
84
    properties[ WinInfo::PROTOCOLS2 ] =
 
85
        NET::WM2UserTime |
 
86
        NET::WM2StartupId |
 
87
        NET::WM2ExtendedStrut |
 
88
        NET::WM2Opacity |
 
89
        0;
 
90
 
 
91
    info = new WinInfo( this, display(), client, rootWindow(), properties, 2 );
 
92
 
 
93
    cmap = attr.colormap;
 
94
 
 
95
    getResourceClass();
 
96
    getWindowRole();
 
97
    getWmClientLeader();
 
98
    getWmClientMachine();
 
99
    getSyncCounter();
 
100
    // first only read the caption text, so that setupWindowRules() can use it for matching,
 
101
    // and only then really set the caption using setCaption(), which checks for duplicates etc.
 
102
    // and also relies on rules already existing
 
103
    cap_normal = readName();
 
104
    setupWindowRules( false );
 
105
    ignore_focus_stealing = options->checkIgnoreFocusStealing( this ); // TODO change to rules
 
106
    setCaption( cap_normal, true );
 
107
 
 
108
    if( Extensions::shapeAvailable())
 
109
        XShapeSelectInput( display(), window(), ShapeNotifyMask );
 
110
    detectShape( window());
 
111
    detectNoBorder();
 
112
    fetchIconicName();
 
113
    getWMHints(); // needs to be done before readTransient() because of reading the group
 
114
    modal = ( info->state() & NET::Modal ) != 0; // needs to be valid before handling groups
 
115
    readTransient();
 
116
    getIcons();
 
117
    getWindowProtocols();
 
118
    getWmNormalHints(); // get xSizeHint
 
119
    getMotifHints();
 
120
 
 
121
    // TODO try to obey all state information from info->state()
 
122
 
 
123
    original_skip_taskbar = skip_taskbar = ( info->state() & NET::SkipTaskbar) != 0;
 
124
    skip_pager = ( info->state() & NET::SkipPager) != 0;
 
125
 
 
126
    KStartupInfoId asn_id;
 
127
    KStartupInfoData asn_data;
 
128
    bool asn_valid = workspace()->checkStartupNotification( window(), asn_id, asn_data );
 
129
 
 
130
    workspace()->updateClientLayer( this );
 
131
 
 
132
    SessionInfo* session = workspace()->takeSessionInfo( this );
 
133
    
 
134
    if ( session )
 
135
        {
 
136
        if ( session->minimized )
 
137
            init_minimize = true;
 
138
        if( session->userNoBorder )
 
139
            setUserNoBorder( true );
 
140
        }
 
141
 
 
142
    setShortcut( rules()->checkShortcut( session ? session->shortcut : QString(), true ));
 
143
 
 
144
    init_minimize = rules()->checkMinimize( init_minimize, !isMapped );
 
145
    if( rules()->checkNoBorder( false, !isMapped ))
 
146
        setUserNoBorder( true );
 
147
    
 
148
    // initial desktop placement
 
149
    if ( session ) 
 
150
        {
 
151
        desk = session->desktop;
 
152
        if( session->onAllDesktops )
 
153
            desk = NET::OnAllDesktops;
 
154
        }
 
155
    else
 
156
        {
 
157
        // if this window is transient, ensure that it is opened on the
 
158
        // same window as its parent.  this is necessary when an application
 
159
        // starts up on a different desktop than is currently displayed
 
160
        if( isTransient())
 
161
            {
 
162
            ClientList mainclients = mainClients();
 
163
            bool on_current = false;
 
164
            Client* maincl = NULL;
 
165
            // this is slightly duplicated from Placement::placeOnMainWindow()
 
166
            for( ClientList::ConstIterator it = mainclients.begin();
 
167
                 it != mainclients.end();
 
168
                 ++it )
 
169
                {
 
170
                if( mainclients.count() > 1 && (*it)->isSpecialWindow())
 
171
                    continue; // don't consider toolbars etc when placing
 
172
                maincl = *it;
 
173
                if( (*it)->isOnCurrentDesktop())
 
174
                    on_current = true;
 
175
                }
 
176
            if( on_current )
 
177
                desk = workspace()->currentDesktop();
 
178
            else if( maincl != NULL )
 
179
                desk = maincl->desktop();
 
180
            }
 
181
        if ( info->desktop() )
 
182
            desk = info->desktop(); // window had the initial desktop property, force it
 
183
        if( desktop() == 0 && asn_valid && asn_data.desktop() != 0 )
 
184
            desk = asn_data.desktop();
 
185
        }
 
186
    if ( desk == 0 ) // assume window wants to be visible on the current desktop
 
187
        desk = workspace()->currentDesktop();
 
188
    desk = rules()->checkDesktop( desk, !isMapped );
 
189
    if( desk != NET::OnAllDesktops ) // do range check
 
190
        desk = qMax( 1, qMin( workspace()->numberOfDesktops(), desk ));
 
191
    info->setDesktop( desk );
 
192
    workspace()->updateOnAllDesktopsOfTransients( this ); // SELI
 
193
//    onAllDesktopsChange(); decoration doesn't exist here yet
 
194
 
 
195
    QRect geom( attr.x, attr.y, attr.width, attr.height );
 
196
    bool placementDone = false;
 
197
 
 
198
    if ( session )
 
199
        geom = session->geometry;
 
200
 
 
201
    QRect area;
 
202
    bool partial_keep_in_area = isMapped || session;
 
203
    if( isMapped || session )
 
204
        area = workspace()->clientArea( FullArea, geom.center(), desktop());
 
205
    else if( options->xineramaPlacementEnabled )
 
206
        {
 
207
        int screen = options->xineramaPlacementScreen;
 
208
        if( screen == -1 ) // active screen
 
209
            screen = asn_data.xinerama() == -1 ? workspace()->activeScreen() : asn_data.xinerama();
 
210
        area = workspace()->clientArea( PlacementArea, workspace()->screenGeometry( screen ).center(), desktop());
 
211
        }
 
212
    else
 
213
        area = workspace()->clientArea( PlacementArea, cursorPos(), desktop());
 
214
 
 
215
    if( int type = checkFullScreenHack( geom ))
 
216
        {
 
217
        fullscreen_mode = FullScreenHack;
 
218
        if( rules()->checkStrictGeometry( false ))
 
219
            {
 
220
            geom = type == 2 // 1 - it's xinerama-aware fullscreen hack, 2 - it's full area
 
221
                ? workspace()->clientArea( FullArea, geom.center(), desktop())
 
222
                : workspace()->clientArea( ScreenArea, geom.center(), desktop());
 
223
            }
 
224
        else
 
225
            geom = workspace()->clientArea( FullScreenArea, geom.center(), desktop());
 
226
        placementDone = true;
 
227
        }
 
228
 
 
229
    if ( isDesktop() ) 
 
230
        {
 
231
        // desktops are treated slightly special
 
232
        geom = workspace()->clientArea( FullArea, geom.center(), desktop());
 
233
        placementDone = true;
 
234
        }
 
235
 
 
236
    bool usePosition = false;
 
237
    if ( isMapped || session || placementDone )
 
238
        placementDone = true; // use geometry
 
239
    else if( isTransient() && !isUtility() && !isDialog() && !isSplash())
 
240
        usePosition = true;
 
241
    else if( isTransient() && !hasNETSupport())
 
242
        usePosition = true;
 
243
    else if( isDialog() && hasNETSupport())
 
244
    // if the dialog is actually non-NETWM transient window, don't try to apply placement to it,
 
245
    // it breaks with too many things (xmms, display)
 
246
        {
 
247
        if( mainClients().count() >= 1 )
 
248
            {
 
249
#if 1
 
250
            // #78082 - Ok, it seems there are after all some cases when an application has a good
 
251
            // reason to specify a position for its dialog. Too bad other WMs have never bothered
 
252
            // with placement for dialogs, so apps always specify positions for their dialogs,
 
253
            // including such silly positions like always centered on the screen or under mouse.
 
254
            // Using ignoring requested position in window-specific settings helps, and now
 
255
            // there's also _NET_WM_FULL_PLACEMENT.
 
256
            usePosition = true;
 
257
#else
 
258
            ; // force using placement policy
 
259
#endif
 
260
            }
 
261
        else
 
262
            usePosition = true;
 
263
        }
 
264
    else if( isSplash())
 
265
        ; // force using placement policy
 
266
    else
 
267
        usePosition = true;
 
268
    if( !rules()->checkIgnoreGeometry( !usePosition ))
 
269
        {
 
270
        bool ignorePPosition = ( options->ignorePositionClasses.contains(QString::fromLatin1(resourceClass())));
 
271
 
 
272
        if ( ( (xSizeHint.flags & PPosition) && !ignorePPosition ) ||
 
273
             (xSizeHint.flags & USPosition) ) 
 
274
            {
 
275
            placementDone = true;
 
276
            // disobey xinerama placement option for now (#70943)
 
277
            area = workspace()->clientArea( PlacementArea, geom.center(), desktop());
 
278
            }
 
279
        }
 
280
    if( true ) // size is always obeyed for now, only with constraints applied
 
281
        if ( (xSizeHint.flags & USSize) || (xSizeHint.flags & PSize) ) 
 
282
            {
 
283
            // keep in mind that we now actually have a size :-)
 
284
            }
 
285
 
 
286
    if (xSizeHint.flags & PMaxSize)
 
287
        geom.setSize( geom.size().boundedTo(
 
288
            rules()->checkMaxSize( QSize(xSizeHint.max_width, xSizeHint.max_height ) ) ) );
 
289
    if (xSizeHint.flags & PMinSize)
 
290
        geom.setSize( geom.size().expandedTo(
 
291
            rules()->checkMinSize( QSize(xSizeHint.min_width, xSizeHint.min_height ) ) ) );
 
292
 
 
293
    if( isMovable())
 
294
        {
 
295
        if( geom.x() > area.right() || geom.y() > area.bottom())
 
296
            placementDone = false; // weird, do not trust.
 
297
        }
 
298
 
 
299
    if ( placementDone )
 
300
        move( geom.x(), geom.y() ); // before gravitating
 
301
 
 
302
    updateDecoration( false ); // also gravitates
 
303
    // TODO is CentralGravity right here, when resizing is done after gravitating?
 
304
    plainResize( rules()->checkSize( sizeForClientSize( geom.size()), !isMapped ));
 
305
 
 
306
    QPoint forced_pos = rules()->checkPosition( invalidPoint, !isMapped );
 
307
    if( forced_pos != invalidPoint )
 
308
        {
 
309
        move( forced_pos );
 
310
        placementDone = true;
 
311
        // don't keep inside workarea if the window has specially configured position
 
312
        partial_keep_in_area = true;
 
313
        area = workspace()->clientArea( FullArea, geom.center(), desktop());
 
314
        }
 
315
    if( !placementDone ) 
 
316
        { // placement needs to be after setting size
 
317
        workspace()->place( this, area );
 
318
        placementDone = true;
 
319
        }
 
320
 
 
321
    if(( !isSpecialWindow() || isToolbar()) && isMovable())
 
322
        keepInArea( area, partial_keep_in_area );
 
323
 
 
324
    if( shape()) 
 
325
        updateShape();
 
326
        
 
327
    //CT extra check for stupid jdk 1.3.1. But should make sense in general
 
328
    // if client has initial state set to Iconic and is transient with a parent
 
329
    // window that is not Iconic, set init_state to Normal
 
330
    if( init_minimize && isTransient())
 
331
        {
 
332
        ClientList mainclients = mainClients();
 
333
        for( ClientList::ConstIterator it = mainclients.begin();
 
334
             it != mainclients.end();
 
335
             ++it )
 
336
            if( (*it)->isShown( true ))
 
337
                init_minimize = false; // SELI even e.g. for NET::Utility?
 
338
        }
 
339
 
 
340
    if( init_minimize )
 
341
        minimize( true ); // no animation
 
342
 
 
343
    // SELI this seems to be mainly for kstart and ksystraycmd
 
344
    // probably should be replaced by something better
 
345
    bool doNotShow = false;
 
346
    if ( workspace()->isNotManaged( caption() ) )
 
347
        doNotShow = true;
 
348
 
 
349
    // other settings from the previous session
 
350
    if ( session ) 
 
351
        {
 
352
        // session restored windows are not considered to be new windows WRT rules,
 
353
        // i.e. obey only forcing rules
 
354
        setKeepAbove( session->keepAbove );
 
355
        setKeepBelow( session->keepBelow );
 
356
        setSkipTaskbar( session->skipTaskbar, true );
 
357
        setSkipPager( session->skipPager );
 
358
        setShade( session->shaded ? ShadeNormal : ShadeNone );
 
359
        if( session->maximized != MaximizeRestore )
 
360
            {
 
361
            maximize( (MaximizeMode) session->maximized );
 
362
            geom_restore = session->restore;
 
363
            }
 
364
        if( session->fullscreen == FullScreenHack )
 
365
            ; // nothing, this should be already set again above
 
366
        else if( session->fullscreen != FullScreenNone )
 
367
            {
 
368
            setFullScreen( true, false );
 
369
            geom_fs_restore = session->fsrestore;
 
370
            }
 
371
        }
 
372
    else 
 
373
        {
 
374
        geom_restore = geometry(); // remember restore geometry
 
375
        if ( isMaximizable()
 
376
             && ( width() >= area.width() || height() >= area.height() ) ) 
 
377
            {
 
378
            // window is too large for the screen, maximize in the
 
379
            // directions necessary
 
380
            if ( width() >= area.width() && height() >= area.height() ) 
 
381
                {
 
382
                maximize( Client::MaximizeFull );
 
383
                geom_restore = QRect(); // use placement when unmaximizing
 
384
                }
 
385
            else if ( width() >= area.width() ) 
 
386
                {
 
387
                maximize( Client::MaximizeHorizontal );
 
388
                geom_restore = QRect(); // use placement when unmaximizing
 
389
                geom_restore.setY( y()); // but only for horizontal direction
 
390
                geom_restore.setHeight( height());
 
391
                }
 
392
            else if ( height() >= area.height() ) 
 
393
                {
 
394
                maximize( Client::MaximizeVertical );
 
395
                geom_restore = QRect(); // use placement when unmaximizing
 
396
                geom_restore.setX( x()); // but only for vertical direction
 
397
                geom_restore.setWidth( width());
 
398
                }
 
399
            }
 
400
        // window may want to be maximized
 
401
        // done after checking that the window isn't larger than the workarea, so that
 
402
        // the restore geometry from the checks above takes precedence, and window
 
403
        // isn't restored larger than the workarea
 
404
        MaximizeMode maxmode = static_cast< MaximizeMode >
 
405
            ((( info->state() & NET::MaxVert ) ? MaximizeVertical : 0 )
 
406
            | (( info->state() & NET::MaxHoriz ) ? MaximizeHorizontal : 0 ));
 
407
        MaximizeMode forced_maxmode = rules()->checkMaximize( maxmode, !isMapped );
 
408
        // either hints were set to maximize, or is forced to maximize,
 
409
        // or is forced to non-maximize and hints were set to maximize
 
410
        if( forced_maxmode != MaximizeRestore || maxmode != MaximizeRestore )
 
411
            maximize( forced_maxmode );
 
412
 
 
413
        // read other initial states
 
414
        setShade( rules()->checkShade( info->state() & NET::Shaded ? ShadeNormal : ShadeNone, !isMapped ));
 
415
        setKeepAbove( rules()->checkKeepAbove( info->state() & NET::KeepAbove, !isMapped ));
 
416
        setKeepBelow( rules()->checkKeepBelow( info->state() & NET::KeepBelow, !isMapped ));
 
417
        setSkipTaskbar( rules()->checkSkipTaskbar( info->state() & NET::SkipTaskbar, !isMapped ), true );
 
418
        setSkipPager( rules()->checkSkipPager( info->state() & NET::SkipPager, !isMapped ));
 
419
        if( info->state() & NET::DemandsAttention )
 
420
            demandAttention();
 
421
        if( info->state() & NET::Modal )
 
422
            setModal( true );
 
423
        if( fullscreen_mode != FullScreenHack && isFullScreenable())
 
424
            setFullScreen( rules()->checkFullScreen( info->state() & NET::FullScreen, !isMapped ), false );
 
425
        }
 
426
 
 
427
    updateAllowedActions( true );
 
428
 
 
429
    // set initial user time directly
 
430
    user_time = readUserTimeMapTimestamp( asn_valid ? &asn_id : NULL, asn_valid ? &asn_data : NULL, session );
 
431
    group()->updateUserTime( user_time ); // and do what Client::updateUserTime() does
 
432
 
 
433
    if( isTopMenu()) // they're shown in Workspace::addClient() if their mainwindow
 
434
        hideClient( true ); // is the active one
 
435
 
 
436
    // this should avoid flicker, because real restacking is done
 
437
    // only after manage() finishes because of blocking, but the window is shown sooner
 
438
    XLowerWindow( display(), frameId());
 
439
    if( session && session->stackingOrder != -1 )
 
440
        {
 
441
        sm_stacking_order = session->stackingOrder;
 
442
        workspace()->restoreSessionStackingOrder( this );
 
443
        }
 
444
 
 
445
    if( compositing())     // sending ConfigureNotify is done when setting mapping state below,
 
446
        sendSyncRequest(); // getting the first sync response means window is ready for compositing
 
447
 
 
448
    if( isShown( true ) && !doNotShow )
 
449
        {
 
450
        if( isDialog())
 
451
            Notify::raise( Notify::TransNew );
 
452
        if( isNormalWindow())
 
453
            Notify::raise( Notify::New );
 
454
 
 
455
        bool allow;
 
456
        if( session )
 
457
            allow = session->active
 
458
                && ( !workspace()->wasUserInteraction()
 
459
                    || workspace()->activeClient() == NULL || workspace()->activeClient()->isDesktop());
 
460
        else
 
461
            allow = workspace()->allowClientActivation( this, userTime(), false );
 
462
 
 
463
        // if session saving, force showing new windows (i.e. "save file?" dialogs etc.)
 
464
        // also force if activation is allowed
 
465
        if( !isOnCurrentDesktop() && !isMapped && !session && ( allow || workspace()->sessionSaving()))
 
466
            workspace()->setCurrentDesktop( desktop());
 
467
 
 
468
        bool belongs_to_desktop = false;
 
469
        for( ClientList::ConstIterator it = group()->members().begin();
 
470
             it != group()->members().end();
 
471
             ++it )
 
472
            if( (*it)->isDesktop())
 
473
                {
 
474
                belongs_to_desktop = true;
 
475
                break;
 
476
                }
 
477
        if( !belongs_to_desktop && workspace()->showingDesktop())
 
478
            workspace()->resetShowingDesktop( options->showDesktopIsMinimizeAll );
 
479
 
 
480
        if( isOnCurrentDesktop() && !isMapped && !allow && (!session || session->stackingOrder < 0 ))
 
481
            workspace()->restackClientUnderActive( this );
 
482
 
 
483
        updateVisibility();
 
484
 
 
485
        if( !isMapped )
 
486
            {
 
487
            if( allow && isOnCurrentDesktop())
 
488
                {
 
489
                if( !isSpecialWindow())
 
490
                    if ( options->focusPolicyIsReasonable() && wantsTabFocus() )
 
491
                        workspace()->requestFocus( this );
 
492
                }
 
493
            else
 
494
                {
 
495
                if( !session && !isSpecialWindow())
 
496
                        demandAttention();
 
497
                }
 
498
            }
 
499
        }
 
500
    else if( !doNotShow ) // if( !isShown( true ) && !doNotShow )
 
501
        {
 
502
        updateVisibility();
 
503
        }
 
504
    else // doNotShow
 
505
        { // SELI HACK !!!
 
506
        hideClient( true );
 
507
        setMappingState( IconicState );
 
508
        }
 
509
    assert( mappingState() != WithdrawnState );
 
510
 
 
511
    if( user_time == CurrentTime || user_time == -1U ) // no known user time, set something old
 
512
        {
 
513
        user_time = xTime() - 1000000;
 
514
        if( user_time == CurrentTime || user_time == -1U ) // let's be paranoid
 
515
            user_time = xTime() - 1000000 + 10;
 
516
        }
 
517
 
 
518
    updateWorkareaDiffs();
 
519
 
 
520
//    sendSyntheticConfigureNotify(); done when setting mapping state
 
521
 
 
522
    delete session;
 
523
    
 
524
    ungrabXServer();
 
525
    
 
526
    client_rules.discardTemporary();
 
527
    applyWindowRules(); // just in case
 
528
    workspace()->discardUsedWindowRules( this, false ); // remove ApplyNow rules
 
529
    updateWindowRules(); // was blocked while !isManaged()
 
530
 
 
531
// TODO there's a small problem here - isManaged() depends on the mapping state,
 
532
// but this client is not yet in Workspace's client list at this point, will
 
533
// be only done in addClient()
 
534
    return true;
 
535
    }
 
536
 
 
537
// called only from manage()
 
538
void Client::embedClient( Window w, const XWindowAttributes &attr )
 
539
    {
 
540
    assert( client == None );
 
541
    assert( frameId() == None );
 
542
    assert( wrapper == None );
 
543
    client = w;
 
544
    // we don't want the window to be destroyed when we are destroyed
 
545
    XAddToSaveSet( display(), client );
 
546
    XSelectInput( display(), client, NoEventMask );
 
547
    XUnmapWindow( display(), client );
 
548
    XWindowChanges wc;     // set the border width to 0
 
549
    wc.border_width = 0; // TODO possibly save this, and also use it for initial configuring of the window
 
550
    XConfigureWindow( display(), client, CWBorderWidth, &wc );
 
551
 
 
552
    XSetWindowAttributes swa;
 
553
    swa.colormap = attr.colormap;
 
554
    swa.background_pixmap = None;
 
555
    swa.border_pixel = 0;
 
556
 
 
557
    Window frame = XCreateWindow( display(), rootWindow(), 0, 0, 1, 1, 0,
 
558
                    attr.depth, InputOutput, attr.visual,
 
559
                    CWColormap | CWBackPixmap | CWBorderPixel, &swa );
 
560
    setWindowHandles( client, frame );
 
561
    wrapper = XCreateWindow( display(), frame, 0, 0, 1, 1, 0,
 
562
                    attr.depth, InputOutput, attr.visual,
 
563
                    CWColormap | CWBackPixmap | CWBorderPixel, &swa );
 
564
 
 
565
    XDefineCursor( display(), frame, QCursor( Qt::ArrowCursor ).handle());
 
566
    // some apps are stupid and don't define their own cursor - set the arrow one for them
 
567
    XDefineCursor( display(), wrapper, QCursor( Qt::ArrowCursor ).handle());
 
568
    XReparentWindow( display(), client, wrapper, 0, 0 );
 
569
    XSelectInput( display(), frame,
 
570
            KeyPressMask | KeyReleaseMask |
 
571
            ButtonPressMask | ButtonReleaseMask |
 
572
            KeymapStateMask |
 
573
            ButtonMotionMask |
 
574
            PointerMotionMask |
 
575
            EnterWindowMask | LeaveWindowMask |
 
576
            FocusChangeMask |
 
577
            ExposureMask |
 
578
            PropertyChangeMask |
 
579
            StructureNotifyMask | SubstructureRedirectMask );
 
580
    XSelectInput( display(), wrapper, ClientWinMask | SubstructureNotifyMask );
 
581
    XSelectInput( display(), client,
 
582
                  FocusChangeMask |
 
583
                  PropertyChangeMask |
 
584
                  ColormapChangeMask |
 
585
                  EnterWindowMask | LeaveWindowMask |
 
586
                  KeyPressMask | KeyReleaseMask
 
587
                  );
 
588
    updateMouseGrab();
 
589
    }
 
590
 
 
591
} // namespace