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

« back to all changes in this revision

Viewing changes to plasma/desktop/shell/controllerwindow.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 2008 Marco Martin <notmart@gmail.com>
 
3
 *   Copyright 2009 Aaron Seigo <aseigo@kde.org>
 
4
 *   Copyright 2010 Chani Armitage <chani@kde.org>
 
5
 *
 
6
 *   This program is free software; you can redistribute it and/or modify
 
7
 *   it under the terms of the GNU Library General Public License as
 
8
 *   published by the Free Software Foundation; either version 2, or
 
9
 *   (at your option) any later version.
 
10
 *
 
11
 *   This program is distributed in the hope that it will be useful,
 
12
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
 *   GNU General Public License for more details
 
15
 *
 
16
 *   You should have received a copy of the GNU Library General Public
 
17
 *   License along with this program; if not, write to the
 
18
 *   Free Software Foundation, Inc.,
 
19
 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 
20
 */
 
21
 
 
22
#include "controllerwindow.h"
 
23
 
 
24
#include <QApplication>
 
25
#include <QBoxLayout>
 
26
#include <QPainter>
 
27
 
 
28
#include <kwindowsystem.h>
 
29
#include <netwm.h>
 
30
 
 
31
#include <Plasma/Containment>
 
32
#include <Plasma/Corona>
 
33
#include <Plasma/Theme>
 
34
#include <Plasma/FrameSvg>
 
35
#include <Plasma/Dialog>
 
36
#include <Plasma/WindowEffects>
 
37
 
 
38
#include "activitymanager/activitymanager.h"
 
39
#include "desktopcorona.h"
 
40
#include "panelview.h"
 
41
#include "plasmaapp.h"
 
42
#include "widgetsexplorer/widgetexplorer.h"
 
43
 
 
44
#include <kephal/screens.h>
 
45
 
 
46
ControllerWindow::ControllerWindow(QWidget* parent)
 
47
   : QWidget(parent),
 
48
     m_location(Plasma::Floating),
 
49
     m_layout(new QBoxLayout(QBoxLayout::TopToBottom, this)),
 
50
     m_background(new Plasma::FrameSvg(this)),
 
51
     m_screen(-1),
 
52
     m_corona(0),
 
53
     m_view(0),
 
54
     m_watchedWidget(0),
 
55
     m_activityManager(0),
 
56
     m_widgetExplorer(0),
 
57
     m_graphicsWidget(0)
 
58
{
 
59
    Q_UNUSED(parent)
 
60
 
 
61
    m_background->setImagePath("dialogs/background");
 
62
    m_background->setContainsMultipleImages(true);
 
63
 
 
64
    setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint);
 
65
    KWindowSystem::setState(winId(), NET::SkipTaskbar | NET::SkipPager | NET::Sticky | NET::KeepAbove);
 
66
    setAttribute(Qt::WA_DeleteOnClose);
 
67
    setAttribute(Qt::WA_TranslucentBackground);
 
68
    setFocus(Qt::ActiveWindowFocusReason);
 
69
    setLocation(Plasma::BottomEdge);
 
70
 
 
71
    QPalette pal = palette();
 
72
    pal.setBrush(backgroundRole(), Qt::transparent);
 
73
    setPalette(pal);
 
74
 
 
75
    Plasma::WindowEffects::overrideShadow(winId(), true);
 
76
 
 
77
 
 
78
    m_layout->setContentsMargins(0, 0, 0, 0);
 
79
 
 
80
    connect(KWindowSystem::self(), SIGNAL(activeWindowChanged(WId)), this, SLOT(onActiveWindowChanged(WId)));
 
81
    connect(m_background, SIGNAL(repaintNeeded()), SLOT(backgroundChanged()));
 
82
    Kephal::Screens *screens = Kephal::Screens::self();
 
83
    connect(screens, SIGNAL(screenResized(Kephal::Screen *, QSize, QSize)),
 
84
            this, SLOT(adjustAndSetMaxSize()));
 
85
    m_adjustViewTimer = new QTimer(this);
 
86
    m_adjustViewTimer->setSingleShot(true);
 
87
    connect(m_adjustViewTimer, SIGNAL(timeout()), this, SLOT(syncToGraphicsWidget()));
 
88
    adjustAndSetMaxSize();
 
89
}
 
90
 
 
91
ControllerWindow::~ControllerWindow()
 
