Change the way how screen edges interact with Effects/Scripts

The main difference is that the activation of an edge is no longer
broadcasted to all effects and scripts, but instead a passed in slot of
the Effect/Script is invoked.

For this the EffectsHandler API is changed to take the Effect as an
argument to (un)reserveElectricBorder. As callback slot the existing
borderActivated is used.

In addition the ScreenEdge monitors the object for beeing destroyed and
unregisters the the edge automatically. This removes the need from the
Effect to call unregister in the dtor.

BUG: 309695
FIXED-IN: 4.11
icc-effect-5.14.5
Martin Gräßlin 2013-01-22 12:47:06 +01:00
parent d9aedf620b
commit 7a7f9d1a34
14 changed files with 105 additions and 140 deletions

View File

@ -536,15 +536,6 @@ Effect* EffectsHandlerImpl::activeFullScreenEffect() const
return fullscreen_effect;
}
bool EffectsHandlerImpl::borderActivated(ElectricBorder border)
{
bool ret = false;
foreach (const EffectPair & ep, loaded_effects)
if (ep.second->borderActivated(border))
ret = true; // bail out or tell all?
return ret;
}
bool EffectsHandlerImpl::grabKeyboard(Effect* effect)
{
if (keyboard_grab_effect != NULL)
@ -1187,21 +1178,23 @@ QPoint EffectsHandlerImpl::cursorPos() const
return Workspace::self()->cursorPos();
}
void EffectsHandlerImpl::reserveElectricBorder(ElectricBorder border)
void EffectsHandlerImpl::reserveElectricBorder(ElectricBorder border, Effect *effect)
{
#ifdef KWIN_BUILD_SCREENEDGES
Workspace::self()->screenEdge()->reserve(border);
Workspace::self()->screenEdge()->reserve(border, effect, "borderActivated");
#else
Q_UNUSED(border)
Q_UNUSED(effect)
#endif
}
void EffectsHandlerImpl::unreserveElectricBorder(ElectricBorder border)
void EffectsHandlerImpl::unreserveElectricBorder(ElectricBorder border, Effect *effect)
{
#ifdef KWIN_BUILD_SCREENEDGES
Workspace::self()->screenEdge()->unreserve(border);
Workspace::self()->screenEdge()->unreserve(border, effect);
#else
Q_UNUSED(border)
Q_UNUSED(effect)
#endif
}

View File

@ -140,8 +140,8 @@ public:
virtual bool checkInputWindowEvent(XEvent* e);
virtual void checkInputWindowStacking();
virtual void reserveElectricBorder(ElectricBorder border);
virtual void unreserveElectricBorder(ElectricBorder border);
virtual void reserveElectricBorder(ElectricBorder border, Effect *effect);
virtual void unreserveElectricBorder(ElectricBorder border, Effect *effect);
virtual unsigned long xrenderBufferPicture();
virtual void reconfigure();
@ -163,7 +163,6 @@ public:
// internal (used by kwin core or compositing code)
void startPaint();
bool borderActivated(ElectricBorder border);
void grabbedKeyboardEvent(QKeyEvent* e);
bool hasKeyboardGrab() const;
void desktopResized(const QSize &size);

View File

