You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1436 lines
58 KiB
1436 lines
58 KiB
/******************************************************************** |
|
KWin - the KDE window manager |
|
This file is part of the KDE project. |
|
|
|
Copyright (C) 2007 Lubos Lunak <l.lunak@kde.org> |
|
Copyright (C) 2008 Lucas Murray <lmurray@undefinedfire.com> |
|
Copyright (C) 2009 Martin Gräßlin <mgraesslin@kde.org> |
|
|
|
This program is free software; you can redistribute it and/or modify |
|
it under the terms of the GNU General Public License as published by |
|
the Free Software Foundation; either version 2 of the License, or |
|
(at your option) any later version. |
|
|
|
This program is distributed in the hope that it will be useful, |
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
GNU General Public License for more details. |
|
|
|
You should have received a copy of the GNU General Public License |
|
along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
*********************************************************************/ |
|
|
|
#include "desktopgrid.h" |
|
// KConfigSkeleton |
|
#include "desktopgridconfig.h" |
|
|
|
#include "../presentwindows/presentwindows_proxy.h" |
|
#include "../effect_builtins.h" |
|
|
|
#include <math.h> |
|
|
|
#include <QAction> |
|
#include <QApplication> |
|
#include <KGlobalAccel> |
|
#include <KLocalizedString> |
|
#include <netwm_def.h> |
|
#include <QEvent> |
|
#include <QMouseEvent> |
|
#include <QtGui/QVector2D> |
|
#include <QQmlContext> |
|
#include <QQmlEngine> |
|
#include <QQuickItem> |
|
|
|
namespace KWin |
|
{ |
|
|
|
// WARNING, TODO: This effect relies on the desktop layout being EWMH-compliant. |
|
|
|
DesktopGridEffect::DesktopGridEffect() |
|
: activated(false) |
|
, timeline() |
|
, keyboardGrab(false) |
|
, wasWindowMove(false) |
|
, wasDesktopMove(false) |
|
, isValidMove(false) |
|
, windowMove(NULL) |
|
, windowMoveDiff() |
|
, gridSize() |
|
, orientation(Qt::Horizontal) |
|
, activeCell(1, 1) |
|
, scale() |
|
, unscaledBorder() |
|
, scaledSize() |
|
, scaledOffset() |
|
, m_proxy(0) |
|
{ |
|
// Load shortcuts |
|
QAction* a = new QAction(this); |
|
a->setObjectName(QStringLiteral("ShowDesktopGrid")); |
|
a->setText(i18n("Show Desktop Grid")); |
|
KGlobalAccel::self()->setDefaultShortcut(a, QList<QKeySequence>() << Qt::CTRL + Qt::Key_F8); |
|
KGlobalAccel::self()->setShortcut(a, QList<QKeySequence>() << Qt::CTRL + Qt::Key_F8); |
|
shortcut = KGlobalAccel::self()->shortcut(a); |
|
effects->registerGlobalShortcut(Qt::CTRL + Qt::Key_F8, a); |
|
connect(a, SIGNAL(triggered(bool)), this, SLOT(toggle())); |
|
connect(KGlobalAccel::self(), &KGlobalAccel::globalShortcutChanged, this, &DesktopGridEffect::globalShortcutChanged); |
|
connect(effects, SIGNAL(windowAdded(KWin::EffectWindow*)), this, SLOT(slotWindowAdded(KWin::EffectWindow*))); |
|
connect(effects, SIGNAL(windowClosed(KWin::EffectWindow*)), this, SLOT(slotWindowClosed(KWin::EffectWindow*))); |
|
connect(effects, SIGNAL(windowDeleted(KWin::EffectWindow*)), this, SLOT(slotWindowDeleted(KWin::EffectWindow*))); |
|
connect(effects, SIGNAL(numberDesktopsChanged(uint)), this, SLOT(slotNumberDesktopsChanged(uint))); |
|
connect(effects, SIGNAL(windowGeometryShapeChanged(KWin::EffectWindow*,QRect)), this, SLOT(slotWindowGeometryShapeChanged(KWin::EffectWindow*,QRect))); |
|
connect(effects, &EffectsHandler::numberScreensChanged, this, &DesktopGridEffect::setup); |
|
|
|
// Load all other configuration details |
|
reconfigure(ReconfigureAll); |
|
} |
|
|
|
DesktopGridEffect::~DesktopGridEffect() |
|
{ |
|
QHash< DesktopButtonsView*, EffectWindow* >::iterator i = m_desktopButtonsViews.begin(); |
|
while (i != m_desktopButtonsViews.end()) { |
|
DesktopButtonsView *view = i.key(); |
|
i = m_desktopButtonsViews.erase(i); |
|
view->deleteLater(); |
|
} |
|
} |
|
|
|
void DesktopGridEffect::reconfigure(ReconfigureFlags) |
|
{ |
|
DesktopGridConfig::self()->read(); |
|
|
|
foreach (ElectricBorder border, borderActivate) { |
|
effects->unreserveElectricBorder(border, this); |
|
} |
|
borderActivate.clear(); |
|
foreach (int i, DesktopGridConfig::borderActivate()) { |
|
borderActivate.append(ElectricBorder(i)); |
|
effects->reserveElectricBorder(ElectricBorder(i), this); |
|
} |
|
|
|
// TODO: rename zoomDuration to duration |
|
zoomDuration = animationTime(DesktopGridConfig::zoomDuration() != 0 ? DesktopGridConfig::zoomDuration() : 300); |
|
timeline.setCurveShape(QTimeLine::EaseInOutCurve); |
|
timeline.setDuration(zoomDuration); |
|
|
|
border = DesktopGridConfig::borderWidth(); |
|
desktopNameAlignment = Qt::Alignment(DesktopGridConfig::desktopNameAlignment()); |
|
layoutMode = DesktopGridConfig::layoutMode(); |
|
customLayoutRows = DesktopGridConfig::customLayoutRows(); |
|
m_usePresentWindows = DesktopGridConfig::presentWindows(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Screen painting |
|
|
|
void DesktopGridEffect::prePaintScreen(ScreenPrePaintData& data, int time) |
|
{ |
|
if (timeline.currentValue() != 0 || activated || (isUsingPresentWindows() && isMotionManagerMovingWindows())) { |
|
if (activated) |
|
timeline.setCurrentTime(timeline.currentTime() + time); |
|
else |
|
timeline.setCurrentTime(timeline.currentTime() - time); |
|
for (int i = 0; i < effects->numberOfDesktops(); i++) { |
|
if (i == highlightedDesktop - 1) |
|
hoverTimeline[i]->setCurrentTime(hoverTimeline[i]->currentTime() + time); |
|
else |
|
hoverTimeline[i]->setCurrentTime(hoverTimeline[i]->currentTime() - time); |
|
} |
|
if (isUsingPresentWindows()) { |
|
QList<WindowMotionManager>::iterator i; |
|
for (i = m_managers.begin(); i != m_managers.end(); ++i) |
|
(*i).calculate(time); |
|
} |
|
// PAINT_SCREEN_BACKGROUND_FIRST is needed because screen will be actually painted more than once, |
|
// so with normal screen painting second screen paint would erase parts of the first paint |
|
if (timeline.currentValue() != 0 || (isUsingPresentWindows() && isMotionManagerMovingWindows())) |
|
data.mask |= PAINT_SCREEN_TRANSFORMED | PAINT_SCREEN_BACKGROUND_FIRST; |
|
if (!activated && timeline.currentValue() == 0 && !(isUsingPresentWindows() && isMotionManagerMovingWindows())) |
|
finish(); |
|
} |
|
effects->prePaintScreen(data, time); |
|
} |
|
|
|
void DesktopGridEffect::paintScreen(int mask, QRegion region, ScreenPaintData& data) |
|
{ |
|
if (timeline.currentValue() == 0 && !isUsingPresentWindows()) { |
|
effects->paintScreen(mask, region, data); |
|
return; |
|
} |
|
for (int desktop = 1; desktop <= effects->numberOfDesktops(); desktop++) { |
|
ScreenPaintData d = data; |
|
paintingDesktop = desktop; |
|
effects->paintScreen(mask, region, d); |
|
} |
|
|
|
// paint the add desktop button |
|
for (QHash< DesktopButtonsView*, EffectWindow*>::iterator it = m_desktopButtonsViews.begin(); |
|
it != m_desktopButtonsViews.end(); ++it) { |
|
if (!it.value()) { |
|
EffectWindow *view = effects->findWindow(it.key()->winId()); |
|
if (view) { |
|
view->setData(WindowForceBlurRole, QVariant(true)); |
|
it.value() = view; |
|
} |
|
} |
|
if (it.value()) { |
|
WindowPaintData d(it.value()); |
|
d.multiplyOpacity(timeline.currentValue()); |
|
effects->drawWindow(it.value(), PAINT_WINDOW_TRANSLUCENT, |
|
infiniteRegion(), d); |
|
} |
|
} |
|
|
|
if (isUsingPresentWindows() && windowMove && wasWindowMove) { |
|
// the moving window has to be painted on top of all desktops |
|
QPoint diff = cursorPos() - m_windowMoveStartPoint; |
|
QRect geo = m_windowMoveGeometry.translated(diff); |
|
WindowPaintData d(windowMove); |
|
d *= QVector2D((qreal)geo.width() / (qreal)windowMove->width(), (qreal)geo.height() / (qreal)windowMove->height()); |
|
d += QPoint(geo.left() - windowMove->x(), geo.top() - windowMove->y()); |
|
effects->drawWindow(windowMove, PAINT_WINDOW_TRANSFORMED | PAINT_WINDOW_LANCZOS, infiniteRegion(), d); |
|
} |
|
|
|
if (desktopNameAlignment) { |
|
for (int screen = 0; screen < effects->numScreens(); screen++) { |
|
QRect screenGeom = effects->clientArea(ScreenArea, screen, 0); |
|
int desktop = 1; |
|
foreach (EffectFrame * frame, desktopNames) { |
|
QPointF posTL(scalePos(screenGeom.topLeft(), desktop, screen)); |
|
QPointF posBR(scalePos(screenGeom.bottomRight(), desktop, screen)); |
|
QRect textArea(posTL.x(), posTL.y(), posBR.x() - posTL.x(), posBR.y() - posTL.y()); |
|
textArea.adjust(textArea.width() / 10, textArea.height() / 10, |
|
-textArea.width() / 10, -textArea.height() / 10); |
|
int x, y; |
|
if (desktopNameAlignment & Qt::AlignLeft) |
|
x = textArea.x(); |
|
else if (desktopNameAlignment & Qt::AlignRight) |
|
x = textArea.right(); |
|
else |
|
x = textArea.center().x(); |
|
if (desktopNameAlignment & Qt::AlignTop) |
|
y = textArea.y(); |
|
else if (desktopNameAlignment & Qt::AlignBottom) |
|
y = textArea.bottom(); |
|
else |
|
y = textArea.center().y(); |
|
frame->setPosition(QPoint(x, y)); |
|
frame->render(region, timeline.currentValue(), 0.7); |
|
++desktop; |
|
} |
|
} |
|
} |
|
} |
|
|
|
void DesktopGridEffect::postPaintScreen() |
|
{ |
|
if (activated ? timeline.currentValue() != 1 : timeline.currentValue() != 0) |
|
effects->addRepaintFull(); // Repaint during zoom |
|
if (isUsingPresentWindows() && isMotionManagerMovingWindows()) |
|
effects->addRepaintFull(); |
|
if (activated) { |
|
for (int i = 0; i < effects->numberOfDesktops(); i++) { |
|
if (hoverTimeline[i]->currentValue() != 0.0 && hoverTimeline[i]->currentValue() != 1.0) { |
|
// Repaint during soft highlighting |
|
effects->addRepaintFull(); |
|
break; |
|
} |
|
} |
|
} |
|
effects->postPaintScreen(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Window painting |
|
|
|
void DesktopGridEffect::prePaintWindow(EffectWindow* w, WindowPrePaintData& data, int time) |
|
{ |
|
if (timeline.currentValue() != 0 || (isUsingPresentWindows() && isMotionManagerMovingWindows())) { |
|
if (w->isOnDesktop(paintingDesktop)) { |
|
w->enablePainting(EffectWindow::PAINT_DISABLED_BY_DESKTOP); |
|
if (w->isMinimized() && isUsingPresentWindows()) |
|
w->enablePainting(EffectWindow::PAINT_DISABLED_BY_MINIMIZE); |
|
data.mask |= PAINT_WINDOW_TRANSFORMED; |
|
|
|
// Split windows at screen edges |
|
for (int screen = 0; screen < effects->numScreens(); screen++) { |
|
QRect screenGeom = effects->clientArea(ScreenArea, screen, 0); |
|
if (w->x() < screenGeom.x()) |
|
data.quads = data.quads.splitAtX(screenGeom.x() - w->x()); |
|
if (w->x() + w->width() > screenGeom.x() + screenGeom.width()) |
|
data.quads = data.quads.splitAtX(screenGeom.x() + screenGeom.width() - w->x()); |
|
if (w->y() < screenGeom.y()) |
|
data.quads = data.quads.splitAtY(screenGeom.y() - w->y()); |
|
if (w->y() + w->height() > screenGeom.y() + screenGeom.height()) |
|
data.quads = data.quads.splitAtY(screenGeom.y() + screenGeom.height() - w->y()); |
|
} |
|
if (windowMove && wasWindowMove && windowMove->findModal() == w) |
|
w->disablePainting(EffectWindow::PAINT_DISABLED_BY_DESKTOP); |
|
} else |
|
w->disablePainting(EffectWindow::PAINT_DISABLED_BY_DESKTOP); |
|
} |
|
effects->prePaintWindow(w, data, time); |
|
} |
|
|
|
void DesktopGridEffect::paintWindow(EffectWindow* w, int mask, QRegion region, WindowPaintData& data) |
|
{ |
|
if (timeline.currentValue() != 0 || (isUsingPresentWindows() && isMotionManagerMovingWindows())) { |
|
if (isUsingPresentWindows() && w == windowMove && wasWindowMove) { |
|
return; // will be painted on top of all other windows |
|
} |
|
if (m_desktopButtonsViews.values().contains(w)) |
|
return; // will be painted on top of all other windows |
|
|
|
qreal xScale = data.xScale(); |
|
qreal yScale = data.yScale(); |
|
|
|
// Don't change brightness of windows on all desktops as this causes flickering |
|
if (!w->isOnAllDesktops() || w->isDesktop()) |
|
data.multiplyBrightness(1.0 - (0.3 * (1.0 - hoverTimeline[paintingDesktop - 1]->currentValue()))); |
|
|
|
for (int screen = 0; screen < effects->numScreens(); screen++) { |
|
// Assume desktop windows can never be on two screens at once (Plasma makes one window per screen) |
|
if (w->isDesktop()) |
|
screen = w->screen(); |
|
QRect screenGeom = effects->clientArea(ScreenArea, screen, 0); |
|
|
|
QRectF transformedGeo = w->geometry(); |
|
// Display all quads on the same screen on the same pass |
|
WindowQuadList screenQuads; |
|
bool quadsAdded = false; |
|
if (isUsingPresentWindows()) { |
|
WindowMotionManager& manager = m_managers[(paintingDesktop-1)*(effects->numScreens())+screen ]; |
|
if (manager.isManaging(w)) { |
|
foreach (const WindowQuad & quad, data.quads) |
|
screenQuads.append(quad); |
|
transformedGeo = manager.transformedGeometry(w); |
|
quadsAdded = true; |
|
if (!manager.areWindowsMoving() && timeline.currentValue() == 1.0) |
|
mask |= PAINT_WINDOW_LANCZOS; |
|
} else if (w->screen() != screen) |
|
quadsAdded = true; // we don't want parts of overlapping windows on the other screen |
|
} |
|
if (!quadsAdded) { |
|
foreach (const WindowQuad & quad, data.quads) { |
|
QRect quadRect( |
|
w->x() + quad.left(), w->y() + quad.top(), |
|
quad.right() - quad.left(), quad.bottom() - quad.top() |
|
); |
|
if (quadRect.intersects(screenGeom)) |
|
screenQuads.append(quad); |
|
} |
|
} |
|
if (screenQuads.isEmpty()) |
|
continue; // Nothing is being displayed, don't bother |
|
WindowPaintData d = data; |
|
d.quads = screenQuads; |
|
|
|
QPointF newPos = scalePos(transformedGeo.topLeft().toPoint(), paintingDesktop, screen); |
|
double progress = timeline.currentValue(); |
|
d.setXScale(interpolate(1, xScale * scale[screen] * (float)transformedGeo.width() / (float)w->geometry().width(), progress)); |
|
d.setYScale(interpolate(1, yScale * scale[screen] * (float)transformedGeo.height() / (float)w->geometry().height(), progress)); |
|
d += QPoint(qRound(newPos.x() - w->x()), qRound(newPos.y() - w->y())); |
|
|
|
if (isUsingPresentWindows() && (w->isDock() || w->isSkipSwitcher())) { |
|
// fade out panels if present windows is used |
|
d.multiplyOpacity((1.0 - timeline.currentValue())); |
|
} |
|
if (isUsingPresentWindows() && w->isMinimized()) { |
|
d.multiplyOpacity(timeline.currentValue()); |
|
} |
|
|
|
if (effects->compositingType() == XRenderCompositing) { |
|
// More exact clipping as XRender displays the entire window instead of just the quad |
|
QPointF screenPosF = scalePos(screenGeom.topLeft(), paintingDesktop).toPoint(); |
|
QPoint screenPos( |
|
qRound(screenPosF.x()), |
|
qRound(screenPosF.y()) |
|
); |
|
QSize screenSize( |
|
qRound(interpolate(screenGeom.width(), scaledSize[screen].width(), progress)), |
|
qRound(interpolate(screenGeom.height(), scaledSize[screen].height(), progress)) |
|
); |
|
PaintClipper pc(effects->clientArea(ScreenArea, screen, 0) & QRect(screenPos, screenSize)); |
|
effects->paintWindow(w, mask, region, d); |
|
} else { |
|
if (w->isDesktop() && timeline.currentValue() == 1.0) { |
|
// desktop windows are not in a motion manager and can always be rendered with |
|
// lanczos sampling except for animations |
|
mask |= PAINT_WINDOW_LANCZOS; |
|
} |
|
effects->paintWindow(w, mask, effects->clientArea(ScreenArea, screen, 0), d); |
|
} |
|
// Assume desktop windows can never be on two screens at once (Plasma makes one window per screen) |
|
if (w->isDesktop()) |
|
break; |
|
} |
|
} else |
|
effects->paintWindow(w, mask, region, data); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// User interaction |
|
|
|
void DesktopGridEffect::slotWindowAdded(EffectWindow* w) |
|
{ |
|
if (!activated) |
|
return; |
|
if (isUsingPresentWindows()) { |
|
if (!isRelevantWithPresentWindows(w)) |
|
return; // don't add |
|
if (w->isOnAllDesktops()) { |
|
for (int i = 0; i < effects->numberOfDesktops(); i++) { |
|
WindowMotionManager& manager = m_managers[ i*effects->numScreens()+w->screen()]; |
|
manager.manage(w); |
|
m_proxy->calculateWindowTransformations(manager.managedWindows(), w->screen(), manager); |
|
} |
|
} else { |
|
WindowMotionManager& manager = m_managers[(w->desktop()-1)*effects->numScreens()+w->screen()]; |
|
manager.manage(w); |
|
m_proxy->calculateWindowTransformations(manager.managedWindows(), w->screen(), manager); |
|
} |
|
} |
|
effects->addRepaintFull(); |
|
} |
|
|
|
void DesktopGridEffect::slotWindowClosed(EffectWindow* w) |
|
{ |
|
if (!activated && timeline.currentValue() == 0) |
|
return; |
|
if (w == windowMove) { |
|
effects->setElevatedWindow(windowMove, false); |
|
windowMove = NULL; |
|
} |
|
if (isUsingPresentWindows()) { |
|
if (w->isOnAllDesktops()) { |
|
for (int i = 0; i < effects->numberOfDesktops(); i++) { |
|
WindowMotionManager& manager = m_managers[i*effects->numScreens()+w->screen()]; |
|
manager.unmanage(w); |
|
m_proxy->calculateWindowTransformations(manager.managedWindows(), w->screen(), manager); |
|
} |
|
} else { |
|
if (w->desktop() <= effects->numberOfDesktops()) { |
|
WindowMotionManager& manager = m_managers[(w->desktop()-1)*effects->numScreens()+w->screen()]; |
|
manager.unmanage(w); |
|
m_proxy->calculateWindowTransformations(manager.managedWindows(), w->screen(), manager); |
|
} |
|
} |
|
} |
|
for (QHash< DesktopButtonsView*, EffectWindow*>::iterator it = m_desktopButtonsViews.begin(); |
|
it != m_desktopButtonsViews.end(); ++it) { |
|
if (it.value() && it.value() == w) { |
|
w->refWindow(); |
|
break; |
|
} |
|
} |
|
effects->addRepaintFull(); |
|
} |
|
|
|
void DesktopGridEffect::slotWindowDeleted(EffectWindow* w) |
|
{ |
|
if (w == windowMove) |
|
windowMove = 0; |
|
for (QHash< DesktopButtonsView*, EffectWindow*>::iterator it = m_desktopButtonsViews.begin(); |
|
it != m_desktopButtonsViews.end(); ++it) { |
|
if (it.value() && it.value() == w) { |
|
it.key()->deleteLater(); |
|
m_desktopButtonsViews.erase(it); |
|
break; |
|
} |
|
} |
|
} |
|
|
|
void DesktopGridEffect::slotWindowGeometryShapeChanged(EffectWindow* w, const QRect& old) |
|
{ |
|
Q_UNUSED(old) |
|
if (!activated) |
|
return; |
|
if (w == windowMove && wasWindowMove) |
|
return; |
|
if (isUsingPresentWindows()) { |
|
if (w->isOnAllDesktops()) { |
|
for (int i = 0; i < effects->numberOfDesktops(); i++) { |
|
WindowMotionManager& manager = m_managers[i*effects->numScreens()+w->screen()]; |
|
m_proxy->calculateWindowTransformations(manager.managedWindows(), w->screen(), manager); |
|
} |
|
} else { |
|
WindowMotionManager& manager = m_managers[(w->desktop()-1)*effects->numScreens()+w->screen()]; |
|
m_proxy->calculateWindowTransformations(manager.managedWindows(), w->screen(), manager); |
|
} |
|
} |
|
} |
|
|
|
void DesktopGridEffect::windowInputMouseEvent(QEvent* e) |
|
{ |
|
if ((e->type() != QEvent::MouseMove |
|
&& e->type() != QEvent::MouseButtonPress |
|
&& e->type() != QEvent::MouseButtonRelease) |
|
|| timeline.currentValue() != 1) // Block user input during animations |
|
return; |
|
QMouseEvent* me = static_cast< QMouseEvent* >(e); |
|
for (QHash< DesktopButtonsView*, EffectWindow*>::iterator it = m_desktopButtonsViews.begin(); |
|
it != m_desktopButtonsViews.end(); ++it) { |
|
DesktopButtonsView* view = it.key(); |
|
if (!wasWindowMove && !wasDesktopMove && view->geometry().contains(me->pos())) { |
|
const QPoint widgetPos = view->mapFromGlobal(me->pos()); |
|
QMouseEvent event(me->type(), widgetPos, me->pos(), me->button(), me->buttons(), me->modifiers()); |
|
view->windowInputMouseEvent(&event); |
|
return; |
|
} |
|
} |
|
|
|
if (e->type() == QEvent::MouseMove) { |
|
int d = posToDesktop(me->pos()); |
|
if (windowMove != NULL && |
|
(me->pos() - dragStartPos).manhattanLength() > QApplication::startDragDistance()) { |
|
// Handle window moving |
|
if (!wasWindowMove) { // Activate on move |
|
if (isUsingPresentWindows() && windowMove->isOnAllDesktops()) { |
|
for (int i = 0; i < effects->numberOfDesktops(); ++i) { |
|
WindowMotionManager& manager = m_managers[(i)*(effects->numScreens()) + windowMove->screen()]; |
|
if ((i + 1) == d) { |
|
const QRectF transformedGeo = manager.transformedGeometry(windowMove); |
|
const QPointF pos = scalePos(transformedGeo.topLeft().toPoint(), d, windowMove->screen()); |
|
const QSize size(scale[windowMove->screen()] *(float)transformedGeo.width(), |
|
scale[windowMove->screen()] *(float)transformedGeo.height()); |
|
m_windowMoveGeometry = QRect(pos.toPoint(), size); |
|
m_windowMoveStartPoint = me->pos(); |
|
} |
|
manager.unmanage(windowMove); |
|
if (EffectWindow* modal = windowMove->findModal()) { |
|
if (manager.isManaging(modal)) |
|
manager.unmanage(modal); |
|
} |
|
m_proxy->calculateWindowTransformations(manager.managedWindows(), windowMove->screen(), manager); |
|
} |
|
} else if (isUsingPresentWindows()) { |
|
WindowMotionManager& manager = m_managers[(windowMove->desktop()-1)*(effects->numScreens()) + windowMove->screen()]; |
|
const QRectF transformedGeo = manager.transformedGeometry(windowMove); |
|
const QPointF pos = scalePos(transformedGeo.topLeft().toPoint(), windowMove->desktop(), windowMove->screen()); |
|
const QSize size(scale[windowMove->screen()] *(float)transformedGeo.width(), |
|
scale[windowMove->screen()] *(float)transformedGeo.height()); |
|
m_windowMoveGeometry = QRect(pos.toPoint(), size); |
|
m_windowMoveStartPoint = me->pos(); |
|
|
|
manager.unmanage(windowMove); |
|
if (EffectWindow* modal = windowMove->findModal()) { |
|
if (manager.isManaging(modal)) |
|
manager.unmanage(modal); |
|
} |
|
m_proxy->calculateWindowTransformations(manager.managedWindows(), windowMove->screen(), manager); |
|
} |
|
effects->defineCursor(Qt::ClosedHandCursor); |
|
} |
|
wasWindowMove = true; |
|
if (windowMove->isMovable() && !isUsingPresentWindows()) { |
|
int screen = effects->screenNumber(me->pos()); |
|
effects->moveWindow(windowMove, unscalePos(me->pos(), NULL) + windowMoveDiff, true, 1.0 / scale[screen]); |
|
} |
|
if (d != highlightedDesktop) { |
|
if (!windowMove->isOnAllDesktops()) |
|
effects->windowToDesktop(windowMove, d); // Not true all desktop move |
|
const int screen = effects->screenNumber(me->pos()); |
|
if (screen != windowMove->screen()) |
|
effects->windowToScreen(windowMove, screen); |
|
} |
|
effects->addRepaintFull(); |
|
} else if ((me->buttons() & Qt::LeftButton) && !wasDesktopMove && |
|
(me->pos() - dragStartPos).manhattanLength() > QApplication::startDragDistance()) { |
|
wasDesktopMove = true; |
|
effects->defineCursor(Qt::ClosedHandCursor); |
|
} |
|
if (d != highlightedDesktop) { // Highlight desktop |
|
if ((me->buttons() & Qt::LeftButton) && isValidMove && !wasWindowMove && d <= effects->numberOfDesktops()) { |
|
EffectWindowList windows = effects->stackingOrder(); |
|
EffectWindowList stack[3]; |
|
for (EffectWindowList::const_iterator it = windows.constBegin(), |
|
end = windows.constEnd(); it != end; ++it) { |
|
EffectWindow *w = const_cast<EffectWindow*>(*it); // we're not really touching it here but below |
|
if (w->isOnAllDesktops()) |
|
continue; |
|
if (w->isOnDesktop(highlightedDesktop)) |
|
stack[0] << w; |
|
if (w->isOnDesktop(d)) |
|
stack[1] << w; |
|
if (w->isOnDesktop(m_originalMovingDesktop)) |
|
stack[2] << w; |
|
} |
|
const int desks[4] = {highlightedDesktop, d, m_originalMovingDesktop, highlightedDesktop}; |
|
for (int i = 0; i < 3; ++i ) { |
|
if (desks[i] == desks[i+1]) |
|
continue; |
|
foreach (EffectWindow *w, stack[i]) { |
|
effects->windowToDesktop(w, desks[i+1]); |
|
if (isUsingPresentWindows()) { |
|
m_managers[(desks[i]-1)*(effects->numScreens()) + w->screen()].unmanage(w); |
|
m_managers[(desks[i+1]-1)*(effects->numScreens()) + w->screen()].manage(w); |
|
} |
|
} |
|
} |
|
if (isUsingPresentWindows()) { |
|
for (int i = 0; i < effects->numScreens(); i++) { |
|
for (int j = 0; j < 3; ++j) { |
|
WindowMotionManager& manager = m_managers[(desks[j]-1)*(effects->numScreens()) + i ]; |
|
m_proxy->calculateWindowTransformations(manager.managedWindows(), i, manager); |
|
} |
|
} |
|
effects->addRepaintFull(); |
|
} |
|
} |
|
setHighlightedDesktop(d); |
|
} |
|
} |
|
if (e->type() == QEvent::MouseButtonPress) { |
|
if (me->buttons() == Qt::LeftButton) { |
|
isValidMove = true; |
|
// QRect rect; |
|
dragStartPos = me->pos(); |
|
bool isDesktop = (me->modifiers() & Qt::ControlModifier); |
|
EffectWindow* w = isDesktop ? NULL : windowAt(me->pos()); |
|
if (w != NULL) |
|
isDesktop = w->isDesktop(); |
|
if (isDesktop) |
|
m_originalMovingDesktop = posToDesktop(me->pos()); |
|
if (w != NULL && !w->isDesktop() && (w->isMovable() || w->isMovableAcrossScreens() || isUsingPresentWindows())) { |
|
// Prepare it for moving |
|
windowMoveDiff = w->pos() - unscalePos(me->pos(), NULL); |
|
windowMove = w; |
|
effects->setElevatedWindow(windowMove, true); |
|
} |
|
} else if ((me->buttons() == Qt::MidButton || me->buttons() == Qt::RightButton) && windowMove == NULL) { |
|
EffectWindow* w = windowAt(me->pos()); |
|
if (w != NULL) { |
|
if (w->isOnAllDesktops()) { |
|
const int desktop = posToDesktop(me->pos()); |
|
effects->windowToDesktop(w, desktop); |
|
if (isUsingPresentWindows()) { |
|
for (int i = 0; i < effects->numberOfDesktops(); i++) { |
|
if (i != desktop - 1) { |
|
WindowMotionManager& manager = m_managers[ i*effects->numScreens() + w->screen()]; |
|
manager.unmanage(w); |
|
m_proxy->calculateWindowTransformations(manager.managedWindows(), w->screen(), manager); |
|
} |
|
} |
|
} |
|
} else { |
|
if (isUsingPresentWindows()) { |
|
const int desktop = w->desktop(); |
|
for (int i = 0; i < effects->numberOfDesktops(); i++) { |
|
if (i != desktop - 1) { |
|
WindowMotionManager& manager = m_managers[ i*effects->numScreens() + w->screen()]; |
|
manager.manage(w); |
|
m_proxy->calculateWindowTransformations(manager.managedWindows(), w->screen(), manager); |
|
} |
|
} |
|
} |
|
effects->windowToDesktop(w, NET::OnAllDesktops); |
|
} |
|
effects->addRepaintFull(); |
|
} |
|
} |
|
} |
|
if (e->type() == QEvent::MouseButtonRelease && me->button() == Qt::LeftButton) { |
|
isValidMove = false; |
|
if (!wasWindowMove && !wasDesktopMove) { |
|
const int desk = posToDesktop(me->pos()); |
|
if (desk > effects->numberOfDesktops()) |
|
return; // don't quit when missing desktop |
|
setCurrentDesktop(desk); |
|
if (windowMove) |
|
effects->activateWindow(windowMove); |
|
setActive(false); |
|
} |
|
if (windowMove) { |
|
if (wasWindowMove) { |
|
if (isUsingPresentWindows()) { |
|
if (windowMove->isOnAllDesktops()) { |
|
const int targetDesktop = posToDesktop(cursorPos()); |
|
for (int i = 0; i < effects->numberOfDesktops(); ++i) { |
|
WindowMotionManager& manager = m_managers[(i)*(effects->numScreens()) + windowMove->screen()]; |
|
manager.manage(windowMove); |
|
if (EffectWindow* modal = windowMove->findModal()) |
|
manager.manage(modal); |
|
if (i + 1 == targetDesktop) { |
|
// for the desktop the window is dropped on, we use the current geometry |
|
manager.setTransformedGeometry(windowMove, moveGeometryToDesktop(targetDesktop)); |
|
} |
|
m_proxy->calculateWindowTransformations(manager.managedWindows(), windowMove->screen(), manager); |
|
} |
|
} else { |
|
WindowMotionManager& manager = m_managers[(windowMove->desktop()-1)*(effects->numScreens()) + windowMove->screen()]; |
|
manager.manage(windowMove); |
|
if (EffectWindow* modal = windowMove->findModal()) |
|
manager.manage(modal); |
|
manager.setTransformedGeometry(windowMove, moveGeometryToDesktop(windowMove->desktop())); |
|
m_proxy->calculateWindowTransformations(manager.managedWindows(), windowMove->screen(), manager); |
|
} |
|
effects->addRepaintFull(); |
|
} |
|
else |
|
effects->activateWindow(windowMove); |
|
} |
|
effects->setElevatedWindow(windowMove, false); |
|
windowMove = NULL; |
|
effects->defineCursor(Qt::PointingHandCursor); |
|
} else if (wasDesktopMove) |
|
effects->defineCursor(Qt::PointingHandCursor); |
|
wasWindowMove = false; |
|
wasDesktopMove = false; |
|
} |
|
} |
|
|
|
void DesktopGridEffect::grabbedKeyboardEvent(QKeyEvent* e) |
|
{ |
|
if (timeline.currentValue() != 1) // Block user input during animations |
|
return; |
|
if (windowMove != NULL) |
|
return; |
|
if (e->type() == QEvent::KeyPress) { |
|
// check for global shortcuts |
|
// HACK: keyboard grab disables the global shortcuts so we have to check for global shortcut (bug 156155) |
|
if (shortcut.contains(e->key() + e->modifiers())) { |
|
toggle(); |
|
return; |
|
} |
|
|
|
int desktop = -1; |
|
// switch by F<number> or just <number> |
|
if (e->key() >= Qt::Key_F1 && e->key() <= Qt::Key_F35) |
|
desktop = e->key() - Qt::Key_F1 + 1; |
|
else if (e->key() >= Qt::Key_0 && e->key() <= Qt::Key_9) |
|
desktop = e->key() == Qt::Key_0 ? 10 : e->key() - Qt::Key_0; |
|
if (desktop != -1) { |
|
if (desktop <= effects->numberOfDesktops()) { |
|
setHighlightedDesktop(desktop); |
|
setCurrentDesktop(desktop); |
|
setActive(false); |
|
} |
|
return; |
|
} |
|
switch(e->key()) { |
|
// Wrap only on autorepeat |
|
case Qt::Key_Left: |
|
setHighlightedDesktop(desktopToLeft(highlightedDesktop, !e->isAutoRepeat())); |
|
break; |
|
case Qt::Key_Right: |
|
setHighlightedDesktop(desktopToRight(highlightedDesktop, !e->isAutoRepeat())); |
|
break; |
|
case Qt::Key_Up: |
|
setHighlightedDesktop(desktopUp(highlightedDesktop, !e->isAutoRepeat())); |
|
break; |
|
case Qt::Key_Down: |
|
setHighlightedDesktop(desktopDown(highlightedDesktop, !e->isAutoRepeat())); |
|
break; |
|
case Qt::Key_Escape: |
|
setActive(false); |
|
return; |
|
case Qt::Key_Enter: |
|
case Qt::Key_Return: |
|
case Qt::Key_Space: |
|
setCurrentDesktop(highlightedDesktop); |
|
setActive(false); |
|
return; |
|
case Qt::Key_Plus: |
|
slotAddDesktop(); |
|
break; |
|
case Qt::Key_Minus: |
|
slotRemoveDesktop(); |
|
break; |
|
default: |
|
break; |
|
} |
|
} |
|
} |
|
|
|
bool DesktopGridEffect::borderActivated(ElectricBorder border) |
|
{ |
|
if (!borderActivate.contains(border)) |
|
return false; |
|
if (effects->activeFullScreenEffect() && effects->activeFullScreenEffect() != this) |
|
return true; |
|
toggle(); |
|
return true; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Helper functions |
|
|
|
// Transform a point to its position on the scaled grid |
|
QPointF DesktopGridEffect::scalePos(const QPoint& pos, int desktop, int screen) const |
|
{ |
|
if (screen == -1) |
|
screen = effects->screenNumber(pos); |
|
QRect screenGeom = effects->clientArea(ScreenArea, screen, 0); |
|
QPoint desktopCell; |
|
if (orientation == Qt::Horizontal) { |
|
desktopCell.setX((desktop - 1) % gridSize.width() + 1); |
|
desktopCell.setY((desktop - 1) / gridSize.width() + 1); |
|
} else { |
|
desktopCell.setX((desktop - 1) / gridSize.height() + 1); |
|
desktopCell.setY((desktop - 1) % gridSize.height() + 1); |
|
} |
|
|
|
double progress = timeline.currentValue(); |
|
QPointF point( |
|
interpolate( |
|
( |
|
(screenGeom.width() + unscaledBorder[screen]) *(desktopCell.x() - 1) |
|
- (screenGeom.width() + unscaledBorder[screen]) *(activeCell.x() - 1) |
|
) + pos.x(), |
|
( |
|
(scaledSize[screen].width() + border) *(desktopCell.x() - 1) |
|
+ scaledOffset[screen].x() |
|
+ (pos.x() - screenGeom.x()) * scale[screen] |
|
), |
|
progress), |
|
interpolate( |
|
( |
|
(screenGeom.height() + unscaledBorder[screen]) *(desktopCell.y() - 1) |
|
- (screenGeom.height() + unscaledBorder[screen]) *(activeCell.y() - 1) |
|
) + pos.y(), |
|
( |
|
(scaledSize[screen].height() + border) *(desktopCell.y() - 1) |
|
+ scaledOffset[screen].y() |
|
+ (pos.y() - screenGeom.y()) * scale[screen] |
|
), |
|
progress) |
|
); |
|
|
|
return point; |
|
} |
|
|
|
// Detransform a point to its position on the full grid |
|
// TODO: Doesn't correctly interpolate (Final position is correct though), don't forget to copy to posToDesktop() |
|
QPoint DesktopGridEffect::unscalePos(const QPoint& pos, int* desktop) const |
|
{ |
|
int screen = effects->screenNumber(pos); |
|
QRect screenGeom = effects->clientArea(ScreenArea, screen, 0); |
|
|
|
//double progress = timeline.currentValue(); |
|
double scaledX = /*interpolate( |
|
( pos.x() - screenGeom.x() + unscaledBorder[screen] / 2.0 ) / ( screenGeom.width() + unscaledBorder[screen] ) + activeCell.x() - 1,*/ |
|
(pos.x() - scaledOffset[screen].x() + double(border) / 2.0) / (scaledSize[screen].width() + border)/*, |
|
progress )*/; |
|
double scaledY = /*interpolate( |
|
( pos.y() - screenGeom.y() + unscaledBorder[screen] / 2.0 ) / ( screenGeom.height() + unscaledBorder[screen] ) + activeCell.y() - 1,*/ |
|
(pos.y() - scaledOffset[screen].y() + double(border) / 2.0) / (scaledSize[screen].height() + border)/*, |
|
progress )*/; |
|
int gx = qBound(0, int(scaledX), gridSize.width() - 1); // Zero-based |
|
int gy = qBound(0, int(scaledY), gridSize.height() - 1); |
|
scaledX -= gx; |
|
scaledY -= gy; |
|
if (desktop != NULL) { |
|
if (orientation == Qt::Horizontal) |
|
*desktop = gy * gridSize.width() + gx + 1; |
|
else |
|
*desktop = gx * gridSize.height() + gy + 1; |
|
} |
|
|
|
return QPoint( |
|
qBound( |
|
screenGeom.x(), |
|
qRound( |
|
scaledX * (screenGeom.width() + unscaledBorder[screen]) |
|
- unscaledBorder[screen] / 2.0 |
|
+ screenGeom.x() |
|
), |
|
screenGeom.right() |
|
), |
|
qBound( |
|
screenGeom.y(), |
|
qRound( |
|
scaledY * (screenGeom.height() + unscaledBorder[screen]) |
|
- unscaledBorder[screen] / 2.0 |
|
+ screenGeom.y() |
|
), |
|
screenGeom.bottom() |
|
) |
|
); |
|
} |
|
|
|
int DesktopGridEffect::posToDesktop(const QPoint& pos) const |
|
{ |
|
// Copied from unscalePos() |
|
int screen = effects->screenNumber(pos); |
|
|
|
double scaledX = (pos.x() - scaledOffset[screen].x() + double(border) / 2.0) / (scaledSize[screen].width() + border); |
|
double scaledY = (pos.y() - scaledOffset[screen].y() + double(border) / 2.0) / (scaledSize[screen].height() + border); |
|
int gx = qBound(0, int(scaledX), gridSize.width() - 1); // Zero-based |
|
int gy = qBound(0, int(scaledY), gridSize.height() - 1); |
|
if (orientation == Qt::Horizontal) |
|
return gy * gridSize.width() + gx + 1; |
|
return gx * gridSize.height() + gy + 1; |
|
} |
|
|
|
EffectWindow* DesktopGridEffect::windowAt(QPoint pos) const |
|
{ |
|
// Get stacking order top first |
|
EffectWindowList windows = effects->stackingOrder(); |
|
EffectWindowList::Iterator begin = windows.begin(); |
|
EffectWindowList::Iterator end = windows.end(); |
|
--end; |
|
while (begin < end) |
|
qSwap(*begin++, *end--); |
|
|
|
int desktop; |
|
pos = unscalePos(pos, &desktop); |
|
if (desktop > effects->numberOfDesktops()) |
|
return NULL; |
|
if (isUsingPresentWindows()) { |
|
const int screen = effects->screenNumber(pos); |
|
EffectWindow *w = |
|
m_managers.at((desktop - 1) * (effects->numScreens()) + screen).windowAtPoint(pos, false); |
|
if (w) |
|
return w; |
|
foreach (EffectWindow * w, windows) { |
|
if (w->isOnDesktop(desktop) && w->isDesktop() && w->geometry().contains(pos)) |
|
return w; |
|
} |
|
} else { |
|
foreach (EffectWindow * w, windows) { |
|
if (w->isOnDesktop(desktop) && !w->isMinimized() && w->geometry().contains(pos)) |
|
return w; |
|
} |
|
} |
|
return NULL; |
|
} |
|
|
|
void DesktopGridEffect::setCurrentDesktop(int desktop) |
|
{ |
|
if (orientation == Qt::Horizontal) { |
|
activeCell.setX((desktop - 1) % gridSize.width() + 1); |
|
activeCell.setY((desktop - 1) / gridSize.width() + 1); |
|
} else { |
|
activeCell.setX((desktop - 1) / gridSize.height() + 1); |
|
activeCell.setY((desktop - 1) % gridSize.height() + 1); |
|
} |
|
if (effects->currentDesktop() != desktop) |
|
effects->setCurrentDesktop(desktop); |
|
} |
|
|
|
void DesktopGridEffect::setHighlightedDesktop(int d) |
|
{ |
|
if (d == highlightedDesktop || d <= 0 || d > effects->numberOfDesktops()) |
|
return; |
|
if (highlightedDesktop > 0 && highlightedDesktop <= hoverTimeline.count()) |
|
hoverTimeline[highlightedDesktop-1]->setCurrentTime(qMin(hoverTimeline[highlightedDesktop-1]->currentTime(), |
|
hoverTimeline[highlightedDesktop-1]->duration())); |
|
highlightedDesktop = d; |
|
if (highlightedDesktop <= hoverTimeline.count()) |
|
hoverTimeline[highlightedDesktop-1]->setCurrentTime(qMax(hoverTimeline[highlightedDesktop-1]->currentTime(), 0)); |
|
effects->addRepaintFull(); |
|
} |
|
|
|
int DesktopGridEffect::desktopToRight(int desktop, bool wrap) const |
|
{ |
|
// Copied from Workspace::desktopToRight() |
|
int dt = desktop - 1; |
|
if (orientation == Qt::Vertical) { |
|
dt += gridSize.height(); |
|
if (dt >= effects->numberOfDesktops()) { |
|
if (wrap) |
|
dt -= effects->numberOfDesktops(); |
|
else |
|
return desktop; |
|
} |
|
} else { |
|
int d = (dt % gridSize.width()) + 1; |
|
if (d >= gridSize.width()) { |
|
if (wrap) |
|
d -= gridSize.width(); |
|
else |
|
return desktop; |
|
} |
|
dt = dt - (dt % gridSize.width()) + d; |
|
} |
|
return dt + 1; |
|
} |
|
|
|
int DesktopGridEffect::desktopToLeft(int desktop, bool wrap) const |
|
{ |
|
// Copied from Workspace::desktopToLeft() |
|
int dt = desktop - 1; |
|
if (orientation == Qt::Vertical) { |
|
dt -= gridSize.height(); |
|
if (dt < 0) { |
|
if (wrap) |
|
dt += effects->numberOfDesktops(); |
|
else |
|
return desktop; |
|
} |
|
} else { |
|
int d = (dt % gridSize.width()) - 1; |
|
if (d < 0) { |
|
if (wrap) |
|
d += gridSize.width(); |
|
else |
|
return desktop; |
|
} |
|
dt = dt - (dt % gridSize.width()) + d; |
|
} |
|
return dt + 1; |
|
} |
|
|
|
int DesktopGridEffect::desktopUp(int desktop, bool wrap) const |
|
{ |
|
// Copied from Workspace::desktopUp() |
|
int dt = desktop - 1; |
|
if (orientation == Qt::Horizontal) { |
|
dt -= gridSize.width(); |
|
if (dt < 0) { |
|
if (wrap) |
|
dt += effects->numberOfDesktops(); |
|
else |
|
return desktop; |
|
} |
|
} else { |
|
int d = (dt % gridSize.height()) - 1; |
|
if (d < 0) { |
|
if (wrap) |
|
d += gridSize.height(); |
|
else |
|
return desktop; |
|
} |
|
dt = dt - (dt % gridSize.height()) + d; |
|
} |
|
return dt + 1; |
|
} |
|
|
|
int DesktopGridEffect::desktopDown(int desktop, bool wrap) const |
|
{ |
|
// Copied from Workspace::desktopDown() |
|
int dt = desktop - 1; |
|
if (orientation == Qt::Horizontal) { |
|
dt += gridSize.width(); |
|
if (dt >= effects->numberOfDesktops()) { |
|
if (wrap) |
|
dt -= effects->numberOfDesktops(); |
|
else |
|
return desktop; |
|
} |
|
} else { |
|
int d = (dt % gridSize.height()) + 1; |
|
if (d >= gridSize.height()) { |
|
if (wrap) |
|
d -= gridSize.height(); |
|
else |
|
return desktop; |
|
} |
|
dt = dt - (dt % gridSize.height()) + d; |
|
} |
|
return dt + 1; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Activation |
|
|
|
void DesktopGridEffect::toggle() |
|
{ |
|
setActive(!activated); |
|
} |
|
|
|
void DesktopGridEffect::setActive(bool active) |
|
{ |
|
if (effects->activeFullScreenEffect() && effects->activeFullScreenEffect() != this) |
|
return; // Only one fullscreen effect at a time thanks |
|
if (active && isMotionManagerMovingWindows()) |
|
return; // Still moving windows from last usage - don't activate |
|
if (activated == active) |
|
return; // Already in that state |
|
|
|
activated = active; |
|
if (activated && timeline.currentValue() == 0) |
|
setup(); |
|
if (!activated) { |
|
if (isUsingPresentWindows()) { |
|
QList<WindowMotionManager>::iterator it; |
|
for (it = m_managers.begin(); it != m_managers.end(); ++it) { |
|
foreach (EffectWindow * w, (*it).managedWindows()) { |
|
(*it).moveWindow(w, w->geometry()); |
|
} |
|
} |
|
} |
|
setHighlightedDesktop(effects->currentDesktop()); // Ensure selected desktop is highlighted |
|
for (QHash< DesktopButtonsView*, EffectWindow*>::iterator it = m_desktopButtonsViews.begin(); |
|
it != m_desktopButtonsViews.end(); ++it) { |
|
it.key()->hide(); |
|
} |
|
} |
|
effects->addRepaintFull(); |
|
} |
|
|
|
void DesktopGridEffect::setup() |
|
{ |
|
if (!isActive()) |
|
return; |
|
if (!keyboardGrab) { |
|
keyboardGrab = effects->grabKeyboard(this); |
|
effects->startMouseInterception(this, Qt::PointingHandCursor); |
|
effects->setActiveFullScreenEffect(this); |
|
} |
|
setHighlightedDesktop(effects->currentDesktop()); |
|
|
|
// Soft highlighting |
|
qDeleteAll(hoverTimeline); |
|
hoverTimeline.clear(); |
|
for (int i = 0; i < effects->numberOfDesktops(); i++) { |
|
QTimeLine *newTimeline = new QTimeLine(zoomDuration, this); |
|
newTimeline->setCurveShape(QTimeLine::EaseInOutCurve); |
|
hoverTimeline.append(newTimeline); |
|
} |
|
hoverTimeline[effects->currentDesktop() - 1]->setCurrentTime(hoverTimeline[effects->currentDesktop() - 1]->duration()); |
|
|
|
// Create desktop name textures if enabled |
|
if (desktopNameAlignment) { |
|
QFont font; |
|
font.setBold(true); |
|
font.setPointSize(12); |
|
for (int i = 0; i < effects->numberOfDesktops(); i++) { |
|
EffectFrame* frame = effects->effectFrame(EffectFrameUnstyled, false); |
|
frame->setFont(font); |
|
frame->setText(effects->desktopName(i + 1)); |
|
frame->setAlignment(desktopNameAlignment); |
|
desktopNames.append(frame); |
|
} |
|
} |
|
setupGrid(); |
|
setCurrentDesktop(effects->currentDesktop()); |
|
|
|
// setup the motion managers |
|
if (m_usePresentWindows) |
|
m_proxy = static_cast<PresentWindowsEffectProxy*>(effects->getProxy(BuiltInEffects::nameForEffect(BuiltInEffect::PresentWindows))); |
|
if (isUsingPresentWindows()) { |
|
for (int i = 1; i <= effects->numberOfDesktops(); i++) { |
|
for (int j = 0; j < effects->numScreens(); j++) { |
|
WindowMotionManager manager; |
|
foreach (EffectWindow * w, effects->stackingOrder()) { |
|
if (w->isOnDesktop(i) && w->screen() == j &&isRelevantWithPresentWindows(w)) { |
|
manager.manage(w); |
|
} |
|
} |
|
m_proxy->calculateWindowTransformations(manager.managedWindows(), j, manager); |
|
m_managers.append(manager); |
|
} |
|
} |
|
} |
|
bool enableAdd = effects->numberOfDesktops() < 20; |
|
bool enableRemove = effects->numberOfDesktops() > 1; |
|
for (int i = 0; i < effects->numScreens(); ++i) { |
|
DesktopButtonsView* view = new DesktopButtonsView(); |
|
view->setAddDesktopEnabled(enableAdd); |
|
view->setRemoveDesktopEnabled(enableRemove); |
|
connect(view, SIGNAL(addDesktop()), SLOT(slotAddDesktop())); |
|
connect(view, SIGNAL(removeDesktop()), SLOT(slotRemoveDesktop())); |
|
const QRect screenRect = effects->clientArea(FullScreenArea, i, 1); |
|
view->setGeometry(screenRect.right() + 1 - view->width(), |
|
screenRect.bottom() + 1 - view->height(), |
|
view->width(), view->height()); |
|
view->show(); |
|
m_desktopButtonsViews.insert(view, NULL); |
|
} |
|
} |
|
|
|
void DesktopGridEffect::setupGrid() |
|
{ |
|
// We need these variables for every paint so lets cache them |
|
int x, y; |
|
int numDesktops = effects->numberOfDesktops(); |
|
switch(layoutMode) { |
|
default: |
|
case LayoutPager: |
|
orientation = Qt::Horizontal; |
|
gridSize = effects->desktopGridSize(); |
|
// sanity check: pager may report incorrect size in case of one desktop |
|
if (numDesktops == 1) { |
|
gridSize = QSize(1, 1); |
|
} |
|
break; |
|
case LayoutAutomatic: |
|
y = sqrt(float(numDesktops)) + 0.5; |
|
x = float(numDesktops) / float(y) + 0.5; |
|
if (x * y < numDesktops) |
|
x++; |
|
orientation = Qt::Horizontal; |
|
gridSize.setWidth(x); |
|
gridSize.setHeight(y); |
|
break; |
|
case LayoutCustom: |
|
orientation = Qt::Horizontal; |
|
gridSize.setWidth(ceil(effects->numberOfDesktops() / double(customLayoutRows))); |
|
gridSize.setHeight(customLayoutRows); |
|
break; |
|
} |
|
scale.clear(); |
|
unscaledBorder.clear(); |
|
scaledSize.clear(); |
|
scaledOffset.clear(); |
|
for (int i = 0; i < effects->numScreens(); i++) { |
|
QRect geom = effects->clientArea(ScreenArea, i, 0); |
|
double sScale; |
|
if (gridSize.width() > gridSize.height()) |
|
sScale = (geom.width() - border * (gridSize.width() + 1)) / double(geom.width() * gridSize.width()); |
|
else |
|
sScale = (geom.height() - border * (gridSize.height() + 1)) / double(geom.height() * gridSize.height()); |
|
double sBorder = border / sScale; |
|
QSizeF size( |
|
double(geom.width()) * sScale, |
|
double(geom.height()) * sScale |
|
); |
|
QPointF offset( |
|
geom.x() + (geom.width() - size.width() * gridSize.width() - border *(gridSize.width() - 1)) / 2.0, |
|
geom.y() + (geom.height() - size.height() * gridSize.height() - border *(gridSize.height() - 1)) / 2.0 |
|
); |
|
scale.append(sScale); |
|
unscaledBorder.append(sBorder); |
|
scaledSize.append(size); |
|
scaledOffset.append(offset); |
|
} |
|
} |
|
|
|
void DesktopGridEffect::finish() |
|
{ |
|
if (desktopNameAlignment) { |
|
qDeleteAll(desktopNames); |
|
desktopNames.clear(); |
|
} |
|
|
|
if (keyboardGrab) |
|
effects->ungrabKeyboard(); |
|
keyboardGrab = false; |
|
effects->stopMouseInterception(this); |
|
effects->setActiveFullScreenEffect(0); |
|
if (isUsingPresentWindows()) { |
|
while (!m_managers.isEmpty()) { |
|
m_managers.first().unmanageAll(); |
|
m_managers.removeFirst(); |
|
} |
|
m_proxy = 0; |
|
} |
|
|
|
QHash< DesktopButtonsView*, EffectWindow* >::iterator i = m_desktopButtonsViews.begin(); |
|
while (i != m_desktopButtonsViews.end()) { |
|
if (*i && (*i)->isDeleted()) |
|
(*i)->unrefWindow(); |
|
DesktopButtonsView *view = i.key(); |
|
i = m_desktopButtonsViews.erase(i); |
|
view->deleteLater(); |
|
} |
|
} |
|
|
|
void DesktopGridEffect::globalShortcutChanged(QAction *action, const QKeySequence& seq) |
|
{ |
|
if (action->objectName() != QStringLiteral("ShowDesktopGrid")) { |
|
return; |
|
} |
|
shortcut.clear(); |
|
shortcut.append(seq); |
|
} |
|
|
|
bool DesktopGridEffect::isMotionManagerMovingWindows() const |
|
{ |
|
if (isUsingPresentWindows()) { |
|
QList<WindowMotionManager>::const_iterator it; |
|
for (it = m_managers.begin(); it != m_managers.end(); ++it) { |
|
if ((*it).areWindowsMoving()) |
|
return true; |
|
} |
|
} |
|
return false; |
|
} |
|
|
|
bool DesktopGridEffect::isUsingPresentWindows() const |
|
{ |
|
return (m_proxy != NULL); |
|
} |
|
|
|
// transforms the geometry of the moved window to a geometry on the desktop |
|
// internal method only used when a window is dropped onto a desktop |
|
QRectF DesktopGridEffect::moveGeometryToDesktop(int desktop) const |
|
{ |
|
QPointF point = unscalePos(m_windowMoveGeometry.topLeft() + cursorPos() - m_windowMoveStartPoint); |
|
const double scaleFactor = scale[ windowMove->screen()]; |
|
if (posToDesktop(m_windowMoveGeometry.topLeft() + cursorPos() - m_windowMoveStartPoint) != desktop) { |
|
// topLeft is not on the desktop - check other corners |
|
// if all corners are not on the desktop the window is bigger than the desktop - no matter what it will look strange |
|
if (posToDesktop(m_windowMoveGeometry.topRight() + cursorPos() - m_windowMoveStartPoint) == desktop) { |
|
point = unscalePos(m_windowMoveGeometry.topRight() + cursorPos() - m_windowMoveStartPoint) - |
|
QPointF(m_windowMoveGeometry.width(), 0) / scaleFactor; |
|
} else if (posToDesktop(m_windowMoveGeometry.bottomLeft() + cursorPos() - m_windowMoveStartPoint) == desktop) { |
|
point = unscalePos(m_windowMoveGeometry.bottomLeft() + cursorPos() - m_windowMoveStartPoint) - |
|
QPointF(0, m_windowMoveGeometry.height()) / scaleFactor; |
|
} else if (posToDesktop(m_windowMoveGeometry.bottomRight() + cursorPos() - m_windowMoveStartPoint) == desktop) { |
|
point = unscalePos(m_windowMoveGeometry.bottomRight() + cursorPos() - m_windowMoveStartPoint) - |
|
QPointF(m_windowMoveGeometry.width(), m_windowMoveGeometry.height()) / scaleFactor; |
|
} |
|
} |
|
return QRectF(point, m_windowMoveGeometry.size() / scaleFactor); |
|
} |
|
|
|
void DesktopGridEffect::slotAddDesktop() |
|
{ |
|
effects->setNumberOfDesktops(effects->numberOfDesktops() + 1); |
|
} |
|
|
|
void DesktopGridEffect::slotRemoveDesktop() |
|
{ |
|
effects->setNumberOfDesktops(effects->numberOfDesktops() - 1); |
|
} |
|
|
|
void DesktopGridEffect::slotNumberDesktopsChanged(uint old) |
|
{ |
|
if (!activated) |
|
return; |
|
const uint desktop = effects->numberOfDesktops(); |
|
bool enableAdd = desktop < 20; |
|
bool enableRemove = desktop > 1; |
|
for (QHash< DesktopButtonsView*, EffectWindow* >::iterator it = m_desktopButtonsViews.begin(); |
|
it != m_desktopButtonsViews.end(); ++it) { |
|
it.key()->setAddDesktopEnabled(enableAdd); |
|
it.key()->setRemoveDesktopEnabled(enableRemove); |
|
} |
|
if (old < desktop) |
|
desktopsAdded(old); |
|
else |
|
desktopsRemoved(old); |
|
} |
|
|
|
void DesktopGridEffect::desktopsAdded(int old) |
|
{ |
|
const int desktop = effects->numberOfDesktops(); |
|
for (int i = old; i <= effects->numberOfDesktops(); i++) { |
|
// add a timeline for the new desktop |
|
QTimeLine *newTimeline = new QTimeLine(zoomDuration, this); |
|
newTimeline->setCurveShape(QTimeLine::EaseInOutCurve); |
|
hoverTimeline.append(newTimeline); |
|
} |
|
|
|
// Create desktop name textures if enabled |
|
if (desktopNameAlignment) { |
|
QFont font; |
|
font.setBold(true); |
|
font.setPointSize(12); |
|
for (int i = old; i < desktop; i++) { |
|
EffectFrame* frame = effects->effectFrame(EffectFrameUnstyled, false); |
|
frame->setFont(font); |
|
frame->setText(effects->desktopName(i + 1)); |
|
frame->setAlignment(desktopNameAlignment); |
|
desktopNames.append(frame); |
|
} |
|
} |
|
|
|
if (isUsingPresentWindows()) { |
|
for (int i = old+1; i <= effects->numberOfDesktops(); ++i) { |
|
for (int j = 0; j < effects->numScreens(); ++j) { |
|
WindowMotionManager manager; |
|
foreach (EffectWindow * w, effects->stackingOrder()) { |
|
if (w->isOnDesktop(i) && w->screen() == j &&isRelevantWithPresentWindows(w)) { |
|
manager.manage(w); |
|
} |
|
} |
|
m_proxy->calculateWindowTransformations(manager.managedWindows(), j, manager); |
|
m_managers.append(manager); |
|
} |
|
} |
|
} |
|
|
|
setupGrid(); |
|
|
|
// and repaint |
|
effects->addRepaintFull(); |
|
} |
|
|
|
void DesktopGridEffect::desktopsRemoved(int old) |
|
{ |
|
const int desktop = effects->numberOfDesktops(); |
|
for (int i = desktop; i < old; i++) { |
|
delete hoverTimeline.takeLast(); |
|
if (desktopNameAlignment) { |
|
delete desktopNames.last(); |
|
desktopNames.removeLast(); |
|
} |
|
if (isUsingPresentWindows()) { |
|
for (int j = 0; j < effects->numScreens(); ++j) { |
|
WindowMotionManager& manager = m_managers.last(); |
|
manager.unmanageAll(); |
|
m_managers.removeLast(); |
|
} |
|
} |
|
} |
|
// add removed windows to the last desktop |
|
if (isUsingPresentWindows()) { |
|
for (int j = 0; j < effects->numScreens(); ++j) { |
|
WindowMotionManager& manager = m_managers[(desktop-1)*(effects->numScreens())+j ]; |
|
foreach (EffectWindow * w, effects->stackingOrder()) { |
|
if (manager.isManaging(w)) |
|
continue; |
|
if (w->isOnDesktop(desktop) && w->screen() == j && isRelevantWithPresentWindows(w)) { |
|
manager.manage(w); |
|
} |
|
} |
|
m_proxy->calculateWindowTransformations(manager.managedWindows(), j, manager); |
|
} |
|
} |
|
|
|
setupGrid(); |
|
|
|
// and repaint |
|
effects->addRepaintFull(); |
|
} |
|
|
|
bool DesktopGridEffect::isActive() const |
|
{ |
|
return timeline.currentValue() != 0 || activated || (isUsingPresentWindows() && isMotionManagerMovingWindows()); |
|
} |
|
|
|
bool DesktopGridEffect::isRelevantWithPresentWindows(EffectWindow *w) const |
|
{ |
|
return !(w->isDesktop() || w->isDock() || w->isSkipSwitcher()) && |
|
w->isCurrentTab() && w->isOnCurrentActivity(); |
|
} |
|
|
|
/************************************************ |
|
* DesktopButtonView |
|
************************************************/ |
|
DesktopButtonsView::DesktopButtonsView(QWindow *parent) |
|
: QQuickView(parent) |
|
{ |
|
setFlags(Qt::X11BypassWindowManagerHint); |
|
setColor(Qt::transparent); |
|
|
|
rootContext()->setContextProperty(QStringLiteral("add"), QVariant(true)); |
|
rootContext()->setContextProperty(QStringLiteral("remove"), QVariant(true)); |
|
setSource(QUrl(QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("kwin/effects/desktopgrid/main.qml")))); |
|
if (QObject *item = rootObject()->findChild<QObject*>(QStringLiteral("addButton"))) { |
|
connect(item, SIGNAL(clicked()), SIGNAL(addDesktop())); |
|
} |
|
if (QObject *item = rootObject()->findChild<QObject*>(QStringLiteral("removeButton"))) { |
|
connect(item, SIGNAL(clicked()), SIGNAL(removeDesktop())); |
|
} |
|
} |
|
|
|
void DesktopButtonsView::windowInputMouseEvent(QMouseEvent *e) |
|
{ |
|
if (e->type() == QEvent::MouseMove) { |
|
mouseMoveEvent(e); |
|
} else if (e->type() == QEvent::MouseButtonPress) { |
|
mousePressEvent(e); |
|
} else if (e->type() == QEvent::MouseButtonDblClick) { |
|
mouseDoubleClickEvent(e); |
|
} else if (e->type() == QEvent::MouseButtonRelease) { |
|
mouseReleaseEvent(e); |
|
} |
|
} |
|
|
|
void DesktopButtonsView::setAddDesktopEnabled(bool enable) |
|
{ |
|
rootContext()->setContextProperty(QStringLiteral("add"), QVariant(enable)); |
|
} |
|
|
|
void DesktopButtonsView::setRemoveDesktopEnabled(bool enable) |
|
{ |
|
rootContext()->setContextProperty(QStringLiteral("remove"), QVariant(enable)); |
|
} |
|
|
|
} // namespace |
|
|
|
#include "desktopgrid.moc"
|
|
|