dtor first
[personal-kdebase.git] / workspace / plasma / shells / desktop / desktopview.cpp
blobed620f7b87e4551f5776c7acf64e383766b550d9
1 /*
2 * Copyright 2007 Aaron Seigo <aseigo@kde.org>
3 * Copyright 2007 Matt Broadstone <mbroadst@gmail.com>
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 as
7 * published by the Free Software Foundation
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
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.
20 #include "desktopview.h"
22 #include <QAction>
23 #include <QFile>
24 #include <QWheelEvent>
25 #include <QCoreApplication>
27 #include <KAuthorized>
28 #include <KMenu>
29 #include <KRun>
30 #include <KToggleAction>
31 #include <KWindowSystem>
33 #include <Plasma/Applet>
34 #include <Plasma/Corona>
35 #include <Plasma/Containment>
36 #include <Plasma/Svg>
37 #include <Plasma/Wallpaper>
38 #include <Plasma/Theme>
40 #include <kephal/screens.h>
42 #include "dashboardview.h"
43 #include "plasmaapp.h"
44 #include "plasma-shell-desktop.h"
46 #ifdef Q_WS_WIN
47 #include "windows.h"
48 #include "windef.h"
49 #include "wingdi.h"
50 #include "winuser.h"
51 #endif
53 DesktopView::DesktopView(Plasma::Containment *containment, int id, QWidget *parent)
54 : Plasma::View(containment, id, parent),
55 m_dashboard(0),
56 m_dashboardFollowsDesktop(true)
58 setFocusPolicy(Qt::NoFocus);
59 #ifdef Q_WS_WIN
60 setWindowFlags(Qt::FramelessWindowHint);
61 SetWindowPos(winId(), HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
62 HWND hwndDesktop = ::FindWindowW(L"Progman", NULL);
63 SetParent(winId(), hwndDesktop);
64 #else
65 setWindowFlags(windowFlags() | Qt::FramelessWindowHint);
66 #endif
68 if (AppSettings::perVirtualDesktopViews()) {
69 kDebug() << "setting to desktop" << containment->desktop() + 1;
70 KWindowSystem::setOnDesktop(winId(), containment->desktop() + 1);
71 } else {
72 KWindowSystem::setOnAllDesktops(winId(), true);
75 KWindowSystem::setType(winId(), NET::Desktop);
76 lower();
78 if (containment) {
79 containment->enableAction("zoom in", false);
80 containment->enableAction("add sibling containment", false);
82 //FIXME should we have next/prev or up/down/left/right or what?
83 QAction *action = new QAction(i18n("Next Activity"), this);
84 action->setShortcutContext(Qt::WidgetWithChildrenShortcut);
85 action->setShortcut(QKeySequence("ctrl+shift+n"));
86 connect(action, SIGNAL(triggered()), this, SLOT(nextContainment()));
87 addAction(action);
88 action = new QAction(i18n("Previous Activity"), this);
89 action->setShortcutContext(Qt::WidgetWithChildrenShortcut);
90 action->setShortcut(QKeySequence("ctrl+shift+p"));
91 connect(action, SIGNAL(triggered()), this, SLOT(previousContainment()));
92 addAction(action);
94 const int w = 25;
95 QPixmap tile(w * 2, w * 2);
96 tile.fill(palette().base().color());
97 QPainter pt(&tile);
98 QColor color = palette().mid().color();
99 color.setAlphaF(.6);
100 pt.fillRect(0, 0, w, w, color);
101 pt.fillRect(w, w, w, w, color);
102 pt.end();
103 QBrush b(tile);
104 setBackgroundBrush(tile);
106 adjustSize();
108 Kephal::Screens *screens = Kephal::Screens::self();
109 connect(screens, SIGNAL(screenResized(Kephal::Screen *, QSize, QSize)),
110 this, SLOT(screenResized(Kephal::Screen *)));
111 connect(screens, SIGNAL(screenMoved(Kephal::Screen *, QPoint, QPoint)),
112 this, SLOT(screenMoved(Kephal::Screen *)));
115 DesktopView::~DesktopView()
117 delete m_dashboard;
120 void DesktopView::toggleDashboard()
122 if (!m_dashboard) {
123 if (!containment()) {
124 return;
127 m_dashboardFollowsDesktop = true;
128 KConfigGroup cg = config();
129 Plasma::Containment *dc = containment();
130 int containmentId = cg.readEntry("DashboardContainment", 0);
131 if (containmentId > 0) {
132 foreach (Plasma::Containment *c, containment()->corona()->containments()) {
133 if ((int)c->id() == containmentId) {
134 dc = c;
135 m_dashboardFollowsDesktop = false;
136 break;
140 m_dashboard = new DashboardView(dc, 0);
141 m_dashboard->addActions(actions());
144 m_dashboard->toggleVisibility();
145 kDebug() << "toggling dashboard for screen" << screen() << m_dashboard->isVisible();
148 void DesktopView::screenResized(Kephal::Screen *s)
150 if (s->id() == screen()) {
151 kDebug() << screen();
152 adjustSize();
156 void DesktopView::screenMoved(Kephal::Screen *s)
158 if (s->id() == screen()) {
159 kDebug() << screen();
160 adjustSize();
164 void DesktopView::adjustSize()
166 // adapt to screen resolution changes
167 QRect geom = Kephal::ScreenUtils::screenGeometry(screen());
168 kDebug() << "screen" << screen() << "geom" << geom;
169 setGeometry(geom);
170 containment()->resize(geom.size());
171 kDebug() << "Containment's geom after resize" << containment()->geometry();
173 if (m_dashboard) {
174 m_dashboard->setGeometry(geom);
177 kDebug() << "Done" << screen() << geometry();
180 bool DesktopView::isDashboardVisible() const
182 return m_dashboard && m_dashboard->isVisible();
185 void DesktopView::setContainment(Plasma::Containment *containment)
187 Plasma::Containment *oldContainment = this->containment();
188 if (containment == oldContainment) {
189 return;
192 Plasma::ZoomLevel zoomLevel = PlasmaApp::self()->desktopZoomLevel();
193 if (zoomLevel == Plasma::DesktopZoom && containment) {
194 //make sure actions are up-to-date
195 //this is icky but necessary to have the toolbox show the right actions for the zoom level
196 containment->enableAction("zoom in", false);
197 containment->enableAction("add sibling containment", false);
200 if (m_dashboard && m_dashboardFollowsDesktop) {
201 m_dashboard->setContainment(containment);
204 if (oldContainment && zoomLevel == Plasma::DesktopZoom) {
205 //make sure actions are up-to-date
206 oldContainment->enableAction("zoom in", false);
207 oldContainment->enableAction("add sibling containment", false);
210 View::setContainment(containment);
213 void DesktopView::zoomIn(Plasma::ZoomLevel zoomLevel)
215 if (zoomLevel == Plasma::DesktopZoom) {
216 setDragMode(NoDrag);
217 qreal factor = Plasma::scalingFactor(zoomLevel) / matrix().m11();
218 scale(factor, factor);
219 if (containment()) {
220 //disconnect from other containments
221 Plasma::Corona *corona = containment()->corona();
222 if (corona) {
223 QList<Plasma::Containment*> containments = corona->containments();
224 foreach (Plasma::Containment *c, containments) {
225 if (c == containment() || c->containmentType() == Plasma::Containment::PanelContainment) {
226 continue;
228 disconnect(c, 0, this, 0);
231 setSceneRect(containment()->geometry());
233 } else if (zoomLevel == Plasma::GroupZoom) {
234 qreal factor = Plasma::scalingFactor(zoomLevel);
235 factor = factor / matrix().m11();
236 scale(factor, factor);
237 setSceneRect(QRectF(0, 0, scene()->sceneRect().right(), scene()->sceneRect().bottom() + TOOLBOX_MARGIN));
238 } else {
239 setDragMode(NoDrag);
243 void DesktopView::zoomOut(Plasma::ZoomLevel zoomLevel)
245 setDragMode(ScrollHandDrag);
246 qreal factor = Plasma::scalingFactor(zoomLevel);
247 qreal s = factor / matrix().m11();
248 scale(s, s);
249 setSceneRect(QRectF(0, 0, scene()->sceneRect().right(), scene()->sceneRect().bottom() + TOOLBOX_MARGIN));
251 if (containment()) {
252 ensureVisible(containment()->sceneBoundingRect());
256 void DesktopView::wheelEvent(QWheelEvent* event)
258 QGraphicsItem * item = scene() ? scene()->itemAt(sceneRect().topLeft() + event->pos()) : 0;
260 if ((!item || item == (QGraphicsItem*)containment()) && event->modifiers() & Qt::ControlModifier) {
261 if (event->modifiers() & Qt::ControlModifier) {
262 if (event->delta() < 0) {
263 PlasmaApp::self()->zoom(containment(), Plasma::ZoomOut);
264 } else {
265 PlasmaApp::self()->zoom(containment(), Plasma::ZoomIn);
269 event->accept();
270 return;
273 QGraphicsView::wheelEvent(event);
276 // This function is reimplemented from QGraphicsView to work around the problem
277 // that QPainter::fillRect(QRectF/QRect, QBrush), which QGraphicsView uses, is
278 // potentially slow when the anti-aliasing hint is set and as implemented won't
279 // hit accelerated code at all when it isn't set. This implementation avoids
280 // the problem by using integer coordinates and by using drawTiledPixmap() in
281 // the case of a texture brush, and fillRect(QRect, QColor) in the case of a
282 // solid pattern. As an additional optimization it draws the background with
283 // CompositionMode_Source.
284 void DesktopView::drawBackground(QPainter *painter, const QRectF &rect)
286 const QPainter::CompositionMode savedMode = painter->compositionMode();
287 const QBrush brush = backgroundBrush();
289 switch (brush.style())
291 case Qt::TexturePattern:
293 // Note: this assumes that the brush origin is (0, 0), and that
294 // the brush has an identity transformation matrix.
295 const QPixmap texture = brush.texture();
296 QRect r = rect.toAlignedRect();
297 r.setLeft(r.left() - (r.left() % texture.width()));
298 r.setTop(r.top() - (r.top() % texture.height()));
299 painter->setCompositionMode(QPainter::CompositionMode_Source);
300 painter->drawTiledPixmap(r, texture);
301 painter->setCompositionMode(savedMode);
302 return;
305 case Qt::SolidPattern:
306 painter->setCompositionMode(QPainter::CompositionMode_Source);
307 painter->fillRect(rect.toAlignedRect(), brush.color());
308 painter->setCompositionMode(savedMode);
309 return;
311 default:
312 QGraphicsView::drawBackground(painter, rect);
316 void DesktopView::screenOwnerChanged(int wasScreen, int isScreen, Plasma::Containment* containment)
318 kDebug() << "was:" << wasScreen << "is:" << isScreen << "my screen:" << screen() << "containment:" << (QObject*)containment << "myself:" << (QObject*)this;
319 if (containment->containmentType() == Plasma::Containment::PanelContainment) {
320 // we don't care about panel containments changing screens on us
321 return;
324 if (wasScreen == screen() && this->containment() == containment) {
325 setContainment(0);
328 if (isScreen == screen()) {
329 setContainment(containment);
333 void DesktopView::nextContainment()
335 QList<Plasma::Containment*> containments = containment()->corona()->containments();
336 int start = containments.indexOf(containment());
337 int i = (start + 1) % containments.size();
338 //FIXME this is a *horrible* way of choosing a "next" containment.
339 while (i != start) {
340 if (containments.at(i)->containmentType() != Plasma::Containment::PanelContainment &&
341 containments.at(i)->screen() == -1) {
342 break;
344 i = (i + 1) % containments.size();
347 Plasma::Containment *c = containments.at(i);
348 setContainment(c);
351 void DesktopView::previousContainment()
353 QList<Plasma::Containment*> containments = containment()->corona()->containments();
354 int start = containments.indexOf(containment());
355 //fun fact: in c++, (-1 % foo) == -1
356 int i = start - 1;
357 if (i < 0) {
358 i += containments.size();
360 //FIXME this is a *horrible* way of choosing a "previous" containment.
361 while (i != start) {
362 if (containments.at(i)->containmentType() != Plasma::Containment::PanelContainment &&
363 containments.at(i)->screen() == -1) {
364 break;
366 if (--i < 0) {
367 i += containments.size();
371 Plasma::Containment *c = containments.at(i);
372 setContainment(c);
375 #include "desktopview.moc"