@ -122,13 +122,13 @@ void CubeEffect::reconfigure(ReconfigureFlags)
{
CubeConfig::self()->readConfig();
foreach (ElectricBorder border, borderActivate) {
effects->unreserveElectricBorder(border);
effects->unreserveElectricBorder(border, this);
}
foreach (ElectricBorder border, borderActivateCylinder) {
effects->unreserveElectricBorder(border);
effects->unreserveElectricBorder(border, this);
}
foreach (ElectricBorder border, borderActivateSphere) {
effects->unreserveElectricBorder(border);
effects->unreserveElectricBorder(border, this);
}
borderActivate.clear();
borderActivateCylinder.clear();
@ -138,21 +138,21 @@ void CubeEffect::reconfigure(ReconfigureFlags)
borderList = CubeConfig::borderActivate();
foreach (int i, borderList) {
borderActivate.append(ElectricBorder(i));
effects->reserveElectricBorder(ElectricBorder(i));
effects->reserveElectricBorder(ElectricBorder(i), this);
}
borderList.clear();
borderList.append(int(ElectricNone));
borderList = CubeConfig::borderActivateCylinder();
foreach (int i, borderList) {
borderActivateCylinder.append(ElectricBorder(i));
effects->reserveElectricBorder(ElectricBorder(i));
effects->reserveElectricBorder(ElectricBorder(i), this);
}
borderList.clear();
borderList.append(int(ElectricNone));
borderList = CubeConfig::borderActivateSphere();
foreach (int i, borderList) {
borderActivateSphere.append(ElectricBorder(i));
effects->reserveElectricBorder(ElectricBorder(i));
effects->reserveElectricBorder(ElectricBorder(i), this);
}
cubeOpacity = (float)CubeConfig::opacity() / 100.0f;
@ -217,15 +217,6 @@ void CubeEffect::reconfigure(ReconfigureFlags)
CubeEffect::~CubeEffect()
{
foreach (ElectricBorder border, borderActivate) {
effects->unreserveElectricBorder(border);
}
foreach (ElectricBorder border, borderActivateCylinder) {
effects->unreserveElectricBorder(border);
}
foreach (ElectricBorder border, borderActivateSphere) {
effects->unreserveElectricBorder(border);
}
delete wallpaper;
delete capTexture;
delete cylinderShader;

View File

@ -89,9 +89,6 @@ DesktopGridEffect::DesktopGridEffect()
DesktopGridEffect::~DesktopGridEffect()
{
foreach (ElectricBorder border, borderActivate) {
effects->unreserveElectricBorder(border);
}
QHash< DesktopButtonsView*, EffectWindow* >::iterator i = m_desktopButtonsViews.begin();
while (i != m_desktopButtonsViews.end()) {
DesktopButtonsView *view = i.key();
@ -105,12 +102,12 @@ void DesktopGridEffect::reconfigure(ReconfigureFlags)
DesktopGridConfig::self()->readConfig();
foreach (ElectricBorder border, borderActivate) {
effects->unreserveElectricBorder(border);
effects->unreserveElectricBorder(border, this);
}
borderActivate.clear();
foreach (int i, DesktopGridConfig::borderActivate()) {
borderActivate.append(ElectricBorder(i));
effects->reserveElectricBorder(ElectricBorder(i));
effects->reserveElectricBorder(ElectricBorder(i), this);
}
// TODO: rename zoomDuration to duration

View File

@ -79,12 +79,6 @@ FlipSwitchEffect::FlipSwitchEffect()
FlipSwitchEffect::~FlipSwitchEffect()
{
foreach (ElectricBorder border, m_borderActivate) {
effects->unreserveElectricBorder(border);
}
foreach (ElectricBorder border, m_borderActivateAll) {
effects->unreserveElectricBorder(border);
}
delete m_captionFrame;
}
@ -97,20 +91,20 @@ void FlipSwitchEffect::reconfigure(ReconfigureFlags)
{
FlipSwitchConfig::self()->readConfig();
foreach (ElectricBorder border, m_borderActivate) {
effects->unreserveElectricBorder(border);
effects->unreserveElectricBorder(border, this);
}
foreach (ElectricBorder border, m_borderActivateAll) {
effects->unreserveElectricBorder(border);
effects->unreserveElectricBorder(border, this);
}
m_borderActivate.clear();
m_borderActivateAll.clear();
foreach (int i, FlipSwitchConfig::borderActivate()) {
m_borderActivate.append(ElectricBorder(i));
effects->reserveElectricBorder(ElectricBorder(i));
effects->reserveElectricBorder(ElectricBorder(i), this);
}
foreach (int i, FlipSwitchConfig::borderActivateAll()) {
m_borderActivateAll.append(ElectricBorder(i));
effects->reserveElectricBorder(ElectricBorder(i));
effects->reserveElectricBorder(ElectricBorder(i), this);
}
m_tabbox = FlipSwitchConfig::tabBox();
m_tabboxAlternative = FlipSwitchConfig::tabBoxAlternative();

View File

@ -103,12 +103,6 @@ PresentWindowsEffect::PresentWindowsEffect()
PresentWindowsEffect::~PresentWindowsEffect()
{
foreach (ElectricBorder border, m_borderActivate) {
effects->unreserveElectricBorder(border);
}
foreach (ElectricBorder border, m_borderActivateAll) {
effects->unreserveElectricBorder(border);
}
delete m_filterFrame;
delete m_closeView;
}
@ -117,24 +111,24 @@ void PresentWindowsEffect::reconfigure(ReconfigureFlags)
{
PresentWindowsConfig::self()->readConfig();
foreach (ElectricBorder border, m_borderActivate) {
effects->unreserveElectricBorder(border);
effects->unreserveElectricBorder(border, this);
}
foreach (ElectricBorder border, m_borderActivateAll) {
effects->unreserveElectricBorder(border);
effects->unreserveElectricBorder(border, this);
}
m_borderActivate.clear();
m_borderActivateAll.clear();
foreach (int i, PresentWindowsConfig::borderActivate()) {
m_borderActivate.append(ElectricBorder(i));
effects->reserveElectricBorder(ElectricBorder(i));
effects->reserveElectricBorder(ElectricBorder(i), this);
}
foreach (int i, PresentWindowsConfig::borderActivateAll()) {
m_borderActivateAll.append(ElectricBorder(i));
effects->reserveElectricBorder(ElectricBorder(i));
effects->reserveElectricBorder(ElectricBorder(i), this);
}
foreach (int i, PresentWindowsConfig::borderActivateClass()) {
m_borderActivateClass.append(ElectricBorder(i));
effects->reserveElectricBorder(ElectricBorder(i));
effects->reserveElectricBorder(ElectricBorder(i), this);
}
m_layoutMode = PresentWindowsConfig::layoutMode();
m_showCaptions = PresentWindowsConfig::drawWindowCaptions();

View File

@ -437,8 +437,6 @@ public:
virtual void windowInputMouseEvent(Window w, QEvent* e);
virtual void grabbedKeyboardEvent(QKeyEvent* e);
virtual bool borderActivated(ElectricBorder border);
/**
* Overwrite this method to indicate whether your effect will be doing something in
* the next frame to be rendered. If the method returns @c false the effect will be
@ -495,6 +493,9 @@ public:
**/
static void setPositionTransformations(WindowPaintData& data, QRect& region, EffectWindow* w,
const QRect& r, Qt::AspectRatioMode aspect);
public Q_SLOTS:
virtual bool borderActivated(ElectricBorder border);
};
@ -651,8 +652,8 @@ public:
virtual void startMousePolling() = 0;
virtual void stopMousePolling() = 0;
virtual void reserveElectricBorder(ElectricBorder border) = 0;
virtual void unreserveElectricBorder(ElectricBorder border) = 0;
virtual void reserveElectricBorder(ElectricBorder border, Effect *effect) = 0;
virtual void unreserveElectricBorder(ElectricBorder border, Effect *effect) = 0;
// functions that allow controlling windows/desktop
virtual void activateWindow(KWin::EffectWindow* c) = 0;

View File

@ -74,6 +74,13 @@ void Edge::reserve()
}
}
void Edge::reserve(QObject *object, const char *slot)
{
connect(object, SIGNAL(destroyed(QObject*)), SLOT(unreserve(QObject*)));
m_callBacks.insert(object, QByteArray(slot));
reserve();
}
void Edge::unreserve()
{
m_reserved--;
@ -82,6 +89,14 @@ void Edge::unreserve()
deactivate();
}
}
void Edge::unreserve(QObject *object)
{
if (m_callBacks.contains(object)) {
m_callBacks.remove(object);
disconnect(object, SIGNAL(destroyed(QObject*)), this, SLOT(unreserve(QObject*)));
unreserve();
}
}
bool Edge::triggersFor(const QPoint &cursorPos) const
{
@ -149,17 +164,14 @@ void Edge::handle(const QPoint &cursorPos)
switchDesktop(cursorPos);
return;
}
if (handleAction() || handleByEffects()) {
if (handleAction() || handleByCallback()) {
pushCursorBack(cursorPos);
return;
}
if (edges()->isDesktopSwitching() && isCorner()) {
// try again desktop switching for the corner
switchDesktop(cursorPos);
return;
}
// fallback notify world that edge got activated
emit activated(m_border);
}
bool Edge::handleAction()
@ -184,12 +196,21 @@ bool Edge::handleAction()
}
}
bool Edge::handleByEffects()
bool Edge::handleByCallback()
{
if (!effects) {
if (m_callBacks.isEmpty()) {
return false;
}
return static_cast<EffectsHandlerImpl*>(effects)->borderActivated(m_border);
for (QHash<QObject *, QByteArray>::iterator it = m_callBacks.begin();
it != m_callBacks.end();
++it) {
bool retVal = false;
QMetaObject::invokeMethod(it.key(), it.value().constData(), Q_RETURN_ARG(bool, retVal), Q_ARG(ElectricBorder, m_border));
if (retVal) {
return true;
}
}
return false;
}
void Edge::switchDesktop(const QPoint &cursorPos)
@ -333,14 +354,6 @@ ScreenEdges::ScreenEdges(QObject *parent)
, m_actionBottomLeft(ElectricActionNone)
, m_actionLeft(ElectricActionNone)
{
m_externalReservations.insert(ElectricTopLeft, 0);
m_externalReservations.insert(ElectricTop, 0);
m_externalReservations.insert(ElectricTopRight, 0);
m_externalReservations.insert(ElectricRight, 0);
m_externalReservations.insert(ElectricBottomRight, 0);
m_externalReservations.insert(ElectricBottom, 0);
m_externalReservations.insert(ElectricBottomLeft, 0);
m_externalReservations.insert(ElectricLeft, 0);
}
ScreenEdges::~ScreenEdges()
@ -568,7 +581,7 @@ static bool isBottomScreen(const QRect &screen, const QRect &fullArea)
void ScreenEdges::recreateEdges()
{
qDeleteAll(m_edges);
QList<WindowBasedEdge*> oldEdges(m_edges);
m_edges.clear();
const QRect fullArea(0, 0, displayWidth(), displayHeight());
const QDesktopWidget *desktop = QApplication::desktop();
@ -591,6 +604,25 @@ void ScreenEdges::recreateEdges()
createHorizontalEdge(ElectricBottom, screen, fullArea);
}
}
// copy over the effect/script reservations from the old edges
for (QList<WindowBasedEdge*>::iterator it = m_edges.begin(); it != m_edges.end(); ++it) {
WindowBasedEdge *edge = *it;
for (QList<WindowBasedEdge*>::const_iterator oldIt = oldEdges.constBegin();
oldIt != oldEdges.constEnd();
++oldIt) {
WindowBasedEdge *oldEdge = *oldIt;
if (oldEdge->border() != edge->border()) {
continue;
}
const QHash<QObject *, QByteArray> &callbacks = oldEdge->callBacks();
for (QHash<QObject *, QByteArray>::const_iterator callback = callbacks.begin();
callback != callbacks.end();
++callback) {
edge->reserve(callback.key(), callback.value().constData());
}
}
}
qDeleteAll(oldEdges);
}
void ScreenEdges::createVerticalEdge(ElectricBorder border, const QRect &screen, const QRect &fullArea)
@ -662,13 +694,6 @@ WindowBasedEdge *ScreenEdges::createEdge(ElectricBorder border, int x, int y, in
}
}
}
QHash<ElectricBorder, int>::const_iterator it = m_externalReservations.constFind(border);
if (it != m_externalReservations.constEnd()) {
for (int i=0; i<it.value(); ++i) {
edge->reserve();
}
}
connect(edge, SIGNAL(activated(ElectricBorder)), SIGNAL(activated(ElectricBorder)));
return edge;
}
@ -717,28 +742,20 @@ void ScreenEdges::reserveDesktopSwitching(bool isToReserve, Qt::Orientations o)
}
}
void ScreenEdges::reserve(ElectricBorder border)
void ScreenEdges::reserve(ElectricBorder border, QObject *object, const char *slot)
{
QHash<ElectricBorder, int>::iterator it = m_externalReservations.find(border);
if (it != m_externalReservations.end()) {
m_externalReservations.insert(border, it.value() + 1);
}
for (QList<WindowBasedEdge*>::iterator it = m_edges.begin(); it != m_edges.end(); ++it) {
if ((*it)->border() == border) {
(*it)->reserve();
(*it)->reserve(object, slot);
}
}
}
void ScreenEdges::unreserve(ElectricBorder border)
void ScreenEdges::unreserve(ElectricBorder border, QObject *object)
{
QHash<ElectricBorder, int>::iterator it = m_externalReservations.find(border);
if (it != m_externalReservations.end()) {
m_externalReservations.insert(border, it.value() - 1);
}
for (QList<WindowBasedEdge*>::iterator it = m_edges.begin(); it != m_edges.end(); ++it) {
if ((*it)->border() == border) {
(*it)->unreserve();
(*it)->unreserve(object);
}
}
}

