/*
*
* Compiz 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 <compiz.h>
#include <text.h>
#include "thumbnail_tex.h"
#include "thumbnail_options.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 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_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;
PaintOutputProc paintOutput;
PaintWindowProc paintWindow;
DonePaintScreenProc donePaintScreen;
DamageWindowRectProc damageWindowRect;
WindowResizeNotifyProc windowResizeNotify;
PaintTransformedOutputProc paintTransformedOutput;
CompWindow *dock;
CompWindow *pointedWin;
Bool showingThumb;
Thumbnail thumb;
Thumbnail oldThumb;
Bool painted;
CompTexture glowTexture;
CompTexture windowTexture;
int x;
int y;
}
ThumbScreen;
typedef struct _IconGeometry
{
int x;
int y;
int width;
int height;
Bool isSet;
}
IconGeometry;
typedef struct _ThumbWindow
{
IconGeometry ig;
}
ThumbWindow;
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)
{
int stride;
void *data;
if (freeThumb)
freeThumbText (s, t);
CompTextAttrib tA;
tA.maxwidth = t->width;
tA.maxheight = 100;
tA.screen = s;
tA.size = thumbnailGetFontSize (s);
tA.color[0] = thumbnailGetFontColorRed (s);
tA.color[1] = thumbnailGetFontColorGreen (s);
tA.color[2] = thumbnailGetFontColorBlue (s);
tA.color[3] = thumbnailGetFontColorAlpha (s);
tA.style = (thumbnailGetFontBold (s) ) ?
TEXT_STYLE_BOLD : TEXT_STYLE_NORMAL;
tA.family = "Sans";
tA.ellipsize = TRUE;
tA.renderMode = TextRenderWindowTitle;
tA.data = (void *) (t->win->id);
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;
}
}
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 = ®ion.extents;
region.numRects = region.size = 1;
damageScreenRegion (s, ®ion);
}
#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);
float maxSize = thumbnailGetThumbSize (s);
double scale = 1.0;
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;
/* 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 (thumbnailGetTitleEnabled (s) )
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 = thumbnailGetBorder (s);
int oDev = outputDeviceForPoint (s, tw->ig.x + (tw->ig.width / 2),
tw->ig.y + (tw->ig.height / 2) );
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)
{
if (thumbnailGetCurrentViewport (w->screen) )
{
/* TODO: We need a faster calculation here */
Bool onViewport = FALSE;
Region reg = XCreateRegion ();
if (!reg)
return FALSE;
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)
continue;
if (cw->state & CompWindowStateSkipTaskbarMask)
continue;
if (cw->state & CompWindowStateSkipPagerMask)
continue;
if (!cw->managed)
continue;
if (!w->texture->pixmap)
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 (thumbnailGetShowDelay (s),
thumbShowThumbnail, s);
}
}
else
{
ts->displayTimeout =
compAddTimeout (thumbnailGetShowDelay (s),
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
thumbWindowResizeNotify (CompWindow *w,
int dx,
int dy,
int dwidth,
int dheight)
{
THUMB_SCREEN (w->screen);
thumbUpdateThumbnail (w->screen);
UNWRAP (ts, w->screen, windowResizeNotify);
(*w->screen->windowResizeNotify) (w, dx, dy, dwidth, dheight);
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);
}
}
else if (event->xproperty.atom == d->wmNameAtom)
{
w = findWindowAtDisplay (d, event->xproperty.window);
if (w)
{
THUMB_SCREEN (w->screen);
if (ts->thumb.win == w && thumbnailGetTitleEnabled (w->screen))
renderThumbText (w->screen, &ts->thumb, TRUE);
}
}
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,
const CompTransform *transform)
{
THUMB_SCREEN (s);
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 */
oldAddWindowGeometry = w->screen->addWindowGeometry;
w->screen->addWindowGeometry = addWindowGeometry;
unsigned int mask = PAINT_WINDOW_TRANSFORMED_MASK |
PAINT_WINDOW_TRANSLUCENT_MASK;
if (w->texture->pixmap)
{
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);
glDisableClientState (GL_TEXTURE_COORD_ARRAY);
if (thumbnailGetWindowLike (s) )
{
glColor4f (1.0, 1.0, 1.0, t->opacity);
enableTexture (s, &ts->windowTexture, COMP_TEXTURE_FILTER_GOOD);
}
else
{
glColor4us (thumbnailGetThumbColorRed (s),
thumbnailGetThumbColorGreen (s),
thumbnailGetThumbColorBlue (s),
thumbnailGetThumbColorAlpha (s) * 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 (thumbnailGetWindowLike (s) )
{
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);
}
glEnableClientState (GL_TEXTURE_COORD_ARRAY);
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 (thumbnailGetMipmap (s) )
s->display->textureFilter = GL_LINEAR_MIPMAP_LINEAR;
FragmentAttrib fragment;
CompTransform wTransform = *transform;
initFragmentAttrib (&fragment, &sAttrib);
matrixTranslate (&wTransform, w->attrib.x, w->attrib.y, 0.0f);
matrixScale (&wTransform, sAttrib.xScale, sAttrib.yScale, 1.0f);
matrixTranslate (&wTransform,
sAttrib.xTranslate / sAttrib.xScale - w->attrib.x,
sAttrib.yTranslate / sAttrib.yScale - w->attrib.y,
0.0f);
glPushMatrix ();
glLoadMatrixf (wTransform.m);
(w->screen->drawWindow) (w, &wTransform, &fragment, &infiniteRegion,
mask);
glPopMatrix ();
s->display->textureFilter = filter;
}
w->screen->addWindowGeometry = oldAddWindowGeometry;
}
static void
thumbPreparePaintScreen (CompScreen *s,
int ms)
{
THUMB_SCREEN (s);
float val = ms;
val /= 1000;
val /= thumbnailGetFadeSpeed (s);
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);
if (ts->thumb.opacity == 0.0)
ts->thumb.win = NULL;
}
ts->oldThumb.opacity = MAX (0.0, ts->oldThumb.opacity - val);
if (ts->oldThumb.opacity == 0.0)
ts->oldThumb.win = NULL;
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
thumbPaintOutput (CompScreen *s,
const ScreenPaintAttrib *sAttrib,
const CompTransform *transform,
Region region,
CompOutput *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, paintOutput);
status = (*s->paintOutput) (s, sAttrib, transform, region,
output, newMask);
WRAP (ts, s, paintOutput, thumbPaintOutput);
if (thumbnailGetAlwaysOnTop (s) && !ts->painted)
{
if (ts->oldThumb.opacity > 0.0 && ts->oldThumb.win)
{
CompTransform sTransform = *transform;
transformToScreenSpace (s, output, -DEFAULT_Z_CAMERA,
&sTransform);
glPushMatrix ();
glLoadMatrixf (sTransform.m);
thumbPaintThumb (s, &ts->oldThumb, &sTransform);
glPopMatrix ();
}
if (ts->thumb.opacity > 0.0 && ts->thumb.win)
{
CompTransform sTransform = *transform;
transformToScreenSpace (s, output, -DEFAULT_Z_CAMERA,
&sTransform);
glPushMatrix ();
glLoadMatrixf (sTransform.m);
thumbPaintThumb (s, &ts->thumb, &sTransform);
glPopMatrix ();
}
}
return status;
}
static void
thumbPaintTransformedOutput (CompScreen *s,
const ScreenPaintAttrib *sAttrib,
const CompTransform *transform,
Region region,
CompOutput *output,
unsigned int mask)
{
THUMB_SCREEN (s);
UNWRAP (ts, s, paintTransformedOutput);
(*s->paintTransformedOutput) (s, sAttrib, transform, region, output, mask);
WRAP (ts, s, paintTransformedOutput, thumbPaintTransformedOutput);
if (thumbnailGetAlwaysOnTop (s) && ts->x == s->x && ts->y == s->y)
{
ts->painted = TRUE;
if (ts->oldThumb.opacity > 0.0 && ts->oldThumb.win)
{
CompTransform sTransform = *transform;
(s->applyScreenTransform) (s, sAttrib, output, &sTransform);
transformToScreenSpace (s, output, -sAttrib->zTranslate,
&sTransform);
glPushMatrix ();
glLoadMatrixf (sTransform.m);
thumbPaintThumb (s, &ts->oldThumb, &sTransform);
glPopMatrix ();
}
if (ts->thumb.opacity > 0.0 && ts->thumb.win)
{
CompTransform sTransform = *transform;
(s->applyScreenTransform) (s, sAttrib, output, &sTransform);
transformToScreenSpace (s, output, -sAttrib->zTranslate,
&sTransform);
glPushMatrix ();
glLoadMatrixf (sTransform.m);
thumbPaintThumb (s, &ts->thumb, &sTransform);
glPopMatrix ();
}
}
}
static Bool
thumbPaintWindow (CompWindow *w,
const WindowPaintAttrib *attrib,
const CompTransform *transform,
Region region,
unsigned int mask)
{
CompScreen *s = w->screen;
Bool status;
THUMB_SCREEN (s);
UNWRAP (ts, s, paintWindow);
status = (*s->paintWindow) (w, attrib, transform, region, mask);
WRAP (ts, s, paintWindow, thumbPaintWindow);
if (!thumbnailGetAlwaysOnTop (s) && 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, transform);
}
if (ts->thumb.opacity > 0.0 && ts->thumb.win && ts->thumb.dock == w)
{
thumbPaintThumb (s, &ts->thumb, transform);
}
}
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
thumbRGBAimageToTexture (CompScreen *screen,
CompTexture *texture,
char *image,
unsigned int width,
unsigned int height)
{
char *data;
int i;
makeScreenCurrent (screen);
data = malloc (4 * width * height);
if (!data)
return FALSE;
for (i = 0; i < height; i++)
memcpy (&data[i * width * 4],
&image[ (height - i - 1) * width * 4], width * 4);
releasePixmapFromTexture (screen, texture);
if (screen->textureNonPowerOfTwo ||
(POWER_OF_TWO (width) && POWER_OF_TWO (height) ) )
{
texture->target = GL_TEXTURE_2D;
texture->matrix.xx = 1.0f / width;
texture->matrix.yy = -1.0f / height;
texture->matrix.y0 = 1.0f;
}
else
{
texture->target = GL_TEXTURE_RECTANGLE_NV;
texture->matrix.xx = 1.0f;
texture->matrix.yy = -1.0f;
texture->matrix.y0 = height;
}
if (!texture->name)
glGenTextures (1, &texture->name);
glBindTexture (texture->target, texture->name);
glTexImage2D (texture->target, 0, GL_RGBA, width, height, 0, GL_RGBA,
GL_UNSIGNED_BYTE, data);
texture->filter = GL_NEAREST;
glTexParameteri (texture->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri (texture->target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri (texture->target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri (texture->target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
texture->wrap = GL_CLAMP_TO_EDGE;
texture->mipmap = TRUE;
glBindTexture (texture->target, 0);
free (data);
return TRUE;
}
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);
WRAP (ts, s, paintOutput, thumbPaintOutput);
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, paintTransformedOutput, thumbPaintTransformedOutput);
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);
thumbRGBAimageToTexture (s, &ts->glowTexture, glowTex, 32, 32);
thumbRGBAimageToTexture (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, paintOutput);
UNWRAP (ts, s, damageWindowRect);
UNWRAP (ts, s, preparePaintScreen);
UNWRAP (ts, s, donePaintScreen);
UNWRAP (ts, s, paintWindow);
UNWRAP (ts, s, windowResizeNotify);
UNWRAP (ts, s, paintTransformedOutput);
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);
}
static int
thumbnailGetVersion (CompPlugin *plugin,
int version)
{
return ABIVERSION;
}
CompPluginVTable thumbVTable = {
"thumbnail",
thumbnailGetVersion,
0,
thumbInit,
thumbFini,
thumbInitDisplay,
thumbFiniDisplay,
thumbInitScreen,
thumbFiniScreen,
thumbInitWindow,
thumbFiniWindow,
0, /* thumbGetDisplayOptions */
0, /* thumbSetDisplayOption */
0,
0
};
CompPluginVTable *
getCompPluginInfo (void)
{
return &thumbVTable;
}
syntax highlighted by Code2HTML, v. 0.9.1