summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorwarlock <warlock.cc@gmail.com>2010-11-09 20:31:25 -0300
committerwarlock <warlock.cc@gmail.com>2010-11-09 20:31:25 -0300
commitd4826b28e01d4725856da4d440f9b59a7928f155 (patch)
tree0b4a6c5f431a0cdcbf94da53466fc8eb69cb3dc8
parentb9e3851c806cdc0c0d3a799677ebd3374c4b8b7c (diff)
downloadwormouse-d4826b28e01d4725856da4d440f9b59a7928f155.tar.gz
wormouse-d4826b28e01d4725856da4d440f9b59a7928f155.tar.bz2
* Initial commit
-rw-r--r--CMakeLists.txt5
-rw-r--r--dummy0
-rw-r--r--images/wormouse.pngbin0 -> 1456 bytes
-rw-r--r--src/wormouse.cpp202
-rw-r--r--src/wormouse.h76
-rw-r--r--wormouse.xml.in51
6 files changed, 334 insertions, 0 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..668c790
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,5 @@
+find_package (Compiz REQUIRED)
+
+include (CompizPlugin)
+
+compiz_plugin (wormouse LIBRARIES Xcursor Xfixes cairo PLUGINDEPS mousepoll)
diff --git a/dummy b/dummy
deleted file mode 100644
index e69de29..0000000
--- a/dummy
+++ /dev/null
diff --git a/images/wormouse.png b/images/wormouse.png
new file mode 100644
index 0000000..f7dbfa5
--- /dev/null
+++ b/images/wormouse.png
Binary files differ
diff --git a/src/wormouse.cpp b/src/wormouse.cpp
new file mode 100644
index 0000000..5aa865e
--- /dev/null
+++ b/src/wormouse.cpp
@@ -0,0 +1,202 @@
+/**
+ * wormouse.cpp
+ *
+ * Copyright (c) 2010 Rodolfo Granata <warlock.cc@gmail.com>
+ *
+ * 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.
+ *
+ **/
+
+#include <math.h>
+#include "wormouse.h"
+
+COMPIZ_PLUGIN_20090315 (wormouse, WormousePluginVTable);
+
+/*boilerplate */
+WormouseScreen::WormouseScreen (CompScreen *screen):
+ PluginClassHandler <WormouseScreen, CompScreen> (screen),
+ cr (NULL), img (NULL), work (NULL), cursor (0), xci (NULL)
+{
+ poller.setCallback (boost::bind (&WormouseScreen::mouseMove, this, _1));
+
+ optionSetCursorImageNotify(boost::bind (&WormouseScreen::updateConfig, this, _1, _2));
+ optionSetShowHotspotNotify(boost::bind (&WormouseScreen::updateConfig, this, _1, _2));
+ optionSetHotspotXNotify(boost::bind (&WormouseScreen::updateConfig, this, _1, _2));
+ optionSetHotspotYNotify(boost::bind (&WormouseScreen::updateConfig, this, _1, _2));
+ optionSetTailFactorNotify(boost::bind (&WormouseScreen::updateConfig, this, _1, _2));
+
+ if (!updateConfig(NULL, Options()))
+ setFailed ();
+}
+
+WormouseScreen::~WormouseScreen ()
+{
+ freeResources ();
+}
+
+bool
+WormouseScreen::updateConfig (CompOption *opt, Options num)
+{
+ show_hotspot = optionGetShowHotspot ();
+
+ CompString path = optionGetCursorImage ();
+ compLogMessage ("wormouse", CompLogLevelInfo,
+ "Loading [%s]\n", path.c_str ());
+ if (!loadCursor (path, optionGetHotspotX (),
+ optionGetHotspotY (), optionGetTailFactor ())) {
+ // Try to load image from standard path if we can't find complete path
+ path = IMAGEDIR + ("/images/" + optionGetCursorImage ());
+ compLogMessage ("wormouse", CompLogLevelInfo,
+ "Loading [%s]\n", path.c_str ());
+ if (!loadCursor (path, optionGetHotspotX (),
+ optionGetHotspotY (), optionGetTailFactor ()))
+ return false;
+ }
+ return true;
+}
+
+bool
+WormouseScreen::loadCursor (CompString &path, int hotx, int hoty, float tailf)
+{
+ freeResources ();
+
+ img = cairo_image_surface_create_from_png (path.c_str ());
+ if (CAIRO_STATUS_SUCCESS != cairo_surface_status (img)) {
+ compLogMessage ("wormouse", CompLogLevelError,
+ "Failed to load cursor image [%s]\n", path.c_str ());
+ return false;
+ }
+
+ // calculate dimensions needed for rotate image
+ wrk_w = cairo_image_surface_get_width (img);
+ wrk_h = cairo_image_surface_get_height (img);
+ wrk_r = sqrt(wrk_w*wrk_w/4.0 + wrk_h*wrk_h/4.0);
+
+ // create a destination canvas
+ work = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 2*wrk_r, 2*wrk_r);
+ cr = cairo_create (work);
+ // clear canvas
+ cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
+ //cairo_set_source_rgba (cr, 0.2, 0.2, 0.2, 0.2);
+ cairo_paint(cr);
+
+ // center our image in the newly created context
+ cairo_translate (cr, (2.0*wrk_r-wrk_w)/2, (2.0*wrk_r-wrk_h)/2);
+ cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
+ cairo_set_source_surface (cr, img, 0, 0);
+ cairo_paint(cr);
+
+ // create a cursor image and set it
+ xci = XcursorImageCreate (2*wrk_r, 2*wrk_r);
+ xci->xhot = (2.0*wrk_r-wrk_w)/2 + hotx;
+ xci->yhot = (2.0*wrk_r-wrk_h)/2 + hoty;
+ xci->pixels = (XcursorPixel *)cairo_image_surface_get_data (work);
+
+ if (show_hotspot) {
+ cairo_identity_matrix (cr);
+ cairo_set_source_rgba (cr, 1, 0, 0, 1);
+ cairo_set_line_width (cr, 1.0);
+ cairo_arc (cr, xci->xhot, xci->yhot, 1.0, 0, 2 * M_PI);
+ cairo_stroke (cr);
+ }
+
+ cursor = XcursorImageLoadCursor (screen->dpy(), xci);
+ XDefineCursor (screen->dpy (), screen->root (), cursor);
+ XFlush (screen->dpy ());
+
+ hot_a = atan2f(wrk_r - xci->yhot, xci->xhot - wrk_r);
+ hot_d = sqrt((xci->xhot - wrk_r) * (xci->xhot - wrk_r) +
+ (xci->yhot - wrk_r) * (xci->yhot - wrk_r));
+ piv_d = tailf * hot_d;
+
+ poller.start ();
+ return true;
+}
+
+void
+WormouseScreen::freeResources ()
+{
+ poller.stop ();
+ //XUndefineCursor(screen->dpy(), screen->root());
+ if (cursor) {
+ XFreeCursor (screen->dpy(), cursor);
+ cursor = 0;
+ }
+ if (xci) {
+ XcursorImageDestroy (xci);
+ xci = NULL;
+ }
+ if (cr) {
+ cairo_destroy (cr);
+ cr = NULL;
+ }
+ if (img) {
+ cairo_surface_destroy (img);
+ img = NULL;
+ }
+ if (work) {
+ cairo_surface_destroy (work);
+ work = NULL;
+ }
+}
+
+void
+WormouseScreen::mouseMove (const CompPoint &pos)
+{
+
+ float a = atan2f(piv_y - pos.y(), pos.x() - piv_x);
+ // update pivoting position
+ piv_x = pos.x() - piv_d * cosf(a);
+ piv_y = pos.y() + piv_d * sinf(a);
+
+ cairo_identity_matrix (cr);
+ cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
+ //cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
+ //cairo_set_source_rgba (cr, 0.2, 0.2, 0.2, 0.2);
+ cairo_paint(cr);
+
+ // center our image in the newly created context
+ cairo_translate (cr, wrk_r, wrk_r);
+ cairo_rotate (cr, hot_a - a);
+ cairo_translate (cr, -wrk_w/2.0, -wrk_h/2.0);
+
+ cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
+ cairo_set_source_surface (cr, img, 0, 0);
+ cairo_paint(cr);
+
+ // create a cursor image and set it
+ xci->xhot = wrk_r + hot_d * cosf(a);
+ xci->yhot = wrk_r - hot_d * sinf(a);
+ xci->pixels = (XcursorPixel *)cairo_image_surface_get_data (work);
+
+ if (show_hotspot) {
+ cairo_identity_matrix (cr);
+ cairo_set_source_rgba (cr, 1, 0, 0, 1);
+ cairo_set_line_width (cr, 1.0);
+ cairo_arc (cr, xci->xhot, xci->yhot, 1.0, 0, 2 * M_PI);
+ cairo_stroke (cr);
+ }
+
+ Cursor newcur = XcursorImageLoadCursor (screen->dpy(), xci);
+ XFixesChangeCursor (screen->dpy (), newcur, cursor);
+ XFreeCursor (screen->dpy (), cursor);
+ cursor = newcur;
+}
+
+bool
+WormousePluginVTable::init ()
+{
+ if (!CompPlugin::checkPluginABI ("core", CORE_ABIVERSION))
+ return false;
+ //TODO: query Xfixes / Xcursor extensions
+
+ return true;
+}
diff --git a/src/wormouse.h b/src/wormouse.h
new file mode 100644
index 0000000..048ff18
--- /dev/null
+++ b/src/wormouse.h
@@ -0,0 +1,76 @@
+/**
+ * wormouse.h
+ *
+ * Copyright (c) 2010 Rodolfo Granata <warlock.cc@gmail.com>
+ *
+ * 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.
+ *
+ **/
+
+#include <core/core.h>
+#include <core/pluginclasshandler.h>
+#include <mousepoll/mousepoll.h>
+#include <cairo/cairo.h>
+
+extern "C" {
+#include <X11/Xcursor/Xcursor.h>
+#include <X11/extensions/Xfixes.h>
+}
+
+#include "wormouse_options.h"
+
+class WormouseScreen :
+ public PluginClassHandler <WormouseScreen, CompScreen>,
+ public WormouseOptions
+{
+ public:
+ WormouseScreen (CompScreen *s);
+ ~WormouseScreen ();
+
+ bool loadCursor (CompString &path, int hotx, int hoty, float tailf = 0.5);
+ void mouseMove (const CompPoint &pos);
+ bool updateConfig (CompOption *opt, Options num);
+
+
+ private:
+ void freeResources ();
+ void rotateCursor (double radians);
+
+ // workbench for cursor rotation
+ cairo_t *cr;
+ cairo_surface_t *img;
+ cairo_surface_t *work;
+ Cursor cursor;
+ XcursorImage *xci;
+ MousePoller poller;
+
+ // math specific
+ float piv_x, piv_y;
+ float wrk_w, wrk_h;
+ float wrk_r; // working radius
+ float piv_d; // distnace from head to place the pivot
+ float hot_a, hot_d; // cursor hotspot (angle + distance from center)
+
+ // option cache
+ bool show_hotspot;
+};
+
+/* boilerplate */
+
+#define WMOUSE_SCREEN(screen) \
+WormouseScreen *ws = WormouseScreen::get (screen);
+
+class WormousePluginVTable :
+ public CompPlugin::VTableForScreen<WormouseScreen>
+{
+ public:
+ bool init ();
+};
diff --git a/wormouse.xml.in b/wormouse.xml.in
new file mode 100644
index 0000000..2d6806a
--- /dev/null
+++ b/wormouse.xml.in
@@ -0,0 +1,51 @@
+<?xml version="1.0"?>
+<compiz>
+ <plugin name="wormouse" useBcop="true">
+ <short>Wormy Mouse</short>
+ <long>Let your mouse pointer follow you</long>
+ <category>Extras</category>
+ <deps>
+ <relation type="after">
+ <plugin>imgpng</plugin>
+ <plugin>mousepoll</plugin>
+ </relation>
+ <requirement>
+ <plugin>imgpng</plugin>
+ <plugin>mousepoll</plugin>
+ </requirement>
+ </deps>
+ <options>
+ <group>
+ <option name="tail_factor" type="float">
+ <_short>Pivot Factor</_short>
+ <_long>The distance from hotspot (through center) to rotation pivot</_long>
+ <default>1.5</default>
+ <min>0.01</min>
+ <max>10</max>
+ <precision>0.01</precision>
+ </option>
+ <option name="show_hotspot" type="bool">
+ <_short>Show hotspot</_short>
+ <_long>Mainly for debugging purposes, show the hotspot</_long>
+ <default>false</default>
+ </option>
+ <option name="hotspot_x" type="int">
+ <_short>Hotspot-x</_short>
+ <_long>X Coordinate of the image's hotspot</_long>
+ <default>3</default>
+ </option>
+ <option name="hotspot_y" type="int">
+ <_short>Hotspot-y</_short>
+ <_long>Y Coordinate of the image's hotspot</_long>
+ <default>5</default>
+ </option>
+ <option name="cursor_image" type="string">
+ <_short>Cursor Image</_short>
+ <_long>Image to use for the cursor</_long>
+ <hints>file;image;</hints>
+ <default>wormouse.png</default>
+ </option>
+ </group>
+ </options>
+ </plugin>
+</compiz>