92
{
 
93
 
 
94
    if (m_activityManager) {
 
95
        if (m_corona) {
 
96
            m_corona->removeOffscreenWidget(m_activityManager);
 
97
        }
 
98
        //FIXME the qt4.6 comment below applies here too
 
99
    }
 
100
    if (m_widgetExplorer) {
 
101
        if (m_corona) {
 
102
            m_corona->removeOffscreenWidget(m_widgetExplorer);
 
103
        }
 
104
 
 
105
        if (m_widgetExplorer->scene()) {
 
106
            //FIXME: causes a crash in Qt 4.6 *sigh*
 
107
            //m_widgetExplorer->scene()->removeItem(m_widgetExplorer);
 
108
        }
 
109
    }
 
110
 
 
111
    delete m_activityManager;
 
112
    delete m_widgetExplorer;
 
113
    delete m_view;
 
114
}
 
115
 
 
116
void ControllerWindow::activate()
 
117
{
 
118
    KWindowSystem::activateWindow(winId());
 
119
}
 
120
 
 
121
void ControllerWindow::adjustAndSetMaxSize()
 
122
{
 
123
    QSize screenSize = PlasmaApp::self()->corona()->screenGeometry(PlasmaApp::self()->corona()->screenId(pos())).size();
 
124
    setMaximumSize(screenSize);
 
125
    adjustSize();
 
126
}
 
127
 
 
128
void ControllerWindow::backgroundChanged()
 
129
{
 
130
    Plasma::Location l = m_location;
 
131
    m_location = Plasma::Floating;
 
132
    setLocation(l);
 
133
    update();
 
134
}
 
135
 
 
136
void ControllerWindow::setContainment(Plasma::Containment *containment)
 
137
{
 
138
    if (containment == m_containment.data()) {
 
139
        return;
 
140
    }
 
141
 
 
142
    if (m_containment) {
 
143
        disconnect(m_containment.data(), 0, this, 0);
 
144
    }
 
145
 
 
146
    m_containment = containment;
 
147
 
 
148
    if (!containment) {
 
149
        return;
 
150
    }
 
151
 
 
152
    m_corona = containment->corona();
 
153
    m_screen = containment->screen();
 
154
 
 
155
    if (m_widgetExplorer) {
 
156
        m_widgetExplorer->setContainment(containment);
 
157
    }
 
158
}
 
159
 
 
160
Plasma::Containment *ControllerWindow::containment() const
 
161
{
 
162
    return m_containment.data();
 
163
}
 
164
 
 
165
void ControllerWindow::setGraphicsWidget(QGraphicsWidget *widget)
 
166
{
 
167
    if (m_graphicsWidget == widget) {
 
168
        return;
 
169
    }
 
170
 
 
171
    if (m_graphicsWidget) {
 
172
        m_graphicsWidget->removeEventFilter(this);
 
173
        if (m_graphicsWidget == m_widgetExplorer) {
 
174
            m_widgetExplorer->deleteLater();
 
175
            m_widgetExplorer = 0;
 
176
        } else if (m_graphicsWidget == m_activityManager) {
 
177
            m_activityManager->deleteLater();
 
178
            m_activityManager = 0;
 
179
        }
 
180
    }
 
181
 
 
182
    m_graphicsWidget = widget;
 
183
 
 
184
    if (widget) {
 
185
        if (!layout()) {
 
186
            QVBoxLayout *lay = new QVBoxLayout(this);
 
187
            lay->setMargin(0);
 
188
            lay->setSpacing(0);
 
189
        }
 
190
 
 
191
        if (!m_view) {
 
192
            m_view = new QGraphicsView(this);
 
193
            m_view->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
 
194
            m_view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
 
195
            m_view->setFrameShape(QFrame::NoFrame);
 
196
            m_view->viewport()->setAutoFillBackground(false);
 
197
            layout()->addWidget(m_view);
 
198
        }
 
199
 
 
200
        m_view->setScene(widget->scene());
 
201
 
 
202
        //try to have the proper size -before- showing the dialog
 
203
        m_view->centerOn(widget);
 
204
        if (widget->layout()) {
 
205
            widget->layout()->activate();
 
206
        }
 
207
        static_cast<QGraphicsLayoutItem *>(widget)->updateGeometry();
 
208
        widget->resize(widget->size().expandedTo(widget->effectiveSizeHint(Qt::MinimumSize)));
 
209
 
 
210
        syncToGraphicsWidget();
 
211
 
 
212
        //adjustSizeTimer->start(150);
 
213
 
 
214
        widget->installEventFilter(this);
 
215
        adjustSize();
 
216
 
 
217
        bool moved = false;
 
218
        if (PlasmaApp::isPanelContainment(containment())) {
 
219
            // try to align it with the appropriate panel view
 
220
            foreach (PanelView * panel, PlasmaApp::self()->panelViews()) {
 
221
                if (panel->containment() == containment()) {
 
222
                    move(positionForPanelGeometry(panel->geometry()));
 
223
                    moved = true;
 
224
                    break;
 
225
                }
 
226
            }
 
227
        }
 
228
 
 
229
        if (!moved) {
 
230
            // set it to the bottom of the screen as we have no better hints to go by
 
231
            QRect geom = PlasmaApp::self()->corona()->availableScreenRect(m_screen);
 
232
            setGeometry(geom.x(), geom.bottom() - height(), geom.width(), height());
 
233
        }
 
234
    } else {
 
235
        delete m_view;
 
236
        m_view = 0;
 
237
    }
 
238
}
 
