kwin/effects/desktopgrid/desktopgrid.cpp
Martin Gräßlin e0a1eae9ec Use Lanczos in desktop grid
svn path=/trunk/KDE/kdebase/workspace/; revision=1191904
2010-11-01 12:17:05 +00:00

1633 lines
62 KiB
C++

/********************************************************************
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 <kde@martin-graesslin.com>
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"
#include "../presentwindows/presentwindows_proxy.h"
#include <math.h>
#include <kaction.h>
#include <kactioncollection.h>
#include <kdebug.h>
#include <klocale.h>
#include <kconfiggroup.h>
#include <netwm_def.h>
#include <QEvent>
#include <QMouseEvent>
#include <kglobalsettings.h>
#include <QtGui/QPainter>
#include <QtGui/QGraphicsLinearLayout>
#include <Plasma/PushButton>
#include <Plasma/WindowEffects>
namespace KWin
{
// WARNING, TODO: This effect relies on the desktop layout being EWMH-compliant.
KWIN_EFFECT( desktopgrid, DesktopGridEffect )
DesktopGridEffect::DesktopGridEffect()
: activated( false )
, timeline()
, keyboardGrab( false )
, wasWindowMove( false )
, wasDesktopMove( false )
, windowMove( NULL )
, windowMoveDiff()
, gridSize()
, orientation( Qt::Horizontal )
, activeCell( 1, 1 )
, scale()
, unscaledBorder()
, scaledSize()
, scaledOffset()
, m_proxy( 0 )
{
// Load shortcuts
KActionCollection* actionCollection = new KActionCollection( this );
KAction* a = (KAction*) actionCollection->addAction( "ShowDesktopGrid" );
a->setText( i18n( "Show Desktop Grid" ));
a->setGlobalShortcut( KShortcut( Qt::CTRL + Qt::Key_F8 ));
shortcut = a->globalShortcut();
connect( a, SIGNAL( triggered( bool )), this, SLOT( toggle() ));
connect( a, SIGNAL( globalShortcutChanged( QKeySequence )), this, SLOT( globalShortcutChanged(QKeySequence)));
// Load all other configuration details
reconfigure( ReconfigureAll );
}
DesktopGridEffect::~DesktopGridEffect()
{
foreach( ElectricBorder border, borderActivate )
{
effects->unreserveElectricBorder( border );
}
}
void DesktopGridEffect::reconfigure( ReconfigureFlags )
{
KConfigGroup conf = effects->effectConfig( "DesktopGrid" );
foreach( ElectricBorder border, borderActivate )
{
effects->unreserveElectricBorder( border );
}
borderActivate.clear();
QList<int> borderList = QList<int>();
borderList.append( int( ElectricNone ) );
borderList = conf.readEntry( "BorderActivate", borderList );
foreach( int i, borderList )
{
borderActivate.append( ElectricBorder( i ) );
effects->reserveElectricBorder( ElectricBorder( i ) );
}
zoomDuration = animationTime( conf, "ZoomDuration", 300 );
timeline.setCurveShape( TimeLine::EaseInOutCurve );
timeline.setDuration( zoomDuration );
border = conf.readEntry( "BorderWidth", 10 );
desktopNameAlignment = Qt::Alignment( conf.readEntry( "DesktopNameAlignment", 0 ));
layoutMode = conf.readEntry( "LayoutMode", int( LayoutPager ));
customLayoutRows = conf.readEntry( "CustomLayoutRows", 2 );
m_usePresentWindows = conf.readEntry( "PresentWindows", true );
}
//-----------------------------------------------------------------------------
// Screen painting
void DesktopGridEffect::prePaintScreen( ScreenPrePaintData& data, int time )
{
if( timeline.value() != 0 || activated || (isUsingPresentWindows() && isMotionManagerMovingWindows()) )
{
if( activated )
timeline.addTime(time);
else
timeline.removeTime(time);
for( int i = 0; i < effects->numberOfDesktops(); i++ )
{
if( i == highlightedDesktop - 1 )
hoverTimeline[i].addTime(time);
else
hoverTimeline[i].removeTime(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.value() != 0 || (isUsingPresentWindows() && isMotionManagerMovingWindows()) )
data.mask |= PAINT_SCREEN_TRANSFORMED | PAINT_SCREEN_BACKGROUND_FIRST;
if( !activated && timeline.value() == 0 && !(isUsingPresentWindows() && isMotionManagerMovingWindows()) )
finish();
}
effects->prePaintScreen( data, time );
}
void DesktopGridEffect::paintScreen( int mask, QRegion region, ScreenPaintData& data )
{
if( timeline.value() == 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.opacity *= timeline.value();
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.xScale *= (float)geo.width()/(float)windowMove->width();
d.yScale *= (float)geo.height()/(float)windowMove->height();
d.xTranslate += qRound( geo.left() - windowMove->x() );
d.yTranslate += qRound( 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 );
PaintClipper pc( screenGeom ); // TODO: Doesn't work in XRender for some reason?
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.value(), 0.7 );
++desktop;
}
}
}
}
void DesktopGridEffect::postPaintScreen()
{
if( activated ? timeline.value() != 1 : timeline.value() != 0 )
effects->addRepaintFull(); // Repaint during zoom
if( isUsingPresentWindows() && isMotionManagerMovingWindows() )
effects->addRepaintFull();
if( activated )
{
for( int i = 0; i < effects->numberOfDesktops(); i++ )
{
if( hoverTimeline[i].value() != 0.0 && hoverTimeline[i].value() != 1.0 )
{ // Repaint during soft highlighting
effects->addRepaintFull();
break;
}
}
}
effects->postPaintScreen();
}
//-----------------------------------------------------------------------------
// Window painting
void DesktopGridEffect::prePaintWindow( EffectWindow* w, WindowPrePaintData& data, int time )
{
if( timeline.value() != 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.value() != 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
double xScale = data.xScale;
double yScale = data.yScale;
// Don't change brightness of windows on all desktops as this causes flickering
if( !w->isOnAllDesktops() || w->isDesktop() )
data.brightness *= 1.0 - ( 0.3 * ( 1.0 - hoverTimeline[paintingDesktop - 1].value() ));
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() )
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.value();
d.xScale = interpolate( 1, xScale * scale[screen] * (float)transformedGeo.width()/(float)w->geometry().width(), progress);
d.yScale = interpolate( 1, yScale * scale[screen] * (float)transformedGeo.height()/(float)w->geometry().height(), progress);
d.xTranslate += qRound( newPos.x() - w->x() );
d.yTranslate += qRound( newPos.y() - w->y() );
if( isUsingPresentWindows() && ( w->isDock() || w->isSkipSwitcher() ) )
{
// fade out panels if present windows is used
d.opacity *= ( 1.0 - timeline.value() );
}
if( isUsingPresentWindows() && w->isMinimized() )
{
d.opacity *= timeline.value();
}
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
{
PaintClipper pc( effects->clientArea( ScreenArea, screen, 0 ));
if( w->isDesktop() && timeline.value() == 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, region, 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::windowAdded( EffectWindow* w )
{
if( !activated )
return;
if( isUsingPresentWindows() )
{
if( w->isDesktop() || w->isDock() || !w->visibleInClientGroup() )
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::windowClosed( EffectWindow* w )
{
if ( !activated && timeline.value() == 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::windowDeleted( EffectWindow* w )
{
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::windowGeometryShapeChanged( 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( Window, QEvent* e )
{
if(( e->type() != QEvent::MouseMove
&& e->type() != QEvent::MouseButtonPress
&& e->type() != QEvent::MouseButtonRelease )
|| timeline.value() != 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() );
const QPointF scenePos = view->mapToScene( widgetPos );
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() > KGlobalSettings::dndEventDelay() )
{ // 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 );
}
XDefineCursor( display(), input, QCursor( Qt::ClosedHandCursor ).handle() );
}
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() > KGlobalSettings::dndEventDelay())
{
wasDesktopMove = true;
XDefineCursor( display(), input, QCursor( Qt::ClosedHandCursor ).handle() );
}
if( d != highlightedDesktop ) // Highlight desktop
{
if ( (me->buttons() & Qt::LeftButton) && !wasWindowMove && d <= effects->numberOfDesktops() )
{
EffectWindowList windows = effects->stackingOrder();
EffectWindowList stack;
foreach( EffectWindow* w, windows )
{
if( w->isOnAllDesktops() )
continue;
if( w->isOnDesktop( highlightedDesktop ) )
{
effects->windowToDesktop( w, d );
if( isUsingPresentWindows() )
{
m_managers[ (d-1)*(effects->numScreens()) + w->screen() ].manage( w );
m_managers[ (highlightedDesktop-1)*(effects->numScreens()) + w->screen() ].unmanage( w );
}
}
else if( w->isOnDesktop( d ) )
stack << w;
}
foreach( EffectWindow* w, stack )
{
effects->windowToDesktop( w, highlightedDesktop );
if( isUsingPresentWindows() )
{
m_managers[ (d-1)*(effects->numScreens()) + w->screen() ].unmanage( w );
m_managers[ (highlightedDesktop-1)*(effects->numScreens()) + w->screen() ].manage( w );
}
}
if( isUsingPresentWindows() )
{
for( int i=0; i<effects->numScreens(); i++ )
{
WindowMotionManager& manager = m_managers[ (d-1)*(effects->numScreens()) + i ];
WindowMotionManager& manager2 = m_managers[ (highlightedDesktop-1)*(effects->numScreens()) + i ];
m_proxy->calculateWindowTransformations( manager.managedWindows(), i, manager );
m_proxy->calculateWindowTransformations( manager2.managedWindows(), i, manager2 );
}
effects->addRepaintFull();
}
}
setHighlightedDesktop( d );
}
}
if( e->type() == QEvent::MouseButtonPress )
{
if( me->buttons() == Qt::LeftButton )
{
// 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( 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 )
{
if( !wasWindowMove && !wasDesktopMove )
{
setCurrentDesktop( posToDesktop( me->pos() ));
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();
}
}
effects->setElevatedWindow( windowMove, false );
windowMove = NULL;
XDefineCursor( display(), input, QCursor( Qt::PointingHandCursor ).handle() );
}
else if ( wasDesktopMove )
XDefineCursor( display(), input, QCursor( Qt::PointingHandCursor ).handle() );
wasWindowMove = false;
wasDesktopMove = false;
}
}
void DesktopGridEffect::grabbedKeyboardEvent( QKeyEvent* e )
{
if( timeline.value() != 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.value();
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.value();
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 );
QRect screenGeom = effects->clientArea( ScreenArea, screen, 0 );
//double progress = timeline.value();
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( 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;
highlightedDesktop = d;
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.value() == 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()
{
keyboardGrab = effects->grabKeyboard( this );
input = effects->createInputWindow( this, 0, 0, displayWidth(), displayHeight(),
Qt::PointingHandCursor );
effects->setActiveFullScreenEffect( this );
setHighlightedDesktop( effects->currentDesktop() );
// Soft highlighting
hoverTimeline.clear();
for( int i = 0; i < effects->numberOfDesktops(); i++ )
{
TimeLine newTimeline( animationTime( zoomDuration ));
newTimeline.setCurveShape( TimeLine::EaseInOutCurve );
hoverTimeline.append( newTimeline );
}
hoverTimeline[effects->currentDesktop() - 1].setProgress( 1.0 );
// 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( "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 && !w->isDesktop() && !w->isDock() &&
w->visibleInClientGroup() && !w->isSkipSwitcher() )
{
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->sceneRect().width(),
screenRect.bottom() + 1 - view->sceneRect().height(),
view->sceneRect().width(), view->sceneRect().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->destroyInputWindow( input );
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( const QKeySequence& seq )
{
shortcut = KShortcut( seq );
}
bool DesktopGridEffect::isMotionManagerMovingWindows()
{
if( isUsingPresentWindows() )
{
QList<WindowMotionManager>::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::numberDesktopsChanged( int old )
{
if( !activated )
return;
const int 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
TimeLine newTimeline( animationTime( zoomDuration ));
newTimeline.setCurveShape( TimeLine::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; 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 && !w->isDesktop() && !w->isDock() &&
w->visibleInClientGroup() )
{
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++ )
{
hoverTimeline.removeLast();
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 ) && w->isOnDesktop( desktop ) && w->screen() == j &&
!w->isDesktop() && !w->isDock() && w->visibleInClientGroup() )
{
manager.manage( w );
}
}
m_proxy->calculateWindowTransformations( manager.managedWindows(), j, manager );
}
}
setupGrid();
// and repaint
effects->addRepaintFull();
}
/************************************************
* DesktopButtonView
************************************************/
DesktopButtonsView::DesktopButtonsView( QWidget* parent )
: QGraphicsView( parent )
{
setWindowFlags( Qt::X11BypassWindowManagerHint );
setAttribute( Qt::WA_TranslucentBackground );
setFrameShape( QFrame::NoFrame );
QPalette pal = palette();
pal.setColor( backgroundRole(), Qt::transparent );
setPalette( pal );
setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
// setup the scene
QGraphicsScene* scene = new QGraphicsScene( this );
m_addDesktopButton = new Plasma::PushButton();
m_addDesktopButton->setIcon( KIcon( "list-add" ) );
m_removeDesktopButton = new Plasma::PushButton();
m_removeDesktopButton->setIcon(KIcon("list-remove"));
scene->addItem( m_addDesktopButton );
scene->addItem( m_removeDesktopButton );
connect( m_addDesktopButton, SIGNAL(clicked()), SIGNAL(addDesktop()));
connect( m_removeDesktopButton, SIGNAL(clicked()), SIGNAL(removeDesktop()));
QGraphicsLinearLayout *layout = new QGraphicsLinearLayout;
layout->addItem( m_addDesktopButton );
layout->addItem( m_removeDesktopButton );
QGraphicsWidget *form = new QGraphicsWidget;
form->setLayout( layout );
form->setGeometry(0, 0, 64*2, 64);
scene->addItem( form );
m_frame = new Plasma::FrameSvg( this );
m_frame->setImagePath( "dialogs/background" );
m_frame->setCacheAllRenderedFrames( true );
m_frame->setEnabledBorders( Plasma::FrameSvg::AllBorders );
qreal left, top, right, bottom;
m_frame->getMargins( left, top, right, bottom );
qreal width = form->size().width() + left + right;
qreal height = form->size().height() + top + bottom;
m_frame->resizeFrame( QSizeF( width, height ) );
Plasma::WindowEffects::enableBlurBehind( winId(), true, m_frame->mask() );
Plasma::WindowEffects::overrideShadow( winId(), true );
form->setPos( left, top );
scene->setSceneRect( QRectF( QPointF( 0, 0 ), QSizeF( width, height ) ) );
setScene( scene );
}
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 )
{
m_addDesktopButton->setEnabled( enable );
}
void DesktopButtonsView::setRemoveDesktopEnabled( bool enable )
{
m_removeDesktopButton->setEnabled( enable );
}
void DesktopButtonsView::drawBackground( QPainter* painter, const QRectF& rect )
{
Q_UNUSED( rect )
painter->setRenderHint( QPainter::Antialiasing );
m_frame->paintFrame( painter );
}
} // namespace
#include "desktopgrid.moc"