Logo Search packages:      
Sourcecode: beryl-plugins version File versions

thumbnail.c

/*
 *
 * 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.
 *
 */

#define _GNU_SOURCE
#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 <beryl-text.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   100
#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_ALWAYS_TOP_DEFAULT         FALSE
#define THUMB_WINDOW_LIKE_DEFAULT        TRUE
#define THUMB_MIPMAP_DEFAULT             FALSE

#define THUMB_TITLE_DEFAULT        TRUE
#define THUMB_FONT_BOLD_DEFAULT    TRUE
#define THUMB_FONT_SIZE_DEFAULT    12
#define THUMB_FONT_SIZE_MIN        6
#define THUMB_FONT_SIZE_MAX        36
#define THUMB_FONT_COLOR_RED       0x0
#define THUMB_FONT_COLOR_GREEN     0x0
#define THUMB_FONT_COLOR_BLUE      0x0
#define THUMB_FONT_COLOR_ALPHA     0xffff

#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_ALWAYS_TOP           6
#define THUMB_SCREEN_OPTION_WINDOW_LIKE           7
#define THUMB_SCREEN_OPTION_MIPMAP    8
#define THUMB_SCREEN_OPTION_TITLE     9
#define THUMB_SCREEN_OPTION_FONT_BOLD     10
#define THUMB_SCREEN_OPTION_FONT_SIZE     11
#define THUMB_SCREEN_OPTION_FONT_COLOR    12
#define THUMB_SCREEN_OPTION_NUM           13

#define THUMB_MOUSE_UPDATE_SPEED 100

#define TEXT_DISTANCE 10

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;
      CompTexture textTexture;
      Pixmap textPixmap;
      int tWidth;
      int tHeight;
} Thumbnail;

