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

« back to all changes in this revision

Viewing changes to plasma/desktop/shell/panelview.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
*   Copyright 2007 by Matt Broadstone <mbroadst@kde.org>
 
3
*   Copyright 2007 by Robert Knight <robertknight@gmail.com>
 
4
*
 
5
*   This program is free software; you can redistribute it and/or modify
 
6
*   it under the terms of the GNU Library General Public License version 2,
 
7
*   or (at your option) any later version.
 
8
*
 
9
*   This program is distributed in the hope that it will be useful,
 
10
*   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
*   GNU General Public License for more details
 
13
*
 
14
*   You should have received a copy of the GNU Library General Public
 
15
*   License along with this program; if not, write to the
 
16
*   Free Software Foundation, Inc.,
 
17
*   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 
18
*/
 
19
 
 
20
#include "panelview.h"
 
21
 
 
22
#include <QApplication>
 
23
#include <QGraphicsLinearLayout>
 
24
#include <QPropertyAnimation>
 
25
#include <QTimer>
 
26
#ifdef Q_WS_X11
 
27
#include <X11/Xatom.h>
 
28
#include <QX11Info>
 
29
#include <X11/extensions/shape.h>
 
30
#endif
 
31
 
 
32
#include <KDebug>
 
33
#include <KIdleTime>
 
34
#include <KWindowSystem>
 
35
 
 
36
#include <Plasma/Containment>
 
37
#include <Plasma/Corona>
 
38
#include <Plasma/Plasma>
 
39
#include <Plasma/PopupApplet>
 
40
#include <Plasma/Svg>
 
41
#include <Plasma/Theme>
 
42
#include <Plasma/WindowEffects>
 
43
 
 
44
#include <kephal/screens.h>
 
45
 
 
46
#include "desktopcorona.h"
 
47
#include "panelappletoverlay.h"
 
48
#include "panelcontroller.h"
 
49
#include "panelshadows.h"
 
50
#include "plasmaapp.h"
 
51
 
 
52
class GlowBar : public QWidget
 
53
{
 
54
public:
 
55
    GlowBar(Plasma::Direction direction, const QRect &triggerZone)
 
56
        : QWidget(0),
 
57
          m_strength(0.3),
 
58
          m_svg(new Plasma::Svg(this)),
 
59
          m_direction(direction)
 
60
    {
 
61
        setAttribute(Qt::WA_TranslucentBackground);
 
62
        KWindowSystem::setOnAllDesktops(winId(), true);
 
63
        KWindowSystem::setType(winId(), NET::Dock);
 
64
        m_svg->setImagePath("widgets/glowbar");
 
65
 
 
66
        QPalette pal = palette();
 
67
        pal.setColor(backgroundRole(), Qt::transparent);
 
68
        setPalette(pal);
 
69
 
 
70
#ifdef Q_WS_X11
 
71
        QRegion region(QRect(0,0,1,1));
 
72
        XShapeCombineRegion(QX11Info::display(), winId(), ShapeInput, 0, 0,
 
73
                            region.handle(), ShapeSet);
 
74
#endif
 
75
 
 
76
        QRect glowGeom = triggerZone;
 
77
        QSize s = sizeHint();
 
78
        switch (m_direction) {
 
79
            case Plasma::Up:
 
80
                glowGeom.setY(glowGeom.y() - s.height() + 1);
 
81
                // fallthrough
 
82
            case Plasma::Down:
 
83
                glowGeom.setHeight(s.height());
 
84
                break;
 
85
            case Plasma::Left:
 
86
                glowGeom.setX(glowGeom.x() - s.width() + 1);
 
87
                // fallthrough
 
88
            case Plasma::Right:
 
89
                glowGeom.setWidth(s.width());
 
90
                break;
 
91
        }
 
92
 
 
93
        //kDebug() << "glow geom is" << glowGeom << "from" << triggerZone;
 
94
        setGeometry(glowGeom);
 
95
        m_buffer = QPixmap(size());
 
96
    }
 
97
 
 
98
    void paintEvent(QPaintEvent* e)
 
99
    {
 
100
        Q_UNUSED(e)
 
101
        QPixmap l, r, c;
 
102
        const QSize glowRadius = m_svg->elementSize("hint-glow-radius");
 
103
        QPoint pixmapPosition(0, 0);
 
104
 
 
105
        m_buffer.fill(QColor(0, 0, 0, int(qreal(255)*m_strength)));
 
106
        QPainter p(&m_buffer);
 
107
        p.setCompositionMode(QPainter::CompositionMode_SourceIn);
 
108
 
 
109
        switch (m_direction) {
 
110
            case Plasma::Down:
 
111
                l = m_svg->pixmap("bottomleft");
 
112
                r = m_svg->pixmap("bottomright");
 
113
                c = m_svg->pixmap("bottom");
 
114
                pixmapPosition = QPoint(0, -glowRadius.height());
 
115
                break;
 
116
            case Plasma::Up:
 
117
                l = m_svg->pixmap("topleft");
 
118
                r = m_svg->pixmap("topright");
 
119
                c = m_svg->pixmap("top");
 
120
                break;
 
121
            case Plasma::Right:
 
122
                l = m_svg->pixmap("topright");
 
123
                r = m_svg->pixmap("bottomright");
 
124
                c = m_svg->pixmap("right");
 
125
                pixmapPosition = QPoint(-glowRadius.width(), 0);
 
126
                break;
 
127
            case Plasma::Left:
 
128
                l = m_svg->pixmap("topleft");
 
129
                r = m_svg->pixmap("bottomleft");
 
130
                c = m_svg->pixmap("left");
 
131
                break;
 
132
        }
 
133
 
 
134
        if (m_direction == Plasma::Left || m_direction == Plasma::Right) {
 
135
            p.drawPixmap(pixmapPosition, l);
 
136
            p.drawTiledPixmap(QRect(pixmapPosition.x(), l.height(), c.width(), height() - l.height() - r.height()), c);
 
137
            p.drawPixmap(QPoint(pixmapPosition.x(), height() - r.height()), r);
 
138
        } else {
 
139
            p.drawPixmap(pixmapPosition, l);
 
140
            p.drawTiledPixmap(QRect(l.width(), pixmapPosition.y(), width() - l.width() - r.width(), c.height()), c);
 
141
            p.drawPixmap(QPoint(width() - r.width(), pixmapPosition.y()), r);
 
142
        }
 
143
 
 
144
        p.end();
 
145
        p.begin(this);
 
146
        p.drawPixmap(QPoint(0, 0), m_buffer);
 
147
    }
 
148
 
 
149
    QSize sizeHint() const
 
150
    {
 
151
        return m_svg->elementSize("bottomright") - m_svg->elementSize("hint-glow-radius");
 
152
    }
 
153
 
 
154
    bool event(QEvent *event)
 
155
    {
 
156
        if (event->type() == QEvent::Paint) {
 
157
            QPainter p(this);
 
158
            p.setCompositionMode(QPainter::CompositionMode_Source);
 
159
            p.fillRect(rect(), Qt::transparent);
 
160
        }
 
161
        return QWidget::event(event);
 
162
    }
 
163
 
 
164
    void updateStrength(QPoint point)
 
165
    {
 
166
        QPoint localPoint = mapFromGlobal(point);
 
167
 
 
168
        qreal newStrength;
 
169
        switch (m_direction) {
 
170
        case Plasma::Up: // when the panel is at the bottom.
 
171
            newStrength = 1 - qreal(-localPoint.y())/m_triggerDistance;
 
172
            break;
 
173
        case Plasma::Right:
 
174
            newStrength = 1 - qreal(localPoint.x())/m_triggerDistance;
 
175
            break;
 
176
        case Plasma::Left: // when the panel is right-aligned
 
177
            newStrength = 1 - qreal(-localPoint.x())/m_triggerDistance;
 
178
            break;
 
179
        case Plasma::Down:
 
180
        default:
 
181
            newStrength = 1- qreal(localPoint.y())/m_triggerDistance;
 
182
            break;
 
183
        }
 
184
        if (qAbs(newStrength - m_strength) > 0.01 && newStrength >= 0 && newStrength <= 1) {
 
185
            m_strength = newStrength;
 
186
            update();
 
187
        }
 
188
    }
 
189
 
 
190
 
 
191
private:
 
192
    static const int m_triggerDistance = 30;
 
193
    qreal m_strength;
 
194
    Plasma::Svg *m_svg;
 
195
    Plasma::Direction m_direction;
 
196
    QPixmap m_buffer;
 
197
};
 
198
 
 
199
PanelView::PanelView(Plasma::Containment *panel, int id, QWidget *parent)
 
200
    : Plasma::View(panel, id, parent),
 
201
      m_panelController(0),
 
202
      m_glowBar(0),
 
203
      m_mousePollTimer(0),
 
204
      m_strutsTimer(new QTimer(this)),
 
205
      m_rehideAfterAutounhideTimer(new QTimer(this)),
 
206
      m_spacer(0),
 
207
      m_spacerIndex(-1),
 
208
#ifdef Q_WS_X11
 
209
      m_unhideTrigger(None),
 
210
#endif
 
211
      m_visibilityMode(NormalPanel),
 
212
      m_lastHorizontal(true),
 
213
      m_editing(false),
 
214
      m_triggerEntered(false),
 
215
      m_respectStatus(true)
 
