diff options
Diffstat (limited to 'src/wormouse.cpp')
-rw-r--r-- | src/wormouse.cpp | 167 |
1 files changed, 139 insertions, 28 deletions
diff --git a/src/wormouse.cpp b/src/wormouse.cpp index 1d41844..69b808e 100644 --- a/src/wormouse.cpp +++ b/src/wormouse.cpp @@ -16,32 +16,11 @@ **/ #include <math.h> +#include <stdlib.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) { @@ -62,12 +41,17 @@ WormouseScreen::updateConfig (CompOption *opt, Options num) return false; } + bool WormouseScreen::loadCursor (CompString &path, int hotx, int hoty, float tail_dist, float image_angle) { freeResources (); +#ifdef _CACHE_ROTATION_ + if (!buildCache (path)) + return false; +#else img = cairo_image_surface_create_from_png (path.c_str ()); if (CAIRO_STATUS_SUCCESS != cairo_surface_status (img)) { compLogMessage ("wormouse", CompLogLevelError, @@ -93,11 +77,15 @@ WormouseScreen::loadCursor (CompString &path, int hotx, int hoty, cairo_set_operator (cr, CAIRO_OPERATOR_OVER); cairo_set_source_surface (cr, img, 0, 0); cairo_paint(cr); +#endif // 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; +#ifdef _CACHE_ROTATION_ + xci->pixels = imageCache[0]; +#else xci->pixels = (XcursorPixel *)cairo_image_surface_get_data (work); if (show_hotspot) { @@ -107,10 +95,11 @@ WormouseScreen::loadCursor (CompString &path, int hotx, int hoty, cairo_arc (cr, xci->xhot, xci->yhot, 1.0, 0, 2 * M_PI); cairo_stroke (cr); } +#endif + Cursor original_cursor = screen->normalCursor (); cursor = XcursorImageLoadCursor (screen->dpy(), xci); - XDefineCursor (screen->dpy (), screen->root (), cursor); - XFlush (screen->dpy ()); + XFixesChangeCursor (screen->dpy (), cursor, original_cursor); // using cairo coordinates (inverted y axis) hot_a = atan2f(xci->yhot - wrk_r, xci->xhot - wrk_r); @@ -127,7 +116,6 @@ void WormouseScreen::freeResources () { poller.stop (); - //XUndefineCursor(screen->dpy(), screen->root()); if (cursor) { XFreeCursor (screen->dpy(), cursor); cursor = 0; @@ -136,6 +124,14 @@ WormouseScreen::freeResources () XcursorImageDestroy (xci); xci = NULL; } +#ifdef _CACHE_ROTATION_ + int a; + for (a = 0; a < 360; a++) + if (imageCache[a]) { + free (imageCache[a]); + imageCache[a] = NULL; + } +#else if (cr) { cairo_destroy (cr); cr = NULL; @@ -148,8 +144,34 @@ WormouseScreen::freeResources () cairo_surface_destroy (work); work = NULL; } +#endif } +#ifdef _CACHE_ROTATION_ +void +WormouseScreen::mouseMove (const CompPoint &pos) +{ + // get the new angle we're traveling + // needent invert y axis since cairo uses same coord system + float a = atan2f(pos.y() - piv_y, pos.x() - piv_x); + // update pivoting position + piv_x = pos.x() - tail_d * cosf(a); + piv_y = pos.y() - tail_d * sinf(a); + + // compensate image orientation + a += wrk_a; + + // create a cursor image and set it + xci->xhot = wrk_r + hot_d * cosf(hot_a + a); + xci->yhot = wrk_r + hot_d * sinf(hot_a + a); + xci->pixels = imageCache[ (int)(360 + a * 180.0 / M_PI) % 360 ]; + + Cursor newcur = XcursorImageLoadCursor (screen->dpy(), xci); + XFixesChangeCursor (screen->dpy (), newcur, cursor); + XFreeCursor (screen->dpy (), cursor); + cursor = newcur; +} +#else void WormouseScreen::mouseMove (const CompPoint &pos) { @@ -196,13 +218,102 @@ WormouseScreen::mouseMove (const CompPoint &pos) XFreeCursor (screen->dpy (), cursor); cursor = newcur; } +#endif + +#ifdef _CACHE_ROTATION_ +bool +WormouseScreen::buildCache (const CompString &path) +{ + cairo_surface_t *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 + cairo_surface_t *work = cairo_image_surface_create ( + CAIRO_FORMAT_ARGB32, 2*wrk_r, 2*wrk_r); + cairo_t *cr = cairo_create (work); + + int a; + for (a = 0; a < 360; a++) { + // clear background + cairo_identity_matrix (cr); + cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR); + cairo_paint(cr); + + // move to the center, rotate, translate back an to the final place + cairo_translate (cr, wrk_r, wrk_r); + cairo_rotate (cr, a * M_PI / 180.0); + cairo_translate (cr, -wrk_w/2.0, -wrk_h/2.0); + + // paint rotate image + cairo_set_operator (cr, CAIRO_OPERATOR_OVER); + cairo_set_source_surface (cr, img, 0, 0); + cairo_paint(cr); + + if (imageCache[a]) free (imageCache[a]); + // cache the image + int stride = cairo_image_surface_get_stride (work); + void *data = cairo_image_surface_get_data (work); + imageCache[a] = (XcursorPixel *)malloc((int)(wrk_r * wrk_r * stride)); + memcpy(imageCache[a], data, wrk_r * wrk_r * stride); + } + + cairo_destroy (cr); + cairo_surface_destroy (img); + cairo_surface_destroy (work); + + return true; +} +#endif + +/*boilerplate */ +WormouseScreen::WormouseScreen (CompScreen *screen): + PluginClassHandler <WormouseScreen, CompScreen> (screen), +#ifndef _CACHE_ROTATION_ + img (NULL), work (NULL), cr (NULL), +#endif + 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)); + +#ifdef _CACHE_ROTATION_ + memset (imageCache, 0, sizeof(imageCache)); +#endif + + + if (!updateConfig(NULL, Options())) + setFailed (); +} + +WormouseScreen::~WormouseScreen () +{ + freeResources (); +} bool WormousePluginVTable::init () { - if (!CompPlugin::checkPluginABI ("core", CORE_ABIVERSION)) - return false; - //TODO: query Xfixes / Xcursor extensions + if (!CompPlugin::checkPluginABI ("core", CORE_ABIVERSION) || + !CompPlugin::checkPluginABI ("mousepoll", COMPIZ_MOUSEPOLL_ABI)) + return false; + + int fixesEventBase, fixesErrorBase; + if (!XFixesQueryExtension(screen->dpy (), &fixesEventBase, &fixesErrorBase)) + return false; return true; } |