239
 
 
240
void ControllerWindow::syncToGraphicsWidget()
 
241
{
 
242
    m_adjustViewTimer->stop();
 
243
    if (m_view && m_graphicsWidget) {
 
244
        QSize prevSize = size();
 
245
 
 
246
        //set the sizehints correctly:
 
247
        int left, top, right, bottom;
 
248
        getContentsMargins(&left, &top, &right, &bottom);
 
249
 
 
250
        //Try to use the screenId directly from the containment, because it won't fail.
 
251
        //If we dont' have containment. try to get the screen by using QWidget::pos(), but it
 
252
        //may fail if syncToGraphicsWidget is called before a real position is set (so pos() will
 
253
        //just return 0x0, which may lead to the wrong screen
 
254
        const QRect screenRect = m_containment ? 
 
255
                                 PlasmaApp::self()->corona()->screenGeometry(m_containment.data()->screen()) :
 
256
                                 PlasmaApp::self()->corona()->screenGeometry(PlasmaApp::self()->corona()->screenId(pos()));
 
257
 
 
258
        QSize maxSize = KWindowSystem::workArea().intersect(screenRect).size();
 
259
 
 
260
        QSize windowSize;
 
261
        if (m_location == Plasma::LeftEdge || m_location == Plasma::RightEdge) {
 
262
            windowSize = QSize(qMin(int(m_graphicsWidget->size().width()) + left + right, maxSize.width()), maxSize.height());
 
263
            m_graphicsWidget->resize(m_graphicsWidget->size().width(), windowSize.height());
 
264
        } else {
 
265
            windowSize = QSize(maxSize.width(), qMin(int(m_graphicsWidget->size().height()) + top + bottom, maxSize.height()));
 
266
            m_graphicsWidget->resize(windowSize.width(), m_graphicsWidget->size().height());
 
267
        }
 
268
 
 
269
        setMinimumSize(windowSize);
 
270
        resize(windowSize);
 
271
 
 
272
        updateGeometry();
 
273
 
 
274
        //reposition and resize the view.
 
275
        //force a valid rect, otherwise it will take up the whole scene
 
276
        QRectF sceneRect(m_graphicsWidget->sceneBoundingRect());
 
277
 
 
278
        sceneRect.setWidth(qMax(qreal(1), sceneRect.width()));
 
279
        sceneRect.setHeight(qMax(qreal(1), sceneRect.height()));
 
280
        m_view->setSceneRect(sceneRect);
 
281
 
 
282
        m_view->centerOn(m_graphicsWidget);
 
283
 
 
284
    }
 
285
}
 
286
 
 
287
bool ControllerWindow::eventFilter(QObject *watched, QEvent *event)
 
288
{
 
289
    if (watched == m_graphicsWidget &&
 
290
        (event->type() == QEvent::GraphicsSceneResize || event->type() == QEvent::GraphicsSceneMove)) {
 
291
        m_adjustViewTimer->start(150);
 
292
    }
 
293
 
 
294
    return QWidget::eventFilter(watched, event);
 
295
}
 
296
 
 
297
void ControllerWindow::setLocation(const Plasma::Location &loc)
 