216
{
 
217
    PlasmaApp::self()->panelShadows()->addWindow(this);
 
218
 
 
219
    // KWin setup
 
220
    KWindowSystem::setOnAllDesktops(winId(), true);
 
221
    KWindowSystem::setType(winId(), NET::Dock);
 
222
    setWindowRole(QString("panel_%1").arg(id));
 
223
 
 
224
    m_strutsTimer->setSingleShot(true);
 
225
    connect(m_strutsTimer, SIGNAL(timeout()), this, SLOT(updateStruts()));
 
226
 
 
227
    // this timer controls checks to re-hide a panel after it's been unhidden
 
228
    // for the user because, e.g., something is demanding attention
 
229
    m_rehideAfterAutounhideTimer->setSingleShot(true);
 
230
    connect(m_rehideAfterAutounhideTimer, SIGNAL(timeout()), this, SLOT(checkAutounhide()));
 
231
 
 
232
    // Graphics view setup
 
233
    setFrameStyle(QFrame::NoFrame);
 
234
    setInteractive(true);
 
235
    setAcceptDrops(true);
 
236
    setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
 
237
    setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
 
238
 
 
239
    QPalette pal = palette();
 
240
    pal.setBrush(backgroundRole(), Qt::transparent);
 
241
    setPalette(pal);
 
242
 
 
243
#ifdef Q_WS_WIN
 
244
    registerAccessBar(true);
 
245
#endif
 
246
 
 
247
    KConfigGroup viewConfig = config();
 
248
    KConfigGroup sizes = KConfigGroup(&viewConfig, "Sizes");
 
249
    m_lastHorizontal = isHorizontal();
 
250
 
 
251
    const bool onScreen = panel->screen() < PlasmaApp::self()->corona()->numScreens();
 
252
    const QRect screenRect = onScreen ?  PlasmaApp::self()->corona()->screenGeometry(panel->screen()) : QRect();
 
253
    const int sw = screenRect.width();
 
254
    const int sh = screenRect.height();
 
255
    m_lastSeenSize = sizes.readEntry("lastsize", m_lastHorizontal ? sw : sh);
 
256
 
 
257
    if (onScreen) {
 
258
        const QString last = m_lastHorizontal ? QString::fromLatin1("Horizontal%1").arg(QString::number(sw)) :
 
259
                                                QString::fromLatin1("Vertical%1").arg(QString::number(sh));
 
260
        if (sizes.hasGroup(last)) {
 
261
            KConfigGroup thisSize(&sizes, last);
 
262
            resize(thisSize.readEntry("size", m_lastHorizontal ? QSize(sw, 27) : QSize(27, sh)));
 
263
        }
 
264
    } else {
 
265
        resize(panel->size().toSize());
 
266
    }
 
267
 
 
268
    m_alignment = alignmentFilter((Qt::Alignment)viewConfig.readEntry("Alignment", (int)Qt::AlignLeft));
 
269
    KConfigGroup sizeConfig(&viewConfig, (m_lastHorizontal ? "Horizontal" : "Vertical") +
 
270
                            QString::number(m_lastSeenSize));
 
271
    m_offset = sizeConfig.readEntry("offset", 0);
 
272
    setVisibilityMode((VisibilityMode)viewConfig.readEntry("panelVisibility", (int)m_visibilityMode));
 
273
 
 
274
    connect(this, SIGNAL(sceneRectAboutToChange()), this, SLOT(pinchContainmentToCurrentScreen()));
 
275
 
 
276
    Kephal::Screens *screens = Kephal::Screens::self();
 
277
    connect(screens, SIGNAL(screenResized(Kephal::Screen *, QSize, QSize)),
 
278
            this, SLOT(pinchContainmentToCurrentScreen()));
 
279
    connect(screens, SIGNAL(screenMoved(Kephal::Screen *, QPoint, QPoint)),
 
280
            this, SLOT(updatePanelGeometry()));
 
281
    connect(screens, SIGNAL(screenAdded(Kephal::Screen *)),
 
282
            this, SLOT(updateStruts()));
 
283
    connect(Plasma::Theme::defaultTheme(), SIGNAL(themeChanged()), this, SLOT(themeChanged()), Qt::QueuedConnection);
 
284
}
 
285
 
 
286
PanelView::~PanelView()
 
287
{
 
288
    if (m_panelController) {
 
289
        disconnect(m_panelController, 0, this, 0);
 
290
        delete m_panelController;
 
291
    }
 
292
 
 
293
    delete m_glowBar;
 
294
    destroyUnhideTrigger();
 
295
#ifdef Q_WS_WIN
 
296
    registerAccessBar(false);
 
297
#endif
 
298
}
 
299
 
 
300
void PanelView::setContainment(Plasma::Containment *containment)
 
301
{
 
302
    kDebug() << "Panel geometry is" << containment->geometry();
 
303
 
 
304
    Plasma::Containment *oldContainment = this->containment();
 
305
    if (oldContainment) {
 
306
        disconnect(oldContainment);
 
307
    }
 
308
 
 
309
    connect(containment, SIGNAL(newStatus(Plasma::ItemStatus)), this, SLOT(statusUpdated(Plasma::ItemStatus)));
 
310
    connect(containment, SIGNAL(destroyed(QObject*)), this, SLOT(panelDeleted()));
 
311
    connect(containment, SIGNAL(toolBoxToggled()), this, SLOT(togglePanelController()));
 
312
    connect(containment, SIGNAL(appletAdded(Plasma::Applet *, const QPointF &)), this, SLOT(appletAdded(Plasma::Applet *)));
 
313
    connect(containment, SIGNAL(showAddWidgetsInterface(QPointF)), this, SLOT(showWidgetExplorer()));
 
314
    connect(containment, SIGNAL(screenChanged(int,int,Plasma::Containment*)), this, SLOT(pinchContainmentToCurrentScreen()));
 
315
    connect(containment, SIGNAL(immutabilityChanged(Plasma::ImmutabilityType)), this, SLOT(immutabilityChanged(Plasma::ImmutabilityType)));
 
316
 
 
317
    KConfigGroup viewIds(KGlobal::config(), "ViewIds");
 
318
 
 
319
    if (oldContainment) {
 
320
        viewIds.deleteEntry(QString::number(oldContainment->id()));
 
321
    }
 
322
 
 
323
    if (containment) {
 
324
        viewIds.writeEntry(QString::number(containment->id()), id());
 
325
        if (containment->corona()) {
 
326
            containment->corona()->requestConfigSync();
 
327
        }
 
328
    }
 
329
 
 
330
    // ensure we aren't overlapping other panels
 
331
    const QRect screenRect = PlasmaApp::self()->corona()->screenGeometry(containment->screen());
 
332
 
 
333
    View::setContainment(containment);
 
334
 
 
335
    // pinchContainment calls updatePanelGeometry for us
 
336
    pinchContainment(screenRect);
 
337
    m_lastMin = containment->minimumSize();
 
338
    m_lastMax = containment->maximumSize();
 
339
 
 
340
    kDebug() << "about to set the containment" << (QObject*)containment;
 
341
 
 
342
    updateStruts();
 
343
 
 
344
    // if we are an autohiding panel, then see if the status mandates we do something about it
 
345
    if (m_visibilityMode != NormalPanel && m_visibilityMode != WindowsGoBelow) {
 
346
        checkUnhide(containment->status());
 
347
    }
 
348
}
 
349
 
 
350
void PanelView::themeChanged()
 
351
{
 
352
    recreateUnhideTrigger();
 
353
}
 
354
 
 
355
void PanelView::setPanelDragPosition(const QPoint &point)
 
356
{
 
357
    QRect screenGeom = PlasmaApp::self()->corona()->screenGeometry(containment()->screen());
 
358
    QRect geom = geometry();
 
359
    geom.translate(-point);
 
360
    if (screenGeom.contains(geom)) {
 
361
        move(pos() - point);
 
362
        if (m_panelController) {
 
363
            m_panelController->move(m_panelController->pos() - point);
 
364
        }
 
365
    }
 
366
}
 
367
 
 
368
void PanelView::setLocation(Plasma::Location location)
 
369
{
 
370
    Plasma::Containment *c = containment();
 
371
    QSizeF s = c->size();
 
372
    QSizeF min = c->minimumSize();
 
373
    QSizeF max = c->maximumSize();
 
374
    qreal panelWidth = s.width();
 
375
    qreal panelHeight = s.height();
 
376
 
 
377
    Plasma::FormFactor formFactor = c->formFactor();
 
378
    bool wasHorizontal = formFactor == Plasma::Horizontal;
 
379
    bool wasFullSize = m_lastSeenSize == (wasHorizontal ? s.width() : s.height());
 
380
 
 
381
    if (location == Plasma::TopEdge || location == Plasma::BottomEdge) {
 
382
        if (!wasHorizontal) {
 
383
            // we're switching! swap the sizes about
 
384
            panelHeight = s.width();
 
385
            if (wasFullSize) {
 
386
                QRect screenGeom = PlasmaApp::self()->corona()->screenGeometry(c->screen());
 
387
                panelWidth = screenGeom.width();
 
388
            } else {
 
389
                panelWidth = s.height();
 
390
            }
 
391
            min = QSizeF(panelWidth, min.width());
 
392
            max = QSizeF(panelWidth, max.width());
 
393
        }
 
394
 
 
395
        formFactor = Plasma::Horizontal;
 
396
    } else {
 
397
        if (wasHorizontal) {
 
398
            // we're switching! swap the sizes about
 
399
 
 
400
            if (wasFullSize) {
 
401
                QRect screenGeom = PlasmaApp::self()->corona()->screenGeometry(c->screen());
 
402
                panelHeight = screenGeom.height();
 
403
            } else {
 
404
                panelHeight = s.width();
 
405
            }
 
406
 
 
407
            panelWidth = s.height();
 
408
            min = QSizeF(min.height(), panelHeight);
 
409
            max = QSizeF(max.height(), panelHeight);
 
410
        }
 
411
 
 
412
        formFactor = Plasma::Vertical;
 
413
    }
 
414
 
 
415
    //kDebug() << "!!!!!!!!!!!!!!!!!! about to set to" << location << panelHeight << formFactor;
 
416
    disconnect(this, SIGNAL(sceneRectAboutToChange()), this, SLOT(pinchContainmentToCurrentScreen()));
 
417
    c->setFormFactor(formFactor);
 
418
    c->setLocation(location);
 
419
 
 
420
    c->setMinimumSize(0, 0);
 
421
    c->setMaximumSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
 
422
    c->resize(panelWidth, panelHeight);
 
423
    c->setMinimumSize(min);
 
424
    c->setMaximumSize(max);
 
425
#ifdef Q_WS_WIN
 
426
    appBarPosChanged();
 
427
#endif
 
428
    const QRect screenRect = PlasmaApp::self()->corona()->screenGeometry(c->screen());
 
429
    pinchContainment(screenRect);
 
430
    KWindowSystem::setOnAllDesktops(winId(), true);
 
431
    connect(this, SIGNAL(sceneRectAboutToChange()), this, SLOT(pinchContainmentToCurrentScreen()));
 
432
}
 
