/* * Copyright © 2005 Novell, Inc. * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Author: David Reveman */ #include #include #include #include #include #include #include #include #include #define BERYL_ADVANCED_DECORATION_VERSION 10121980 typedef struct _Vector { int dx; int dy; int x0; int y0; } Vector; #define DECOR_BARE 0 #define DECOR_NORMAL 1 #define DECOR_ACTIVE 2 #define DECOR_NUM 3 typedef struct _DecorTexture { struct _DecorTexture *next; int refCount; Pixmap pixmap; Damage damage; CompTexture texture; } DecorTexture; typedef struct _Decoration { int refCount; DecorTexture *texture; CompWindowExtents output; CompWindowExtents input; CompWindowExtents maxInput; int minWidth; int minHeight; long flags; decor_quad_t *quad; int nQuad; } Decoration; typedef struct _ScaledQuad { CompMatrix matrix; double sx, sy; // stretch scales BoxRec box; } ScaledQuad; typedef struct _WindowDecoration { Decoration *decor; ScaledQuad *quad; int nQuad; } WindowDecoration; #define DECOR_APPLY_PAINT_MODIFIERS_DEFAULT TRUE #define DECOR_SHADOWS_ON_DOCKS_DEFAULT FALSE #define DECOR_MIPMAP_DEFAULT FALSE #define DECOR_DISPLAY_OPTION_APPLY_PAINT_MODIFIERS 0 #define DECOR_DISPLAY_OPTION_SHADOWS_ON_DOCKS 1 #define DECOR_DISPLAY_OPTION_COMMAND 2 #define DECOR_DISPLAY_OPTION_MIPMAP 3 #define DECOR_DISPLAY_OPTION_NUM 4 static int displayPrivateIndex; typedef struct _DecorDisplay { int screenPrivateIndex; HandleEventProc handleEvent; DecorTexture *textures; Atom supportingDmCheckAtom; Atom winDecorAtom; Atom decorAtom[DECOR_NUM]; CompOption opt[DECOR_DISPLAY_OPTION_NUM]; } DecorDisplay; typedef struct _DecorScreen { int windowPrivateIndex; Window dmWin; Decoration *decor[DECOR_NUM]; DrawWindowProc drawWindow; DamageWindowRectProc damageWindowRect; GetOutputExtentsForWindowProc getOutputExtentsForWindow; WindowMoveNotifyProc windowMoveNotify; WindowResizeNotifyProc windowResizeNotify; WindowStateChangeNotifyProc windowStateChangeNotify; } DecorScreen; typedef struct _DecorWindow { WindowDecoration *wd; Decoration *decor; Bool needsUpdate; } DecorWindow; #define GET_DECOR_DISPLAY(d) \ ((DecorDisplay *) (d)->privates[displayPrivateIndex].ptr) #define DECOR_DISPLAY(d) \ DecorDisplay *dd = GET_DECOR_DISPLAY (d) #define GET_DECOR_SCREEN(s, dd) \ ((DecorScreen *) (s)->privates[(dd)->screenPrivateIndex].ptr) #define DECOR_SCREEN(s) \ DecorScreen *ds = GET_DECOR_SCREEN (s, GET_DECOR_DISPLAY (s->display)) #define GET_DECOR_WINDOW(w, ds) \ ((DecorWindow *) (w)->privates[(ds)->windowPrivateIndex].ptr) #define DECOR_WINDOW(w) \ DecorWindow *dw = GET_DECOR_WINDOW (w, \ GET_DECOR_SCREEN (w->screen, \ GET_DECOR_DISPLAY (w->screen->display))) #define NUM_OPTIONS(d) (sizeof ((d)->opt) / sizeof (CompOption)) static void decorDisplayInitOptions(DecorDisplay * dd) { CompOption *o; o = &dd->opt[DECOR_DISPLAY_OPTION_APPLY_PAINT_MODIFIERS]; o->advanced = False; o->name = "apply_paint_modifiers"; o->group = N_("Misc. options"); o->subGroup = N_("Appearance"); o->displayHints = ""; o->shortDesc = N_("Apply Transparency/Brightness/Saturation"); o->longDesc = N_ ("Apply the transparency/brightness/saturation of the Window to the Decoration."); o->type = CompOptionTypeBool; o->value.b = DECOR_APPLY_PAINT_MODIFIERS_DEFAULT; o = &dd->opt[DECOR_DISPLAY_OPTION_COMMAND]; o->advanced = False; o->name = "command"; o->group = N_("Misc. options"); o->subGroup = N_(""); o->displayHints = ""; o->shortDesc = N_("Command Line"); o->longDesc = N_("Decorator Command Line that is executed if no " "decorator is already running."); o->type = CompOptionTypeString; o->value.s = strdup(""); o->rest.s.string = NULL; o->rest.s.nString = 0; o = &dd->opt[DECOR_DISPLAY_OPTION_SHADOWS_ON_DOCKS]; o->advanced = False; o->name = "shadows_on_docks"; o->group = N_("Misc. options"); o->subGroup = N_("Appearance"); o->displayHints = ""; o->shortDesc = N_("Draw Shadows on Panel Type Windows"); o->longDesc = N_("Draw basic Shadow Decoration on panel windows."); o->type = CompOptionTypeBool; o->value.b = DECOR_SHADOWS_ON_DOCKS_DEFAULT; /*o = &dd->opt[DECOR_DISPLAY_OPTION_DROP_SHADOWS]; o->advanced=False; o->name = "drop_shadows"; o->group=N_(""); o->subGroup=N_(""); o->displayHints=""; o->shortDesc = N_("Draw simple shaped drop-shadows"); o->longDesc = N_("Draw a simple shaped drop-shadow on windows, separate from " "decoration manager."); o->type = CompOptionTypeBool; o->value.b = FALSE; */ o = &dd->opt[DECOR_DISPLAY_OPTION_MIPMAP]; o->advanced = False; o->name = "mipmap"; o->group = N_("Main"); o->subGroup = N_(""); o->displayHints = ""; o->shortDesc = N_("Mipmap"); o->longDesc = N_("Allow Mipmaps to be generated for Decoration textures."); o->type = CompOptionTypeBool; o->value.b = DECOR_MIPMAP_DEFAULT; } static CompOption *decorGetDisplayOptions(CompDisplay * display, int *count) { if (display) { DECOR_DISPLAY(display); *count = NUM_OPTIONS(dd); return dd->opt; } else { DecorDisplay *dd = malloc(sizeof(DecorDisplay)); decorDisplayInitOptions(dd); *count = NUM_OPTIONS(dd); return dd->opt; } } static Bool decorWindowUpdate(CompWindow * w, Bool move); static Bool decorSetDisplayOption(CompDisplay * display, char *name, CompOptionValue * value) { CompOption *o; int index; DECOR_DISPLAY(display); o = compFindOption(dd->opt, NUM_OPTIONS(dd), name, &index); if (!o) return FALSE; switch (index) { case DECOR_DISPLAY_OPTION_APPLY_PAINT_MODIFIERS: //case DECOR_DISPLAY_OPTION_DROP_SHADOWS: if (compSetBoolOption(o, value)) { damageScreen(display->screens); return TRUE; } break; case DECOR_DISPLAY_OPTION_COMMAND: if (compSetStringOption(o, value)) { if (display->screens && *o->value.s != '\0') { DECOR_SCREEN(display->screens); /* run decorator command if no decorator is present on first screen */ if (!ds->dmWin) { if (fork() == 0) { putenv(display->displayString); execl("/bin/sh", "/bin/sh", "-c", o->value.s, NULL); exit(0); } } } return TRUE; } break; case DECOR_DISPLAY_OPTION_SHADOWS_ON_DOCKS: if (compSetBoolOption(o, value)) { CompScreen *s; CompWindow *w; for (s = display->screens; s; s = s->next) for (w = s->windows; w; w = w->next) decorWindowUpdate(w, TRUE); return TRUE; } case DECOR_DISPLAY_OPTION_MIPMAP: if (compSetBoolOption(o, value)) return TRUE; default: break; } return FALSE; } static Bool decorDrawWindow(CompWindow * w, const WindowPaintAttrib * attrib, Region region, unsigned int mask) { Bool status; DECOR_WINDOW(w); if (dw->needsUpdate) decorWindowUpdate(w, FALSE); DECOR_SCREEN(w->screen); DECOR_DISPLAY(w->screen->display); if (!(mask & PAINT_WINDOW_SOLID_MASK)) { DECOR_WINDOW(w); if (mask & PAINT_WINDOW_TRANSFORMED_MASK) region = getInfiniteRegion(); if (dw->wd && region->numRects) { WindowDecoration *wd = dw->wd; WindowPaintAttrib sAttrib = *attrib; REGION box; int i; box.rects = &box.extents; box.numRects = 1; w->vCount = 0; for (i = 0; i < wd->nQuad; i++) { box.extents = wd->quad[i].box; if (box.extents.x1 < box.extents.x2 && box.extents.y1 < box.extents.y2) { (*w->screen->addWindowGeometry) (w, &wd-> quad [i]. matrix, 1, &box, region); } } if (!dd->opt[DECOR_DISPLAY_OPTION_APPLY_PAINT_MODIFIERS].value.b) { sAttrib.opacity = OPAQUE; sAttrib.saturation = COLOR; sAttrib.brightness = BRIGHT; } if (w->vCount) { (*w->screen->drawWindowTexture) (w, &wd->decor->texture->texture, &sAttrib, mask | PAINT_WINDOW_TRANSLUCENT_MASK | PAINT_WINDOW_DECORATION_MASK); } } } UNWRAP(ds, w->screen, drawWindow); status = (*w->screen->drawWindow) (w, attrib, region, mask); WRAP(ds, w->screen, drawWindow, decorDrawWindow); return status; } static DecorTexture *decorGetTexture(CompScreen * screen, Pixmap pixmap) { DecorTexture *texture; unsigned int width, height, depth, ui; Window root; int i; DECOR_DISPLAY(screen->display); for (texture = dd->textures; texture; texture = texture->next) { if (texture->pixmap == pixmap) { texture->refCount++; return texture; } } texture = malloc(sizeof(DecorTexture)); if (!texture) return NULL; initTexture(screen, &texture->texture); // we get damage events for decorations if (texture->texture.mode == TEXTURE_MODE_COPY) { texture->texture.mode = TEXTURE_MODE_COPY_DAMAGE; texture->texture.cmd.damaged = TRUE; texture->texture.cmd.fullDamage = TRUE; } if (!XGetGeometry(screen->display->display, pixmap, &root, &i, &i, &width, &height, &ui, &depth)) { finiTexture(screen, &texture->texture); free(texture); return NULL; } if (!bindPixmapToTexture(screen, &texture->texture, pixmap, width, height, depth)) { finiTexture(screen, &texture->texture); free(texture); return NULL; } if (!dd->opt[DECOR_DISPLAY_OPTION_MIPMAP].value.b) texture->texture.mipmap = FALSE; texture->damage = XDamageCreate(screen->display->display, pixmap, XDamageReportRawRectangles); texture->refCount = 1; texture->pixmap = pixmap; texture->next = dd->textures; dd->textures = texture; return texture; } static void decorReleaseTexture(CompScreen * screen, DecorTexture * texture) { DECOR_DISPLAY(screen->display); texture->refCount--; if (texture->refCount) return; if (texture == dd->textures) { dd->textures = texture->next; } else { DecorTexture *t; for (t = dd->textures; t; t = t->next) { if (t->next == texture) { t->next = texture->next; break; } } } finiTexture(screen, &texture->texture); free(texture); } static void computeQuadBox(decor_quad_t * q, int width, int height, int *return_x1, int *return_y1, int *return_x2, int *return_y2, double *return_sx, double *return_sy) { int x1, y1, x2, y2; double sx, sy; sx = 1; sy = 1; decor_apply_gravity(q->p1.gravity, q->p1.x, q->p1.y, width, height, &x1, &y1); decor_apply_gravity(q->p2.gravity, q->p2.x, q->p2.y, width, height, &x2, &y2); if (q->clamp & CLAMP_HORZ) { if (x2 - x1 > 0 && (q->clamp & CLAMP_VERT) && q->p1.x == 0 && q->p2.x == 0) sx = (double)q->max_width / ((double)x2 - (double)x1); if ((q->p1.x == 0 && q->p2.x == 0) || !(q->clamp & CLAMP_VERT)) { if (x1 < 0) x1 = 0; if (x2 > width) x2 = width; } } if (q->clamp & CLAMP_VERT) { if (y2 - y1 > 0 && (q->clamp & CLAMP_HORZ) && q->p1.y == 0 && q->p2.y == 0) sy = (double)q->max_height / ((double)y2 - (double)y1); if ((q->p1.y == 0 && q->p2.y == 0) || !(q->clamp & CLAMP_HORZ)) { if (y1 < 0) y1 = 0; if (y2 > height) y2 = height; } } if (q->max_width < x2 - x1 && !(q->clamp & CLAMP_VERT && q->clamp & CLAMP_HORZ)) { if (q->align & ALIGN_RIGHT) x1 = x2 - q->max_width; else x2 = x1 + q->max_width; } if (q->max_height < y2 - y1 && !(q->clamp & CLAMP_VERT && q->clamp & CLAMP_HORZ)) { if (q->align & ALIGN_BOTTOM) y1 = y2 - q->max_height; else y2 = y1 + q->max_height; } *return_x1 = x1; *return_y1 = y1; *return_x2 = x2; *return_y2 = y2; if (return_sx) *return_sx = sx; if (return_sy) *return_sy = sy; } static Decoration *decorCreateDecoration(CompScreen * screen, Window id, Atom decorAtom) { Decoration *decoration; Atom actual; int result, format; unsigned long n, nleft; unsigned char *data; long *prop; Pixmap pixmap; decor_extents_t input; decor_extents_t maxInput; decor_quad_t *quad; int nQuad; int minWidth, minHeight; int left, right, top, bottom; int x1, y1, x2, y2; double sx, sy; result = XGetWindowProperty(screen->display->display, id, decorAtom, 0L, 1024L, FALSE, XA_INTEGER, &actual, &format, &n, &nleft, &data); if (result != Success || !n || !data) return NULL; prop = (long*) data; if (decor_property_get_version(prop) != decor_version()) { fprintf (stderr, "%s: decoration: property ignored because " "version is %d and decoration plugin version is %d\n", getProgramName(), decor_property_get_version (prop), decor_version ()); XFree(data); return NULL; } nQuad = (n - BASE_PROP_SIZE) / QUAD_PROP_SIZE; quad = malloc(sizeof(decor_quad_t) * nQuad); if (!quad) { XFree(data); return NULL; } nQuad = decor_property_to_quads(prop, n, &pixmap, &input, &maxInput, &minWidth, &minHeight, quad); XFree(data); if (!nQuad) { free(quad); return NULL; } decoration = malloc(sizeof(Decoration)); if (!decoration) { free(quad); return NULL; } decoration->texture = decorGetTexture(screen, pixmap); if (!decoration->texture) { free(decoration); free(quad); return NULL; } decoration->minWidth = minWidth; decoration->minHeight = minHeight; decoration->quad = quad; decoration->nQuad = nQuad; left = 0; right = decoration->minWidth; top = 0; bottom = decoration->minHeight; while (nQuad--) { computeQuadBox(quad, minWidth, minHeight, &x1, &y1, &x2, &y2, &sx, &sy); if (x1 < left) left = x1; if (y1 < top) top = y1; if (x2 > right) right = x2; if (y2 > bottom) bottom = y2; quad++; } decoration->input.left = input.left; decoration->input.right = input.right; decoration->input.top = input.top; decoration->input.bottom = input.bottom; decoration->maxInput.left = maxInput.left; decoration->maxInput.right = maxInput.right; decoration->maxInput.top = maxInput.top; decoration->maxInput.bottom = maxInput.bottom; decoration->output.left = -left; decoration->output.right = right - decoration->minWidth; decoration->output.top = -top; decoration->output.bottom = bottom - decoration->minHeight; decoration->refCount = 1; return decoration; } static void decorReleaseDecoration(CompScreen * screen, Decoration * decoration) { decoration->refCount--; if (decoration->refCount) return; decorReleaseTexture(screen, decoration->texture); free(decoration->quad); free(decoration); } static void decorWindowUpdateDecoration(CompWindow * w) { Decoration *decoration; DECOR_DISPLAY(w->screen->display); DECOR_WINDOW(w); dw->needsUpdate = False; decoration = decorCreateDecoration(w->screen, w->id, dd->winDecorAtom); if (dw->decor) decorReleaseDecoration(w->screen, dw->decor); dw->decor = decoration; } static WindowDecoration *createWindowDecoration(Decoration * d) { WindowDecoration *wd; wd = malloc(sizeof(WindowDecoration) + sizeof(ScaledQuad) * d->nQuad); if (!wd) return NULL; d->refCount++; wd->decor = d; wd->quad = (ScaledQuad *) (wd + 1); wd->nQuad = d->nQuad; return wd; } static void destroyWindowDecoration(CompScreen * screen, WindowDecoration * wd) { decorReleaseDecoration(screen, wd->decor); free(wd); } static void setDecorationMatrices(CompWindow * w) { WindowDecoration *wd; int i; float x0, y0; DECOR_WINDOW(w); wd = dw->wd; if (!wd) return; for (i = 0; i < wd->nQuad; i++) { decor_matrix_t a; CompMatrix b; wd->quad[i].matrix = wd->decor->texture->texture.matrix; x0 = wd->decor->quad[i].m.x0; y0 = wd->decor->quad[i].m.y0; a = wd->decor->quad[i].m; b = wd->quad[i].matrix; wd->quad[i].matrix.xx = a.xx * b.xx + a.yx * b.xy; wd->quad[i].matrix.yx = a.xx * b.yx + a.yx * b.yy; wd->quad[i].matrix.xy = a.xy * b.xx + a.yy * b.xy; wd->quad[i].matrix.yy = a.xy * b.yx + a.yy * b.yy; wd->quad[i].matrix.x0 = x0 * b.xx + y0 * b.xy + b.x0; wd->quad[i].matrix.y0 = x0 * b.yx + y0 * b.yy + b.y0; if (wd->decor->quad[i].clamp & CLAMP_VERT && wd->decor->quad[i].clamp & CLAMP_HORZ) { wd->quad[i].matrix.xx *= wd->quad[i].sx; wd->quad[i].matrix.yx *= wd->quad[i].sx; wd->quad[i].matrix.xy *= wd->quad[i].sy; wd->quad[i].matrix.yy *= wd->quad[i].sy; } if (wd->decor->quad[i].align & ALIGN_RIGHT) x0 = wd->quad[i].box.x2 - wd->quad[i].box.x1; else x0 = 0.0f; if (wd->decor->quad[i].align & ALIGN_BOTTOM) y0 = wd->quad[i].box.y2 - wd->quad[i].box.y1; else y0 = 0.0f; wd->quad[i].matrix.x0 -= x0 * wd->quad[i].matrix.xx + y0 * wd->quad[i].matrix.xy; wd->quad[i].matrix.y0 -= y0 * wd->quad[i].matrix.yy + x0 * wd->quad[i].matrix.yx; wd->quad[i].matrix.x0 -= wd->quad[i].box.x1 * wd->quad[i].matrix.xx + wd->quad[i].box.y1 * wd->quad[i].matrix.xy; wd->quad[i].matrix.y0 -= wd->quad[i].box.y1 * wd->quad[i].matrix.yy + wd->quad[i].box.x1 * wd->quad[i].matrix.yx; } } static void updateWindowDecorationScale(CompWindow * w) { WindowDecoration *wd; int x1, y1, x2, y2; double sx, sy; int i; DECOR_WINDOW(w); wd = dw->wd; if (!wd) return; for (i = 0; i < wd->nQuad; i++) { computeQuadBox(&wd->decor->quad[i], w->width, w->height, &x1, &y1, &x2, &y2, &sx, &sy); wd->quad[i].box.x1 = x1 + w->attrib.x; wd->quad[i].box.y1 = y1 + w->attrib.y; wd->quad[i].box.x2 = x2 + w->attrib.x; wd->quad[i].box.y2 = y2 + w->attrib.y; wd->quad[i].sx = sx; wd->quad[i].sy = sy; } setDecorationMatrices(w); } static Bool decorCheckSize(CompWindow * w, Decoration * decor) { return (decor->minWidth <= w->width && decor->minHeight <= w->height); } static Bool decorWindowUpdate(CompWindow * w, Bool move) { WindowDecoration *wd; Decoration *old, *decor = NULL; DECOR_SCREEN(w->screen); DECOR_WINDOW(w); DECOR_DISPLAY(w->screen->display); wd = dw->wd; old = (wd) ? wd->decor : NULL; if (dw->decor && decorCheckSize(w, dw->decor)) { if (w->type != CompWindowTypeFullscreenMask) decor = dw->decor; } else { if (w->attrib.override_redirect) { if (w->region->numRects == 1 && !w->alpha) decor = ds->decor[DECOR_BARE]; } else { switch (w->type) { case CompWindowTypeDialogMask: case CompWindowTypeModalDialogMask: case CompWindowTypeUtilMask: case CompWindowTypeNormalMask: if (w->mwmDecor & (MwmDecorAll | MwmDecorTitle | MwmDecorBorder)) { if (w->id == w->screen->display->activeWindow) decor = ds->decor[DECOR_ACTIVE]; else decor = ds->decor[DECOR_NORMAL]; break; } /* fall-through */ default: if (w->region->numRects == 1 && !w->alpha) decor = ds->decor[DECOR_BARE]; /* no decoration on windows with below state */ if (w->state & CompWindowStateBelowMask) decor = NULL; if (w->type == CompWindowTypeDockMask && !dd->opt[DECOR_DISPLAY_OPTION_SHADOWS_ON_DOCKS].value.b) decor = NULL; if (w->type & CompWindowTypeDesktopMask) decor = NULL; break; } } if (decor) { if (!decorCheckSize(w, decor)) decor = NULL; } } if (!ds->dmWin) decor = NULL; if (decor == old) return FALSE; damageWindowOutputExtents(w); if (old) destroyWindowDecoration(w->screen, wd); if (decor) { dw->wd = createWindowDecoration(decor); if (!dw->wd) return FALSE; if ((w->state & MAXIMIZE_STATE) == MAXIMIZE_STATE) setWindowFrameExtents(w, &decor->maxInput); else setWindowFrameExtents(w, &decor->input); updateWindowOutputExtents(w); damageWindowOutputExtents(w); updateWindowDecorationScale(w); } else { dw->wd = NULL; } return TRUE; } static void decorCheckForDmOnScreen(CompScreen * s, Bool updateWindows) { CompDisplay *d = s->display; Atom actual; int result, format; unsigned long n, left; unsigned char *data; Window dmWin = None; DECOR_DISPLAY(s->display); DECOR_SCREEN(s); result = XGetWindowProperty(d->display, s->root, dd->supportingDmCheckAtom, 0L, 1L, FALSE, XA_WINDOW, &actual, &format, &n, &left, &data); if (result == Success && n && data) { XWindowAttributes attr; memcpy(&dmWin, data, sizeof(Window)); XFree(data); compCheckForError(d->display); XGetWindowAttributes(d->display, dmWin, &attr); if (compCheckForError(d->display)) dmWin = None; } if (dmWin != ds->dmWin) { CompWindow *w; int i; if (dmWin) { for (i = 0; i < DECOR_NUM; i++) ds->decor[i] = decorCreateDecoration(s, s->root, dd->decorAtom[i]); } else { for (i = 0; i < DECOR_NUM; i++) { if (ds->decor[i]) { decorReleaseDecoration(s, ds->decor[i]); ds->decor[i] = 0; } } for (w = s->windows; w; w = w->next) { DECOR_WINDOW(w); if (dw->decor) { decorReleaseDecoration(s, dw->decor); dw->decor = 0; } } } ds->dmWin = dmWin; if (updateWindows) { for (w = s->windows; w; w = w->next) decorWindowUpdate(w, TRUE); } } } static void decorHandleEvent(CompDisplay * d, XEvent * event) { Window activeWindow = 0; CompWindow *w; DECOR_DISPLAY(d); switch (event->type) { case PropertyNotify: if (event->xproperty.atom == d->winActiveAtom) activeWindow = d->activeWindow; break; case DestroyNotify: w = findWindowAtDisplay(d, event->xdestroywindow.window); if (w) { DECOR_SCREEN(w->screen); if (w->id == ds->dmWin) decorCheckForDmOnScreen(w->screen, TRUE); } default: if (event->type == d->damageEvent + XDamageNotify) { XDamageNotifyEvent *de = (XDamageNotifyEvent *) event; DecorTexture *t; for (t = dd->textures; t; t = t->next) { if (t->pixmap == de->drawable) { DecorWindow *dw; DecorScreen *ds; CompScreen *s; t->texture.oldMipmaps = TRUE; for (s = d->screens; s; s = s->next) { ds = GET_DECOR_SCREEN(s, dd); for (w = s->windows; w; w = w->next) { if (w->shaded || w->mapNum) { dw = GET_DECOR_WINDOW(w, ds); if (dw->wd && dw->wd->decor->texture == t) { if (dw->wd->decor->texture->texture. mode == TEXTURE_MODE_COPY_DAMAGE) { dw->wd->decor->texture->texture.cmd. damaged = TRUE; dw->wd->decor->texture->texture.cmd. fullDamage = TRUE; } damageWindowOutputExtents(w); } } } } return; } } } break; } UNWRAP(dd, d, handleEvent); (*d->handleEvent) (d, event); WRAP(dd, d, handleEvent, decorHandleEvent); switch (event->type) { case PropertyNotify: if (event->xproperty.atom == d->winActiveAtom) { if (d->activeWindow != activeWindow) { w = findWindowAtDisplay(d, activeWindow); if (w) decorWindowUpdate(w, FALSE); w = findWindowAtDisplay(d, d->activeWindow); if (w) decorWindowUpdate(w, FALSE); } } else if (event->xproperty.atom == dd->winDecorAtom) { w = findWindowAtDisplay(d, event->xproperty.window); if (w) { decorWindowUpdateDecoration(w); decorWindowUpdate(w, TRUE); } } else if (event->xproperty.atom == d->mwmHintsAtom) { w = findWindowAtDisplay(d, event->xproperty.window); if (w) decorWindowUpdate(w, TRUE); } else { CompScreen *s; s = findScreenAtDisplay(d, event->xproperty.window); if (s) { if (event->xproperty.atom == dd->supportingDmCheckAtom) { decorCheckForDmOnScreen(s, TRUE); } else { int i; for (i = 0; i < DECOR_NUM; i++) { if (event->xproperty.atom == dd->decorAtom[i]) { DECOR_SCREEN(s); if (ds->decor[i]) decorReleaseDecoration(s, ds->decor[i]); ds->decor[i] = decorCreateDecoration (s, s->root, dd->decorAtom[i]); for (w = s->windows; w; w = w->next) decorWindowUpdate(w, TRUE); } } } } } break; case MapRequest: w = findWindowAtDisplay(d, event->xmaprequest.window); if (w) decorWindowUpdate(w, TRUE); break; default: if (d->shapeExtension && event->type == d->shapeEvent + ShapeNotify) { w = findWindowAtDisplay(d, ((XShapeEvent *) event)->window); if (w) decorWindowUpdate(w, TRUE); } break; } } static Bool decorDamageWindowRect(CompWindow * w, Bool initial, BoxPtr rect) { Bool status; DECOR_SCREEN(w->screen); if (initial) decorWindowUpdate(w, FALSE); UNWRAP(ds, w->screen, damageWindowRect); status = (*w->screen->damageWindowRect) (w, initial, rect); WRAP(ds, w->screen, damageWindowRect, decorDamageWindowRect); return status; } static void decorGetOutputExtentsForWindow(CompWindow * w, CompWindowExtents * output) { DECOR_SCREEN(w->screen); DECOR_WINDOW(w); if (dw->needsUpdate) decorWindowUpdate(w, FALSE); UNWRAP(ds, w->screen, getOutputExtentsForWindow); (*w->screen->getOutputExtentsForWindow) (w, output); WRAP(ds, w->screen, getOutputExtentsForWindow, decorGetOutputExtentsForWindow); if (dw->wd) { CompWindowExtents *e = &dw->wd->decor->output; if (e->left > output->left) output->left = e->left; if (e->right > output->right) output->right = e->right; if (e->top > output->top) output->top = e->top; if (e->bottom > output->bottom) output->bottom = e->bottom; } } static void decorWindowMoveNotify(CompWindow * w, int dx, int dy, Bool immediate) { DECOR_SCREEN(w->screen); DECOR_WINDOW(w); if (dw->wd) { WindowDecoration *wd = dw->wd; int i; for (i = 0; i < wd->nQuad; i++) { wd->quad[i].box.x1 += dx; wd->quad[i].box.y1 += dy; wd->quad[i].box.x2 += dx; wd->quad[i].box.y2 += dy; } setDecorationMatrices(w); } UNWRAP(ds, w->screen, windowMoveNotify); (*w->screen->windowMoveNotify) (w, dx, dy, immediate); WRAP(ds, w->screen, windowMoveNotify, decorWindowMoveNotify); } static void decorWindowResizeNotify(CompWindow * w, int dx, int dy, int dwidth, int dheight, Bool preview) { DECOR_SCREEN(w->screen); if ( !decorWindowUpdate(w, FALSE)) updateWindowDecorationScale(w); UNWRAP(ds, w->screen, windowResizeNotify); (*w->screen->windowResizeNotify) (w, dx, dy, dwidth, dheight, preview); WRAP(ds, w->screen, windowResizeNotify, decorWindowResizeNotify); } static void decorWindowStateChangeNotify(CompWindow * w) { DECOR_SCREEN(w->screen); DECOR_WINDOW(w); if (dw->wd && dw->wd->decor) { Decoration *decor = dw->wd->decor; if ((w->state & MAXIMIZE_STATE) == MAXIMIZE_STATE) setWindowFrameExtents(w, &decor->maxInput); else setWindowFrameExtents(w, &decor->input); } UNWRAP(ds, w->screen, windowStateChangeNotify); (*w->screen->windowStateChangeNotify) (w); WRAP(ds, w->screen, windowStateChangeNotify, decorWindowStateChangeNotify); } static Bool decorInitDisplay(CompPlugin * p, CompDisplay * d) { DecorDisplay *dd; dd = malloc(sizeof(DecorDisplay)); if (!dd) return FALSE; dd->screenPrivateIndex = allocateScreenPrivateIndex(d); if (dd->screenPrivateIndex < 0) { free(dd); return FALSE; } dd->textures = 0; dd->supportingDmCheckAtom = XInternAtom(d->display, "_NET_SUPPORTING_DM_CHECK", 0); dd->winDecorAtom = XInternAtom(d->display, "_NET_WINDOW_DECOR", 0); dd->decorAtom[DECOR_BARE] = XInternAtom(d->display, "_NET_WINDOW_DECOR_BARE", 0); dd->decorAtom[DECOR_NORMAL] = XInternAtom(d->display, "_NET_WINDOW_DECOR_NORMAL", 0); dd->decorAtom[DECOR_ACTIVE] = XInternAtom(d->display, "_NET_WINDOW_DECOR_ACTIVE", 0); decorDisplayInitOptions(dd); WRAP(dd, d, handleEvent, decorHandleEvent); d->privates[displayPrivateIndex].ptr = dd; return TRUE; } static void decorFiniDisplay(CompPlugin * p, CompDisplay * d) { DECOR_DISPLAY(d); freeScreenPrivateIndex(d, dd->screenPrivateIndex); UNWRAP(dd, d, handleEvent); free(dd); } static Bool decorInitScreen(CompPlugin * p, CompScreen * s) { DecorScreen *ds; DECOR_DISPLAY(s->display); ds = malloc(sizeof(DecorScreen)); if (!ds) return FALSE; ds->windowPrivateIndex = allocateWindowPrivateIndex(s); if (ds->windowPrivateIndex < 0) { free(ds); return FALSE; } memset(ds->decor, 0, sizeof(ds->decor)); ds->dmWin = None; WRAP(ds, s, drawWindow, decorDrawWindow); WRAP(ds, s, damageWindowRect, decorDamageWindowRect); WRAP(ds, s, getOutputExtentsForWindow, decorGetOutputExtentsForWindow); WRAP(ds, s, windowMoveNotify, decorWindowMoveNotify); WRAP(ds, s, windowResizeNotify, decorWindowResizeNotify); WRAP(ds, s, windowStateChangeNotify, decorWindowStateChangeNotify); s->privates[dd->screenPrivateIndex].ptr = ds; decorCheckForDmOnScreen(s, FALSE); return TRUE; } static void decorFiniScreen(CompPlugin * p, CompScreen * s) { int i; DECOR_SCREEN(s); for (i = 0; i < DECOR_NUM; i++) if (ds->decor[i]) decorReleaseDecoration(s, ds->decor[i]); UNWRAP(ds, s, drawWindow); UNWRAP(ds, s, damageWindowRect); UNWRAP(ds, s, getOutputExtentsForWindow); UNWRAP(ds, s, windowMoveNotify); UNWRAP(ds, s, windowResizeNotify); UNWRAP(ds, s, windowStateChangeNotify); free(ds); } static Bool decorInitWindow(CompPlugin * p, CompWindow * w) { DecorWindow *dw; DECOR_SCREEN(w->screen); dw = malloc(sizeof(DecorWindow)); if (!dw) return FALSE; dw->wd = NULL; dw->decor = NULL; w->privates[ds->windowPrivateIndex].ptr = dw; dw->needsUpdate = False; if (!w->attrib.override_redirect) decorWindowUpdateDecoration(w); if (w->shaded || w->attrib.map_state == IsViewable) dw->needsUpdate = True; return TRUE; } static void decorFiniWindow(CompPlugin * p, CompWindow * w) { DECOR_WINDOW(w); if (dw->wd) destroyWindowDecoration(w->screen, dw->wd); if (dw->decor) decorReleaseDecoration(w->screen, dw->decor); free(dw); } static Bool decorInit(CompPlugin * p) { displayPrivateIndex = allocateDisplayPrivateIndex(); if (displayPrivateIndex < 0) return FALSE; return TRUE; } static void decorFini(CompPlugin * p) { if (displayPrivateIndex >= 0) freeDisplayPrivateIndex(displayPrivateIndex); } static CompPluginVTable decorVTable = { "decoration", N_("Window Decoration"), N_("Window decorations"), decorInit, decorFini, decorInitDisplay, decorFiniDisplay, decorInitScreen, decorFiniScreen, decorInitWindow, decorFiniWindow, decorGetDisplayOptions, decorSetDisplayOption, 0, /* GetScreenOptions */ 0, /* SetScreenOption */ 0, 0, 0, 0, BERYL_ABI_INFO, "beryl-plugins", "effects", 0, 0, True, }; CompPluginVTable *getCompPluginInfo(void) { return &decorVTable; }