polish track mouse effect, add xrender implementation

This commit is contained in:
Thomas Lübking 2012-04-19 21:06:11 +02:00
parent 9a1ad96e93
commit c2940d8889
9 changed files with 300 additions and 192 deletions

View file

@ -13,7 +13,8 @@ install( FILES
# Data files
install( FILES
trackmouse/data/trackmouse.png
trackmouse/data/tm_inner.png
trackmouse/data/tm_outer.png
DESTINATION ${DATA_INSTALL_DIR}/kwin )
#######################################

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

View file

@ -22,6 +22,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "trackmouse.h"
#include <QTime>
#include <QMatrix4x4>
#include <kwinconfig.h>
#include <kwinglutils.h>
@ -35,7 +36,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <KDE/KLocale>
#include <math.h>
#include <X11/extensions/Xrender.h>
#include <kdebug.h>
@ -44,65 +45,73 @@ namespace KWin
KWIN_EFFECT(trackmouse, TrackMouseEffect)
const int STARS = 5;
const int DIST = 50;
TrackMouseEffect::TrackMouseEffect()
: active(false)
, angle(0)
, texture(NULL)
: m_active(false)
, m_angle(0)
{
mousePolling = false;
actionCollection = new KActionCollection(this);
action = static_cast< KAction* >(actionCollection->addAction("TrackMouse"));
action->setText(i18n("Track mouse"));
action->setGlobalShortcut(KShortcut());
m_texture[0] = m_texture[1] = 0;
#ifdef KWIN_HAVE_XRENDER_COMPOSITING
m_pixmap[0] = m_pixmap[1] = 0;
if ( effects->compositingType() == XRenderCompositing)
m_angleBase = 1.57079632679489661923; // Pi/2
#endif
if ( effects->compositingType() == OpenGLCompositing)
m_angleBase = 90.0;
m_mousePolling = false;
KActionCollection *actionCollection = new KActionCollection(this);
m_action = static_cast< KAction* >(actionCollection->addAction("TrackMouse"));
m_action->setText(i18n("Track mouse"));
m_action->setGlobalShortcut(KShortcut());
connect(action, SIGNAL(triggered(bool)), this, SLOT(toggle()));
connect(m_action, SIGNAL(triggered(bool)), this, SLOT(toggle()));
connect(effects, SIGNAL(mouseChanged(QPoint,QPoint,Qt::MouseButtons,Qt::MouseButtons,Qt::KeyboardModifiers,Qt::KeyboardModifiers)),
this, SLOT(slotMouseChanged(QPoint,QPoint,Qt::MouseButtons,Qt::MouseButtons,Qt::KeyboardModifiers,Qt::KeyboardModifiers)));
SLOT(slotMouseChanged(QPoint,QPoint,Qt::MouseButtons,Qt::MouseButtons,Qt::KeyboardModifiers,Qt::KeyboardModifiers)));
reconfigure(ReconfigureAll);
}
TrackMouseEffect::~TrackMouseEffect()
{
if (mousePolling)
if (m_mousePolling)
effects->stopMousePolling();
delete texture;
for (int i = 0; i < 2; ++i) {
delete m_texture[i]; m_texture[i] = 0;
#ifdef KWIN_HAVE_XRENDER_COMPOSITING
delete m_pixmap[i]; m_pixmap[i] = 0;
#endif
}
}
void TrackMouseEffect::reconfigure(ReconfigureFlags)
{
m_modifiers = 0;
KConfigGroup conf = effects->effectConfig("TrackMouse");
bool shift = conf.readEntry("Shift", false);
bool alt = conf.readEntry("Alt", false);
bool control = conf.readEntry("Control", true);
bool meta = conf.readEntry("Meta", true);
modifier = 0;
if (meta)
modifier |= Qt::MetaModifier;
if (control)
modifier |= Qt::ControlModifier;
if (alt)
modifier |= Qt::AltModifier;
if (shift)
modifier |= Qt::ShiftModifier;
if (modifier != 0 && action != NULL) {
if (!mousePolling)
if (conf.readEntry("Shift", false))
m_modifiers |= Qt::ShiftModifier;
if (conf.readEntry("Alt", false))
m_modifiers |= Qt::AltModifier;
if (conf.readEntry("Control", true))
m_modifiers |= Qt::ControlModifier;
if (conf.readEntry("Meta", true))
m_modifiers |= Qt::MetaModifier;
if (m_modifiers) {
if (!m_mousePolling)
effects->startMousePolling();
mousePolling = true;
} else if (action != NULL) {
if (mousePolling)
m_mousePolling = true;
} else if (m_mousePolling) {
effects->stopMousePolling();
mousePolling = false;
m_mousePolling = false;
}
}
void TrackMouseEffect::prePaintScreen(ScreenPrePaintData& data, int time)
{
if (active) {
if (m_active) {
QTime t = QTime::currentTime();
angle = ((t.second() % 4) * 90.0) + (t.msec() / 1000.0 * 90.0);
m_angle = ((t.second() % 4) * m_angleBase) + (t.msec() / 1000.0 * m_angleBase);
m_lastRect[0].moveCenter(cursorPos());
m_lastRect[1].moveCenter(cursorPos());
data.paint |= m_lastRect[0].adjusted(-1,-1,1,1);
}
effects->prePaintScreen(data, time);
}
@ -110,100 +119,149 @@ void TrackMouseEffect::prePaintScreen(ScreenPrePaintData& data, int time)
void TrackMouseEffect::paintScreen(int mask, QRegion region, ScreenPaintData& data)
{
effects->paintScreen(mask, region, data); // paint normal screen
if (!active)
if (!m_active)
return;
if (texture) {
if ( effects->compositingType() == OpenGLCompositing && m_texture[0] && m_texture[1]) {
GLShader *shader(0);
QMatrix4x4 modelview;
if (ShaderManager::instance()->isValid()) {
ShaderManager::instance()->pushShader(ShaderManager::SimpleShader);
ShaderManager::instance()->pushShader(ShaderManager::GenericShader);
shader = ShaderManager::instance()->getBoundShader();
modelview = shader->getUniformMatrix4x4("modelview");
}
texture->bind();
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
for (int i = 0;
i < STARS;
++i) {
QRect r = starRect(i);
texture->render(region, r);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
QMatrix4x4 matrix(modelview);
const QPointF p = m_lastRect[0].topLeft() + QPoint(m_lastRect[0].width()/2.0, m_lastRect[0].height()/2.0);
for (int i = 0; i < 2; ++i) {
matrix.translate(p.x(), p.y(), 0.0);
matrix.rotate(i ? -2*m_angle : m_angle, 0, 0, 1.0);
matrix.translate(-p.x(), -p.y(), 0.0);
if (shader)
shader->setUniform(GLShader::ModelViewMatrix, matrix);
else
pushMatrix(matrix);
m_texture[i]->bind();
m_texture[i]->render(region, m_lastRect[i]);
m_texture[i]->unbind();
if (!shader)
popMatrix();
}
texture->unbind();
glDisable(GL_BLEND);
if (ShaderManager::instance()->isValid()) {
shader->setUniform(GLShader::ModelViewMatrix, modelview);
ShaderManager::instance()->popShader();
}
}
#ifdef KWIN_HAVE_XRENDER_COMPOSITING
if ( effects->compositingType() == XRenderCompositing && m_pixmap[0] && m_pixmap[1]) {
float sine = sin(m_angle);
const float cosine = cos(m_angle);
for (int i = 0; i < 2; ++i) {
if (i) sine = -sine;
const float dx = m_pixmap[i]->width()/2.0;
const float dy = m_pixmap[i]->height()/2.0;
XTransform xform = {{
{ XDoubleToFixed( cosine ), XDoubleToFixed( -sine ), XDoubleToFixed( dx - cosine*dx + sine*dy ) },
{ XDoubleToFixed( sine ), XDoubleToFixed( cosine ), XDoubleToFixed( dy - sine*dx - cosine*dy ) },
{ XDoubleToFixed( 0.0 ), XDoubleToFixed( 0.0 ), XDoubleToFixed( 1.0 ) }
}};
XRenderSetPictureTransform(display(), m_pixmap[i]->x11PictureHandle(), &xform );
XRenderSetPictureFilter( display(), m_pixmap[i]->x11PictureHandle(), FilterBilinear, 0, 0 );
XRenderComposite(display(), PictOpOver, m_pixmap[i]->x11PictureHandle(), 0,
effects->xrenderBufferPicture(), 0, 0, 0, 0,
m_lastRect[i].x(), m_lastRect[i].y(), m_lastRect[i].width(), m_lastRect[i].height());
}
}
#endif
}
void TrackMouseEffect::postPaintScreen()
{
if (active) {
for (int i = 0;
i < STARS;
++i)
effects->addRepaint(starRect(i));
if (m_active) {
effects->addRepaint(m_lastRect[0].adjusted(-1,-1,1,1));
}
effects->postPaintScreen();
}
bool TrackMouseEffect::init()
{
#ifdef KWIN_HAVE_XRENDER_COMPOSITING
if (!(m_texture[0] || m_pixmap[0])) {
loadTexture();
if (!(m_texture[0] || m_pixmap[0]))
return false;
}
#else
if (!m_texture[0]) {
loadTexture();
if (!m_texture[0])
return false;
}
#endif
m_lastRect[0].moveCenter(cursorPos());
m_lastRect[1].moveCenter(cursorPos());
m_active = true;
m_angle = 0;
return true;
}
void TrackMouseEffect::toggle()
{
if (mousePolling)
if (m_mousePolling)
return;
if (!active) {
if (texture == NULL)
loadTexture();
if (texture == NULL)
return;
active = true;
angle = 0;
} else
active = false;
for (int i = 0; i < STARS; ++i)
effects->addRepaint(starRect(i));
}
void TrackMouseEffect::slotMouseChanged(const QPoint&, const QPoint&, Qt::MouseButtons,
Qt::MouseButtons, Qt::KeyboardModifiers modifiers, Qt::KeyboardModifiers)
{
if (modifier != 0 && modifiers == modifier) {
if (!active) {
if (texture == NULL)
loadTexture();
if (texture == NULL)
return;
active = true;
angle = 0;
}
for (int i = 0; i < STARS; ++i)
effects->addRepaint(starRect(i));
} else if (active) {
for (int i = 0; i < STARS; ++i)
effects->addRepaint(starRect(i));
active = false;
if (m_active) {
m_active = false;
} else if (!init()) {
return;
}
effects->addRepaint(m_lastRect[0].adjusted(-1,-1,1,1));
}
QRect TrackMouseEffect::starRect(int num) const
void TrackMouseEffect::slotMouseChanged(const QPoint&, const QPoint&,
Qt::MouseButtons, Qt::MouseButtons,
Qt::KeyboardModifiers modifiers, Qt::KeyboardModifiers)
{
int a = angle + 360 / STARS * num;
int x = cursorPos().x() + int(DIST * cos(a * (2 * M_PI / 360)));
int y = cursorPos().y() + int(DIST * sin(a * (2 * M_PI / 360)));
return QRect(QPoint(x - textureSize.width() / 2,
y - textureSize.height() / 2), textureSize);
if (!m_mousePolling) // we didn't ask for it but maybe someone else did...
return;
if (m_modifiers && modifiers == m_modifiers) {
if (!m_active && !init()) {
return;
}
effects->addRepaint(m_lastRect[0].adjusted(-1,-1,1,1));
} else if (m_active) {
m_active = false;
effects->addRepaint(m_lastRect[0].adjusted(-1,-1,1,1));
}
}
void TrackMouseEffect::loadTexture()
{
QString file = KGlobal::dirs()->findResource("appdata", "trackmouse.png");
if (file.isEmpty())
QString f[2] = {KGlobal::dirs()->findResource("appdata", "tm_outer.png"),
KGlobal::dirs()->findResource("appdata", "tm_inner.png")};
if (f[0].isEmpty() || f[1].isEmpty())
return;
QImage im(file);
texture = new GLTexture(im);
textureSize = im.size();
for (int i = 0; i < 2; ++i) {
if ( effects->compositingType() == OpenGLCompositing) {
QImage img(f[i]);
m_texture[i] = new GLTexture(img);
m_lastRect[i].setSize(img.size());
}
#ifdef KWIN_HAVE_XRENDER_COMPOSITING
if ( effects->compositingType() == XRenderCompositing) {
m_pixmap[i] = new QPixmap(f[i]);
m_lastRect[i].setSize(m_pixmap[i]->size());
}
#endif
}
}
bool TrackMouseEffect::isActive() const
{
return active;
return m_active;
}
} // namespace

View file

@ -48,15 +48,18 @@ private slots:
Qt::MouseButtons buttons, Qt::MouseButtons oldbuttons,
Qt::KeyboardModifiers modifiers, Qt::KeyboardModifiers oldmodifiers);
private:
QRect starRect(int num) const;
bool init();
void loadTexture();
bool active, mousePolling;
int angle;
GLTexture* texture;
QSize textureSize;
KActionCollection* actionCollection;
KAction* action;
Qt::KeyboardModifiers modifier;
QRect m_lastRect[2];
bool m_active, m_mousePolling;
float m_angle;
float m_angleBase;
GLTexture* m_texture[2];
#ifdef KWIN_HAVE_XRENDER_COMPOSITING
QPixmap *m_pixmap[2];
#endif
KAction* m_action;
Qt::KeyboardModifiers m_modifiers;
};
} // namespace

View file

@ -49,53 +49,56 @@ TrackMouseEffectConfig::TrackMouseEffectConfig(QWidget* parent, const QVariantLi
m_ui = new TrackMouseEffectConfigForm(this);
QVBoxLayout* layout = new QVBoxLayout(this);
layout->addWidget(m_ui);
connect(m_ui->editor, SIGNAL(keyChange()), this, SLOT(changed()));
connect(m_ui->alt, SIGNAL(stateChanged(int)), this, SLOT(changed()));
connect(m_ui->control, SIGNAL(stateChanged(int)), this, SLOT(changed()));
connect(m_ui->meta, SIGNAL(stateChanged(int)), this, SLOT(changed()));
connect(m_ui->shift, SIGNAL(stateChanged(int)), this, SLOT(changed()));
connect(m_ui->alt, SIGNAL(toggled(bool)), this, SLOT(enableEditor(bool)));
connect(m_ui->control, SIGNAL(toggled(bool)), this, SLOT(enableEditor(bool)));
connect(m_ui->meta, SIGNAL(toggled(bool)), this, SLOT(enableEditor(bool)));
connect(m_ui->shift, SIGNAL(toggled(bool)), this, SLOT(enableEditor(bool)));
connect(m_ui->alt, SIGNAL(clicked(bool)), SLOT(changed()));
connect(m_ui->control, SIGNAL(clicked(bool)), SLOT(changed()));
connect(m_ui->meta, SIGNAL(clicked(bool)), SLOT(changed()));
connect(m_ui->shift, SIGNAL(clicked(bool)), SLOT(changed()));
connect(m_ui->modifierRadio, SIGNAL(clicked(bool)), SLOT(changed()));
connect(m_ui->shortcutRadio, SIGNAL(clicked(bool)), SLOT(changed()));
m_actionCollection = new KActionCollection(this, KComponentData("kwin"));
m_actionCollection->setConfigGroup("TrackMouse");
m_actionCollection->setConfigGlobal(true);
action = static_cast< KAction* >(m_actionCollection->addAction("TrackMouse"));
action->setText(i18n("Track mouse"));
action->setProperty("isConfigurationAction", true);
action->setGlobalShortcut(KShortcut());
m_ui->editor->addCollection(m_actionCollection);
KAction *a = static_cast< KAction* >(m_actionCollection->addAction("TrackMouse"));
a->setText(i18n("Track mouse"));
a->setProperty("isConfigurationAction", true);
a->setGlobalShortcut(KShortcut());
connect(m_ui->shortcut, SIGNAL(keySequenceChanged(const QKeySequence&)),
SLOT(shortcutChanged(const QKeySequence&)));
load();
}
TrackMouseEffectConfig::~TrackMouseEffectConfig()
{
m_ui->editor->undoChanges();
}
void TrackMouseEffectConfig::load()
{
KCModule::load();
if (KAction *a = qobject_cast<KAction*>(m_actionCollection->action("TrackMouse")))
m_ui->shortcut->setKeySequence(a->globalShortcut().primary());
KConfigGroup conf = EffectsHandler::effectConfig("TrackMouse");
m_ui->meta->setChecked(conf.readEntry("Meta", true));
m_ui->control->setChecked(conf.readEntry("Control", true));
m_ui->alt->setChecked(conf.readEntry("Alt", false));
m_ui->shift->setChecked(conf.readEntry("Shift", false));
const bool modifiers = m_ui->shift->isChecked() || m_ui->alt->isChecked() ||
m_ui->control->isChecked() || m_ui->meta->isChecked();
m_ui->modifierRadio->setChecked(modifiers);
m_ui->shortcutRadio->setChecked(!modifiers);
emit changed(false);
}
void TrackMouseEffectConfig::save()
{
KConfigGroup conf = EffectsHandler::effectConfig("TrackMouse");
conf.writeEntry("Shift", m_ui->shift->isChecked());
conf.writeEntry("Alt", m_ui->alt->isChecked());
conf.writeEntry("Control", m_ui->control->isChecked());
conf.writeEntry("Meta", m_ui->meta->isChecked());
m_ui->editor->save();
conf.writeEntry("Shift", m_ui->modifierRadio->isChecked() && m_ui->shift->isChecked());
conf.writeEntry("Alt", m_ui->modifierRadio->isChecked() && m_ui->alt->isChecked());
conf.writeEntry("Control", m_ui->modifierRadio->isChecked() && m_ui->control->isChecked());
conf.writeEntry("Meta", m_ui->modifierRadio->isChecked() && m_ui->meta->isChecked());
m_actionCollection->writeSettings();
conf.sync();
emit changed(false);
EffectsHandler::sendReloadMessage("trackmouse");
@ -103,7 +106,7 @@ void TrackMouseEffectConfig::save()
void TrackMouseEffectConfig::defaults()
{
m_ui->editor->allDefault();
m_ui->shortcut->clearKeySequence();
m_ui->meta->setChecked(true);
m_ui->control->setChecked(true);
m_ui->alt->setChecked(false);
@ -111,19 +114,15 @@ void TrackMouseEffectConfig::defaults()
emit changed(true);
}
void TrackMouseEffectConfig::enableEditor(bool enabled)
void TrackMouseEffectConfig::shortcutChanged(const QKeySequence &seq)
{
if (!enabled && !m_ui->alt->isChecked() && !m_ui->shift->isChecked() && !m_ui->meta->isChecked() && !m_ui->control->isChecked()) {
m_ui->editor->setEnabled(true);
emit changed(true);
} else if (enabled && (m_ui->alt->isChecked() || m_ui->shift->isChecked() || m_ui->meta->isChecked() || m_ui->control->isChecked())) {
m_ui->editor->setEnabled(false);
action->setGlobalShortcut(KShortcut(), KAction::ShortcutTypes(KAction::ActiveShortcut | KAction::DefaultShortcut), KAction::NoAutoloading);
emit changed(true);
}
if (KAction *a = qobject_cast<KAction*>(m_actionCollection->action("TrackMouse")))
a->setGlobalShortcut(KShortcut(seq), KAction::ActiveShortcut, KAction::NoAutoloading);
// m_actionCollection->writeSettings();
emit changed(true);
}
} // namespace
#include "trackmouse_config.moc"

View file

@ -51,10 +51,9 @@ public slots:
virtual void load();
virtual void defaults();
private slots:
virtual void enableEditor(bool);
void shortcutChanged(const QKeySequence &seq);
private:
TrackMouseEffectConfigForm* m_ui;
KAction *action;
KActionCollection* m_actionCollection;
};

View file

@ -6,81 +6,129 @@
<rect>
<x>0</x>
<y>0</y>
<width>278</width>
<height>223</height>
<width>311</width>
<height>101</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Modifier keys</string>
<layout class="QFormLayout" name="formLayout">
<property name="fieldGrowthPolicy">
<enum>QFormLayout::FieldsStayAtSizeHint</enum>
</property>
<item row="0" column="0" colspan="2">
<widget class="KTitleWidget" name="ktitlewidget">
<property name="text">
<string>Trigger on</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QRadioButton" name="modifierRadio">
<property name="text">
<string>Modifiers</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QWidget" name="widget" native="true">
<property name="enabled">
<bool>false</bool>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="margin">
<number>0</number>
</property>
<item>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QCheckBox" name="shift">
<property name="text">
<string>Shift</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="meta">
<property name="text">
<string>Meta</string>
</property>
</widget>
</item>
</layout>
<widget class="QCheckBox" name="alt">
<property name="text">
<string>Alt</string>
</property>
</widget>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QCheckBox" name="control">
<property name="text">
<string>Ctrl</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="alt">
<property name="text">
<string>Alt</string>
</property>
</widget>
</item>
</layout>
<widget class="QCheckBox" name="control">
<property name="text">
<string>Ctrl</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="shift">
<property name="text">
<string>Shift</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="meta">
<property name="text">
<string>Meta</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<item row="2" column="0">
<widget class="QRadioButton" name="shortcutRadio">
<property name="text">
<string>Shortcut</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="KWin::GlobalShortcutsEditor" name="editor" native="true"/>
</item>
</layout>
</widget>
</item>
<item row="2" column="1">
<widget class="KKeySequenceWidget" name="shortcut">
<property name="enabled">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>KWin::GlobalShortcutsEditor</class>
<class>KKeySequenceWidget</class>
<extends>QWidget</extends>
<header location="global">kwineffects.h</header>
<container>1</container>
<slots>
<slot>clearCollections()</slot>
</slots>
<header>kkeysequencewidget.h</header>
</customwidget>
<customwidget>
<class>KTitleWidget</class>
<extends>QWidget</extends>
<header>ktitlewidget.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
<connections>
<connection>
<sender>shortcutRadio</sender>
<signal>toggled(bool)</signal>
<receiver>shortcut</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>107</x>
<y>75</y>
</hint>
<hint type="destinationlabel">
<x>183</x>
<y>75</y>
</hint>
</hints>
</connection>
<connection>
<sender>modifierRadio</sender>
<signal>toggled(bool)</signal>
<receiver>widget</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>99</x>
<y>44</y>
</hint>
<hint type="destinationlabel">
<x>309</x>
<y>52</y>
</hint>
</hints>
</connection>
</connections>
</ui>