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

« back to all changes in this revision

Viewing changes to kwin/effects/presentwindows/presentwindows.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) 2007 Rivo Laks <rivolaks@hot.ee>
 
6
Copyright (C) 2008 Lucas Murray <lmurray@undefinedfire.com>
 
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
#include "presentwindows.h"
 
23
 
 
24
#include <kactioncollection.h>
 
25
#include <kaction.h>
 
26
#include <klocale.h>
 
27
#include <kcolorscheme.h>
 
28
#include <kconfiggroup.h>
 
29
#include <kdebug.h>
 
30
#include <kglobalsettings.h>
 
31
 
 
32
#ifdef KWIN_HAVE_OPENGL_COMPOSITING
 
33
#include <kwinglutils.h>
 
34
#endif
 
35
 
 
36
#include <QMouseEvent>
 
37
#include <QtGui/QPainter>
 
38
#include <QtGui/QGraphicsLinearLayout>
 
39
#include <Plasma/FrameSvg>
 
40
#include <Plasma/PushButton>
 
41
#include <Plasma/WindowEffects>
 
42
#include <netwm_def.h>
 
43
 
 
44
#include <math.h>
 
45
#include <assert.h>
 
46
#include <limits.h>
 
47
#include <QTimer>
 
48
#include <QVector4D>
 
49
 
 
50
namespace KWin
 
