kwin/effects.h

527 lines
18 KiB
C
Raw Normal View History

/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2006 Lubos Lunak <l.lunak@kde.org>
Copyright (C) 2010, 2011 Martin Gräßlin <mgraesslin@kde.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************/
#ifndef KWIN_EFFECTSIMPL_H
#define KWIN_EFFECTSIMPL_H
#include "kwineffects.h"
#include "scene.h"
#include "xcbutils.h"
#include <QStack>
#include <QHash>
#include <QQueue>
#include <Plasma/FrameSvg>
namespace Plasma {
class Theme;
}
class QDBusPendingCallWatcher;
class QDBusServiceWatcher;
class KService;
class OrgFreedesktopScreenSaverInterface;
namespace KWin
{
class AbstractThumbnailItem;
class DesktopThumbnailItem;
class WindowThumbnailItem;
class Client;
class Compositor;
class Deleted;
class EffectLoader;
class Unmanaged;
class ScreenLockerWatcher;
class EffectsHandlerImpl : public EffectsHandler
{
Q_OBJECT
Q_CLASSINFO("D-Bus Interface", "org.kde.kwin.Effects")
Q_PROPERTY(QStringList activeEffects READ activeEffects)
Q_PROPERTY(QStringList loadedEffects READ loadedEffects)
Q_PROPERTY(QStringList listOfEffects READ listOfEffects)
2011-01-30 17:34:42 +03:00
public:
EffectsHandlerImpl(Compositor *compositor, Scene *scene);
2011-01-30 17:34:42 +03:00
virtual ~EffectsHandlerImpl();
void prePaintScreen(ScreenPrePaintData& data, int time) override;
void paintScreen(int mask, QRegion region, ScreenPaintData& data) override;
/**
* Special hook to perform a paintScreen but just with the windows on @p desktop.
**/
void paintDesktop(int desktop, int mask, QRegion region, ScreenPaintData& data);
void postPaintScreen() override;
void prePaintWindow(EffectWindow* w, WindowPrePaintData& data, int time) override;
void paintWindow(EffectWindow* w, int mask, QRegion region, WindowPaintData& data) override;
void postPaintWindow(EffectWindow* w) override;
void paintEffectFrame(EffectFrame* frame, QRegion region, double opacity, double frameOpacity) override;
2011-01-30 17:34:42 +03:00
Effect *provides(Effect::Feature ef);
2011-01-30 17:34:42 +03:00
void drawWindow(EffectWindow* w, int mask, QRegion region, WindowPaintData& data) override;
void buildQuads(EffectWindow* w, WindowQuadList& quadList) override;
void activateWindow(EffectWindow* c) override;
EffectWindow* activeWindow() const override;
void moveWindow(EffectWindow* w, const QPoint& pos, bool snap = false, double snapAdjust = 1.0) override;
void windowToDesktop(EffectWindow* w, int desktop) override;
void windowToScreen(EffectWindow* w, int screen) override;
void setShowingDesktop(bool showing) override;
QString currentActivity() const override;
int currentDesktop() const override;
int numberOfDesktops() const override;
void setCurrentDesktop(int desktop) override;
void setNumberOfDesktops(int desktops) override;
QSize desktopGridSize() const override;
int desktopGridWidth() const override;
int desktopGridHeight() const override;
int workspaceWidth() const override;
int workspaceHeight() const override;
int desktopAtCoords(QPoint coords) const override;
QPoint desktopGridCoords(int id) const override;
QPoint desktopCoords(int id) const override;
int desktopAbove(int desktop = 0, bool wrap = true) const override;
int desktopToRight(int desktop = 0, bool wrap = true) const override;
int desktopBelow(int desktop = 0, bool wrap = true) const override;
int desktopToLeft(int desktop = 0, bool wrap = true) const override;
QString desktopName(int desktop) const override;
bool optionRollOverDesktops() const override;
2011-01-30 17:34:42 +03:00
QPoint cursorPos() const override;
bool grabKeyboard(Effect* effect) override;
void ungrabKeyboard() override;
// not performing XGrabPointer
void startMouseInterception(Effect *effect, Qt::CursorShape shape) override;
void stopMouseInterception(Effect *effect) override;
void* getProxy(QString name) override;
void startMousePolling() override;
void stopMousePolling() override;
EffectWindow* findWindow(WId id) const override;
EffectWindowList stackingOrder() const override;
void setElevatedWindow(EffectWindow* w, bool set) override;
void setTabBoxWindow(EffectWindow*) override;
void setTabBoxDesktop(int) override;
EffectWindowList currentTabBoxWindowList() const override;
void refTabBox() override;
void unrefTabBox() override;
void closeTabBox() override;
QList< int > currentTabBoxDesktopList() const override;
int currentTabBoxDesktop() const override;
EffectWindow* currentTabBoxWindow() const override;
void setActiveFullScreenEffect(Effect* e) override;
Effect* activeFullScreenEffect() const override;
void addRepaintFull() override;
void addRepaint(const QRect& r) override;
void addRepaint(const QRegion& r) override;
void addRepaint(int x, int y, int w, int h) override;
int activeScreen() const override;
int numScreens() const override;
int screenNumber(const QPoint& pos) const override;
QRect clientArea(clientAreaOption, int screen, int desktop) const override;
QRect clientArea(clientAreaOption, const EffectWindow* c) const override;
QRect clientArea(clientAreaOption, const QPoint& p, int desktop) const override;
double animationTimeFactor() const override;
WindowQuadType newWindowQuadType() override;
void defineCursor(Qt::CursorShape shape) override;
bool checkInputWindowEvent(xcb_button_press_event_t *e);
bool checkInputWindowEvent(xcb_motion_notify_event_t *e);
void checkInputWindowStacking();
2011-01-30 17:34:42 +03:00
void reserveElectricBorder(ElectricBorder border, Effect *effect) override;
void unreserveElectricBorder(ElectricBorder border, Effect *effect) override;
2011-01-30 17:34:42 +03:00
unsigned long xrenderBufferPicture() override;
QPainter* scenePainter() override;
void reconfigure() override;
void registerPropertyType(long atom, bool reg) override;
QByteArray readRootProperty(long atom, long type, int format) const override;
void deleteRootProperty(long atom) const override;
xcb_atom_t announceSupportProperty(const QByteArray& propertyName, Effect* effect) override;
void removeSupportProperty(const QByteArray& propertyName, Effect* effect) override;
2011-01-30 17:34:42 +03:00
bool hasDecorationShadows() const override;
2011-01-30 17:34:42 +03:00
bool decorationsHaveAlpha() const override;
2011-01-30 17:34:42 +03:00
bool decorationSupportsBlurBehind() const override;
2011-01-30 17:34:42 +03:00
EffectFrame* effectFrame(EffectFrameStyle style, bool staticSize, const QPoint& position, Qt::Alignment alignment) const override;
2011-01-30 17:34:42 +03:00
QVariant kwinOption(KWinOption kwopt) override;
bool isScreenLocked() const override;
bool makeOpenGLContextCurrent() override;
void doneOpenGLContextCurrent() override;
Better handling for making the compositing OpenGL context current With QtQuick2 it's possible that the scene graph rendering context either lives in an own thread or uses the main GUI thread. In the latter case it's the same thread as our compositing OpenGL context lives in. This means our basic assumption that between two rendering passes the context stays current does not hold. The code already ensured that before we start a rendering pass the context is made current, but there are many more possible cases. If we use OpenGL in areas not triggered by the rendering loop but in response to other events the context needs to be made current. This includes the loading and unloading of effects (some effects use OpenGL in the static effect check, in the ctor and dtor), background loading of texture data, lazy loading after first usage invoked by shortcut, etc. etc. To properly handle these cases new methods are added to EffectsHandler to make the compositing OpenGL context current. These calls delegate down into the scene. On non-OpenGL scenes they are noop, but on OpenGL they go into the backend and make the context current. In addition they ensure that Qt doesn't think that it's QOpenGLContext is current by calling doneCurrent() on the QOpenGLContext::currentContext(). This unfortunately causes an additional call to makeCurrent with a null context, but there is no other way to tell Qt - it doesn't notice when a different context is made current with low level API calls. In the multi-threaded architecture this doesn't matter as ::currentContext() returns null. A short evaluation showed that a transition to QOpenGLContext doesn't seem feasible. Qt only supports either GLX or EGL while KWin supports both and when entering the transition phase for Wayland, it would become extremely tricky if our native platform is X11, but we want a Wayland EGL context. A future solution might be to have a "KWin-QPA plugin" which uses either xcb or Wayland and hides everything from Qt. The API documentation is extended to describe when the effects-framework ensures that an OpenGL context is current. The effects are changed to make the context current in cases where it's not guaranteed. This has been done by looking for creation or deletion of GLTextures and Shaders. If there are other OpenGL usages outside the rendering loop, ctor/dtor this needs to be changed, too.
2013-11-22 18:05:36 +04:00
2011-01-30 17:34:42 +03:00
// internal (used by kwin core or compositing code)
void startPaint();
void grabbedKeyboardEvent(QKeyEvent* e);
bool hasKeyboardGrab() const;
void desktopResized(const QSize &size);
2011-01-30 17:34:42 +03:00
void reloadEffect(Effect *effect) override;
2011-01-30 17:34:42 +03:00
QStringList loadedEffects() const;
QStringList listOfEffects() const;
QList<EffectWindow*> elevatedWindows() const;
QStringList activeEffects() const;
2011-01-30 17:34:42 +03:00
/**
* @returns Whether we are currently in a desktop rendering process triggered by paintDesktop hook
**/
bool isDesktopRendering() const {
return m_desktopRendering;
}
/**
* @returns the desktop currently being rendered in the paintDesktop hook.
**/
int currentRenderedDesktop() const {
return m_currentRenderedDesktop;
}
public Q_SLOTS:
void slotCurrentTabAboutToChange(EffectWindow* from, EffectWindow* to);
void slotTabAdded(EffectWindow* from, EffectWindow* to);
void slotTabRemoved(EffectWindow* c, EffectWindow* newActiveWindow);
// slots for D-Bus interface
Q_SCRIPTABLE void reconfigureEffect(const QString& name);
Q_SCRIPTABLE bool loadEffect(const QString& name, bool checkDefault = false);
Q_SCRIPTABLE void toggleEffect(const QString& name);
Q_SCRIPTABLE void unloadEffect(const QString& name);
Q_SCRIPTABLE bool isEffectLoaded(const QString& name) const;
Q_SCRIPTABLE QString supportInformation(const QString& name) const;
Q_SCRIPTABLE QString debug(const QString& name, const QString& parameter = QString()) const;
protected Q_SLOTS:
void slotDesktopChanged(int old, KWin::Client *withClient);
void slotDesktopPresenceChanged(KWin::Client *c, int old);
void slotClientAdded(KWin::Client *c);
void slotClientShown(KWin::Toplevel*);
void slotUnmanagedAdded(KWin::Unmanaged *u);
void slotUnmanagedShown(KWin::Toplevel*);
void slotWindowClosed(KWin::Toplevel *c);
void slotClientActivated(KWin::Client *c);
void slotDeletedRemoved(KWin::Deleted *d);
void slotClientMaximized(KWin::Client *c, KDecorationDefines::MaximizeMode maxMode);
void slotClientStartUserMovedResized(KWin::Client *c);
void slotClientStepUserMovedResized(KWin::Client *c, const QRect &geometry);
void slotClientFinishUserMovedResized(KWin::Client *c);
2011-03-06 12:30:23 +03:00
void slotOpacityChanged(KWin::Toplevel *t, qreal oldOpacity);
2011-03-06 12:55:27 +03:00
void slotClientMinimized(KWin::Client *c, bool animate);
2011-03-06 13:08:19 +03:00
void slotClientUnminimized(KWin::Client *c, bool animate);
void slotClientModalityChanged();
void slotGeometryShapeChanged(KWin::Toplevel *t, const QRect &old);
void slotPaddingChanged(KWin::Toplevel *t, const QRect &old);
2011-03-12 17:04:22 +03:00
void slotWindowDamaged(KWin::Toplevel *t, const QRect& r);
2011-03-12 21:18:19 +03:00
void slotPropertyNotify(KWin::Toplevel *t, long atom);
void slotPropertyNotify(long atom);
2011-01-30 17:34:42 +03:00
protected:
bool loadScriptedEffect(const QString &name, KService *service);
2011-01-30 17:34:42 +03:00
KLibrary* findEffectLibrary(KService* service);
void effectsChanged();
void setupClientConnections(KWin::Client *c);
void setupUnmanagedConnections(KWin::Unmanaged *u);
2011-01-30 17:34:42 +03:00
Effect* keyboard_grab_effect;
Effect* fullscreen_effect;
QList<EffectWindow*> elevated_windows;
QMultiMap< int, EffectPair > effect_order;
QHash< long, int > registered_atoms;
int next_window_quad_type;
private Q_SLOTS:
void slotEffectsQueried();
private:
typedef QVector< Effect*> EffectsList;
typedef EffectsList::const_iterator EffectsIterator;
Effect *loadBuiltInEffect(const QByteArray &name, bool checkDefault);
EffectsList m_activeEffects;
EffectsIterator m_currentDrawWindowIterator;
EffectsIterator m_currentPaintWindowIterator;
EffectsIterator m_currentPaintEffectFrameIterator;
EffectsIterator m_currentPaintScreenIterator;
EffectsIterator m_currentBuildQuadsIterator;
typedef QHash< QByteArray, QList< Effect*> > PropertyEffectMap;
PropertyEffectMap m_propertiesForEffects;
QHash<QByteArray, qulonglong> m_managedProperties;
Compositor *m_compositor;
Scene *m_scene;
ScreenLockerWatcher *m_screenLockerWatcher;
bool m_desktopRendering;
int m_currentRenderedDesktop;
Xcb::Window m_mouseInterceptionWindow;
QList<Effect*> m_grabbedMouseEffects;
EffectLoader *m_effectLoader;
};
2011-12-29 13:31:37 +04:00
class EffectWindowImpl : public EffectWindow
{
Q_OBJECT
2011-01-30 17:34:42 +03:00
public:
explicit EffectWindowImpl(Toplevel *toplevel);
2011-01-30 17:34:42 +03:00
virtual ~EffectWindowImpl();
virtual void enablePainting(int reason);
virtual void disablePainting(int reason);
virtual bool isPaintingEnabled();
virtual void refWindow();
virtual void unrefWindow();
virtual const EffectWindowGroup* group() const;
virtual QRegion shape() const;
virtual QRect decorationInnerRect() const;
virtual QByteArray readProperty(long atom, long type, int format) const;
virtual void deleteProperty(long atom) const;
virtual EffectWindow* findModal();
virtual EffectWindowList mainWindows() const;
virtual WindowQuadList buildQuads(bool force = false) const;
virtual void referencePreviousWindowPixmap();
virtual void unreferencePreviousWindowPixmap();
2011-01-30 17:34:42 +03:00
const Toplevel* window() const;
Toplevel* window();
void setWindow(Toplevel* w); // internal
void setSceneWindow(Scene::Window* w); // internal
const Scene::Window* sceneWindow() const; // internal
Scene::Window* sceneWindow(); // internal
void elevate(bool elevate);
2011-01-30 17:34:42 +03:00
void setData(int role, const QVariant &data);
QVariant data(int role) const;
void registerThumbnail(AbstractThumbnailItem *item);
QHash<WindowThumbnailItem*, QWeakPointer<EffectWindowImpl> > const &thumbnails() const {
return m_thumbnails;
}
QList<DesktopThumbnailItem*> const &desktopThumbnails() const {
return m_desktopThumbnails;
}
private Q_SLOTS:
void thumbnailDestroyed(QObject *object);
void thumbnailTargetChanged();
void desktopThumbnailDestroyed(QObject *object);
2011-01-30 17:34:42 +03:00
private:
void insertThumbnail(WindowThumbnailItem *item);
2011-01-30 17:34:42 +03:00
Toplevel* toplevel;
Scene::Window* sw; // This one is used only during paint pass.
QHash<int, QVariant> dataMap;
QHash<WindowThumbnailItem*, QWeakPointer<EffectWindowImpl> > m_thumbnails;
QList<DesktopThumbnailItem*> m_desktopThumbnails;
};
class EffectWindowGroupImpl
: public EffectWindowGroup
2011-01-30 17:34:42 +03:00
{
public:
explicit EffectWindowGroupImpl(Group* g);
2011-01-30 17:34:42 +03:00
virtual EffectWindowList members() const;
private:
Group* group;
};
class EffectFrameImpl
: public QObject, public EffectFrame
2011-01-30 17:34:42 +03:00
{
Q_OBJECT
2011-01-30 17:34:42 +03:00
public:
explicit EffectFrameImpl(EffectFrameStyle style, bool staticSize = true, QPoint position = QPoint(-1, -1),
Qt::Alignment alignment = Qt::AlignCenter);
virtual ~EffectFrameImpl();
virtual void free();
virtual void render(QRegion region = infiniteRegion(), double opacity = 1.0, double frameOpacity = 1.0);
virtual Qt::Alignment alignment() const;
virtual void setAlignment(Qt::Alignment alignment);
virtual const QFont& font() const;
virtual void setFont(const QFont& font);
virtual const QRect& geometry() const;
virtual void setGeometry(const QRect& geometry, bool force = false);
virtual const QIcon& icon() const override;
virtual void setIcon(const QIcon& icon) override;
2011-01-30 17:34:42 +03:00
virtual const QSize& iconSize() const;
virtual void setIconSize(const QSize& size);
virtual void setPosition(const QPoint& point);
virtual const QString& text() const;
virtual void setText(const QString& text);
virtual EffectFrameStyle style() const {
2011-01-30 17:34:42 +03:00
return m_style;
};
Plasma::FrameSvg& frame() {
return m_frame;
}
bool isStatic() const {
return m_static;
};
2011-01-30 17:34:42 +03:00
void finalRender(QRegion region, double opacity, double frameOpacity) const;
virtual void setShader(GLShader* shader) {
m_shader = shader;
}
virtual GLShader* shader() const {
return m_shader;
}
virtual void setSelection(const QRect& selection);
const QRect& selection() const {
return m_selectionGeometry;
}
Plasma::FrameSvg& selectionFrame() {
return m_selection;
}
/**
* The foreground text color as specified by the default Plasma theme.
*/
QColor styledTextColor();
2011-01-30 17:34:42 +03:00
private Q_SLOTS:
void plasmaThemeChanged();
private:
Q_DISABLE_COPY(EffectFrameImpl) // As we need to use Qt slots we cannot copy this class
void align(QRect &geometry); // positions geometry around m_point respecting m_alignment
void autoResize(); // Auto-resize if not a static size
EffectFrameStyle m_style;
Plasma::FrameSvg m_frame; // TODO: share between all EffectFrames
Plasma::FrameSvg m_selection;
// Position
bool m_static;
QPoint m_point;
Qt::Alignment m_alignment;
QRect m_geometry;
// Contents
QString m_text;
QFont m_font;
QIcon m_icon;
2011-01-30 17:34:42 +03:00
QSize m_iconSize;
QRect m_selectionGeometry;
Scene::EffectFrame* m_sceneFrame;
GLShader* m_shader;
Plasma::Theme *m_theme;
2011-01-30 17:34:42 +03:00
};
class ScreenLockerWatcher : public QObject
{
Q_OBJECT
public:
explicit ScreenLockerWatcher(QObject *parent = 0);
virtual ~ScreenLockerWatcher();
bool isLocked() const {
return m_locked;
}
Q_SIGNALS:
void locked(bool locked);
private Q_SLOTS:
void setLocked(bool activated);
void activeQueried(QDBusPendingCallWatcher *watcher);
void serviceOwnerChanged(const QString &serviceName, const QString &oldOwner, const QString &newOwner);
void serviceRegisteredQueried();
void serviceOwnerQueried();
private:
OrgFreedesktopScreenSaverInterface *m_interface;
QDBusServiceWatcher *m_serviceWatcher;
bool m_locked;
};
class EffectLoader : public QObject
{
Q_OBJECT
public:
explicit EffectLoader(EffectsHandlerImpl *parent);
virtual ~EffectLoader();
void queue(const QString &effect, bool checkDefault = false);
private Q_SLOTS:
void dequeue();
private:
void scheduleDequeue();
EffectsHandlerImpl *m_effects;
QQueue<QPair<QString, bool>> m_queue;
bool m_dequeueScheduled;
};
inline
QList<EffectWindow*> EffectsHandlerImpl::elevatedWindows() const
2011-01-30 17:34:42 +03:00
{
return elevated_windows;
2011-01-30 17:34:42 +03:00
}
inline
2011-01-30 17:34:42 +03:00
EffectWindowGroupImpl::EffectWindowGroupImpl(Group* g)
: group(g)
{
}
2011-01-30 17:34:42 +03:00
EffectWindow* effectWindow(Toplevel* w);
EffectWindow* effectWindow(Scene::Window* w);
inline
const Scene::Window* EffectWindowImpl::sceneWindow() const
2011-01-30 17:34:42 +03:00
{
return sw;
2011-01-30 17:34:42 +03:00
}
inline
Scene::Window* EffectWindowImpl::sceneWindow()
2011-01-30 17:34:42 +03:00
{
return sw;
2011-01-30 17:34:42 +03:00
}
inline
const Toplevel* EffectWindowImpl::window() const
2011-01-30 17:34:42 +03:00
{
return toplevel;
2011-01-30 17:34:42 +03:00
}
inline
Toplevel* EffectWindowImpl::window()
2011-01-30 17:34:42 +03:00
{
return toplevel;
2011-01-30 17:34:42 +03:00
}
} // namespace
#endif