View File

@ -59,20 +59,16 @@ public:
bool isReserved() const;
ElectricBorder border() const;
void reserve(QObject *object, const char *slot);
const QHash<QObject *, QByteArray> &callBacks() const;
public Q_SLOTS:
void reserve();
void unreserve();
void unreserve(QObject *object);
void setBorder(ElectricBorder border);
void setAction(ElectricBorderAction action);
void setGeometry(const QRect &geometry);
Q_SIGNALS:
/**
* Emitted when the @p border got activated and there is neither an effect nor a global
* action configured for this @p border.
* @param border The border which got activated
**/
void activated(ElectricBorder border);
protected:
ScreenEdges *edges();
const ScreenEdges *edges() const;
@ -84,7 +80,7 @@ private:
bool canActivate(const QPoint &cursorPos, const QDateTime &triggerTime);
void handle(const QPoint &cursorPos);
bool handleAction();
bool handleByEffects();
bool handleByCallback();
void switchDesktop(const QPoint &cursorPos);
void pushCursorBack(const QPoint &cursorPos);
ScreenEdges *m_edges;
@ -95,6 +91,7 @@ private:
QDateTime m_lastTrigger;
QDateTime m_lastReset;
QPoint m_triggeredPoint;
QHash<QObject *, QByteArray> m_callBacks;
};
class WindowBasedEdge : public Edge
@ -200,20 +197,23 @@ public:
* like effects and scripts. When the effect/script does no longer need the edge it is supposed
* to call @link unreserve.
* @param border the screen edge to mark as reserved
* @param object The object on which the @p callback needs to be invoked
* @param callback The method name to be invoked - uses QMetaObject::invokeMethod
* @see unreserve
* @todo: add pointer to script/effect
*/
void reserve(ElectricBorder border);
void reserve(ElectricBorder border, QObject *object, const char *callback);
/**
* Mark the specified screen edge as unreserved. This method is provided for external activation
* like effects and scripts. This method is only allowed to be called if @link reserve had been
* called before for the same @p border. An unbalanced calling of reserve/unreserve leads to the
* edge never being active or never being able to deactivate again.
* @param border the screen edge to mark as unreserved
* @see unreserve
* @param object the object on which the callback had been invoked
* @see reserve
* @todo: add pointer to script/effect
*/
void unreserve(ElectricBorder border);
void unreserve(ElectricBorder border, QObject *object);
/**
* Reserve desktop switching for screen edges, if @p isToReserve is @c true. Unreserve otherwise.
* @param reserve indicated weather desktop switching should be reserved or unreseved
@ -272,13 +272,6 @@ public Q_SLOTS:
* Recreates all edges e.g. after the screen size changes.
**/
void recreateEdges();
Q_SIGNALS:
/**
* Emitted when the @p border got activated and there is neither an effect nor a global
* action configured for this @p border.
* @param border The border which got activated
**/
void activated(ElectricBorder border);
private:
enum { ElectricDisabled = 0, ElectricMoveOnly = 1, ElectricAlways = 2 };
void setDesktopSwitching(bool enable);
@ -307,7 +300,6 @@ private:
ElectricBorderAction m_actionBottom;
ElectricBorderAction m_actionBottomLeft;
ElectricBorderAction m_actionLeft;
QHash<ElectricBorder, int> m_externalReservations;
};
/**********************************************************
@ -394,6 +386,11 @@ inline ElectricBorder Edge::border() const
return m_border;
}
inline const QHash< QObject *, QByteArray > &Edge::callBacks() const
{
return m_callBacks;
}
/**********************************************************
* Inlines WindowBasedEdge
*********************************************************/