433
 
 
434
Plasma::Location PanelView::location() const
 
435
{
 
436
    if (containment()) {
 
437
        return containment()->location();
 
438
    } else {
 
439
        return Plasma::BottomEdge;
 
440
    }
 
441
}
 
442
 
 
443
void PanelView::setVisibilityMode(PanelView::VisibilityMode mode)
 
444
{
 
445
    m_visibilityMode = mode;
 
446
 
 
447
    if (mode == LetWindowsCover) {
 
448
        KWindowSystem::setState(winId(), NET::KeepBelow);
 
449
    } else {
 
450
        KWindowSystem::clearState(winId(), NET::KeepBelow);
 
451
    }
 
452
    //life is vastly simpler if we ensure we're visible now
 
453
    unhide();
 
454
 
 
455
    disconnect(containment(), SIGNAL(activate()), this, SLOT(unhide()));
 
456
    disconnect(containment(), SIGNAL(newStatus(Plasma::ItemStatus)), this, SLOT(checkUnhide(Plasma::ItemStatus)));
 
457
    if (mode == NormalPanel || mode == WindowsGoBelow) {
 
458
        //remove the last remnants of hide/unhide
 
459
        delete m_mousePollTimer;
 
460
        m_mousePollTimer = 0;
 
461
    } else {
 
462
        connect(containment(), SIGNAL(activate()), this, SLOT(unhide()));
 
463
        connect(containment(), SIGNAL(newStatus(Plasma::ItemStatus)), this, SLOT(checkUnhide(Plasma::ItemStatus)));
 
464
    }
 
465
 
 
466
    config().writeEntry("panelVisibility", (int)mode);
 
467
 
 
468
    //if the user didn't cause this, hide again in a bit
 
469
    if ((mode == AutoHide || mode == LetWindowsCover) && !m_editing) {
 
470
        if (m_mousePollTimer) {
 
471
            m_mousePollTimer->stop();
 
472
        }
 
473
 
 
474
        QTimer::singleShot(2000, this, SLOT(startAutoHide()));
 
475
    }
 
476
 
 
477
    KWindowSystem::setOnAllDesktops(winId(), true);
 
478
}
 
479
 
 
480
PanelView::VisibilityMode PanelView::visibilityMode() const
 
481
{
 
482
    return m_visibilityMode;
 
483
}
 
484
 
 
485
void PanelView::updatePanelGeometry()
 
486
{
 
487
    Plasma::Containment *c = containment();
 
488
 
 
489
    if (!c) {
 
490
        return;
 
491
    }
 
492
 
 
493
    kDebug() << "New panel geometry is" << c->geometry();
 
494
 
 
495
    QSize size = c->size().expandedTo(c->minimumSize()).toSize();
 
496
    QRect geom(QPoint(0,0), size);
 
497
    int screen = c->screen();
 
498
 
 
499
    if (screen < 0) {
 
500
        //TODO: is there a valid use for -1 with a panel? floating maybe?
 
501
        screen = 0;
 
502
    }
 
503
 
 
504
    QRect screenGeom = PlasmaApp::self()->corona()->screenGeometry(screen);
 
505
 
 
506
    if (m_alignment != Qt::AlignCenter) {
 
507
        m_offset = qMax(m_offset, 0);
 
508
    }
 
509
 
 
510
    //Sanity controls
 
511
    switch (location()) {
 
512
    case Plasma::TopEdge:
 
513
    case Plasma::BottomEdge:
 
514
        //resize the panel if is too large
 
515
        if (geom.width() > screenGeom.width()) {
 
516
            geom.setWidth(screenGeom.width());
 
517
        }
 
518
 
 
519
        //move the panel left/right if there is not enough room
 
520
        if (m_alignment == Qt::AlignLeft) {
 
521
             if (m_offset + geom.width() > screenGeom.width() + 1) {
 
522
                 m_offset = screenGeom.width() - geom.width();
 
523
             }
 
524
        } else if (m_alignment == Qt::AlignRight) {
 
525
             if (screenGeom.width() - m_offset - geom.width() < -1 ) {
 
526
                 m_offset = screenGeom.width() - geom.width();
 
527
             }
 
528
        } else if (m_alignment == Qt::AlignCenter) {
 
529
             if (screenGeom.center().x() - screenGeom.x() + m_offset + geom.width()/2 > screenGeom.width() + 1) {
 
530
                 m_offset = screenGeom.width() - geom.width()/2 - (screenGeom.center().x() - screenGeom.x());
 
531
             } else if (screenGeom.center().x() - screenGeom.x() + m_offset - geom.width()/2 < -1) {
 
532
                 m_offset = (screenGeom.center().x() - screenGeom.x()) - geom.width()/2;
 
533
             }
 
534
        }
 
535
        break;
 
536
 
 
537
    case Plasma::LeftEdge:
 
538
    case Plasma::RightEdge:
 
539
        //resize the panel if is too tall
 
540
        if (geom.height() > screenGeom.height()) {
 
541
            geom.setHeight(screenGeom.height());
 
542
        }
 
543
 
 
544
        //move the panel bottom if there is not enough room
 
545
        //FIXME: still using alignleft/alignright is simpler and less error prone, but aligntop/alignbottom is more correct?
 
546
        if (m_alignment == Qt::AlignLeft) {
 
547
            if (m_offset + geom.height() > screenGeom.height() + 1) {
 
548
                m_offset = screenGeom.height() - geom.height();
 
549
            }
 
550
        } else if (m_alignment == Qt::AlignRight) {
 
551
            if (screenGeom.height() - m_offset - geom.height() < -1) {
 
552
                m_offset = screenGeom.height() - geom.height();
 
553
            }
 
554
        } else if (m_alignment == Qt::AlignCenter) {
 
555
            if (screenGeom.center().y() - screenGeom.top() + m_offset + geom.height()/2 > screenGeom.height() + 1) {
 
556
                m_offset = screenGeom.height() - geom.height()/2 - (screenGeom.center().y() - screenGeom.top());
 
557
             } else if (screenGeom.center().y() - screenGeom.top() + m_offset - geom.height()/2 < -1) {
 
558
                m_offset = (screenGeom.center().y() - screenGeom.top()) - geom.width()/2;
 
559
             }
 
560
        }
 
561
        break;
 
562
 
 
563
    //TODO: floating panels (probably they will save their own geometry)
 
564
    default:
 
565
        break;
 
566
    }
 
567
 
 
568
    //Actual movement
 
569
    switch (location()) {
 
570
    case Plasma::TopEdge:
 
571
        if (m_alignment == Qt::AlignLeft) {
 
572
            geom.moveTopLeft(QPoint(m_offset + screenGeom.left(), screenGeom.top()));
 
573
        } else if (m_alignment == Qt::AlignRight) {
 
574
            geom.moveTopRight(QPoint(screenGeom.right() - m_offset, screenGeom.top()));
 
575
        } else if (m_alignment == Qt::AlignCenter) {
 
576
            geom.moveTopLeft(QPoint(screenGeom.center().x() - geom.width()/2 + 1 - geom.width()%2 + m_offset, screenGeom.top()));
 
577
        }
 
578
 
 
579
        break;
 
580
 
 
581
    case Plasma::LeftEdge:
 
582
        if (m_alignment == Qt::AlignLeft) {
 
583
            geom.moveTopLeft(QPoint(screenGeom.left(), m_offset + screenGeom.top()));
 
584
        } else if (m_alignment == Qt::AlignRight) {
 
585
            geom.moveBottomLeft(QPoint(screenGeom.left(), screenGeom.bottom() - m_offset));
 
586
        } else if (m_alignment == Qt::AlignCenter) {
 
587
            geom.moveTopLeft(QPoint(screenGeom.left(), screenGeom.center().y() - geom.height()/2 + 1 - geom.height()%2 + m_offset));
 
588
        }
 
589
 
 
590
        break;
 
591
 
 
592
    case Plasma::RightEdge:
 
593
        if (m_alignment == Qt::AlignLeft) {
 
594
            geom.moveTopRight(QPoint(screenGeom.right(), m_offset + screenGeom.top()));
 
595
        } else if (m_alignment == Qt::AlignRight) {
 
596
            geom.moveBottomRight(QPoint(screenGeom.right(), screenGeom.bottom() - m_offset));
 
597
        } else if (m_alignment == Qt::AlignCenter) {
 
598
            geom.moveTopRight(QPoint(screenGeom.right(), screenGeom.center().y() - geom.height()/2 + 1 - geom.height()%2 + m_offset));
 
599
        }
 
600
 
 
601
        break;
 
602
 
 
603
    case Plasma::BottomEdge:
 
604
    default:
 
605
        if (m_alignment == Qt::AlignLeft) {
 
606
            geom.moveBottomLeft(QPoint(m_offset + screenGeom.left(), screenGeom.bottom()));
 
607
        } else if (m_alignment == Qt::AlignRight) {
 
608
            geom.moveBottomRight(QPoint(screenGeom.right() - m_offset, screenGeom.bottom()));
 
609
        } else if (m_alignment == Qt::AlignCenter) {
 
610
            geom.moveBottomLeft(QPoint(screenGeom.center().x() - geom.width()/2 + 1 - geom.width()%2 + m_offset, screenGeom.bottom()));
 
611
        }
 
612
 
 
613
        break;
 
614
    }
 
615
 
 
616
    kDebug() << (QObject*)this << "thinks its panel is at " << geom << "was" << geometry();
 
617
    if (geom == geometry()) {
 
618
        // our geometry is the same, but the panel moved around
 
619
        // so make sure our struts are still valid
 
620
        m_strutsTimer->stop();
 
621
        m_strutsTimer->start(STRUTSTIMERDELAY);
 
622
    } else {
 
623
        if (m_panelController && QPoint(pos() - geom.topLeft()).manhattanLength() > 100) {
 
624
            resize(geom.size());
 
625
            QPropertyAnimation *panelAnimation = new QPropertyAnimation(this, "pos", this);
 
626
            panelAnimation->setEasingCurve(QEasingCurve::InOutQuad);
 
627
            panelAnimation->setDuration(300);
 
628
            panelAnimation->setStartValue(pos());
 
629
            panelAnimation->setEndValue(geom.topLeft());
 
630
            panelAnimation->start(QAbstractAnimation::DeleteWhenStopped);
 
631
 
 
632
            QPropertyAnimation *controllerAnimation = new QPropertyAnimation(m_panelController, "pos", m_panelController);
 
633
            controllerAnimation->setEasingCurve(QEasingCurve::InOutQuad);
 
634
            controllerAnimation->setDuration(300);
 
635
            controllerAnimation->setStartValue(m_panelController->pos());
 
636
            controllerAnimation->setEndValue(m_panelController->positionForPanelGeometry(geom));
 
637
            controllerAnimation->start(QAbstractAnimation::DeleteWhenStopped);
 
638
        } else {
 
639
            setGeometry(geom);
 
640
        }
 
641
    }
 
642
 
 
643
    m_lastMin = c->minimumSize();
 
644
    m_lastMax = c->maximumSize();
 
645
 
 
646
    //update the panel controller location position and size
 
647
    if (m_panelController) {
 
648
        m_panelController->setLocation(c->location());
 
649
 
 
650
        foreach (PanelAppletOverlay *o, m_appletOverlays) {
 
651
            o->syncOrientation();
 
652
        }
 
653
    }
 
654
 
 
655
    recreateUnhideTrigger();
 
656
}
 
