You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1107 lines
29 KiB
1107 lines
29 KiB
/***************************************************************** |
|
KWin - the KDE window manager |
|
This file is part of the KDE project. |
|
|
|
Copyright (C) 2006 Lubos Lunak <l.lunak@kde.org> |
|
|
|
You can Freely distribute this program under the GNU General Public |
|
License. See the file "COPYING" for the exact licensing terms. |
|
******************************************************************/ |
|
|
|
#include "effects.h" |
|
|
|
#include "deleted.h" |
|
#include "client.h" |
|
#include "group.h" |
|
#include "scene_xrender.h" |
|
#include "scene_opengl.h" |
|
#include "workspace.h" |
|
#include "kwinglutils.h" |
|
|
|
#include <QFile> |
|
|
|
#include "kdebug.h" |
|
#include "klibloader.h" |
|
#include "kdesktopfile.h" |
|
#include "kconfiggroup.h" |
|
#include "kstandarddirs.h" |
|
#include <kservice.h> |
|
#include <kservicetypetrader.h> |
|
#include <kplugininfo.h> |
|
|
|
#include <assert.h> |
|
|
|
|
|
namespace KWin |
|
{ |
|
|
|
|
|
EffectsHandlerImpl::EffectsHandlerImpl(CompositingType type) |
|
: EffectsHandler(type) |
|
, keyboard_grab_effect( NULL ) |
|
{ |
|
reconfigure(); |
|
} |
|
|
|
EffectsHandlerImpl::~EffectsHandlerImpl() |
|
{ |
|
if( keyboard_grab_effect != NULL ) |
|
ungrabKeyboard(); |
|
foreach( EffectPair ep, loaded_effects ) |
|
unloadEffect( ep.first ); |
|
foreach( InputWindowPair pos, input_windows ) |
|
XDestroyWindow( display(), pos.second ); |
|
} |
|
|
|
void EffectsHandlerImpl::reconfigure() |
|
{ |
|
KSharedConfig::Ptr _config = KGlobal::config(); |
|
KConfigGroup conf(_config, "Plugins"); |
|
|
|
KService::List offers = KServiceTypeTrader::self()->query("KWin/Effect"); |
|
QStringList effectsToBeLoaded; |
|
// First unload necessary effects |
|
foreach( KService::Ptr service, offers ) |
|
{ |
|
KPluginInfo plugininfo( service ); |
|
plugininfo.load( conf ); |
|
|
|
bool isloaded = isEffectLoaded( plugininfo.pluginName() ); |
|
bool shouldbeloaded = plugininfo.isPluginEnabled(); |
|
if( !shouldbeloaded && isloaded ) |
|
unloadEffect( plugininfo.pluginName() ); |
|
if( shouldbeloaded ) |
|
effectsToBeLoaded.append( plugininfo.pluginName() ); |
|
} |
|
// Then load those that should be loaded |
|
foreach( QString effectName, effectsToBeLoaded ) |
|
{ |
|
if( !isEffectLoaded( effectName )) |
|
{ |
|
loadEffect( effectName ); |
|
} |
|
} |
|
} |
|
|
|
// the idea is that effects call this function again which calls the next one |
|
void EffectsHandlerImpl::prePaintScreen( ScreenPrePaintData& data, int time ) |
|
{ |
|
if( current_paint_screen < loaded_effects.size()) |
|
{ |
|
loaded_effects[current_paint_screen++].second->prePaintScreen( data, time ); |
|
--current_paint_screen; |
|
} |
|
// no special final code |
|
} |
|
|
|
void EffectsHandlerImpl::paintScreen( int mask, QRegion region, ScreenPaintData& data ) |
|
{ |
|
if( current_paint_screen < loaded_effects.size()) |
|
{ |
|
loaded_effects[current_paint_screen++].second->paintScreen( mask, region, data ); |
|
--current_paint_screen; |
|
} |
|
else |
|
scene->finalPaintScreen( mask, region, data ); |
|
} |
|
|
|
void EffectsHandlerImpl::postPaintScreen() |
|
{ |
|
if( current_paint_screen < loaded_effects.size()) |
|
{ |
|
loaded_effects[current_paint_screen++].second->postPaintScreen(); |
|
--current_paint_screen; |
|
} |
|
// no special final code |
|
} |
|
|
|
void EffectsHandlerImpl::prePaintWindow( EffectWindow* w, WindowPrePaintData& data, int time ) |
|
{ |
|
if( current_paint_window < loaded_effects.size()) |
|
{ |
|
loaded_effects[current_paint_window++].second->prePaintWindow( w, data, time ); |
|
--current_paint_window; |
|
} |
|
// no special final code |
|
} |
|
|
|
void EffectsHandlerImpl::paintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data ) |
|
{ |
|
if( current_paint_window < loaded_effects.size()) |
|
{ |
|
loaded_effects[current_paint_window++].second->paintWindow( w, mask, region, data ); |
|
--current_paint_window; |
|
} |
|
else |
|
scene->finalPaintWindow( static_cast<EffectWindowImpl*>( w ), mask, region, data ); |
|
} |
|
|
|
void EffectsHandlerImpl::postPaintWindow( EffectWindow* w ) |
|
{ |
|
if( current_paint_window < loaded_effects.size()) |
|
{ |
|
loaded_effects[current_paint_window++].second->postPaintWindow( w ); |
|
--current_paint_window; |
|
} |
|
// no special final code |
|
} |
|
|
|
void EffectsHandlerImpl::drawWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data ) |
|
{ |
|
if( current_draw_window < loaded_effects.size()) |
|
{ |
|
loaded_effects[current_draw_window++].second->drawWindow( w, mask, region, data ); |
|
--current_draw_window; |
|
} |
|
else |
|
scene->finalDrawWindow( static_cast<EffectWindowImpl*>( w ), mask, region, data ); |
|
} |
|
|
|
// start another painting pass |
|
void EffectsHandlerImpl::startPaint() |
|
{ |
|
assert( current_paint_screen == 0 ); |
|
assert( current_paint_window == 0 ); |
|
assert( current_draw_window == 0 ); |
|
assert( current_transform == 0 ); |
|
} |
|
|
|
void EffectsHandlerImpl::windowUserMovedResized( EffectWindow* c, bool first, bool last ) |
|
{ |
|
foreach( EffectPair ep, loaded_effects ) |
|
ep.second->windowUserMovedResized( c, first, last ); |
|
} |
|
|
|
void EffectsHandlerImpl::windowOpacityChanged( EffectWindow* c, float old_opacity ) |
|
{ |
|
if( static_cast<EffectWindowImpl*>(c)->window()->opacity() == old_opacity ) |
|
return; |
|
foreach( EffectPair ep, loaded_effects ) |
|
ep.second->windowOpacityChanged( c, old_opacity ); |
|
} |
|
|
|
void EffectsHandlerImpl::windowAdded( EffectWindow* c ) |
|
{ |
|
foreach( EffectPair ep, loaded_effects ) |
|
ep.second->windowAdded( c ); |
|
} |
|
|
|
void EffectsHandlerImpl::windowDeleted( EffectWindow* c ) |
|
{ |
|
foreach( EffectPair ep, loaded_effects ) |
|
ep.second->windowDeleted( c ); |
|
Toplevel* c2 = static_cast< EffectWindowImpl* >( c )->window(); |
|
elevated_windows.removeAll( c2 ); |
|
} |
|
|
|
void EffectsHandlerImpl::windowClosed( EffectWindow* c ) |
|
{ |
|
foreach( EffectPair ep, loaded_effects ) |
|
ep.second->windowClosed( c ); |
|
} |
|
|
|
void EffectsHandlerImpl::windowActivated( EffectWindow* c ) |
|
{ |
|
foreach( EffectPair ep, loaded_effects ) |
|
ep.second->windowActivated( c ); |
|
} |
|
|
|
void EffectsHandlerImpl::windowMinimized( EffectWindow* c ) |
|
{ |
|
foreach( EffectPair ep, loaded_effects ) |
|
ep.second->windowMinimized( c ); |
|
} |
|
|
|
void EffectsHandlerImpl::windowUnminimized( EffectWindow* c ) |
|
{ |
|
foreach( EffectPair ep, loaded_effects ) |
|
ep.second->windowUnminimized( c ); |
|
} |
|
|
|
void EffectsHandlerImpl::desktopChanged( int old ) |
|
{ |
|
foreach( EffectPair ep, loaded_effects ) |
|
ep.second->desktopChanged( old ); |
|
} |
|
|
|
void EffectsHandlerImpl::windowDamaged( EffectWindow* w, const QRect& r ) |
|
{ |
|
if( w == NULL ) |
|
return; |
|
foreach( EffectPair ep, loaded_effects ) |
|
ep.second->windowDamaged( w, r ); |
|
} |
|
|
|
void EffectsHandlerImpl::windowGeometryShapeChanged( EffectWindow* w, const QRect& old ) |
|
{ |
|
if( w == NULL ) // during late cleanup effectWindow() may be already NULL |
|
return; // in some functions that may still call this |
|
foreach( EffectPair ep, loaded_effects ) |
|
ep.second->windowGeometryShapeChanged( w, old ); |
|
} |
|
|
|
void EffectsHandlerImpl::tabBoxAdded( int mode ) |
|
{ |
|
foreach( EffectPair ep, loaded_effects ) |
|
ep.second->tabBoxAdded( mode ); |
|
} |
|
|
|
void EffectsHandlerImpl::tabBoxClosed() |
|
{ |
|
foreach( EffectPair ep, loaded_effects ) |
|
ep.second->tabBoxClosed(); |
|
} |
|
|
|
void EffectsHandlerImpl::tabBoxUpdated() |
|
{ |
|
foreach( EffectPair ep, loaded_effects ) |
|
ep.second->tabBoxUpdated(); |
|
} |
|
|
|
bool EffectsHandlerImpl::borderActivated( ElectricBorder border ) |
|
{ |
|
bool ret = false; |
|
foreach( EffectPair ep, loaded_effects ) |
|
if( ep.second->borderActivated( border )) |
|
ret = true; // bail out or tell all? |
|
return ret; |
|
} |
|
|
|
void EffectsHandlerImpl::mouseChanged( const QPoint& pos, const QPoint& old, |
|
Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers ) |
|
{ |
|
foreach( EffectPair ep, loaded_effects ) |
|
ep.second->mouseChanged( pos, old, buttons, modifiers ); |
|
} |
|
|
|
bool EffectsHandlerImpl::grabKeyboard( Effect* effect ) |
|
{ |
|
if( keyboard_grab_effect != NULL ) |
|
return false; |
|
bool ret = grabXKeyboard(); |
|
if( !ret ) |
|
return false; |
|
keyboard_grab_effect = effect; |
|
return true; |
|
} |
|
|
|
void EffectsHandlerImpl::ungrabKeyboard() |
|
{ |
|
assert( keyboard_grab_effect != NULL ); |
|
ungrabXKeyboard(); |
|
keyboard_grab_effect = NULL; |
|
} |
|
|
|
void EffectsHandlerImpl::grabbedKeyboardEvent( QKeyEvent* e ) |
|
{ |
|
if( keyboard_grab_effect != NULL ) |
|
keyboard_grab_effect->grabbedKeyboardEvent( e ); |
|
} |
|
|
|
bool EffectsHandlerImpl::hasKeyboardGrab() const |
|
{ |
|
return keyboard_grab_effect != NULL; |
|
} |
|
|
|
void EffectsHandlerImpl::activateWindow( EffectWindow* c ) |
|
{ |
|
if( Client* cl = dynamic_cast< Client* >( static_cast<EffectWindowImpl*>(c)->window())) |
|
Workspace::self()->activateClient( cl, true ); |
|
} |
|
|
|
EffectWindow* EffectsHandlerImpl::activeWindow() const |
|
{ |
|
return Workspace::self()->activeClient() ? Workspace::self()->activeClient()->effectWindow() : NULL; |
|
} |
|
|
|
void EffectsHandlerImpl::moveWindow( EffectWindow* w, const QPoint& pos ) |
|
{ |
|
Client* cl = dynamic_cast< Client* >( static_cast<EffectWindowImpl*>(w)->window()); |
|
if( cl && cl->isMovable()) |
|
cl->move( pos ); |
|
} |
|
|
|
void EffectsHandlerImpl::windowToDesktop( EffectWindow* w, int desktop ) |
|
{ |
|
Client* cl = dynamic_cast< Client* >( static_cast<EffectWindowImpl*>(w)->window()); |
|
if( cl && cl->isMovable()) |
|
Workspace::self()->sendClientToDesktop( cl, desktop, true ); |
|
} |
|
|
|
int EffectsHandlerImpl::currentDesktop() const |
|
{ |
|
return Workspace::self()->currentDesktop(); |
|
} |
|
|
|
int EffectsHandlerImpl::numberOfDesktops() const |
|
{ |
|
return Workspace::self()->numberOfDesktops(); |
|
} |
|
|
|
void EffectsHandlerImpl::setCurrentDesktop( int desktop ) |
|
{ |
|
Workspace::self()->setCurrentDesktop( desktop ); |
|
} |
|
|
|
QString EffectsHandlerImpl::desktopName( int desktop ) const |
|
{ |
|
return Workspace::self()->desktopName( desktop ); |
|
} |
|
|
|
void EffectsHandlerImpl::calcDesktopLayout(int* x, int* y, Qt::Orientation* orientation) const |
|
{ |
|
Workspace::self()->calcDesktopLayout( x, y, orientation ); |
|
} |
|
|
|
bool EffectsHandlerImpl::optionRollOverDesktops() const |
|
{ |
|
return options->rollOverDesktops; |
|
} |
|
|
|
int EffectsHandlerImpl::displayWidth() const |
|
{ |
|
return KWin::displayWidth(); |
|
} |
|
|
|
int EffectsHandlerImpl::displayHeight() const |
|
{ |
|
return KWin::displayWidth(); |
|
} |
|
|
|
EffectWindowList EffectsHandlerImpl::stackingOrder() const |
|
{ |
|
ClientList list = Workspace::self()->stackingOrder(); |
|
EffectWindowList ret; |
|
foreach( Client* c, list ) |
|
ret.append( effectWindow( c )); |
|
return ret; |
|
} |
|
|
|
void EffectsHandlerImpl::setElevatedWindow( EffectWindow* w, bool set ) |
|
{ |
|
Toplevel* c = static_cast< EffectWindowImpl* >( w )->window(); |
|
elevated_windows.removeAll( c ); |
|
if( set ) |
|
elevated_windows.append( c ); |
|
} |
|
|
|
void EffectsHandlerImpl::setTabBoxWindow(EffectWindow* w) |
|
{ |
|
if( Client* c = dynamic_cast< Client* >( static_cast< EffectWindowImpl* >( w )->window())) |
|
Workspace::self()->setTabBoxClient( c ); |
|
} |
|
|
|
void EffectsHandlerImpl::setTabBoxDesktop(int desktop) |
|
{ |
|
Workspace::self()->setTabBoxDesktop( desktop ); |
|
} |
|
|
|
EffectWindowList EffectsHandlerImpl::currentTabBoxWindowList() const |
|
{ |
|
EffectWindowList ret; |
|
ClientList clients = Workspace::self()->currentTabBoxClientList(); |
|
foreach( Client* c, clients ) |
|
ret.append( c->effectWindow()); |
|
return ret; |
|
} |
|
|
|
void EffectsHandlerImpl::refTabBox() |
|
{ |
|
Workspace::self()->refTabBox(); |
|
} |
|
|
|
void EffectsHandlerImpl::unrefTabBox() |
|
{ |
|
Workspace::self()->unrefTabBox(); |
|
} |
|
|
|
void EffectsHandlerImpl::closeTabBox() |
|
{ |
|
Workspace::self()->closeTabBox(); |
|
} |
|
|
|
QList< int > EffectsHandlerImpl::currentTabBoxDesktopList() const |
|
{ |
|
return Workspace::self()->currentTabBoxDesktopList(); |
|
} |
|
|
|
int EffectsHandlerImpl::currentTabBoxDesktop() const |
|
{ |
|
return Workspace::self()->currentTabBoxDesktop(); |
|
} |
|
|
|
EffectWindow* EffectsHandlerImpl::currentTabBoxWindow() const |
|
{ |
|
if( Client* c = Workspace::self()->currentTabBoxClient()) |
|
return c->effectWindow(); |
|
return NULL; |
|
} |
|
|
|
void EffectsHandlerImpl::pushRenderTarget(GLRenderTarget* target) |
|
{ |
|
#ifdef HAVE_OPENGL |
|
target->enable(); |
|
render_targets.push(target); |
|
#endif |
|
} |
|
|
|
GLRenderTarget* EffectsHandlerImpl::popRenderTarget() |
|
{ |
|
#ifdef HAVE_OPENGL |
|
GLRenderTarget* ret = render_targets.pop(); |
|
ret->disable(); |
|
if( !render_targets.isEmpty() ) |
|
render_targets.top()->enable(); |
|
return ret; |
|
#else |
|
return 0; |
|
#endif |
|
} |
|
|
|
void EffectsHandlerImpl::addRepaintFull() |
|
{ |
|
Workspace::self()->addRepaintFull(); |
|
} |
|
|
|
void EffectsHandlerImpl::addRepaint( const QRect& r ) |
|
{ |
|
Workspace::self()->addRepaint( r ); |
|
} |
|
|
|
void EffectsHandlerImpl::addRepaint( int x, int y, int w, int h ) |
|
{ |
|
Workspace::self()->addRepaint( x, y, w, h ); |
|
} |
|
|
|
QRect EffectsHandlerImpl::clientArea( clientAreaOption opt, const QPoint& p, int desktop ) const |
|
{ |
|
return Workspace::self()->clientArea( opt, p, desktop ); |
|
} |
|
|
|
Window EffectsHandlerImpl::createInputWindow( Effect* e, int x, int y, int w, int h, const QCursor& cursor ) |
|
{ |
|
XSetWindowAttributes attrs; |
|
attrs.override_redirect = True; |
|
Window win = XCreateWindow( display(), rootWindow(), x, y, w, h, 0, 0, InputOnly, CopyFromParent, |
|
CWOverrideRedirect, &attrs ); |
|
// TODO keeping on top? |
|
// TODO enter/leave notify? |
|
XSelectInput( display(), win, ButtonPressMask | ButtonReleaseMask | PointerMotionMask ); |
|
XDefineCursor( display(), win, cursor.handle()); |
|
XMapWindow( display(), win ); |
|
input_windows.append( qMakePair( e, win )); |
|
return win; |
|
} |
|
|
|
void EffectsHandlerImpl::destroyInputWindow( Window w ) |
|
{ |
|
foreach( InputWindowPair pos, input_windows ) |
|
{ |
|
if( pos.second == w ) |
|
{ |
|
input_windows.removeAll( pos ); |
|
XDestroyWindow( display(), w ); |
|
return; |
|
} |
|
} |
|
assert( false ); |
|
} |
|
|
|
bool EffectsHandlerImpl::checkInputWindowEvent( XEvent* e ) |
|
{ |
|
if( e->type != ButtonPress && e->type != ButtonRelease && e->type != MotionNotify ) |
|
return false; |
|
foreach( InputWindowPair pos, input_windows ) |
|
{ |
|
if( pos.second == e->xany.window ) |
|
{ |
|
switch( e->type ) |
|
{ |
|
case ButtonPress: |
|
{ |
|
XButtonEvent* e2 = &e->xbutton; |
|
Qt::MouseButton button = x11ToQtMouseButton( e2->button ); |
|
Qt::MouseButtons buttons = x11ToQtMouseButtons( e2->state ) | button; |
|
QMouseEvent ev( QEvent::MouseButtonPress, |
|
QPoint( e2->x, e2->y ), QPoint( e2->x_root, e2->y_root ), |
|
button, buttons, x11ToQtKeyboardModifiers( e2->state )); |
|
pos.first->windowInputMouseEvent( pos.second, &ev ); |
|
break; // ---> |
|
} |
|
case ButtonRelease: |
|
{ |
|
XButtonEvent* e2 = &e->xbutton; |
|
Qt::MouseButton button = x11ToQtMouseButton( e2->button ); |
|
Qt::MouseButtons buttons = x11ToQtMouseButtons( e2->state ) & ~button; |
|
QMouseEvent ev( QEvent::MouseButtonRelease, |
|
QPoint( e2->x, e2->y ), QPoint( e2->x_root, e2->y_root ), |
|
button, buttons, x11ToQtKeyboardModifiers( e2->state )); |
|
pos.first->windowInputMouseEvent( pos.second, &ev ); |
|
break; // ---> |
|
} |
|
case MotionNotify: |
|
{ |
|
XMotionEvent* e2 = &e->xmotion; |
|
QMouseEvent ev( QEvent::MouseMove, QPoint( e2->x, e2->y ), QPoint( e2->x_root, e2->y_root ), |
|
Qt::NoButton, x11ToQtMouseButtons( e2->state ), x11ToQtKeyboardModifiers( e2->state )); |
|
pos.first->windowInputMouseEvent( pos.second, &ev ); |
|
break; // ---> |
|
} |
|
} |
|
return true; // eat event |
|
} |
|
} |
|
return false; |
|
} |
|
|
|
void EffectsHandlerImpl::checkInputWindowStacking() |
|
{ |
|
if( input_windows.count() == 0 ) |
|
return; |
|
Window* wins = new Window[ input_windows.count() ]; |
|
int pos = 0; |
|
foreach( InputWindowPair it, input_windows ) |
|
wins[ pos++ ] = it.second; |
|
XRaiseWindow( display(), wins[ 0 ] ); |
|
XRestackWindows( display(), wins, pos ); |
|
delete[] wins; |
|
} |
|
|
|
QPoint EffectsHandlerImpl::cursorPos() const |
|
{ |
|
return Workspace::self()->cursorPos(); |
|
} |
|
|
|
void EffectsHandlerImpl::checkElectricBorder(const QPoint &pos, Time time) |
|
{ |
|
Workspace::self()->checkElectricBorder( pos, time ); |
|
} |
|
|
|
void EffectsHandlerImpl::reserveElectricBorder( ElectricBorder border ) |
|
{ |
|
Workspace::self()->reserveElectricBorder( border ); |
|
} |
|
|
|
void EffectsHandlerImpl::unreserveElectricBorder( ElectricBorder border ) |
|
{ |
|
Workspace::self()->unreserveElectricBorder( border ); |
|
} |
|
|
|
void EffectsHandlerImpl::reserveElectricBorderSwitching( bool reserve ) |
|
{ |
|
Workspace::self()->reserveElectricBorderSwitching( reserve ); |
|
} |
|
|
|
unsigned long EffectsHandlerImpl::xrenderBufferPicture() |
|
{ |
|
#if defined(HAVE_XRENDER) && defined(HAVE_XFIXES) |
|
if( SceneXrender* s = dynamic_cast< SceneXrender* >( scene )) |
|
return s->bufferPicture(); |
|
#endif |
|
return None; |
|
} |
|
|
|
KLibrary* EffectsHandlerImpl::findEffectLibrary( KService* service ) |
|
{ |
|
QString libname = service->library(); |
|
KLibrary* library = KLibLoader::self()->library(libname); |
|
if( !library ) |
|
{ |
|
kError( 1212 ) << "couldn't open library for effect '" << |
|
service->name() << "'" << endl; |
|
return 0; |
|
} |
|
|
|
return library; |
|
} |
|
|
|
void EffectsHandlerImpl::toggleEffect( const QString& name ) |
|
{ |
|
if( isEffectLoaded( name )) |
|
unloadEffect( name ); |
|
else |
|
loadEffect( name ); |
|
} |
|
|
|
bool EffectsHandlerImpl::loadEffect( const QString& name ) |
|
{ |
|
Workspace::self()->addRepaintFull(); |
|
assert( current_paint_screen == 0 ); |
|
assert( current_paint_window == 0 ); |
|
assert( current_draw_window == 0 ); |
|
assert( current_transform == 0 ); |
|
|
|
if( !name.startsWith("kwin4_effect_") ) |
|
kWarning( 1212 ) << "Effect names usually have kwin4_effect_ prefix" ; |
|
|
|
// Make sure a single effect won't be loaded multiple times |
|
for(QVector< EffectPair >::const_iterator it = loaded_effects.constBegin(); it != loaded_effects.constEnd(); ++it) |
|
{ |
|
if( (*it).first == name ) |
|
{ |
|
kDebug( 1212 ) << "EffectsHandler::loadEffect : Effect already loaded : " << name; |
|
return true; |
|
} |
|
} |
|
|
|
|
|
kDebug( 1212 ) << "Trying to load " << name; |
|
QString internalname = name.toLower(); |
|
|
|
QString constraint = QString("[X-KDE-PluginInfo-Name] == '%1'").arg(internalname); |
|
KService::List offers = KServiceTypeTrader::self()->query("KWin/Effect", constraint); |
|
if(offers.isEmpty()) |
|
{ |
|
kError( 1212 ) << "Couldn't find effect " << name << endl; |
|
return false; |
|
} |
|
KService::Ptr service = offers.first(); |
|
|
|
KLibrary* library = findEffectLibrary( service.data() ); |
|
if( !library ) |
|
{ |
|
return false; |
|
} |
|
|
|
QString supported_symbol = "effect_supported_" + name; |
|
KLibrary::void_function_ptr supported_func = library->resolveFunction(supported_symbol.toAscii().data()); |
|
QString create_symbol = "effect_create_" + name; |
|
KLibrary::void_function_ptr create_func = library->resolveFunction(create_symbol.toAscii().data()); |
|
if( supported_func ) |
|
{ |
|
typedef bool (*t_supportedfunc)(); |
|
t_supportedfunc supported = reinterpret_cast<t_supportedfunc>(supported_func); |
|
if(!supported()) |
|
{ |
|
kWarning( 1212 ) << "EffectsHandler::loadEffect : Effect " << name << " is not supported" ; |
|
library->unload(); |
|
return false; |
|
} |
|
} |
|
if(!create_func) |
|
{ |
|
kError( 1212 ) << "EffectsHandler::loadEffect : effect_create function not found" << endl; |
|
library->unload(); |
|
return false; |
|
} |
|
typedef Effect* (*t_createfunc)(); |
|
t_createfunc create = reinterpret_cast<t_createfunc>(create_func); |
|
|
|
// Make sure all depenedencies have been loaded |
|
// TODO: detect circular deps |
|
KPluginInfo plugininfo( service ); |
|
QStringList dependencies = plugininfo.dependencies(); |
|
foreach( QString depName, dependencies ) |
|
{ |
|
if( !loadEffect(depName)) |
|
{ |
|
kError() << "EffectsHandler::loadEffect : Couldn't load dependencies for effect " << name << endl; |
|
library->unload(); |
|
return false; |
|
} |
|
} |
|
|
|
Effect* e = create(); |
|
|
|
effect_order.insert( service->property( "X-Ordering" ).toInt(), EffectPair( name, e )); |
|
effectsChanged(); |
|
effect_libraries[ name ] = library; |
|
|
|
return true; |
|
} |
|
|
|
void EffectsHandlerImpl::unloadEffect( const QString& name ) |
|
{ |
|
Workspace::self()->addRepaintFull(); |
|
assert( current_paint_screen == 0 ); |
|
assert( current_paint_window == 0 ); |
|
assert( current_draw_window == 0 ); |
|
assert( current_transform == 0 ); |
|
|
|
for( QMap< int, EffectPair >::iterator it = effect_order.begin(); it != effect_order.end(); ++it) |
|
{ |
|
if ( it.value().first == name ) |
|
{ |
|
kDebug( 1212 ) << "EffectsHandler::unloadEffect : Unloading Effect : " << name; |
|
delete it.value().second; |
|
effect_order.erase(it); |
|
effectsChanged(); |
|
effect_libraries[ name ]->unload(); |
|
return; |
|
} |
|
} |
|
|
|
kDebug( 1212 ) << "EffectsHandler::unloadEffect : Effect not loaded : " << name; |
|
} |
|
|
|
void EffectsHandlerImpl::reloadEffect( const QString& name ) |
|
{ |
|
if( isEffectLoaded( name )) |
|
{ |
|
unloadEffect( name ); |
|
loadEffect( name ); |
|
} |
|
} |
|
|
|
bool EffectsHandlerImpl::isEffectLoaded( const QString& name ) |
|
{ |
|
for( QVector< EffectPair >::iterator it = loaded_effects.begin(); it != loaded_effects.end(); ++it) |
|
if ( (*it).first == name ) |
|
return true; |
|
|
|
return false; |
|
} |
|
|
|
void EffectsHandlerImpl::effectsChanged() |
|
{ |
|
loaded_effects.clear(); |
|
kDebug() << "Recreating effects' list:"; |
|
foreach( EffectPair effect, effect_order ) |
|
{ |
|
kDebug() << effect.first; |
|
loaded_effects.append( effect ); |
|
} |
|
} |
|
|
|
|
|
//**************************************** |
|
// EffectWindowImpl |
|
//**************************************** |
|
|
|
EffectWindowImpl::EffectWindowImpl() : EffectWindow() |
|
, toplevel( NULL ) |
|
, sw( NULL ) |
|
{ |
|
} |
|
|
|
EffectWindowImpl::~EffectWindowImpl() |
|
{ |
|
} |
|
|
|
bool EffectWindowImpl::isPaintingEnabled() |
|
{ |
|
return sceneWindow()->isPaintingEnabled(); |
|
} |
|
|
|
void EffectWindowImpl::enablePainting( int reason ) |
|
{ |
|
sceneWindow()->enablePainting( reason ); |
|
} |
|
|
|
void EffectWindowImpl::disablePainting( int reason ) |
|
{ |
|
sceneWindow()->disablePainting( reason ); |
|
} |
|
|
|
void EffectWindowImpl::addRepaint( const QRect& r ) |
|
{ |
|
toplevel->addRepaint( r ); |
|
} |
|
|
|
void EffectWindowImpl::addRepaint( int x, int y, int w, int h ) |
|
{ |
|
toplevel->addRepaint( x, y, w, h ); |
|
} |
|
|
|
void EffectWindowImpl::addRepaintFull() |
|
{ |
|
toplevel->addRepaintFull(); |
|
} |
|
|
|
int EffectWindowImpl::desktop() const |
|
{ |
|
return toplevel->desktop(); |
|
} |
|
|
|
bool EffectWindowImpl::isOnAllDesktops() const |
|
{ |
|
return desktop() == NET::OnAllDesktops; |
|
} |
|
|
|
QString EffectWindowImpl::caption() const |
|
{ |
|
if( Client* c = dynamic_cast<Client*>( toplevel )) |
|
return c->caption(); |
|
else |
|
return ""; |
|
} |
|
|
|
QString EffectWindowImpl::windowClass() const |
|
{ |
|
return toplevel->resourceName() + ' ' + toplevel->resourceClass(); |
|
} |
|
|
|
QPixmap EffectWindowImpl::icon() const |
|
{ |
|
if( Client* c = dynamic_cast<Client*>( toplevel )) |
|
return c->icon(); |
|
return QPixmap(); // TODO |
|
} |
|
|
|
const EffectWindowGroup* EffectWindowImpl::group() const |
|
{ |
|
if( Client* c = dynamic_cast< Client* >( toplevel )) |
|
return c->group()->effectGroup(); |
|
return NULL; // TODO |
|
} |
|
|
|
bool EffectWindowImpl::isMinimized() const |
|
{ |
|
if( Client* c = dynamic_cast<Client*>( toplevel )) |
|
return c->isMinimized(); |
|
else |
|
return false; |
|
} |
|
|
|
float EffectWindowImpl::opacity() const |
|
{ |
|
return toplevel->opacity(); |
|
} |
|
|
|
bool EffectWindowImpl::isDeleted() const |
|
{ |
|
return (dynamic_cast<Deleted*>( toplevel ) != 0); |
|
} |
|
|
|
void EffectWindowImpl::refWindow() |
|
{ |
|
if( Deleted* d = dynamic_cast< Deleted* >( toplevel )) |
|
return d->refWindow(); |
|
abort(); // TODO |
|
} |
|
|
|
void EffectWindowImpl::unrefWindow() |
|
{ |
|
if( Deleted* d = dynamic_cast< Deleted* >( toplevel )) |
|
return d->unrefWindow( true ); // delayed |
|
abort(); // TODO |
|
} |
|
|
|
void EffectWindowImpl::setWindow( Toplevel* w ) |
|
{ |
|
toplevel = w; |
|
} |
|
|
|
void EffectWindowImpl::setSceneWindow( Scene::Window* w ) |
|
{ |
|
sw = w; |
|
} |
|
|
|
int EffectWindowImpl::x() const |
|
{ |
|
return toplevel->x(); |
|
} |
|
|
|
int EffectWindowImpl::y() const |
|
{ |
|
return toplevel->y(); |
|
} |
|
|
|
int EffectWindowImpl::width() const |
|
{ |
|
return toplevel->width(); |
|
} |
|
|
|
int EffectWindowImpl::height() const |
|
{ |
|
return toplevel->height(); |
|
} |
|
|
|
QRect EffectWindowImpl::geometry() const |
|
{ |
|
return toplevel->geometry(); |
|
} |
|
|
|
QSize EffectWindowImpl::size() const |
|
{ |
|
return toplevel->size(); |
|
} |
|
|
|
QPoint EffectWindowImpl::pos() const |
|
{ |
|
return toplevel->pos(); |
|
} |
|
|
|
QRect EffectWindowImpl::rect() const |
|
{ |
|
return toplevel->rect(); |
|
} |
|
|
|
QRect EffectWindowImpl::contentsRect() const |
|
{ |
|
return QRect( toplevel->clientPos(), toplevel->clientSize()); |
|
} |
|
|
|
bool EffectWindowImpl::isMovable() const |
|
{ |
|
if( Client* c = dynamic_cast< Client* >( toplevel )) |
|
return c->isMovable(); |
|
return false; |
|
} |
|
|
|
bool EffectWindowImpl::isUserMove() const |
|
{ |
|
if( Client* c = dynamic_cast< Client* >( toplevel )) |
|
return c->isMove(); |
|
return false; |
|
} |
|
|
|
bool EffectWindowImpl::isUserResize() const |
|
{ |
|
if( Client* c = dynamic_cast< Client* >( toplevel )) |
|
return c->isResize(); |
|
return false; |
|
} |
|
|
|
QRect EffectWindowImpl::iconGeometry() const |
|
{ |
|
if( Client* c = dynamic_cast< Client* >( toplevel )) |
|
return c->iconGeometry(); |
|
return QRect(); |
|
} |
|
|
|
bool EffectWindowImpl::isDesktop() const |
|
{ |
|
return toplevel->isDesktop(); |
|
} |
|
|
|
bool EffectWindowImpl::isDock() const |
|
{ |
|
return toplevel->isDock(); |
|
} |
|
|
|
bool EffectWindowImpl::isToolbar() const |
|
{ |
|
return toplevel->isToolbar(); |
|
} |
|
|
|
bool EffectWindowImpl::isTopMenu() const |
|
{ |
|
return toplevel->isTopMenu(); |
|
} |
|
|
|
bool EffectWindowImpl::isMenu() const |
|
{ |
|
return toplevel->isMenu(); |
|
} |
|
|
|
bool EffectWindowImpl::isNormalWindow() const |
|
{ |
|
return toplevel->isNormalWindow(); |
|
} |
|
|
|
bool EffectWindowImpl::isSpecialWindow() const |
|
{ |
|
if( Client* c = dynamic_cast<Client*>( toplevel )) |
|
return c->isSpecialWindow(); |
|
else |
|
return false; |
|
} |
|
|
|
bool EffectWindowImpl::isDialog() const |
|
{ |
|
return toplevel->isDialog(); |
|
} |
|
|
|
bool EffectWindowImpl::isSplash() const |
|
{ |
|
return toplevel->isSplash(); |
|
} |
|
|
|
bool EffectWindowImpl::isUtility() const |
|
{ |
|
return toplevel->isUtility(); |
|
} |
|
|
|
bool EffectWindowImpl::isDropdownMenu() const |
|
{ |
|
return toplevel->isDropdownMenu(); |
|
} |
|
|
|
bool EffectWindowImpl::isPopupMenu() const |
|
{ |
|
return toplevel->isPopupMenu(); |
|
} |
|
|
|
bool EffectWindowImpl::isTooltip() const |
|
{ |
|
return toplevel->isTooltip(); |
|
} |
|
|
|
bool EffectWindowImpl::isNotification() const |
|
{ |
|
return toplevel->isNotification(); |
|
} |
|
|
|
bool EffectWindowImpl::isComboBox() const |
|
{ |
|
return toplevel->isComboBox(); |
|
} |
|
|
|
bool EffectWindowImpl::isDNDIcon() const |
|
{ |
|
return toplevel->isDNDIcon(); |
|
} |
|
|
|
bool EffectWindowImpl::isModal() const |
|
{ |
|
if( Client* c = dynamic_cast< Client* >( toplevel )) |
|
return c->isModal(); |
|
return false; |
|
} |
|
|
|
EffectWindow* EffectWindowImpl::findModal() |
|
{ |
|
if( Client* c = dynamic_cast< Client* >( toplevel )) |
|
{ |
|
if( Client* c2 = c->findModal()) |
|
return c2->effectWindow(); |
|
} |
|
return NULL; |
|
} |
|
|
|
EffectWindowList EffectWindowImpl::mainWindows() const |
|
{ |
|
if( Client* c = dynamic_cast< Client* >( toplevel )) |
|
{ |
|
EffectWindowList ret; |
|
ClientList mainclients = c->mainClients(); |
|
foreach( Client* tmp, mainclients ) |
|
ret.append( tmp->effectWindow()); |
|
return ret; |
|
} |
|
return EffectWindowList(); |
|
} |
|
|
|
WindowQuadList EffectWindowImpl::buildQuads() const |
|
{ |
|
return sceneWindow()->buildQuads(); |
|
} |
|
|
|
EffectWindow* effectWindow( Toplevel* w ) |
|
{ |
|
EffectWindowImpl* ret = w->effectWindow(); |
|
return ret; |
|
} |
|
|
|
EffectWindow* effectWindow( Scene::Window* w ) |
|
{ |
|
EffectWindowImpl* ret = w->window()->effectWindow(); |
|
ret->setSceneWindow( w ); |
|
return ret; |
|
} |
|
|
|
//**************************************** |
|
// EffectWindowGroupImpl |
|
//**************************************** |
|
|
|
|
|
EffectWindowList EffectWindowGroupImpl::members() const |
|
{ |
|
EffectWindowList ret; |
|
foreach( Toplevel* c, group->members()) |
|
ret.append( c->effectWindow()); |
|
return ret; |
|
} |
|
|
|
} // namespace
|
|
|