View File

@ -272,20 +272,10 @@ ScriptedEffect::ScriptedEffect()
, m_scriptFile(QString())
{
connect(m_engine, SIGNAL(signalHandlerException(QScriptValue)), SLOT(signalHandlerException(QScriptValue)));
#ifdef KWIN_BUILD_SCREENEDGES
connect(Workspace::self()->screenEdge(), SIGNAL(activated(ElectricBorder)), SLOT(slotBorderActivated(ElectricBorder)));
#endif
}
ScriptedEffect::~ScriptedEffect()
{
#ifdef KWIN_BUILD_SCREENEDGES
for (QHash<int, QList<QScriptValue> >::const_iterator it = m_screenEdgeCallbacks.constBegin();
it != m_screenEdgeCallbacks.constEnd();
++it) {
KWin::Workspace::self()->screenEdge()->unreserve(static_cast<KWin::ElectricBorder>(it.key()));
}
#endif
}
bool ScriptedEffect::init(const QString &effectName, const QString &pathToScript)
@ -410,9 +400,10 @@ void ScriptedEffect::globalShortcutTriggered()
callGlobalShortcutCallback<KWin::ScriptedEffect*>(this, sender());
}
void ScriptedEffect::slotBorderActivated(ElectricBorder edge)
bool ScriptedEffect::borderActivated(ElectricBorder edge)
{
screenEdgeActivated(this, edge);
return true;
}
QVariant ScriptedEffect::readConfig(const QString &key, const QVariant defaultValue)