typedef struct _ThumbScreen {
      int   windowPrivateIndex;

      CompTimeoutHandle mouseTimeout;
      CompTimeoutHandle displayTimeout;

      PreparePaintScreenProc preparePaintScreen;
    PaintScreenProc     paintScreen;
      PaintWindowProc   paintWindow;
      DonePaintScreenProc donePaintScreen;
    DamageWindowRectProc   damageWindowRect;
      WindowResizeNotifyProc  windowResizeNotify;
      PaintTransformedScreenProc paintTransformedScreen;

      CompWindow *dock;
      CompWindow *pointedWin;
      Bool showingThumb;
      Thumbnail thumb;
      Thumbnail oldThumb;
      Bool painted;

      CompTexture glowTexture;
      CompTexture windowTexture;

      int x;
      int y;

    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;

char * getUtf8Property(CompDisplay *d,Window id,Atom atom)
{
      Atom type;
      int format;
      unsigned long nitems;
      unsigned long bytes_after;
      char *val;
      int result;
      char *retval;

      type = None;
      val = NULL;
      result = XGetWindowProperty (d->display, id, atom, 0L, 65536, False,
                                                 d->utf8StringAtom,     &type, &format, &nitems,
                                                 &bytes_after, (unsigned char **)&val);

      if (result != Success)
            return NULL;

      if (type != d->utf8StringAtom || format != 8 || nitems == 0)
      {
            if (val)
                  XFree (val);
            return NULL;
      }

      retval = strndup (val, nitems);

      XFree (val);

      return retval;
}

char * getTextProperty(CompDisplay *d,Window id,Atom atom)
{
      XTextProperty text;
      char *retval;

      text.nitems = 0;
      if (XGetTextProperty (d->display, id, &text, atom))
      {
            retval = strndup ((char *)text.value,text.nitems);
            if (text.value)
                  XFree (text.value);
      }
      else
      {
            retval = NULL;
      }
      return retval;
}


char * getWindowName(CompWindow *w)
{
      char *name = NULL;

      CompDisplay *d = w->screen->display;

      Atom visName = XInternAtom(d->display, "_NET_WM_VISIBLE_NAME", FALSE);

      name = getUtf8Property (d, w->id, visName);

      if (name == NULL)
            name = getUtf8Property(d, w->id, d->wmNameAtom);

      if (name == NULL)
            name = getTextProperty (d, w->id, XA_WM_NAME);

      return name;
}

static void freeThumbText(CompScreen *s,Thumbnail *t)
{
      if (!t->textPixmap)
            return;
      releasePixmapFromTexture(s,&t->textTexture);
      initTexture (s, &t->textTexture);
      XFreePixmap(s->display->display,t->textPixmap);
      t->textPixmap = None;
}

static void renderThumbText(CompScreen *s,Thumbnail *t, Bool freeThumb)
{
      THUMB_SCREEN(s);

      if (freeThumb)
            freeThumbText(s,t);

      CompTextAttrib tA;

      tA.maxwidth = t->width;
      tA.maxheight = 100;
      tA.screen = s;
      tA.size = ts->opt[THUMB_SCREEN_OPTION_FONT_SIZE].value.i;
      tA.color[0] = ts->opt[THUMB_SCREEN_OPTION_FONT_COLOR].value.c[0];
      tA.color[1] = ts->opt[THUMB_SCREEN_OPTION_FONT_COLOR].value.c[1];
      tA.color[2] = ts->opt[THUMB_SCREEN_OPTION_FONT_COLOR].value.c[2];
      tA.color[3] = ts->opt[THUMB_SCREEN_OPTION_FONT_COLOR].value.c[3];
      tA.style = (ts->opt[THUMB_SCREEN_OPTION_FONT_BOLD].value.b)?
                        TEXT_STYLE_BOLD : TEXT_STYLE_NORMAL;
      tA.family = "Sans";
      tA.ellipsize = TRUE;

      tA.text = getWindowName(t->win);

      if (!tA.text)
            return;

      int stride;
      void *data;

      initTexture (s, &t->textTexture);

      if ((*s->display->fileToImage)(s->display,TEXT_ID,(char *)&tA,
                                                   &t->tWidth,&t->tHeight,&stride,&data))
      {
            t->textPixmap = (Pixmap)data;
            bindPixmapToTexture(s,&t->textTexture,t->textPixmap,
                                          t->tWidth,t->tHeight,32);
      }
      else
      {
            t->textPixmap = None;
            t->tWidth = 0;
            t->tHeight = 0;
      }

      free (tA.text);
}


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);
      if (t->textPixmap)
            region.extents.y2 += t->tHeight + TEXT_DISTANCE;
      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);

      freeThumbText(s,&ts->oldThumb);
      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);

      if (ts->opt[THUMB_SCREEN_OPTION_TITLE].value.b)
            renderThumbText(s,&ts->thumb,FALSE);
      else
            freeThumbText(s,&ts->thumb);

      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
      {
            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;
      }

      int tHeight = ts->thumb.height;
      if (ts->thumb.textPixmap)
            tHeight += ts->thumb.tHeight + TEXT_DISTANCE;

      // failsave position
      tPos[0] = igMidPoint[0] - (ts->thumb.width / 2.0);
      if (tw->ig.y - tHeight >= 0)
      {
            tPos[1] = tw->ig.y - tHeight;
      }
      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)
                  tmpPos[0] = ox2 - ts->thumb.width - off;
            else
                  tmpPos[0] = ox1 + off;
      }
      tMidPoint[0] = tmpPos[0] + (ts->thumb.width / 2.0);

      tmpPos[1] = WIN_Y(ts->dock) - tHeight - off;
      tMidPoint[1] = tmpPos[1] + (tHeight / 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] + (tHeight / 2.0);
      if (tmpPos[1] + tHeight + 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] - (tHeight / 2.0);
      if (tmpPos[1] - off < oy1)
            tmpPos[1] = oy1 + off;
      if (tmpPos[1] + off + tHeight > oy2)
      {
            if (tHeight + (2*off) <= oh)
                  tmpPos[1] = oy2 - ts->thumb.height - off;
            else
                  tmpPos[1] = oy1 + off;
      }
      tMidPoint[1] = tmpPos[1] + (tHeight / 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 && !found;cw = cw->next)
            {
                  THUMB_WINDOW(cw);
                  if (!tw->ig.isSet)
                        continue;
                  if (cw->attrib.map_state != IsViewable && !cw->thumbPixmap)
                        continue;
                  if (cw->state & CompWindowStateSkipTaskbarMask)
                continue;
                  if (cw->state & CompWindowStateSkipPagerMask)
                continue;
                  if (cw->state & CompWindowStateOffscreenMask)
                        continue;
                  if (!cw->managed)
                        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 taskbar 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 Border Glow Color");
      o->longDesc = N_("Thumbnail Background and Border Glow 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       = N_("Taskbar");
      o->advanced       = False;
      o->displayHints   = "";

      o = &ts->opt[THUMB_SCREEN_OPTION_ALWAYS_TOP];
    o->name             = "always_on_top";
    o->shortDesc  = N_("Thumbnails Always on Top");
    o->longDesc         = N_("Paint Thumbnails Always on Top.");
    o->type             = CompOptionTypeBool;
    o->value.b          = THUMB_ALWAYS_TOP_DEFAULT;
      o->group          = N_("Settings");
      o->subGroup       = N_("Taskbar");
      o->advanced       = False;
      o->displayHints   = "";

      o = &ts->opt[THUMB_SCREEN_OPTION_WINDOW_LIKE];
    o->name             = "window_like";
    o->shortDesc  = N_("Paint Window Like Background");
    o->longDesc         = N_("Paint Window Like Background instead of Glow.");
    o->type             = CompOptionTypeBool;
    o->value.b          = THUMB_WINDOW_LIKE_DEFAULT;
      o->group          = N_("Settings");
      o->subGroup       = "";
      o->advanced       = False;
      o->displayHints   = "";

      o = &ts->opt[THUMB_SCREEN_OPTION_MIPMAP];
    o->name             = "mipmap";
    o->shortDesc  = N_("Generate Mipmaps");
    o->longDesc         = N_("Generate mipmaps when possible for higher quality "
                                     "scaling.");
    o->type             = CompOptionTypeBool;
    o->value.b          = THUMB_MIPMAP_DEFAULT;
      o->group          = N_("Settings");
      o->subGroup       = "";
      o->advanced       = TRUE;
      o->displayHints   = "";

      o = &ts->opt[THUMB_SCREEN_OPTION_TITLE];
    o->name             = "title_enabled";
    o->shortDesc  = N_("Enable Titles");
    o->longDesc         = N_("Show Window Title in Thumbnail.");
    o->type             = CompOptionTypeBool;
    o->value.b          = THUMB_TITLE_DEFAULT;
      o->group          = N_("Settings");
      o->subGroup       = N_("Window title");
      o->advanced       = FALSE;
      o->displayHints   = "";

      o = &ts->opt[THUMB_SCREEN_OPTION_FONT_BOLD];
    o->name             = "font_bold";
    o->shortDesc  = N_("Bold Font");
    o->longDesc         = N_("Should be the window title Bold.");
    o->type             = CompOptionTypeBool;
    o->value.b          = THUMB_FONT_BOLD_DEFAULT;
      o->group          = N_("Settings");
      o->subGroup       = N_("Window title");
      o->advanced       = FALSE;
      o->displayHints   = "";

      o = &ts->opt[THUMB_SCREEN_OPTION_FONT_SIZE];
    o->name             = "font_size";
    o->shortDesc  = N_("Font Size");
    o->longDesc         = N_("Window title Font Size.");
    o->type             = CompOptionTypeInt;
      o->group          = N_("Settings");
      o->subGroup       = N_("Window title");
      o->advanced       = FALSE;
      o->displayHints   = "";
      o->value.i        = THUMB_FONT_SIZE_DEFAULT;
      o->rest.i.min = THUMB_FONT_SIZE_MIN;
      o->rest.i.max = THUMB_FONT_SIZE_MAX;

      o = &ts->opt[THUMB_SCREEN_OPTION_FONT_COLOR];
      o->name           = "font_color";
      o->group          = N_("Settings");
      o->subGroup       = N_("Window title");
      o->advanced       = False;
      o->shortDesc      = N_("Font Color");
      o->longDesc       = N_("Window title Font Color.");
      o->advanced       = FALSE;
      o->displayHints = "";
      o->type = CompOptionTypeColor;
      o->value.c[0] = THUMB_FONT_COLOR_RED;
      o->value.c[1] = THUMB_FONT_COLOR_GREEN;
      o->value.c[2] = THUMB_FONT_COLOR_BLUE;
      o->value.c[3] = THUMB_FONT_COLOR_ALPHA;

}


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:
            case THUMB_SCREEN_OPTION_FONT_SIZE:
                  if (compSetIntOption (o, value))
                  {
                      return TRUE;
                  }
                  break;
            case THUMB_SCREEN_OPTION_COLOR:
            case THUMB_SCREEN_OPTION_FONT_COLOR:
                  if (compSetColorOption(o, value))
                  {
                        return TRUE;
                  }
                  break;
            case THUMB_SCREEN_OPTION_FADE:
                  if (compSetFloatOption(o, value))
                  {
                        return TRUE;
                  }
                  break;
            case THUMB_SCREEN_OPTION_ALWAYS_TOP:
            case THUMB_SCREEN_OPTION_CURRENT_VIEWPORT:
            case THUMB_SCREEN_OPTION_WINDOW_LIKE:
            case THUMB_SCREEN_OPTION_MIPMAP:
            case THUMB_SCREEN_OPTION_TITLE:
            case THUMB_SCREEN_OPTION_FONT_BOLD:
                  if (compSetBoolOption(o, value))
                  {
                        return TRUE;
                  }
          default:
                  break;
    }

    return FALSE;
}

