summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt5
-rw-r--r--dock.xml.in40
-rw-r--r--dummy0
-rw-r--r--src/dock.cpp323
-rw-r--r--src/dock.h135
-rw-r--r--src/ipw.cpp108
-rw-r--r--src/ipw.h40
7 files changed, 651 insertions, 0 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..df19c66
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,5 @@
+find_package (Compiz REQUIRED)
+
+include (CompizPlugin)
+
+compiz_plugin (dock PLUGINDEPS composite opengl)
diff --git a/dock.xml.in b/dock.xml.in
new file mode 100644
index 0000000..17f535c
--- /dev/null
+++ b/dock.xml.in
@@ -0,0 +1,40 @@
+<?xml version="1.0"?>
+<compiz>
+ <plugin name="dock" useBcop="true">
+ <_short>Dock</_short>
+ <_long>Description</_long>
+ <category>Window Management</category>
+ <deps>
+ <requirement>
+ <plugin>composite</plugin>
+ <plugin>opengl</plugin>
+ </requirement>
+ <relation type="after">
+ <plugin>composite</plugin>
+ <plugin>opengl</plugin>
+ <plugin>cube</plugin>
+ <plugin>expo</plugin>
+ </relation>
+ </deps>
+
+ <options>
+ <group>
+ <_short>Bindings</_short>
+ <option name="toggle_key" type="key">
+ <_short>Toggle docked state</_short>
+ <default>&lt;Super&gt;t</default>
+ </option>
+ </group>
+
+ <group>
+ <_short>Behaviour</_short>
+ <option name="window_match" type="match">
+ <_short>dock Windows</_short>
+ <_long>Windows that can be docked</_long>
+ <default>Normal</default>
+ </option>
+ </group>
+
+ </options>
+ </plugin>
+</compiz>
diff --git a/dummy b/dummy
deleted file mode 100644
index e69de29..0000000
--- a/dummy
+++ /dev/null
diff --git a/src/dock.cpp b/src/dock.cpp
new file mode 100644
index 0000000..5d9aa0c
--- /dev/null
+++ b/src/dock.cpp
@@ -0,0 +1,323 @@
+#include "dock.h"
+
+COMPIZ_PLUGIN_20090315 (dock, DockPluginVTable);
+
+
+void DockScreen::toggleHandlers(bool state) {
+ screen->handleEventSetEnabled(this, state);
+}
+
+void DockWindow::toggleHandlers(bool state) {
+ window->moveNotifySetEnabled(this, state);
+ gWindow->glPaintSetEnabled(this, state);
+}
+
+
+DockWindow::DockWindow (CompWindow *window) :
+ PluginClassHandler <DockWindow, CompWindow> (window),
+ cWindow (CompositeWindow::get (window)),
+ gWindow (GLWindow::get (window)),
+ window (window),
+ ipw (NULL)
+{
+ WindowInterface::setHandler (window, false);
+ CompositeWindowInterface::setHandler (cWindow, false);
+ GLWindowInterface::setHandler (gWindow, false);
+
+ /* dock all windows by default */
+ DockScreen::get(screen)->setWindowDocked(this, true);
+}
+
+bool DockWindow::isDockable() const {
+ DOCK_SCREEN(screen);
+
+ if (window->type() &
+ (CompWindowTypeDockMask |
+ CompWindowTypeDesktopMask))
+ return false;
+ if (window->state() &
+ (CompWindowStateSkipPagerMask | CompWindowStateShadedMask))
+ return false;
+ if (window->overrideRedirect() ||
+ window->invisible() ||
+ window->shaded() ||
+ window->minimized())
+ return false;
+
+ if (ss->optionGetWindowMatch().evaluate(window))
+ return true;
+
+ return false;
+}
+
+DockWindow::~DockWindow () {
+ DockScreen::get(screen)->setWindowDocked(this, false);
+ if (ipw) delete ipw;
+}
+
+
+DockScreen::DockScreen (CompScreen *screen) :
+ PluginClassHandler <DockScreen, CompScreen> (screen),
+ cScreen (CompositeScreen::get (screen)),
+ gScreen (GLScreen::get (screen)),
+ grabbedWindow (None),
+ grabIndex (0),
+ moveCursor (XCreateFontCursor(screen->dpy(), XC_fleur)),
+ docking_size (DOCKING_SIZE),
+ dock_spacing (10)
+{
+ ScreenInterface::setHandler (screen, false);
+ CompositeScreenInterface::setHandler (cScreen, false);
+ GLScreenInterface::setHandler (gScreen, false);
+
+ /* control bindings */
+ optionSetToggleKeyInitiate(boost::bind(&DockScreen::toggleDock, this, _1, _2, _3));
+}
+
+DockScreen::~DockScreen () {
+ if (moveCursor)
+ XFreeCursor(screen->dpy(), moveCursor);
+}
+
+bool DockWindow::dock(int docked_size) {
+
+ if (docked || !isDockable())
+ return false;
+
+ docked = true;
+ toggleHandlers(true);
+
+ int max_dim = window->height() > window->width() ?
+ window->height() : window->width();
+ // TODO: check for max_dim != 0
+ wScale = docked_size / (float)max_dim;
+
+ move_dx = move_dy = 0;
+
+ /* create the IPW */
+ if (ipw) delete ipw;
+ ipw = new IPWindow(window);
+
+ /* damage the window */
+ cWindow->addDamage();
+
+ return true;
+}
+
+
+bool DockWindow::undock() {
+ if (!docked || !isDockable())
+ return false;
+
+ docked = false;
+ toggleHandlers(true);
+ wScale = 1.0;
+
+ if (ipw) {
+ delete ipw;
+ ipw = NULL;
+ }
+
+ /* restore undocked window position */
+ window->move(-move_dx, -move_dy, true);
+ window->syncPosition();
+
+ /* damage the window */
+ cWindow->addDamage();
+
+ return true;
+}
+
+void DockScreen::setWindowDocked(DockWindow *w, bool docked) {
+ bool changed = false;
+
+ if (docked) {
+ if ((changed = w->dock(docking_size)))
+ dockedWindows.push_back(w);
+ } else {
+ if ((changed = w->undock()))
+ dockedWindows.remove(w);
+ }
+
+ if (changed) {
+ adjustDocked();
+ toggleHandlers(!dockedWindows.empty());
+ }
+}
+
+bool DockWindow::isDocked() const {
+ return docked;
+}
+
+bool DockScreen::toggleDock(CompAction *action, CompAction::State state,
+ CompOption::Vector options) {
+ CompWindow *w;
+ if (!(w = screen->findWindow(screen->activeWindow())))
+ return true;
+
+ DOCK_WINDOW(w);
+ setWindowDocked(sw, !sw->isDocked());
+
+ return true;
+}
+
+void DockWindow::dockMove(int dx, int dy) {
+
+ move_dx += dx; move_dy += dy;
+
+ window->move(dx, dy, true);
+ window->syncPosition();
+
+ if (ipw) ipw->syncIPW();
+}
+
+
+void DockScreen::adjustDocked() {
+
+ std::list<DockWindow*>::iterator it;
+ int x = dock_spacing;
+
+ for (it = dockedWindows.begin(); it != dockedWindows.end(); it++) {
+ CompWindow *w = (*it)->window;
+
+ int dx, dy;
+
+ dx = x - w->inputRect().x();
+ dy = dock_spacing - w->inputRect().y();
+
+ (*it)->dockMove(dx, dy);
+
+ x += (*it)->wScale * w->width() + dock_spacing;
+ }
+}
+
+
+void DockScreen::handleEvent(XEvent *ev) {
+ CompWindow *w;
+
+ switch (ev->type) {
+
+ case EnterNotify:
+ if ((w = IPW2OverridenWin(ev->xcrossing.window))) {
+ XEvent e;
+ memcpy(&e.xcrossing, &ev->xcrossing, sizeof(XCrossingEvent));
+ e.xcrossing.window = w->frame() ? w->frame() : w->id();
+ XSendEvent(screen->dpy(), w->id(), false, EnterWindowMask, &e);
+ }
+ break;
+
+ case MotionNotify:
+ if (grabIndex && (w = screen->findWindow(grabbedWindow))) {
+ int dx = ev->xmotion.x_root - motion_lastx;
+ int dy = ev->xmotion.y_root - motion_lasty;
+
+ DockWindow::get(w)->dockMove(dx, dy);
+
+ motion_lastx += dx;
+ motion_lasty += dy;
+ }
+ break;
+
+ case ButtonPress:
+ if ((w = IPW2OverridenWin(ev->xbutton.window))) {
+ if (!screen->otherGrabExist("dock", 0)) {
+ w->activate();
+ grabbedWindow = w->id();
+ grabIndex = screen->pushGrab(moveCursor, "dock");
+ motion_lastx = ev->xbutton.x_root;
+ motion_lasty = ev->xbutton.y_root;
+ }
+ }
+ break;
+
+ case ButtonRelease:
+ if ((w = screen->findWindow(grabbedWindow))) {
+ setWindowDocked(DockWindow::get(w), false);
+ grabbedWindow = None;
+ if (grabIndex) {
+ w->moveInputFocusTo();
+ screen->removeGrab(grabIndex, NULL);
+ grabIndex = 0;
+ }
+ }
+ break;
+
+ }
+
+ screen->handleEvent(ev);
+
+ switch (ev->type) {
+ case ConfigureNotify:
+
+ /* xconfigure.above holds the window which xconfigure.window is above of */
+
+ std::list<DockWindow*>::iterator it;
+ for (it = dockedWindows.begin();
+ it != dockedWindows.end(); it++) {
+
+ if ((*it)->ipw->overridenWin == ev->xconfigure.window) {
+ if (ev->xconfigure.above != (*it)->prev) {
+ (*it)->prev = ev->xconfigure.above;
+ (*it)->ipw->syncIPW();
+ }
+ }
+
+ if ((*it)->ipw->overridenWin == ev->xconfigure.above) {
+ if (ev->xconfigure.window != (*it)->next) {
+ (*it)->next = ev->xconfigure.window;
+ (*it)->ipw->syncIPW();
+ }
+ }
+ }
+ break;
+ }
+
+}
+
+
+bool DockWindow::glPaint(const GLWindowPaintAttrib &attrib,
+ const GLMatrix &transform,
+ const CompRegion &region, unsigned int mask) {
+
+ if (docked) {
+ GLMatrix mTrans = transform;
+ float tx, ty;
+ tx = window->input().left * (wScale - 1.0);
+ ty = window->input().top * (wScale - 1.0);
+
+ mTrans.translate(window->x(), window->y(), 0.0);
+ mTrans.scale(wScale, wScale, 1.0);
+ mTrans.translate(tx / wScale - window->x(),
+ ty / wScale - window->y(), 0.0);
+
+ mask |= PAINT_WINDOW_TRANSFORMED_MASK;
+
+ return gWindow->glPaint(attrib, mTrans, region, mask);
+ } else {
+ return gWindow->glPaint(attrib, transform, region, mask);
+ }
+}
+
+
+bool DockScreen::glPaintOutput(const GLScreenPaintAttrib &attrib,
+ const GLMatrix &transform, const CompRegion &region,
+ CompOutput *output, unsigned int mask) {
+
+ if (!dockedWindows.empty())
+ mask |= PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS_MASK;
+
+ return gScreen->glPaintOutput (attrib, transform, region, output, mask);
+}
+
+
+bool DockPluginVTable::init () {
+
+ if (!CompPlugin::checkPluginABI ("core", CORE_ABIVERSION) ||
+ !CompPlugin::checkPluginABI ("composite", COMPIZ_COMPOSITE_ABI) ||
+ !CompPlugin::checkPluginABI ("opengl", COMPIZ_OPENGL_ABI))
+ return false;
+
+ // TODO: check for XShape xtension
+
+ return true;
+}
diff --git a/src/dock.h b/src/dock.h
new file mode 100644
index 0000000..006e98c
--- /dev/null
+++ b/src/dock.h
@@ -0,0 +1,135 @@
+/*
+ * Compiz dock plugin
+ *
+ * dock.h
+ *
+ * Author(s):
+ * Rodolfo Granata <warlock.cc@gmail.com>
+ *
+ * Description:
+ *
+ */
+
+#ifndef _DOCK_H_
+#define _DOCK_H_
+
+#include <X11/extensions/shape.h>
+#include <X11/cursorfont.h>
+
+#include <cmath>
+
+#include <core/core.h>
+#include <composite/composite.h>
+#include <opengl/opengl.h>
+
+#include "dock_options.h"
+#include "ipw.h"
+
+#define DOCKING_SIZE 150.0 // pixel size of docked windows
+
+#define DOCK_SCREEN(s) \
+ DockScreen *ss = DockScreen::get (s)
+
+#define DOCK_WINDOW(w) \
+ DockWindow *sw = DockWindow::get (w)
+
+
+class DockWindow :
+ public PluginClassHandler <DockWindow, CompWindow>,
+ public WindowInterface,
+ public CompositeWindowInterface,
+ public GLWindowInterface
+{
+ public:
+ DockWindow (CompWindow *);
+ ~DockWindow ();
+
+ bool isDocked() const;
+ bool isDockable() const;
+ bool dock(int docked_size);
+ bool undock();
+
+ void dockMove(int dx, int dy);
+
+ //private:
+
+ CompositeWindow *cWindow;
+ GLWindow *gWindow;
+ CompWindow *window;
+ IPWindow *ipw;
+
+ float wScale;
+ bool docked;
+
+ /* undo vector */
+ int move_dx, move_dy;
+
+ /* restacking checks */
+ Window prev, next;
+
+ void toggleHandlers(bool state);
+
+ /* wraped handlers */
+ bool glPaint (const GLWindowPaintAttrib &, const GLMatrix &,
+ const CompRegion &, unsigned int);
+
+};
+
+class DockScreen :
+ public PluginClassHandler <DockScreen, CompScreen>,
+ public ScreenInterface,
+ public CompositeScreenInterface,
+ public GLScreenInterface,
+ public DockOptions
+{
+ public:
+
+ DockScreen (CompScreen *);
+ ~DockScreen ();
+
+ void setWindowDocked(DockWindow *w, bool docked);
+
+ //private:
+
+ CompositeScreen *cScreen;
+ GLScreen *gScreen;
+
+ Window grabbedWindow;
+ CompScreen::GrabHandle grabIndex;
+ Cursor moveCursor;
+
+ int motion_lastx, motion_lasty;
+
+ /* list of currently docked windows */
+ std::list<DockWindow*> dockedWindows;
+ /* Normalized size for docked windows */
+ int docking_size;
+ /* docked windows spacing */
+ int dock_spacing;
+
+ void adjustDocked();
+
+ bool toggleDock(CompAction *action, CompAction::State state,
+ CompOption::Vector options);
+
+ void toggleHandlers(bool state);
+
+ /* wraped handlers */
+ void handleEvent (XEvent *);
+
+ bool glPaintOutput (const GLScreenPaintAttrib &, const GLMatrix &,
+ const CompRegion &, CompOutput *, unsigned int);
+
+ private:
+
+};
+
+
+class DockPluginVTable :
+ public CompPlugin::VTableForScreenAndWindow <DockScreen, DockWindow>
+{
+ public:
+ bool init ();
+};
+
+#endif /* _DOCK_H_ */
diff --git a/src/ipw.cpp b/src/ipw.cpp
new file mode 100644
index 0000000..e7c7e25
--- /dev/null
+++ b/src/ipw.cpp
@@ -0,0 +1,108 @@
+#include "ipw.h"
+#include "dock.h"
+
+void IPWindow::clearOverridenShape() {
+ /* first retrieve current shape and save that fore later */
+ winRects = XShapeGetRectangles(screen->dpy(), overridenWin,
+ ShapeInput, &nRects, &rOrdering);
+
+ /* if returned shape matches exactly window shape =>
+ * window hasn't being shaped */
+ if (nRects == 1 &&
+ winRects[0].x == -compWin->serverGeometry().border() &&
+ winRects[0].y == -compWin->serverGeometry().border() &&
+ winRects[0].width == compWin->serverWidth() +
+ 2 * compWin->serverGeometry().border() &&
+ winRects[0].height == compWin->serverHeight() +
+ 2 * compWin->serverGeometry().border()) {
+ nRects = 0;
+ }
+
+ /* clear shape */
+ XShapeSelectInput(screen->dpy(), overridenWin, NoEventMask);
+ XShapeCombineRectangles(screen->dpy(), overridenWin, ShapeInput,
+ 0, 0, NULL, 0, ShapeSet, 0);
+ XShapeSelectInput(screen->dpy(), overridenWin, ShapeNotify);
+}
+
+void IPWindow::restoreOverridenShape() {
+ if (nRects) {
+ XShapeCombineRectangles(screen->dpy(), overridenWin,
+ ShapeInput, 0, 0, winRects,
+ nRects, ShapeSet, rOrdering);
+ } else {
+ XShapeCombineMask(screen->dpy(), overridenWin,
+ ShapeInput, 0, 0, None, ShapeSet);
+ }
+
+ if (winRects) {
+ XFree(winRects);
+ nRects = -1;
+ rOrdering = 0;
+ }
+}
+
+
+/* put the IPW where the real window is */
+void IPWindow::syncIPW() {
+ XWindowChanges xwc;
+
+ DOCK_WINDOW(compWin);
+
+ xwc.x = compWin->inputRect().x();
+ xwc.y = compWin->inputRect().y();
+ xwc.width = compWin->inputRect().width() * sw->wScale;
+ xwc.height = compWin->inputRect().height() * sw->wScale;
+ xwc.stack_mode = Below;
+ xwc.sibling = overridenWin;
+
+ XConfigureWindow(screen->dpy(), ipwWin,
+ CWSibling | CWStackMode | CWX | CWY | CWWidth | CWHeight, &xwc);
+}
+
+
+IPWindow::IPWindow(CompWindow *cw) : compWin(cw) {
+ XSetWindowAttributes attrib;
+
+ /* select windo to override */
+ overridenWin = cw->frame() ? cw->frame() : cw->id();
+
+ clearOverridenShape();
+
+ /* Create input prevention window (IPW) */
+ attrib.override_redirect = true;
+ attrib.event_mask = 0;
+
+ ipwWin = XCreateWindow(screen->dpy(), screen->root(), 0, 0, 100, 100,
+ 0, CopyFromParent, InputOnly, CopyFromParent,
+ CWEventMask | CWOverrideRedirect, &attrib);
+
+ XMapWindow(screen->dpy(), ipwWin);
+ /* put the IPW over the real window */
+ syncIPW();
+}
+
+IPWindow::~IPWindow() {
+ restoreOverridenShape();
+ XUnmapWindow(screen->dpy(), ipwWin);
+ XDestroyWindow(screen->dpy(), ipwWin);
+}
+
+
+
+CompWindow *IPW2OverridenWin(Window ipw) {
+
+ DOCK_SCREEN(screen);
+
+ std::list<DockWindow *>::iterator it;
+
+ for (it = ss->dockedWindows.begin();
+ it != ss->dockedWindows.end(); it++)
+ if ((*it)->ipw && (*it)->ipw->ipwWin == ipw)
+ return (*it)->window;
+
+ /* not an IPW window */
+ return NULL;
+}
+
+/* vim: set sw=2 sts=2 : */
diff --git a/src/ipw.h b/src/ipw.h
new file mode 100644
index 0000000..9e961e6
--- /dev/null
+++ b/src/ipw.h
@@ -0,0 +1,40 @@
+/*
+ * Rodolfo Granata <warlock.cc@gmail.com>
+ */
+
+#ifndef _IPW_H_
+#define _IPW_H_
+
+#include <core/core.h>
+
+class IPWindow {
+ public:
+
+ IPWindow(CompWindow *);
+ ~IPWindow();
+
+ void syncIPW();
+
+ //private:
+
+ void clearOverridenShape();
+ void restoreOverridenShape();
+
+ /* actual window we're preventing input to */
+ CompWindow *compWin;
+ /* Xwindow we're preventing input to */
+ Window overridenWin;
+ /* input prevention window */
+ Window ipwWin;
+
+ /* saved shape */
+ XRectangle *winRects;
+ int nRects;
+ int rOrdering;
+};
+
+CompWindow *IPW2OverridenWin(Window ipw);
+
+#endif /* _IPW_H_ */
+
+/* vim: set sw=2 sts=2 : */