657
 
 
658
bool PanelView::isHorizontal() const
 
659
{
 
660
    return location() == Plasma::BottomEdge ||
 
661
           location() == Plasma::TopEdge;
 
662
}
 
663
 
 
664
void PanelView::pinchContainmentToCurrentScreen()
 
665
{
 
666
    kDebug() << "pinching to current screen";
 
667
    const QRect screenRect = PlasmaApp::self()->corona()->screenGeometry(containment()->screen());
 
668
    pinchContainment(screenRect);
 
669
}
 
670
 
 
671
void PanelView::pinchContainment(const QRect &screenGeom)
 
672
{
 
673
    kDebug() << "**************************** pinching" << screenGeom << m_lastSeenSize;
 
674
    disconnect(this, SIGNAL(sceneRectAboutToChange()), this, SLOT(pinchContainmentToCurrentScreen()));
 
675
    bool horizontal = isHorizontal();
 
676
 
 
677
    const int oldOffset = m_offset;
 
678
    const int sw = screenGeom.width();
 
679
    const int sh = screenGeom.height();
 
680
 
 
681
    Plasma::Containment *c = containment();
 
682
    QSizeF min = c->minimumSize();
 
683
    QSizeF max = c->maximumSize();
 
684
 
 
685
    KConfigGroup sizes = config();
 
686
    sizes = KConfigGroup(&sizes, "Sizes");
 
687
 
 
688
    if (m_lastHorizontal != horizontal || m_lastSeenSize != (horizontal ? sw : sh)) {
 
689
        // we're adjusting size. store the current size now
 
690
        KConfigGroup lastSize(&sizes, (m_lastHorizontal ? "Horizontal" : "Vertical") +
 
691
                                      QString::number(m_lastSeenSize));
 
692
        lastSize.writeEntry("size", size());
 
693
        lastSize.writeEntry("offset", m_offset);
 
694
        lastSize.writeEntry("min", m_lastMin);
 
695
        lastSize.writeEntry("max", m_lastMax);
 
696
        configNeedsSaving();
 
697
 
 
698
        const QString last = horizontal ? QString::fromLatin1("Horizontal%1").arg(QString::number(sw)) :
 
699
                                          QString::fromLatin1("Vertical%1").arg(QString::number(sh));
 
700
        if (sizes.hasGroup(last)) {
 
701
            KConfigGroup thisSize(&sizes, last);
 
702
 
 
703
            /*
 
704
            kDebug() << "has saved properties..." << last
 
705
                     << thisSize.readEntry("min", min)
 
706
                     << thisSize.readEntry("max", max)
 
707
                     << thisSize.readEntry("size", c->geometry().size())
 
708
                     << thisSize.readEntry("offset", 0);
 
709
            */
 
710
            c->setMinimumSize(0, 0);
 
711
            c->setMaximumSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
 
712
            c->resize(thisSize.readEntry("size", c->geometry().size()));
 
713
            c->setMinimumSize(thisSize.readEntry("min", min));
 
714
            c->setMaximumSize(thisSize.readEntry("max", max));
 
715
            m_offset = thisSize.readEntry("offset", 0);
 
716
        } else if (m_lastSeenSize < (horizontal ? sw : sh) &&
 
717
                   (horizontal ? c->geometry().width() :
 
718
                                 c->geometry().height()) >= m_lastSeenSize) {
 
719
            // we are moving from a smaller space where we are 100% to a larger one
 
720
            kDebug() << "we are moving from a smaller space where we are 100% to a larger one";
 
721
            c->setMinimumSize(0, 0);
 
722
            c->setMaximumSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
 
723
 
 
724
            if (horizontal) {
 
725
                c->setMaximumSize(sw, max.height());
 
726
                c->resize(sw, c->geometry().height());
 
727
                if (min.width() == max.width()) {
 
728
                    c->setMinimumSize(sw, min.height());
 
729
                }
 
730
            } else {
 
731
                c->setMaximumSize(max.width(), sh);
 
732
                c->resize(c->geometry().width(), sh);
 
733
                if (min.height() == max.height()) {
 
734
                    c->setMinimumSize(min.width(), sh);
 
735
                }
 
736
            }
 
737
        } else if (m_lastSeenSize > (horizontal ? sw : sh) &&
 
738
                    (m_offset + (horizontal ? c->geometry().width() :
 
739
                                 c->geometry().height())) > (horizontal ? sw : sh)) {
 
740
            kDebug() << "we are moving from a bigger space to a smaller one where the panel won't fit!!";
 
741
            if ((horizontal ? c->geometry().width() :
 
742
                                 c->geometry().height()) > (horizontal ? sw : sh)) {
 
743
                kDebug() << "panel is larger than screen, adjusting panel size";
 
744
                setOffset(0);
 
745
                c->setMinimumSize(0, 0);
 
746
                c->setMaximumSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
 
747
 
 
748
                if (horizontal) {
 
749
                    c->setMaximumSize(sw, max.height());
 
750
                    c->resize(sw, c->geometry().height());
 
751
                    if (min.width() == max.width()) {
 
752
                        c->setMinimumSize(sw, min.height());
 
753
                    }
 
754
                } else {
 
755
                    c->setMaximumSize(max.width(), sh);
 
756
                    c->resize(c->geometry().width(), sh);
 
757
                    if (min.height() == max.height()) {
 
758
                        c->setMinimumSize(min.width(), sh);
 
759
                    }
 
760
                }
 
761
            } else {
 
762
                kDebug() << "reducing offset so the panel fits in screen";
 
763
                setOffset((horizontal ? sw : sh) -
 
764
                          (horizontal ? c->geometry().width() : c->geometry().height()));
 
765
            }
 
766
        }
 
767
    }
 
768
 
 
769
    // Pinching strategy:
 
770
    // if our containment is too big for the size of the screen we are now on,
 
771
    // then we first try and limit the offset and then if that still doesn't
 
772
    // give us enough room, we limit the size of the panel itself by setting
 
773
    // the minimum and maximum sizes.
 
774
 
 
775
    //kDebug() << "checking panel" << c->geometry() << "against" << screenGeom;
 
776
 
 
777
    // resize to max if for some reason the size is empty
 
778
    // otherwise its not possible to interact with the panel at all
 
779
    if (c->size().isEmpty()) {
 
780
        c->resize(max);
 
781
    }
 
782
 
 
783
    // write to the config file if the size has changed, or if we haven't recorded the lastsize
 
784
    // previously which ensures we'll always have a value even after first run
 
785
    const bool writeConfig = m_lastSeenSize != (horizontal ? sw : sh) || !sizes.hasKey("lastsize");
 
786
    m_lastHorizontal = horizontal;
 
787
    m_lastSeenSize = (horizontal ? sw : sh);
 
788
    if (writeConfig) {
 
789
        sizes.writeEntry("lastsize", m_lastSeenSize);
 
790
        configNeedsSaving();
 
791
    }
 
792
 
 
793
    updatePanelGeometry();
 
794
 
 
795
    if (m_offset != oldOffset) {
 
796
        sizes.writeEntry("offset", m_lastSeenSize);
 
797
        configNeedsSaving();
 
798
    }
 
799
 
 
800
    if (m_panelController) {
 
801
        m_panelController->setOffset(m_offset);
 
802
    }
 
803
 
 
804
    connect(this, SIGNAL(sceneRectAboutToChange()), this, SLOT(pinchContainmentToCurrentScreen()));
 
805
    recreateUnhideTrigger();
 
806
    kDebug() << "Done pinching, containment's geom" << c->geometry() << "own geom" << geometry();
 
807
}
 
808
 
 
809
void PanelView::setOffset(int newOffset)
 
810
{
 
811
    m_offset = newOffset;
 
812
 
 
813
    //TODO: do we ever need to worry about pinching here, or
 
814
    //      do we just assume that the offset is always < screenSize - containmentSize?
 
815
    updatePanelGeometry();
 
816
 
 
817
    KConfigGroup viewConfig = config();
 
818
    viewConfig = KConfigGroup(&viewConfig, (m_lastHorizontal ? "Horizontal" : "Vertical") +
 
819
                              QString::number(m_lastSeenSize));
 
820
    viewConfig.writeEntry("offset", m_offset);
 
821
    configNeedsSaving();
 
822
}
 