View File

@ -128,6 +128,7 @@ public:
public Q_SLOTS:
void animate(KWin::EffectWindow *w, Attribute a, int ms, KWin::FPx2 to, KWin::FPx2 from = KWin::FPx2(), KWin::AnimationData *data = NULL, QEasingCurve::Type curve = QEasingCurve::Linear, int delay = 0);
virtual bool borderActivated(ElectricBorder border);
Q_SIGNALS:
/**
@ -138,7 +139,6 @@ Q_SIGNALS:
private Q_SLOTS:
void signalHandlerException(const QScriptValue &value);
void globalShortcutTriggered();
void slotBorderActivated(ElectricBorder edge);
private:
ScriptedEffect();
bool init(const QString &effectName, const QString &pathToScript);

View File

@ -215,20 +215,10 @@ KWin::AbstractScript::AbstractScript(int id, QString scriptName, QString pluginN
if (m_pluginName.isNull()) {
m_pluginName = scriptName;
}
#ifdef KWIN_BUILD_SCREENEDGES
connect(KWin::Workspace::self()->screenEdge(), SIGNAL(activated(ElectricBorder)), SLOT(borderActivated(ElectricBorder)));
#endif
}
KWin::AbstractScript::~AbstractScript()
{
#ifdef KWIN_BUILD_SCREENEDGES
for (QHash<int, QList<QScriptValue> >::const_iterator it = m_screenEdgeCallbacks.constBegin();
it != m_screenEdgeCallbacks.constEnd();
++it) {
KWin::Workspace::self()->screenEdge()->unreserve(static_cast<KWin::ElectricBorder>(it.key()));
}
#endif
}
KConfigGroup KWin::AbstractScript::config() const
@ -258,9 +248,10 @@ void KWin::AbstractScript::globalShortcutTriggered()
callGlobalShortcutCallback<KWin::AbstractScript*>(this, sender());
}
void KWin::AbstractScript::borderActivated(KWin::ElectricBorder edge)
bool KWin::AbstractScript::borderActivated(KWin::ElectricBorder edge)
{
screenEdgeActivated(this, edge);
return true;
}
void KWin::AbstractScript::installScriptFunctions(QScriptEngine* engine)

View File

@ -134,7 +134,7 @@ public Q_SLOTS:
private Q_SLOTS:
void globalShortcutTriggered();
void borderActivated(ElectricBorder edge);
bool borderActivated(ElectricBorder edge);
/**
* @brief Slot invoked when a menu action is destroyed. Used to remove the action and callback
* from the map of actions.

View File

@ -162,7 +162,7 @@ QScriptValue registerScreenEdge(QScriptContext *context, QScriptEngine *engine)
if (it == script->screenEdgeCallbacks().end()) {
// not yet registered
#ifdef KWIN_BUILD_SCREENEDGES
KWin::Workspace::self()->screenEdge()->reserve(static_cast<KWin::ElectricBorder>(edge));
KWin::Workspace::self()->screenEdge()->reserve(static_cast<KWin::ElectricBorder>(edge), script, "borderActivated");
#endif
script->screenEdgeCallbacks().insert(edge, QList<QScriptValue>() << context->argument(1));
} else {