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"
24 #include <QWheelEvent>
25 #include <QCoreApplication>
27 #include <KAuthorized>
30 #include <KToggleAction>
31 #include <KWindowSystem>
33 #include <Plasma/Applet>
34 #include <Plasma/Corona>
35 #include <Plasma/Containment>
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"
53 DesktopView::DesktopView(Plasma::Containment
*containment
, int id
, QWidget
*parent
)
54 : Plasma::View(containment
, id
, parent
),
56 m_dashboardFollowsDesktop(true)
58 setFocusPolicy(Qt::NoFocus
);
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
);
65 setWindowFlags(windowFlags() | Qt::FramelessWindowHint
);
68 if (AppSettings::perVirtualDesktopViews()) {
69 kDebug() << "setting to desktop" << containment
->desktop() + 1;
70 KWindowSystem::setOnDesktop(winId(), containment
->desktop() + 1);
72 KWindowSystem::setOnAllDesktops(winId(), true);
75 KWindowSystem::setType(winId(), NET::Desktop
);
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()));
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()));
95 QPixmap
tile(w
* 2, w
* 2);
96 tile
.fill(palette().base().color());
98 QColor color
= palette().mid().color();
100 pt
.fillRect(0, 0, w
, w
, color
);
101 pt
.fillRect(w
, w
, w
, w
, color
);
104 setBackgroundBrush(tile
);
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()
120 void DesktopView::toggleDashboard()
123 if (!containment()) {
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
) {
135 m_dashboardFollowsDesktop
= false;
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();
156 void DesktopView::screenMoved(Kephal::Screen
*s
)
158 if (s
->id() == screen()) {
159 kDebug() << screen();
164 void DesktopView::adjustSize()
166 // adapt to screen resolution changes
167 QRect geom
= Kephal::ScreenUtils::screenGeometry(screen());
168 kDebug() << "screen" << screen() << "geom" << geom
;
170 containment()->resize(geom
.size());
171 kDebug() << "Containment's geom after resize" << containment()->geometry();
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
) {
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
) {
217 qreal factor
= Plasma::scalingFactor(zoomLevel
) / matrix().m11();
218 scale(factor
, factor
);
220 //disconnect from other containments
221 Plasma::Corona
*corona
= containment()->corona();
223 QList
<Plasma::Containment
*> containments
= corona
->containments();
224 foreach (Plasma::Containment
*c
, containments
) {
225 if (c
== containment() || c
->containmentType() == Plasma::Containment::PanelContainment
) {
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
));
243 void DesktopView::zoomOut(Plasma::ZoomLevel zoomLevel
)
245 setDragMode(ScrollHandDrag
);
246 qreal factor
= Plasma::scalingFactor(zoomLevel
);
247 qreal s
= factor
/ matrix().m11();
249 setSceneRect(QRectF(0, 0, scene()->sceneRect().right(), scene()->sceneRect().bottom() + TOOLBOX_MARGIN
));
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
);
265 PlasmaApp::self()->zoom(containment(), Plasma::ZoomIn
);
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
);
305 case Qt::SolidPattern
:
306 painter
->setCompositionMode(QPainter::CompositionMode_Source
);
307 painter
->fillRect(rect
.toAlignedRect(), brush
.color());
308 painter
->setCompositionMode(savedMode
);
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
324 if (wasScreen
== screen() && this->containment() == containment
) {
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.
340 if (containments
.at(i
)->containmentType() != Plasma::Containment::PanelContainment
&&
341 containments
.at(i
)->screen() == -1) {
344 i
= (i
+ 1) % containments
.size();
347 Plasma::Containment
*c
= containments
.at(i
);
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
358 i
+= containments
.size();
360 //FIXME this is a *horrible* way of choosing a "previous" containment.
362 if (containments
.at(i
)->containmentType() != Plasma::Containment::PanelContainment
&&
363 containments
.at(i
)->screen() == -1) {
367 i
+= containments
.size();
371 Plasma::Containment
*c
= containments
.at(i
);
375 #include "desktopview.moc"