823
 
 
824
int PanelView::offset() const
 
825
{
 
826
    return m_offset;
 
827
}
 
828
 
 
829
void PanelView::setAlignment(Qt::Alignment align)
 
830
{
 
831
    m_alignment = alignmentFilter(align);
 
832
    KConfigGroup viewConfig = config();
 
833
    viewConfig.writeEntry("Alignment", (int)m_alignment);
 
834
    configNeedsSaving();
 
835
}
 
836
 
 
837
Qt::Alignment PanelView::alignment() const
 
838
{
 
839
    return m_alignment;
 
840
}
 
841
 
 
842
void PanelView::immutabilityChanged(Plasma::ImmutabilityType immutability)
 
843
{
 
844
    if (immutability != Plasma::Mutable) {
 
845
        delete m_panelController;
 
846
        m_panelController = 0;
 
847
    }
 
848
}
 
849
 
 
850
void PanelView::togglePanelController()
 
851
{
 
852
    //kDebug();
 
853
    m_editing = false;
 
854
    if (containment()->immutability() != Plasma::Mutable) {
 
855
        delete m_panelController;
 
856
        m_panelController = 0;
 
857
        return;
 
858
    }
 
859
 
 
860
    if (!m_panelController) {
 
861
        m_panelController = new PanelController(0);
 
862
        m_panelController->setContainment(containment());
 
863
        m_panelController->setLocation(containment()->location());
 
864
        m_panelController->setAlignment(m_alignment);
 
865
        m_panelController->setOffset(m_offset);
 
866
        m_panelController->setVisibilityMode(m_visibilityMode);
 
867
 
 
868
        connect(m_panelController, SIGNAL(destroyed(QObject*)), this, SLOT(editingComplete()));
 
869
        connect(m_panelController, SIGNAL(offsetChanged(int)), this, SLOT(setOffset(int)));
 
870
        connect(m_panelController, SIGNAL(partialMove(const QPoint&)), this, SLOT(setPanelDragPosition(const QPoint&)));
 
871
        connect(m_panelController, SIGNAL(alignmentChanged(Qt::Alignment)), this, SLOT(setAlignment(Qt::Alignment)));
 
872
        connect(m_panelController, SIGNAL(locationChanged(Plasma::Location)), this, SLOT(setLocation(Plasma::Location)));
 
873
        connect(m_panelController, SIGNAL(panelVisibilityModeChanged(PanelView::VisibilityMode)), this, SLOT(setVisibilityMode(PanelView::VisibilityMode)));
 
874
 
 
875
        if (containment()->containmentType() == Plasma::Containment::PanelContainment && 
 
876
            dynamic_cast<QGraphicsLinearLayout*>(containment()->layout())) {
 
877
            setTabOrder(0, m_panelController);
 
878
            QWidget *prior = m_panelController;
 
879
 
 
880
            // we only support mouse over drags for panels with linear layouts
 
881
            QColor overlayColor(Plasma::Theme::defaultTheme()->color(Plasma::Theme::BackgroundColor));
 
882
            QBrush overlayBrush(overlayColor);
 
883
            QPalette p(palette());
 
884
            p.setBrush(QPalette::Window, overlayBrush);
 
885
            foreach (Plasma::Applet *applet, containment()->applets()) {
 
886
                PanelAppletOverlay *moveOverlay = new PanelAppletOverlay(applet, this);
 
887
                connect(moveOverlay, SIGNAL(removedWithApplet(PanelAppletOverlay*)),
 
888
                        this, SLOT(overlayDestroyed(PanelAppletOverlay*)));
 
889
                connect(moveOverlay, SIGNAL(moved(PanelAppletOverlay*)),
 
890
                        this, SLOT(overlayMoved(PanelAppletOverlay*)));
 
891
                moveOverlay->setPalette(p);
 
892
                moveOverlay->show();
 
893
                moveOverlay->raise();
 
894
                m_appletOverlays << moveOverlay;
 
895
                //kDebug() << moveOverlay << moveOverlay->geometry();
 
896
                setTabOrder(prior, moveOverlay);
 
897
                prior = moveOverlay;
 
898
            }
 
899
        }
 
900
    }
 
901
 
 
902
    if (m_panelController->isVisible()) {
 
903
        if (m_panelController->showingWidgetExplorer() ||
 
904
            m_panelController->showingActivityManager()) {
 
905
            m_panelController->switchToController();
 
906
            m_panelController->move(m_panelController->positionForPanelGeometry(geometry()));
 
907
        } else {
 
908
            Plasma::WindowEffects::slideWindow(m_panelController, location());
 
909
            m_panelController->close();
 
910
            updateStruts();
 
911
        }
 
912
    } else {
 
913
        m_editing = true;
 
914
        m_panelController->resize(m_panelController->sizeHint());
 
915
        m_panelController->move(m_panelController->positionForPanelGeometry(geometry()));
 
916
        Plasma::WindowEffects::slideWindow(m_panelController, location());
 
917
        kDebug() << "showing panel controller!" << m_panelController->geometry();
 
918
        m_panelController->show();
 
919
    }
 
920
}
 
921
 
 
922
void PanelView::editingComplete()
 
923
{
 
924
    //kDebug();
 
925
    m_panelController = 0;
 
926
    m_editing = false;
 
927
    qDeleteAll(m_appletOverlays);
 
928
    m_appletOverlays.clear();
 
929
 
 
930
    if (!containment()) {
 
931
        return;
 
932
    }
 
933
 
 
934
    containment()->closeToolBox();
 
935
    updateStruts();
 
936
 
 
937
    if (m_visibilityMode == LetWindowsCover || m_visibilityMode == AutoHide) {
 
938
        startAutoHide();
 
939
    }
 
940
}
 
941
 
 
942
void PanelView::overlayDestroyed(PanelAppletOverlay *overlay)
 
943
{
 
944
    m_appletOverlays.remove(overlay);
 
945
}
 
946
 
 
947
void PanelView::overlayMoved(PanelAppletOverlay *overlay)
 
948
{
 
949
    Q_UNUSED(overlay)
 
950
    foreach (PanelAppletOverlay *o, m_appletOverlays) {
 
951
        o->syncIndex();
 
952
    }
 
953
}
 
954
 
 
955
Qt::Alignment PanelView::alignmentFilter(Qt::Alignment align) const
 
956
{
 
957
    //If it's not a supported alignment default to Qt::AlignLeft
 
958
    if (align == Qt::AlignLeft || align == Qt::AlignRight || align == Qt::AlignCenter) {
 
959
        return align;
 
960
    } else {
 
961
        return Qt::AlignLeft;
 
962
    }
 
963
}
 
964
 
 
965
void PanelView::updateStruts()
 
