diff options
author | Dmitriy Kostiuk <dmitriykostiuk@gmail.com> | 2011-03-24 14:48:35 +0200 |
---|---|---|
committer | Dmitriy Kostiuk <dmitriykostiuk@gmail.com> | 2011-03-24 14:48:35 +0200 |
commit | 54bf7f8c623fb6afb61ecb11b188b1dcb67cab61 (patch) | |
tree | 7eb59f616fc072b42c81e690de9de82c41c11bbc | |
parent | 714e3f2116ae717e85398d783a5301a517d96ce0 (diff) | |
download | twist-master.tar.gz twist-master.tar.bz2 |
-rw-r--r-- | CMakeLists.txt | 5 | ||||
-rw-r--r-- | dummy | 0 | ||||
-rw-r--r-- | src/twist.cpp | 404 | ||||
-rw-r--r-- | src/twist.h | 125 | ||||
-rw-r--r-- | twist.xml.in | 39 |
5 files changed, 573 insertions, 0 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..ba09030 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,5 @@ +find_package (Compiz REQUIRED) + +include (CompizPlugin) + +compiz_plugin (twist PLUGINDEPS composite opengl mousepoll) diff --git a/src/twist.cpp b/src/twist.cpp new file mode 100644 index 0000000..f56f17f --- /dev/null +++ b/src/twist.cpp @@ -0,0 +1,404 @@ +/* +* twist.cpp + +* Description: + +* The plugin allows to compress part of selected window to enlarge free space on the desktop. +* "Twisted" window thus has reduced height or width, while still readable (more or less). +* The feature should be especially useful on netbooks for their weak screen resolution. +* Please note that while being quiet usable, twist was created as an experiment +* to find out ways of improving modern hardware-accelerated GUI. +* So don't panic if its experimental nature would show itself in some bad way + +* Using the plugin: +* To twist a window you should drag it to the direction you want, and continue dragging after +* the screen edge is reached. Twisted window consists of two parts - normal (non-compressed) part, +* which is accessible by mouse as usually, and compressed one. +* As for now, compressed part of the window can be accessed only by keyboard, but in many cases +* that is not a problem: e.g. you can compress bottom of the window, when most of its clickable +* elements (like menus or toolbars) are residing on top. + +* also "screw" mode was added for testing purposes in addition to standart compressing +* (try to chose it in config) + +* Contributions: + +* The concept and the code created by Dmitriy Kostiuk (d.k AT list.ru) and Alexander Nikoniuk (nikoniuk AT mail.ru). + +* The code is licensed under GPL v.2. +* The plugin was created in bounds of a research project in Micro and Midi-ergonomisc Laboratory of Brest State Technical University +*/ + + +#include "twist.h" + +COMPIZ_PLUGIN_20090315 (twist, TwistPluginVTable); + +static void +toggleScreenFunctions (bool enabled) // add screen events handlers +{ + TWIST_SCREEN (screen); + + screen->handleEventSetEnabled (ts, enabled); + ts->cScreen->donePaintSetEnabled (ts, enabled); +} + +static void +toggleWindowFunctions (CompWindow *w, bool enabled) // add window event handlers +{ + TWIST_WINDOW (w); + + tw->gWindow->glPaintSetEnabled (tw, enabled); + tw->gWindow->glAddGeometrySetEnabled (tw, enabled); +} + +float f(float y) +{ + return 0.000007 * pow (y, 2); +} + +bool +TwistWindow::glPaint (const GLWindowPaintAttrib &attrib, + const GLMatrix &transform, + const CompRegion ®ion, + unsigned int mask) +{ + if (this->transform != NONE) + { + int dx = 0, dy = 0; + if (this->transform & TOGGLE_BOTTOM) + { + dy = -ceil(30 * (1 - k_bottom)); + } + if (this->transform & TOGGLE_TOP) + { + dy = ceil(30 * (1 - k_top)); + } + if (this->transform & TOGGLE_LEFT) + { + dx = ceil(30 * (1 - k_left)); + } + if (this->transform & TOGGLE_RIGHT) + { + dx = -ceil(30 * (1 - k_right)); + } + // exit if window isn't on the current wirtual desktop: + if (screen->currentOutputDev ().workArea ().width() < window->x() + ||screen->currentOutputDev ().workArea ().x() > (window->x()+window->width()) + ||screen->currentOutputDev ().workArea ().height() < window->y() + ||screen->currentOutputDev ().workArea ().y() > (window->y()+window->height())) + return true; + + if (dx != 0 || dy != 0) + window->moveToViewportPosition (window->x () + dx, window->y () + dy, true); + + const int GRID_SIZE = 50; + float width = window->width () + 10; + float y = screen->currentOutputDev ().workArea ().y () + screen->currentOutputDev ().workArea ().height () - BEND_SIZE; + float height = BEND_SIZE; + float x = window->x () - 5; + if (x < 0) + { + width += x; + x = 0; + } + + GLMatrix mTransform = transform; + float xTranslate, yTranslate; + float const mScale = 0.99999; // chose 'almost 1:1 scale' for the window to work with it as with texture + mask |= PAINT_WINDOW_TRANSFORMED_MASK; // setting a mask + // making scaling transformations of a window: + xTranslate = window->input ().left * (mScale - 1.0f); + yTranslate = window->input ().top * (mScale - 1.0f); + + mTransform.translate (window->x (), window->y (), 0); + mTransform.scale (mScale, mScale, 0); + mTransform.translate (xTranslate / mScale - window->x (), yTranslate / mScale - window->y (), 0.0f); + + gWindow->glPaint (attrib, mTransform, region, mask); // call paint handler of the parent class + // glAddGeometry should be automatically called at this moment + TWIST_SCREEN(screen); + + if (ts->optionGetTwistingType () == 0) + { + + glBindTexture (GL_TEXTURE_2D, texture); + glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, x, screen->height () - (y + height), width, height, 0); + + //glMatrixMode (GL_PROJECTION); + + //glPushMatrix (); + + //glLoadIdentity(); + //glOrtho(0, 0, screen->width (), screen->height (), -1, 1); + + glEnable (GL_TEXTURE_2D); + + float x1 = x; + float x2 = x + width; + float dy = float(height - 28) / GRID_SIZE; + glBegin (GL_QUADS); + for (int i = 0; i < GRID_SIZE; ++i) + { + float y1 = y + dy * i; + float y2 = y + dy * (i + 1); + float z1 = f(y1 - y); + float z2 = f(y2 - y); + + float texY1 = 1 - float (i) / GRID_SIZE; + float texY2 = 1 - float (i + 1) / GRID_SIZE; + glTexCoord2f (0.0f, texY2);glVertex3f (x1, y2, z2); // bottom left + glTexCoord2f (1.0f, texY2);glVertex3f (x2, y2, z2); // bottom right + glTexCoord2f (1.0f, texY1);glVertex3f (x2, y1, z1); // top right + glTexCoord2f (0.0f, texY1);glVertex3f (x1, y1, z1); // top left + } + glEnd (); + + glBindTexture (GL_TEXTURE_2D, 0); + glDisable (GL_TEXTURE_2D); + + //glPopMatrix (); + + } + } + else + { + //TWIST_WINDOW (window); + //tw->gWindow->glAddGeometrySetEnabled (tw, false); + gWindow->glPaint (attrib, transform, region, mask); + //tw->gWindow->glAddGeometrySetEnabled (tw, true); + } + + return true; +} + +void +TwistWindow::glAddGeometry (const GLTexture::MatrixList& matrices, + const CompRegion& region, + const CompRegion& clip, + unsigned int maxGridWidth, + unsigned int maxGridHeight) +{ // transforming part of the window + // oldVCount - old amount of vertices + // workArea().y - height of an apper panel + // workArea().height - height of the working area + // bendingBorderY - upper border of the window compressed area in screen coordinates + // k is a scale factor for the concrete window + int i, oldVCount = gWindow->geometry ().vCount; + GLfloat *v; + + bendingBorderBottom = screen->currentOutputDev ().workArea ().y () + screen->currentOutputDev ().workArea ().height () - BEND_SIZE; + k_bottom = BEND_SIZE / (window->y () + window->height () + 5 - bendingBorderBottom); + + bendingBorderTop = screen->currentOutputDev ().workArea ().y () + BEND_SIZE; + k_top = (BEND_SIZE) / (bendingBorderTop - window->y () + 20); + + bendingBorderLeft = screen->currentOutputDev ().workArea ().x () + BEND_SIZE; + k_left = BEND_SIZE / (bendingBorderLeft - window->x () + 5); + + bendingBorderRight = screen->currentOutputDev ().workArea ().x () + screen->currentOutputDev ().workArea ().width () - BEND_SIZE; + k_right = BEND_SIZE / (window->x () + window->width () + 5 - bendingBorderRight); + + gWindow->glAddGeometry (matrices, region, clip, // parent function + MIN(maxGridWidth , 50), // here window is painted + MIN(maxGridHeight , 50)); // v will be array of vertices coordinates + v = gWindow->geometry ().vertices; // v points to window vertices array + v += gWindow->geometry ().vertexStride - 3; // going 1 vertex (3 coordinates) back + v += gWindow->geometry ().vertexStride * oldVCount; // passing old vertices + + int toggle = transform & (TOGGLE_BOTTOM | TOGGLE_TOP | TOGGLE_LEFT | TOGGLE_RIGHT); + transform = NONE; + + if (k_bottom < 1 && k_bottom > 0) + { + transform |= BOTTOM | (toggle & TOGGLE_BOTTOM); + } + if (k_top < 1 && k_top > 0) + { + transform |= TOP | (toggle & TOGGLE_TOP); + } + if (k_left < 1 && k_left > 0) + { + transform |= LEFT | (toggle & TOGGLE_LEFT); + } + if (k_right < 1 && k_right > 0) + { + transform |= RIGHT | (toggle & TOGGLE_RIGHT); + } + + for (i = oldVCount; i < gWindow->geometry ().vCount; i++) // for all new vertices + { + if (transform & BOTTOM && v[1] > bendingBorderBottom) // if vertex is in bottom scaled area + { + v[1] = bendingBorderBottom + (v[1] - bendingBorderBottom) * k_bottom ; // changing its y coord + } + if (transform & TOP && v[1] < bendingBorderTop) // if vertex is in top scaled area + { + v[1] = (screen->currentOutputDev ().workArea ().y () + BEND_SIZE) * (1 - k_top) + v[1] * k_top; + } + if (transform & RIGHT && v[0] > bendingBorderRight) // if vertex is in right scaled area + { + v[0] = bendingBorderRight + (v[0] - bendingBorderRight) * k_right; + } + if (transform & LEFT && v[0] < bendingBorderLeft) // if vertex is in left scaled area + { + v[0] = (screen->currentOutputDev ().workArea ().x () + BEND_SIZE) * (1 - k_left) + v[0] * k_left; + } + + v += gWindow->geometry ().vertexStride; // passing one vertex + } + +} + +void +TwistScreen::donePaint () +{ + foreach (CompWindow *w, screen->windows ()) + { + TWIST_WINDOW(w); + + if (tw->transform != NONE) + { + tw->cWindow->addDamage (); + } + } + cScreen->donePaint (); + +} + +void +TwistScreen::handleEvent (XEvent *event) +{ + /*switch (event->type) + { + case ButtonPrets: + if (pointerY > 650 && optionGetTwistingType () == 1) + { + CompWindow *window = screen->findWindow (screen->activeWindow ()); + const float bendingBorderY = 650.0; + const float k = (screen->currentOutputDev ().workArea ().y () + screen->currentOutputDev ().workArea ().height () - bendingBorderY) / (window->y () + window->height () - bendingBorderY); + float y = bendingBorderY + (pointerY - bendingBorderY) / k; + pointerY = y; + event->type = ButtonRelease; + screen->handleEvent (event); + event->type = ButtonPrets; + screen->warpPointer (0 , y - pointerY); + if (XSendEvent(XOpenDisplay(NULL), PointerWindow, True, ButtonReleaseMask, event) == 0) + std::cout << "Error to send the event!"; + } + break; + }*/ + + screen->handleEvent (event); +} + + +TwistScreen::TwistScreen (CompScreen *screen) : + PluginClassHandler <TwistScreen, CompScreen> (screen), + cScreen (CompositeScreen::get (screen)), + gScreen (GLScreen::get (screen)) +{ + ScreenInterface::setHandler (screen, false); + CompositeScreenInterface::setHandler (cScreen, false); + GLScreenInterface::setHandler (gScreen, false); + + pollHandle.setCallback (boost::bind (&TwistScreen::positionUpdate, this, _1)); + pollHandle.start (); + + toggleScreenFunctions(true); +} + +TwistScreen::~TwistScreen () +{ + pollHandle.stop (); +} + +TwistWindow::TwistWindow (CompWindow *window) : + PluginClassHandler <TwistWindow, CompWindow> (window), + window (window), + cWindow (CompositeWindow::get (window)), + gWindow (GLWindow::get (window)), + transform(NONE), + bendingBorderTop(0), + bendingBorderBottom(0), + bendingBorderLeft(0), + bendingBorderRight(0) +{ + WindowInterface::setHandler (window, false); + CompositeWindowInterface::setHandler (cWindow, false); + GLWindowInterface::setHandler (gWindow, false); + + + glGenTextures (1, &texture); + + glEnable (GL_TEXTURE_2D); + + //Bind the texture + glBindTexture (GL_TEXTURE_2D, texture); + + // Load the parameters + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); + + glTexImage2D (GL_TEXTURE_2D, 0, GL_RGB, 0, 0, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); + + glBindTexture (GL_TEXTURE_2D, 0); + glDisable (GL_TEXTURE_2D); + + if (window->wmType () & 65283) + //not (CompWindowTypeDesktopMask | CompWindowTypeDockMask) and etc + return; + + toggleWindowFunctions (window, true); +} + +void +TwistScreen::positionUpdate (const CompPoint & pos) +{ + CompWindow *w = screen->findWindow (screen->activeWindow ()); + TWIST_WINDOW (w); + + int posX = pos.x (); + int posY = pos.y (); + + if (tw->transform & BOTTOM && posY >= tw->bendingBorderBottom && posX >= w->x () && posX <= w->x () + w->width ()) + { + tw->transform |= TOGGLE_BOTTOM; + } + if (tw->transform & TOP && posY <= tw->bendingBorderTop && posX >= w->x () && posX <= w->x () + w->width ()) + { + tw->transform |= TOGGLE_TOP; + } + if (tw->transform & LEFT && posX <= tw->bendingBorderLeft && posY >= w->y () - 20 && posY <= w->y () + w->height ()) + { + tw->transform |= TOGGLE_LEFT; + } + if (tw->transform & RIGHT && posX >= tw->bendingBorderRight && posY >= w->y () - 20 && posY <= w->y () + w->height ()) + { + tw->transform |= TOGGLE_RIGHT; + } +} + +TwistWindow::~TwistWindow () { } + +bool +TwistPluginVTable::init () +{ + if (!CompPlugin::checkPluginABI ("core", CORE_ABIVERSION)) + return false; + if (!CompPlugin::checkPluginABI ("composite", COMPIZ_COMPOSITE_ABI)) + return false; + if (!CompPlugin::checkPluginABI ("opengl", COMPIZ_OPENGL_ABI)) + return false; + + if (!screen->XShape ()) + { + compLogMessage ("twist", CompLogLevelError, + "No Shape extension found. Twisting not potsible \n"); + return false; + } + compLogMessage ("twist", CompLogLevelWarn, "Hello from twist!\n"); + return true; +} diff --git a/src/twist.h b/src/twist.h new file mode 100644 index 0000000..f63f270 --- /dev/null +++ b/src/twist.h @@ -0,0 +1,125 @@ +/* +* twist.h + +* Description: +
+* The plugin dynamically compresses bottom part of selected windows to enlarge free space on the desktop. +* "Twisted" window thus has reduced height, while still readable (more or less). +* The feature should be especially useful on netbooks for their weak vertical screen resolution. +* Please note that while being quiet usable, twist was created as an experiment to find out ways of improving modern hardware-accelerated GUI. +* So don't panic if its experimental nature would show itself in some bad way
+
+* Using the plugin:
+* To twist a window you should drag it down, and continue dragging after the screen bottom is reached. Twisted window consists of two parts - +* normal (upper) part, which is accessible by mouse as usually, and compressed (lower) one. As for now, compressed part of the window can be accessed +* only by keyboard, but in many cases that is not a problem, as most clickable elements (like menus or toolbars) often are residing on top.
+
+* Contributions:
+
+* The concept and the code created by Dmitriy Kostiuk (d.k AT list.ru) and Alexander Nikoniuk (nikoniuk AT mail.ru).
+
+* The code is licensed under GPL v.2.
+* The plugin was created in bounds of a research project in Micro and Midi-ergonomisc Laboratory of Brest State Technical University +*/ + +#include <cmath> + +#include <core/core.h> +#include <composite/composite.h> +#include <opengl/opengl.h> +#include <mousepoll/mousepoll.h> + +#include "twist_options.h" + +const int BEND_SIZE = 125; +enum Transformation +{ + NONE = 0, + BOTTOM = 1, + TOP = 2, + LEFT = 4, + RIGHT = 8, + TOGGLE_BOTTOM = 16, + TOGGLE_TOP = 32, + TOGGLE_LEFT = 64, + TOGGLE_RIGHT = 128 +}; + +class TwistWindow : + public PluginClassHandler <TwistWindow, CompWindow>, + public WindowInterface, + public CompositeWindowInterface, + public GLWindowInterface +{ + public: + + int transform; + float bendingBorderTop, bendingBorderBottom, bendingBorderLeft, bendingBorderRight; + float k_top, k_bottom, k_left, k_right; // compression ratios + + GLuint texture; + + TwistWindow (CompWindow *); + ~TwistWindow (); + + CompWindow *window; + CompositeWindow *cWindow; + GLWindow *gWindow; + + bool + glPaint (const GLWindowPaintAttrib &, + const GLMatrix &, + const CompRegion &, + unsigned int); + + void glAddGeometry (const GLTexture::MatrixList&, + const CompRegion&, const CompRegion&, + unsigned int, unsigned int); + +}; + +#define TWIST_WINDOW(w) \ + TwistWindow *tw = TwistWindow::get (w) + +#define TWIST_SCREEN(w) \ + TwistScreen *ts = TwistScreen::get (w) + +class TwistScreen : + public PluginClassHandler <TwistScreen, CompScreen>, + public ScreenInterface, + public CompositeScreenInterface, + public GLScreenInterface, + public TwistOptions +{ + public: + + TwistScreen (CompScreen *); + ~TwistScreen (); + + CompositeScreen *cScreen; + GLScreen *gScreen; + + void + donePaint (); + + bool + Activate (CompAction *action, + CompAction::State state, + CompOption::Vector options); + + void + handleEvent (XEvent *event); + + MousePoller pollHandle; + + void + positionUpdate (const CompPoint &); + +}; + +class TwistPluginVTable : + public CompPlugin::VTableForScreenAndWindow <TwistScreen, TwistWindow> +{ + public: + bool init (); +}; diff --git a/twist.xml.in b/twist.xml.in new file mode 100644 index 0000000..9081e41 --- /dev/null +++ b/twist.xml.in @@ -0,0 +1,39 @@ +<?xml version="1.0"?> +<compiz> + <plugin name="twist" useBcop="true"> + <_short>Twist </_short> + <_long>allows you to twist bottom part of the window that doesn't fit the screen</_long> + <category>Window Management</category> + <deps> + <requirement> + <plugin>opengl</plugin> + </requirement> + <relation type="after"> + <plugin>composite</plugin> + <plugin>opengl</plugin> + <plugin>wall</plugin> + <plugin>decor</plugin> + </relation> + </deps> + <options> + <group> + <_short>Bindings</_short> + <option name="twisting_type" type="int"> + <_short>Twisting type</_short> + <_long>How to twist the bottom part of the window</_long> + <min>0</min> + <max>1</max> + <default>0</default> + <desc> + <value>0</value> + <_name>Screw</_name> + </desc> + <desc> + <value>1</value> + <_name>Compress</_name> + </desc> + </option> + </group> + </options> + </plugin> +</compiz> |