51
{
 
52
 
 
53
KWIN_EFFECT(presentwindows, PresentWindowsEffect)
 
54
 
 
55
PresentWindowsEffect::PresentWindowsEffect()
 
56
    : m_proxy(this)
 
57
    , m_activated(false)
 
58
    , m_ignoreMinimized(false)
 
59
    , m_decalOpacity(0.0)
 
60
    , m_hasKeyboardGrab(false)
 
61
    , m_tabBoxEnabled(false)
 
62
    , m_mode(ModeCurrentDesktop)
 
63
    , m_managerWindow(NULL)
 
64
    , m_highlightedWindow(NULL)
 
65
    , m_filterFrame(effects->effectFrame(EffectFrameStyled, false))
 
66
    , m_closeView(NULL)
 
67
    , m_dragInProgress(false)
 
68
    , m_dragWindow(NULL)
 
69
    , m_highlightedDropTarget(NULL)
 
70
    , m_dragToClose(false)
 
71
{
 
72
    m_atomDesktop = XInternAtom(display(), "_KDE_PRESENT_WINDOWS_DESKTOP", False);
 
73
    m_atomWindows = XInternAtom(display(), "_KDE_PRESENT_WINDOWS_GROUP", False);
 
74
    effects->registerPropertyType(m_atomDesktop, true);
 
75
    effects->registerPropertyType(m_atomWindows, true);
 
76
 
 
77
    // Announce support by creating a dummy version on the root window
 
78
    unsigned char dummy = 0;
 
79
    XChangeProperty(display(), rootWindow(), m_atomDesktop, m_atomDesktop, 8, PropModeReplace, &dummy, 1);
 
80
    XChangeProperty(display(), rootWindow(), m_atomWindows, m_atomWindows, 8, PropModeReplace, &dummy, 1);
 
81
 
 
82
    QFont font;
 
83
    font.setPointSize(font.pointSize() * 2);
 
84
    font.setBold(true);
 
85
    m_filterFrame->setFont(font);
 
86
 
 
87
    KActionCollection* actionCollection = new KActionCollection(this);
 
88
    KAction* a = (KAction*)actionCollection->addAction("Expose");
 
89
    a->setText(i18n("Toggle Present Windows (Current desktop)"));
 
90
    a->setGlobalShortcut(KShortcut(Qt::CTRL + Qt::Key_F9));
 
91
    shortcut = a->globalShortcut();
 
92
    connect(a, SIGNAL(triggered(bool)), this, SLOT(toggleActive()));
 
93
    connect(a, SIGNAL(globalShortcutChanged(QKeySequence)), this, SLOT(globalShortcutChanged(QKeySequence)));
 
94
    KAction* b = (KAction*)actionCollection->addAction("ExposeAll");
 
95
    b->setText(i18n("Toggle Present Windows (All desktops)"));
 
96
    b->setGlobalShortcut(KShortcut(Qt::CTRL + Qt::Key_F10));
 
97
    shortcutAll = b->globalShortcut();
 
98
    connect(b, SIGNAL(triggered(bool)), this, SLOT(toggleActiveAllDesktops()));
 
99
    connect(b, SIGNAL(globalShortcutChanged(QKeySequence)), this, SLOT(globalShortcutChangedAll(QKeySequence)));
 
100
    KAction* c = (KAction*)actionCollection->addAction("ExposeClass");
 
101
    c->setText(i18n("Toggle Present Windows (Window class)"));
 
102
    c->setGlobalShortcut(KShortcut(Qt::CTRL + Qt::Key_F7));
 
103
    connect(c, SIGNAL(triggered(bool)), this, SLOT(toggleActiveClass()));
 
104
    connect(c, SIGNAL(globalShortcutChanged(QKeySequence)), this, SLOT(globalShortcutChangedClass(QKeySequence)));
 
105
    shortcutClass = c->globalShortcut();
 
106
    reconfigure(ReconfigureAll);
 
107
    connect(effects, SIGNAL(windowAdded(EffectWindow*)), this, SLOT(slotWindowAdded(EffectWindow*)));
 
108
    connect(effects, SIGNAL(windowClosed(EffectWindow*)), this, SLOT(slotWindowClosed(EffectWindow*)));
 
109
    connect(effects, SIGNAL(windowDeleted(EffectWindow*)), this, SLOT(slotWindowDeleted(EffectWindow*)));
 
110
    connect(effects, SIGNAL(windowGeometryShapeChanged(EffectWindow*,QRect)), this, SLOT(slotWindowGeometryShapeChanged(EffectWindow*,QRect)));
 
111
    connect(effects, SIGNAL(tabBoxAdded(int)), this, SLOT(slotTabBoxAdded(int)));
 
112
    connect(effects, SIGNAL(tabBoxClosed()), this, SLOT(slotTabBoxClosed()));
 
113
    connect(effects, SIGNAL(tabBoxUpdated()), this, SLOT(slotTabBoxUpdated()));
 
114
    connect(effects, SIGNAL(tabBoxKeyEvent(QKeyEvent*)), this, SLOT(slotTabBoxKeyEvent(QKeyEvent*)));
 
115
    connect(effects, SIGNAL(propertyNotify(EffectWindow*,long)), this, SLOT(slotPropertyNotify(EffectWindow*,long)));
 
116
}
 
117
 
 
118
PresentWindowsEffect::~PresentWindowsEffect()
 
119
{
 
120
    XDeleteProperty(display(), rootWindow(), m_atomDesktop);
 
121
    effects->registerPropertyType(m_atomDesktop, false);
 
122
    XDeleteProperty(display(), rootWindow(), m_atomWindows);
 
123
    effects->registerPropertyType(m_atomWindows, false);
 
124
    foreach (ElectricBorder border, m_borderActivate) {
 
125
        effects->unreserveElectricBorder(border);
 
126
    }
 
127
    foreach (ElectricBorder border, m_borderActivateAll) {
 
128
        effects->unreserveElectricBorder(border);
 
129
    }
 
130
    delete m_filterFrame;
 
131
    delete m_closeView;
 
132
}
 
133
 
 
134
void PresentWindowsEffect::reconfigure(ReconfigureFlags)
 
135
{
 
136
    KConfigGroup conf = effects->effectConfig("PresentWindows");
 
137
    foreach (ElectricBorder border, m_borderActivate) {
 
138
        effects->unreserveElectricBorder(border);
 
139
    }
 
140
    foreach (ElectricBorder border, m_borderActivateAll) {
 
141
        effects->unreserveElectricBorder(border);
 
142
    }
 
143
    m_borderActivate.clear();
 
144
    m_borderActivateAll.clear();
 
145
    QList<int> borderList = QList<int>();
 
146
    borderList.append(int(ElectricNone));
 
147
    borderList = conf.readEntry("BorderActivate", borderList);
 
148
    foreach (int i, borderList) {
 
149
        m_borderActivate.append(ElectricBorder(i));
 
150
        effects->reserveElectricBorder(ElectricBorder(i));
 
151
    }
 
152
    borderList.clear();
 
153
    borderList.append(int(ElectricTopLeft));
 
154
    borderList = conf.readEntry("BorderActivateAll", borderList);
 
155
    foreach (int i, borderList) {
 
156
        m_borderActivateAll.append(ElectricBorder(i));
 
157
        effects->reserveElectricBorder(ElectricBorder(i));
 
158
    }
 
159
    m_layoutMode = conf.readEntry("LayoutMode", int(LayoutNatural));
 
160
    m_showCaptions = conf.readEntry("DrawWindowCaptions", true);
 
161
    m_showIcons = conf.readEntry("DrawWindowIcons", true);
 
162
    m_doNotCloseWindows = !conf.readEntry("AllowClosingWindows", true);
 
163
    m_tabBoxAllowed = conf.readEntry("TabBox", false);
 
164
    m_tabBoxAlternativeAllowed = conf.readEntry("TabBoxAlternative", false);
 
165
    m_ignoreMinimized = conf.readEntry("IgnoreMinimized", false);
 
166
    m_accuracy = conf.readEntry("Accuracy", 1) * 20;
 
167
    m_fillGaps = conf.readEntry("FillGaps", true);
 
168
    m_fadeDuration = double(animationTime(150));
 
169
    m_showPanel = conf.readEntry("ShowPanel", false);
 
170
    m_leftButtonWindow = (WindowMouseAction)conf.readEntry("LeftButtonWindow", (int)WindowActivateAction);
 
171
    m_middleButtonWindow = (WindowMouseAction)conf.readEntry("MiddleButtonWindow", (int)WindowNoAction);
 
172
    m_rightButtonWindow = (WindowMouseAction)conf.readEntry("RightButtonWindow", (int)WindowExitAction);
 
173
    m_leftButtonDesktop = (DesktopMouseAction)conf.readEntry("LeftButtonDesktop", (int)DesktopExitAction);
 
174
    m_middleButtonDesktop = (DesktopMouseAction)conf.readEntry("MiddleButtonDesktop", (int)DesktopNoAction);
 
175
    m_rightButtonDesktop = (DesktopMouseAction)conf.readEntry("RightButtonDesktop", (int)DesktopNoAction);
 
176
    m_dragToClose = conf.readEntry("DragToClose", false);
 
177
}
 
178
 
 
179
void* PresentWindowsEffect::proxy()
 
180
{
 
181
    return &m_proxy;
 
182
}
 
183
 
 
184
void PresentWindowsEffect::toggleActiveClass()
 
185
{
 
186
    if (!m_activated) {
 
187
        if (!effects->activeWindow())
 
188
            return;
 
189
        m_mode = ModeWindowClass;
 
190
        m_class = effects->activeWindow()->windowClass();
 
191
    }
 
192
    setActive(!m_activated);
 
193
}
 
194
 
 
195
//-----------------------------------------------------------------------------
 
196
// Screen painting
 
197
 
 
198
void PresentWindowsEffect::prePaintScreen(ScreenPrePaintData &data, int time)
 
199
{
 
200
    m_motionManager.calculate(time);
 
201
 
 
202
    // We need to mark the screen as having been transformed otherwise there will be no repainting
 
203
    if (m_activated || m_motionManager.managingWindows())
 
204
        data.mask |= Effect::PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS;
 
205
 
 
206
    if (m_activated)
 
207
        m_decalOpacity = qMin(1.0, m_decalOpacity + time / m_fadeDuration);
 
208
    else
 
209
        m_decalOpacity = qMax(0.0, m_decalOpacity - time / m_fadeDuration);
 
210
 
 
211
    effects->prePaintScreen(data, time);
 
212
}
 
213
 
 
214
void PresentWindowsEffect::paintScreen(int mask, QRegion region, ScreenPaintData &data)
 
215
{
 
216
    effects->paintScreen(mask, region, data);
 
217
 
 
218
    // Display the filter box
 
219
    if (!m_windowFilter.isEmpty())
 
220
        m_filterFrame->render(region);
 
221
    // Display drop targets
 
222
    for (int i=0; i<m_dropTargets.size(); ++i) {
 
223
        m_dropTargets.at(i)->render();
 
224
    }
 
225
}
 
226
 
 
227
void PresentWindowsEffect::postPaintScreen()
 
228
{
 
229
    if (m_motionManager.areWindowsMoving())
 
230
        effects->addRepaintFull();
 
231
    else if (!m_activated && m_motionManager.managingWindows()) {
 
232
        // We have finished moving them back, stop processing
 
233
        m_motionManager.unmanageAll();
 
234
 
 
235
        DataHash::iterator i = m_windowData.begin();
 
236
        while (i != m_windowData.end()) {
 
237
            delete i.value().textFrame;
 
238
            delete i.value().iconFrame;
 
239
            i++;
 
240
        }
 
241
        m_windowData.clear();
 
242
 
 
243
        foreach (EffectWindow * w, effects->stackingOrder()) {
 
244
            if (w->isDock()) {
 
245
                w->setData(WindowForceBlurRole, QVariant(false));
 
246
            }
 
247
        }
 
248
        effects->setActiveFullScreenEffect(NULL);
 
249
    }
 
250
 
 
251
    // Update windows that are changing brightness or opacity
 
252
    DataHash::const_iterator i;
 
253
    for (i = m_windowData.constBegin(); i != m_windowData.constEnd(); ++i) {
 
254
        if (i.value().opacity > 0.0 && i.value().opacity < 1.0)
 
255
            i.key()->addRepaintFull();
 
256
        if (i.value().highlight > 0.0 && i.value().highlight < 1.0)
 
257
            i.key()->addRepaintFull();
 
258
    }
 
259
 
 
260
    effects->postPaintScreen();
 
261
}
 
262
 
 
263
//-----------------------------------------------------------------------------
 
264
// Window painting
 
265
 
 
266
void PresentWindowsEffect::prePaintWindow(EffectWindow *w, WindowPrePaintData &data, int time)
 
267
{
 
268
    // TODO: We should also check to see if any windows are fading just in case fading takes longer
 
269
    //       than moving the windows when the effect is deactivated.
 
270
    if (m_activated || m_motionManager.areWindowsMoving()) {
 
271
        DataHash::iterator winData = m_windowData.find(w);
 
272
        if (winData == m_windowData.end()) {
 
273
            effects->prePaintWindow(w, data, time);
 
274
            return;
 
275
        }
 
276
        w->enablePainting(EffectWindow::PAINT_DISABLED_BY_MINIMIZE);   // Display always
 
277
        w->enablePainting(EffectWindow::PAINT_DISABLED_BY_DESKTOP);
 
278
        if (winData->visible)
 
279
            w->enablePainting(EffectWindow::PAINT_DISABLED_BY_CLIENT_GROUP);
 
280
 
 
281
        // Calculate window's opacity
 
282
        // TODO: Minimized windows or windows not on the current desktop are only 75% visible?
 
283
        if (winData->visible) {
 
284
            if (winData->deleted)
 
285
                winData->opacity = qMax(0.0, winData->opacity - time / m_fadeDuration);
 
286
            else
 
287
                winData->opacity = qMin(/*(w->isMinimized() || !w->isOnCurrentDesktop()) ? 0.75 :*/ 1.0,
 
288
                                          winData->opacity + time / m_fadeDuration);
 
289
        } else
 
290
            winData->opacity = qMax(0.0, winData->opacity - time / m_fadeDuration);
 
291
        if (winData->opacity <= 0.0) {
 
292
            // don't disable painting for panels if show panel is set
 
293
            if (!(m_showPanel && w->isDock()))
 
294
                w->disablePainting(EffectWindow::PAINT_DISABLED);
 
295
        } else if (winData->opacity != 1.0)
 
296
            data.setTranslucent();
 
297
 
 
298
        // Calculate window's brightness
 
299
        if (w == m_highlightedWindow || w == m_closeWindow || !m_activated)
 
300
            winData->highlight = qMin(1.0, winData->highlight + time / m_fadeDuration);
 
301
        else
 
302
            winData->highlight = qMax(0.0, winData->highlight - time / m_fadeDuration);
 
303
 
 
304
        // Closed windows
 
305
        if (winData->deleted) {
 
306
            data.setTranslucent();
 
307
            if (winData->opacity <= 0.0 && winData->referenced) {
 
308
                // it's possible that another effect has referenced the window
 
309
                // we have to keep the window in the list to prevent flickering
 
310
                winData->referenced = false;
 
311
                w->unrefWindow();
 
312
            } else
 
313
                w->enablePainting(EffectWindow::PAINT_DISABLED_BY_DELETE);
 
314
        }
 
315
 
 
316
        // desktop windows on other desktops (Plasma activity per desktop) should not be painted
 
317
        if (w->isDesktop() && !w->isOnCurrentDesktop())
 
318
            w->disablePainting(EffectWindow::PAINT_DISABLED_BY_DESKTOP);
 
319
 
 
320
        if (m_motionManager.isManaging(w))
 
321
            data.setTransformed(); // We will be moving this window
 
322
    }
 
323
    effects->prePaintWindow(w, data, time);
 
324
}
 
325
 
 
326
void PresentWindowsEffect::paintWindow(EffectWindow *w, int mask, QRegion region, WindowPaintData &data)
 
327
{
 
328
    if (m_activated || m_motionManager.areWindowsMoving()) {
 
329
        DataHash::const_iterator winData = m_windowData.constFind(w);
 
330
        if (winData == m_windowData.constEnd() || (w->isDock() && m_showPanel)) {
 
331
            // in case the panel should be shown just display it without any changes
 
332
            effects->paintWindow(w, mask, region, data);
 
333
            return;
 
334
        }
 
335
 
 
336
        // Apply opacity and brightness
 
337
        data.opacity *= winData->opacity;
 
338
        data.brightness *= interpolate(0.7, 1.0, winData->highlight);
 
339
 
 
340
        if (m_motionManager.isManaging(w)) {
 
341
            m_motionManager.apply(w, data);
 
342
 
 
343
            if (!m_motionManager.areWindowsMoving()) {
 
344
                mask |= PAINT_WINDOW_LANCZOS;
 
345
            }
 
346
            if (m_dragInProgress && m_dragWindow == w) {
 
347
                QPoint diff = cursorPos() - m_dragStart;
 
348
                data.xTranslate += diff.x();
 
349
                data.yTranslate += diff.y();
 
350
            }
 
351
            effects->paintWindow(w, mask, region, data);
 
352
 
 
353
            QRect rect = m_motionManager.transformedGeometry(w).toRect();
 
354
            if (m_showIcons) {
 
355
                QPoint point(rect.x() + rect.width() * 0.95,
 
356
                             rect.y() + rect.height() * 0.95);
 
357
                winData->iconFrame->setPosition(point);
 
358
#ifdef KWIN_HAVE_OPENGL_COMPOSITING
 
359
                if (effects->compositingType() == KWin::OpenGLCompositing && data.shader) {
 
360
                    const float a = 0.9 * data.opacity * m_decalOpacity * 0.75;
 
361
                    data.shader->setUniform(GLShader::ModulationConstant, QVector4D(a, a, a, a));
 
362
                }
 
363
#endif
 
364
                winData->iconFrame->render(region, 0.9 * data.opacity * m_decalOpacity, 0.75);
 
365
            }
 
366
            if (m_showCaptions) {
 
367
                QPoint point(rect.x() + rect.width() / 2,
 
368
                             rect.y() + rect.height() / 2);
 
369
                winData->textFrame->setPosition(point);
 
370
#ifdef KWIN_HAVE_OPENGL_COMPOSITING
 
371
                if (effects->compositingType() == KWin::OpenGLCompositing && data.shader) {
 
372
                    const float a = 0.9 * data.opacity * m_decalOpacity * 0.75;
 
373
                    data.shader->setUniform(GLShader::ModulationConstant, QVector4D(a, a, a, a));
 
374
                }
 
375
#endif
 
376
                winData->textFrame->render(region, 0.9 * data.opacity * m_decalOpacity, 0.75);
 
377
            }
 
378
        } else
 
379
            effects->paintWindow(w, mask, region, data);
 
380
    } else
 
381
        effects->paintWindow(w, mask, region, data);
 
382
}
 
383
 
 
384
//-----------------------------------------------------------------------------
 
385
// User interaction
 
386
 
 
387
void PresentWindowsEffect::slotWindowAdded(EffectWindow *w)
 
388
{
 
389
    if (!m_activated)
 
390
        return;
 
391
    WindowData *winData = &m_windowData[w];
 
392
    winData->visible = isVisibleWindow(w);
 
393
    winData->opacity = 0.0;
 
394
    winData->highlight = 0.0;
 
395
    winData->textFrame = effects->effectFrame(EffectFrameUnstyled, false);
 
396
    QFont font;
 
397
    font.setBold(true);
 
398
    font.setPointSize(12);
 
399
    winData->textFrame->setFont(font);
 
400
    winData->iconFrame = effects->effectFrame(EffectFrameUnstyled, false);
 
401
    winData->iconFrame->setAlignment(Qt::AlignRight | Qt::AlignBottom);
 
402
    winData->iconFrame->setIcon(w->icon());
 
403
    if (isSelectableWindow(w)) {
 
404
        m_motionManager.manage(w);
 
405
        rearrangeWindows();
 
406
    }
 
407
    if (w == effects->findWindow(m_closeView->winId())) {
 
408
        winData->visible = true;
 
409
        winData->highlight = 1.0;
 
410
        m_closeWindow = w;
 
411
        w->setData(WindowForceBlurRole, QVariant(true));
 
412
    }
 
413
}
 
414
 
 
415
void PresentWindowsEffect::slotWindowClosed(EffectWindow *w)
 
416
{
 
417
    if (m_managerWindow == w)
 
418
        m_managerWindow = NULL;
 
419
    DataHash::iterator winData = m_windowData.find(w);
 
420
    if (winData == m_windowData.end())
 
421
        return;
 
422
    winData->deleted = true;
 
423
    winData->referenced = true;
 
424
    w->refWindow();
 
425
    if (m_highlightedWindow == w)
 
426
        setHighlightedWindow(findFirstWindow());
 
427
    if (m_closeWindow == w) {
 
428
        m_closeWindow = 0;
 
429
        return; // don't rearrange
 
430
    }
 
431
    rearrangeWindows();
 
432
 
 
433
    foreach (EffectWindow *w, m_motionManager.managedWindows()) {
 
434
        winData = m_windowData.find(w);
 
435
        if (winData != m_windowData.end() && !winData->deleted)
 
436
           return; // found one that is not deleted? then we go on
 
437
    }
 
438
    setActive(false);     //else no need to keep this open
 
439
}
 
440
 
 
441
void PresentWindowsEffect::slotWindowDeleted(EffectWindow *w)
 
442
{
 
443
    DataHash::iterator winData = m_windowData.find(w);
 
444
    if (winData == m_windowData.end())
 
445
        return;
 
446
    delete winData->textFrame;
 
447
    delete winData->iconFrame;
 
448
    m_windowData.erase(winData);
 
449
    m_motionManager.unmanage(w);
 
450
}
 
451
 
 
452
void PresentWindowsEffect::slotWindowGeometryShapeChanged(EffectWindow* w, const QRect& old)
 
453
{
 
454
    Q_UNUSED(old)
 
455
    if (!m_activated)
 
456
        return;
 
457
    if (!m_windowData.contains(w))
 
458
        return;
 
459
    rearrangeWindows();
 
460
}
 
461
 
 
462
bool PresentWindowsEffect::borderActivated(ElectricBorder border)
 
463
{
 
464
    if (!m_borderActivate.contains(border) && !m_borderActivateAll.contains(border))
 
465
        return false;
 
466
    if (effects->activeFullScreenEffect() && effects->activeFullScreenEffect() != this)
 
467
        return true;
 
468
    if (m_borderActivate.contains(border))
 
469
        toggleActive();
 
470
    else
 
471
        toggleActiveAllDesktops();
 
472
    return true;
 
473
}
 
474
 
 
475
void PresentWindowsEffect::windowInputMouseEvent(Window w, QEvent *e)
 
476
{
 
477
    assert(w == m_input);
 
478
    Q_UNUSED(w);
 
479
 
 
480
    QMouseEvent* me = static_cast< QMouseEvent* >(e);
 
481
    if (m_closeView->geometry().contains(me->pos())) {
 
482
        if (!m_closeView->isVisible()) {
 
483
            updateCloseWindow();
 
484
        }
 
485
        if (m_closeView->isVisible()) {
 
486
            const QPoint widgetPos = m_closeView->mapFromGlobal(me->pos());
 
487
            const QPointF scenePos = m_closeView->mapToScene(widgetPos);
 
488
            QMouseEvent event(me->type(), widgetPos, me->pos(), me->button(), me->buttons(), me->modifiers());
 
489
            m_closeView->windowInputMouseEvent(&event);
 
490
            return;
 
491
        }
 
492
    }
 
493
    // Which window are we hovering over? Always trigger as we don't always get move events before clicking
 
494
    // We cannot use m_motionManager.windowAtPoint() as the window might not be visible
 
495
    EffectWindowList windows = m_motionManager.managedWindows();
 
496
    bool hovering = false;
 
497
    for (int i = 0; i < windows.size(); ++i) {
 
498
        DataHash::const_iterator winData = m_windowData.constFind(windows.at(i));
 
499
        if (winData == m_windowData.constEnd())
 
500
            continue;
 
501
        if (m_motionManager.transformedGeometry(windows.at(i)).contains(cursorPos()) &&
 
502
                winData->visible && !winData->deleted) {
 
503
            hovering = true;
 
504
            if (windows.at(i) && m_highlightedWindow != windows.at(i) && !m_dragInProgress)
 
505
                setHighlightedWindow(windows.at(i));
 
506
            break;
 
507
        }
 
508
    }
 
509
    if (m_highlightedWindow && m_motionManager.transformedGeometry(m_highlightedWindow).contains(me->pos()))
 
510
        updateCloseWindow();
 
511
    else
 
512
        m_closeView->hide();
 
513
 
 
514
    if (e->type() == QEvent::MouseButtonRelease) {
 
515
        if (me->button() == Qt::LeftButton) {
 
516
            if (m_dragInProgress && m_dragWindow) {
 
517
                // handle drop
 
518
                for (int i=0; i<m_dropTargets.size(); ++i) {
 
519
                    if (m_dropTargets.at(i)->geometry().contains(me->pos())) {
 
520
                        m_dragWindow->closeWindow();
 
521
                        break;
 
522
                    }
 
523
                }
 
524
                effects->setElevatedWindow(m_dragWindow, false);
 
525
                m_dragInProgress = false;
 
526
                m_dragWindow = NULL;
 
527
                if (m_highlightedDropTarget) {
 
528
                    KIcon icon("user-trash");
 
529
                    m_highlightedDropTarget->setIcon(icon.pixmap(QSize(128, 128), QIcon::Normal));
 
530
                    m_highlightedDropTarget = NULL;
 
531
                }
 
532
                effects->addRepaintFull();
 
533
                XDefineCursor(display(), m_input, QCursor(Qt::PointingHandCursor).handle());
 
534
                return;
 
535
            }
 
536
            if (hovering) {
 
537
                // mouse is hovering above a window - use MouseActionsWindow
 
538
                mouseActionWindow(m_leftButtonWindow);
 
539
            } else {
 
540
                // mouse is hovering above desktop - use MouseActionsDesktop
 
541
                mouseActionDesktop(m_leftButtonDesktop);
 
542
            }
 
543
        }
 
544
        if (me->button() == Qt::MidButton) {
 
545
            if (hovering) {
 
546
                // mouse is hovering above a window - use MouseActionsWindow
 
547
                mouseActionWindow(m_middleButtonWindow);
 
548
            } else {
 
549
                // mouse is hovering above desktop - use MouseActionsDesktop
 
550
                mouseActionDesktop(m_middleButtonDesktop);
 
551
            }
 
552
        }
 
553
        if (me->button() == Qt::RightButton) {
 
554
            if (hovering) {
 
555
                // mouse is hovering above a window - use MouseActionsWindow
 
556
                mouseActionWindow(m_rightButtonWindow);
 
557
            } else {
 
558
                // mouse is hovering above desktop - use MouseActionsDesktop
 
559
                mouseActionDesktop(m_rightButtonDesktop);
 
560
            }
 
561
        }
 
562
        // reset dragging state
 
563
        effects->setElevatedWindow(m_dragWindow, false);
 
564
        m_dragInProgress = false;
 
565
        m_dragWindow = NULL;
 
566
        if (m_highlightedDropTarget) {
 
567
            effects->addRepaint(m_highlightedDropTarget->geometry());
 
568
            KIcon icon("user-trash");
 
569
            m_highlightedDropTarget->setIcon(icon.pixmap(QSize(128, 128), QIcon::Normal));
 
570
            m_highlightedDropTarget = NULL;
 
571
        }
 
572
        XDefineCursor(display(), m_input, QCursor(Qt::PointingHandCursor).handle());
 
573
    } else if (e->type() == QEvent::MouseButtonPress && me->button() == Qt::LeftButton && hovering && m_dragToClose) {
 
574
        m_dragStart = me->pos();
 
575
        m_dragWindow = m_highlightedWindow;
 
576
        m_dragInProgress = false;
 
577
        m_highlightedDropTarget = NULL;
 
578
        effects->setElevatedWindow(m_dragWindow, true);
 
579
        effects->addRepaintFull();
 
580
    }
 
581
    if (e->type() == QEvent::MouseMove && m_dragWindow) {
 
582
        if ((me->pos() - m_dragStart).manhattanLength() > KGlobalSettings::dndEventDelay() && !m_dragInProgress) {
 
583
            m_dragInProgress = true;
 
584
            XDefineCursor(display(), m_input, QCursor(Qt::ForbiddenCursor).handle());
 
585
        }
 
586
        if (!m_dragInProgress) {
 
587
            return;
 
588
        }
 
589
        effects->addRepaintFull();
 
590
        EffectFrame *target = NULL;
 
591
        foreach(EffectFrame *frame, m_dropTargets) {
 
592
            if (frame->geometry().contains(me->pos())) {
 
593
                target = frame;
 
594
                break;
 
595
            }
 
596
        }
 
597
        if (target && !m_highlightedDropTarget) {
 
598
            m_highlightedDropTarget = target;
 
599
            KIcon icon("user-trash");
 
600
            effects->addRepaint(m_highlightedDropTarget->geometry());
 
601
            m_highlightedDropTarget->setIcon(icon.pixmap(QSize(128, 128), QIcon::Active));
 
602
            XDefineCursor(display(), m_input, QCursor(Qt::DragMoveCursor).handle());
 
603
        } else if (!target && m_highlightedDropTarget) {
 
604
            KIcon icon("user-trash");
 
605
            effects->addRepaint(m_highlightedDropTarget->geometry());
 
606
            m_highlightedDropTarget->setIcon(icon.pixmap(QSize(128, 128), QIcon::Normal));
 
607
            m_highlightedDropTarget = NULL;
 
608
            XDefineCursor(display(), m_input, QCursor(Qt::ForbiddenCursor).handle());
 
609
        }
 
610
    }
 
611
}
 
612
 
 
613
void PresentWindowsEffect::mouseActionWindow(WindowMouseAction& action)
 
614
{
 
615
    switch(action) {
 
616
    case WindowActivateAction:
 
617
        if (m_highlightedWindow)
 
618
            effects->activateWindow(m_highlightedWindow);
 
619
        setActive(false);
 
620
        break;
 
621
    case WindowExitAction:
 
622
        setActive(false);
 
623
        break;
 
624
    case WindowToCurrentDesktopAction:
 
625
        if (m_highlightedWindow)
 
626
            effects->windowToDesktop(m_highlightedWindow, effects->currentDesktop());
 
627
        break;
 
628
    case WindowToAllDesktopsAction:
 
629
        if (m_highlightedWindow) {
 
630
            if (m_highlightedWindow->isOnAllDesktops())
 
631
                effects->windowToDesktop(m_highlightedWindow, effects->currentDesktop());
 
632
            else
 
633
                effects->windowToDesktop(m_highlightedWindow, NET::OnAllDesktops);
 
634
        }
 
635
        break;
 
636
    case WindowMinimizeAction:
 
637
        if (m_highlightedWindow) {
 
638
            if (m_highlightedWindow->isMinimized())
 
639
                m_highlightedWindow->unminimize();
 
640
            else
 
641
                m_highlightedWindow->minimize();
 
642
        }
 
643
        break;
 
644
    case WindowCloseAction:
 
645
        if (m_highlightedWindow) {
 
646
            m_highlightedWindow->closeWindow();
 
647
        }
 
648
        break;
 
649
    default:
 
650
        break;
 
651
    }
 
652
}
 
653
 
 
654
void PresentWindowsEffect::mouseActionDesktop(DesktopMouseAction& action)
 
655
{
 
656
    switch(action) {
 
657
    case DesktopActivateAction:
 
658
        if (m_highlightedWindow)
 
659
            effects->activateWindow(m_highlightedWindow);
 
660
        setActive(false);
 
661
        break;
 
662
    case DesktopExitAction:
 
663
        setActive(false);
 
664
        break;
 
665
    case DesktopShowDesktopAction:
 
666
        effects->setShowingDesktop(true);
 
667
        setActive(false);
 
668
    default:
 
669
        break;
 
670
    }
 
671
}
 
672
 
 
673
 
 
674
void PresentWindowsEffect::grabbedKeyboardEvent(QKeyEvent *e)
 
675
{
 
676
    if (e->type() == QEvent::KeyPress) {
 
677
        // check for global shortcuts
 
678
        // HACK: keyboard grab disables the global shortcuts so we have to check for global shortcut (bug 156155)
 
679
        if (m_mode == ModeCurrentDesktop && shortcut.contains(e->key() + e->modifiers())) {
 
680
            toggleActive();
 
681
            return;
 
682
        }
 
683
        if (m_mode == ModeAllDesktops && shortcutAll.contains(e->key() + e->modifiers())) {
 
684
            toggleActiveAllDesktops();
 
685
            return;
 
686
        }
 
687
        if (m_mode == ModeWindowClass && shortcutClass.contains(e->key() + e->modifiers())) {
 
688
            toggleActiveClass();
 
689
            return;
 
690
        }
 
691
 
 
692
        switch(e->key()) {
 
693
            // Wrap only if not auto-repeating
 
694
        case Qt::Key_Left:
 
695
            if (m_highlightedWindow)
 
696
                setHighlightedWindow(relativeWindow(m_highlightedWindow, -1, 0, !e->isAutoRepeat()));
 
697
            break;
 
698
        case Qt::Key_Right:
 
699
            if (m_highlightedWindow)
 
700
                setHighlightedWindow(relativeWindow(m_highlightedWindow, 1, 0, !e->isAutoRepeat()));
 
701
            break;
 
702
        case Qt::Key_Up:
 
703
            if (m_highlightedWindow)
 
704
                setHighlightedWindow(relativeWindow(m_highlightedWindow, 0, -1, !e->isAutoRepeat()));
 
705
            break;
 
706
        case Qt::Key_Down:
 
707
            if (m_highlightedWindow)
 
708
                setHighlightedWindow(relativeWindow(m_highlightedWindow, 0, 1, !e->isAutoRepeat()));
 
709
            break;
 
710
        case Qt::Key_Home:
 
711
            if (m_highlightedWindow)
 
712
                setHighlightedWindow(relativeWindow(m_highlightedWindow, -1000, 0, false));
 
713
            break;
 
714
        case Qt::Key_End:
 
715
            if (m_highlightedWindow)
 
716
                setHighlightedWindow(relativeWindow(m_highlightedWindow, 1000, 0, false));
 
717
            break;
 
718
        case Qt::Key_PageUp:
 
719
            if (m_highlightedWindow)
 
720
                setHighlightedWindow(relativeWindow(m_highlightedWindow, 0, -1000, false));
 
721
            break;
 
722
        case Qt::Key_PageDown:
 
723
            if (m_highlightedWindow)
 
724
                setHighlightedWindow(relativeWindow(m_highlightedWindow, 0, 1000, false));
 
725
            break;
 
726
        case Qt::Key_Backspace:
 
727
            if (!m_windowFilter.isEmpty()) {
 
728
                m_windowFilter.remove(m_windowFilter.length() - 1, 1);
 
729
                updateFilterFrame();
 
730
                rearrangeWindows();
 
731
            }
 
732
            return;
 
733
        case Qt::Key_Escape:
 
734
            setActive(false);
 
735
            return;
 
736
        case Qt::Key_Return:
 
737
        case Qt::Key_Enter:
 
738
            if (m_highlightedWindow)
 
739
                effects->activateWindow(m_highlightedWindow);
 
740
            setActive(false);
 
741
            return;
 
742
        case Qt::Key_Tab:
 
743
            return; // Nothing at the moment
 
744
        case Qt::Key_Delete:
 
745
            if (!m_windowFilter.isEmpty()) {
 
746
                m_windowFilter.clear();
 
747
                updateFilterFrame();
 
748
                rearrangeWindows();
 
749
            }
 
750
            break;
 
751
        case 0:
 
752
            return; // HACK: Workaround for Qt bug on unbound keys (#178547)
 
753
        default:
 
754
            if (!e->text().isEmpty()) {
 
755
                m_windowFilter.append(e->text());
 
756
                updateFilterFrame();
 
757
                rearrangeWindows();
 
758
                return;
 
759
            }
 
760
            break;
 
761
        }
 
762
    }
 
763
}
 
764
 
 
765
//-----------------------------------------------------------------------------
 
766
// Tab box
 
767
 
 
768
void PresentWindowsEffect::slotTabBoxAdded(int mode)
 
769
{
 
770
    if (effects->activeFullScreenEffect() && effects->activeFullScreenEffect() != this)
 
771
        return;
 
772
    if (m_activated)
 
773
        return;
 
774
    if (((mode == TabBoxWindowsMode && m_tabBoxAllowed) ||
 
775
            (mode == TabBoxWindowsAlternativeMode && m_tabBoxAlternativeAllowed)) &&
 
776
            effects->currentTabBoxWindowList().count() > 0) {
 
777
        m_tabBoxEnabled = true;
 
778
        setActive(true);
 
779
        if (m_activated)
 
780
            effects->refTabBox();
 
781
        else
 
782
            m_tabBoxEnabled = false;
 
783
    }
 
784
}
 
785
 
 
786
void PresentWindowsEffect::slotTabBoxClosed()
 
787
{
 
788
    if (m_activated) {
 
789
        effects->unrefTabBox();
 
790
        setActive(false, true);
 
791
        m_tabBoxEnabled = false;
 
792
    }
 
793
}
 
794
 
 
795
void PresentWindowsEffect::slotTabBoxUpdated()
 
796
{
 
797
    if (m_activated)
 
798
        setHighlightedWindow(effects->currentTabBoxWindow());
 
799
}
 
800
 
 
801
void PresentWindowsEffect::slotTabBoxKeyEvent(QKeyEvent* event)
 
802
{
 
803
    if (!m_activated)
 
804
        return;
 
805
    // not using the "normal" grabbedKeyboardEvent as we don't want to filter in tabbox
 
806
    if (event->type() == QEvent::KeyPress) {
 
807
        switch(event->key()) {
 
808
            // Wrap only if not auto-repeating
 
809
        case Qt::Key_Left:
 
810
            setHighlightedWindow(relativeWindow(m_highlightedWindow, -1, 0, !event->isAutoRepeat()));
 
811
            break;
 
812
        case Qt::Key_Right:
 
813
            setHighlightedWindow(relativeWindow(m_highlightedWindow, 1, 0, !event->isAutoRepeat()));
 
814
            break;
 
815
        case Qt::Key_Up:
 
816
            setHighlightedWindow(relativeWindow(m_highlightedWindow, 0, -1, !event->isAutoRepeat()));
 
817
            break;
 
818
        case Qt::Key_Down:
 
819
            setHighlightedWindow(relativeWindow(m_highlightedWindow, 0, 1, !event->isAutoRepeat()));
 
820
            break;
 
821
        case Qt::Key_Home:
 
822
            setHighlightedWindow(relativeWindow(m_highlightedWindow, -1000, 0, false));
 
823
            break;
 
824
        case Qt::Key_End:
 
825
            setHighlightedWindow(relativeWindow(m_highlightedWindow, 1000, 0, false));
 
826
            break;
 
827
        case Qt::Key_PageUp:
 
828
            setHighlightedWindow(relativeWindow(m_highlightedWindow, 0, -1000, false));
 
829
            break;
 
830
        case Qt::Key_PageDown:
 
831
            setHighlightedWindow(relativeWindow(m_highlightedWindow, 0, 1000, false));
 
832
            break;
 
833
        default:
 
834
            // nothing
 
835
            break;
 
836
        }
 
837
    }
 
838
}
 
839
 
 
840
//-----------------------------------------------------------------------------
 
841
// Atom handling
 
842
void PresentWindowsEffect::slotPropertyNotify(EffectWindow* w, long a)
 
843
{
 
844
    if (!w || (a != m_atomDesktop && a != m_atomWindows))
 
845
        return; // Not our atom
 
846
 
 
847
    if (a == m_atomDesktop) {
 
848
        QByteArray byteData = w->readProperty(m_atomDesktop, m_atomDesktop, 32);
 
849
        if (byteData.length() < 1) {
 
850
            // Property was removed, end present windows
 
851
            setActive(false);
 
852
            return;
 
853
        }
 
854
        long* data = reinterpret_cast<long*>(byteData.data());
 
855
 
 
856
        if (!data[0]) {
 
857
            // Purposely ending present windows by issuing a NULL target
 
858
            setActive(false);
 
859
            return;
 
860
        }
 
861
        // present windows is active so don't do anything
 
862
        if (m_activated)
 
863
            return;
 
864
 
 
865
        int desktop = data[0];
 
866
        if (desktop > effects->numberOfDesktops())
 
867
            return;
 
868
        if (desktop == -1)
 
869
            toggleActiveAllDesktops();
 
870
        else {
 
871
            m_mode = ModeSelectedDesktop;
 
872
            m_desktop = desktop;
 
873
            m_managerWindow = w;
 
874
            setActive(true);
 
875
        }
 
876
    } else if (a == m_atomWindows) {
 
877
        QByteArray byteData = w->readProperty(m_atomWindows, m_atomWindows, 32);
 
878
        if (byteData.length() < 1) {
 
879
            // Property was removed, end present windows
 
880
            setActive(false);
 
881
            return;
 
882
        }
 
883
        long* data = reinterpret_cast<long*>(byteData.data());
 
884
 
 
885
        if (!data[0]) {
 
886
            // Purposely ending present windows by issuing a NULL target
 
887
            setActive(false);
 
888
            return;
 
889
        }
 
890
        // present windows is active so don't do anything
 
891
        if (m_activated)
 
892
            return;
 
893
 
 
894
        // for security clear selected windows
 
895
        m_selectedWindows.clear();
 
896
        int length = byteData.length() / sizeof(data[0]);
 
897
        for (int i = 0; i < length; i++) {
 
898
            EffectWindow* foundWin = effects->findWindow(data[i]);
 
899
            if (!foundWin) {
 
900
                kDebug(1212) << "Invalid window targetted for present windows. Requested:" << data[i];
 
901
                continue;
 
902
            }
 
903
            m_selectedWindows.append(foundWin);
 
904
        }
 
905
        m_mode = ModeWindowGroup;
 
906
        m_managerWindow = w;
 
907
        setActive(true);
 
908
    }
 
909
}
 
910
 
 
911
//-----------------------------------------------------------------------------
 
912
// Window rearranging
 
913
 
 
914
void PresentWindowsEffect::rearrangeWindows()
 
915
{
 
916
    if (!m_activated)
 
917
        return;
 
918
 
 
919
    effects->addRepaintFull(); // Trigger the first repaint
 
920
    m_closeView->hide();
 
921
 
 
922
    // Work out which windows are on which screens
 
923
    EffectWindowList windowlist;
 
924
    QList<EffectWindowList> windowlists;
 
925
    for (int i = 0; i < effects->numScreens(); i++)
 
926
        windowlists.append(EffectWindowList());
 
927
 
 
928
    if (m_windowFilter.isEmpty()) {
 
929
        if (m_tabBoxEnabled)
 
930
            // Assume we correctly set things up, should be identical to
 
931
            // m_motionManager except just in a slightly different order.
 
932
            windowlist = effects->currentTabBoxWindowList();
 
933
        else
 
934
            windowlist = m_motionManager.managedWindows();
 
935
        foreach (EffectWindow * w, m_motionManager.managedWindows()) {
 
936
            DataHash::iterator winData = m_windowData.find(w);
 
937
            if (winData == m_windowData.end() || winData->deleted)
 
938
                continue; // don't include closed windows
 
939
            windowlists[w->screen()].append(w);
 
940
            winData->visible = true;
 
941
        }
 
942
    } else {
 
943
        // Can we move this filtering somewhere else?
 
944
        foreach (EffectWindow * w, m_motionManager.managedWindows()) {
 
945
            DataHash::iterator winData = m_windowData.find(w);
 
946
            if (winData == m_windowData.end() || winData->deleted)
 
947
                continue; // don't include closed windows
 
948
            if (w->caption().contains(m_windowFilter, Qt::CaseInsensitive) ||
 
949
                    w->windowClass().contains(m_windowFilter, Qt::CaseInsensitive) ||
 
950
                    w->windowRole().contains(m_windowFilter, Qt::CaseInsensitive)) {
 
951
                windowlist.append(w);
 
952
                windowlists[w->screen()].append(w);
 
953
                winData->visible = true;
 
954
            } else
 
955
                winData->visible = false;
 
956
        }
 
957
    }
 
958
    if (windowlist.isEmpty()) {
 
959
        setHighlightedWindow(NULL);   // TODO: Having a NULL highlighted window isn't really safe
 
960
        return;
 
961
    }
 
962
 
 
963
    // We filtered out the highlighted window
 
964
    if (m_highlightedWindow) {
 
965
        DataHash::iterator winData = m_windowData.find(m_highlightedWindow);
 
966
        if (winData != m_windowData.end() && !winData->visible)
 
967
            setHighlightedWindow(findFirstWindow());
 
968
    } else if (m_tabBoxEnabled)
 
969
        setHighlightedWindow(effects->currentTabBoxWindow());
 
970
    else
 
971
        setHighlightedWindow(findFirstWindow());
 
972
 
 
973
    int screens = m_tabBoxEnabled ? 1 : effects->numScreens();
 
974
    for (int screen = 0; screen < screens; screen++) {
 
975
        EffectWindowList windows;
 
976
        if (m_tabBoxEnabled) {
 
977
            // Kind of cheating here
 
978
            screen = effects->activeScreen();
 
979
            windows = windowlist;
 
980
        } else
 
981
            windows = windowlists[screen];
 
982
 
 
983
        // Don't rearrange if the grid is the same size as what it was before to prevent
 
984
        // windows moving to a better spot if one was filtered out.
 
985
        if (m_layoutMode == LayoutRegularGrid &&
 
986
                m_gridSizes[screen].columns * m_gridSizes[screen].rows &&
 
987
                windows.size() < m_gridSizes[screen].columns * m_gridSizes[screen].rows &&
 
988
                windows.size() > (m_gridSizes[screen].columns - 1) * m_gridSizes[screen].rows &&
 
989
                windows.size() > m_gridSizes[screen].columns *(m_gridSizes[screen].rows - 1) &&
 
990
                !m_tabBoxEnabled)
 
991
            continue;
 
992
 
 
993
        // No point continuing if there is no windows to process
 
994
        if (!windows.count())
 
995
            continue;
 
996
 
 
997
        calculateWindowTransformations(windows, screen, m_motionManager);
 
998
    }
 
999
 
 
1000
    // Resize text frames if required
 
1001
    QFontMetrics* metrics = NULL; // All fonts are the same
 
1002
    foreach (EffectWindow * w, m_motionManager.managedWindows()) {
 
1003
        DataHash::iterator winData = m_windowData.find(w);
 
1004
        if (winData == m_windowData.end())
 
1005
            continue;
 
1006
        if (!metrics)
 
1007
            metrics = new QFontMetrics(winData->textFrame->font());
 
1008
        QRect geom = m_motionManager.targetGeometry(w).toRect();
 
1009
        QString string = metrics->elidedText(w->caption(), Qt::ElideRight, geom.width() * 0.9);
 
1010
        if (string != winData->textFrame->text())
 
1011
            winData->textFrame->setText(string);
 
1012
    }
 
1013
    delete metrics;
 
1014
}
 
1015
 
 
1016
void PresentWindowsEffect::calculateWindowTransformations(EffectWindowList windowlist, int screen,
 
1017
        WindowMotionManager& motionManager, bool external)
 
1018
{
 
1019
    if (m_layoutMode == LayoutRegularGrid || m_tabBoxEnabled)   // Force the grid for window switching
 
1020
        calculateWindowTransformationsClosest(windowlist, screen, motionManager);
 
1021
    else if (m_layoutMode == LayoutFlexibleGrid)
 
1022
        calculateWindowTransformationsKompose(windowlist, screen, motionManager);
 
1023
    else
 
1024
        calculateWindowTransformationsNatural(windowlist, screen, motionManager);
 
1025
 
 
1026
    // If called externally we don't need to remember this data
 
1027
    if (external)
 
1028
        m_windowData.clear();
 
1029
}
 
1030
 
 
1031
static inline int distance(QPoint &pos1, QPoint &pos2)
 
1032
{
 
1033
    const int xdiff = pos1.x() - pos2.x();
 
1034
    const int ydiff = pos1.y() - pos2.y();
 
1035
    return int(sqrt(float(xdiff*xdiff + ydiff*ydiff)));
 
1036
}
 
1037
 
 
1038
void PresentWindowsEffect::calculateWindowTransformationsClosest(EffectWindowList windowlist, int screen,
 
1039
        WindowMotionManager& motionManager)
 
1040
{
 
1041
    // This layout mode requires at least one window visible
 
1042
    if (windowlist.count() == 0)
 
1043
        return;
 
1044
 
 
1045
    QRect area = effects->clientArea(ScreenArea, screen, effects->currentDesktop());
 
1046
    if (m_showPanel)   // reserve space for the panel
 
1047
        area = effects->clientArea(MaximizeArea, screen, effects->currentDesktop());
 
1048
    int columns = int(ceil(sqrt(double(windowlist.count()))));
 
1049
    int rows = int(ceil(windowlist.count() / double(columns)));
 
1050
 
 
1051
    // Remember the size for later
 
1052
    // If we are using this layout externally we don't need to remember m_gridSizes.
 
1053
    if (m_gridSizes.size() != 0) {
 
1054
        m_gridSizes[screen].columns = columns;
 
1055
        m_gridSizes[screen].rows = rows;
 
1056
    }
 
1057
 
 
1058
    // Assign slots
 
1059
    int slotWidth = area.width() / columns;
 
1060
    int slotHeight = area.height() / rows;
 
1061
    QVector<EffectWindow*> takenSlots;
 
1062
    takenSlots.resize(rows*columns);
 
1063
    takenSlots.fill(0);
 
1064
 
 
1065
    if (m_tabBoxEnabled) {
 
1066
        // Rearrange in the correct order. As rearrangeWindows() is only ever
 
1067
        // called once so we can use effects->currentTabBoxWindow() here.
 
1068
        int selectedWindow = qMax(0, windowlist.indexOf(effects->currentTabBoxWindow()));
 
1069
        int j = 0;
 
1070
        for (int i = selectedWindow; i < windowlist.count(); ++i)
 
1071
            takenSlots[j++] = windowlist[i];
 
1072
        for (int i = selectedWindow - 1; i >= 0; --i)
 
1073
            takenSlots[j++] = windowlist[i];
 
1074
    } else {
 
1075
 
 
1076
        // precalculate all slot centers
 
1077
        QVector<QPoint> slotCenters;
 
1078
        slotCenters.resize(rows*columns);
 
1079
        for (int x = 0; x < columns; ++x)
 
1080
            for (int y = 0; y < rows; ++y) {
 
1081
                slotCenters[x + y*columns] = QPoint(area.x() + slotWidth * x + slotWidth / 2,
 
1082
                                                    area.y() + slotHeight * y + slotHeight / 2);
 
1083
            }
 
1084
 
 
1085
        // Assign each window to the closest available slot
 
1086
        EffectWindowList tmpList = windowlist; // use a QLinkedList copy instead?
 
1087
        QPoint otherPos;
 
1088
        while (!tmpList.isEmpty()) {
 
1089
            EffectWindow *w = tmpList.first();
 
1090
            int slotCandidate = -1, slotCandidateDistance = INT_MAX;
 
1091
            QPoint pos = w->geometry().center();
 
1092
            for (int i = 0; i < columns*rows; ++i) { // all slots
 
1093
                const int dist = distance(pos, slotCenters[i]);
 
1094
                if (dist < slotCandidateDistance) { // window is interested in this slot
 
1095
                    EffectWindow *occupier = takenSlots[i];
 
1096
                    assert(occupier != w);
 
1097
                    if (!occupier || dist < distance((otherPos = occupier->geometry().center()), slotCenters[i])) {
 
1098
                        // either nobody lives here, or we're better - takeover the slot if it's our best
 
1099
                        slotCandidate = i;
 
1100
                        slotCandidateDistance = dist;
 
1101
                    }
 
1102
                }
 
1103
            }
 
1104
            assert(slotCandidate != -1);
 
1105
            if (takenSlots[slotCandidate])
 
1106
                tmpList << takenSlots[slotCandidate]; // occupier needs a new home now :p
 
1107
            tmpList.removeAll(w);
 
1108
            takenSlots[slotCandidate] = w; // ...and we rumble in =)
 
1109
        }
 
1110
    }
 
1111
 
 
1112
    for (int slot = 0; slot < columns*rows; ++slot) {
 
1113
        EffectWindow *w = takenSlots[slot];
 
1114
        if (!w) // some slots might be empty
 
1115
            continue;
 
1116
 
 
1117
        // Work out where the slot is
 
1118
        QRect target(
 
1119
            area.x() + (slot % columns) * slotWidth,
 
1120
            area.y() + (slot / columns) * slotHeight,
 
1121
            slotWidth, slotHeight);
 
1122
        target.adjust(10, 10, -10, -10);   // Borders
 
1123
        double scale;
 
1124
        if (target.width() / double(w->width()) < target.height() / double(w->height())) {
 
1125
            // Center vertically
 
1126
            scale = target.width() / double(w->width());
 
1127
            target.moveTop(target.top() + (target.height() - int(w->height() * scale)) / 2);
 
1128
            target.setHeight(int(w->height() * scale));
 
1129
        } else {
 
1130
            // Center horizontally
 
1131
            scale = target.height() / double(w->height());
 
1132
            target.moveLeft(target.left() + (target.width() - int(w->width() * scale)) / 2);
 
1133
            target.setWidth(int(w->width() * scale));
 
1134
        }
 
1135
        // Don't scale the windows too much
 
1136
        if (scale > 2.0 || (scale > 1.0 && (w->width() > 300 || w->height() > 300))) {
 
1137
            scale = (w->width() > 300 || w->height() > 300) ? 1.0 : 2.0;
 
1138
            target = QRect(
 
1139
                         target.center().x() - int(w->width() * scale) / 2,
 
1140
                         target.center().y() - int(w->height() * scale) / 2,
 
1141
                         scale * w->width(), scale * w->height());
 
1142
        }
 
1143
        motionManager.moveWindow(w, target);
 
1144
    }
 
1145
}
 
1146
 
 
1147
void PresentWindowsEffect::calculateWindowTransformationsKompose(EffectWindowList windowlist, int screen,
 
1148
        WindowMotionManager& motionManager)
 
1149
{
 
1150
    // This layout mode requires at least one window visible
 
1151
    if (windowlist.count() == 0)
 
1152
        return;
 
1153
 
 
1154
    QRect availRect = effects->clientArea(ScreenArea, screen, effects->currentDesktop());
 
1155
    if (m_showPanel)   // reserve space for the panel
 
1156
        availRect = effects->clientArea(MaximizeArea, screen, effects->currentDesktop());
 
1157
    qSort(windowlist);   // The location of the windows should not depend on the stacking order
 
1158
 
 
1159
    // Following code is taken from Kompose 0.5.4, src/komposelayout.cpp
 
1160
 
 
1161
    int spacing = 10;
 
1162
    int rows, columns;
 
1163
    double parentRatio = availRect.width() / (double)availRect.height();
 
1164
    // Use more columns than rows when parent's width > parent's height
 
1165
    if (parentRatio > 1) {
 
1166
        columns = (int)ceil(sqrt((double)windowlist.count()));
 
1167
        rows = (int)ceil((double)windowlist.count() / (double)columns);
 
1168
    } else {
 
1169
        rows = (int)ceil(sqrt((double)windowlist.count()));
 
1170
        columns = (int)ceil((double)windowlist.count() / (double)rows);
 
1171
    }
 
1172
    //kDebug(1212) << "Using " << rows << " rows & " << columns << " columns for " << windowlist.count() << " clients";
 
1173
 
 
1174
    // Calculate width & height
 
1175
    int w = (availRect.width() - (columns + 1) * spacing) / columns;
 
1176
    int h = (availRect.height() - (rows + 1) * spacing) / rows;
 
1177
 
 
1178
    EffectWindowList::iterator it(windowlist.begin());
 
1179
    QList<QRect> geometryRects;
 
1180
    QList<int> maxRowHeights;
 
1181
    // Process rows
 
1182
    for (int i = 0; i < rows; ++i) {
 
1183
        int xOffsetFromLastCol = 0;
 
1184
        int maxHeightInRow = 0;
 
1185
        // Process columns
 
1186
        for (int j = 0; j < columns; ++j) {
 
1187
            EffectWindow* window;
 
1188
 
 
1189
            // Check for end of List
 
1190
            if (it == windowlist.end())
 
1191
                break;
 
1192
            window = *it;
 
1193
 
 
1194
            // Calculate width and height of widget
 
1195
            double ratio = aspectRatio(window);
 
1196
 
 
1197
            int widgetw = 100;
 
1198
            int widgeth = 100;
 
1199
            int usableW = w;
 
1200
            int usableH = h;
 
1201
 
 
1202
            // use width of two boxes if there is no right neighbour
 
1203
            if (window == windowlist.last() && j != columns - 1) {
 
1204
                usableW = 2 * w;
 
1205
            }
 
1206
            ++it; // We need access to the neighbour in the following
 
1207
            // expand if right neighbour has ratio < 1
 
1208
            if (j != columns - 1 && it != windowlist.end() && aspectRatio(*it) < 1) {
 
1209
                int addW = w - widthForHeight(*it, h);
 
1210
                if (addW > 0) {
 
1211
                    usableW = w + addW;
 
1212
                }
 
1213
            }
 
1214
 
 
1215
            if (ratio == -1) {
 
1216
                widgetw = w;
 
1217
                widgeth = h;
 
1218
            } else {
 
1219
                double widthByHeight = widthForHeight(window, usableH);
 
1220
                double heightByWidth = heightForWidth(window, usableW);
 
1221
                if ((ratio >= 1.0 && heightByWidth <= usableH) ||
 
1222
                        (ratio < 1.0 && widthByHeight > usableW)) {
 
1223
                    widgetw = usableW;
 
1224
                    widgeth = (int)heightByWidth;
 
1225
                } else if ((ratio < 1.0 && widthByHeight <= usableW) ||
 
1226
                          (ratio >= 1.0 && heightByWidth > usableH)) {
 
1227
                    widgeth = usableH;
 
1228
                    widgetw = (int)widthByHeight;
 
1229
                }
 
1230
                // Don't upscale large-ish windows
 
1231
                if (widgetw > window->width() && (window->width() > 300 || window->height() > 300)) {
 
1232
                    widgetw = window->width();
 
1233
                    widgeth = window->height();
 
1234
                }
 
1235
            }
 
1236
 
 
1237
            // Set the Widget's size
 
1238
 
 
1239
            int alignmentXoffset = 0;
 
1240
            int alignmentYoffset = 0;
 
1241
            if (i == 0 && h > widgeth)
 
1242
                alignmentYoffset = h - widgeth;
 
1243
            if (j == 0 && w > widgetw)
 
1244
                alignmentXoffset = w - widgetw;
 
1245
            QRect geom(availRect.x() + j *(w + spacing) + spacing + alignmentXoffset + xOffsetFromLastCol,
 
1246
                       availRect.y() + i *(h + spacing) + spacing + alignmentYoffset,
 
1247
                       widgetw, widgeth);
 
1248
            geometryRects.append(geom);
 
1249
 
 
1250
            // Set the x offset for the next column
 
1251
            if (alignmentXoffset == 0)
 
1252
                xOffsetFromLastCol += widgetw - w;
 
1253
            if (maxHeightInRow < widgeth)
 
1254
                maxHeightInRow = widgeth;
 
1255
        }
 
1256
        maxRowHeights.append(maxHeightInRow);
 
1257
    }
 
1258
 
 
1259
    int topOffset = 0;
 
1260
    for (int i = 0; i < rows; i++) {
 
1261
        for (int j = 0; j < columns; j++) {
 
1262
            int pos = i * columns + j;
 
1263
            if (pos >= windowlist.count())
 
1264
                break;
 
1265
 
 
1266
            EffectWindow* window = windowlist[pos];
 
1267
            QRect target = geometryRects[pos];
 
1268
            target.setY(target.y() + topOffset);
 
1269
            // @Marrtin: any idea what this is good for?
 
1270
//             DataHash::iterator winData = m_windowData.find(window);
 
1271
//             if (winData != m_windowData.end())
 
1272
//                 winData->slot = pos;
 
1273
            motionManager.moveWindow(window, target);
 
1274
 
 
1275
            //kDebug(1212) << "Window '" << window->caption() << "' gets moved to (" <<
 
1276
            //        mWindowData[window].area.left() << "; " << mWindowData[window].area.right() <<
 
1277
            //        "), scale: " << mWindowData[window].scale << endl;
 
1278
        }
 
1279
        if (maxRowHeights[i] - h > 0)
 
1280
            topOffset += maxRowHeights[i] - h;
 
1281
    }
 
1282
}
 
1283
 
 
1284
void PresentWindowsEffect::calculateWindowTransformationsNatural(EffectWindowList windowlist, int screen,
 
1285
        WindowMotionManager& motionManager)
 
1286
{
 
1287
    // If windows do not overlap they scale into nothingness, fix by resetting. To reproduce
 
1288
    // just have a single window on a Xinerama screen or have two windows that do not touch.
 
1289
    // TODO: Work out why this happens, is most likely a bug in the manager.
 
1290
    foreach (EffectWindow * w, windowlist)
 
1291
        if (motionManager.transformedGeometry(w) == w->geometry())
 
1292
            motionManager.reset(w);
 
1293
 
 
1294
    if (windowlist.count() == 1) {
 
1295
        // Just move the window to its original location to save time
 
1296
        if (effects->clientArea(FullScreenArea, windowlist[0]).contains(windowlist[0]->geometry())) {
 
1297
            motionManager.moveWindow(windowlist[0], windowlist[0]->geometry());
 
1298
            return;
 
1299
        }
 
1300
    }
 
1301
 
 
1302
    // As we are using pseudo-random movement (See "slot") we need to make sure the list
 
1303
    // is always sorted the same way no matter which window is currently active.
 
1304
    qSort(windowlist);
 
1305
 
 
1306
    QRect area = effects->clientArea(ScreenArea, screen, effects->currentDesktop());
 
1307
    if (m_showPanel)   // reserve space for the panel
 
1308
        area = effects->clientArea(MaximizeArea, screen, effects->currentDesktop());
 
1309
    QRect bounds = area;
 
1310
    int direction = 0;
 
1311
    QHash<EffectWindow*, QRect> targets;
 
1312
    QHash<EffectWindow*, int> directions;
 
1313
    foreach (EffectWindow * w, windowlist) {
 
1314
        bounds = bounds.united(w->geometry());
 
1315
        targets[w] = w->geometry();
 
1316
        // Reuse the unused "slot" as a preferred direction attribute. This is used when the window
 
1317
        // is on the edge of the screen to try to use as much screen real estate as possible.
 
1318
        directions[w] = direction;
 
1319
        direction++;
 
1320
        if (direction == 4)
 
1321
            direction = 0;
 
1322
    }
 
1323
 
 
1324
    // Iterate over all windows, if two overlap push them apart _slightly_ as we try to
 
1325
    // brute-force the most optimal positions over many iterations.
 
1326
    bool overlap;
 
1327
    do {
 
1328
        overlap = false;
 
1329
        foreach (EffectWindow * w, windowlist) {
 
1330
            QRect *target_w = &targets[w];
 
1331
            foreach (EffectWindow * e, windowlist) {
 
1332
                if (w == e)
 
1333
                    continue;
 
1334
                QRect *target_e = &targets[e];
 
1335
                if (target_w->adjusted(-5, -5, 5, 5).intersects(target_e->adjusted(-5, -5, 5, 5))) {
 
1336
                    overlap = true;
 
1337
 
 
1338
                    // Determine pushing direction
 
1339
                    QPoint diff(target_e->center() - target_w->center());
 
1340
                    // Prevent dividing by zero and non-movement
 
1341
                    if (diff.x() == 0 && diff.y() == 0)
 
1342
                        diff.setX(1);
 
1343
                    // Try to keep screen aspect ratio
 
1344
                    //if (bounds.height() / bounds.width() > area.height() / area.width())
 
1345
                    //    diff.setY(diff.y() / 2);
 
1346
                    //else
 
1347
                    //    diff.setX(diff.x() / 2);
 
1348
                    // Approximate a vector of between 10px and 20px in magnitude in the same direction
 
1349
                    diff *= m_accuracy / double(diff.manhattanLength());
 
1350
                    // Move both windows apart
 
1351
                    target_w->translate(-diff);
 
1352
                    target_e->translate(diff);
 
1353
 
 
1354
                    // Try to keep the bounding rect the same aspect as the screen so that more
 
1355
                    // screen real estate is utilised. We do this by splitting the screen into nine
 
1356
                    // equal sections, if the window center is in any of the corner sections pull the
 
1357
                    // window towards the outer corner. If it is in any of the other edge sections
 
1358
                    // alternate between each corner on that edge. We don't want to determine it
 
1359
                    // randomly as it will not produce consistant locations when using the filter.
 
1360
                    // Only move one window so we don't cause large amounts of unnecessary zooming
 
1361
                    // in some situations. We need to do this even when expanding later just in case
 
1362
                    // all windows are the same size.
 
1363
                    // (We are using an old bounding rect for this, hopefully it doesn't matter)
 
1364
                    int xSection = (target_w->x() - bounds.x()) / (bounds.width() / 3);
 
1365
                    int ySection = (target_w->y() - bounds.y()) / (bounds.height() / 3);
 
1366
                    diff = QPoint(0, 0);
 
1367
                    if (xSection != 1 || ySection != 1) { // Remove this if you want the center to pull as well
 
1368
                        if (xSection == 1)
 
1369
                            xSection = (directions[w] / 2 ? 2 : 0);
 
1370
                        if (ySection == 1)
 
1371
                            ySection = (directions[w] % 2 ? 2 : 0);
 
1372
                    }
 
1373
                    if (xSection == 0 && ySection == 0)
 
1374
                        diff = QPoint(bounds.topLeft() - target_w->center());
 
1375
                    if (xSection == 2 && ySection == 0)
 
1376
                        diff = QPoint(bounds.topRight() - target_w->center());
 
1377
                    if (xSection == 2 && ySection == 2)
 
1378
                        diff = QPoint(bounds.bottomRight() - target_w->center());
 
1379
                    if (xSection == 0 && ySection == 2)
 
1380
                        diff = QPoint(bounds.bottomLeft() - target_w->center());
 
1381
                    if (diff.x() != 0 || diff.y() != 0) {
 
1382
                        diff *= m_accuracy / double(diff.manhattanLength());
 
1383
                        target_w->translate(diff);
 
1384
                    }
 
1385
 
 
1386
                    // Update bounding rect
 
1387
                    bounds = bounds.united(*target_w);
 
1388
                    bounds = bounds.united(*target_e);
 
1389
                }
 
1390
            }
 
1391
        }
 
1392
    } while (overlap);
 
1393
 
 
1394
    // Work out scaling by getting the most top-left and most bottom-right window coords.
 
1395
    // The 20's and 10's are so that the windows don't touch the edge of the screen.
 
1396
    double scale;
 
1397
    if (bounds == area)
 
1398
        scale = 1.0; // Don't add borders to the screen
 
1399
    else if (area.width() / double(bounds.width()) < area.height() / double(bounds.height()))
 
1400
        scale = (area.width() - 20) / double(bounds.width());
 
1401
    else
 
1402
        scale = (area.height() - 20) / double(bounds.height());
 
1403
    // Make bounding rect fill the screen size for later steps
 
1404
    bounds = QRect(
 
1405
                 bounds.x() - (area.width() - 20 - bounds.width() * scale) / 2 - 10 / scale,
 
1406
                 bounds.y() - (area.height() - 20 - bounds.height() * scale) / 2 - 10 / scale,
 
1407
                 area.width() / scale,
 
1408
                 area.height() / scale
 
1409
             );
 
1410
 
 
1411
    // Move all windows back onto the screen and set their scale
 
1412
    QHash<EffectWindow*, QRect>::iterator target = targets.begin();
 
1413
    while (target != targets.end()) {
 
1414
        target->setRect((target->x() - bounds.x()) * scale + area.x(),
 
1415
                        (target->y() - bounds.y()) * scale + area.y(),
 
1416
                        target->width() * scale,
 
1417
                        target->height() * scale
 
1418
                        );
 
1419
        ++target;
 
1420
    }
 
1421
 
 
1422
    // Try to fill the gaps by enlarging windows if they have the space
 
1423
    if (m_fillGaps) {
 
1424
        // Don't expand onto or over the border
 
1425
        QRegion borderRegion(area.adjusted(-200, -200, 200, 200));
 
1426
        borderRegion ^= area.adjusted(10 / scale, 10 / scale, -10 / scale, -10 / scale);
 
1427
 
 
1428
        bool moved;
 
1429
        do {
 
1430
            moved = false;
 
1431
            foreach (EffectWindow * w, windowlist) {
 
1432
                QRect oldRect;
 
1433
                QRect *target = &targets[w];
 
1434
                // This may cause some slight distortion if the windows are enlarged a large amount
 
1435
                int widthDiff = m_accuracy;
 
1436
                int heightDiff = heightForWidth(w, target->width() + widthDiff) - target->height();
 
1437
                int xDiff = widthDiff / 2;  // Also move a bit in the direction of the enlarge, allows the
 
1438
                int yDiff = heightDiff / 2; // center windows to be enlarged if there is gaps on the side.
 
1439
 
 
1440
                // Attempt enlarging to the top-right
 
1441
                oldRect = *target;
 
1442
                target->setRect(target->x() + xDiff,
 
1443
                                target->y() - yDiff - heightDiff,
 
1444
                                target->width() + widthDiff,
 
1445
                                target->height() + heightDiff
 
1446
                                );
 
1447
                if (isOverlappingAny(w, targets, borderRegion))
 
1448
                    *target = oldRect;
 
1449
                else
 
1450
                    moved = true;
 
1451
 
 
1452
                // Attempt enlarging to the bottom-right
 
1453
                oldRect = *target;
 
1454
                target->setRect(
 
1455
                                 target->x() + xDiff,
 
1456
                                 target->y() + yDiff,
 
1457
                                 target->width() + widthDiff,
 
1458
                                 target->height() + heightDiff
 
1459
                             );
 
1460
                if (isOverlappingAny(w, targets, borderRegion))
 
1461
                    *target = oldRect;
 
1462
                else
 
1463
                    moved = true;
 
1464
 
 
1465
                // Attempt enlarging to the bottom-left
 
1466
                oldRect = *target;
 
1467
                target->setRect(
 
1468
                                 target->x() - xDiff - widthDiff,
 
1469
                                 target->y() + yDiff,
 
1470
                                 target->width() + widthDiff,
 
1471
                                 target->height() + heightDiff
 
1472
                             );
 
1473
                if (isOverlappingAny(w, targets, borderRegion))
 
1474
                    *target = oldRect;
 
1475
                else
 
1476
                    moved = true;
 
1477
 
 
1478
                // Attempt enlarging to the top-left
 
1479
                oldRect = *target;
 
1480
                target->setRect(
 
1481
                                 target->x() - xDiff - widthDiff,
 
1482
                                 target->y() - yDiff - heightDiff,
 
1483
                                 target->width() + widthDiff,
 
1484
                                 target->height() + heightDiff
 
1485
                             );
 
1486
                if (isOverlappingAny(w, targets, borderRegion))
 
1487
                    *target = oldRect;
 
1488
                else
 
1489
                    moved = true;
 
1490
            }
 
1491
        } while (moved);
 
1492
 
 
1493
        // The expanding code above can actually enlarge windows over 1.0/2.0 scale, we don't like this
 
1494
        // We can't add this to the loop above as it would cause a never-ending loop so we have to make
 
1495
        // do with the less-than-optimal space usage with using this method.
 
1496
        foreach (EffectWindow * w, windowlist) {
 
1497
            QRect *target = &targets[w];
 
1498
            double scale = target->width() / double(w->width());
 
1499
            if (scale > 2.0 || (scale > 1.0 && (w->width() > 300 || w->height() > 300))) {
 
1500
                scale = (w->width() > 300 || w->height() > 300) ? 1.0 : 2.0;
 
1501
                target->setRect(
 
1502
                                 target->center().x() - int(w->width() * scale) / 2,
 
1503
                                 target->center().y() - int(w->height() * scale) / 2,
 
1504
                                 w->width() * scale,
 
1505
                                 w->height() * scale);
 
1506
            }
 
1507
        }
 
1508
    }
 
1509
 
 
1510
    // Notify the motion manager of the targets
 
1511
    foreach (EffectWindow * w, windowlist)
 
1512
        motionManager.moveWindow(w, targets.value(w));
 
1513
}
 
1514
 
 
1515
 
 
1516
bool PresentWindowsEffect::isOverlappingAny(EffectWindow *w, const QHash<EffectWindow*, QRect> &targets, const QRegion &border)
 
1517
{
 
1518
    QHash<EffectWindow*, QRect>::const_iterator winTarget = targets.find(w);
 
1519
    if (winTarget == targets.constEnd())
 
1520
        return false;
 
1521
    if (border.intersects(*winTarget))
 
1522
        return true;
 
1523
    // Is there a better way to do this?
 
1524
    QHash<EffectWindow*, QRect>::const_iterator target;
 
1525
    for (target = targets.constBegin(); target != targets.constEnd(); ++target) {
 
1526
        if (target == winTarget)
 
1527
            continue;
 
1528
        if (winTarget->adjusted(-5, -5, 5, 5).intersects(target->adjusted(-5, -5, 5, 5)))
 
1529
            return true;
 
1530
    }
 
1531
    return false;
 
1532
}
 
1533
 
 
1534
//-----------------------------------------------------------------------------
 
1535
// Activation
 
1536
 
 
1537
void PresentWindowsEffect::setActive(bool active, bool closingTab)
 
1538
{
 
1539
    if (effects->activeFullScreenEffect() && effects->activeFullScreenEffect() != this)
 
1540
        return;
 
1541
    if (m_activated == active)
 
1542
        return;
 
1543
    if (m_activated && m_tabBoxEnabled && !closingTab) {
 
1544
        effects->closeTabBox();
 
1545
        return;
 
1546
    }
 
1547
    m_activated = active;
 
1548
    if (m_activated) {
 
1549
        m_decalOpacity = 0.0;
 
1550
        m_highlightedWindow = NULL;
 
1551
        m_windowFilter.clear();
 
1552
 
 
1553
        m_closeView = new CloseWindowView();
 
1554
        connect(m_closeView, SIGNAL(close()), SLOT(closeWindow()));
 
1555
 
 
1556
        // Add every single window to m_windowData (Just calling [w] creates it)
 
1557
        foreach (EffectWindow * w, effects->stackingOrder()) {
 
1558
            DataHash::iterator winData;
 
1559
            if ((winData = m_windowData.find(w)) != m_windowData.end()) {
 
1560
                winData->visible = isVisibleWindow(w);
 
1561
                continue; // Happens if we reactivate before the ending animation finishes
 
1562
            }
 
1563
            winData = m_windowData.insert(w, WindowData());
 
1564
            winData->visible = isVisibleWindow(w);
 
1565
            winData->deleted = false;
 
1566
            winData->referenced = false;
 
1567
            winData->opacity = 0.0;
 
1568
            if (w->isOnCurrentDesktop() && !w->isMinimized())
 
1569
                winData->opacity = 1.0;
 
1570
            winData->highlight = 1.0;
 
1571
            winData->textFrame = effects->effectFrame(EffectFrameUnstyled, false);
 
1572
            QFont font;
 
1573
            font.setBold(true);
 
1574
            font.setPointSize(12);
 
1575
            winData->textFrame->setFont(font);
 
1576
            winData->iconFrame = effects->effectFrame(EffectFrameUnstyled, false);
 
1577
            winData->iconFrame->setAlignment(Qt::AlignRight | Qt::AlignBottom);
 
1578
            winData->iconFrame->setIcon(w->icon());
 
1579
        }
 
1580
 
 
1581
        if (m_tabBoxEnabled) {
 
1582
            DataHash::iterator winData;
 
1583
            foreach (EffectWindow * w, effects->currentTabBoxWindowList()) {
 
1584
                if (!w)
 
1585
                    continue;
 
1586
                m_motionManager.manage(w);
 
1587
                if ((winData = m_windowData.find(w)) != m_windowData.end())
 
1588
                    winData->visible = effects->currentTabBoxWindowList().contains(w);
 
1589
            }
 
1590
            // Hide windows not in the list
 
1591
            foreach (EffectWindow * w, effects->stackingOrder()) {
 
1592
                if ((winData = m_windowData.find(w)) != m_windowData.end())
 
1593
                    winData->visible = isVisibleWindow(w) &&
 
1594
                            (!isSelectableWindow(w) || effects->currentTabBoxWindowList().contains(w));
 
1595
            }
 
1596
        } else {
 
1597
            // Filter out special windows such as panels and taskbars
 
1598
            foreach (EffectWindow * w, effects->stackingOrder())
 
1599
            if (isSelectableWindow(w))
 
1600
                m_motionManager.manage(w);
 
1601
        }
 
1602
        if (m_motionManager.managedWindows().isEmpty() ||
 
1603
                ((m_motionManager.managedWindows().count() == 1) && m_motionManager.managedWindows().first()->isOnCurrentDesktop()  &&
 
1604
                 (m_ignoreMinimized || !m_motionManager.managedWindows().first()->isMinimized()))) {
 
1605
            // No point triggering if there is nothing to do
 
1606
            m_activated = false;
 
1607
 
 
1608
            DataHash::iterator i = m_windowData.begin();
 
1609
            while (i != m_windowData.end()) {
 
1610
                delete i.value().textFrame;
 
1611
                delete i.value().iconFrame;
 
1612
                ++i;
 
1613
            }
 
1614
            m_windowData.clear();
 
1615
 
 
1616
            m_motionManager.unmanageAll();
 
1617
            return;
 
1618
        }
 
1619
 
 
1620
        // Create temporary input window to catch mouse events
 
1621
        m_input = effects->createFullScreenInputWindow(this, Qt::PointingHandCursor);
 
1622
        m_hasKeyboardGrab = effects->grabKeyboard(this);
 
1623
        effects->setActiveFullScreenEffect(this);
 
1624
 
 
1625
        m_gridSizes.clear();
 
1626
        for (int i = 0; i < effects->numScreens(); ++i) {
 
1627
            m_gridSizes.append(GridSize());
 
1628
            if (m_dragToClose) {
 
1629
                const QRect screenRect = effects->clientArea(FullScreenArea, i, 1);
 
1630
                EffectFrame *frame = effects->effectFrame(EffectFrameNone, false);
 
1631
                KIcon icon("user-trash");
 
1632
                frame->setIcon(icon.pixmap(QSize(128, 128)));
 
1633
                frame->setPosition(QPoint(screenRect.x() + screenRect.width(), screenRect.y()));
 
1634
                frame->setAlignment(Qt::AlignRight | Qt::AlignTop);
 
1635
                m_dropTargets.append(frame);
 
1636
            }
 
1637
        }
 
1638
 
 
1639
        rearrangeWindows();
 
1640
        if (m_tabBoxEnabled)
 
1641
            setHighlightedWindow(effects->currentTabBoxWindow());
 
1642
        else
 
1643
            setHighlightedWindow(effects->activeWindow());
 
1644
 
 
1645
        foreach (EffectWindow * w, effects->stackingOrder()) {
 
1646
            if (w->isDock()) {
 
1647
                w->setData(WindowForceBlurRole, QVariant(true));
 
1648
            }
 
1649
        }
 
1650
    } else {
 
1651
        // Fade in/out all windows
 
1652
        EffectWindow *activeWindow = effects->activeWindow();
 
1653
        if (m_tabBoxEnabled)
 
1654
            activeWindow = effects->currentTabBoxWindow();
 
1655
        int desktop = effects->currentDesktop();
 
1656
        if (activeWindow && !activeWindow->isOnAllDesktops())
 
1657
            desktop = activeWindow->desktop();
 
1658
        foreach (EffectWindow * w, effects->stackingOrder()) {
 
1659
            DataHash::iterator winData = m_windowData.find(w);
 
1660
            if (winData != m_windowData.end())
 
1661
                winData->visible = (w->isOnDesktop(desktop) || w->isOnAllDesktops()) &&
 
1662
                                    !w->isMinimized() && (w->visibleInClientGroup() || winData->visible);
 
1663
        }
 
1664
        delete m_closeView;
 
1665
        m_closeView = 0;
 
1666
        while (!m_dropTargets.empty()) {
 
1667
            delete m_dropTargets.takeFirst();
 
1668
        }
 
1669
 
 
1670
        // Move all windows back to their original position
 
1671
        foreach (EffectWindow * w, m_motionManager.managedWindows())
 
1672
        m_motionManager.moveWindow(w, w->geometry());
 
1673
        m_filterFrame->free();
 
1674
        m_windowFilter.clear();
 
1675
        m_selectedWindows.clear();
 
1676
 
 
1677
        effects->destroyInputWindow(m_input);
 
1678
        if (m_hasKeyboardGrab)
 
1679
            effects->ungrabKeyboard();
 
1680
        m_hasKeyboardGrab = false;
 
1681
 
 
1682
        // destroy atom on manager window
 
1683
        if (m_managerWindow) {
 
1684
            if (m_mode == ModeSelectedDesktop)
 
1685
                m_managerWindow->deleteProperty(m_atomDesktop);
 
1686
            else if (m_mode == ModeWindowGroup)
 
1687
                m_managerWindow->deleteProperty(m_atomWindows);
 
1688
            m_managerWindow = NULL;
 
1689
        }
 
1690
    }
 
1691
    effects->addRepaintFull(); // Trigger the first repaint
 
1692
}
 
1693
 
 
1694
//-----------------------------------------------------------------------------
 
1695
// Filter box
 
1696
 
 
1697
void PresentWindowsEffect::updateFilterFrame()
 
1698
{
 
1699
    QRect area = effects->clientArea(ScreenArea, effects->activeScreen(), effects->currentDesktop());
 
1700
    m_filterFrame->setPosition(QPoint(area.x() + area.width() / 2, area.y() + area.height() / 2));
 
1701
    m_filterFrame->setText(i18n("Filter:\n%1", m_windowFilter));
 
1702
}
 
1703
 
 
1704
//-----------------------------------------------------------------------------
 
1705
// Helper functions
 
1706
 
 
1707
bool PresentWindowsEffect::isSelectableWindow(EffectWindow *w)
 
1708
{
 
1709
    if (!w->isOnCurrentActivity())
 
1710
        return false;
 
1711
    if (w->isSpecialWindow() || w->isUtility())
 
1712
        return false;
 
1713
    if (w->isDeleted())
 
1714
        return false;
 
1715
    if (!w->acceptsFocus())
 
1716
        return false;
 
1717
    if (!w->visibleInClientGroup())
 
1718
        return false;
 
1719
    if (w->isSkipSwitcher())
 
1720
        return false;
 
1721
    if (w == effects->findWindow(m_closeView->winId()))
 
1722
        return false;
 
1723
    if (m_tabBoxEnabled)
 
1724
        return true;
 
1725
    if (m_ignoreMinimized && w->isMinimized())
 
1726
        return false;
 
1727
    switch(m_mode) {
 
1728
    default:
 
1729
    case ModeAllDesktops:
 
1730
        return true;
 
1731
    case ModeCurrentDesktop:
 
1732
        return w->isOnCurrentDesktop();
 
1733
    case ModeSelectedDesktop:
 
1734
        return w->isOnDesktop(m_desktop);
 
1735
    case ModeWindowGroup:
 
1736
        return m_selectedWindows.contains(w);
 
1737
    case ModeWindowClass:
 
1738
        return m_class == w->windowClass();
 
1739
    }
 
1740
}
 
1741
 
 
1742
bool PresentWindowsEffect::isVisibleWindow(EffectWindow *w)
 
1743
{
 
1744
    if (w->isDesktop())
 
1745
        return true;
 
1746
    return isSelectableWindow(w);
 
1747
}
 
1748
 
 
1749
void PresentWindowsEffect::setHighlightedWindow(EffectWindow *w)
 
1750
{
 
1751
    if (w == m_highlightedWindow || (w != NULL && !m_motionManager.isManaging(w)))
 
1752
        return;
 
1753
 
 
1754
    m_closeView->hide();
 
1755
    if (m_highlightedWindow)
 
1756
        m_highlightedWindow->addRepaintFull(); // Trigger the first repaint
 
1757
    m_highlightedWindow = w;
 
1758
    if (m_highlightedWindow)
 
1759
        m_highlightedWindow->addRepaintFull(); // Trigger the first repaint
 
1760
 
 
1761
    if (m_tabBoxEnabled && m_highlightedWindow)
 
1762
        effects->setTabBoxWindow(w);
 
1763
    updateCloseWindow();
 
1764
}
 
1765
 
 
1766
void PresentWindowsEffect::updateCloseWindow()
 
1767
{
 
1768
    if (m_doNotCloseWindows)
 
1769
        return;
 
1770
    if (m_closeView->isVisible())
 
1771
        return;
 
1772
    if (!m_highlightedWindow) {
 
1773
        m_closeView->hide();
 
1774
        return;
 
1775
    }
 
1776
    const QRectF rect = m_motionManager.targetGeometry(m_highlightedWindow);
 
1777
    m_closeView->setGeometry(rect.x() + rect.width() - m_closeView->sceneRect().width(), rect.y(),
 
1778
                             m_closeView->sceneRect().width(), m_closeView->sceneRect().height());
 
1779
    if (rect.contains(effects->cursorPos()))
 
1780
        m_closeView->delayedShow();
 
1781
    else
 
1782
        m_closeView->hide();
 
1783
}
 
1784
 
 
1785
void PresentWindowsEffect::closeWindow()
 
1786
{
 
1787
    if (m_highlightedWindow)
 
1788
        m_highlightedWindow->closeWindow();
 
1789
}
 
1790
 
 
1791
EffectWindow* PresentWindowsEffect::relativeWindow(EffectWindow *w, int xdiff, int ydiff, bool wrap) const
 
1792
{
 
1793
    // TODO: Is it possible to select hidden windows?
 
1794
    EffectWindow* next;
 
1795
    QRect area = effects->clientArea(FullArea, 0, effects->currentDesktop());
 
1796
    QRect detectRect;
 
1797
 
 
1798
    // Detect across the width of the desktop
 
1799
    if (xdiff != 0) {
 
1800
        if (xdiff > 0) {
 
1801
            // Detect right
 
1802
            for (int i = 0; i < xdiff; i++) {
 
1803
                QRectF wArea = m_motionManager.transformedGeometry(w);
 
1804
                detectRect = QRect(0, wArea.y(), area.width(), wArea.height());
 
1805
                next = NULL;
 
1806
                foreach (EffectWindow * e, m_motionManager.managedWindows()) {
 
1807
                    DataHash::const_iterator winData = m_windowData.find(e);
 
1808
                    if (winData == m_windowData.end() || !winData->visible)
 
1809
                        continue;
 
1810
                    QRectF eArea = m_motionManager.transformedGeometry(e);
 
1811
                    if (eArea.intersects(detectRect) &&
 
1812
                            eArea.x() > wArea.x()) {
 
1813
                        if (next == NULL)
 
1814
                            next = e;
 
1815
                        else {
 
1816
                            QRectF nArea = m_motionManager.transformedGeometry(next);
 
1817
                            if (eArea.x() < nArea.x())
 
1818
                                next = e;
 
1819
                        }
 
1820
                    }
 
1821
                }
 
1822
                if (next == NULL) {
 
1823
                    if (wrap)   // We are at the right-most window, now get the left-most one to wrap
 
1824
                        return relativeWindow(w, -1000, 0, false);
 
1825
                    break; // No more windows to the right
 
1826
                }
 
1827
                w = next;
 
1828
            }
 
1829
            return w;
 
1830
        } else {
 
1831
            // Detect left
 
1832
            for (int i = 0; i < -xdiff; i++) {
 
1833
                QRectF wArea = m_motionManager.transformedGeometry(w);
 
1834
                detectRect = QRect(0, wArea.y(), area.width(), wArea.height());
 
1835
                next = NULL;
 
1836
                foreach (EffectWindow * e, m_motionManager.managedWindows()) {
 
1837
                    DataHash::const_iterator winData = m_windowData.find(e);
 
1838
                    if (winData == m_windowData.end() || !winData->visible)
 
1839
                        continue;
 
1840
                    QRectF eArea = m_motionManager.transformedGeometry(e);
 
1841
                    if (eArea.intersects(detectRect) &&
 
1842
                            eArea.x() + eArea.width() < wArea.x() + wArea.width()) {
 
1843
                        if (next == NULL)
 
1844
                            next = e;
 
1845
                        else {
 
1846
                            QRectF nArea = m_motionManager.transformedGeometry(next);
 
1847
                            if (eArea.x() + eArea.width() > nArea.x() + nArea.width())
 
1848
                                next = e;
 
1849
                        }
 
1850
                    }
 
1851
                }
 
1852
                if (next == NULL) {
 
1853
                    if (wrap)   // We are at the left-most window, now get the right-most one to wrap
 
1854
                        return relativeWindow(w, 1000, 0, false);
 
1855
                    break; // No more windows to the left
 
1856
                }
 
1857
                w = next;
 
1858
            }
 
1859
            return w;
 
1860
        }
 
1861
    }
 
1862
 
 
1863
    // Detect across the height of the desktop
 
1864
    if (ydiff != 0) {
 
1865
        if (ydiff > 0) {
 
1866
            // Detect down
 
1867
            for (int i = 0; i < ydiff; i++) {
 
1868
                QRectF wArea = m_motionManager.transformedGeometry(w);
 
1869
                detectRect = QRect(wArea.x(), 0, wArea.width(), area.height());
 
1870
                next = NULL;
 
1871
                foreach (EffectWindow * e, m_motionManager.managedWindows()) {
 
1872
                    DataHash::const_iterator winData = m_windowData.find(e);
 
1873
                    if (winData == m_windowData.end() || !winData->visible)
 
1874
                        continue;
 
1875
                    QRectF eArea = m_motionManager.transformedGeometry(e);
 
1876
                    if (eArea.intersects(detectRect) &&
 
1877
                            eArea.y() > wArea.y()) {
 
1878
                        if (next == NULL)
 
1879
                            next = e;
 
1880
                        else {
 
1881
                            QRectF nArea = m_motionManager.transformedGeometry(next);
 
1882
                            if (eArea.y() < nArea.y())
 
1883
                                next = e;
 
1884
                        }
 
1885
                    }
 
1886
                }
 
1887
                if (next == NULL) {
 
1888
                    if (wrap)   // We are at the bottom-most window, now get the top-most one to wrap
 
1889
                        return relativeWindow(w, 0, -1000, false);
 
1890
                    break; // No more windows to the bottom
 
1891
                }
 
1892
                w = next;
 
1893
            }
 
1894
            return w;
 
1895
        } else {
 
1896
            // Detect up
 
1897
            for (int i = 0; i < -ydiff; i++) {
 
1898
                QRectF wArea = m_motionManager.transformedGeometry(w);
 
1899
                detectRect = QRect(wArea.x(), 0, wArea.width(), area.height());
 
1900
                next = NULL;
 
1901
                foreach (EffectWindow * e, m_motionManager.managedWindows()) {
 
1902
                    DataHash::const_iterator winData = m_windowData.find(e);
 
1903
                    if (winData == m_windowData.end() || !winData->visible)
 
1904
                        continue;
 
1905
                    QRectF eArea = m_motionManager.transformedGeometry(e);
 
1906
                    if (eArea.intersects(detectRect) &&
 
1907
                            eArea.y() + eArea.height() < wArea.y() + wArea.height()) {
 
1908
                        if (next == NULL)
 
1909
                            next = e;
 
1910
                        else {
 
1911
                            QRectF nArea = m_motionManager.transformedGeometry(next);
 
1912
                            if (eArea.y() + eArea.height() > nArea.y() + nArea.height())
 
1913
                                next = e;
 
1914
                        }
 
1915
                    }
 
1916
                }
 
1917
                if (next == NULL) {
 
1918
                    if (wrap)   // We are at the top-most window, now get the bottom-most one to wrap
 
1919
                        return relativeWindow(w, 0, 1000, false);
 
1920
                    break; // No more windows to the top
 
1921
                }
 
1922
                w = next;
 
1923
            }
 
1924
            return w;
 
1925
        }
 
1926
    }
 
1927
 
 
1928
    abort(); // Should never get here
 
1929
}
 
1930
 
 
1931
EffectWindow* PresentWindowsEffect::findFirstWindow() const
 
1932
{
 
1933
    EffectWindow *topLeft = NULL;
 
1934
    QRectF topLeftGeometry;
 
1935
    foreach (EffectWindow * w, m_motionManager.managedWindows()) {
 
1936
        DataHash::const_iterator winData = m_windowData.find(w);
 
1937
        if (winData == m_windowData.end())
 
1938
            continue;
 
1939
        QRectF geometry = m_motionManager.transformedGeometry(w);
 
1940
        if (winData->visible == false)
 
1941
            continue; // Not visible
 
1942
        if (winData->deleted)
 
1943
            continue; // Window has been closed
 
1944
        if (topLeft == NULL) {
 
1945
            topLeft = w;
 
1946
            topLeftGeometry = geometry;
 
1947
        } else if (geometry.x() < topLeftGeometry.x() || geometry.y() < topLeftGeometry.y()) {
 
1948
            topLeft = w;
 
1949
            topLeftGeometry = geometry;
 
1950
        }
 
1951
    }
 
1952
    return topLeft;
 
1953
}
 
1954
 
 
1955
void PresentWindowsEffect::globalShortcutChanged(const QKeySequence& seq)
 
1956
{
 
1957
    shortcut = KShortcut(seq);
 
1958
}
 
1959
 
 
1960
void PresentWindowsEffect::globalShortcutChangedAll(const QKeySequence& seq)
 
1961
{
 
1962
    shortcutAll = KShortcut(seq);
 
1963
}
 
1964
 
 
1965
void PresentWindowsEffect::globalShortcutChangedClass(const QKeySequence& seq)
 
1966
{
 
1967
    shortcutClass = KShortcut(seq);
 
1968
}
 
1969
 
 
1970
/************************************************
 
1971
* CloseWindowView
 
1972
************************************************/
 
1973
CloseWindowView::CloseWindowView(QWidget* parent)
 
1974
    : QGraphicsView(parent)
 
1975
    , m_delayedShowTimer(new QTimer(this))
 
1976
{
 
1977
    setWindowFlags(Qt::X11BypassWindowManagerHint);
 
1978
    setAttribute(Qt::WA_TranslucentBackground);
 
1979
    setFrameShape(QFrame::NoFrame);
 
1980
    QPalette pal = palette();
 
1981
    pal.setColor(backgroundRole(), Qt::transparent);
 
1982
    setPalette(pal);
 
1983
    setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
 
1984
    setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
 
1985
 
 
1986
    // setup the scene
 
1987
    QGraphicsScene* scene = new QGraphicsScene(this);
 
1988
    m_closeButton = new Plasma::PushButton();
 
1989
    m_closeButton->setIcon(KIcon("window-close"));
 
1990
    scene->addItem(m_closeButton);
 
1991
    connect(m_closeButton, SIGNAL(clicked()), SIGNAL(close()));
 
1992
 
 
1993
    QGraphicsLinearLayout *layout = new QGraphicsLinearLayout;
 
1994
    layout->addItem(m_closeButton);
 
1995
 
 
1996
    QGraphicsWidget *form = new QGraphicsWidget;
 
1997
    form->setLayout(layout);
 
1998
    form->setGeometry(0, 0, 32, 32);
 
1999
    scene->addItem(form);
 
2000
 
 
2001
    m_frame = new Plasma::FrameSvg(this);
 
2002
    m_frame->setImagePath("dialogs/background");
 
2003
    m_frame->setCacheAllRenderedFrames(true);
 
2004
    m_frame->setEnabledBorders(Plasma::FrameSvg::AllBorders);
 
2005
    qreal left, top, right, bottom;
 
2006
    m_frame->getMargins(left, top, right, bottom);
 
2007
    qreal width = form->size().width() + left + right;
 
2008
    qreal height = form->size().height() + top + bottom;
 
2009
    m_frame->resizeFrame(QSizeF(width, height));
 
2010
    Plasma::WindowEffects::enableBlurBehind(winId(), true, m_frame->mask());
 
2011
    Plasma::WindowEffects::overrideShadow(winId(), true);
 
2012
    form->setPos(left, top);
 
2013
    scene->setSceneRect(QRectF(QPointF(0, 0), QSizeF(width, height)));
 
2014
    setScene(scene);
 
2015
 
 
2016
    // setup the timer
 
2017
    m_delayedShowTimer->setSingleShot(true);
 
2018
    m_delayedShowTimer->setInterval(500);
 
2019
    connect(m_delayedShowTimer, SIGNAL(timeout()), SLOT(show()));
 
2020
}
 
2021
 
 
2022
void CloseWindowView::windowInputMouseEvent(QMouseEvent* e)
 
2023
{
 
2024
    if (m_delayedShowTimer->isActive())
 
2025
        return;
 
2026
    if (e->type() == QEvent::MouseMove) {
 
2027
        mouseMoveEvent(e);
 
2028
    } else if (e->type() == QEvent::MouseButtonPress) {
 
2029
        mousePressEvent(e);
 
2030
    } else if (e->type() == QEvent::MouseButtonDblClick) {
 
2031
        mouseDoubleClickEvent(e);
 
2032
    } else if (e->type() == QEvent::MouseButtonRelease) {
 
2033
        mouseReleaseEvent(e);
 
2034
    }
 
2035
}
 
2036
 
 
2037
void CloseWindowView::drawBackground(QPainter* painter, const QRectF& rect)
 
2038
{
 
2039
    Q_UNUSED(rect)
 
2040
    painter->setRenderHint(QPainter::Antialiasing);
 
2041
    m_frame->paintFrame(painter);
 
2042
}
 
2043
 
 
2044
void CloseWindowView::hide()
 
2045
{
 
2046
    m_delayedShowTimer->stop();
 
2047
    QWidget::hide();
 
2048
}
 
2049
 
 
2050
void CloseWindowView::delayedShow()
 
2051
{
 
2052
    if (isVisible() || m_delayedShowTimer->isActive())
 
2053
        return;
 
2054
    m_delayedShowTimer->start();
 
2055
}
 
2056
 
 
2057
 
 
2058
} // namespace
 
2059
 
 
2060
#include "presentwindows.moc"