298
{
 
299
    if (m_location == loc) {
 
300
        return;
 
301
    }
 
302
 
 
303
    Plasma::WindowEffects::slideWindow(this, loc);
 
304
 
 
305
    m_location = loc;
 
306
 
 
307
    switch (loc) {
 
308
    case Plasma::LeftEdge:
 
309
        m_background->setEnabledBorders(Plasma::FrameSvg::RightBorder);
 
310
        m_layout->setDirection(QBoxLayout::TopToBottom);
 
311
        setContentsMargins(0, 0, m_background->marginSize(Plasma::RightMargin), 0);
 
312
        break;
 
313
 
 
314
    case Plasma::RightEdge:
 
315
        m_background->setEnabledBorders(Plasma::FrameSvg::LeftBorder);
 
316
        m_layout->setDirection(QBoxLayout::TopToBottom);
 
317
        setContentsMargins(m_background->marginSize(Plasma::LeftMargin), 0, 0, 0);
 
318
        break;
 
319
 
 
320
    case Plasma::TopEdge:
 
321
        m_background->setEnabledBorders(Plasma::FrameSvg::BottomBorder);
 
322
        m_layout->setDirection(QBoxLayout::BottomToTop);
 
323
        setContentsMargins(0, 0, 0, m_background->marginSize(Plasma::BottomMargin));
 
324
        break;
 
325
 
 
326
    case Plasma::BottomEdge:
 
327
    default:
 
328
        m_background->setEnabledBorders(Plasma::FrameSvg::TopBorder);
 
329
        m_layout->setDirection(QBoxLayout::TopToBottom);
 
330
        setContentsMargins(0, m_background->marginSize(Plasma::TopMargin), 0, 0);
 
331
        break;
 
332
    }
 
333
 
 
334
    if (m_watchedWidget) {
 
335
        //FIXME maybe I should make these two inherit from something
 
336
        //or make orientation a slot.
 
337
        if (m_watchedWidget == (QGraphicsWidget*)m_widgetExplorer) {
 
338
            m_widgetExplorer->setLocation(location());
 
339
        } else {
 
340
            m_activityManager->setLocation(location());
 
341
        }
 
342
    }
 
343
}
 
344
 
 
345
QPoint ControllerWindow::positionForPanelGeometry(const QRect &panelGeom) const
 
346
{
 
347
    int screen;
 
348
    if (m_containment) {
 
349
        screen = m_containment.data()->screen();
 
350
    } else {
 
351
        //guess: 
 
352
        screen = PlasmaApp::self()->corona()->screenId(QCursor::pos());
 
353
    }
 
354
 
 
355
    QRect screenGeom = PlasmaApp::self()->corona()->screenGeometry(screen);
 
356
 
 
357
    switch (m_location) {
 
358
    case Plasma::LeftEdge:
 
359
        return QPoint(panelGeom.right(), screenGeom.top());
 
360
        break;
 
361
    case Plasma::RightEdge:
 
362
        return QPoint(panelGeom.left() - width(), screenGeom.top());
 
363
        break;
 
364
    case Plasma::TopEdge:
 
365
        return QPoint(screenGeom.left(), panelGeom.bottom());
 
366
        break;
 
367
    case Plasma::BottomEdge:
 
368
    default:
 
369
        return QPoint(screenGeom.left(), panelGeom.top() - height());
 
370
        break;
 
371
    }
 
372
}
 
373
 
 
374
Plasma::Location ControllerWindow::location() const
 
375
{
 
376
    return m_location;
 
377
}
 
378
 
 
379
Qt::Orientation ControllerWindow::orientation() const
 
380
{
 
381
    if (m_location == Plasma::LeftEdge || m_location == Plasma::RightEdge) {
 
382
        return Qt::Vertical;
 
383
    }
 
384
 
 
385
    return Qt::Horizontal;
 
386
}
 
387
 
 
388
 
 
389
void ControllerWindow::showWidgetExplorer()
 
390
{
 
391
    if (!m_containment) {
 
392
        return;
 
393
    }
 
394
 
 
395
    if (!m_widgetExplorer) {
 
396
        m_widgetExplorer = new Plasma::WidgetExplorer(location());
 
397
        m_watchedWidget = m_widgetExplorer;
 
398
        m_widgetExplorer->setContainment(m_containment.data());
 
399
        m_widgetExplorer->populateWidgetList();
 
400
        m_widgetExplorer->setIconSize(KIconLoader::SizeHuge);
 
401
        QAction *activityAction = new QAction(KIcon("preferences-activities"), i18n("Activities"), m_widgetExplorer);
 
402
        connect(activityAction, SIGNAL(triggered()), this, SLOT(showActivityManager()));
 
403
        m_widgetExplorer->addAction(activityAction);
 
404
 
 
405
        m_containment.data()->corona()->addOffscreenWidget(m_widgetExplorer);
 
406
        m_widgetExplorer->show();
 
407
 
 
408
        m_widgetExplorer->setIconSize(KIconLoader::SizeHuge);
 
409
 
 
410
        if (orientation() == Qt::Horizontal) {
 
411
            m_widgetExplorer->resize(width(), m_widgetExplorer->size().height());
 
412
        } else {
 
413
            m_widgetExplorer->resize(m_widgetExplorer->size().width(), height());
 
414
        }
 
415
 
 
416
        setGraphicsWidget(m_widgetExplorer);
 
417
 
 
418
        connect(m_widgetExplorer, SIGNAL(closeClicked()), this, SLOT(close()));
 
419
    } else {
 
420
        m_widgetExplorer->setLocation(location());
 
421
        m_widgetExplorer->show();
 
422
        m_watchedWidget = m_widgetExplorer;
 
423
        setGraphicsWidget(m_widgetExplorer);
 
424
    }
 
425
    m_widgetExplorer->setFocus();
 
426
}
 
