summaryrefslogtreecommitdiff
path: root/beryl-plugins/src/thumbnail.c
diff options
context:
space:
mode:
authorquinn <quinn@d7aaf104-2d23-0410-ae22-9d23157bf5a3>2007-01-16 00:53:43 +0000
committerquinn <quinn@d7aaf104-2d23-0410-ae22-9d23157bf5a3>2007-01-16 00:53:43 +0000
commitaac67c294688894ba0cc8f660ecd6ab4e5ed104a (patch)
tree82f4fd920b5d179d6aae13c303b2fd94c92ae602 /beryl-plugins/src/thumbnail.c
parent24faec7e2d21870e397650bff3c7f8fd7420bc9b (diff)
downloadmarex-dev-aac67c294688894ba0cc8f660ecd6ab4e5ed104a.tar.gz
marex-dev-aac67c294688894ba0cc8f660ecd6ab4e5ed104a.tar.bz2
beryl-plugins:
* trunk thumbnail2 git-svn-id: file:///beryl/trunk@2698 d7aaf104-2d23-0410-ae22-9d23157bf5a3
Diffstat (limited to 'beryl-plugins/src/thumbnail.c')
-rw-r--r--beryl-plugins/src/thumbnail.c1211
1 files changed, 1211 insertions, 0 deletions
diff --git a/beryl-plugins/src/thumbnail.c b/beryl-plugins/src/thumbnail.c
new file mode 100644
index 0000000..1892f74
--- /dev/null
+++ b/beryl-plugins/src/thumbnail.c
@@ -0,0 +1,1211 @@
+/*
+ *
+ * Beryl thumbnail plugin
+ *
+ * thumbnail.c
+ *
+ * Copyright : (C) 2007 by Dennis Kasprzyk
+ * E-mail : onestone@beryl-project.org
+ *
+ * Based on thumbnail.c:
+ * Copyright : (C) 2007 Stjepan Glavina
+ * E-mail : stjepang@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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <X11/Xatom.h>
+#include <X11/extensions/Xrender.h>
+
+#include <beryl.h>
+#include "thumbnail_tex.h"
+
+#define GET_THUMB_DISPLAY(d) \
+ ((ThumbDisplay *) (d)->privates[displayPrivateIndex].ptr)
+
+#define THUMB_DISPLAY(d) \
+ ThumbDisplay *td = GET_THUMB_DISPLAY (d)
+
+#define GET_THUMB_SCREEN(s, td) \
+ ((ThumbScreen *) (s)->privates[(td)->screenPrivateIndex].ptr)
+
+#define THUMB_SCREEN(s) \
+ ThumbScreen *ts = GET_THUMB_SCREEN (s, GET_THUMB_DISPLAY (s->display))
+
+#define GET_THUMB_WINDOW(w, ts) \
+ ((ThumbWindow *) (w)->privates[(ts)->windowPrivateIndex].ptr)
+
+#define THUMB_WINDOW_PTR(w) \
+ GET_THUMB_WINDOW (w, \
+ GET_THUMB_SCREEN (w->screen, \
+ GET_THUMB_DISPLAY (w->screen->display)))
+
+#define THUMB_WINDOW(w) \
+ ThumbWindow *tw = THUMB_WINDOW_PTR(w)
+
+#define NUM_OPTIONS(s) (sizeof ((s)->opt) / sizeof (CompOption))
+
+#define WIN_X(w) ((w)->attrib.x - (w)->input.left)
+#define WIN_Y(w) ((w)->attrib.y - (w)->input.top)
+#define WIN_W(w) ((w)->width + (w)->input.left + (w)->input.right)
+#define WIN_H(w) ((w)->height + (w)->input.top + (w)->input.bottom)
+
+#define THUMB_SIZE_DEFAULT 200
+#define THUMB_SIZE_MIN 50
+#define THUMB_SIZE_MAX 1500
+
+#define THUMB_DELAY_DEFAULT 1000
+#define THUMB_DELAY_MIN 100
+#define THUMB_DELAY_MAX 10000
+
+#define THUMB_FADE_DEFAULT 0.5
+#define THUMB_FADE_MIN 0.0
+#define THUMB_FADE_MAX 5.0
+#define THUMB_FADE_PRECISION 0.1
+
+#define THUMB_COLOR_RED_DEFAULT 0x0000
+#define THUMB_COLOR_GREEN_DEFAULT 0x0000
+#define THUMB_COLOR_BLUE_DEFAULT 0x0000
+#define THUMB_COLOR_ALPHA_DEFAULT 0x7fff
+
+#define THUMB_BORDER_DEFAULT 16
+#define THUMB_BORDER_MIN 1
+#define THUMB_BORDER_MAX 32
+
+#define THUMB_CURRENT_VIEWPORT_DEFAULT TRUE
+#define THUMB_ALLWAYS_TOP_DEFAULT FALSE
+
+#define THUMB_SCREEN_OPTION_SIZE 0
+#define THUMB_SCREEN_OPTION_DELAY 1
+#define THUMB_SCREEN_OPTION_COLOR 2
+#define THUMB_SCREEN_OPTION_BORDER 3
+#define THUMB_SCREEN_OPTION_FADE 4
+#define THUMB_SCREEN_OPTION_CURRENT_VIEWPORT 5
+#define THUMB_SCREEN_OPTION_ALLWAYS_TOP 6
+#define THUMB_SCREEN_OPTION_NUM 7
+
+#define THUMB_MOUSE_UPDATE_SPEED 100
+
+static int displayPrivateIndex;
+
+typedef struct _ThumbDisplay {
+ int screenPrivateIndex;
+
+ HandleEventProc handleEvent;
+ Atom winIconGeometryAtom;
+
+} ThumbDisplay;
+
+typedef struct _Thumbnail {
+ int x;
+ int y;
+ int width;
+ int height;
+ float scale;
+ float opacity;
+ int offset;
+ CompWindow *win;
+ CompWindow *dock;
+} Thumbnail;
+
+typedef struct _ThumbScreen {
+ int windowPrivateIndex;
+
+ CompTimeoutHandle mouseTimeout;
+ CompTimeoutHandle displayTimeout;
+
+ PreparePaintScreenProc preparePaintScreen;
+ PaintScreenProc paintScreen;
+ PaintWindowProc paintWindow;
+ DonePaintScreenProc donePaintScreen;
+ DamageWindowRectProc damageWindowRect;
+
+ CompWindow *dock;
+ CompWindow *pointedWin;
+ Bool showingThumb;
+ Thumbnail thumb;
+ Thumbnail oldThumb;
+
+ CompTexture glowTexture;
+
+ CompOption opt[THUMB_SCREEN_OPTION_NUM];
+} ThumbScreen;
+
+typedef struct _IconGeometry {
+ int x;
+ int y;
+ int width;
+ int height;
+ Bool isSet;
+} IconGeometry;
+
+typedef struct _ThumbWindow {
+ IconGeometry ig;
+} ThumbWindow;
+
+
+static void
+updateWindowIconGeometry (CompWindow *w)
+{
+ THUMB_DISPLAY(w->screen->display);
+ THUMB_WINDOW(w);
+
+ Atom actual;
+ int result, format;
+ unsigned long n, left;
+ unsigned char *data;
+ unsigned long *mydata;
+
+ result = XGetWindowProperty (w->screen->display->display,
+ w->id, td->winIconGeometryAtom, 0L, 4L,
+ FALSE, XA_CARDINAL, &actual, &format, &n,
+ &left, &data);
+
+ mydata = (unsigned long *) data;
+
+ tw->ig.isSet = FALSE;
+
+ if (result == Success && actual == XA_CARDINAL && n == 4)
+ {
+ tw->ig.x = mydata[0];
+ tw->ig.y = mydata[1];
+ tw->ig.width = mydata[2];
+ tw->ig.height = mydata[3];
+ tw->ig.isSet = TRUE;
+ XFree (data);
+ }
+}
+
+static void
+damageThumbRegion (CompScreen *s, Thumbnail *t)
+{
+ REGION region;
+ region.extents.x1 = t->x - t->offset;
+ region.extents.y1 = t->y - t->offset;
+ region.extents.x2 = region.extents.x1 + t->width + (t->offset * 2);
+ region.extents.y2 = region.extents.y1 + t->height + (t->offset * 2);
+ region.rects = &region.extents;
+ region.numRects = region.size = 1;
+
+ damageScreenRegion(s, &region);
+}
+
+#define GET_DISTANCE(a,b) \
+ (sqrt((((a)[0] - (b)[0]) * ((a)[0] - (b)[0])) + \
+ (((a)[1] - (b)[1]) * ((a)[1] - (b)[1]))))
+
+static void
+thumbUpdateThumbnail( CompScreen *s)
+{
+ THUMB_SCREEN(s);
+
+ if (ts->thumb.win == ts->pointedWin)
+ return;
+
+ if (ts->thumb.opacity > 0.0 && ts->oldThumb.opacity > 0.0)
+ return;
+
+ if (ts->thumb.win)
+ damageThumbRegion(s,&ts->thumb);
+ ts->oldThumb = ts->thumb;
+
+ ts->thumb.win = ts->pointedWin;
+ ts->thumb.dock = ts->dock;
+
+ if (!ts->thumb.win)
+ return;
+
+ float maxSize = ts->opt[THUMB_SCREEN_OPTION_SIZE].value.i;
+ double scale = 1.0;
+ // do we nee to scale the window down?
+ if (WIN_W(ts->thumb.win) > maxSize || WIN_H(ts->thumb.win) > maxSize)
+ {
+ if (WIN_W(ts->thumb.win) >= WIN_H(ts->thumb.win))
+ scale = maxSize / WIN_W(ts->thumb.win);
+ else
+ scale = maxSize / WIN_H(ts->thumb.win);
+ }
+ ts->thumb.width = WIN_W(ts->thumb.win) * scale;
+ ts->thumb.height = WIN_H(ts->thumb.win) * scale;
+
+ ts->thumb.scale = scale;
+
+ THUMB_WINDOW(ts->thumb.win);
+
+ int igMidPoint[2] = { tw->ig.x + (tw->ig.width / 2),
+ tw->ig.y + (tw->ig.height / 2)};
+
+ int tMidPoint[2];
+ int tPos[2];
+ int tmpPos[2];
+ float distance = 1000000;
+ int off = ts->opt[THUMB_SCREEN_OPTION_BORDER].value.i;
+ int oDev = screenGetOutputDev(s,tw->ig.x,tw->ig.y,tw->ig.width,tw->ig.height);
+ int ox1,oy1,ox2,oy2,ow,oh;
+ if (s->nOutputDev == 1 || oDev > s->nOutputDev)
+ {
+ ox1 = 0;
+ oy1 = 0;
+ ox2 = s->width;
+ oy2 = s->height;
+ ow = s->width;
+ oh = s->height;
+ }
+ else
+ {
+ --oDev;
+ ox1 = s->outputDev[oDev].region.extents.x1;
+ ox2 = s->outputDev[oDev].region.extents.x2;
+ oy1 = s->outputDev[oDev].region.extents.y1;
+ oy2 = s->outputDev[oDev].region.extents.y2;
+ ow = ox2 - ox1;
+ oh = oy2 - oy1;
+ }
+
+ // failsave position
+ tPos[0] = igMidPoint[0] - (ts->thumb.width / 2.0);
+ if (tw->ig.y - ts->thumb.height >= 0)
+ {
+ tPos[1] = tw->ig.y - ts->thumb.height;
+ }
+ else
+ {
+ tPos[1] = tw->ig.y + tw->ig.height;
+ }
+
+ // above
+ tmpPos[0] = igMidPoint[0] - (ts->thumb.width / 2.0);
+ if (tmpPos[0] - off < ox1)
+ tmpPos[0] = ox1 + off;
+ if (tmpPos[0] + off + ts->thumb.width > ox2)
+ {
+ if (ts->thumb.width + (2*off) - ow > 0)
+ tmpPos[0] = ox2 - tmpPos[0] - off;
+ else
+ tmpPos[0] = ox1 + off;
+ }
+ tMidPoint[0] = tmpPos[0] + (ts->thumb.width / 2.0);
+
+ tmpPos[1] = WIN_Y(ts->dock) - ts->thumb.height - off;
+ tMidPoint[1] = tmpPos[1] + (ts->thumb.height / 2.0);
+ if (tmpPos[1] > oy1)
+ {
+ tPos[0] = tmpPos[0];
+ tPos[1] = tmpPos[1];
+ distance = GET_DISTANCE(igMidPoint,tMidPoint);
+ }
+
+ // below
+ tmpPos[1] = WIN_Y(ts->dock) + WIN_H(ts->dock) + off;
+ tMidPoint[1] = tmpPos[1] + (ts->thumb.height / 2.0);
+ if (tmpPos[1] + ts->thumb.height + off < oy2 &&
+ GET_DISTANCE(igMidPoint,tMidPoint) < distance)
+ {
+ tPos[0] = tmpPos[0];
+ tPos[1] = tmpPos[1];
+ distance = GET_DISTANCE(igMidPoint,tMidPoint);
+ }
+
+ // left
+ tmpPos[1] = igMidPoint[1] - (ts->thumb.height / 2.0);
+ if (tmpPos[1] - off < oy1)
+ tmpPos[1] = oy1 + off;
+ if (tmpPos[1] + off + ts->thumb.height > oy2)
+ {
+ if (ts->thumb.height + (2*off) - oh > 0)
+ tmpPos[1] = oy2 - tmpPos[1] - off;
+ else
+ tmpPos[1] = oy1 + off;
+ }
+ tMidPoint[1] = tmpPos[1] + (ts->thumb.height / 2.0);
+
+ tmpPos[0] = WIN_X(ts->dock) - ts->thumb.width - off;
+ tMidPoint[0] = tmpPos[0] + (ts->thumb.width / 2.0);
+ if (tmpPos[0] > ox1 &&
+ GET_DISTANCE(igMidPoint,tMidPoint) < distance)
+ {
+ tPos[0] = tmpPos[0];
+ tPos[1] = tmpPos[1];
+ distance = GET_DISTANCE(igMidPoint,tMidPoint);
+ }
+
+ // right
+ tmpPos[0] = WIN_X(ts->dock) + WIN_W(ts->dock) + off;
+ tMidPoint[0] = tmpPos[0] + (ts->thumb.width / 2.0);
+ if (tmpPos[0] + ts->thumb.width + off < ox2 &&
+ GET_DISTANCE(igMidPoint,tMidPoint) < distance)
+ {
+ tPos[0] = tmpPos[0];
+ tPos[1] = tmpPos[1];
+ distance = GET_DISTANCE(igMidPoint,tMidPoint);
+ }
+
+ ts->thumb.x = tPos[0];
+ ts->thumb.y = tPos[1];
+
+ ts->thumb.offset = off;
+
+ ts->thumb.opacity = 0.0;
+
+ damageThumbRegion(s,&ts->thumb);
+}
+
+static Bool
+thumbShowThumbnail (void *vs)
+{
+ CompScreen *s = (CompScreen *) vs;
+ THUMB_SCREEN(s);
+ ts->showingThumb = TRUE;
+ thumbUpdateThumbnail(s);
+ damageThumbRegion(s,&ts->thumb);
+ return TRUE;
+}
+
+static Bool
+checkPosition (CompWindow *w)
+{
+ THUMB_SCREEN(w->screen);
+
+ if (ts->opt[THUMB_SCREEN_OPTION_CURRENT_VIEWPORT].value.b)
+ {
+ // TODO: We need a faster calculation here
+ Bool onViewport = FALSE;
+ Region reg = XCreateRegion();
+ XIntersectRegion(w->region,&w->screen->region,reg);
+ if (reg->numRects)
+ onViewport = TRUE;
+ XDestroyRegion(reg);
+ if (!onViewport)
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static Bool
+thumbUpdateMouse (void *vs)
+{
+ CompScreen *s = (CompScreen *) vs;
+
+ THUMB_SCREEN(s);
+
+ int winX, winY;
+ int rootX, rootY;
+ unsigned int mask_return;
+ Window root_return;
+ Window child_return;
+
+ XQueryPointer(s->display->display, s->root,
+ &root_return, &child_return,
+ &rootX, &rootY, &winX,
+ &winY, &mask_return);
+
+ CompWindow *w = findWindowAtDisplay(s->display, child_return);
+
+ if (w && w->type & CompWindowTypeDockMask)
+ {
+ if (ts->dock != w)
+ {
+ ts->dock = w;
+ if (ts->displayTimeout)
+ {
+ compRemoveTimeout(ts->displayTimeout);
+ ts->displayTimeout = 0;
+ }
+ ts->pointedWin = NULL;
+ ts->showingThumb = FALSE;
+ }
+
+ CompWindow *cw = s->windows;
+ CompWindow *found = NULL;
+ for (;cw;cw = cw->next)
+ {
+ THUMB_WINDOW(cw);
+ if (!tw->ig.isSet)
+ continue;
+ if (rootX >= tw->ig.x && rootX < tw->ig.x + tw->ig.width &&
+ rootY >= tw->ig.y && rootY < tw->ig.y + tw->ig.height &&
+ checkPosition(cw))
+ {
+ found = cw;
+ }
+ }
+
+ if (found)
+ {
+ if (!ts->showingThumb &&
+ !(ts->thumb.opacity != 0.0 && ts->thumb.win == found))
+ {
+ if (ts->displayTimeout)
+ {
+ if (ts->pointedWin != found)
+ {
+ compRemoveTimeout(ts->displayTimeout);
+ ts->displayTimeout = compAddTimeout(
+ ts->opt[THUMB_SCREEN_OPTION_DELAY].value.i,
+ thumbShowThumbnail, s);
+ }
+ }
+ else
+ {
+ ts->displayTimeout =
+ compAddTimeout(ts->opt[THUMB_SCREEN_OPTION_DELAY].value.i,
+ thumbShowThumbnail, s);
+ }
+ }
+ ts->pointedWin = found;
+ thumbUpdateThumbnail(s);
+ }
+ else
+ {
+ ts->dock = NULL;
+ if (ts->displayTimeout)
+ {
+ compRemoveTimeout(ts->displayTimeout);
+ ts->displayTimeout = 0;
+ }
+ ts->pointedWin = 0;
+ ts->showingThumb = FALSE;
+ }
+
+ } else
+ {
+ ts->dock = NULL;
+ if (ts->displayTimeout)
+ {
+ compRemoveTimeout(ts->displayTimeout);
+ ts->displayTimeout = 0;
+ }
+ ts->pointedWin = NULL;
+ ts->showingThumb = FALSE;
+ }
+
+ ts->mouseTimeout = compAddTimeout(THUMB_MOUSE_UPDATE_SPEED, thumbUpdateMouse, s);
+ return FALSE;
+}
+
+static void
+thumbScreenInitOptions (ThumbScreen *ts)
+{
+ CompOption *o;
+
+ o = &ts->opt[THUMB_SCREEN_OPTION_SIZE];
+ o->name = "thumb_size";
+ o->shortDesc = N_("Thumbnail size");
+ o->longDesc = N_("Thumbnail window size");
+ o->type = CompOptionTypeInt;
+ o->value.i = THUMB_SIZE_DEFAULT;
+ o->rest.i.min = THUMB_SIZE_MIN;
+ o->rest.i.max = THUMB_SIZE_MAX;
+ o->group = N_("Settings");
+ o->subGroup = "";
+ o->advanced = False;
+ o->displayHints = "";
+
+
+ o = &ts->opt[THUMB_SCREEN_OPTION_DELAY];
+ o->name = "show_delay";
+ o->shortDesc = N_("Show delay");
+ o->longDesc = N_("Time (in ms) before thumbnail is shown when hovering "
+ "over a task button (10-10000)");
+ o->type = CompOptionTypeInt;
+ o->value.i = THUMB_DELAY_DEFAULT;
+ o->rest.i.min = THUMB_DELAY_MIN;
+ o->rest.i.max = THUMB_DELAY_MAX;
+ o->group = N_("Settings");
+ o->subGroup = "";
+ o->advanced = False;
+ o->displayHints = "";
+
+ o = &ts->opt[THUMB_SCREEN_OPTION_BORDER];
+ o->name = "border";
+ o->shortDesc = N_("Thumbnail border size");
+ o->longDesc = N_("Size of thumbnail border");
+ o->type = CompOptionTypeInt;
+ o->value.i = THUMB_BORDER_DEFAULT;
+ o->rest.i.min = THUMB_BORDER_MIN;
+ o->rest.i.max = THUMB_BORDER_MAX;
+ o->group = N_("Settings");
+ o->subGroup = "";
+ o->advanced = False;
+ o->displayHints = "";
+
+ o = &ts->opt[THUMB_SCREEN_OPTION_COLOR];
+ o->name = "thumb_color";
+ o->group = N_("Settings");
+ o->subGroup = N_("");
+ o->advanced = False;
+ o->shortDesc = N_("Thumbnail background color");
+ o->longDesc = N_("Thumbnail background and border color");
+ o->displayHints = "";
+ o->type = CompOptionTypeColor;
+ o->value.c[0] = THUMB_COLOR_RED_DEFAULT;
+ o->value.c[1] = THUMB_COLOR_GREEN_DEFAULT;
+ o->value.c[2] = THUMB_COLOR_BLUE_DEFAULT;
+ o->value.c[3] = THUMB_COLOR_ALPHA_DEFAULT;
+
+ o = &ts->opt[THUMB_SCREEN_OPTION_FADE];
+ o->name = "fade_speed";
+ o->group = N_("Settings");
+ o->subGroup = N_("");
+ o->advanced = False;
+ o->shortDesc = N_("Fade in/out duration");
+ o->longDesc = N_("Fade in/out duration in seconds");
+ o->displayHints = "";
+ o->type = CompOptionTypeFloat;
+ o->value.f = THUMB_FADE_DEFAULT;
+ o->rest.f.min = THUMB_FADE_MIN;
+ o->rest.f.max = THUMB_FADE_MAX;
+ o->rest.f.precision = THUMB_FADE_PRECISION;
+
+ o = &ts->opt[THUMB_SCREEN_OPTION_CURRENT_VIEWPORT];
+ o->name = "current_viewport";
+ o->shortDesc = N_("Taskbar shows only windows of current viewport");
+ o->longDesc = N_("Set it if the taskbar shows only windows of current viewport");
+ o->type = CompOptionTypeBool;
+ o->value.b = THUMB_CURRENT_VIEWPORT_DEFAULT;
+ o->group = N_("Settings");
+ o->subGroup = "Taskbar";
+ o->advanced = False;
+ o->displayHints = "";
+
+ o = &ts->opt[THUMB_SCREEN_OPTION_ALLWAYS_TOP];
+ o->name = "allways_on_top";
+ o->shortDesc = N_("Paint thumbnails allways on top");
+ o->longDesc = N_("Paint thumbnails allways on top of the desktop");
+ o->type = CompOptionTypeBool;
+ o->value.b = THUMB_ALLWAYS_TOP_DEFAULT;
+ o->group = N_("Settings");
+ o->subGroup = "Taskbar";
+ o->advanced = False;
+ o->displayHints = "";
+
+}
+
+
+static CompOption *
+thumbGetScreenOptions (CompScreen *screen,
+ int *count)
+{
+ if (screen)
+ {
+ THUMB_SCREEN (screen);
+
+ *count = NUM_OPTIONS (ts);
+ return ts->opt;
+ }
+ else
+ {
+ ThumbScreen * ts = malloc(sizeof(ThumbScreen));
+ thumbScreenInitOptions(ts);
+
+ *count = NUM_OPTIONS (ts);
+ return ts->opt;
+ }
+}
+
+
+static Bool
+thumbSetScreenOption (CompScreen *screen,
+ char *name,
+ CompOptionValue *value)
+{
+ CompOption *o;
+ int index;
+
+ THUMB_SCREEN (screen);
+
+ o = compFindOption (ts->opt, NUM_OPTIONS (ts), name, &index);
+ if (!o)
+ return FALSE;
+
+ switch (index)
+ {
+ case THUMB_SCREEN_OPTION_SIZE:
+ case THUMB_SCREEN_OPTION_DELAY:
+ case THUMB_SCREEN_OPTION_BORDER:
+ if (compSetIntOption (o, value))
+ {
+ return TRUE;
+ }
+ break;
+ case THUMB_SCREEN_OPTION_COLOR:
+ if (compSetColorOption(o, value))
+ {
+ return TRUE;
+ }
+ break;
+ case THUMB_SCREEN_OPTION_FADE:
+ if (compSetFloatOption(o, value))
+ {
+ return TRUE;
+ }
+ break;
+ case THUMB_SCREEN_OPTION_ALLWAYS_TOP:
+ case THUMB_SCREEN_OPTION_CURRENT_VIEWPORT:
+ if (compSetBoolOption(o, value))
+ {
+ return TRUE;
+ }
+ default:
+ break;
+ }
+
+ return FALSE;
+}
+
+
+static void
+thumbHandleEvent (CompDisplay *d,
+ XEvent *event)
+{
+ THUMB_DISPLAY (d);
+
+ UNWRAP (td, d, handleEvent);
+ (*d->handleEvent) (d, event);
+ WRAP (td, d, handleEvent, thumbHandleEvent);
+
+ CompWindow *w;
+
+ switch (event->type)
+ {
+ case PropertyNotify:
+ if (event->xproperty.atom == td->winIconGeometryAtom)
+ {
+ w = findWindowAtDisplay(d, event->xproperty.window);
+ if (w)
+ {
+ updateWindowIconGeometry(w);
+ }
+ }
+ break;
+ case ButtonPress:
+ {
+ CompScreen *s = findScreenAtDisplay (d, event->xbutton.root);
+ if (!s)
+ break;
+
+ THUMB_SCREEN(s);
+ ts->dock = NULL;
+ if (ts->displayTimeout)
+ {
+ compRemoveTimeout(ts->displayTimeout);
+ ts->displayTimeout = 0;
+ }
+ ts->pointedWin = 0;
+ ts->showingThumb = FALSE;
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+
+static void
+thumbPaintThumb(CompScreen *s,Thumbnail *t)
+{
+ THUMB_SCREEN(s);
+ DrawWindowGeometryProc oldDrawWindowGeometry;
+ AddWindowGeometryProc oldAddWindowGeometry;
+ CompWindow *w = t->win;
+
+ if (!w)
+ return;
+
+ int wx = t->x;
+ int wy = t->y;
+ float width = t->width;
+ float height = t->height;
+ WindowPaintAttrib sAttrib = w->paint;
+
+ /* Wrap drawWindowGeometry to make sure the general
+ drawWindowGeometry function is used */
+ oldDrawWindowGeometry = w->screen->drawWindowGeometry;
+ w->screen->drawWindowGeometry = getBaseDrawWindowGeometry();
+ oldAddWindowGeometry = w->screen->addWindowGeometry;
+ w->screen->addWindowGeometry = getBaseAddWindowGeometry();
+
+ unsigned int mask = PAINT_WINDOW_TRANSFORMED_MASK;
+
+ if (w->attrib.map_state == IsViewable || w->thumbPixmap)
+ {
+
+ int off = t->offset;
+
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
+ glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+ glColor4us(ts->opt[THUMB_SCREEN_OPTION_COLOR].value.c[0],
+ ts->opt[THUMB_SCREEN_OPTION_COLOR].value.c[1],
+ ts->opt[THUMB_SCREEN_OPTION_COLOR].value.c[2],
+ ts->opt[THUMB_SCREEN_OPTION_COLOR].value.c[3] * t->opacity);
+
+ glBegin(GL_QUADS);
+ glVertex2f(wx,wy);
+ glVertex2f(wx,wy+height);
+ glVertex2f(wx+width,wy+height);
+ glVertex2f(wx+width,wy);
+ glEnd();
+
+ enableTexture(s, &ts->glowTexture, COMP_TEXTURE_FILTER_GOOD);
+ glBegin(GL_QUADS);
+
+ glTexCoord2f(0,1);
+ glVertex2f(wx-off,wy-off);
+ glTexCoord2f(0,0);
+ glVertex2f(wx-off,wy);
+ glTexCoord2f(1,0);
+ glVertex2f(wx,wy);
+ glTexCoord2f(1,1);
+ glVertex2f(wx,wy-off);
+
+ glTexCoord2f(1,1);
+ glVertex2f(wx+width,wy-off);
+ glTexCoord2f(1,0);
+ glVertex2f(wx+width,wy);
+ glTexCoord2f(0,0);
+ glVertex2f(wx+width+off,wy);
+ glTexCoord2f(0,1);
+ glVertex2f(wx+width+off,wy-off);
+
+ glTexCoord2f(0,0);
+ glVertex2f(wx-off,wy+height);
+ glTexCoord2f(0,1);
+ glVertex2f(wx-off,wy+height+off);
+ glTexCoord2f(1,1);
+ glVertex2f(wx,wy+height+off);
+ glTexCoord2f(1,0);
+ glVertex2f(wx,wy+height);
+
+ glTexCoord2f(1,0);
+ glVertex2f(wx+width,wy+height);
+ glTexCoord2f(1,1);
+ glVertex2f(wx+width,wy+height+off);
+ glTexCoord2f(0,1);
+ glVertex2f(wx+width+off,wy+height+off);
+ glTexCoord2f(0,0);
+ glVertex2f(wx+width+off,wy+height);
+
+ glTexCoord2f(1,1);
+ glVertex2f(wx,wy-off);
+ glTexCoord2f(1,0);
+ glVertex2f(wx,wy);
+ glTexCoord2f(1,0);
+ glVertex2f(wx+width,wy);
+ glTexCoord2f(1,1);
+ glVertex2f(wx+width,wy-off);
+
+ glTexCoord2f(1,0);
+ glVertex2f(wx,wy+height);
+ glTexCoord2f(1,1);
+ glVertex2f(wx,wy+height+off);
+ glTexCoord2f(1,1);
+ glVertex2f(wx+width,wy+height+off);
+ glTexCoord2f(1,0);
+ glVertex2f(wx+width,wy+height);
+
+ glTexCoord2f(0,0);
+ glVertex2f(wx-off,wy);
+ glTexCoord2f(0,0);
+ glVertex2f(wx-off,wy+height);
+ glTexCoord2f(1,0);
+ glVertex2f(wx,wy+height);
+ glTexCoord2f(1,0);
+ glVertex2f(wx,wy);
+
+ glTexCoord2f(1,0);
+ glVertex2f(wx+width,wy);
+ glTexCoord2f(1,0);
+ glVertex2f(wx+width,wy+height);
+ glTexCoord2f(0,0);
+ glVertex2f(wx+width+off,wy+height);
+ glTexCoord2f(0,0);
+ glVertex2f(wx+width+off,wy);
+
+ glEnd();
+ disableTexture(s, &ts->glowTexture);
+
+ glDisable(GL_BLEND);
+ glBlendFunc(GL_ONE,GL_ONE_MINUS_SRC_ALPHA);
+ screenTexEnvMode (s,GL_REPLACE);
+
+ glColor4usv(defaultColor);
+
+ sAttrib.opacity *= t->opacity;
+ sAttrib.yScale = t->scale;
+ sAttrib.xScale = t->scale;
+
+ sAttrib.xTranslate =
+ wx - w->attrib.x + w->input.left * sAttrib.xScale;
+ sAttrib.yTranslate = wy - w->attrib.y + w->input.top * sAttrib.yScale;
+
+ (w->screen->drawWindow) (w, &sAttrib, getInfiniteRegion(), mask);
+
+ }
+
+ w->screen->drawWindowGeometry = oldDrawWindowGeometry;
+ w->screen->addWindowGeometry = oldAddWindowGeometry;
+}
+
+static void thumbPreparePaintScreen(CompScreen * s, int ms)
+{
+ THUMB_SCREEN(s);
+
+ float val = ms;
+ val /= 1000;
+ val /= ts->opt[THUMB_SCREEN_OPTION_FADE].value.f;
+
+ if (otherScreenGrabExist(s, 0))
+ {
+ ts->dock = NULL;
+ if (ts->displayTimeout)
+ {
+ compRemoveTimeout(ts->displayTimeout);
+ ts->displayTimeout = 0;
+ }
+ ts->pointedWin = 0;
+ ts->showingThumb = FALSE;
+ }
+
+ if (ts->showingThumb && ts->thumb.win == ts->pointedWin)
+ {
+ ts->thumb.opacity = MIN(1.0,ts->thumb.opacity + val);
+ }
+ if (!ts->showingThumb || ts->thumb.win != ts->pointedWin)
+ {
+ ts->thumb.opacity = MAX(0.0,ts->thumb.opacity - val);
+ }
+ ts->oldThumb.opacity = MAX(0.0,ts->oldThumb.opacity - val);
+
+ UNWRAP(ts, s, preparePaintScreen);
+ (*s->preparePaintScreen) (s,ms);
+ WRAP(ts, s, preparePaintScreen, thumbPreparePaintScreen);
+}
+
+static void thumbDonePaintScreen(CompScreen * s)
+{
+ THUMB_SCREEN(s);
+
+ if (ts->thumb.opacity > 0.0 && ts->thumb.opacity < 1.0)
+ damageThumbRegion(s,&ts->thumb);
+ if (ts->oldThumb.opacity > 0.0 && ts->oldThumb.opacity < 1.0)
+ damageThumbRegion(s,&ts->oldThumb);
+
+ UNWRAP(ts, s, donePaintScreen);
+ (*s->donePaintScreen) (s);
+ WRAP(ts, s, donePaintScreen, thumbDonePaintScreen);
+}
+
+static Bool
+thumbPaintScreen (CompScreen *s,
+ const ScreenPaintAttrib *sAttrib,
+ Region region,
+ int output,
+ unsigned int mask)
+{
+ Bool status;
+
+ THUMB_SCREEN (s);
+
+ unsigned int newMask = mask;
+
+ if ((ts->oldThumb.opacity > 0.0 && ts->oldThumb.win) ||
+ (ts->thumb.opacity > 0.0 && ts->thumb.win))
+ newMask |= PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS_MASK;
+
+ UNWRAP (ts, s, paintScreen);
+ status = (*s->paintScreen) (s, sAttrib, region, output, newMask);
+ WRAP (ts, s, paintScreen, thumbPaintScreen);
+
+ if (ts->opt[THUMB_SCREEN_OPTION_ALLWAYS_TOP].value.b)
+ {
+ if (ts->oldThumb.opacity > 0.0 && ts->oldThumb.win)
+ {
+ glPushMatrix();
+ prepareXCoords(s, output,-DEFAULT_Z_CAMERA);
+ thumbPaintThumb(s,&ts->oldThumb);
+ glPopMatrix();
+ }
+ if (ts->thumb.opacity > 0.0 && ts->thumb.win)
+ {
+ glPushMatrix();
+ prepareXCoords(s, output,-DEFAULT_Z_CAMERA);
+ thumbPaintThumb(s,&ts->thumb);
+ glPopMatrix();
+ }
+ }
+
+ return status;
+}
+
+static Bool
+thumbPaintWindow (CompWindow *w,
+ const WindowPaintAttrib *attrib,
+ Region region,
+ unsigned int mask)
+{
+ CompScreen *s = w->screen;
+ Bool status;
+
+ THUMB_SCREEN (s);
+
+ UNWRAP (ts, s, paintWindow);
+ status = (*s->paintWindow) (w, attrib, region, mask);
+ WRAP (ts, s, paintWindow, thumbPaintWindow);
+
+ if (!ts->opt[THUMB_SCREEN_OPTION_ALLWAYS_TOP].value.b)
+ {
+ if (ts->oldThumb.opacity > 0.0 && ts->oldThumb.win &&
+ ts->oldThumb.dock == w)
+ {
+ thumbPaintThumb(s,&ts->oldThumb);
+ }
+ if (ts->thumb.opacity > 0.0 && ts->thumb.win && ts->thumb.dock == w)
+ {
+ thumbPaintThumb(s,&ts->thumb);
+ }
+ }
+
+ return status;
+}
+
+static Bool
+thumbDamageWindowRect (CompWindow *w,
+ Bool initial,
+ BoxPtr rect)
+{
+ Bool status;
+
+ THUMB_SCREEN (w->screen);
+
+ if (ts->thumb.win == w && ts->thumb.opacity > 0.0)
+ damageThumbRegion(w->screen,&ts->thumb);
+ if (ts->oldThumb.win == w && ts->oldThumb.opacity > 0.0)
+ damageThumbRegion(w->screen,&ts->oldThumb);
+
+ UNWRAP (ts, w->screen, damageWindowRect);
+ status = (*w->screen->damageWindowRect) (w, initial, rect);
+ WRAP (ts, w->screen, damageWindowRect, thumbDamageWindowRect);
+
+ return status;
+}
+
+
+static Bool
+thumbInitDisplay (CompPlugin *p,
+ CompDisplay *d)
+{
+ ThumbDisplay *td;
+
+ td = malloc (sizeof (ThumbDisplay));
+ if (!td)
+ return FALSE;
+
+ td->screenPrivateIndex = allocateScreenPrivateIndex (d);
+ if (td->screenPrivateIndex < 0)
+ {
+ free (td);
+ return FALSE;
+ }
+
+ td->winIconGeometryAtom = XInternAtom (d->display,
+ "_NET_WM_ICON_GEOMETRY", FALSE);
+
+ WRAP (td, d, handleEvent, thumbHandleEvent);
+
+ d->privates[displayPrivateIndex].ptr = td;
+
+ return TRUE;
+}
+
+
+static void
+thumbFiniDisplay (CompPlugin *p,
+ CompDisplay *d)
+{
+ THUMB_DISPLAY (d);
+
+ freeScreenPrivateIndex (d, td->screenPrivateIndex);
+
+ UNWRAP (td, d, handleEvent);
+
+ free (td);
+}
+
+static Bool thumbInitWindow(CompPlugin * p, CompWindow * w)
+{
+ ThumbWindow *tw;
+
+ THUMB_SCREEN(w->screen);
+
+ // create window
+ tw = calloc(1, sizeof(ThumbWindow));
+ if (!tw)
+ return FALSE;
+
+ w->privates[ts->windowPrivateIndex].ptr = tw;
+
+ updateWindowIconGeometry(w);
+
+ return TRUE;
+}
+
+static void thumbFiniWindow(CompPlugin * p, CompWindow * w)
+{
+ THUMB_WINDOW(w);
+ THUMB_SCREEN(w->screen);
+
+ if (ts->thumb.win == w)
+ {
+ damageThumbRegion(w->screen,&ts->thumb);
+ ts->thumb.win = NULL;
+ ts->thumb.opacity = 0;
+ }
+
+ if (ts->oldThumb.win == w)
+ {
+ damageThumbRegion(w->screen,&ts->oldThumb);
+ ts->oldThumb.win = NULL;
+ ts->oldThumb.opacity = 0;
+ }
+
+
+ // free window pointer
+ free(tw);
+}
+
+
+static Bool
+thumbInitScreen (CompPlugin *p,
+ CompScreen *s)
+{
+ ThumbScreen *ts;
+
+ THUMB_DISPLAY (s->display);
+
+ ts = calloc (1,sizeof (ThumbScreen));
+ if (!ts)
+ return FALSE;
+
+ ts->windowPrivateIndex = allocateWindowPrivateIndex(s);
+
+ thumbScreenInitOptions (ts);
+
+ WRAP (ts, s, paintScreen, thumbPaintScreen);
+ WRAP (ts, s, damageWindowRect, thumbDamageWindowRect);
+ WRAP (ts, s, preparePaintScreen, thumbPreparePaintScreen);
+ WRAP (ts, s, donePaintScreen, thumbDonePaintScreen);
+ WRAP (ts, s, paintWindow, thumbPaintWindow);
+
+ ts->dock = NULL;
+ ts->pointedWin = NULL;
+ ts->displayTimeout = 0;
+ ts->thumb.win = NULL;
+ ts->oldThumb.win = NULL;
+ ts->showingThumb = FALSE;
+
+ s->privates[td->screenPrivateIndex].ptr = ts;
+
+ ts->mouseTimeout =
+ compAddTimeout(THUMB_MOUSE_UPDATE_SPEED, thumbUpdateMouse, s);
+
+ initTexture (s, &ts->glowTexture);
+
+ imageToTexture (s, &ts->glowTexture,glowTex,32,32);
+
+ return TRUE;
+}
+
+
+static void
+thumbFiniScreen (CompPlugin *p,
+ CompScreen *s)
+{
+ THUMB_SCREEN (s);
+
+ UNWRAP (ts, s, paintScreen);
+ UNWRAP (ts, s, damageWindowRect);
+ UNWRAP (ts, s, preparePaintScreen);
+ UNWRAP (ts, s, donePaintScreen);
+ UNWRAP (ts, s, paintWindow);
+
+ if (ts->mouseTimeout)
+ compRemoveTimeout (ts->mouseTimeout);
+
+ finiTexture (s, &ts->glowTexture);
+
+ free (ts);
+}
+
+
+static Bool
+thumbInit (CompPlugin *p)
+{
+ displayPrivateIndex = allocateDisplayPrivateIndex ();
+ if (displayPrivateIndex < 0)
+ return FALSE;
+
+ return TRUE;
+}
+
+
+static void
+thumbFini (CompPlugin *p)
+{
+ if (displayPrivateIndex >= 0)
+ freeDisplayPrivateIndex (displayPrivateIndex);
+}
+
+
+CompPluginVTable thumbVTable = {
+ "thumbnail",
+ N_("Window thumbnails"),
+ N_("Window thumbnails at the taskbar"),
+ thumbInit,
+ thumbFini,
+ thumbInitDisplay,
+ thumbFiniDisplay,
+ thumbInitScreen,
+ thumbFiniScreen,
+ thumbInitWindow,
+ thumbFiniWindow,
+ 0, /* thumbGetDisplayOptions */
+ 0, /* thumbSetDisplayOption */
+ thumbGetScreenOptions,
+ thumbSetScreenOption,
+ 0, /* Deps */
+ 0, /* nDeps */
+ 0, /* Features */
+ 0, /* nFeatures */
+ BERYL_ABI_INFO,
+ "thumbnail",
+ "misc",
+ 0,
+ 0,
+ True,
+};
+
+
+CompPluginVTable *
+getCompPluginInfo (void)
+{
+ return &thumbVTable;
+}
+