not quite so much needs to be delayed to the init() function
[personal-kdebase.git] / workspace / kwin / effects.cpp
blobd45bf41333a08274f853c3da2a094078e0582a83
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 "effects.h"
23 #include "deleted.h"
24 #include "client.h"
25 #include "group.h"
26 #include "scene_xrender.h"
27 #include "scene_opengl.h"
28 #include "unmanaged.h"
29 #include "workspace.h"
30 #include "kwinglutils.h"
32 #include <QFile>
34 #include "kdebug.h"
35 #include "klibloader.h"
36 #include "kdesktopfile.h"
37 #include "kconfiggroup.h"
38 #include "kstandarddirs.h"
39 #include <kservice.h>
40 #include <kservicetypetrader.h>
41 #include <kplugininfo.h>
43 #include <assert.h>
46 namespace KWin
50 EffectsHandlerImpl::EffectsHandlerImpl(CompositingType type)
51 : EffectsHandler(type)
52 , keyboard_grab_effect( NULL )
53 , fullscreen_effect( 0 )
54 , next_window_quad_type( EFFECT_QUAD_TYPE_START )
56 reconfigure();
59 EffectsHandlerImpl::~EffectsHandlerImpl()
61 if( keyboard_grab_effect != NULL )
62 ungrabKeyboard();
63 foreach( const EffectPair &ep, loaded_effects )
64 unloadEffect( ep.first );
65 foreach( const InputWindowPair &pos, input_windows )
66 XDestroyWindow( display(), pos.second );
69 void EffectsHandlerImpl::reconfigure()
71 KSharedConfig::Ptr _config = KGlobal::config();
72 KConfigGroup conf(_config, "Plugins");
74 KService::List offers = KServiceTypeTrader::self()->query("KWin/Effect");
75 QStringList effectsToBeLoaded;
76 // First unload necessary effects
77 foreach( const KService::Ptr &service, offers )
79 KPluginInfo plugininfo( service );
80 plugininfo.load( conf );
82 bool isloaded = isEffectLoaded( plugininfo.pluginName() );
83 bool shouldbeloaded = plugininfo.isPluginEnabled();
84 if( !shouldbeloaded && isloaded )
85 unloadEffect( plugininfo.pluginName() );
86 if( shouldbeloaded )
87 effectsToBeLoaded.append( plugininfo.pluginName() );
89 QStringList newLoaded;
90 // Then load those that should be loaded
91 foreach( const QString &effectName, effectsToBeLoaded )
93 if( !isEffectLoaded( effectName ))
95 loadEffect( effectName );
96 newLoaded.append( effectName );
99 foreach( const EffectPair &ep, loaded_effects )
101 if( !newLoaded.contains( ep.first )) // don't reconfigure newly loaded effects
102 ep.second->reconfigure( Effect::ReconfigureAll );
106 // the idea is that effects call this function again which calls the next one
107 void EffectsHandlerImpl::prePaintScreen( ScreenPrePaintData& data, int time )
109 if( current_paint_screen < loaded_effects.size())
111 loaded_effects[current_paint_screen++].second->prePaintScreen( data, time );
112 --current_paint_screen;
114 // no special final code
117 void EffectsHandlerImpl::paintScreen( int mask, QRegion region, ScreenPaintData& data )
119 if( current_paint_screen < loaded_effects.size())
121 loaded_effects[current_paint_screen++].second->paintScreen( mask, region, data );
122 --current_paint_screen;
124 else
125 scene->finalPaintScreen( mask, region, data );
128 void EffectsHandlerImpl::postPaintScreen()
130 if( current_paint_screen < loaded_effects.size())
132 loaded_effects[current_paint_screen++].second->postPaintScreen();
133 --current_paint_screen;
135 // no special final code
138 void EffectsHandlerImpl::prePaintWindow( EffectWindow* w, WindowPrePaintData& data, int time )
140 if( current_paint_window < loaded_effects.size())
142 loaded_effects[current_paint_window++].second->prePaintWindow( w, data, time );
143 --current_paint_window;
145 // no special final code
148 void EffectsHandlerImpl::paintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data )
150 if( current_paint_window < loaded_effects.size())
152 loaded_effects[current_paint_window++].second->paintWindow( w, mask, region, data );
153 --current_paint_window;
155 else
156 scene->finalPaintWindow( static_cast<EffectWindowImpl*>( w ), mask, region, data );
159 void EffectsHandlerImpl::postPaintWindow( EffectWindow* w )
161 if( current_paint_window < loaded_effects.size())
163 loaded_effects[current_paint_window++].second->postPaintWindow( w );
164 --current_paint_window;
166 // no special final code
169 void EffectsHandlerImpl::drawWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data )
171 if( current_draw_window < loaded_effects.size())
173 loaded_effects[current_draw_window++].second->drawWindow( w, mask, region, data );
174 --current_draw_window;
176 else
177 scene->finalDrawWindow( static_cast<EffectWindowImpl*>( w ), mask, region, data );
180 void EffectsHandlerImpl::buildQuads( EffectWindow* w, WindowQuadList& quadList )
182 if( current_build_quads < loaded_effects.size())
184 loaded_effects[current_build_quads++].second->buildQuads( w, quadList );
185 --current_build_quads;
189 bool EffectsHandlerImpl::hasDecorationShadows() const
191 return Workspace::self()->hasDecorationShadows();
194 QList< QList<QImage> > EffectsHandlerImpl::shadowTextures()
196 return Workspace::self()->decorationShadowTextures();
199 int EffectsHandlerImpl::shadowTextureList( ShadowType type ) const
201 return Workspace::self()->decorationShadowTextureList( type );
204 // start another painting pass
205 void EffectsHandlerImpl::startPaint()
207 assert( current_paint_screen == 0 );
208 assert( current_paint_window == 0 );
209 assert( current_draw_window == 0 );
210 assert( current_build_quads == 0 );
211 assert( current_transform == 0 );
214 void EffectsHandlerImpl::windowUserMovedResized( EffectWindow* c, bool first, bool last )
216 foreach( const EffectPair &ep, loaded_effects )
217 ep.second->windowUserMovedResized( c, first, last );
220 void EffectsHandlerImpl::windowOpacityChanged( EffectWindow* c, double old_opacity )
222 if( static_cast<EffectWindowImpl*>(c)->window()->opacity() == old_opacity )
223 return;
224 foreach( const EffectPair &ep, loaded_effects )
225 ep.second->windowOpacityChanged( c, old_opacity );
228 void EffectsHandlerImpl::windowAdded( EffectWindow* c )
230 foreach( const EffectPair &ep, loaded_effects )
231 ep.second->windowAdded( c );
234 void EffectsHandlerImpl::windowDeleted( EffectWindow* c )
236 foreach( const EffectPair &ep, loaded_effects )
237 ep.second->windowDeleted( c );
238 elevated_windows.removeAll( c );
241 void EffectsHandlerImpl::windowClosed( EffectWindow* c )
243 foreach( const EffectPair &ep, loaded_effects )
244 ep.second->windowClosed( c );
247 void EffectsHandlerImpl::windowActivated( EffectWindow* c )
249 foreach( const EffectPair &ep, loaded_effects )
250 ep.second->windowActivated( c );
253 void EffectsHandlerImpl::windowMinimized( EffectWindow* c )
255 foreach( const EffectPair &ep, loaded_effects )
256 ep.second->windowMinimized( c );
259 void EffectsHandlerImpl::windowUnminimized( EffectWindow* c )
261 foreach( const EffectPair &ep, loaded_effects )
262 ep.second->windowUnminimized( c );
265 void EffectsHandlerImpl::desktopChanged( int old )
267 foreach( const EffectPair &ep, loaded_effects )
268 ep.second->desktopChanged( old );
271 void EffectsHandlerImpl::windowDamaged( EffectWindow* w, const QRect& r )
273 if( w == NULL )
274 return;
275 foreach( const EffectPair &ep, loaded_effects )
276 ep.second->windowDamaged( w, r );
279 void EffectsHandlerImpl::windowGeometryShapeChanged( EffectWindow* w, const QRect& old )
281 if( w == NULL ) // during late cleanup effectWindow() may be already NULL
282 return; // in some functions that may still call this
283 foreach( const EffectPair &ep, loaded_effects )
284 ep.second->windowGeometryShapeChanged( w, old );
287 void EffectsHandlerImpl::tabBoxAdded( int mode )
289 foreach( const EffectPair &ep, loaded_effects )
290 ep.second->tabBoxAdded( mode );
293 void EffectsHandlerImpl::tabBoxClosed()
295 foreach( const EffectPair &ep, loaded_effects )
296 ep.second->tabBoxClosed();
299 void EffectsHandlerImpl::tabBoxUpdated()
301 foreach( const EffectPair &ep, loaded_effects )
302 ep.second->tabBoxUpdated();
305 void EffectsHandlerImpl::setActiveFullScreenEffect( Effect* e )
307 fullscreen_effect = e;
308 Workspace::self()->checkUnredirect();
311 Effect* EffectsHandlerImpl::activeFullScreenEffect() const
313 return fullscreen_effect;
316 bool EffectsHandlerImpl::borderActivated( ElectricBorder border )
318 bool ret = false;
319 foreach( const EffectPair &ep, loaded_effects )
320 if( ep.second->borderActivated( border ))
321 ret = true; // bail out or tell all?
322 return ret;
325 void EffectsHandlerImpl::mouseChanged( const QPoint& pos, const QPoint& oldpos,
326 Qt::MouseButtons buttons, Qt::MouseButtons oldbuttons,
327 Qt::KeyboardModifiers modifiers, Qt::KeyboardModifiers oldmodifiers )
329 foreach( const EffectPair &ep, loaded_effects )
330 ep.second->mouseChanged( pos, oldpos, buttons, oldbuttons, modifiers, oldmodifiers );
333 bool EffectsHandlerImpl::grabKeyboard( Effect* effect )
335 if( keyboard_grab_effect != NULL )
336 return false;
337 bool ret = grabXKeyboard();
338 if( !ret )
339 return false;
340 keyboard_grab_effect = effect;
341 return true;
344 void EffectsHandlerImpl::ungrabKeyboard()
346 assert( keyboard_grab_effect != NULL );
347 ungrabXKeyboard();
348 keyboard_grab_effect = NULL;
351 void EffectsHandlerImpl::grabbedKeyboardEvent( QKeyEvent* e )
353 if( keyboard_grab_effect != NULL )
354 keyboard_grab_effect->grabbedKeyboardEvent( e );
357 bool EffectsHandlerImpl::hasKeyboardGrab() const
359 return keyboard_grab_effect != NULL;
362 void EffectsHandlerImpl::propertyNotify( EffectWindow* c, long atom )
364 if( !registered_atoms.contains( atom ))
365 return;
366 foreach( const EffectPair &ep, loaded_effects )
367 ep.second->propertyNotify( c, atom );
370 void EffectsHandlerImpl::registerPropertyType( long atom, bool reg )
372 if( reg )
373 ++registered_atoms[ atom ]; // initialized to 0 if not present yet
374 else
376 if( --registered_atoms[ atom ] == 0 )
377 registered_atoms.remove( atom );
381 void EffectsHandlerImpl::activateWindow( EffectWindow* c )
383 if( Client* cl = dynamic_cast< Client* >( static_cast<EffectWindowImpl*>(c)->window()))
384 Workspace::self()->activateClient( cl, true );
387 EffectWindow* EffectsHandlerImpl::activeWindow() const
389 return Workspace::self()->activeClient() ? Workspace::self()->activeClient()->effectWindow() : NULL;
392 void EffectsHandlerImpl::moveWindow( EffectWindow* w, const QPoint& pos )
394 Client* cl = dynamic_cast< Client* >( static_cast<EffectWindowImpl*>(w)->window());
395 if( cl && cl->isMovable())
396 cl->move( pos );
399 void EffectsHandlerImpl::windowToDesktop( EffectWindow* w, int desktop )
401 Client* cl = dynamic_cast< Client* >( static_cast<EffectWindowImpl*>(w)->window());
402 if( cl && !cl->isDesktop() && !cl->isDock() && !cl->isTopMenu())
403 Workspace::self()->sendClientToDesktop( cl, desktop, true );
406 int EffectsHandlerImpl::currentDesktop() const
408 return Workspace::self()->currentDesktop();
411 int EffectsHandlerImpl::numberOfDesktops() const
413 return Workspace::self()->numberOfDesktops();
416 void EffectsHandlerImpl::setCurrentDesktop( int desktop )
418 Workspace::self()->setCurrentDesktop( desktop );
421 QString EffectsHandlerImpl::desktopName( int desktop ) const
423 return Workspace::self()->desktopName( desktop );
426 void EffectsHandlerImpl::calcDesktopLayout(int* x, int* y, Qt::Orientation* orientation) const
428 Workspace::self()->calcDesktopLayout( x, y, orientation );
431 bool EffectsHandlerImpl::optionRollOverDesktops() const
433 return options->rollOverDesktops;
436 int EffectsHandlerImpl::desktopToLeft( int desktop, bool wrap ) const
438 return Workspace::self()->desktopToLeft( desktop, wrap );
441 int EffectsHandlerImpl::desktopToRight( int desktop, bool wrap ) const
443 return Workspace::self()->desktopToRight( desktop, wrap );
446 int EffectsHandlerImpl::desktopUp( int desktop, bool wrap ) const
448 return Workspace::self()->desktopUp( desktop, wrap );
451 int EffectsHandlerImpl::desktopDown( int desktop, bool wrap ) const
453 return Workspace::self()->desktopDown( desktop, wrap );
456 double EffectsHandlerImpl::animationTimeFactor() const
458 return options->animationTimeFactor();
461 WindowQuadType EffectsHandlerImpl::newWindowQuadType()
463 return WindowQuadType( next_window_quad_type++ );
466 int EffectsHandlerImpl::displayWidth() const
468 return KWin::displayWidth();
471 int EffectsHandlerImpl::displayHeight() const
473 return KWin::displayWidth();
476 EffectWindow* EffectsHandlerImpl::findWindow( WId id ) const
478 if( Client* w = Workspace::self()->findClient( WindowMatchPredicate( id )))
479 return w->effectWindow();
480 if( Unmanaged* w = Workspace::self()->findUnmanaged( WindowMatchPredicate( id )))
481 return w->effectWindow();
482 return NULL;
485 EffectWindowList EffectsHandlerImpl::stackingOrder() const
487 ClientList list = Workspace::self()->stackingOrder();
488 EffectWindowList ret;
489 foreach( Client* c, list )
490 ret.append( effectWindow( c ));
491 return ret;
494 void EffectsHandlerImpl::setElevatedWindow( EffectWindow* w, bool set )
496 elevated_windows.removeAll( w );
497 if( set )
498 elevated_windows.append( w );
501 void EffectsHandlerImpl::setTabBoxWindow(EffectWindow* w)
503 if( Client* c = dynamic_cast< Client* >( static_cast< EffectWindowImpl* >( w )->window()))
504 Workspace::self()->setTabBoxClient( c );
507 void EffectsHandlerImpl::setTabBoxDesktop(int desktop)
509 Workspace::self()->setTabBoxDesktop( desktop );
512 EffectWindowList EffectsHandlerImpl::currentTabBoxWindowList() const
514 EffectWindowList ret;
515 ClientList clients = Workspace::self()->currentTabBoxClientList();
516 foreach( Client* c, clients )
517 ret.append( c->effectWindow());
518 return ret;
521 void EffectsHandlerImpl::refTabBox()
523 Workspace::self()->refTabBox();
526 void EffectsHandlerImpl::unrefTabBox()
528 Workspace::self()->unrefTabBox();
531 void EffectsHandlerImpl::closeTabBox()
533 Workspace::self()->closeTabBox();
536 QList< int > EffectsHandlerImpl::currentTabBoxDesktopList() const
538 return Workspace::self()->currentTabBoxDesktopList();
541 int EffectsHandlerImpl::currentTabBoxDesktop() const
543 return Workspace::self()->currentTabBoxDesktop();
546 EffectWindow* EffectsHandlerImpl::currentTabBoxWindow() const
548 if( Client* c = Workspace::self()->currentTabBoxClient())
549 return c->effectWindow();
550 return NULL;
553 void EffectsHandlerImpl::pushRenderTarget(GLRenderTarget* target)
555 #ifdef KWIN_HAVE_OPENGL_COMPOSITING
556 target->enable();
557 render_targets.push(target);
558 #endif
561 GLRenderTarget* EffectsHandlerImpl::popRenderTarget()
563 #ifdef KWIN_HAVE_OPENGL_COMPOSITING
564 GLRenderTarget* ret = render_targets.pop();
565 ret->disable();
566 if( !render_targets.isEmpty() )
567 render_targets.top()->enable();
568 return ret;
569 #else
570 return 0;
571 #endif
574 void EffectsHandlerImpl::addRepaintFull()
576 Workspace::self()->addRepaintFull();
579 void EffectsHandlerImpl::addRepaint( const QRect& r )
581 Workspace::self()->addRepaint( r );
584 void EffectsHandlerImpl::addRepaint( const QRegion& r )
586 Workspace::self()->addRepaint( r );
589 void EffectsHandlerImpl::addRepaint( int x, int y, int w, int h )
591 Workspace::self()->addRepaint( x, y, w, h );
594 int EffectsHandlerImpl::activeScreen() const
596 return Workspace::self()->activeScreen();
599 int EffectsHandlerImpl::numScreens() const
601 return Workspace::self()->numScreens();
604 int EffectsHandlerImpl::screenNumber( const QPoint& pos ) const
606 return Workspace::self()->screenNumber( pos );
609 QRect EffectsHandlerImpl::clientArea( clientAreaOption opt, int screen, int desktop ) const
611 return Workspace::self()->clientArea( opt, screen, desktop );
614 QRect EffectsHandlerImpl::clientArea( clientAreaOption opt, const EffectWindow* c ) const
616 const Toplevel* t = static_cast< const EffectWindowImpl* >(c)->window();
617 if( const Client* cl = dynamic_cast< const Client* >( t ))
618 return Workspace::self()->clientArea( opt, cl );
619 else
620 return Workspace::self()->clientArea( opt, t->geometry().center(), Workspace::self()->currentDesktop());
623 QRect EffectsHandlerImpl::clientArea( clientAreaOption opt, const QPoint& p, int desktop ) const
625 return Workspace::self()->clientArea( opt, p, desktop );
628 Window EffectsHandlerImpl::createInputWindow( Effect* e, int x, int y, int w, int h, const QCursor& cursor )
630 XSetWindowAttributes attrs;
631 attrs.override_redirect = True;
632 Window win = XCreateWindow( display(), rootWindow(), x, y, w, h, 0, 0, InputOnly, CopyFromParent,
633 CWOverrideRedirect, &attrs );
634 // TODO keeping on top?
635 // TODO enter/leave notify?
636 XSelectInput( display(), win, ButtonPressMask | ButtonReleaseMask | PointerMotionMask );
637 XDefineCursor( display(), win, cursor.handle());
638 XMapWindow( display(), win );
639 input_windows.append( qMakePair( e, win ));
640 return win;
643 void EffectsHandlerImpl::destroyInputWindow( Window w )
645 foreach( const InputWindowPair &pos, input_windows )
647 if( pos.second == w )
649 input_windows.removeAll( pos );
650 XDestroyWindow( display(), w );
651 return;
654 abort();
657 bool EffectsHandlerImpl::checkInputWindowEvent( XEvent* e )
659 if( e->type != ButtonPress && e->type != ButtonRelease && e->type != MotionNotify )
660 return false;
661 foreach( const InputWindowPair &pos, input_windows )
663 if( pos.second == e->xany.window )
665 switch( e->type )
667 case ButtonPress:
669 XButtonEvent* e2 = &e->xbutton;
670 Qt::MouseButton button = x11ToQtMouseButton( e2->button );
671 Qt::MouseButtons buttons = x11ToQtMouseButtons( e2->state ) | button;
672 QMouseEvent ev( QEvent::MouseButtonPress,
673 QPoint( e2->x, e2->y ), QPoint( e2->x_root, e2->y_root ),
674 button, buttons, x11ToQtKeyboardModifiers( e2->state ));
675 pos.first->windowInputMouseEvent( pos.second, &ev );
676 break; // --->
678 case ButtonRelease:
680 XButtonEvent* e2 = &e->xbutton;
681 Qt::MouseButton button = x11ToQtMouseButton( e2->button );
682 Qt::MouseButtons buttons = x11ToQtMouseButtons( e2->state ) & ~button;
683 QMouseEvent ev( QEvent::MouseButtonRelease,
684 QPoint( e2->x, e2->y ), QPoint( e2->x_root, e2->y_root ),
685 button, buttons, x11ToQtKeyboardModifiers( e2->state ));
686 pos.first->windowInputMouseEvent( pos.second, &ev );
687 break; // --->
689 case MotionNotify:
691 XMotionEvent* e2 = &e->xmotion;
692 QMouseEvent ev( QEvent::MouseMove, QPoint( e2->x, e2->y ), QPoint( e2->x_root, e2->y_root ),
693 Qt::NoButton, x11ToQtMouseButtons( e2->state ), x11ToQtKeyboardModifiers( e2->state ));
694 pos.first->windowInputMouseEvent( pos.second, &ev );
695 break; // --->
698 return true; // eat event
701 return false;
704 void EffectsHandlerImpl::checkInputWindowStacking()
706 if( input_windows.count() == 0 )
707 return;
708 Window* wins = new Window[ input_windows.count() ];
709 int pos = 0;
710 foreach( const InputWindowPair &it, input_windows )
711 wins[ pos++ ] = it.second;
712 XRaiseWindow( display(), wins[ 0 ] );
713 XRestackWindows( display(), wins, pos );
714 delete[] wins;
717 QPoint EffectsHandlerImpl::cursorPos() const
719 return Workspace::self()->cursorPos();
722 void EffectsHandlerImpl::checkElectricBorder(const QPoint &pos, Time time)
724 Workspace::self()->checkElectricBorder( pos, time );
727 void EffectsHandlerImpl::reserveElectricBorder( ElectricBorder border )
729 Workspace::self()->reserveElectricBorder( border );
732 void EffectsHandlerImpl::unreserveElectricBorder( ElectricBorder border )
734 Workspace::self()->unreserveElectricBorder( border );
737 void EffectsHandlerImpl::reserveElectricBorderSwitching( bool reserve )
739 Workspace::self()->reserveElectricBorderSwitching( reserve );
742 unsigned long EffectsHandlerImpl::xrenderBufferPicture()
744 #ifdef KWIN_HAVE_XRENDER_COMPOSITING
745 if( SceneXrender* s = dynamic_cast< SceneXrender* >( scene ))
746 return s->bufferPicture();
747 #endif
748 return None;
751 KLibrary* EffectsHandlerImpl::findEffectLibrary( KService* service )
753 QString libname = service->library();
754 KLibrary* library = KLibLoader::self()->library(libname);
755 if( !library )
757 kError( 1212 ) << "couldn't open library for effect '" <<
758 service->name() << "'" << endl;
759 return 0;
762 return library;
765 void EffectsHandlerImpl::toggleEffect( const QString& name )
767 if( isEffectLoaded( name ))
768 unloadEffect( name );
769 else
770 loadEffect( name );
773 QStringList EffectsHandlerImpl::loadedEffects() const
775 QStringList listModules;
776 for(QVector< EffectPair >::const_iterator it = loaded_effects.constBegin(); it != loaded_effects.constEnd(); ++it)
778 listModules <<(*it).first;
780 return listModules;
783 QStringList EffectsHandlerImpl::listOfEffects() const
785 KService::List offers = KServiceTypeTrader::self()->query("KWin/Effect");
786 QStringList listOfModules;
787 // First unload necessary effects
788 foreach( const KService::Ptr &service, offers )
790 KPluginInfo plugininfo( service );
791 listOfModules<<plugininfo.pluginName();
793 return listOfModules;
796 bool EffectsHandlerImpl::loadEffect( const QString& name )
798 Workspace::self()->addRepaintFull();
799 assert( current_paint_screen == 0 );
800 assert( current_paint_window == 0 );
801 assert( current_draw_window == 0 );
802 assert( current_build_quads == 0 );
803 assert( current_transform == 0 );
805 if( !name.startsWith("kwin4_effect_") )
806 kWarning( 1212 ) << "Effect names usually have kwin4_effect_ prefix" ;
808 // Make sure a single effect won't be loaded multiple times
809 for(QVector< EffectPair >::const_iterator it = loaded_effects.constBegin(); it != loaded_effects.constEnd(); ++it)
811 if( (*it).first == name )
813 kDebug( 1212 ) << "EffectsHandler::loadEffect : Effect already loaded : " << name;
814 return true;
819 kDebug( 1212 ) << "Trying to load " << name;
820 QString internalname = name.toLower();
822 QString constraint = QString("[X-KDE-PluginInfo-Name] == '%1'").arg(internalname);
823 KService::List offers = KServiceTypeTrader::self()->query("KWin/Effect", constraint);
824 if(offers.isEmpty())
826 kError( 1212 ) << "Couldn't find effect " << name << endl;
827 return false;
829 KService::Ptr service = offers.first();
831 KLibrary* library = findEffectLibrary( service.data() );
832 if( !library )
834 return false;
837 QString version_symbol = "effect_version_" + name;
838 KLibrary::void_function_ptr version_func = library->resolveFunction(version_symbol.toAscii());
839 if( version_func == NULL )
841 kWarning( 1212 ) << "Effect " << name << " does not provide required API version, ignoring.";
842 return false;
844 typedef int (*t_versionfunc)();
845 int version = reinterpret_cast< t_versionfunc >( version_func )(); // call it
846 // Version must be the same or less, but major must be the same.
847 // With major 0 minor must match exactly.
848 if( version > KWIN_EFFECT_API_VERSION
849 || ( version >> 8 ) != KWIN_EFFECT_API_VERSION_MAJOR
850 || ( KWIN_EFFECT_API_VERSION_MAJOR == 0 && version != KWIN_EFFECT_API_VERSION ))
852 kWarning( 1212 ) << "Effect " << name << " requires unsupported API version " << version;
853 return false;
855 QString supported_symbol = "effect_supported_" + name;
856 KLibrary::void_function_ptr supported_func = library->resolveFunction(supported_symbol.toAscii().data());
857 QString create_symbol = "effect_create_" + name;
858 KLibrary::void_function_ptr create_func = library->resolveFunction(create_symbol.toAscii().data());
859 if( supported_func )
861 typedef bool (*t_supportedfunc)();
862 t_supportedfunc supported = reinterpret_cast<t_supportedfunc>(supported_func);
863 if(!supported())
865 kWarning( 1212 ) << "EffectsHandler::loadEffect : Effect " << name << " is not supported" ;
866 library->unload();
867 return false;
870 if(!create_func)
872 kError( 1212 ) << "EffectsHandler::loadEffect : effect_create function not found" << endl;
873 library->unload();
874 return false;
876 typedef Effect* (*t_createfunc)();
877 t_createfunc create = reinterpret_cast<t_createfunc>(create_func);
879 // Make sure all depenedencies have been loaded
880 // TODO: detect circular deps
881 KPluginInfo plugininfo( service );
882 QStringList dependencies = plugininfo.dependencies();
883 foreach( const QString &depName, dependencies )
885 if( !loadEffect(depName))
887 kError(1212) << "EffectsHandler::loadEffect : Couldn't load dependencies for effect " << name << endl;
888 library->unload();
889 return false;
893 Effect* e = create();
895 effect_order.insert( service->property( "X-KDE-Ordering" ).toInt(), EffectPair( name, e ));
896 effectsChanged();
897 effect_libraries[ name ] = library;
899 return true;
902 void EffectsHandlerImpl::unloadEffect( const QString& name )
904 Workspace::self()->addRepaintFull();
905 assert( current_paint_screen == 0 );
906 assert( current_paint_window == 0 );
907 assert( current_draw_window == 0 );
908 assert( current_build_quads == 0 );
909 assert( current_transform == 0 );
911 for( QMap< int, EffectPair >::iterator it = effect_order.begin(); it != effect_order.end(); ++it)
913 if ( it.value().first == name )
915 kDebug( 1212 ) << "EffectsHandler::unloadEffect : Unloading Effect : " << name;
916 if( activeFullScreenEffect() == it.value().second )
918 setActiveFullScreenEffect( 0 );
920 delete it.value().second;
921 effect_order.erase(it);
922 effectsChanged();
923 effect_libraries[ name ]->unload();
924 return;
928 kDebug( 1212 ) << "EffectsHandler::unloadEffect : Effect not loaded : " << name;
931 void EffectsHandlerImpl::reconfigureEffect( const QString& name )
933 for( QVector< EffectPair >::iterator it = loaded_effects.begin(); it != loaded_effects.end(); ++it)
934 if ( (*it).first == name )
936 (*it).second->reconfigure( Effect::ReconfigureAll );
937 return;
941 bool EffectsHandlerImpl::isEffectLoaded( const QString& name )
943 for( QVector< EffectPair >::iterator it = loaded_effects.begin(); it != loaded_effects.end(); ++it)
944 if ( (*it).first == name )
945 return true;
947 return false;
950 void EffectsHandlerImpl::effectsChanged()
952 loaded_effects.clear();
953 // kDebug(1212) << "Recreating effects' list:";
954 foreach( const EffectPair &effect, effect_order )
956 // kDebug(1212) << effect.first;
957 loaded_effects.append( effect );
962 //****************************************
963 // EffectWindowImpl
964 //****************************************
966 EffectWindowImpl::EffectWindowImpl() : EffectWindow()
967 , toplevel( NULL )
968 , sw( NULL )
972 EffectWindowImpl::~EffectWindowImpl()
976 bool EffectWindowImpl::isPaintingEnabled()
978 return sceneWindow()->isPaintingEnabled();
981 void EffectWindowImpl::enablePainting( int reason )
983 sceneWindow()->enablePainting( reason );
986 void EffectWindowImpl::disablePainting( int reason )
988 sceneWindow()->disablePainting( reason );
991 void EffectWindowImpl::addRepaint( const QRect& r )
993 toplevel->addRepaint( r );
996 void EffectWindowImpl::addRepaint( int x, int y, int w, int h )
998 toplevel->addRepaint( x, y, w, h );
1001 void EffectWindowImpl::addRepaintFull()
1003 toplevel->addRepaintFull();
1006 int EffectWindowImpl::desktop() const
1008 return toplevel->desktop();
1011 bool EffectWindowImpl::isOnAllDesktops() const
1013 return desktop() == NET::OnAllDesktops;
1016 QString EffectWindowImpl::caption() const
1018 if( Client* c = dynamic_cast<Client*>( toplevel ))
1019 return c->caption();
1020 else
1021 return "";
1024 QString EffectWindowImpl::windowClass() const
1026 return toplevel->resourceName() + ' ' + toplevel->resourceClass();
1029 QString EffectWindowImpl::windowRole() const
1031 return toplevel->windowRole();
1034 QPixmap EffectWindowImpl::icon() const
1036 if( Client* c = dynamic_cast<Client*>( toplevel ))
1037 return c->icon();
1038 return QPixmap(); // TODO
1041 const EffectWindowGroup* EffectWindowImpl::group() const
1043 if( Client* c = dynamic_cast< Client* >( toplevel ))
1044 return c->group()->effectGroup();
1045 return NULL; // TODO
1048 bool EffectWindowImpl::isMinimized() const
1050 if( Client* c = dynamic_cast<Client*>( toplevel ))
1051 return c->isMinimized();
1052 else
1053 return false;
1056 double EffectWindowImpl::opacity() const
1058 return toplevel->opacity();
1061 bool EffectWindowImpl::isDeleted() const
1063 return (dynamic_cast<Deleted*>( toplevel ) != 0);
1066 void EffectWindowImpl::refWindow()
1068 if( Deleted* d = dynamic_cast< Deleted* >( toplevel ))
1069 return d->refWindow();
1070 abort(); // TODO
1073 void EffectWindowImpl::unrefWindow()
1075 if( Deleted* d = dynamic_cast< Deleted* >( toplevel ))
1076 return d->unrefWindow( true ); // delayed
1077 abort(); // TODO
1080 void EffectWindowImpl::setWindow( Toplevel* w )
1082 toplevel = w;
1085 void EffectWindowImpl::setSceneWindow( Scene::Window* w )
1087 sw = w;
1090 int EffectWindowImpl::x() const
1092 return toplevel->x();
1095 int EffectWindowImpl::y() const
1097 return toplevel->y();
1100 int EffectWindowImpl::width() const
1102 return toplevel->width();
1105 int EffectWindowImpl::height() const
1107 return toplevel->height();
1110 QRect EffectWindowImpl::geometry() const
1112 return toplevel->geometry();
1115 QRegion EffectWindowImpl::shape() const
1117 return sw ? sw->shape() : geometry();
1120 int EffectWindowImpl::screen() const
1122 return toplevel->screen();
1125 bool EffectWindowImpl::hasOwnShape() const
1127 return toplevel->shape();
1130 QSize EffectWindowImpl::size() const
1132 return toplevel->size();
1135 QPoint EffectWindowImpl::pos() const
1137 return toplevel->pos();
1140 QRect EffectWindowImpl::rect() const
1142 return toplevel->rect();
1145 QRect EffectWindowImpl::contentsRect() const
1147 return QRect( toplevel->clientPos(), toplevel->clientSize());
1150 QByteArray EffectWindowImpl::readProperty( long atom, long type, int format ) const
1152 int len = 32768;
1153 for(;;)
1155 unsigned char* data;
1156 Atom rtype;
1157 int rformat;
1158 unsigned long nitems, after;
1159 if( XGetWindowProperty( QX11Info::display(), window()->window(),
1160 atom, 0, len, False, AnyPropertyType,
1161 &rtype, &rformat, &nitems, &after, &data ) == Success )
1163 if( after > 0 )
1165 XFree( data );
1166 len *= 2;
1167 continue;
1169 if( long( rtype ) == type && rformat == format )
1171 int bytelen = format == 8 ? nitems : format == 16 ? nitems * sizeof( short ) : nitems * sizeof( long );
1172 QByteArray ret( reinterpret_cast< const char* >( data ), bytelen );
1173 XFree( data );
1174 return ret;
1176 else // wrong format, type or something
1178 XFree( data );
1179 return QByteArray();
1182 else // XGetWindowProperty() failed
1183 return QByteArray();
1187 bool EffectWindowImpl::isMovable() const
1189 if( Client* c = dynamic_cast< Client* >( toplevel ))
1190 return c->isMovable();
1191 return false;
1194 bool EffectWindowImpl::isMovableAcrossScreens() const
1196 if( Client* c = dynamic_cast< Client* >( toplevel ))
1197 return c->isMovableAcrossScreens();
1198 return false;
1201 bool EffectWindowImpl::isUserMove() const
1203 if( Client* c = dynamic_cast< Client* >( toplevel ))
1204 return c->isMove();
1205 return false;
1208 bool EffectWindowImpl::isUserResize() const
1210 if( Client* c = dynamic_cast< Client* >( toplevel ))
1211 return c->isResize();
1212 return false;
1215 QRect EffectWindowImpl::iconGeometry() const
1217 if( Client* c = dynamic_cast< Client* >( toplevel ))
1218 return c->iconGeometry();
1219 return QRect();
1222 bool EffectWindowImpl::isDesktop() const
1224 return toplevel->isDesktop();
1227 bool EffectWindowImpl::isDock() const
1229 return toplevel->isDock();
1232 bool EffectWindowImpl::isToolbar() const
1234 return toplevel->isToolbar();
1237 bool EffectWindowImpl::isTopMenu() const
1239 return toplevel->isTopMenu();
1242 bool EffectWindowImpl::isMenu() const
1244 return toplevel->isMenu();
1247 bool EffectWindowImpl::isNormalWindow() const
1249 return toplevel->isNormalWindow();
1252 bool EffectWindowImpl::isSpecialWindow() const
1254 if( Client* c = dynamic_cast<Client*>( toplevel ))
1255 return c->isSpecialWindow();
1256 else
1257 return true;
1260 bool EffectWindowImpl::isDialog() const
1262 return toplevel->isDialog();
1265 bool EffectWindowImpl::isSplash() const
1267 return toplevel->isSplash();
1270 bool EffectWindowImpl::isUtility() const
1272 return toplevel->isUtility();
1275 bool EffectWindowImpl::isDropdownMenu() const
1277 return toplevel->isDropdownMenu();
1280 bool EffectWindowImpl::isPopupMenu() const
1282 return toplevel->isPopupMenu();
1285 bool EffectWindowImpl::isTooltip() const
1287 return toplevel->isTooltip();
1290 bool EffectWindowImpl::isNotification() const
1292 return toplevel->isNotification();
1295 bool EffectWindowImpl::isComboBox() const
1297 return toplevel->isComboBox();
1300 bool EffectWindowImpl::isDNDIcon() const
1302 return toplevel->isDNDIcon();
1305 bool EffectWindowImpl::isManaged() const
1307 return dynamic_cast< const Client* >( toplevel ) != NULL;
1310 bool EffectWindowImpl::isModal() const
1312 if( Client* c = dynamic_cast< Client* >( toplevel ))
1313 return c->isModal();
1314 return false;
1317 EffectWindow* EffectWindowImpl::findModal()
1319 if( Client* c = dynamic_cast< Client* >( toplevel ))
1321 if( Client* c2 = c->findModal())
1322 return c2->effectWindow();
1324 return NULL;
1327 EffectWindowList EffectWindowImpl::mainWindows() const
1329 if( Client* c = dynamic_cast< Client* >( toplevel ))
1331 EffectWindowList ret;
1332 ClientList mainclients = c->mainClients();
1333 foreach( Client* tmp, mainclients )
1334 ret.append( tmp->effectWindow());
1335 return ret;
1337 return EffectWindowList();
1340 QList<QRect> EffectWindowImpl::shadowQuads( ShadowType type ) const
1342 if( type == ShadowBorderedActive || type == ShadowBorderedInactive )
1344 if( Client* c = dynamic_cast< Client* >( toplevel ))
1345 return c->shadowQuads( type );
1346 return QList<QRect>();
1348 return toplevel->workspace()->decorationShadowQuads( type, toplevel->size() );
1351 double EffectWindowImpl::shadowOpacity( ShadowType type ) const
1353 if( type == ShadowBorderedActive || type == ShadowBorderedInactive )
1355 if( Client* c = dynamic_cast< Client* >( toplevel ))
1356 return c->shadowOpacity( type );
1357 return 1.0;
1359 return toplevel->workspace()->decorationShadowOpacity( type );
1362 double EffectWindowImpl::shadowBrightness( ShadowType type ) const
1364 if( type == ShadowBorderedActive || type == ShadowBorderedInactive )
1366 if( Client* c = dynamic_cast< Client* >( toplevel ))
1367 return c->shadowBrightness( type );
1368 return 1.0;
1370 return toplevel->workspace()->decorationShadowBrightness( type );
1373 double EffectWindowImpl::shadowSaturation( ShadowType type ) const
1375 if( type == ShadowBorderedActive || type == ShadowBorderedInactive )
1377 if( Client* c = dynamic_cast< Client* >( toplevel ))
1378 return c->shadowSaturation( type );
1379 return 1.0;
1381 return toplevel->workspace()->decorationShadowSaturation( type );
1384 WindowQuadList EffectWindowImpl::buildQuads( bool force ) const
1386 return sceneWindow()->buildQuads( force );
1389 EffectWindow* effectWindow( Toplevel* w )
1391 EffectWindowImpl* ret = w->effectWindow();
1392 return ret;
1395 EffectWindow* effectWindow( Scene::Window* w )
1397 EffectWindowImpl* ret = w->window()->effectWindow();
1398 ret->setSceneWindow( w );
1399 return ret;
1402 //****************************************
1403 // EffectWindowGroupImpl
1404 //****************************************
1407 EffectWindowList EffectWindowGroupImpl::members() const
1409 EffectWindowList ret;
1410 foreach( Toplevel* c, group->members())
1411 ret.append( c->effectWindow());
1412 return ret;
1415 } // namespace