static void
thumbWindowResizeNotify(CompWindow *w, int dx, int dy, int dwidth, int dheight,
                                    Bool preview)
{
      THUMB_SCREEN ( w->screen );

      if (!preview)
            thumbUpdateThumbnail(w->screen);

      UNWRAP(ts,w->screen,windowResizeNotify);
      (*w->screen->windowResizeNotify) (w, dx, dy, dwidth, dheight, preview);
      WRAP(ts,w->screen,windowResizeNotify,thumbWindowResizeNotify);
}

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;

      if (t->textPixmap)
            height += t->tHeight + TEXT_DISTANCE;

      /* 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);

            if (ts->opt[THUMB_SCREEN_OPTION_WINDOW_LIKE].value.b)
            {
                  glColor4f(1.0,1.0,1.0,t->opacity);
                  enableTexture(s, &ts->windowTexture, COMP_TEXTURE_FILTER_GOOD);
            }
            else
            {
                  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);

                  enableTexture(s, &ts->glowTexture, COMP_TEXTURE_FILTER_GOOD);
            }

            glBegin(GL_QUADS);

            glTexCoord2f(1,0);
            glVertex2f(wx,wy);
            glVertex2f(wx,wy+height);
            glVertex2f(wx+width,wy+height);
            glVertex2f(wx+width,wy);

            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();

            if (ts->opt[THUMB_SCREEN_OPTION_WINDOW_LIKE].value.b)
            {
                  disableTexture(s, &ts->windowTexture);
            }
            else
            {
                  disableTexture(s, &ts->glowTexture);
            }

            glColor4usv(defaultColor);
            glBlendFunc(GL_ONE,GL_ONE_MINUS_SRC_ALPHA);

            if (t->textPixmap)
            {
                  glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
                  glColor4f(1.0,1.0,1.0,t->opacity);

                  enableTexture(s, &t->textTexture,COMP_TEXTURE_FILTER_GOOD);

                  CompMatrix *m = &t->textTexture.matrix;

                  float ox = 0.0;
                  if (t->tWidth < width)
                        ox = (width - t->tWidth) / 2.0;

                  float w = MIN(width,t->tWidth);
                  float h = t->tHeight;

                  glBegin(GL_QUADS);

                  glTexCoord2f(COMP_TEX_COORD_X(m,0),COMP_TEX_COORD_Y(m,0));
                  glVertex2f(wx+ox,wy+height-h);
                  glTexCoord2f(COMP_TEX_COORD_X(m,0),COMP_TEX_COORD_Y(m,h));
                  glVertex2f(wx+ox,wy+height);
                  glTexCoord2f(COMP_TEX_COORD_X(m,w),COMP_TEX_COORD_Y(m,h));
                  glVertex2f(wx+ox+w,wy+height);
                  glTexCoord2f(COMP_TEX_COORD_X(m,w),COMP_TEX_COORD_Y(m,0));
                  glVertex2f(wx+ox+w,wy+height-h);

                  glEnd();

                  disableTexture(s, &t->textTexture);
                  glColor4usv(defaultColor);
            }

            glDisable(GL_BLEND);
            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;

            GLenum filter = s->display->textureFilter;

            if (ts->opt[THUMB_SCREEN_OPTION_MIPMAP].value.b)
                  s->display->textureFilter = GL_LINEAR_MIPMAP_LINEAR;

            (w->screen->drawWindow) (w, &sAttrib, getInfiniteRegion(), mask);

            s->display->textureFilter = filter;
      }

      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);

      ts->painted = FALSE;

      ts->x = s->x;
      ts->y = s->y;

      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_ALWAYS_TOP].value.b && !ts->painted)
      {
            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 void
thumbPaintTransformedScreen (CompScreen               *s,
                          const ScreenPaintAttrib *sAttrib,
                          Region                        region,
                          int                           output,
                          unsigned int                  mask)
{

    THUMB_SCREEN (s);

      UNWRAP (ts, s, paintTransformedScreen);
      (*s->paintTransformedScreen) (s, sAttrib, region, output, mask);
      WRAP (ts, s, paintTransformedScreen, thumbPaintTransformedScreen);

      if (ts->opt[THUMB_SCREEN_OPTION_ALWAYS_TOP].value.b &&
          ts->x == s->x && ts->y == s->y)
      {
            ts->painted = TRUE;
            if (ts->oldThumb.opacity > 0.0 && ts->oldThumb.win)
            {
                  glPushMatrix();
                  (s->applyScreenTransform) (s, sAttrib, output);
                  prepareXCoords(s, output,-sAttrib->zTranslate);
                  thumbPaintThumb(s,&ts->oldThumb);
                  glPopMatrix();
            }
            if (ts->thumb.opacity > 0.0 && ts->thumb.win)
            {
                  glPushMatrix();
                  (s->applyScreenTransform) (s, sAttrib, output);
                  prepareXCoords(s, output,-sAttrib->zTranslate);
                  thumbPaintThumb(s,&ts->thumb);
                  glPopMatrix();
            }
      }
}

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_ALWAYS_TOP].value.b &&
          ts->x == s->x && ts->y == s->y)
      {
            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);
      WRAP (ts,s,windowResizeNotify, thumbWindowResizeNotify);
      WRAP (ts, s, paintTransformedScreen, thumbPaintTransformedScreen);

      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);
      initTexture (s, &ts->windowTexture);

      imageToTexture (s, &ts->glowTexture,glowTex,32,32);
      imageToTexture (s, &ts->windowTexture,windowTex,32,32);

      ts->thumb.textPixmap = None;
      ts->oldThumb.textPixmap = None;

    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);
      UNWRAP (ts,s,windowResizeNotify);
      UNWRAP (ts, s, paintTransformedScreen);

      if (ts->mouseTimeout)
            compRemoveTimeout (ts->mouseTimeout);

      freeThumbText (s,&ts->thumb);
      freeThumbText (s,&ts->oldThumb);

      finiTexture (s, &ts->glowTexture);
      finiTexture (s, &ts->windowTexture);

    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 Previews"),
    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;
}


Generated by  Doxygen 1.6.0   Back to index