~ubuntu-branches/ubuntu/utopic/kde-workspace/utopic-proposed

« back to all changes in this revision

Viewing changes to kwin/manage.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Michał Zając
  • Date: 2011-07-09 08:31:15 UTC
  • Revision ID: james.westby@ubuntu.com-20110709083115-ohyxn6z93mily9fc
Tags: upstream-4.6.90
Import upstream version 4.6.90

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
This program is free software; you can redistribute it and/or modify
 
9
it under the terms of the GNU General Public License as published by
 
10
the Free Software Foundation; either version 2 of the License, or
 
11
(at your option) any later version.
 
12
 
 
13
This program is distributed in the hope that it will be useful,
 
14
but WITHOUT ANY WARRANTY; without even the implied warranty of
 
15
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
16
GNU General Public License for more details.
 
17
 
 
18
You should have received a copy of the GNU General Public License
 
19
along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
20
*********************************************************************/
 
21
 
 
22
// This file contains things relevant to handling incoming events.
 
23
 
 
24
#include "client.h"
 
25
 
 
26
#include <kstartupinfo.h>
 
27
#include <kglobal.h>
 
28
#include <X11/extensions/shape.h>
 
29
 
 
30
#include "notifications.h"
 
31
#include <QX11Info>
 
32
#include "rules.h"
 
33
#include "group.h"
 
34
 
 
35
#include "scripting/workspaceproxy.h"
 
36
 
 
37
namespace KWin
 
