You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1054 lines
24 KiB
1054 lines
24 KiB
/*
|
|
* Copyright © 2006 Novell, Inc.
|
|
*
|
|
* Permission to use, copy, modify, distribute, and sell this software
|
|
* and its documentation for any purpose is hereby granted without
|
|
* fee, provided that the above copyright notice appear in all copies
|
|
* and that both that copyright notice and this permission notice
|
|
* appear in supporting documentation, and that the name of
|
|
* Novell, Inc. not be used in advertising or publicity pertaining to
|
|
* distribution of the software without specific, written prior permission.
|
|
* Novell, Inc. makes no representations about the suitability of this
|
|
* software for any purpose. It is provided "as is" without express or
|
|
* implied warranty.
|
|
*
|
|
* NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
|
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
|
|
* NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
|
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
|
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
|
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
|
|
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
*
|
|
* Author: David Reveman <davidr@novell.com>
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include <cairo/cairo-xlib.h>
|
|
#include <librsvg/rsvg.h>
|
|
#include <librsvg/rsvg-cairo.h>
|
|
|
|
#include <X11/Xatom.h>
|
|
#include <X11/extensions/shape.h>
|
|
|
|
#include <compiz-core.h>
|
|
#include <decoration.h>
|
|
|
|
static CompMetadata svgMetadata;
|
|
|
|
#define SVG_DISPLAY_OPTION_SET 0
|
|
#define SVG_DISPLAY_OPTION_NUM 1
|
|
|
|
static int displayPrivateIndex;
|
|
|
|
typedef struct _SvgDisplay {
|
|
CompOption opt[SVG_DISPLAY_OPTION_NUM];
|
|
|
|
int screenPrivateIndex;
|
|
|
|
HandleCompizEventProc handleCompizEvent;
|
|
|
|
FileToImageProc fileToImage;
|
|
} SvgDisplay;
|
|
|
|
typedef struct _SvgScreen {
|
|
int windowPrivateIndex;
|
|
|
|
DrawWindowProc drawWindow;
|
|
|
|
WindowMoveNotifyProc windowMoveNotify;
|
|
WindowResizeNotifyProc windowResizeNotify;
|
|
|
|
BoxRec zoom;
|
|
} SvgScreen;
|
|
|
|
typedef struct _SvgSource {
|
|
decor_point_t p1;
|
|
decor_point_t p2;
|
|
|
|
RsvgHandle *svg;
|
|
RsvgDimensionData dimension;
|
|
} SvgSource;
|
|
|
|
typedef struct _SvgTexture {
|
|
CompTexture texture;
|
|
CompMatrix matrix;
|
|
cairo_t *cr;
|
|
Pixmap pixmap;
|
|
int width;
|
|
int height;
|
|
} SvgTexture;
|
|
|
|
typedef struct _SvgContext {
|
|
SvgSource *source;
|
|
REGION box;
|
|
SvgTexture texture[2];
|
|
BoxRec rect;
|
|
int width, height;
|
|
} SvgContext;
|
|
|
|
typedef struct _SvgWindow {
|
|
SvgSource *source;
|
|
SvgContext *context;
|
|
} SvgWindow;
|
|
|
|
#define GET_SVG_DISPLAY(d) \
|
|
((SvgDisplay *) (d)->base.privates[displayPrivateIndex].ptr)
|
|
|
|
#define SVG_DISPLAY(d) \
|
|
SvgDisplay *sd = GET_SVG_DISPLAY (d)
|
|
|
|
#define GET_SVG_SCREEN(s, sd) \
|
|
((SvgScreen *) (s)->base.privates[(sd)->screenPrivateIndex].ptr)
|
|
|
|
#define SVG_SCREEN(s) \
|
|
SvgScreen *ss = GET_SVG_SCREEN (s, GET_SVG_DISPLAY (s->display))
|
|
|
|
#define GET_SVG_WINDOW(w, ss) \
|
|
((SvgWindow *) (w)->base.privates[(ss)->windowPrivateIndex].ptr)
|
|
|
|
#define SVG_WINDOW(w) \
|
|
SvgWindow *sw = GET_SVG_WINDOW (w, \
|
|
GET_SVG_SCREEN (w->screen, \
|
|
GET_SVG_DISPLAY (w->screen->display)))
|
|
|
|
#define NUM_OPTIONS(d) (sizeof ((d)->opt) / sizeof (CompOption))
|
|
|
|
static void
|
|
renderSvg (CompScreen *s,
|
|
SvgSource *source,
|
|
SvgTexture *texture,
|
|
float x1,
|
|
float y1,
|
|
float x2,
|
|
float y2,
|
|
int width,
|
|
int height)
|
|
{
|
|
float w = x2 - x1;
|
|
float h = y2 - y1;
|
|
|
|
cairo_save (texture->cr);
|
|
|
|
cairo_set_operator (texture->cr, CAIRO_OPERATOR_SOURCE);
|
|
cairo_set_source_rgba (texture->cr, 1.0, 1.0, 1.0, 0.0);
|
|
cairo_paint (texture->cr);
|
|
cairo_set_operator (texture->cr, CAIRO_OPERATOR_OVER);
|
|
|
|
cairo_scale (texture->cr, 1.0 / w, 1.0 / h);
|
|
|
|
cairo_scale (texture->cr,
|
|
(double) width / source->dimension.width,
|
|
(double) height / source->dimension.height);
|
|
|
|
cairo_translate (texture->cr,
|
|
-x1 * source->dimension.width,
|
|
-y1 * source->dimension.height);
|
|
|
|
rsvg_handle_render_cairo (source->svg, texture->cr);
|
|
|
|
cairo_restore (texture->cr);
|
|
}
|
|
|
|
static Bool
|
|
initSvgTexture (CompWindow *w,
|
|
SvgSource *source,
|
|
SvgTexture *texture,
|
|
int width,
|
|
int height)
|
|
{
|
|
cairo_surface_t *surface;
|
|
CompScreen *s = w->screen;
|
|
Visual *visual;
|
|
int depth;
|
|
|
|
initTexture (s, &texture->texture);
|
|
|
|
texture->width = width;
|
|
texture->height = height;
|
|
|
|
texture->pixmap = None;
|
|
texture->cr = NULL;
|
|
|
|
if (width && height)
|
|
{
|
|
XWindowAttributes attr;
|
|
XGetWindowAttributes (s->display->display, w->id, &attr);
|
|
|
|
depth = attr.depth;
|
|
texture->pixmap = XCreatePixmap (s->display->display, s->root,
|
|
width, height, depth);
|
|
|
|
if (!bindPixmapToTexture (s,
|
|
&texture->texture,
|
|
texture->pixmap,
|
|
width, height, depth))
|
|
{
|
|
fprintf (stderr, "%s: Couldn't bind pixmap 0x%x to "
|
|
"texture\n", programName, (int) texture->pixmap);
|
|
|
|
XFreePixmap (s->display->display, texture->pixmap);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
visual = attr.visual;
|
|
surface = cairo_xlib_surface_create (s->display->display,
|
|
texture->pixmap, visual,
|
|
width, height);
|
|
texture->cr = cairo_create (surface);
|
|
cairo_surface_destroy (surface);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
finiSvgTexture (CompScreen *s,
|
|
SvgTexture *texture)
|
|
{
|
|
if (texture->cr)
|
|
cairo_destroy (texture->cr);
|
|
|
|
if (texture->pixmap)
|
|
XFreePixmap (s->display->display, texture->pixmap);
|
|
|
|
finiTexture (s, &texture->texture);
|
|
}
|
|
|
|
static void
|
|
updateWindowSvgMatrix (CompWindow *w)
|
|
{
|
|
CompMatrix *m;
|
|
int width, height;
|
|
|
|
SVG_WINDOW (w);
|
|
|
|
width = sw->context->box.extents.x2 - sw->context->box.extents.x1;
|
|
height = sw->context->box.extents.y2 - sw->context->box.extents.y1;
|
|
|
|
m = &sw->context->texture[0].matrix;
|
|
*m = sw->context->texture[0].texture.matrix;
|
|
|
|
m->xx *= (float) sw->context->texture[0].width / width;
|
|
m->yy *= (float) sw->context->texture[0].height / height;
|
|
|
|
m->x0 -= (sw->context->box.extents.x1 * m->xx);
|
|
m->y0 -= (sw->context->box.extents.y1 * m->yy);
|
|
|
|
m = &sw->context->texture[1].matrix;
|
|
*m = sw->context->texture[1].texture.matrix;
|
|
|
|
width = sw->context->rect.x2 - sw->context->rect.x1;
|
|
height = sw->context->rect.y2 - sw->context->rect.y1;
|
|
|
|
m->xx *= (float) sw->context->texture[1].width / width;
|
|
m->yy *= (float) sw->context->texture[1].height / height;
|
|
|
|
m->x0 -= (sw->context->rect.x1 * m->xx);
|
|
m->y0 -= (sw->context->rect.y1 * m->yy);
|
|
}
|
|
|
|
static Bool
|
|
svgDrawWindow (CompWindow *w,
|
|
const CompTransform *transform,
|
|
const FragmentAttrib *attrib,
|
|
Region region,
|
|
unsigned int mask)
|
|
{
|
|
Bool status;
|
|
|
|
SVG_SCREEN (w->screen);
|
|
|
|
UNWRAP (ss, w->screen, drawWindow);
|
|
status = (*w->screen->drawWindow) (w, transform, attrib, region, mask);
|
|
WRAP (ss, w->screen, drawWindow, svgDrawWindow);
|
|
|
|
if (status)
|
|
{
|
|
SVG_WINDOW (w);
|
|
|
|
if (mask & PAINT_WINDOW_TRANSFORMED_MASK)
|
|
region = &infiniteRegion;
|
|
|
|
if (sw->context && region->numRects)
|
|
{
|
|
CompTexture *texture = &sw->context->texture[0].texture;
|
|
CompMatrix *matrix = &sw->context->texture[0].matrix;
|
|
REGION r;
|
|
|
|
r.rects = &r.extents;
|
|
r.numRects = 1;
|
|
|
|
r.extents = sw->context->box.extents;
|
|
|
|
if (r.extents.x1 < ss->zoom.x1)
|
|
r.extents.x1 = ss->zoom.x1;
|
|
if (r.extents.y1 < ss->zoom.y1)
|
|
r.extents.y1 = ss->zoom.y1;
|
|
if (r.extents.x2 > ss->zoom.x2)
|
|
r.extents.x2 = ss->zoom.x2;
|
|
if (r.extents.y2 > ss->zoom.y2)
|
|
r.extents.y2 = ss->zoom.y2;
|
|
|
|
w->vCount = w->indexCount = 0;
|
|
|
|
(*w->screen->addWindowGeometry) (w,
|
|
matrix, 1,
|
|
&sw->context->box,
|
|
region);
|
|
|
|
if (mask & PAINT_WINDOW_TRANSLUCENT_MASK)
|
|
mask |= PAINT_WINDOW_BLEND_MASK;
|
|
|
|
(*w->screen->drawWindowTexture) (w, texture, attrib, mask);
|
|
|
|
if (r.extents.x1 < r.extents.x2 && r.extents.y1 < r.extents.y2)
|
|
{
|
|
float xScale, yScale;
|
|
float dx, dy;
|
|
int width, height;
|
|
int saveFilter;
|
|
|
|
r.extents.x1--;
|
|
r.extents.y1--;
|
|
r.extents.x2++;
|
|
r.extents.y2++;
|
|
|
|
xScale = w->screen->width / (float)
|
|
(ss->zoom.x2 - ss->zoom.x1);
|
|
yScale = w->screen->height / (float)
|
|
(ss->zoom.y2 - ss->zoom.y1);
|
|
|
|
dx = r.extents.x2 - r.extents.x1;
|
|
dy = r.extents.y2 - r.extents.y1;
|
|
|
|
width = dx * xScale + 0.5f;
|
|
height = dy * yScale + 0.5f;
|
|
|
|
if (r.extents.x1 != sw->context->rect.x1 ||
|
|
r.extents.y1 != sw->context->rect.y1 ||
|
|
r.extents.x2 != sw->context->rect.x2 ||
|
|
r.extents.y2 != sw->context->rect.y2 ||
|
|
width != sw->context->width ||
|
|
height != sw->context->height)
|
|
{
|
|
float x1, y1, x2, y2;
|
|
|
|
sw->context->rect = r.extents;
|
|
|
|
sw->context->width = width;
|
|
sw->context->height = height;
|
|
|
|
dx = sw->context->box.extents.x2 -
|
|
sw->context->box.extents.x1;
|
|
dy = sw->context->box.extents.y2 -
|
|
sw->context->box.extents.y1;
|
|
|
|
x1 = (r.extents.x1 - sw->context->box.extents.x1) / dx;
|
|
y1 = (r.extents.y1 - sw->context->box.extents.y1) / dy;
|
|
x2 = (r.extents.x2 - sw->context->box.extents.x1) / dx;
|
|
y2 = (r.extents.y2 - sw->context->box.extents.y1) / dy;
|
|
|
|
finiSvgTexture (w->screen, &sw->context->texture[1]);
|
|
|
|
if (initSvgTexture (w, sw->context->source,
|
|
&sw->context->texture[1],
|
|
width, height))
|
|
{
|
|
renderSvg (w->screen, sw->context->source,
|
|
&sw->context->texture[1],
|
|
x1, y1, x2, y2,
|
|
width, height);
|
|
|
|
updateWindowSvgMatrix (w);
|
|
}
|
|
}
|
|
|
|
texture = &sw->context->texture[1].texture;
|
|
matrix = &sw->context->texture[1].matrix;
|
|
|
|
w->vCount = w->indexCount = 0;
|
|
|
|
saveFilter = w->screen->filter[SCREEN_TRANS_FILTER];
|
|
w->screen->filter[SCREEN_TRANS_FILTER] =
|
|
COMP_TEXTURE_FILTER_GOOD;
|
|
|
|
(*w->screen->addWindowGeometry) (w, matrix, 1, &r, region);
|
|
(*w->screen->drawWindowTexture) (w, texture, attrib, mask);
|
|
|
|
w->screen->filter[SCREEN_TRANS_FILTER] = saveFilter;
|
|
}
|
|
else if (sw->context->texture[1].width)
|
|
{
|
|
finiSvgTexture (w->screen, &sw->context->texture[1]);
|
|
initSvgTexture (w, sw->source, &sw->context->texture[1], 0, 0);
|
|
|
|
memset (&sw->context->rect, 0, sizeof (BoxRec));
|
|
|
|
sw->context->width = 0;
|
|
sw->context->height = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
static void
|
|
updateWindowSvgContext (CompWindow *w,
|
|
SvgSource *source)
|
|
{
|
|
int x1, y1, x2, y2;
|
|
|
|
SVG_WINDOW (w);
|
|
|
|
if (sw->context)
|
|
{
|
|
finiSvgTexture (w->screen, &sw->context->texture[0]);
|
|
finiSvgTexture (w->screen, &sw->context->texture[1]);
|
|
}
|
|
else
|
|
{
|
|
sw->context = malloc (sizeof (SvgContext));
|
|
if (!sw->context)
|
|
return;
|
|
}
|
|
|
|
memset (&sw->context->rect, 0, sizeof (BoxRec));
|
|
|
|
sw->context->width = 0;
|
|
sw->context->height = 0;
|
|
|
|
initSvgTexture (w, source, &sw->context->texture[1], 0, 0);
|
|
|
|
sw->context->source = source;
|
|
|
|
sw->context->box.rects = &sw->context->box.extents;
|
|
sw->context->box.numRects = 1;
|
|
|
|
decor_apply_gravity (source->p1.gravity,
|
|
source->p1.x, source->p1.y,
|
|
w->width, w->height,
|
|
&x1, &y1);
|
|
|
|
decor_apply_gravity (source->p2.gravity,
|
|
source->p2.x, source->p2.y,
|
|
w->width, w->height,
|
|
&x2, &y2);
|
|
|
|
x1 = MAX (x1, 0);
|
|
y1 = MAX (y1, 0);
|
|
x2 = MIN (x2, w->width);
|
|
y2 = MIN (y2, w->height);
|
|
|
|
if (!initSvgTexture (w, source, &sw->context->texture[0],
|
|
w->width, w->height))
|
|
{
|
|
free (sw->context);
|
|
sw->context = NULL;
|
|
}
|
|
else
|
|
{
|
|
renderSvg (w->screen, source, &sw->context->texture[0],
|
|
0.0f, 0.0f, 1.0f, 1.0f, w->width, w->height);
|
|
|
|
initSvgTexture (w, source, &sw->context->texture[1], 0, 0);
|
|
|
|
sw->context->box.extents.x1 = x1;
|
|
sw->context->box.extents.y1 = y1;
|
|
sw->context->box.extents.x2 = x2;
|
|
sw->context->box.extents.y2 = y2;
|
|
|
|
sw->context->box.extents.x1 += w->attrib.x;
|
|
sw->context->box.extents.y1 += w->attrib.y;
|
|
sw->context->box.extents.x2 += w->attrib.x;
|
|
sw->context->box.extents.y2 += w->attrib.y;
|
|
|
|
updateWindowSvgMatrix (w);
|
|
}
|
|
}
|
|
|
|
static Bool
|
|
svgSet (CompDisplay *d,
|
|
CompAction *action,
|
|
CompActionState state,
|
|
CompOption *option,
|
|
int nOption)
|
|
{
|
|
CompWindow *w;
|
|
Window xid;
|
|
|
|
xid = getIntOptionNamed (option, nOption, "window", 0);
|
|
|
|
w = findWindowAtDisplay (d, xid);
|
|
if (w)
|
|
{
|
|
decor_point_t p[2];
|
|
char *data;
|
|
RsvgHandle *svg = NULL;
|
|
GError *error = NULL;
|
|
|
|
SVG_WINDOW (w);
|
|
|
|
memset (p, 0, sizeof (p));
|
|
|
|
p[0].gravity = getIntOptionNamed (option, nOption, "gravity0",
|
|
GRAVITY_NORTH | GRAVITY_WEST);
|
|
|
|
p[0].x = getIntOptionNamed (option, nOption, "x0", 0);
|
|
p[0].y = getIntOptionNamed (option, nOption, "y0", 0);
|
|
|
|
p[1].gravity = getIntOptionNamed (option, nOption, "gravity1",
|
|
GRAVITY_SOUTH | GRAVITY_EAST);
|
|
|
|
p[1].x = getIntOptionNamed (option, nOption, "x1", 0);
|
|
p[1].y = getIntOptionNamed (option, nOption, "y1", 0);
|
|
|
|
data = getStringOptionNamed (option, nOption, "data", 0);
|
|
if (data)
|
|
svg = rsvg_handle_new_from_data ((guint8 *) data, strlen (data),
|
|
&error);
|
|
|
|
if (sw->source)
|
|
{
|
|
rsvg_handle_free (sw->source->svg);
|
|
sw->source->svg = svg;
|
|
}
|
|
else
|
|
{
|
|
sw->source = malloc (sizeof (SvgSource));
|
|
if (sw->source)
|
|
sw->source->svg = svg;
|
|
}
|
|
|
|
if (sw->source && sw->source->svg)
|
|
{
|
|
sw->source->p1 = p[0];
|
|
sw->source->p2 = p[1];
|
|
|
|
sw->source->svg = svg;
|
|
|
|
rsvg_handle_get_dimensions (svg, &sw->source->dimension);
|
|
|
|
updateWindowSvgContext (w, sw->source);
|
|
}
|
|
else
|
|
{
|
|
if (svg)
|
|
rsvg_handle_free (svg);
|
|
|
|
if (sw->source)
|
|
{
|
|
free (sw->source);
|
|
sw->source = NULL;
|
|
}
|
|
|
|
if (sw->context)
|
|
{
|
|
finiSvgTexture (w->screen, &sw->context->texture[0]);
|
|
free (sw->context);
|
|
sw->context = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static void
|
|
svgWindowMoveNotify (CompWindow *w,
|
|
int dx,
|
|
int dy,
|
|
Bool immediate)
|
|
{
|
|
SVG_SCREEN (w->screen);
|
|
SVG_WINDOW (w);
|
|
|
|
if (sw->context)
|
|
{
|
|
sw->context->box.extents.x1 += dx;
|
|
sw->context->box.extents.y1 += dy;
|
|
sw->context->box.extents.x2 += dx;
|
|
sw->context->box.extents.y2 += dy;
|
|
|
|
updateWindowSvgMatrix (w);
|
|
}
|
|
|
|
UNWRAP (ss, w->screen, windowMoveNotify);
|
|
(*w->screen->windowMoveNotify) (w, dx, dy, immediate);
|
|
WRAP (ss, w->screen, windowMoveNotify, svgWindowMoveNotify);
|
|
}
|
|
|
|
static void
|
|
svgWindowResizeNotify (CompWindow *w,
|
|
int dx,
|
|
int dy,
|
|
int dwidth,
|
|
int dheight)
|
|
{
|
|
SVG_SCREEN (w->screen);
|
|
SVG_WINDOW (w);
|
|
|
|
if (sw->source)
|
|
updateWindowSvgContext (w, sw->source);
|
|
|
|
UNWRAP (ss, w->screen, windowResizeNotify);
|
|
(*w->screen->windowResizeNotify) (w, dx, dy, dwidth, dheight);
|
|
WRAP (ss, w->screen, windowResizeNotify, svgWindowResizeNotify);
|
|
}
|
|
|
|
static void
|
|
svgHandleCompizEvent (CompDisplay *d,
|
|
const char *pluginName,
|
|
const char *eventName,
|
|
CompOption *option,
|
|
int nOption)
|
|
{
|
|
SVG_DISPLAY (d);
|
|
|
|
UNWRAP (sd, d, handleCompizEvent);
|
|
(*d->handleCompizEvent) (d, pluginName, eventName, option, nOption);
|
|
WRAP (sd, d, handleCompizEvent, svgHandleCompizEvent);
|
|
|
|
if (strcmp (pluginName, "zoom") == 0)
|
|
{
|
|
CompScreen *s;
|
|
int output = getIntOptionNamed (option, nOption, "output", 0);
|
|
|
|
s = findScreenAtDisplay (d, getIntOptionNamed (option, nOption,
|
|
"root", 0));
|
|
if (s && output == 0)
|
|
{
|
|
SVG_SCREEN (s);
|
|
|
|
if (strcmp (eventName, "in") == 0)
|
|
{
|
|
ss->zoom.x1 = getIntOptionNamed (option, nOption, "x1", 0);
|
|
ss->zoom.y1 = getIntOptionNamed (option, nOption, "y1", 0);
|
|
ss->zoom.x2 = getIntOptionNamed (option, nOption, "x2", 0);
|
|
ss->zoom.y2 = getIntOptionNamed (option, nOption, "y2", 0);
|
|
}
|
|
else if (strcmp (eventName, "out") == 0)
|
|
{
|
|
memset (&ss->zoom, 0, sizeof (BoxRec));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static Bool
|
|
readSvgFileToImage (char *file,
|
|
int *width,
|
|
int *height,
|
|
void **data)
|
|
{
|
|
cairo_surface_t *surface;
|
|
FILE *fp;
|
|
GError *error = NULL;
|
|
RsvgHandle *svgHandle;
|
|
RsvgDimensionData svgDimension;
|
|
|
|
fp = fopen (file, "r");
|
|
if (!fp)
|
|
return FALSE;
|
|
|
|
fclose (fp);
|
|
|
|
svgHandle = rsvg_handle_new_from_file (file, &error);
|
|
if (!svgHandle)
|
|
return FALSE;
|
|
|
|
rsvg_handle_get_dimensions (svgHandle, &svgDimension);
|
|
|
|
*width = svgDimension.width;
|
|
*height = svgDimension.height;
|
|
|
|
*data = malloc (svgDimension.width * svgDimension.height * 4);
|
|
if (!*data)
|
|
{
|
|
rsvg_handle_free (svgHandle);
|
|
return FALSE;
|
|
}
|
|
|
|
surface = cairo_image_surface_create_for_data (*data,
|
|
CAIRO_FORMAT_ARGB32,
|
|
svgDimension.width,
|
|
svgDimension.height,
|
|
svgDimension.width * 4);
|
|
if (surface)
|
|
{
|
|
cairo_t *cr;
|
|
|
|
cr = cairo_create (surface);
|
|
|
|
cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
|
|
cairo_paint (cr);
|
|
cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
|
|
|
|
rsvg_handle_render_cairo (svgHandle, cr);
|
|
|
|
cairo_destroy (cr);
|
|
cairo_surface_destroy (surface);
|
|
}
|
|
|
|
rsvg_handle_free (svgHandle);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static char *
|
|
svgExtension (const char *name)
|
|
{
|
|
|
|
if (strlen (name) > 4)
|
|
{
|
|
if (strcasecmp (name + (strlen (name) - 4), ".svg") == 0)
|
|
return "";
|
|
}
|
|
|
|
return ".svg";
|
|
}
|
|
|
|
static Bool
|
|
svgFileToImage (CompDisplay *d,
|
|
const char *path,
|
|
const char *name,
|
|
int *width,
|
|
int *height,
|
|
int *stride,
|
|
void **data)
|
|
{
|
|
Bool status = FALSE;
|
|
char *extension = svgExtension (name);
|
|
char *file;
|
|
int len;
|
|
|
|
SVG_DISPLAY (d);
|
|
|
|
len = (path ? strlen (path) : 0) + strlen (name) + strlen (extension) + 2;
|
|
|
|
file = malloc (len);
|
|
if (file)
|
|
{
|
|
if (path)
|
|
sprintf (file, "%s/%s%s", path, name, extension);
|
|
else
|
|
sprintf (file, "%s%s", name, extension);
|
|
|
|
status = readSvgFileToImage (file, width, height, data);
|
|
|
|
free (file);
|
|
|
|
if (status)
|
|
{
|
|
*stride = *width * 4;
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
UNWRAP (sd, d, fileToImage);
|
|
status = (*d->fileToImage) (d, path, name, width, height, stride, data);
|
|
WRAP (sd, d, fileToImage, svgFileToImage);
|
|
|
|
return status;
|
|
}
|
|
|
|
static CompOption *
|
|
svgGetDisplayOptions (CompPlugin *plugin,
|
|
CompDisplay *display,
|
|
int *count)
|
|
{
|
|
SVG_DISPLAY (display);
|
|
|
|
*count = NUM_OPTIONS (sd);
|
|
return sd->opt;
|
|
}
|
|
|
|
static Bool
|
|
svgSetDisplayOption (CompPlugin *plugin,
|
|
CompDisplay *display,
|
|
const char *name,
|
|
CompOptionValue *value)
|
|
{
|
|
CompOption *o;
|
|
|
|
SVG_DISPLAY (display);
|
|
|
|
o = compFindOption (sd->opt, NUM_OPTIONS (sd), name, NULL);
|
|
if (!o)
|
|
return FALSE;
|
|
|
|
return compSetDisplayOption (display, o, value);
|
|
}
|
|
|
|
static const CompMetadataOptionInfo svgDisplayOptionInfo[] = {
|
|
{ "set", "action", 0, svgSet, NULL }
|
|
};
|
|
|
|
static Bool
|
|
svgInitDisplay (CompPlugin *p,
|
|
CompDisplay *d)
|
|
{
|
|
SvgDisplay *sd;
|
|
CompScreen *s;
|
|
|
|
if (!checkPluginABI ("core", CORE_ABIVERSION))
|
|
return FALSE;
|
|
|
|
sd = malloc (sizeof (SvgDisplay));
|
|
if (!sd)
|
|
return FALSE;
|
|
|
|
if (!compInitDisplayOptionsFromMetadata (d,
|
|
&svgMetadata,
|
|
svgDisplayOptionInfo,
|
|
sd->opt,
|
|
SVG_DISPLAY_OPTION_NUM))
|
|
{
|
|
free (sd);
|
|
return FALSE;
|
|
}
|
|
|
|
sd->screenPrivateIndex = allocateScreenPrivateIndex (d);
|
|
if (sd->screenPrivateIndex < 0)
|
|
{
|
|
compFiniDisplayOptions (d, sd->opt, SVG_DISPLAY_OPTION_NUM);
|
|
free (sd);
|
|
return FALSE;
|
|
}
|
|
|
|
WRAP (sd, d, handleCompizEvent, svgHandleCompizEvent);
|
|
WRAP (sd, d, fileToImage, svgFileToImage);
|
|
|
|
d->base.privates[displayPrivateIndex].ptr = sd;
|
|
|
|
for (s = d->screens; s; s = s->next)
|
|
updateDefaultIcon (s);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
svgFiniDisplay (CompPlugin *p,
|
|
CompDisplay *d)
|
|
{
|
|
CompScreen *s;
|
|
|
|
SVG_DISPLAY (d);
|
|
|
|
UNWRAP (sd, d, handleCompizEvent);
|
|
UNWRAP (sd, d, fileToImage);
|
|
|
|
for (s = d->screens; s; s = s->next)
|
|
updateDefaultIcon (s);
|
|
|
|
freeScreenPrivateIndex (d, sd->screenPrivateIndex);
|
|
|
|
compFiniDisplayOptions (d, sd->opt, SVG_DISPLAY_OPTION_NUM);
|
|
|
|
free (sd);
|
|
}
|
|
|
|
static Bool
|
|
svgInitScreen (CompPlugin *p,
|
|
CompScreen *s)
|
|
{
|
|
SvgScreen *ss;
|
|
|
|
SVG_DISPLAY (s->display);
|
|
|
|
ss = malloc (sizeof (SvgScreen));
|
|
if (!ss)
|
|
return FALSE;
|
|
|
|
ss->windowPrivateIndex = allocateWindowPrivateIndex (s);
|
|
if (ss->windowPrivateIndex < 0)
|
|
{
|
|
free (ss);
|
|
return FALSE;
|
|
}
|
|
|
|
memset (&ss->zoom, 0, sizeof (BoxRec));
|
|
|
|
WRAP (ss, s, drawWindow, svgDrawWindow);
|
|
WRAP (ss, s, windowMoveNotify, svgWindowMoveNotify);
|
|
WRAP (ss, s, windowResizeNotify, svgWindowResizeNotify);
|
|
|
|
s->base.privates[sd->screenPrivateIndex].ptr = ss;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
svgFiniScreen (CompPlugin *p,
|
|
CompScreen *s)
|
|
{
|
|
SVG_SCREEN (s);
|
|
|
|
freeWindowPrivateIndex (s, ss->windowPrivateIndex);
|
|
|
|
UNWRAP (ss, s, drawWindow);
|
|
UNWRAP (ss, s, windowMoveNotify);
|
|
UNWRAP (ss, s, windowResizeNotify);
|
|
|
|
free (ss);
|
|
}
|
|
|
|
static Bool
|
|
svgInitWindow (CompPlugin *p,
|
|
CompWindow *w)
|
|
{
|
|
SvgWindow *sw;
|
|
|
|
SVG_SCREEN (w->screen);
|
|
|
|
sw = malloc (sizeof (SvgWindow));
|
|
if (!sw)
|
|
return FALSE;
|
|
|
|
sw->source = NULL;
|
|
sw->context = NULL;
|
|
|
|
w->base.privates[ss->windowPrivateIndex].ptr = sw;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
svgFiniWindow (CompPlugin *p,
|
|
CompWindow *w)
|
|
{
|
|
SVG_WINDOW (w);
|
|
|
|
if (sw->source)
|
|
{
|
|
rsvg_handle_free (sw->source->svg);
|
|
free (sw->source);
|
|
}
|
|
|
|
if (sw->context)
|
|
{
|
|
finiSvgTexture (w->screen, &sw->context->texture[0]);
|
|
free (sw->context);
|
|
}
|
|
|
|
free (sw);
|
|
}
|
|
|
|
static CompBool
|
|
svgInitObject (CompPlugin *p,
|
|
CompObject *o)
|
|
{
|
|
static InitPluginObjectProc dispTab[] = {
|
|
(InitPluginObjectProc) 0, /* InitCore */
|
|
(InitPluginObjectProc) svgInitDisplay,
|
|
(InitPluginObjectProc) svgInitScreen,
|
|
(InitPluginObjectProc) svgInitWindow
|
|
};
|
|
|
|
RETURN_DISPATCH (o, dispTab, ARRAY_SIZE (dispTab), TRUE, (p, o));
|
|
}
|
|
|
|
static void
|
|
svgFiniObject (CompPlugin *p,
|
|
CompObject *o)
|
|
{
|
|
static FiniPluginObjectProc dispTab[] = {
|
|
(FiniPluginObjectProc) 0, /* FiniCore */
|
|
(FiniPluginObjectProc) svgFiniDisplay,
|
|
(FiniPluginObjectProc) svgFiniScreen,
|
|
(FiniPluginObjectProc) svgFiniWindow
|
|
};
|
|
|
|
DISPATCH (o, dispTab, ARRAY_SIZE (dispTab), (p, o));
|
|
}
|
|
|
|
static CompOption *
|
|
svgGetObjectOptions (CompPlugin *plugin,
|
|
CompObject *object,
|
|
int *count)
|
|
{
|
|
static GetPluginObjectOptionsProc dispTab[] = {
|
|
(GetPluginObjectOptionsProc) 0, /* GetCoreOptions */
|
|
(GetPluginObjectOptionsProc) svgGetDisplayOptions
|
|
};
|
|
|
|
*count = 0;
|
|
RETURN_DISPATCH (object, dispTab, ARRAY_SIZE (dispTab),
|
|
(void *) count, (plugin, object, count));
|
|
}
|
|
|
|
static CompBool
|
|
svgSetObjectOption (CompPlugin *plugin,
|
|
CompObject *object,
|
|
const char *name,
|
|
CompOptionValue *value)
|
|
{
|
|
static SetPluginObjectOptionProc dispTab[] = {
|
|
(SetPluginObjectOptionProc) 0, /* SetCoreOption */
|
|
(SetPluginObjectOptionProc) svgSetDisplayOption
|
|
};
|
|
|
|
RETURN_DISPATCH (object, dispTab, ARRAY_SIZE (dispTab), FALSE,
|
|
(plugin, object, name, value));
|
|
}
|
|
|
|
static Bool
|
|
svgInit (CompPlugin *p)
|
|
{
|
|
if (!compInitPluginMetadataFromInfo (&svgMetadata,
|
|
p->vTable->name,
|
|
svgDisplayOptionInfo,
|
|
SVG_DISPLAY_OPTION_NUM,
|
|
0, 0))
|
|
return FALSE;
|
|
|
|
displayPrivateIndex = allocateDisplayPrivateIndex ();
|
|
if (displayPrivateIndex < 0)
|
|
{
|
|
compFiniMetadata (&svgMetadata);
|
|
return FALSE;
|
|
}
|
|
|
|
rsvg_init ();
|
|
|
|
compAddMetadataFromFile (&svgMetadata, p->vTable->name);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
svgFini (CompPlugin *p)
|
|
{
|
|
freeDisplayPrivateIndex (displayPrivateIndex);
|
|
compFiniMetadata (&svgMetadata);
|
|
|
|
rsvg_term ();
|
|
}
|
|
|
|
static CompMetadata *
|
|
svgGetMetadata (CompPlugin *plugin)
|
|
{
|
|
return &svgMetadata;
|
|
}
|
|
|
|
CompPluginVTable svgVTable = {
|
|
"svg",
|
|
svgGetMetadata,
|
|
svgInit,
|
|
svgFini,
|
|
svgInitObject,
|
|
svgFiniObject,
|
|
svgGetObjectOptions,
|
|
svgSetObjectOption
|
|
};
|
|
|
|
CompPluginVTable *
|
|
getCompPluginInfo20070830 (void)
|
|
{
|
|
return &svgVTable;
|
|
}
|