966
{
 
967
    if (!containment()) {
 
968
        return;
 
969
    }
 
970
 
 
971
    NETExtendedStrut strut;
 
972
 
 
973
    if (m_visibilityMode == NormalPanel) {
 
974
        const QRect thisScreen = PlasmaApp::self()->corona()->screenGeometry(containment()->screen());
 
975
        const QRect wholeScreen = Kephal::ScreenUtils::desktopGeometry();
 
976
 
 
977
        //Extended struts against a screen edge near to another screen are really harmful, so windows maximized under the panel is a lesser pain
 
978
        //TODO: force "windows can cover" in those cases?
 
979
        const int numScreens = PlasmaApp::self()->corona()->numScreens();
 
980
        for (int i = 0; i < numScreens; ++i) {
 
981
            if (i == containment()->screen()) {
 
982
                continue;
 
983
            }
 
984
 
 
985
            const QRect otherScreen = PlasmaApp::self()->corona()->screenGeometry(i);
 
986
 
 
987
            switch (location())
 
988
            {
 
989
            case Plasma::TopEdge:
 
990
                if (otherScreen.bottom() <= thisScreen.top()) {
 
991
                    KWindowSystem::setExtendedStrut(winId(), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
 
992
                    return;
 
993
                }
 
994
                break;
 
995
            case Plasma::BottomEdge:
 
996
                if (otherScreen.top() >= thisScreen.bottom()) {
 
997
                    KWindowSystem::setExtendedStrut(winId(), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
 
998
                    return;
 
999
                }
 
1000
                break;
 
1001
            case Plasma::RightEdge:
 
1002
                if (otherScreen.left() >= thisScreen.right()) {
 
1003
                    KWindowSystem::setExtendedStrut(winId(), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
 
1004
                    return;
 
1005
                }
 
1006
                break;
 
1007
            case Plasma::LeftEdge:
 
1008
                if (otherScreen.right() <= thisScreen.left()) {
 
1009
                    KWindowSystem::setExtendedStrut(winId(), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
 
1010
                    return;
 
1011
                }
 
1012
                break;
 
1013
            default:
 
1014
                return;
 
1015
            }
 
1016
        }
 
1017
        // extended struts are to the combined screen geoms, not the single screen
 
1018
        int leftOffset = wholeScreen.x() - thisScreen.x();
 
1019
        int rightOffset = wholeScreen.right() - thisScreen.right();
 
1020
        int bottomOffset = wholeScreen.bottom() - thisScreen.bottom();
 
1021
        int topOffset = wholeScreen.top() - thisScreen.top();
 
1022
        kDebug() << "screen l/r/b/t offsets are:" << leftOffset << rightOffset << bottomOffset << topOffset << location();
 
1023
 
 
1024
        switch (location())
 
1025
        {
 
1026
            case Plasma::TopEdge:
 
1027
                strut.top_width = height() + topOffset;
 
1028
                strut.top_start = x();
 
1029
                strut.top_end = x() + width() - 1;
 
1030
                break;
 
1031
 
 
1032
            case Plasma::BottomEdge:
 
1033
                strut.bottom_width = height() + bottomOffset;
 
1034
                strut.bottom_start = x();
 
1035
                strut.bottom_end = x() + width() - 1;
 
1036
                //kDebug() << "setting bottom edge to" << strut.bottom_width
 
1037
                //         << strut.bottom_start << strut.bottom_end;
 
1038
                break;
 
1039
 
 
1040
            case Plasma::RightEdge:
 
1041
                strut.right_width = width() + rightOffset;
 
1042
                strut.right_start = y();
 
1043
                strut.right_end = y() + height() - 1;
 
1044
                break;
 
1045
 
 
1046
            case Plasma::LeftEdge:
 
1047
                strut.left_width = width() + leftOffset;
 
1048
                strut.left_start = y();
 
1049
                strut.left_end = y() + height() - 1;
 
1050
                break;
 
1051
 
 
1052
            default:
 
1053
                //kDebug() << "where are we?";
 
1054
            break;
 
1055
        }
 
1056
    }
 
1057
 
 
1058
    KWindowSystem::setExtendedStrut(winId(), strut.left_width,
 
1059
                                             strut.left_start,
 
1060
                                             strut.left_end,
 
1061
                                             strut.right_width,
 
1062
                                             strut.right_start,
 
1063
                                             strut.right_end,
 
1064
                                             strut.top_width,
 
1065
                                             strut.top_start,
 
1066
                                             strut.top_end,
 
1067
                                             strut.bottom_width,
 
1068
                                             strut.bottom_start,
 
1069
                                             strut.bottom_end);
 
1070
 
 
1071
    if (m_panelController) {
 
1072
        m_panelController->setLocation(containment()->location());
 
1073
 
 
1074
        if (m_panelController->isVisible()) {
 
1075
            m_panelController->resize(m_panelController->sizeHint());
 
1076
            m_panelController->move(m_panelController->positionForPanelGeometry(geometry()));
 
1077
            Plasma::WindowEffects::slideWindow(m_panelController, location());
 
1078
        }
 
1079
 
 
1080
        foreach (PanelAppletOverlay *o, m_appletOverlays) {
 
1081
            o->syncOrientation();
 
1082
        }
 
1083
    }
 
1084
 
 
1085
    recreateUnhideTrigger();
 
1086
}
 
1087
 
 
1088
bool PanelView:: migratedFrom(int screenId) const
 
1089
{
 
1090
    KConfigGroup cg = config();
 
1091
    QList<int> migrations;
 
1092
    migrations = cg.readEntry("Migrations", migrations);
 
1093
    return migrations.contains(screenId);
 
1094
}
 
1095
 
 
1096
void PanelView::migrateTo(int screenId)
 
1097
{
 
1098
    KConfigGroup cg = config();
 
1099
    QList<int> migrations;
 
1100
    migrations = cg.readEntry("Migrations", migrations);
 
1101
 
 
1102
    const int index = migrations.indexOf(screenId);
 
1103
    if (index == -1) {
 
1104
        migrations.append(screenId);
 
1105
    } else {
 
1106
        migrations = migrations.mid(0, migrations.length() - index - 1);
 
1107
    }
 
1108
 
 
1109
    cg.writeEntry("Migrations", migrations);
 
1110
    setScreen(screenId);
 
1111
}
 
1112
 
 
1113
void PanelView::showWidgetExplorer()
 
1114
{
 
1115
    if (!containment()) {
 
1116
        return;
 
1117
    }
 
1118
 
 
1119
    if (!m_panelController) {
 
1120
        m_editing = true;
 
1121
        ControllerWindow *controller = PlasmaApp::self()->showWidgetExplorer(screen(), containment());
 
1122
        connect(controller, SIGNAL(destroyed(QObject*)), this, SLOT(editingComplete()), Qt::UniqueConnection);
 
1123
    } else {
 
1124
        m_panelController->showWidgetExplorer();
 
1125
    }
 
1126
}
 
1127
 
 
1128
void PanelView::moveEvent(QMoveEvent *event)
 
1129
{
 
1130
    Plasma::View::moveEvent(event);
 
1131
    m_strutsTimer->stop();
 
1132
    m_strutsTimer->start(STRUTSTIMERDELAY);
 
1133
    recreateUnhideTrigger();
 
1134
 
 
1135
    if (containment()) {
 
1136
        foreach (Plasma::Applet *applet, containment()->applets()) {
 
1137
            applet->updateConstraints(Plasma::PopupConstraint);
 
1138
        }
 
1139
    }
 
1140
}
 
1141
 
 
1142
void PanelView::resizeEvent(QResizeEvent *event)
 
1143
{
 
1144
    //kDebug() << event->oldSize() << event->size();
 
1145
    Plasma::View::resizeEvent(event);
 
1146
    recreateUnhideTrigger();
 
1147
    m_strutsTimer->stop();
 
1148
    m_strutsTimer->start(STRUTSTIMERDELAY);
 
1149
#ifdef Q_WS_WIN
 
1150
    appBarPosChanged();
 
1151
#endif
 
1152
 
 
1153
    if (containment()) {
 
1154
        foreach (Plasma::Applet *applet, containment()->applets()) {
 
1155
            applet->updateConstraints(Plasma::PopupConstraint);
 
1156
        }
 
1157
    }
 
1158
}
 
1159
 
 
1160
void PanelView::updateHinter()
 
1161
{
 
1162
#ifdef Q_WS_X11
 
1163
    QPoint mousePos = QCursor::pos();
 
1164
    m_glowBar->updateStrength(mousePos);
 
1165
 
 
1166
    if (!m_unhideTriggerGeom.contains(mousePos)) {
 
1167
        hideHinter();
 
1168
        XMoveResizeWindow(QX11Info::display(), m_unhideTrigger, m_unhideTriggerGeom.x(), m_unhideTriggerGeom.y(), m_unhideTriggerGeom.width(), m_unhideTriggerGeom.height());
 
1169
    }
 
1170
#endif
 
1171
}
 
1172
 
 
1173
QRect PanelView::unhideHintGeometry() const
 
1174
{
 
1175
#ifdef Q_WS_X11
 
1176
    return m_unhideTriggerGeom;
 
1177
#else
 
1178
    return QRect();
 
1179
#endif
 
1180
}
 
1181
 
 
1182
bool PanelView::hintOrUnhide(const QPoint &point, bool dueToDnd)
 
1183
{
 
1184
#ifdef Q_WS_X11
 
1185
    if (m_visibilityMode != LetWindowsCover && isVisible()) {
 
1186
        return false;
 
1187
    }
 
1188
 
 
1189
    KWindowInfo activeWindow = KWindowSystem::windowInfo(KWindowSystem::activeWindow(), NET::WMState);
 
1190
    if (activeWindow.state() & NET::FullScreen) {
 
1191
        return false;
 
1192
    }
 
1193
 
 
1194
    if (!shouldHintHide()) {
 
1195
        //kDebug() << "should not hint hide";
 
1196
        unhide(!dueToDnd);
 
1197
        return true;
 
1198
    }
 
1199
 
 
1200
    //kDebug() << point << m_triggerZone;
 
1201
    if (m_triggerZone.contains(point)) {
 
1202
        //kDebug() << "unhide!" << point;
 
1203
        unhide(!dueToDnd);
 
1204
        return true;
 
1205
    } else if (!m_glowBar) {
 
1206
        Plasma::Direction direction = Plasma::locationToDirection(location());
 
1207
        m_glowBar = new GlowBar(direction, m_triggerZone);
 
1208
        m_glowBar->show();
 
1209
        XMoveResizeWindow(QX11Info::display(), m_unhideTrigger, m_triggerZone.x(), m_triggerZone.y(), m_triggerZone.width(), m_triggerZone.height());
 
1210
 
 
1211
        //FIXME: This is ugly as hell but well, yeah
 
1212
        if (!m_mousePollTimer) {
 
1213
            m_mousePollTimer = new QTimer(this);
 
1214
        }
 
1215
 
 
1216
        connect(m_mousePollTimer, SIGNAL(timeout()), this, SLOT(updateHinter()), Qt::UniqueConnection);
 
1217
        m_mousePollTimer->start(200);
 
1218
    }
 
1219
 
 
1220
    return false;
 
1221
#else
 
1222
    return false;
 
1223
#endif
 
1224
}
 
1225
 
 
1226
void PanelView::hideHinter()
 
1227
{
 
1228
    //kDebug() << "hide the glow";
 
1229
    if (m_mousePollTimer) {
 
1230
        m_mousePollTimer->stop();
 
1231
        disconnect(m_mousePollTimer, SIGNAL(timeout()), this, SLOT(updateHinter()));
 
1232
    }
 
1233
 
 
1234
    delete m_glowBar;
 
1235
    m_glowBar = 0;
 
1236
}
 
1237
 
 
1238
bool PanelView::hasPopup()
 
1239
{
 
1240
    if (QApplication::activePopupWidget() || m_panelController) {
 
1241
        return true;
 
1242
    }
 
1243
 
 
1244
    if (containment()) {
 
1245
        foreach (Plasma::Applet *applet, containment()->applets()) {
 
1246
            if (applet->isPopupShowing()) {
 
1247
                return true;
 
1248
            }
 
1249
        }
 
1250
    }
 
1251
 
 
1252
    return false;
 
1253
}
 
1254
 
 
1255
void PanelView::unhide(bool destroyTrigger)
 
1256
{
 
1257
    //kill the unhide stuff
 
1258
    hideHinter();
 
1259
    if (destroyTrigger) {
 
1260
        destroyUnhideTrigger();
 
1261
    }
 
1262
 
 
1263
    //ensure it's visible
 
1264
    if (!isVisible()) {
 
1265
        Plasma::WindowEffects::slideWindow(this, location());
 
1266
        show();
 
1267
    }
 
1268
 
 
1269
    KWindowSystem::setOnAllDesktops(winId(), true);
 
1270
 
 
1271
    //non-hiding panels stop here
 
1272
    if (m_visibilityMode == NormalPanel || m_visibilityMode == WindowsGoBelow) {
 
1273
        return;
 
1274
    }
 
1275
 
 
1276
    //set up the re-hiding stuff
 
1277
    if (!m_mousePollTimer) {
 
1278
        m_mousePollTimer = new QTimer(this);
 
1279
    }
 
1280
 
 
1281
    connect(m_mousePollTimer, SIGNAL(timeout()), this, SLOT(startAutoHide()), Qt::UniqueConnection);
 
1282
    m_mousePollTimer->start(500);
 
1283
 
 
1284
    //avoid hide-show loops
 
1285
    if (m_visibilityMode == LetWindowsCover) {
 
1286
        m_triggerEntered = true;
 
1287
        KWindowSystem::clearState(winId(), NET::KeepBelow);
 
1288
        KWindowSystem::raiseWindow(winId());
 
1289
        QTimer::singleShot(0, this, SLOT(resetTriggerEnteredSuppression()));
 
1290
    }
 
1291
}
 
1292
 
 
1293
void PanelView::statusUpdated(Plasma::ItemStatus newStatus)
 
1294
{
 
1295
    if (newStatus == Plasma::AcceptingInputStatus) {
 
1296
        KWindowSystem::forceActiveWindow(winId());
 
1297
    }
 
1298
}
 
1299
 
 
1300
void PanelView::checkUnhide(Plasma::ItemStatus newStatus)
 
1301
{
 
1302
    //kDebug() << "================= got a status: " << newStatus << Plasma::ActiveStatus;
 
1303
    m_respectStatus = true;
 
1304
 
 
1305
    if (newStatus > Plasma::ActiveStatus) {
 
1306
        unhide();
 
1307
        if (newStatus == Plasma::NeedsAttentionStatus) {
 
1308
            //kDebug() << "starting the timer!";
 
1309
            // start our rehide timer, so that the panel doesn't stay up and stuck forever and a day
 
1310
            m_rehideAfterAutounhideTimer->start(AUTOUNHIDE_CHECK_DELAY);
 
1311
        }
 
1312
    } else {
 
1313
        //kDebug() << "new status, just autohiding";
 
1314
        startAutoHide();
 
1315
    }
 
1316
}
 
1317
 
 
1318
void PanelView::checkAutounhide()
 
1319
{
 
1320
    //kDebug() << "***************************" << KIdleTime::instance()->idleTime();
 
1321
    if (KIdleTime::instance()->idleTime() >= AUTOUNHIDE_CHECK_DELAY) {
 
1322
        // the user is idle .. let's not hige the panel on them quite yet, but rather given them a
 
1323
        // chance to see this thing!
 
1324
        connect(KIdleTime::instance(), SIGNAL(resumingFromIdle()), this, SLOT(checkAutounhide()),
 
1325
                Qt::UniqueConnection);
 
1326
        KIdleTime::instance()->catchNextResumeEvent();
 
1327
        //kDebug() << "exit 1 ***************************";
 
1328
        return;
 
1329
    }
 
1330
 
 
1331
    m_respectStatus = false;
 
1332
    //kDebug() << "in to check ... who's resonsible?" << sender() << KIdleTime::instance();
 
1333
    if (sender() == KIdleTime::instance()) {
 
1334
        //kDebug() << "doing a 2s wait";
 
1335
        QTimer::singleShot(2000, this, SLOT(startAutoHide()));
 
1336
    } else {
 
1337
        //kDebug() << "just starting autohide!";
 
1338
        startAutoHide();
 
1339
    }
 
1340
 
 
1341
    // this line must come after the check on sender() as it *clears* that value!
 
1342
    disconnect(KIdleTime::instance(), SIGNAL(resumingFromIdle()), this, SLOT(checkAutounhide()));
 
1343
    //kDebug() << "exit 0 ***************************";
 
1344
}
 
1345
 
 
1346
void PanelView::unhide()
 
1347
{
 
1348
    unhide(true);
 
1349
}
 
1350
 
 
1351
void PanelView::resetTriggerEnteredSuppression()
 
1352
{
 
1353
    m_triggerEntered = false;
 
1354
}
 
1355
 
 
1356
void PanelView::startAutoHide()
 
1357
{
 
1358
    /*
 
1359
    kDebug() << m_editing << (containment() ? containment()->status() : 0) << Plasma::ActiveStatus
 
1360
             << geometry().adjusted(-10, -10, 10, 10).contains(QCursor::pos()) << hasPopup();
 
1361
    if (containment() && containment()->status() > Plasma::ActiveStatus) {
 
1362
        foreach (Plasma::Applet *applet, containment()->applets()) {
 
1363
            kDebug() << "     " << applet->name() << applet->status();
 
1364
        }
 
1365
    }
 
1366
    */
 
1367
 
 
1368
 
 
1369
    if (m_editing || (m_respectStatus && (containment() && containment()->status() > Plasma::ActiveStatus))) {
 
1370
        if (m_mousePollTimer) {
 
1371
            m_mousePollTimer->stop();
 
1372
            disconnect(m_mousePollTimer, SIGNAL(timeout()), this, SLOT(startAutoHide()));
 
1373
        }
 
1374
 
 
1375
        return;
 
1376
    }
 
1377
 
 
1378
    // since we've gotten this far, we don't need to worry about rehiding-after-auto-unhide, so just
 
1379
    // stop the timer
 
1380
    m_rehideAfterAutounhideTimer->stop();
 
1381
 
 
1382
    if (geometry().adjusted(-10, -10, 10, 10).contains(QCursor::pos()) || hasPopup()) {
 
1383
        if (!m_mousePollTimer) {
 
1384
            leaveEvent(0);
 
1385
        }
 
1386
        return;
 
1387
    }
 
1388
 
 
1389
    if (m_mousePollTimer) {
 
1390
        m_mousePollTimer->stop();
 
1391
        disconnect(m_mousePollTimer, SIGNAL(timeout()), this, SLOT(startAutoHide()));
 
1392
    }
 
1393
 
 
1394
    if (m_visibilityMode == LetWindowsCover) {
 
1395
        KWindowSystem::setState(winId(), NET::KeepBelow);
 
1396
        KWindowSystem::lowerWindow(winId());
 
1397
        createUnhideTrigger();
 
1398
    } else {
 
1399
        Plasma::WindowEffects::slideWindow(this, location());
 
1400
        createUnhideTrigger();
 
1401
        hide();
 
1402
    }
 
1403
}
 
1404
 
 
1405
void PanelView::leaveEvent(QEvent *event)
 
1406
{
 
1407
    if (m_visibilityMode == LetWindowsCover && m_triggerEntered) {
 
1408
        //this prevents crazy hide-unhide loops that can happen at times
 
1409
        m_triggerEntered = false;
 
1410
    } else if (containment() &&
 
1411
               (m_visibilityMode == AutoHide || m_visibilityMode == LetWindowsCover) && !m_editing) {
 
1412
        // even if we dont have a popup, we'll start a timer, so
 
1413
        // that the panel stays if the mouse only leaves for a
 
1414
        // few ms
 
1415
        if (!m_mousePollTimer) {
 
1416
            m_mousePollTimer = new QTimer(this);
 
1417
        }
 
1418
 
 
1419
        connect(m_mousePollTimer, SIGNAL(timeout()), this, SLOT(startAutoHide()), Qt::UniqueConnection);
 
1420
        m_mousePollTimer->start(500);
 
1421
    }
 
1422
 
 
1423
    if (event) {
 
1424
        // startAutoHide calls this with a null event pointer, so we have to check it
 
1425
        Plasma::View::leaveEvent(event);
 
1426
    }
 
1427
}
 
1428
 
 
1429
void PanelView::drawBackground(QPainter *painter, const QRectF &rect)
 
1430
{
 
1431
    if (PlasmaApp::hasComposite()) {
 
1432
        painter->setCompositionMode(QPainter::CompositionMode_Source);
 
1433
        painter->fillRect(rect.toAlignedRect(), Qt::transparent);
 
1434
    } else {
 
1435
        Plasma::View::drawBackground(painter, rect);
 
1436
    }
 
1437
}
 
1438
 
 
1439
void PanelView::paintEvent(QPaintEvent *event)
 
1440
{
 
1441
    Plasma::View::paintEvent(event);
 
1442
}
 
1443
 
 
1444
bool PanelView::event(QEvent *event)
 
1445
{
 
1446
    if (event->type() == QEvent::Paint) {
 
1447
        QPainter p(this);
 
1448
        p.setCompositionMode(QPainter::CompositionMode_Source);
 
1449
        p.fillRect(rect(), Qt::transparent);
 
1450
    }
 
1451
 
 
1452
    return Plasma::View::event(event);
 
1453
}
 
1454
 
 
1455
void PanelView::appletAdded(Plasma::Applet *applet)
 
1456
{
 
1457
    if (m_panelController && containment()->containmentType() == Plasma::Containment::PanelContainment) {
 
1458
        QColor overlayColor(Plasma::Theme::defaultTheme()->color(Plasma::Theme::BackgroundColor));
 
1459
        QBrush overlayBrush(overlayColor);
 
1460
        QPalette p(palette());
 
1461
        p.setBrush(QPalette::Window, overlayBrush);
 
1462
 
 
1463
        PanelAppletOverlay *moveOverlay = new PanelAppletOverlay(applet, this);
 
1464
        connect(moveOverlay, SIGNAL(removedWithApplet(PanelAppletOverlay*)),
 
1465
                this, SLOT(overlayDestroyed(PanelAppletOverlay*)));
 
1466
        moveOverlay->setPalette(p);
 
1467
        moveOverlay->show();
 
1468
        moveOverlay->raise();
 
1469
        m_appletOverlays << moveOverlay;
 
1470
 
 
1471
        QWidget *prior = m_panelController;
 
1472
        Plasma::Applet *priorApplet = 0;
 
1473
        foreach (Plasma::Applet *otherApplet, containment()->applets()) {
 
1474
            if (applet == otherApplet) {
 
1475
                break;
 
1476
            }
 
1477
 
 
1478
            priorApplet = otherApplet;
 
1479
        }
 
1480
 
 
1481
        if (priorApplet) {
 
1482
            foreach (PanelAppletOverlay *overlay, m_appletOverlays) {
 
1483
                if (overlay->applet() == priorApplet) {
 
1484
                    prior = overlay;
 
1485
                    break;
 
1486
                }
 
1487
            }
 
1488
        }
 
1489
 
 
1490
        setTabOrder(prior, moveOverlay);
 
1491
    }
 
1492
}
 
1493
 
 
1494
bool PanelView::shouldHintHide() const
 
1495
{
 
1496
    return m_visibilityMode == AutoHide && PlasmaApp::hasComposite();
 
1497
}
 
1498
 
 
1499
void PanelView::recreateUnhideTrigger()
 
1500
{
 
1501
#ifdef Q_WS_X11
 
1502
    if (m_unhideTrigger == None) {
 
1503
        return;
 
1504
    }
 
1505
 
 
1506
    XDestroyWindow(QX11Info::display(), m_unhideTrigger);
 
1507
    m_unhideTrigger = None;
 
1508
    createUnhideTrigger();
 
1509
#endif
 
1510
}
 
1511
 
 
1512
void PanelView::createUnhideTrigger()
 
1513
{
 
1514
#ifdef Q_WS_X11
 
1515
    //kDebug() << m_unhideTrigger << None;
 
1516
    if (m_unhideTrigger != None) {
 
1517
        return;
 
1518
    }
 
1519
 
 
1520
    bool fancy = shouldHintHide();
 
1521
    int actualWidth = 1;
 
1522
    int actualHeight = 1;
 
1523
    int triggerWidth = fancy ? 30 : 1;
 
1524
    int triggerHeight = fancy ? 30 : 1;
 
1525
 
 
1526
    QPoint actualTriggerPoint = pos();
 
1527
    QPoint triggerPoint = pos();
 
1528
 
 
1529
    switch (location()) {
 
1530
        case Plasma::TopEdge:
 
1531
            actualWidth = triggerWidth = width();
 
1532
 
 
1533
            if (fancy) {
 
1534
                triggerWidth += 30;
 
1535
                triggerPoint.setX(qMax(0, triggerPoint.x() - 15));
 
1536
            }
 
1537
            break;
 
1538
        case Plasma::BottomEdge:
 
1539
            actualWidth = triggerWidth = width();
 
1540
            actualTriggerPoint = triggerPoint = geometry().bottomLeft();
 
1541
 
 
1542
            if (fancy) {
 
1543
                triggerWidth += 30;
 
1544
                triggerPoint.setX(qMax(0, triggerPoint.x() - 15));
 
1545
                triggerPoint.setY(qMax(0, triggerPoint.y() - 29));
 
1546
            }
 
1547
            break;
 
1548
        case Plasma::RightEdge:
 
1549
            actualHeight = triggerHeight = height();
 
1550
            actualTriggerPoint = triggerPoint = geometry().topRight();
 
1551
 
 
1552
            if (fancy) {
 
1553
                triggerHeight += 30;
 
1554
                triggerPoint.setY(qMax(0, triggerPoint.y() - 15));
 
1555
                triggerPoint.setX(qMax(0, triggerPoint.x() - 29));
 
1556
            }
 
1557
            break;
 
1558
        case Plasma::LeftEdge:
 
1559
            actualHeight = triggerHeight = height();
 
1560
 
 
1561
            if (fancy) {
 
1562
                triggerHeight += 30;
 
1563
                triggerPoint.setY(qMax(0, triggerPoint.y() - 15));
 
1564
            }
 
1565
            break;
 
1566
        default:
 
1567
            // no hiding unless we're on an edge.
 
1568
            return;
 
1569
            break;
 
1570
    }
 
1571
 
 
1572
 
 
1573
    XSetWindowAttributes attributes;
 
1574
    attributes.override_redirect = True;
 
1575
    attributes.event_mask = EnterWindowMask;
 
1576
 
 
1577
 
 
1578
    attributes.event_mask = EnterWindowMask | LeaveWindowMask | PointerMotionMask |
 
1579
                            KeyPressMask | KeyPressMask | ButtonPressMask |
 
1580
                            ButtonReleaseMask | ButtonMotionMask |
 
1581
                            KeymapStateMask | VisibilityChangeMask |
 
1582
                            StructureNotifyMask | ResizeRedirectMask |
 
1583
                            SubstructureNotifyMask |
 
1584
                            SubstructureRedirectMask | FocusChangeMask |
 
1585
                            PropertyChangeMask | ColormapChangeMask | OwnerGrabButtonMask;
 
1586
 
 
1587
    unsigned long valuemask = CWOverrideRedirect | CWEventMask;
 
1588
    m_unhideTrigger = XCreateWindow(QX11Info::display(), QX11Info::appRootWindow(),
 
1589
                                    triggerPoint.x(), triggerPoint.y(), triggerWidth, triggerHeight,
 
1590
                                    0, CopyFromParent, InputOnly, CopyFromParent,
 
1591
                                    valuemask, &attributes);
 
1592
 
 
1593
    XChangeProperty(QX11Info::display(), m_unhideTrigger, PlasmaApp::self()->m_XdndAwareAtom,
 
1594
                    XA_WINDOW, 32, PropModeReplace, (unsigned char *)&PlasmaApp::self()->m_XdndVersionAtom, 1);
 
1595
    XMapWindow(QX11Info::display(), m_unhideTrigger);
 
1596
    m_unhideTriggerGeom = QRect(triggerPoint, QSize(triggerWidth, triggerHeight));
 
1597
    m_triggerZone = QRect(actualTriggerPoint, QSize(actualWidth, actualHeight));
 
1598
#endif
 
1599
    //kDebug() << m_unhideTrigger;
 
1600
    PlasmaApp::self()->panelHidden(true);
 
1601
}
 
1602
 
 
1603
void PanelView::destroyUnhideTrigger()
 
1604
{
 
1605
#ifdef Q_WS_X11
 
1606
    if (m_unhideTrigger == None) {
 
1607
        return;
 
1608
    }
 
1609
 
 
1610
    //kDebug();
 
1611
    XDestroyWindow(QX11Info::display(), m_unhideTrigger);
 
1612
    m_unhideTrigger = None;
 
1613
    m_triggerZone = m_unhideTriggerGeom = QRect();
 
1614
#endif
 
1615
 
 
1616
    //kDebug();
 
1617
    PlasmaApp::self()->panelHidden(false);
 
1618
}
 
1619
 
 
1620
void PanelView::panelDeleted()
 
1621
{
 
1622
    if (!QApplication::closingDown()) {
 
1623
        // the panel was removed at runtime; clean up our configuration object as well
 
1624
        KConfigGroup c = config();
 
1625
        c.deleteGroup();
 
1626
        configNeedsSaving();
 
1627
    }
 
1628
 
 
1629
    delete m_mousePollTimer;
 
1630
    m_mousePollTimer = 0;
 
1631
    m_strutsTimer->stop();
 
1632
 
 
1633
    deleteLater();
 
1634
}
 
1635
 
 
1636
void PanelView::positionSpacer(const QPoint pos)
 
1637
{
 
1638
    if (!containment()) {
 
1639
        return;
 
1640
    }
 
1641
 
 
1642
    QGraphicsLinearLayout *lay = dynamic_cast<QGraphicsLinearLayout*>(containment()->layout());
 
1643
 
 
1644
    if (!lay) {
 
1645
        return;
 
1646
    }
 
1647
 
 
1648
    Plasma::FormFactor f = containment()->formFactor();
 
1649
    int insertIndex = -1;
 
1650
 
 
1651
    //FIXME: needed in two places, make it a function?
 
1652
    for (int i = 0; i < lay->count(); ++i) {
 
1653
        QRectF siblingGeometry = lay->itemAt(i)->geometry();
 
1654
 
 
1655
        if (f == Plasma::Horizontal) {
 
1656
            qreal middle = (siblingGeometry.left() + siblingGeometry.right()) / 2.0;
 
1657
            if (pos.x() < middle) {
 
1658
                insertIndex = i;
 
1659
                break;
 
1660
            } else if (pos.x() <= siblingGeometry.right()) {
 
1661
                insertIndex = i + 1;
 
1662
                break;
 
1663
            }
 
1664
        } else { // Plasma::Vertical
 
1665
            qreal middle = (siblingGeometry.top() + siblingGeometry.bottom()) / 2.0;
 
1666
            if (pos.y() < middle) {
 
1667
                insertIndex = i;
 
1668
                break;
 
1669
            } else if (pos.y() <= siblingGeometry.bottom()) {
 
1670
                insertIndex = i + 1;
 
1671
                break;
 
1672
            }
 
1673
        }
 
1674
    }
 
1675
 
 
1676
    m_spacerIndex = insertIndex;
 
1677
    if (insertIndex != -1) {
 
1678
        if (!m_spacer) {
 
1679
            m_spacer = new QGraphicsWidget(containment());
 
1680
            //m_spacer->panel = this;
 
1681
        }
 
1682
        lay->removeItem(m_spacer);
 
1683
        m_spacer->show();
 
1684
        lay->insertItem(insertIndex, m_spacer);
 
1685
    }
 
1686
}
 
1687
 
 
1688
void PanelView::dragLeaveEvent(QDragLeaveEvent *event)
 
1689
{
 
1690
    if (containment()) {
 
1691
        containment()->showDropZone(QPoint());
 
1692
    }
 
1693
 
 
1694
    Plasma::View::dragLeaveEvent(event);
 
1695
}
 
1696
 
 
1697
void PanelView::dropEvent(QDropEvent *event)
 
1698
{
 
1699
    Plasma::View::dropEvent(event);
 
1700
 
 
1701
    if (containment()) {
 
1702
        containment()->showDropZone(QPoint());
 
1703
    }
 
1704
}
 
1705
 
 
1706
#include "panelview.moc"
 
1707