427
 
 
428
bool ControllerWindow::showingWidgetExplorer() const
 
429
{
 
430
    return m_widgetExplorer;
 
431
}
 
432
 
 
433
void ControllerWindow::showActivityManager()
 
434
{
 
435
    if (!m_activityManager) {
 
436
        m_activityManager = new ActivityManager(location());
 
437
        m_watchedWidget = m_activityManager;
 
438
 
 
439
        m_corona->addOffscreenWidget(m_activityManager);
 
440
        m_activityManager->show();
 
441
 
 
442
        if (orientation() == Qt::Horizontal) {
 
443
            m_activityManager->resize(width(), m_activityManager->size().height());
 
444
        } else {
 
445
            m_activityManager->resize(m_activityManager->size().width(), height());
 
446
        }
 
447
 
 
448
        m_activityManager->setIconSize(KIconLoader::SizeHuge);
 
449
 
 
450
        setGraphicsWidget(m_activityManager);
 
451
 
 
452
        connect(m_activityManager, SIGNAL(addWidgetsRequested()), this, SLOT(showWidgetExplorer()));
 
453
        connect(m_activityManager, SIGNAL(closeClicked()), this, SLOT(close()));
 
454
    } else {
 
455
        m_activityManager->setLocation(location());
 
456
        m_watchedWidget = m_activityManager;
 
457
        m_activityManager->show();
 
458
        setGraphicsWidget(m_activityManager);
 
459
    }
 
460
    m_activityManager->setFlag(QGraphicsItem::ItemIsFocusable);
 
461
    m_activityManager->setFocus();
 
462
}
 
463
 
 
464
bool ControllerWindow::showingActivityManager() const
 
465
{
 
466
    return m_activityManager;
 
467
}
 
468
 
 
469
bool ControllerWindow::isControllerViewVisible() const
 
470
{
 
471
    return m_view && m_view->isVisible();
 
472
}
 
473
 
 
474
Plasma::FrameSvg *ControllerWindow::background() const
 
475
{
 
476
    return m_background;
 
477
}
 
478
 
 
479
int ControllerWindow::screen() const
 
480
{
 
481
    return m_screen;
 
482
}
 
483
 
 
484
void ControllerWindow::setScreen(int screen)
 
485
{
 
486
    m_screen = screen;
 
487
}
 
488
 
 
489
void ControllerWindow::onActiveWindowChanged(WId id)
 
490
{
 
491
    Q_UNUSED(id)
 
492
 
 
493
    // Small delay when closing due to lost focus
 
494
    QTimer::singleShot(300, this, SLOT(closeIfNotFocussed()));
 
495
}
 
496
 
 
497
void ControllerWindow::closeIfNotFocussed()
 
498
{
 
499
    if (!QApplication::activeWindow()) {
 
500
        close();
 
501
    }
 
502
}
 
503
 
 
504
void ControllerWindow::paintEvent(QPaintEvent *event)
 
505
{
 
506
    Q_UNUSED(event)
 
507
 
 
508
    QPainter painter(this);
 
509
    painter.setCompositionMode(QPainter::CompositionMode_Source );
 
510
 
 
511
    m_background->paintFrame(&painter);
 
512
}
 
513
 
 
514
void ControllerWindow::keyPressEvent(QKeyEvent *event)
 
515
{
 
516
    if (event->key() == Qt::Key_Escape) {
 
517
        close();
 
518
    }
 
519
}
 
520
 
 
521
void ControllerWindow::resizeEvent(QResizeEvent * event)
 
522
{
 
523
    m_background->resizeFrame(size());
 
524
 
 
525
    Plasma::WindowEffects::enableBlurBehind(effectiveWinId(), true, m_background->mask());
 
526
 
 
527
    qDebug() << "ControllerWindow::resizeEvent" << event->oldSize();
 
528
 
 
529
    QWidget::resizeEvent(event);
 
530
}
 
531
 
 
532
#include "controllerwindow.moc"