38
{
 
39
 
 
40
/**
 
41
 * Manages the clients. This means handling the very first maprequest:
 
42
 * reparenting, initial geometry, initial state, placement, etc.
 
43
 * Returns false if KWin is not going to manage this window.
 
44
 */
 
45
bool Client::manage(Window w, bool isMapped)
 
46
{
 
47
    StackingUpdatesBlocker stacking_blocker(workspace());
 
48
 
 
49
    //Scripting call. Does not use a signal/slot mechanism
 
50
    //as ensuring connections was a bit difficult between
 
51
    //so many clients and the workspace
 
52
    SWrapper::WorkspaceProxy* ws_wrap = SWrapper::WorkspaceProxy::instance();
 
53
    if (ws_wrap != 0) {
 
54
        ws_wrap->sl_clientManaging(this);
 
55
    }
 
56
 
 
57
    grabXServer();
 
58
 
 
59
    XWindowAttributes attr;
 
60
    if (!XGetWindowAttributes(display(), w, &attr)) {
 
61
        ungrabXServer();
 
62
        return false;
 
63
    }
 
64
 
 
65
    // From this place on, manage() must not return false
 
66
    block_geometry_updates = 1;
 
67
    pending_geometry_update = PendingGeometryForced; // Force update when finishing with geometry changes
 
68
 
 
69
    embedClient(w, attr);
 
70
 
 
71
    vis = attr.visual;
 
72
    bit_depth = attr.depth;
 
73
 
 
74
    // SELI TODO: Order all these things in some sane manner
 
75
 
 
76
    bool init_minimize = false;
 
77
    XWMHints* hints = XGetWMHints(display(), w);
 
78
    if (hints && (hints->flags & StateHint) && hints->initial_state == IconicState)
 
79
        init_minimize = true;
 
80
    if (hints)
 
81
        XFree(hints);
 
82
    if (isMapped)
 
83
        init_minimize = false; // If it's already mapped, ignore hint
 
84
 
 
85
    unsigned long properties[2];
 
86
    properties[WinInfo::PROTOCOLS] =
 
87
        NET::WMDesktop |
 
88
        NET::WMState |
 
89
        NET::WMWindowType |
 
90
        NET::WMStrut |
 
91
        NET::WMName |
 
92
        NET::WMIconGeometry |
 
93
        NET::WMIcon |
 
94
        NET::WMPid |
 
95
        NET::WMIconName |
 
96
        0;
 
97
    properties[WinInfo::PROTOCOLS2] =
 
98
        NET::WM2UserTime |
 
99
        NET::WM2StartupId |
 
100
        NET::WM2ExtendedStrut |
 
101
        NET::WM2Opacity |
 
102
        NET::WM2FullscreenMonitors |
 
103
        NET::WM2FrameOverlap |
 
104
        0;
 
105
 
 
106
    info = new WinInfo(this, display(), client, rootWindow(), properties, 2);
 
107
 
 
108
    cmap = attr.colormap;
 
109
 
 
110
    getResourceClass();
 
111
    getWindowRole();
 
112
    getWmClientLeader();
 
113
    getWmClientMachine();
 
114
    getSyncCounter();
 
115
    // First only read the caption text, so that setupWindowRules() can use it for matching,
 
116
    // and only then really set the caption using setCaption(), which checks for duplicates etc.
 
117
    // and also relies on rules already existing
 
118
    cap_normal = readName();
 
119
    setupWindowRules(false);
 
120
    ignore_focus_stealing = options->checkIgnoreFocusStealing(this);   // TODO: Change to rules
 
121
    setCaption(cap_normal, true);
 
122
 
 
123
    if (Extensions::shapeAvailable())
 
124
        XShapeSelectInput(display(), window(), ShapeNotifyMask);
 
125
    detectShape(window());
 
126
    detectNoBorder();
 
127
    fetchIconicName();
 
128
    getWMHints(); // Needs to be done before readTransient() because of reading the group
 
129
    modal = (info->state() & NET::Modal) != 0;   // Needs to be valid before handling groups
 
130
    readTransient();
 
131
    getIcons();
 
132
    getWindowProtocols();
 
133
    getWmNormalHints(); // Get xSizeHint
 
134
    getMotifHints();
 
135
 
 
136
    // TODO: Try to obey all state information from info->state()
 
137
 
 
138
    original_skip_taskbar = skip_taskbar = (info->state() & NET::SkipTaskbar) != 0;
 
139
    skip_pager = (info->state() & NET::SkipPager) != 0;
 
140
 
 
141
    setupCompositing();
 
142
 
 
143
    KStartupInfoId asn_id;
 
144
    KStartupInfoData asn_data;
 
145
    bool asn_valid = workspace()->checkStartupNotification(window(), asn_id, asn_data);
 
146
 
 
147
    workspace()->updateClientLayer(this);
 
148
 
 
149
    SessionInfo* session = workspace()->takeSessionInfo(this);
 
150
    if (session) {
 
151
        init_minimize = session->minimized;
 
152
        noborder = session->noBorder;
 
153
    }
 
154
 
 
155
    setShortcut(rules()->checkShortcut(session ? session->shortcut : QString(), true));
 
156
 
 
157
    init_minimize = rules()->checkMinimize(init_minimize, !isMapped);
 
158
    noborder = rules()->checkNoBorder(noborder, !isMapped);
 
159
 
 
160
    checkActivities();
 
161
 
 
162
    // Initial desktop placement
 
163
    if (session) {
 
164
        desk = session->desktop;
 
165
        if (session->onAllDesktops)
 
166
            desk = NET::OnAllDesktops;
 
167
        setOnActivities(session->activities);
 
168
    } else {
 
169
        // If this window is transient, ensure that it is opened on the
 
170
        // same window as its parent.  this is necessary when an application
 
171
        // starts up on a different desktop than is currently displayed
 
172
        if (isTransient()) {
 
173
            ClientList mainclients = mainClients();
 
174
            bool on_current = false;
 
175
            bool on_all = false;
 
176
            Client* maincl = NULL;
 
177
            // This is slightly duplicated from Placement::placeOnMainWindow()
 
178
            for (ClientList::ConstIterator it = mainclients.constBegin();
 
179
                    it != mainclients.constEnd();
 
180
                    ++it) {
 
181
                if (mainclients.count() > 1 && (*it)->isSpecialWindow())
 
182
                    continue; // Don't consider toolbars etc when placing
 
183
                maincl = *it;
 
184
                if ((*it)->isOnCurrentDesktop())
 
185
                    on_current = true;
 
186
                if ((*it)->isOnAllDesktops())
 
187
                    on_all = true;
 
188
            }
 
189
            if (on_all)
 
190
                desk = NET::OnAllDesktops;
 
191
            else if (on_current)
 
192
                desk = workspace()->currentDesktop();
 
193
            else if (maincl != NULL)
 
194
                desk = maincl->desktop();
 
195
 
 
196
            if (maincl)
 
197
                setOnActivities(maincl->activities());
 
198
        }
 
199
        if (info->desktop())
 
200
            desk = info->desktop(); // Window had the initial desktop property, force it
 
201
        if (desktop() == 0 && asn_valid && asn_data.desktop() != 0)
 
202
            desk = asn_data.desktop();
 
203
        if (!isMapped && !noborder && isNormalWindow() && !activitiesDefined) {
 
204
            //a new, regular window, when we're not recovering from a crash,
 
205
            //and it hasn't got an activity. let's try giving it the current one.
 
206
            //TODO: decide whether to keep this before the 4.6 release
 
207
            //TODO: if we are keeping it (at least as an option), replace noborder checking
 
208
            //with a public API for setting windows to be on all activities.
 
209
            //something like KWindowSystem::setOnAllActivities or
 
210
            //KActivityConsumer::setOnAllActivities
 
211
            setOnActivity(Workspace::self()->currentActivity(), true);
 
212
        }
 
213
    }
 
214
    if (desk == 0)   // Assume window wants to be visible on the current desktop
 
215
        desk = workspace()->currentDesktop();
 
216
    desk = rules()->checkDesktop(desk, !isMapped);
 
217
    if (desk != NET::OnAllDesktops)   // Do range check
 
218
        desk = qMax(1, qMin(workspace()->numberOfDesktops(), desk));
 
219
    info->setDesktop(desk);
 
220
    workspace()->updateOnAllDesktopsOfTransients(this);   // SELI TODO
 
221
    //onAllDesktopsChange(); // Decoration doesn't exist here yet
 
222
 
 
223
    QRect geom(attr.x, attr.y, attr.width, attr.height);
 
224
    bool placementDone = false;
 
225
 
 
226
    if (session)
 
227
        geom = session->geometry;
 
228
 
 
229
    QRect area;
 
230
    bool partial_keep_in_area = isMapped || session;
 
231
    if (isMapped || session)
 
232
        area = workspace()->clientArea(FullArea, geom.center(), desktop());
 
233
    else if (options->xineramaPlacementEnabled) {
 
234
        int screen = options->xineramaPlacementScreen;
 
235
        if (screen == -1)   // Active screen
 
236
            screen = asn_data.xinerama() == -1 ? workspace()->activeScreen() : asn_data.xinerama();
 
237
        area = workspace()->clientArea(PlacementArea, workspace()->screenGeometry(screen).center(), desktop());
 
238
    } else
 
239
        area = workspace()->clientArea(PlacementArea, cursorPos(), desktop());
 
240
 
 
241
    if (int type = checkFullScreenHack(geom)) {
 
242
        fullscreen_mode = FullScreenHack;
 
243
        if (rules()->checkStrictGeometry(false)) {
 
244
            geom = type == 2 // 1 = It's xinerama-aware fullscreen hack, 2 = It's full area
 
245
                   ? workspace()->clientArea(FullArea, geom.center(), desktop())
 
246
                   : workspace()->clientArea(ScreenArea, geom.center(), desktop());
 
247
        } else
 
248
            geom = workspace()->clientArea(FullScreenArea, geom.center(), desktop());
 
249
        placementDone = true;
 
250
    }
 
251
 
 
252
    if (isDesktop())
 
253
        // KWin doesn't manage desktop windows
 
254
        placementDone = true;
 
255
 
 
256
    bool usePosition = false;
 
257
    if (isMapped || session || placementDone)
 
258
        placementDone = true; // Use geometry
 
259
    else if (isTransient() && !isUtility() && !isDialog() && !isSplash())
 
260
        usePosition = true;
 
261
    else if (isTransient() && !hasNETSupport())
 
262
        usePosition = true;
 
263
    else if (isDialog() && hasNETSupport()) {
 
264
        // If the dialog is actually non-NETWM transient window, don't try to apply placement to it,
 
265
        // it breaks with too many things (xmms, display)
 
266
        if (mainClients().count() >= 1) {
 
267
#if 1
 
268
            // #78082 - Ok, it seems there are after all some cases when an application has a good
 
269
            // reason to specify a position for its dialog. Too bad other WMs have never bothered
 
270
            // with placement for dialogs, so apps always specify positions for their dialogs,
 
271
            // including such silly positions like always centered on the screen or under mouse.
 
272
            // Using ignoring requested position in window-specific settings helps, and now
 
273
            // there's also _NET_WM_FULL_PLACEMENT.
 
274
            usePosition = true;
 
275
#else
 
276
            ; // Force using placement policy
 
277
#endif
 
278
        } else
 
279
            usePosition = true;
 
280
    } else if (isSplash())
 
281
        ; // Force using placement policy
 
282
    else
 
283
        usePosition = true;
 
284
    if (!rules()->checkIgnoreGeometry(!usePosition)) {
 
285
        bool ignorePPosition = options->ignorePositionClasses.contains(
 
286
                                   QString::fromLatin1(resourceClass()));
 
287
 
 
288
        if (((xSizeHint.flags & PPosition) && !ignorePPosition) ||
 
289
                (xSizeHint.flags & USPosition)) {
 
290
            placementDone = true;
 
291
            // Disobey xinerama placement option for now (#70943)
 
292
            area = workspace()->clientArea(PlacementArea, geom.center(), desktop());
 
293
        }
 
294
    }
 
295
    //if ( true ) // Size is always obeyed for now, only with constraints applied
 
296
    //    if (( xSizeHint.flags & USSize ) || ( xSizeHint.flags & PSize ))
 
297
    //        {
 
298
    //        // Keep in mind that we now actually have a size :-)
 
299
    //        }
 
300
 
 
301
    if (xSizeHint.flags & PMaxSize)
 
302
        geom.setSize(geom.size().boundedTo(
 
303
                         rules()->checkMaxSize(QSize(xSizeHint.max_width, xSizeHint.max_height))));
 
304
    if (xSizeHint.flags & PMinSize)
 
305
        geom.setSize(geom.size().expandedTo(
 
306
                         rules()->checkMinSize(QSize(xSizeHint.min_width, xSizeHint.min_height))));
 
307
 
 
308
    if (isMovable() && (geom.x() > area.right() || geom.y() > area.bottom()))
 
309
        placementDone = false; // Weird, do not trust.
 
310
 
 
311
    if (placementDone)
 
312
        move(geom.x(), geom.y());   // Before gravitating
 
313
 
 
314
    // Create client group if the window will have a decoration
 
315
    bool dontKeepInArea = false;
 
316
    if (!noBorder()) {
 
317
        client_group = NULL;
 
318
        // Automatically add to previous groups on session restore
 
319
        if (session && session->clientGroupClient && session->clientGroupClient != this)
 
320
            session->clientGroupClient->clientGroup()->add(this, -1, true);
 
321
        else if (isMapped)
 
322
            // If the window is already mapped (Restarted KWin) add any windows that already have the
 
323
            // same geometry to the same client group. (May incorrectly handle maximized windows)
 
324
            foreach (ClientGroup * group, workspace()->clientGroups)
 
325
            if (geom == QRect(group->visible()->pos(), group->visible()->clientSize()) &&
 
326
                    desk == group->visible()->desktop() &&
 
327
                    activities() == group->visible()->activities() &&
 
328
                    group->visible()->maximizeMode() != MaximizeFull) {
 
329
                group->add(this, -1, true);
 
330
                break;
 
331
            }
 
332
        if (!client_group && !isMapped && !session) {
 
333
            // Attempt to automatically group similar windows
 
334
            const Client* similar = workspace()->findSimilarClient(this);
 
335
            if (similar && similar->clientGroup() && !similar->noBorder()) {
 
336
                geom = QRect(similar->pos() + similar->clientPos(), similar->clientSize());
 
337
                updateDecoration(false);
 
338
                similar->clientGroup()->add(this, -1,
 
339
                                            rules()->checkAutogroupInForeground(options->autogroupInForeground));
 
340
                // Don't move entire group
 
341
                geom = QRect(similar->pos() + similar->clientPos(), similar->clientSize());
 
342
                placementDone = true;
 
343
                dontKeepInArea = true;
 
344
            }
 
345
        }
 
346
        if (!client_group)
 
347
            client_group = new ClientGroup(this);
 
348
    }
 
349
 
 
350
    updateDecoration(false);   // Also gravitates
 
351
    // TODO: Is CentralGravity right here, when resizing is done after gravitating?
 
352
    plainResize(rules()->checkSize(sizeForClientSize(geom.size()), !isMapped));
 
353
 
 
354
    QPoint forced_pos = rules()->checkPosition(invalidPoint, !isMapped);
 
355
    if (forced_pos != invalidPoint) {
 
356
        move(forced_pos);
 
357
        placementDone = true;
 
358
        // Don't keep inside workarea if the window has specially configured position
 
359
        partial_keep_in_area = true;
 
360
        area = workspace()->clientArea(FullArea, geom.center(), desktop());
 
361
    }
 
362
    if (!placementDone) {
 
363
        // Placement needs to be after setting size
 
364
        workspace()->place(this, area);
 
365
        placementDone = true;
 
366
    }
 
367
 
 
368
    if ((!isSpecialWindow() || isToolbar()) && isMovable() && !dontKeepInArea)
 
369
        keepInArea(area, partial_keep_in_area);
 
370
 
 
371
    updateShape();
 
372
 
 
373
    // CT: Extra check for stupid jdk 1.3.1. But should make sense in general
 
374
    // if client has initial state set to Iconic and is transient with a parent
 
375
    // window that is not Iconic, set init_state to Normal
 
376
    if (init_minimize && isTransient()) {
 
377
        ClientList mainclients = mainClients();
 
378
        for (ClientList::ConstIterator it = mainclients.constBegin();
 
379
                it != mainclients.constEnd();
 
380
                ++it)
 
381
            if ((*it)->isShown(true))
 
382
                init_minimize = false; // SELI TODO: Even e.g. for NET::Utility?
 
383
    }
 
384
    // If a dialog is shown for minimized window, minimize it too
 
385
    if (!init_minimize && isTransient() && mainClients().count() > 0) {
 
386
        bool visible_parent = false;
 
387
        // Use allMainClients(), to include also main clients of group transients
 
388
        // that have been optimized out in Client::checkGroupTransients()
 
389
        ClientList mainclients = allMainClients();
 
390
        for (ClientList::ConstIterator it = mainclients.constBegin();
 
391
                it != mainclients.constEnd();
 
392
                ++it)
 
393
            if ((*it)->isShown(true))
 
394
                visible_parent = true;
 
395
        if (!visible_parent) {
 
396
            init_minimize = true;
 
397
            demandAttention();
 
398
        }
 
399
    }
 
400
 
 
401
    if (init_minimize)
 
402
        minimize(true);   // No animation
 
403
 
 
404
 
 
405
    // SELI TODO: This seems to be mainly for kstart and ksystraycmd
 
406
    // probably should be replaced by something better
 
407
    bool doNotShow = false;
 
408
    if (workspace()->isNotManaged(caption()))
 
409
        doNotShow = true;
 
410
 
 
411
    // Other settings from the previous session
 
412
    if (session) {
 
413
        // Session restored windows are not considered to be new windows WRT rules,
 
414
        // I.e. obey only forcing rules
 
415
        setKeepAbove(session->keepAbove);
 
416
        setKeepBelow(session->keepBelow);
 
417
        setSkipTaskbar(session->skipTaskbar, true);
 
418
        setSkipPager(session->skipPager);
 
419
        setSkipSwitcher(session->skipSwitcher);
 
420
        setShade(session->shaded ? ShadeNormal : ShadeNone);
 
421
        setOpacity(session->opacity);
 
422
        if (session->maximized != MaximizeRestore) {
 
423
            maximize(MaximizeMode(session->maximized));
 
424
            geom_restore = session->restore;
 
425
        }
 
426
        if (session->fullscreen == FullScreenHack)
 
427
            ; // Nothing, this should be already set again above
 
428
        else if (session->fullscreen != FullScreenNone) {
 
429
            setFullScreen(true, false);
 
430
            geom_fs_restore = session->fsrestore;
 
431
        }
 
432
    } else {
 
433
        geom_restore = geometry(); // Remember restore geometry
 
434
        if (isMaximizable() && (width() >= area.width() || height() >= area.height())) {
 
435
            // Window is too large for the screen, maximize in the
 
436
            // directions necessary
 
437
            if (width() >= area.width() && height() >= area.height()) {
 
438
                maximize(Client::MaximizeFull);
 
439
                geom_restore = QRect(); // Use placement when unmaximizing
 
440
            } else if (width() >= area.width()) {
 
441
                maximize(Client::MaximizeHorizontal);
 
442
                geom_restore = QRect(); // Use placement when unmaximizing
 
443
                geom_restore.setY(y());   // But only for horizontal direction
 
444
                geom_restore.setHeight(height());
 
445
            } else if (height() >= area.height()) {
 
446
                maximize(Client::MaximizeVertical);
 
447
                geom_restore = QRect(); // Use placement when unmaximizing
 
448
                geom_restore.setX(x());   // But only for vertical direction
 
449
                geom_restore.setWidth(width());
 
450
            }
 
451
        }
 
452
 
 
453
        // Window may want to be maximized
 
454
        // done after checking that the window isn't larger than the workarea, so that
 
455
        // the restore geometry from the checks above takes precedence, and window
 
456
        // isn't restored larger than the workarea
 
457
        MaximizeMode maxmode = static_cast<MaximizeMode>(
 
458
                                   ((info->state() & NET::MaxVert) ? MaximizeVertical : 0) |
 
459
                                   ((info->state() & NET::MaxHoriz) ? MaximizeHorizontal : 0));
 
460
        MaximizeMode forced_maxmode = rules()->checkMaximize(maxmode, !isMapped);
 
461
 
 
462
        // Either hints were set to maximize, or is forced to maximize,
 
463
        // or is forced to non-maximize and hints were set to maximize
 
464
        if (forced_maxmode != MaximizeRestore || maxmode != MaximizeRestore)
 
465
            maximize(forced_maxmode);
 
466
 
 
467
        // Read other initial states
 
468
        setShade(rules()->checkShade(info->state() & NET::Shaded ? ShadeNormal : ShadeNone, !isMapped));
 
469
        setKeepAbove(rules()->checkKeepAbove(info->state() & NET::KeepAbove, !isMapped));
 
470
        setKeepBelow(rules()->checkKeepBelow(info->state() & NET::KeepBelow, !isMapped));
 
471
        setSkipTaskbar(rules()->checkSkipTaskbar(info->state() & NET::SkipTaskbar, !isMapped), true);
 
472
        setSkipPager(rules()->checkSkipPager(info->state() & NET::SkipPager, !isMapped));
 
473
        setSkipSwitcher(rules()->checkSkipSwitcher(false, !isMapped));
 
474
        if (info->state() & NET::DemandsAttention)
 
475
            demandAttention();
 
476
        if (info->state() & NET::Modal)
 
477
            setModal(true);
 
478
        if (fullscreen_mode != FullScreenHack && isFullScreenable())
 
479
            setFullScreen(rules()->checkFullScreen(info->state() & NET::FullScreen, !isMapped), false);
 
480
    }
 
481
 
 
482
    updateAllowedActions(true);
 
483
 
 
484
    // Set initial user time directly
 
485
    user_time = readUserTimeMapTimestamp(asn_valid ? &asn_id : NULL, asn_valid ? &asn_data : NULL, session);
 
486
    group()->updateUserTime(user_time);   // And do what Client::updateUserTime() does
 
487
 
 
488
    if (isTopMenu())  // They're shown in Workspace::addClient() if their mainwindow
 
489
        hideClient(true);   // Is the active one
 
490
 
 
491
    // This should avoid flicker, because real restacking is done
 
492
    // only after manage() finishes because of blocking, but the window is shown sooner
 
493
    XLowerWindow(display(), frameId());
 
494
    if (session && session->stackingOrder != -1) {
 
495
        sm_stacking_order = session->stackingOrder;
 
496
        workspace()->restoreSessionStackingOrder(this);
 
497
    }
 
498
 
 
499
    if (compositing())
 
500
        // Sending ConfigureNotify is done when setting mapping state below,
 
501
        // Getting the first sync response means window is ready for compositing
 
502
        sendSyncRequest();
 
503
 
 
504
    if (isShown(true) && !doNotShow) {
 
505
        if (isDialog())
 
506
            Notify::raise(Notify::TransNew);
 
507
        if (isNormalWindow())
 
508
            Notify::raise(Notify::New);
 
509
 
 
510
        bool allow;
 
511
        if (session)
 
512
            allow = session->active &&
 
513
                    (!workspace()->wasUserInteraction() || workspace()->activeClient() == NULL ||
 
514
                     workspace()->activeClient()->isDesktop());
 
515
        else
 
516
            allow = workspace()->allowClientActivation(this, userTime(), false);
 
517
 
 
518
        if (!(isMapped || session)) {
 
519
            if (workspace()->sessionSaving()) {
 
520
                /*
 
521
                 * If we get a new window during session saving, we assume it's some 'save file?' dialog
 
522
                 * which the user really needs to see (to know why logout's stalled).
 
523
                 *
 
524
                 * Given the current session management protocol, I can't see a nicer way of doing this.
 
525
                 * Someday I'd like to see a protocol that tells the windowmanager who's doing SessionInteract.
 
526
                 */
 
527
                needsSessionInteract = true;
 
528
                //show the parent too
 
529
                ClientList mainclients = mainClients();
 
530
                for (ClientList::ConstIterator it = mainclients.constBegin();
 
531
                        it != mainclients.constEnd(); ++it) {
 
532
                    (*it)->setSessionInteract(true);
 
533
                }
 
534
            } else if (allow) {
 
535
                // also force if activation is allowed
 
536
                if (!isOnCurrentDesktop()) {
 
537
                    workspace()->setCurrentDesktop(desktop());
 
538
                }
 
539
                /*if (!isOnCurrentActivity()) {
 
540
                    workspace()->setCurrentActivity( activities().first() );
 
541
                } FIXME no such method*/
 
542
            }
 
543
        }
 
544
 
 
545
        bool belongs_to_desktop = false;
 
546
        for (ClientList::ConstIterator it = group()->members().constBegin();
 
547
                it != group()->members().constEnd();
 
548
                ++it)
 
549
            if ((*it)->isDesktop()) {
 
550
                belongs_to_desktop = true;
 
551
                break;
 
552
            }
 
553
        if (!belongs_to_desktop && workspace()->showingDesktop())
 
554
            workspace()->resetShowingDesktop(options->showDesktopIsMinimizeAll);
 
555
 
 
556
        if (isOnCurrentDesktop() && !isMapped && !allow && (!session || session->stackingOrder < 0))
 
557
            workspace()->restackClientUnderActive(this);
 
558
 
 
559
        updateVisibility();
 
560
 
 
561
        if (!isMapped) {
 
562
            if (allow && isOnCurrentDesktop()) {
 
563
                if (!isSpecialWindow())
 
564
                    if (options->focusPolicyIsReasonable() && wantsTabFocus())
 
565
                        workspace()->requestFocus(this);
 
566
            } else if (!session && !isSpecialWindow())
 
567
                demandAttention();
 
568
        }
 
569
    } else if (!doNotShow) // if ( !isShown( true ) && !doNotShow )
 
570
        updateVisibility();
 
571
    else // doNotShow
 
572
        hideClient(true);   // SELI HACK !!!
 
573
    assert(mapping_state != Withdrawn);
 
574
    blockGeometryUpdates(false);
 
575
 
 
576
    if (user_time == CurrentTime || user_time == -1U) {
 
577
        // No known user time, set something old
 
578
        user_time = xTime() - 1000000;
 
579
        if (user_time == CurrentTime || user_time == -1U)   // Let's be paranoid
 
580
            user_time = xTime() - 1000000 + 10;
 
581
    }
 
582
 
 
583
    //sendSyntheticConfigureNotify(); // Done when setting mapping state
 
584
 
 
585
    delete session;
 
586
 
 
587
    ungrabXServer();
 
588
 
 
589
    client_rules.discardTemporary();
 
590
    applyWindowRules(); // Just in case
 
591
    workspace()->discardUsedWindowRules(this, false);   // Remove ApplyNow rules
 
592
    updateWindowRules(); // Was blocked while !isManaged()
 
593
 
 
594
    updateCompositeBlocking(true);
 
595
 
 
596
    // TODO: there's a small problem here - isManaged() depends on the mapping state,
 
597
    // but this client is not yet in Workspace's client list at this point, will
 
598
    // be only done in addClient()
 
599
    return true;
 
600
}
 
601
 
 
602
// Called only from manage()
 
603
void Client::embedClient(Window w, const XWindowAttributes& attr)
 
604
{
 
605
    assert(client == None);
 
606
    assert(frameId() == None);
 
607
    assert(wrapper == None);
 
608
    client = w;
 
609
 
 
610
    // We don't want the window to be destroyed when we are destroyed
 
611
    XAddToSaveSet(display(), client);
 
612
    XSelectInput(display(), client, NoEventMask);
 
613
    XUnmapWindow(display(), client);
 
614
    XWindowChanges wc; // Set the border width to 0
 
615
    wc.border_width = 0; // TODO: Possibly save this, and also use it for initial configuring of the window
 
616
    XConfigureWindow(display(), client, CWBorderWidth, &wc);
 
617
 
 
618
    XSetWindowAttributes swa;
 
619
    swa.colormap = attr.colormap;
 
620
    swa.background_pixmap = None;
 
621
    swa.border_pixel = 0;
 
622
 
 
623
    Window frame = XCreateWindow(display(), rootWindow(), 0, 0, 1, 1, 0,
 
624
                                 attr.depth, InputOutput, attr.visual, CWColormap | CWBackPixmap | CWBorderPixel, &swa);
 
625
    setWindowHandles(client, frame);
 
626
    wrapper = XCreateWindow(display(), frame, 0, 0, 1, 1, 0,
 
627
                            attr.depth, InputOutput, attr.visual, CWColormap | CWBackPixmap | CWBorderPixel, &swa);
 
628
 
 
629
    XDefineCursor(display(), frame, QCursor(Qt::ArrowCursor).handle());
 
630
    // Some apps are stupid and don't define their own cursor - set the arrow one for them
 
631
    XDefineCursor(display(), wrapper, QCursor(Qt::ArrowCursor).handle());
 
632
    XReparentWindow(display(), client, wrapper, 0, 0);
 
633
    XSelectInput(display(), frame,
 
634
                 KeyPressMask | KeyReleaseMask |
 
635
                 ButtonPressMask | ButtonReleaseMask |
 
636
                 KeymapStateMask |
 
637
                 ButtonMotionMask |
 
638
                 PointerMotionMask |
 
639
                 EnterWindowMask | LeaveWindowMask |
 
640
                 FocusChangeMask |
 
641
                 ExposureMask |
 
642
                 PropertyChangeMask |
 
643
                 StructureNotifyMask | SubstructureRedirectMask);
 
644
    XSelectInput(display(), wrapper, ClientWinMask | SubstructureNotifyMask);
 
645
    XSelectInput(display(), client,
 
646
                 FocusChangeMask |
 
647
                 PropertyChangeMask |
 
648
                 ColormapChangeMask |
 
649
                 EnterWindowMask | LeaveWindowMask |
 
650
                 KeyPressMask | KeyReleaseMask
 
651
                );
 
652
 
 
653
    updateMouseGrab();
 
654
}
 
655
 
 
656
} // namespace