1 /********************************************************************
2 KWin - the KDE window manager
3 This file is part of the KDE project.
5 Copyright (C) 2006 Lubos Lunak <l.lunak@kde.org>
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
19 *********************************************************************/
21 #include "kwineffects.h"
23 #include "kwinglutils.h"
24 #include "kwinxrenderutils.h"
26 #include <QtDBus/QtDBus>
29 #include <QtCore/QTimeLine>
30 #include <QtGui/QFontMetrics>
31 #include <QtGui/QPainter>
32 #include <QtGui/QPixmap>
35 #include <ksharedconfig.h>
36 #include <kconfiggroup.h>
40 #ifdef KWIN_HAVE_XRENDER_COMPOSITING
41 #include <X11/extensions/Xrender.h>
42 #include <X11/extensions/Xfixes.h>
48 void WindowPrePaintData::setTranslucent()
50 mask
|= Effect::PAINT_WINDOW_TRANSLUCENT
;
51 mask
&= ~Effect::PAINT_WINDOW_OPAQUE
;
52 clip
= QRegion(); // cannot clip, will be transparent
55 void WindowPrePaintData::setTransformed()
57 mask
|= Effect::PAINT_WINDOW_TRANSFORMED
;
61 WindowPaintData::WindowPaintData( EffectWindow
* w
)
62 : opacity( w
->opacity())
63 , contents_opacity( 1.0 )
64 , decoration_opacity( 1.0 )
76 quads
= w
->buildQuads();
79 ScreenPaintData::ScreenPaintData()
90 RotationData::RotationData()
93 , xRotationPoint( 0.0 )
94 , yRotationPoint( 0.0 )
95 , zRotationPoint( 0.0 )
99 //****************************************
101 //****************************************
111 void Effect::reconfigure( ReconfigureFlags
)
115 void Effect::windowUserMovedResized( EffectWindow
* , bool, bool )
119 void Effect::windowOpacityChanged( EffectWindow
*, double )
123 void Effect::windowAdded( EffectWindow
* )
127 void Effect::windowClosed( EffectWindow
* )
131 void Effect::windowDeleted( EffectWindow
* )
135 void Effect::windowActivated( EffectWindow
* )
139 void Effect::windowMinimized( EffectWindow
* )
143 void Effect::windowUnminimized( EffectWindow
* )
147 void Effect::windowInputMouseEvent( Window
, QEvent
* )
151 void Effect::grabbedKeyboardEvent( QKeyEvent
* )
155 void Effect::propertyNotify( EffectWindow
* , long )
159 void Effect::desktopChanged( int )
163 void Effect::windowDamaged( EffectWindow
*, const QRect
& )
167 void Effect::windowGeometryShapeChanged( EffectWindow
*, const QRect
& )
171 void Effect::tabBoxAdded( int )
175 void Effect::tabBoxClosed()
179 void Effect::tabBoxUpdated()
182 bool Effect::borderActivated( ElectricBorder
)
187 void Effect::mouseChanged( const QPoint
&, const QPoint
&, Qt::MouseButtons
,
188 Qt::MouseButtons
, Qt::KeyboardModifiers
, Qt::KeyboardModifiers
)
192 void Effect::prePaintScreen( ScreenPrePaintData
& data
, int time
)
194 effects
->prePaintScreen( data
, time
);
197 void Effect::paintScreen( int mask
, QRegion region
, ScreenPaintData
& data
)
199 effects
->paintScreen( mask
, region
, data
);
202 void Effect::postPaintScreen()
204 effects
->postPaintScreen();
207 void Effect::prePaintWindow( EffectWindow
* w
, WindowPrePaintData
& data
, int time
)
209 effects
->prePaintWindow( w
, data
, time
);
212 void Effect::paintWindow( EffectWindow
* w
, int mask
, QRegion region
, WindowPaintData
& data
)
214 effects
->paintWindow( w
, mask
, region
, data
);
217 void Effect::postPaintWindow( EffectWindow
* w
)
219 effects
->postPaintWindow( w
);
222 void Effect::drawWindow( EffectWindow
* w
, int mask
, QRegion region
, WindowPaintData
& data
)
224 effects
->drawWindow( w
, mask
, region
, data
);
227 void Effect::buildQuads( EffectWindow
* w
, WindowQuadList
& quadList
)
229 effects
->buildQuads( w
, quadList
);
232 QRect
Effect::transformWindowDamage( EffectWindow
* w
, const QRect
& r
)
234 return effects
->transformWindowDamage( w
, r
);
237 void Effect::setPositionTransformations( WindowPaintData
& data
, QRect
& region
, EffectWindow
* w
,
238 const QRect
& r
, Qt::AspectRatioMode aspect
)
240 QSize size
= w
->size();
241 size
.scale( r
.size(), aspect
);
242 data
.xScale
= size
.width() / double( w
->width());
243 data
.yScale
= size
.height() / double( w
->height());
244 int width
= int( w
->width() * data
.xScale
);
245 int height
= int( w
->height() * data
.yScale
);
246 int x
= r
.x() + ( r
.width() - width
) / 2;
247 int y
= r
.y() + ( r
.height() - height
) / 2;
248 region
= QRect( x
, y
, width
, height
);
249 data
.xTranslate
= x
- w
->x();
250 data
.yTranslate
= y
- w
->y();
253 int Effect::displayWidth()
255 return KWin::displayWidth();
258 int Effect::displayHeight()
260 return KWin::displayHeight();
263 QPoint
Effect::cursorPos()
265 return effects
->cursorPos();
268 double Effect::animationTime( const KConfigGroup
& cfg
, const QString
& key
, int defaultTime
)
270 int time
= cfg
.readEntry( key
, 0 );
271 return time
!= 0 ? time
: qMax( defaultTime
* effects
->animationTimeFactor(), 1. );
274 double Effect::animationTime( int defaultTime
)
275 { // at least 1ms, otherwise 0ms times can break some things
276 return qMax( defaultTime
* effects
->animationTimeFactor(), 1. );
279 //****************************************
281 //****************************************
283 EffectsHandler::EffectsHandler(CompositingType type
)
284 : current_paint_screen( 0 )
285 , current_paint_window( 0 )
286 , current_draw_window( 0 )
287 , current_build_quads( 0 )
288 , current_transform( 0 )
289 , compositing_type( type
)
291 if( compositing_type
== NoCompositing
)
293 KWin::effects
= this;
296 EffectsHandler::~EffectsHandler()
298 // All effects should already be unloaded by Impl dtor
299 assert( loaded_effects
.count() == 0 );
302 QRect
EffectsHandler::transformWindowDamage( EffectWindow
* w
, const QRect
& r
)
304 if( current_transform
< loaded_effects
.size())
306 QRect rr
= loaded_effects
[current_transform
++].second
->transformWindowDamage( w
, r
);
314 Window
EffectsHandler::createInputWindow( Effect
* e
, const QRect
& r
, const QCursor
& cursor
)
316 return createInputWindow( e
, r
.x(), r
.y(), r
.width(), r
.height(), cursor
);
319 Window
EffectsHandler::createFullScreenInputWindow( Effect
* e
, const QCursor
& cursor
)
321 return createInputWindow( e
, 0, 0, displayWidth(), displayHeight(), cursor
);
324 CompositingType
EffectsHandler::compositingType() const
326 return compositing_type
;
329 bool EffectsHandler::saturationSupported() const
331 switch( compositing_type
)
333 #ifdef KWIN_HAVE_OPENGL_COMPOSITING
334 case OpenGLCompositing
:
335 return GLTexture::saturationSupported();
337 case XRenderCompositing
:
338 return false; // never
344 void EffectsHandler::sendReloadMessage( const QString
& effectname
)
346 QDBusMessage message
= QDBusMessage::createMethodCall("org.kde.kwin", "/KWin", "org.kde.KWin", "reconfigureEffect");
347 message
<< QString("kwin4_effect_" + effectname
);
348 QDBusConnection::sessionBus().send(message
);
351 KConfigGroup
EffectsHandler::effectConfig( const QString
& effectname
)
353 KSharedConfig::Ptr kwinconfig
= KSharedConfig::openConfig( "kwinrc", KConfig::NoGlobals
);
354 return kwinconfig
->group( "Effect-" + effectname
);
357 bool EffectsHandler::paintText( const QString
& text
, const QRect
& rect
, const QColor
& color
,
358 const QFont
& font
, const Qt::Alignment
& alignment
)
361 // Calculate size of the text
362 QFontMetrics
fm( font
);
363 QString painttext
= fm
.elidedText( text
, Qt::ElideRight
, rect
.width() );
364 QRect textrect
= fm
.boundingRect( painttext
);
366 // Create temporary QImage where the text will be drawn onto
367 QImage
textImage( textrect
.width(), textrect
.height(), QImage::Format_ARGB32
);
368 textImage
.fill( Qt::transparent
);
371 p
.begin( &textImage
);
373 p
.setRenderHint( QPainter::TextAntialiasing
);
375 p
.drawText( -textrect
.topLeft(), painttext
);
378 // Area covered by text
380 if( alignment
& Qt::AlignLeft
)
382 else if( alignment
& Qt::AlignRight
)
383 rectX
= rect
.right() - textrect
.width();
385 rectX
= rect
.center().x() - textrect
.width() / 2;
386 if( alignment
& Qt::AlignTop
)
388 else if( alignment
& Qt::AlignBottom
)
389 rectY
= rect
.bottom() - textrect
.height();
391 rectY
= rect
.center().y() - textrect
.height() / 2;
392 QRect
area( rectX
, rectY
, textrect
.width(), textrect
.height() );
394 #ifdef KWIN_HAVE_OPENGL_COMPOSITING
395 if( effects
->compositingType() == OpenGLCompositing
)
397 GLTexture
textTexture( textImage
, GL_TEXTURE_RECTANGLE_ARB
);
398 glPushAttrib( GL_CURRENT_BIT
| GL_ENABLE_BIT
| GL_TEXTURE_BIT
);
399 glEnable( GL_BLEND
);
400 glBlendFunc( GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
402 textTexture
.render( infiniteRegion(), area
);
403 textTexture
.unbind();
408 #ifdef KWIN_HAVE_XRENDER_COMPOSITING
409 if( effects
->compositingType() == XRenderCompositing
)
411 XRenderPicture
textPicture( QPixmap::fromImage( textImage
));
412 XRenderComposite( display(), textImage
.depth() == 32 ? PictOpOver
: PictOpSrc
,
413 textPicture
, None
, effects
->xrenderBufferPicture(),
414 0, 0, 0, 0, area
.x(), area
.y(), area
.width(), area
.height());
421 bool EffectsHandler::paintTextWithBackground( const QString
& text
, const QRect
& rect
, const QColor
& color
,
422 const QColor
& bgcolor
, const QFont
& font
, const Qt::Alignment
& alignment
)
424 // Calculate size of the text
425 QFontMetrics
fm( font
);
426 QString painttext
= fm
.elidedText( text
, Qt::ElideRight
, rect
.width() );
427 QRect textrect
= fm
.boundingRect( painttext
);
429 // Area covered by text
431 if( alignment
& Qt::AlignLeft
)
433 else if( alignment
& Qt::AlignRight
)
434 rectX
= rect
.right() - textrect
.width();
436 rectX
= rect
.center().x() - textrect
.width() / 2;
437 if( alignment
& Qt::AlignTop
)
439 else if( alignment
& Qt::AlignBottom
)
440 rectY
= rect
.bottom() - textrect
.height();
442 rectY
= rect
.center().y() - textrect
.height() / 2;
443 QRect
area( rectX
, rectY
, textrect
.width(), textrect
.height() );
445 #ifdef KWIN_HAVE_OPENGL_COMPOSITING
446 if( effects
->compositingType() == OpenGLCompositing
)
448 glColor4f( bgcolor
.redF(), bgcolor
.greenF(), bgcolor
.blueF(), bgcolor
.alphaF() );
449 renderRoundBox( area
.adjusted( -8, -3, 8, 3 ), 5 );
451 return paintText( text
, rect
, color
, font
, alignment
);
454 #ifdef KWIN_HAVE_XRENDER_COMPOSITING
455 if( effects
->compositingType() == XRenderCompositing
)
457 xRenderRoundBox( effects
->xrenderBufferPicture(), area
.adjusted( -8, -3, 8, 3 ), 5, bgcolor
);
458 return paintText( text
, rect
, color
, font
, alignment
);
465 EffectsHandler
* effects
= 0;
468 //****************************************
470 //****************************************
472 EffectWindow::EffectWindow()
476 EffectWindow::~EffectWindow()
480 bool EffectWindow::isOnCurrentDesktop() const
482 return isOnDesktop( effects
->currentDesktop());
485 bool EffectWindow::isOnDesktop( int d
) const
487 return desktop() == d
|| isOnAllDesktops();
490 bool EffectWindow::hasDecoration() const
492 return contentsRect() != QRect( 0, 0, width(), height());
496 //****************************************
498 //****************************************
500 EffectWindowGroup::~EffectWindowGroup()
504 //****************************************
505 // GlobalShortcutsEditor
506 //****************************************
508 GlobalShortcutsEditor::GlobalShortcutsEditor( QWidget
*parent
) :
509 KShortcutsEditor( parent
, GlobalAction
)
513 /***************************************************************
515 ***************************************************************/
517 WindowQuad
WindowQuad::makeSubQuad( double x1
, double y1
, double x2
, double y2
) const
519 assert( x1
< x2
&& y1
< y2
&& x1
>= left() && x2
<= right() && y1
>= top() && y2
<= bottom());
522 kFatal( 1212 ) << "Splitting quads is allowed only in pre-paint calls!" ;
524 WindowQuad
ret( *this );
525 // vertices are clockwise starting from topleft
526 ret
.verts
[ 0 ].px
= x1
;
527 ret
.verts
[ 3 ].px
= x1
;
528 ret
.verts
[ 1 ].px
= x2
;
529 ret
.verts
[ 2 ].px
= x2
;
530 ret
.verts
[ 0 ].py
= y1
;
531 ret
.verts
[ 1 ].py
= y1
;
532 ret
.verts
[ 2 ].py
= y2
;
533 ret
.verts
[ 3 ].py
= y2
;
534 // original x/y are supposed to be the same, no transforming is done here
535 ret
.verts
[ 0 ].ox
= x1
;
536 ret
.verts
[ 3 ].ox
= x1
;
537 ret
.verts
[ 1 ].ox
= x2
;
538 ret
.verts
[ 2 ].ox
= x2
;
539 ret
.verts
[ 0 ].oy
= y1
;
540 ret
.verts
[ 1 ].oy
= y1
;
541 ret
.verts
[ 2 ].oy
= y2
;
542 ret
.verts
[ 3 ].oy
= y2
;
543 double my_tleft
= verts
[ 0 ].tx
;
544 double my_tright
= verts
[ 2 ].tx
;
545 double my_ttop
= verts
[ 0 ].ty
;
546 double my_tbottom
= verts
[ 2 ].ty
;
547 double tleft
= ( x1
- left()) / ( right() - left()) * ( my_tright
- my_tleft
) + my_tleft
;
548 double tright
= ( x2
- left()) / ( right() - left()) * ( my_tright
- my_tleft
) + my_tleft
;
549 double ttop
= ( y1
- top()) / ( bottom() - top()) * ( my_tbottom
- my_ttop
) + my_ttop
;
550 double tbottom
= ( y2
- top()) / ( bottom() - top()) * ( my_tbottom
- my_ttop
) + my_ttop
;
551 ret
.verts
[ 0 ].tx
= tleft
;
552 ret
.verts
[ 3 ].tx
= tleft
;
553 ret
.verts
[ 1 ].tx
= tright
;
554 ret
.verts
[ 2 ].tx
= tright
;
555 ret
.verts
[ 0 ].ty
= ttop
;
556 ret
.verts
[ 1 ].ty
= ttop
;
557 ret
.verts
[ 2 ].ty
= tbottom
;
558 ret
.verts
[ 3 ].ty
= tbottom
;
562 bool WindowQuad::smoothNeeded() const
564 // smoothing is needed if the width or height of the quad does not match the original size
565 double width
= verts
[ 1 ].ox
- verts
[ 0 ].ox
;
566 double height
= verts
[ 2 ].oy
- verts
[ 1 ].oy
;
567 return( verts
[ 1 ].px
- verts
[ 0 ].px
!= width
|| verts
[ 2 ].px
- verts
[ 3 ].px
!= width
568 || verts
[ 2 ].py
- verts
[ 1 ].py
!= height
|| verts
[ 3 ].py
- verts
[ 0 ].py
!= height
);
571 /***************************************************************
573 ***************************************************************/
575 WindowQuadList
WindowQuadList::splitAtX( double x
) const
578 foreach( const WindowQuad
&quad
, *this )
581 if( quad
.isTransformed())
582 kFatal( 1212 ) << "Splitting quads is allowed only in pre-paint calls!" ;
584 bool wholeleft
= true;
585 bool wholeright
= true;
590 if( quad
[ i
].x() < x
)
592 if( quad
[ i
].x() > x
)
595 if( wholeleft
|| wholeright
) // is whole in one split part
600 if( quad
.left() == quad
.right() ) // quad has no size
605 ret
.append( quad
.makeSubQuad( quad
.left(), quad
.top(), x
, quad
.bottom()));
606 ret
.append( quad
.makeSubQuad( x
, quad
.top(), quad
.right(), quad
.bottom()));
611 WindowQuadList
WindowQuadList::splitAtY( double y
) const
614 foreach( const WindowQuad
&quad
, *this )
617 if( quad
.isTransformed())
618 kFatal( 1212 ) << "Splitting quads is allowed only in pre-paint calls!" ;
620 bool wholetop
= true;
621 bool wholebottom
= true;
626 if( quad
[ i
].y() < y
)
628 if( quad
[ i
].y() > y
)
631 if( wholetop
|| wholebottom
) // is whole in one split part
636 if( quad
.top() == quad
.bottom() ) // quad has no size
641 ret
.append( quad
.makeSubQuad( quad
.left(), quad
.top(), quad
.right(), y
));
642 ret
.append( quad
.makeSubQuad( quad
.left(), y
, quad
.right(), quad
.bottom()));
647 WindowQuadList
WindowQuadList::makeGrid( int maxquadsize
) const
651 // find the bounding rectangle
652 double left
= first().left();
653 double right
= first().right();
654 double top
= first().top();
655 double bottom
= first().bottom();
656 foreach( const WindowQuad
&quad
, *this )
659 if( quad
.isTransformed())
660 kFatal( 1212 ) << "Splitting quads is allowed only in pre-paint calls!" ;
662 left
= qMin( left
, quad
.left());
663 right
= qMax( right
, quad
.right());
664 top
= qMin( top
, quad
.top());
665 bottom
= qMax( bottom
, quad
.bottom());
668 for( double x
= left
;
676 foreach( const WindowQuad
&quad
, *this )
678 if( QRectF( QPointF( quad
.left(), quad
.top()), QPointF( quad
.right(), quad
.bottom()))
679 .intersects( QRectF( x
, y
, maxquadsize
, maxquadsize
)))
681 ret
.append( quad
.makeSubQuad( qMax( x
, quad
.left()), qMax( y
, quad
.top()),
682 qMin( quad
.right(), x
+ maxquadsize
), qMin( quad
.bottom(), y
+ maxquadsize
)));
690 WindowQuadList
WindowQuadList::makeRegularGrid( int xSubdivisions
, int ySubdivisions
) const
694 // find the bounding rectangle
695 double left
= first().left();
696 double right
= first().right();
697 double top
= first().top();
698 double bottom
= first().bottom();
699 foreach( const WindowQuad
&quad
, *this )
702 if( quad
.isTransformed())
703 kFatal( 1212 ) << "Splitting quads is allowed only in pre-paint calls!" ;
705 left
= qMin( left
, quad
.left());
706 right
= qMax( right
, quad
.right());
707 top
= qMin( top
, quad
.top());
708 bottom
= qMax( bottom
, quad
.bottom());
711 double xincrement
= (right
- left
) / xSubdivisions
;
712 double yincrement
= (bottom
- top
) / ySubdivisions
;
718 for( double x
= left
;
722 foreach( const WindowQuad
&quad
, *this )
724 if( QRectF( QPointF( quad
.left(), quad
.top()), QPointF( quad
.right(), quad
.bottom()))
725 .intersects( QRectF( x
, y
, xincrement
, yincrement
)))
727 ret
.append( quad
.makeSubQuad( qMax( x
, quad
.left()), qMax( y
, quad
.top()),
728 qMin( quad
.right(), x
+ xincrement
), qMin( quad
.bottom(), y
+ yincrement
)));
736 void WindowQuadList::makeArrays( float** vertices
, float** texcoords
) const
738 *vertices
= new float[ count() * 4 * 2 ];
739 *texcoords
= new float[ count() * 4 * 2 ];
740 float* vpos
= *vertices
;
741 float* tpos
= *texcoords
;
749 *vpos
++ = at( i
)[ j
].x();
750 *vpos
++ = at( i
)[ j
].y();
751 *tpos
++ = at( i
)[ j
].tx
;
752 *tpos
++ = at( i
)[ j
].ty
;
756 WindowQuadList
WindowQuadList::select( WindowQuadType type
) const
758 foreach( const WindowQuad
&q
, *this )
760 if( q
.type() != type
) // something else than ones to select, make a copy and filter
763 foreach( const WindowQuad
&q
, *this )
765 if( q
.type() == type
)
771 return *this; // nothing to filter out
774 WindowQuadList
WindowQuadList::filterOut( WindowQuadType type
) const
776 foreach( const WindowQuad
&q
, *this )
778 if( q
.type() == type
) // something to filter out, make a copy and filter
781 foreach( const WindowQuad
&q
, *this )
783 if( q
.type() != type
)
789 return *this; // nothing to filter out
792 bool WindowQuadList::smoothNeeded() const
794 foreach( const WindowQuad
&q
, *this )
795 if( q
.smoothNeeded())
800 bool WindowQuadList::isTransformed() const
802 foreach( const WindowQuad
&q
, *this )
803 if( q
.isTransformed())
808 /***************************************************************
810 ***************************************************************/
812 QStack
< QRegion
>* PaintClipper::areas
= NULL
;
814 PaintClipper::PaintClipper( const QRegion
& allowed_area
)
815 : area( allowed_area
)
820 PaintClipper::~PaintClipper()
825 void PaintClipper::push( const QRegion
& allowed_area
)
827 if( allowed_area
== infiniteRegion()) // don't push these
830 areas
= new QStack
< QRegion
>;
831 areas
->push( allowed_area
);
834 void PaintClipper::pop( const QRegion
& allowed_area
)
836 if( allowed_area
== infiniteRegion())
838 Q_ASSERT( areas
!= NULL
);
839 Q_ASSERT( areas
->top() == allowed_area
);
841 if( areas
->isEmpty())
848 bool PaintClipper::clip()
850 return areas
!= NULL
;
853 QRegion
PaintClipper::paintArea()
855 assert( areas
!= NULL
); // can be called only with clip() == true
856 QRegion ret
= QRegion( 0, 0, displayWidth(), displayHeight());
857 foreach( const QRegion
&r
, *areas
)
862 struct PaintClipper::Iterator::Data
864 Data() : index( 0 ) {}
866 #ifdef KWIN_HAVE_OPENGL_COMPOSITING
867 QVector
< QRect
> rects
;
871 PaintClipper::Iterator::Iterator()
874 #ifdef KWIN_HAVE_OPENGL_COMPOSITING
875 if( clip() && effects
->compositingType() == OpenGLCompositing
)
877 glPushAttrib( GL_SCISSOR_BIT
);
878 glEnable( GL_SCISSOR_TEST
);
879 data
->rects
= paintArea().rects();
881 next(); // move to the first one
884 #ifdef KWIN_HAVE_XRENDER_COMPOSITING
885 if( clip() && effects
->compositingType() == XRenderCompositing
)
887 XserverRegion region
= toXserverRegion( paintArea());
888 XFixesSetPictureClipRegion( display(), effects
->xrenderBufferPicture(), 0, 0, region
);
889 XFixesDestroyRegion( display(), region
); // it's ref-counted
894 PaintClipper::Iterator::~Iterator()
896 #ifdef KWIN_HAVE_OPENGL_COMPOSITING
897 if( clip() && effects
->compositingType() == OpenGLCompositing
)
900 #ifdef KWIN_HAVE_XRENDER_COMPOSITING
901 if( clip() && effects
->compositingType() == XRenderCompositing
)
902 XFixesSetPictureClipRegion( display(), effects
->xrenderBufferPicture(), 0, 0, None
);
907 bool PaintClipper::Iterator::isDone()
910 return data
->index
== 1; // run once
911 #ifdef KWIN_HAVE_OPENGL_COMPOSITING
912 if( effects
->compositingType() == OpenGLCompositing
)
913 return data
->index
>= data
->rects
.count(); // run once per each area
915 #ifdef KWIN_HAVE_XRENDER_COMPOSITING
916 if( effects
->compositingType() == XRenderCompositing
)
917 return data
->index
== 1; // run once
922 void PaintClipper::Iterator::next()
925 #ifdef KWIN_HAVE_OPENGL_COMPOSITING
926 if( clip() && effects
->compositingType() == OpenGLCompositing
&& data
->index
< data
->rects
.count())
928 const QRect
& r
= data
->rects
[ data
->index
];
929 // Scissor rect has to be given in OpenGL coords
930 glScissor( r
.x(), displayHeight() - r
.y() - r
.height(), r
.width(), r
.height());
935 QRect
PaintClipper::Iterator::boundingRect() const
938 return infiniteRegion();
939 #ifdef KWIN_HAVE_OPENGL_COMPOSITING
940 if( effects
->compositingType() == OpenGLCompositing
)
941 return data
->rects
[ data
->index
];
943 #ifdef KWIN_HAVE_XRENDER_COMPOSITING
944 if( effects
->compositingType() == XRenderCompositing
)
945 return paintArea().boundingRect();
948 return infiniteRegion();
952 /***************************************************************
954 ***************************************************************/
956 TimeLine::TimeLine(const int duration
)
959 m_Duration
= duration
;
960 m_TimeLine
= new QTimeLine(m_Duration
? m_Duration
: 1); // (avoid QTimeLine warning)
961 m_TimeLine
->setFrameRange(0, m_Duration
);
962 m_TimeLine
->setCurveShape(QTimeLine::EaseInCurve
);
965 TimeLine::TimeLine(const TimeLine
&other
)
967 m_Time
= other
.m_Time
;
968 m_Duration
= other
.m_Duration
;
969 m_TimeLine
= new QTimeLine(m_Duration
? m_Duration
: 1);
970 m_TimeLine
->setFrameRange(0, m_Duration
);
971 setCurveShape(m_CurveShape
);
972 if( m_Duration
!= 0 )
973 setProgress(m_Progress
);
976 TimeLine::~TimeLine()
981 int TimeLine::duration() const
986 void TimeLine::setDuration(const int msec
)
989 m_TimeLine
->setDuration(m_Duration
);
990 m_TimeLine
->setFrameRange(0, m_Duration
);
993 double TimeLine::value() const
995 Q_ASSERT( m_Duration
!= 0 );
996 return valueForTime(m_Time
);
999 double TimeLine::valueForTime(const int msec
) const
1001 Q_ASSERT( m_Duration
!= 0 );
1002 // Catch non QTimeLine CurveShapes here, (but there are none right now)
1005 // else use QTimeLine ...
1006 return m_TimeLine
->valueForTime(msec
);
1009 void TimeLine::addTime(const int msec
)
1011 Q_ASSERT( m_Duration
!= 0 );
1012 m_Time
= qMin(m_Duration
, m_Time
+ msec
);
1013 m_Progress
= (double)m_Time
/ m_Duration
;
1016 void TimeLine::removeTime(const int msec
)
1018 Q_ASSERT( m_Duration
!= 0 );
1019 m_Time
= qMax(0, m_Time
- msec
);
1020 m_Progress
= (double)m_Time
/ m_Duration
;
1023 void TimeLine::setProgress(const double progress
)
1025 Q_ASSERT( m_Duration
!= 0 );
1026 m_Progress
= progress
;
1027 m_Time
= qRound(m_Duration
* progress
);
1030 double TimeLine::progress() const
1032 Q_ASSERT( m_Duration
!= 0 );
1036 int TimeLine::time() const
1038 Q_ASSERT( m_Duration
!= 0 );
1042 void TimeLine::addProgress(const double progress
)
1044 Q_ASSERT( m_Duration
!= 0 );
1045 m_Progress
+= progress
;
1046 m_Time
= (int)(m_Duration
* m_Progress
);
1049 void TimeLine::setCurveShape(CurveShape curveShape
)
1054 m_TimeLine
->setCurveShape(QTimeLine::EaseInCurve
);
1057 m_TimeLine
->setCurveShape(QTimeLine::EaseOutCurve
);
1059 case EaseInOutCurve
:
1060 m_TimeLine
->setCurveShape(QTimeLine::EaseInOutCurve
);
1063 m_TimeLine
->setCurveShape(QTimeLine::LinearCurve
);
1066 m_TimeLine
->setCurveShape(QTimeLine::SineCurve
);
1069 m_CurveShape
= curveShape
;
1072 /***************************************************************
1074 ***************************************************************/
1076 WindowMotionManager::WindowMotionManager( bool useGlobalAnimationModifier
)
1077 : m_useGlobalAnimationModifier( useGlobalAnimationModifier
)
1078 , m_movingWindows( 0 )
1079 { // TODO: Allow developer to modify motion attributes
1080 } // TODO: What happens when the window moves by an external force?
1082 WindowMotionManager::~WindowMotionManager()
1086 void WindowMotionManager::manage( EffectWindow
*w
)
1088 if( m_managedWindows
.contains( w
))
1091 double strength
= 0.9;
1092 double decay
= 0.75;
1093 if( m_useGlobalAnimationModifier
)
1095 if( effects
->animationTimeFactor() ) // If == 0 we just skip the calculation
1096 strength
= 0.9 / effects
->animationTimeFactor();
1097 decay
= effects
->animationTimeFactor() / ( effects
->animationTimeFactor() + 0.3333333 );
1100 m_managedWindows
[ w
] = WindowMotion();
1101 m_managedWindows
[ w
].translation
.setStrengthDecay( strength
, decay
);
1102 m_managedWindows
[ w
].scale
.setStrengthDecay( strength
, decay
/ 2.0 );
1104 m_managedWindows
[ w
].translation
.setValue( w
->pos() );
1105 m_managedWindows
[ w
].scale
.setValue( QPointF( 1.0, 1.0 ));
1108 void WindowMotionManager::unmanage( EffectWindow
*w
)
1110 if( !m_managedWindows
.contains( w
))
1113 QPointF diffT
= m_managedWindows
[ w
].translation
.distance();
1114 QPointF diffS
= m_managedWindows
[ w
].scale
.distance();
1115 if( diffT
.x() != 0.0 || diffT
.y() != 0.0 || diffS
.x() != 0.0 || diffS
.y() != 0.0 )
1116 m_movingWindows
--; // Window was moving
1118 m_managedWindows
.remove( w
);
1121 void WindowMotionManager::unmanageAll()
1123 m_managedWindows
.clear();
1124 m_movingWindows
= 0;
1127 void WindowMotionManager::calculate( int time
)
1129 if( !effects
->animationTimeFactor() )
1130 { // Just skip it completely if the user wants no animation
1131 m_movingWindows
= 0;
1132 QHash
<EffectWindow
*, WindowMotion
>::iterator it
= m_managedWindows
.begin();
1133 for(; it
!= m_managedWindows
.end(); it
++ )
1135 WindowMotion
*motion
= &it
.value();
1136 motion
->translation
.finish();
1137 motion
->scale
.finish();
1141 QHash
<EffectWindow
*, WindowMotion
>::iterator it
= m_managedWindows
.begin();
1142 for(; it
!= m_managedWindows
.end(); it
++ )
1144 WindowMotion
*motion
= &it
.value();
1145 bool stopped
= false;
1147 // TODO: What happens when distance() == 0 but we are still moving fast?
1148 // TODO: Motion needs to be calculated from the window's center
1150 QPointF diffT
= motion
->translation
.distance();
1151 if( diffT
!= QPoint( 0.0, 0.0 ))
1153 motion
->translation
.calculate( time
);
1154 diffT
= motion
->translation
.distance();
1155 if( qAbs( diffT
.x() ) < 0.5 && qAbs( motion
->translation
.velocity().x() ) < 0.2 &&
1156 qAbs( diffT
.y() ) < 0.5 && qAbs( motion
->translation
.velocity().y() ) < 0.2 )
1157 { // Hide tiny oscillations
1158 motion
->translation
.finish();
1159 diffT
= QPoint( 0.0, 0.0 );
1164 QPointF diffS
= motion
->scale
.distance();
1165 if( diffS
!= QPoint( 0.0, 0.0 ))
1167 motion
->scale
.calculate( time
);
1168 diffS
= motion
->scale
.distance();
1169 if( qAbs( diffS
.x() ) < 0.002 && qAbs( motion
->scale
.velocity().x() ) < 0.05 &&
1170 qAbs( diffS
.y() ) < 0.002 && qAbs( motion
->scale
.velocity().y() ) < 0.05 )
1171 { // Hide tiny oscillations
1172 motion
->scale
.finish();
1173 diffS
= QPoint( 0.0, 0.0 );
1178 // We just finished this window's motion
1179 if( stopped
&& diffT
== QPoint( 0.0, 0.0 ) && diffS
== QPoint( 0.0, 0.0 ))
1184 void WindowMotionManager::reset()
1186 if( !m_managedWindows
.count() )
1189 EffectWindowList windows
= m_managedWindows
.keys();
1191 for( int i
= 0; i
< windows
.size(); i
++ )
1193 EffectWindow
*w
= windows
.at( i
);
1194 m_managedWindows
[ w
].translation
.setTarget( w
->pos() );
1195 m_managedWindows
[ w
].translation
.finish();
1196 m_managedWindows
[ w
].scale
.setTarget( QPointF( 1.0, 1.0 ));
1197 m_managedWindows
[ w
].scale
.finish();
1201 void WindowMotionManager::reset( EffectWindow
*w
)
1203 if( !m_managedWindows
.contains( w
))
1206 m_managedWindows
[ w
].translation
.setTarget( w
->pos() );
1207 m_managedWindows
[ w
].translation
.finish();
1208 m_managedWindows
[ w
].scale
.setTarget( QPointF( 1.0, 1.0 ));
1209 m_managedWindows
[ w
].scale
.finish();
1212 void WindowMotionManager::apply( EffectWindow
*w
, WindowPaintData
&data
)
1214 if( !m_managedWindows
.contains( w
))
1217 // TODO: Take into account existing scale so that we can work with multiple managers (E.g. Present windows + grid)
1218 data
.xTranslate
+= m_managedWindows
[ w
].translation
.value().x() - w
->x();
1219 data
.yTranslate
+= m_managedWindows
[ w
].translation
.value().y() - w
->y();
1220 data
.xScale
*= m_managedWindows
[ w
].scale
.value().x();
1221 data
.yScale
*= m_managedWindows
[ w
].scale
.value().y();
1224 void WindowMotionManager::moveWindow( EffectWindow
*w
, QPoint target
, double scale
, double yScale
)
1226 if( !m_managedWindows
.contains( w
))
1227 abort(); // Notify the effect author that they did something wrong
1231 QPointF
scalePoint( scale
, yScale
);
1233 if( m_managedWindows
[ w
].translation
.value() == target
&&
1234 m_managedWindows
[ w
].scale
.value() == scalePoint
)
1235 return; // Window already at that position
1237 m_managedWindows
[ w
].translation
.setTarget( target
);
1238 m_managedWindows
[ w
].scale
.setTarget( scalePoint
);
1240 if( m_managedWindows
[ w
].translation
.velocity() == QPointF( 0.0, 0.0 ) &&
1241 m_managedWindows
[ w
].scale
.velocity() == QPointF( 0.0, 0.0 ))
1245 QRectF
WindowMotionManager::transformedGeometry( EffectWindow
*w
) const
1247 QRectF
geometry( w
->geometry() );
1249 // TODO: Take into account existing scale so that we can work with multiple managers (E.g. Present windows + grid)
1250 geometry
.moveTo( m_managedWindows
[ w
].translation
.value() );
1251 geometry
.setWidth( geometry
.width() * m_managedWindows
[ w
].scale
.value().x() );
1252 geometry
.setHeight( geometry
.height() * m_managedWindows
[ w
].scale
.value().y() );
1257 EffectWindow
* WindowMotionManager::windowAtPoint( QPoint point
, bool useStackingOrder
) const
1259 // TODO: Stacking order uses EffectsHandler::stackingOrder() then filters by m_managedWindows
1260 EffectWindowList windows
= m_managedWindows
.keys();
1262 for( int i
= 0; i
< windows
.size(); i
++ )
1263 if( transformedGeometry( windows
.at( i
)).contains( point
))
1264 return windows
.at( i
);