diff options
author | Danny Baumann <dannybaumann@web.de> | 2007-04-02 15:44:04 +0200 |
---|---|---|
committer | Danny Baumann <dannybaumann@web.de> | 2007-04-02 15:44:04 +0200 |
commit | f4d1fd48ab08f4a8ac417cec5496c84b5f55afce (patch) | |
tree | 628a48a5ea754ed195342b4097767c33514e0be9 /src/thumbnail.c | |
parent | 04d0f4a2ba324e37d320adcc9054ac3b2eb6b453 (diff) | |
download | beryl-premerge-f4d1fd48ab08f4a8ac417cec5496c84b5f55afce.tar.gz beryl-premerge-f4d1fd48ab08f4a8ac417cec5496c84b5f55afce.tar.bz2 |
added ported plugins (TODO: add build system ;-) )
Diffstat (limited to 'src/thumbnail.c')
-rw-r--r-- | src/thumbnail.c | 1334 |
1 files changed, 1334 insertions, 0 deletions
diff --git a/src/thumbnail.c b/src/thumbnail.c new file mode 100644 index 0000000..deb7d03 --- /dev/null +++ b/src/thumbnail.c @@ -0,0 +1,1334 @@ +/* + * + * 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-plugin.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; + 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; + +} 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) +{ + if (freeThumb) + freeThumbText (s, t); + + CompTextAttrib tA; + + tA.maxwidth = t->width; + tA.maxheight = 100; + tA.screen = s; + tA.size = thumbGetFontSize (s); + tA.color[0] = thumbGetFontColorRed (s); + tA.color[1] = thumbGetFontColorGreen (s); + tA.color[2] = thumbGetFontColorBlue (s); + tA.color[3] = thumbGetFontColorAlpha (s); + tA.style = (thumbGetFontBold (s)) ? TEXT_STYLE_BOLD : TEXT_STYLE_NORMAL; + tA.family = "Sans"; + tA.ellipsize = TRUE; + + tA.renderMode = TextRenderWindowTitle; + tA.data = (void *)(t->win->id); + + + 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; + } + + +} + + +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); + + 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 = thumbGetThumbSize (s); + 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 (thumbGetTitleEnabled (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 = thumbGetBorder (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 (thumbGetCurrentViewport (w->screen)) + { + // 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) + 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 (thumbGetShowDelay (s), + thumbShowThumbnail, s); + } + } + else + { + ts->displayTimeout = + compAddTimeout (thumbGetShowDelay (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) + 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); + + if (thumbGetWindowLike (s)) + { + glColor4f (1.0, 1.0, 1.0, t->opacity); + enableTexture (s, &ts->windowTexture, COMP_TEXTURE_FILTER_GOOD); + } + else + { + glColor4us (thumbGetThumbColorRed (s), + thumbGetThumbColorGreen (s), + thumbGetThumbColorBlue (s), + thumbGetThumbColorAlpha (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 (thumbGetWindowLike (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); + } + + 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 (thumbGetMipmap (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, 0.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 /= thumbGetFadeSpeed (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); + } + 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, + const CompTransform * transform, + 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, transform, region, output, newMask); + WRAP (ts, s, paintScreen, thumbPaintScreen); + + if (thumbGetAlwaysOnTop (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 +thumbPaintTransformedScreen (CompScreen * s, + const ScreenPaintAttrib * sAttrib, + const CompTransform * transform, + Region region, int output, unsigned int mask) +{ + + THUMB_SCREEN (s); + + UNWRAP (ts, s, paintTransformedScreen); + (*s->paintTransformedScreen) (s, sAttrib, transform, region, output, + mask); + WRAP (ts, s, paintTransformedScreen, thumbPaintTransformedScreen); + + if (thumbGetAlwaysOnTop (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 (!thumbGetAlwaysOnTop (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, 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); + + 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, 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); +} + +static int +thumbGetVersion (CompPlugin * plugin, int version) +{ + return ABIVERSION; +} + + +CompPluginVTable thumbVTable = { + "thumbnail", + N_("Window Previews"), + N_("Window thumbnails at the taskbar"), + thumbGetVersion, + thumbInit, + thumbFini, + thumbInitDisplay, + thumbFiniDisplay, + thumbInitScreen, + thumbFiniScreen, + thumbInitWindow, + thumbFiniWindow, + 0, /* thumbGetDisplayOptions */ + 0, /* thumbSetDisplayOption */ + 0, + 0, + 0, /* Deps */ + 0, /* nDeps */ + 0, /* Features */ + 0, /* nFeatures */ +}; + + +CompPluginVTable * +getCompPluginInfo (void) +{ + return &thumbVTable; +} |