Screen Edge bindings for Scripts and Scripted Effects
ScreenEdge is changed to emit a signal whenever a screen edge got activated without an action or effect taking care of it. A Script can reserve one to many callbacks for an edge and the callback get's triggered whenever the signal is emitted. On deconstruction of the Script the edge is unreserved again. FEATURE: 299275 FIXED-IN: 4.9.0 REVIEW: 104904
This commit is contained in:
parent
7c8aa660d1
commit
c9c4e020e2
9 changed files with 149 additions and 3 deletions
|
@ -289,8 +289,11 @@ void ScreenEdge::check(const QPoint& pos, Time now)
|
|||
if (effects && static_cast<EffectsHandlerImpl*>(effects)->borderActivated(border))
|
||||
{} // Handled by effects
|
||||
else {
|
||||
switchDesktop(border, pos);
|
||||
return; // Don't reset cursor position
|
||||
if (options->electricBorders() == Options::ElectricAlways) {
|
||||
switchDesktop(border, pos);
|
||||
return; // Don't reset cursor position
|
||||
}
|
||||
emit activated(border);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ namespace KWin {
|
|||
* @author Arthur Arlt
|
||||
* @since 4.8
|
||||
*/
|
||||
class ScreenEdge : QObject {
|
||||
class ScreenEdge : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
ScreenEdge();
|
||||
|
@ -108,6 +108,13 @@ public Q_SLOTS:
|
|||
* actions or disabled desktop switching.
|
||||
*/
|
||||
void update(bool force=false);
|
||||
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:
|
||||
/**
|
||||
* Switch the desktop if desktop switching is enabled and a screen edge
|
||||
|
|
|
@ -41,6 +41,14 @@
|
|||
<read></read>
|
||||
<detaileddescription>Reads the config value for key in the Script's configuration with the optional default value. If not providing a default value and no value stored in the configuration an undefined value is returned.</detaileddescription>
|
||||
</memberdef>
|
||||
<memberdef kind="function">
|
||||
<type>Q_SCRIPTABLE bool</type>
|
||||
<definition>bool KWin::Scripting::registerScreenEdge</definition>
|
||||
<argsstring>(ElectricBorder border, QScriptValue callback)</argsstring>
|
||||
<name>registerScreenEdge</name>
|
||||
<read></read>
|
||||
<detaileddescription>Registers the callback for the screen edge. When the mouse gets pushed against the given edge the callback will be invoked.</detaileddescription>
|
||||
</memberdef>
|
||||
<memberdef kind="function">
|
||||
<type>Q_SCRIPTABLE bool</type>
|
||||
<definition>bool KWin::Scripting::registerShortcut</definition>
|
||||
|
|
|
@ -21,6 +21,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
#include "scriptedeffect.h"
|
||||
#include "meta.h"
|
||||
#include "scriptingutils.h"
|
||||
#include "workspace_wrapper.h"
|
||||
// KDE
|
||||
#include <KDE/KConfigGroup>
|
||||
#include <KDE/KDebug>
|
||||
|
@ -83,6 +84,11 @@ QScriptValue kwinScriptGlobalShortcut(QScriptContext *context, QScriptEngine *en
|
|||
return globalShortcut<KWin::ScriptedEffect*>(context, engine);
|
||||
}
|
||||
|
||||
QScriptValue kwinScriptScreenEdge(QScriptContext *context, QScriptEngine *engine)
|
||||
{
|
||||
return registerScreenEdge<KWin::ScriptedEffect*>(context, engine);
|
||||
}
|
||||
|
||||
QScriptValue effectWindowToScriptValue(QScriptEngine *eng, const KEffectWindowRef &window)
|
||||
{
|
||||
return eng->newQObject(window, QScriptEngine::QtOwnership,
|
||||
|
@ -140,6 +146,20 @@ 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(borderActivated(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)
|
||||
|
@ -155,6 +175,7 @@ bool ScriptedEffect::init(const QString &effectName, const QString &pathToScript
|
|||
QScriptValue effectsObject = m_engine->newQObject(effects, QScriptEngine::QtOwnership, QScriptEngine::ExcludeDeleteLater);
|
||||
m_engine->globalObject().setProperty("effects", effectsObject, QScriptValue::Undeletable);
|
||||
m_engine->globalObject().setProperty("Effect", m_engine->newQMetaObject(&ScriptedEffect::staticMetaObject));
|
||||
m_engine->globalObject().setProperty("KWin", m_engine->newQMetaObject(&WorkspaceWrapper::staticMetaObject));
|
||||
m_engine->globalObject().setProperty("effect", m_engine->newQObject(this, QScriptEngine::QtOwnership, QScriptEngine::ExcludeDeleteLater), QScriptValue::Undeletable);
|
||||
m_engine->globalObject().setProperty("AnimationData", m_engine->scriptValueFromQMetaObject<AnimationData>());
|
||||
MetaScripting::registration(m_engine);
|
||||
|
@ -176,6 +197,7 @@ bool ScriptedEffect::init(const QString &effectName, const QString &pathToScript
|
|||
m_engine->globalObject().setProperty("displayHeight", displayHeightFunc);
|
||||
// add global Shortcut
|
||||
registerGlobalShortcutFunction(this, m_engine, kwinScriptGlobalShortcut);
|
||||
registerScreenEdgeFunction(this, m_engine, kwinScriptScreenEdge);
|
||||
|
||||
QScriptValue ret = m_engine->evaluate(scriptFile.readAll());
|
||||
|
||||
|
@ -257,6 +279,11 @@ void ScriptedEffect::globalShortcutTriggered()
|
|||
callGlobalShortcutCallback<KWin::ScriptedEffect*>(this, sender());
|
||||
}
|
||||
|
||||
void ScriptedEffect::slotBorderActivated(ElectricBorder edge)
|
||||
{
|
||||
screenEdgeActivated(this, edge);
|
||||
}
|
||||
|
||||
QVariant ScriptedEffect::readConfig(const QString &key, const QVariant defaultValue)
|
||||
{
|
||||
KConfigGroup cg = effects->effectConfig(m_effectName);
|
||||
|
|
|
@ -103,6 +103,7 @@ public:
|
|||
QString activeConfig() const;
|
||||
void setActiveConfig(const QString &name);
|
||||
static ScriptedEffect *create(const QString &effectName, const QString &pathToScript);
|
||||
virtual ~ScriptedEffect();
|
||||
/**
|
||||
* Whether another effect has grabbed the @p w with the given @p grabRole.
|
||||
* @param w The window to check
|
||||
|
@ -121,6 +122,9 @@ public:
|
|||
const QHash<QAction*, QScriptValue> &shortcutCallbacks() const {
|
||||
return m_shortcutCallbacks;
|
||||
}
|
||||
QHash<int, QList<QScriptValue > > &screenEdgeCallbacks() {
|
||||
return m_screenEdgeCallbacks;
|
||||
}
|
||||
|
||||
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 curve = QEasingCurve(), int delay = 0);
|
||||
|
@ -134,6 +138,7 @@ 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);
|
||||
|
@ -141,6 +146,7 @@ private:
|
|||
QString m_effectName;
|
||||
QString m_scriptFile;
|
||||
QHash<QAction*, QScriptValue> m_shortcutCallbacks;
|
||||
QHash<int, QList<QScriptValue> > m_screenEdgeCallbacks;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -139,6 +139,11 @@ QScriptValue kwinAssertNotNull(QScriptContext *context, QScriptEngine *engine)
|
|||
return true;
|
||||
}
|
||||
|
||||
QScriptValue kwinRegisterScreenEdge(QScriptContext *context, QScriptEngine *engine)
|
||||
{
|
||||
return KWin::registerScreenEdge<KWin::AbstractScript*>(context, engine);
|
||||
}
|
||||
|
||||
KWin::AbstractScript::AbstractScript(int id, QString scriptName, QString pluginName, QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_scriptId(id)
|
||||
|
@ -150,10 +155,20 @@ 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
|
||||
|
@ -183,6 +198,11 @@ void KWin::AbstractScript::globalShortcutTriggered()
|
|||
callGlobalShortcutCallback<KWin::AbstractScript*>(this, sender());
|
||||
}
|
||||
|
||||
void KWin::AbstractScript::borderActivated(KWin::ElectricBorder edge)
|
||||
{
|
||||
screenEdgeActivated(this, edge);
|
||||
}
|
||||
|
||||
void KWin::AbstractScript::installScriptFunctions(QScriptEngine* engine)
|
||||
{
|
||||
// add our print
|
||||
|
@ -195,6 +215,8 @@ void KWin::AbstractScript::installScriptFunctions(QScriptEngine* engine)
|
|||
engine->globalObject().setProperty("readConfig", configFunc);
|
||||
// add global Shortcut
|
||||
registerGlobalShortcutFunction(this, engine, kwinScriptGlobalShortcut);
|
||||
// add screen edge
|
||||
registerScreenEdgeFunction(this, engine, kwinRegisterScreenEdge);
|
||||
// add assertions
|
||||
QScriptValue assertTrueFunc = engine->newFunction(kwinAssertTrue);
|
||||
engine->globalObject().setProperty("assertTrue", assertTrueFunc);
|
||||
|
|
|
@ -22,6 +22,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
#ifndef KWIN_SCRIPTING_H
|
||||
#define KWIN_SCRIPTING_H
|
||||
|
||||
#include <kwinglobals.h>
|
||||
|
||||
#include <QtCore/QFile>
|
||||
#include <QtCore/QHash>
|
||||
#include <QtCore/QStringList>
|
||||
|
@ -62,6 +64,9 @@ public:
|
|||
const QHash<QAction*, QScriptValue> &shortcutCallbacks() const {
|
||||
return m_shortcutCallbacks;
|
||||
}
|
||||
QHash<int, QList<QScriptValue > > &screenEdgeCallbacks() {
|
||||
return m_screenEdgeCallbacks;
|
||||
}
|
||||
|
||||
public Q_SLOTS:
|
||||
Q_SCRIPTABLE void stop();
|
||||
|
@ -69,6 +74,7 @@ public Q_SLOTS:
|
|||
|
||||
private Q_SLOTS:
|
||||
void globalShortcutTriggered();
|
||||
void borderActivated(ElectricBorder edge);
|
||||
|
||||
Q_SIGNALS:
|
||||
Q_SCRIPTABLE void print(const QString &text);
|
||||
|
@ -100,6 +106,7 @@ private:
|
|||
bool m_running;
|
||||
WorkspaceWrapper *m_workspace;
|
||||
QHash<QAction*, QScriptValue> m_shortcutCallbacks;
|
||||
QHash<int, QList<QScriptValue> > m_screenEdgeCallbacks;
|
||||
};
|
||||
|
||||
class Script : public AbstractScript
|
||||
|
|
|
@ -21,6 +21,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
#ifndef KWIN_SCRIPTINGUTILS_H
|
||||
#define KWIN_SCRIPTINGUTILS_H
|
||||
|
||||
#include "workspace.h"
|
||||
|
||||
#include <KDE/KAction>
|
||||
#include <KDE/KActionCollection>
|
||||
#include <KDE/KDebug>
|
||||
|
@ -132,6 +134,50 @@ void callGlobalShortcutCallback(T script, QObject *sender)
|
|||
value.call();
|
||||
};
|
||||
|
||||
template<class T>
|
||||
QScriptValue registerScreenEdge(QScriptContext *context, QScriptEngine *engine)
|
||||
{
|
||||
T script = qobject_cast<T>(context->callee().data().toQObject());
|
||||
if (!script) {
|
||||
return engine->undefinedValue();
|
||||
}
|
||||
if (!validateParameters(context, 2, 2)) {
|
||||
return engine->undefinedValue();
|
||||
}
|
||||
if (!validateArgumentType<int>(context)) {
|
||||
return engine->undefinedValue();
|
||||
}
|
||||
if (!context->argument(1).isFunction()) {
|
||||
context->throwError(QScriptContext::SyntaxError, i18nc("KWin Scripting error thrown due to incorrect argument",
|
||||
"Second argument to registerScreenEdge needs to be a callback"));
|
||||
}
|
||||
|
||||
const int edge = context->argument(0).toVariant().toInt();
|
||||
QHash<int, QList<QScriptValue> >::iterator it = script->screenEdgeCallbacks().find(edge);
|
||||
if (it == script->screenEdgeCallbacks().end()) {
|
||||
// not yet registered
|
||||
#ifdef KWIN_BUILD_SCREENEDGES
|
||||
KWin::Workspace::self()->screenEdge()->reserve(static_cast<KWin::ElectricBorder>(edge));
|
||||
#endif
|
||||
script->screenEdgeCallbacks().insert(edge, QList<QScriptValue>() << context->argument(1));
|
||||
} else {
|
||||
it->append(context->argument(1));
|
||||
}
|
||||
return engine->newVariant(true);
|
||||
};
|
||||
|
||||
template<class T>
|
||||
void screenEdgeActivated(T *script, int edge)
|
||||
{
|
||||
QHash<int, QList<QScriptValue> >::iterator it = script->screenEdgeCallbacks().find(edge);
|
||||
if (it != script->screenEdgeCallbacks().end()) {
|
||||
foreach (const QScriptValue &value, it.value()) {
|
||||
QScriptValue callback(value);
|
||||
callback.call();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<class T>
|
||||
QScriptValue scriptingAssert(QScriptContext *context, QScriptEngine *engine, int min, int max, T defaultVal = T())
|
||||
{
|
||||
|
@ -194,6 +240,13 @@ inline void registerGlobalShortcutFunction(QObject *parent, QScriptEngine *engin
|
|||
shortcutFunc.setData(engine->newQObject(parent));
|
||||
engine->globalObject().setProperty("registerShortcut", shortcutFunc);
|
||||
};
|
||||
|
||||
inline void registerScreenEdgeFunction(QObject *parent, QScriptEngine *engine, QScriptEngine::FunctionSignature function)
|
||||
{
|
||||
QScriptValue shortcutFunc = engine->newFunction(function);
|
||||
shortcutFunc.setData(engine->newQObject(parent));
|
||||
engine->globalObject().setProperty("registerScreenEdge", shortcutFunc);
|
||||
};
|
||||
} // namespace KWin
|
||||
|
||||
#endif // KWIN_SCRIPTINGUTILS_H
|
||||
|
|
|
@ -35,6 +35,7 @@ class WorkspaceWrapper : public QObject
|
|||
{
|
||||
Q_OBJECT
|
||||
Q_ENUMS(ClientAreaOption)
|
||||
Q_ENUMS(ElectricBorder)
|
||||
Q_PROPERTY(int currentDesktop READ currentDesktop WRITE setCurrentDesktop NOTIFY currentDesktopChanged)
|
||||
Q_PROPERTY(KWin::Client *activeClient READ activeClient WRITE setActiveClient NOTIFY clientActivated)
|
||||
// TODO: write and notify?
|
||||
|
@ -125,6 +126,18 @@ public:
|
|||
///< one whole screen, ignore struts
|
||||
ScreenArea
|
||||
};
|
||||
enum ElectricBorder {
|
||||
ElectricTop,
|
||||
ElectricTopRight,
|
||||
ElectricRight,
|
||||
ElectricBottomRight,
|
||||
ElectricBottom,
|
||||
ElectricBottomLeft,
|
||||
ElectricLeft,
|
||||
ElectricTopLeft,
|
||||
ELECTRIC_COUNT,
|
||||
ElectricNone
|
||||
};
|
||||
|
||||
WorkspaceWrapper(QObject* parent = 0);
|
||||
#define GETTERSETTERDEF( rettype, getter, setter ) \
|
||||
|
|
Loading…
Reference in a new issue