/*
* Copyright © 2006 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.
*
* Authors: David Reveman <davidr@novell.com>
* James Eady <jmeady@gmail.com> (Lines, arrows, text)
*/
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <glib.h>
#include <cairo-xlib-xrender.h>
#include <librsvg/rsvg.h>
#include <librsvg/rsvg-cairo.h>
#include <beryl.h>
#define ANNO_INITIATE_BUTTON_DEFAULT Button1
#define ANNO_INITIATE_BUTTON_MODIFIERS_DEFAULT (CompSuperMask | CompAltMask)
#define ANNO_ERASE_BUTTON_DEFAULT Button3
#define ANNO_ERASE_BUTTON_MODIFIERS_DEFAULT (CompSuperMask | CompAltMask)
#define ANNO_CLEAR_KEY_DEFAULT "k"
#define ANNO_CLEAR_KEY_MODIFIERS_DEFAULT (CompSuperMask | CompAltMask)
// <Drawing Utensils>
#define ANNO_SWITCH_PAINTBRUSH_KEY_DEFAULT "p"
#define ANNO_SWITCH_PAINTBRUSH_KEY_MODIFIERS_DEFAULT (CompSuperMask | CompAltMask)
#define ANNO_SWITCH_LINE_KEY_DEFAULT "l"
#define ANNO_SWITCH_LINE_KEY_MODIFIERS_DEFAULT (CompSuperMask | CompAltMask)
#define ANNO_SWITCH_ARROW_KEY_DEFAULT "a"
#define ANNO_SWITCH_ARROW_KEY_MODIFIERS_DEFAULT (CompSuperMask | CompAltMask)
#define ANNO_PUT_TEXT_KEY_DEFAULT "t"
#define ANNO_PUT_TEXT_KEY_MODIFIERS_DEFAULT (CompSuperMask | CompAltMask)
// </Drawing Utensils>
#define ANNO_TOOL_PAINTBRUSH 0
#define ANNO_TOOL_LINE 1
#define ANNO_TOOL_ARROW 2
#define ANNO_FILL_COLOR_RED_DEFAULT 0xffff
#define ANNO_FILL_COLOR_GREEN_DEFAULT 0x0000
#define ANNO_FILL_COLOR_BLUE_DEFAULT 0x0000
#define ANNO_STROKE_COLOR_RED_DEFAULT 0x0000
#define ANNO_STROKE_COLOR_GREEN_DEFAULT 0xffff
#define ANNO_STROKE_COLOR_BLUE_DEFAULT 0x0000
#define ANNO_LINE_WIDTH_MIN 0.1f
#define ANNO_LINE_WIDTH_MAX 100.0f
#define ANNO_LINE_WIDTH_DEFAULT 3.0f
#define ANNO_LINE_WIDTH_PRECISION 0.1f
#define ANNO_STROKE_WIDTH_MIN 0.1f
#define ANNO_STROKE_WIDTH_MAX 20.0f
#define ANNO_STROKE_WIDTH_DEFAULT 1.0f
#define ANNO_STROKE_WIDTH_PRECISION 0.1f
static int displayPrivateIndex;
static int annoLastPointerX = 0;
static int annoLastPointerY = 0;
#define ANNO_DISPLAY_OPTION_INITIATE 0
#define ANNO_DISPLAY_OPTION_DRAW 1
#define ANNO_DISPLAY_OPTION_TRANSFORM 2
#define ANNO_DISPLAY_OPTION_SWITCH_CONTEXT 3
#define ANNO_DISPLAY_OPTION_ERASE 4
#define ANNO_DISPLAY_OPTION_CLEAR 5
#define ANNO_DISPLAY_OPTION_FILL_COLOR 6
#define ANNO_DISPLAY_OPTION_STROKE_COLOR 7
#define ANNO_DISPLAY_OPTION_LINE_WIDTH 8
#define ANNO_DISPLAY_OPTION_STROKE_WIDTH 9
#define ANNO_DISPLAY_OPTION_SVG_FILE 10
#define ANNO_DISPLAY_OPTION_TOOL 11
#define ANNO_DISPLAY_OPTION_PRELOAD 12
#define ANNO_DISPLAY_OPTION_USE_PAINTBRUSH 13
#define ANNO_DISPLAY_OPTION_USE_LINE 14
#define ANNO_DISPLAY_OPTION_USE_ARROW 15
#define ANNO_DISPLAY_OPTION_TEXT_STRINGS 16
#define ANNO_DISPLAY_OPTION_PUT_TEXT 17
#define ANNO_DISPLAY_OPTION_NUM 18
#define ANNO_NUMBER_CONTEXTS 12
typedef struct _AnnoDisplay
{
int screenPrivateIndex;
HandleEventProc handleEvent;
CompOption opt[ANNO_DISPLAY_OPTION_NUM];
} AnnoDisplay;
typedef struct _AnnoScreen
{
PaintScreenProc paintScreen;
int grabIndex;
Pixmap pixmap[ANNO_NUMBER_CONTEXTS];
CompTexture texture[ANNO_NUMBER_CONTEXTS];
cairo_surface_t *surface[ANNO_NUMBER_CONTEXTS];
cairo_t *cairo[ANNO_NUMBER_CONTEXTS];
Bool content[ANNO_NUMBER_CONTEXTS];
int currentContext;
RsvgHandle **svgHandle;
int nSvgHandle;
Bool eraseMode;
Bool isDrawing;
int tool;
int firstX;
int firstY;
int stringIndex;
} AnnoScreen;
#define GET_ANNO_DISPLAY(d) \
((AnnoDisplay *) (d)->privates[displayPrivateIndex].ptr)
#define ANNO_DISPLAY(d) \
AnnoDisplay *ad = GET_ANNO_DISPLAY (d)
#define GET_ANNO_SCREEN(s, ad) \
((AnnoScreen *) (s)->privates[(ad)->screenPrivateIndex].ptr)
#define ANNO_SCREEN(s) \
AnnoScreen *as = GET_ANNO_SCREEN (s, GET_ANNO_DISPLAY (s->display))
#define NUM_OPTIONS(s) (sizeof ((s)->opt) / sizeof (CompOption))
#define NUM_TOOLS (sizeof (tools) / sizeof (tools[0]))
static void annoCairoClear(CompScreen * s, cairo_t * cr, int context)
{
ANNO_SCREEN(s);
cairo_save(cr);
cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);
cairo_paint(cr);
cairo_restore(cr);
as->content[context] = FALSE;
}
static cairo_t *annoCairoContext(CompScreen * s, int contextID)
{
ANNO_SCREEN(s);
if (!as->cairo || !as->cairo[contextID])
{
XRenderPictFormat *format;
Screen *screen;
int w, h;
screen = ScreenOfDisplay(s->display->display, s->screenNum);
w = s->width;
h = s->height;
format = XRenderFindStandardFormat(s->display->display,
PictStandardARGB32);
as->pixmap[contextID] =
XCreatePixmap(s->display->display, s->root, w, h, 32);
if (!bindPixmapToTexture(s, &as->texture[contextID],
as->pixmap[contextID], w, h, 32))
{
fprintf(stderr,
"%s: Couldn't bind annotate pixmap 0x%x to "
"texture\n", getProgramName(),
(int)as->pixmap[contextID]);
XFreePixmap(s->display->display, as->pixmap[contextID]);
return NULL;
}
as->surface[contextID] =
cairo_xlib_surface_create_with_xrender_format(s->display->
display,
as->
pixmap
[contextID],
screen, format,
w, h);
as->cairo[contextID] = cairo_create(as->surface[contextID]);
annoCairoClear(s, as->cairo[contextID], contextID);
}
return as->cairo[contextID];
}
static Bool
annoCanvasSwitchContext(CompDisplay * d,
CompAction * action,
CompActionState state,
CompOption * option, int nOption)
{
Window xid;
int contextNumber;
CompScreen *s;
xid = getIntOptionNamed(option, nOption, "root", 0);
contextNumber = getIntOptionNamed(option, nOption, "context", 0);
s = findScreenAtDisplay(d, xid);
if (s)
{
ANNO_SCREEN(s);
as->currentContext = contextNumber;
damageScreen(s);
return TRUE;
}
return FALSE;
}
static void annoSetSourceColor(cairo_t * cr, unsigned short *color)
{
cairo_set_source_rgba(cr,
(double)color[0] / 0xffff,
(double)color[1] / 0xffff,
(double)color[2] / 0xffff,
(double)color[3] / 0xffff);
}
static void
annoDrawCircle(CompScreen * s,
int contextID,
double xc,
double yc,
double radius,
unsigned short *fillColor,
unsigned short *strokeColor, double strokeWidth)
{
REGION reg;
cairo_t *cr;
ANNO_SCREEN(s);
cr = annoCairoContext(s, contextID);
if (cr)
{
double ex1, ey1, ex2, ey2;
annoSetSourceColor(cr, fillColor);
cairo_arc(cr, xc, yc, radius, 0, 2 * M_PI);
cairo_fill_preserve(cr);
cairo_set_line_width(cr, strokeWidth);
cairo_stroke_extents(cr, &ex1, &ey1, &ex2, &ey2);
annoSetSourceColor(cr, strokeColor);
cairo_stroke(cr);
reg.rects = ®.extents;
reg.numRects = 1;
reg.extents.x1 = ex1;
reg.extents.y1 = ey1;
reg.extents.x2 = ex2;
reg.extents.y2 = ey2;
as->content[contextID] = TRUE;
damageScreenRegion(s, ®);
}
}
static void
annoDrawRectangle(CompScreen * s,
int contextID,
double x,
double y,
double w,
double h,
unsigned short *fillColor,
unsigned short *strokeColor,
double strokeWidth, double angle)
{
REGION reg;
cairo_t *cr;
ANNO_SCREEN(s);
cr = annoCairoContext(s, contextID);
if (cr)
{
double ex1, ey1, ex2, ey2;
if (angle != 0)
{
cairo_save(cr);
cairo_translate(cr, x + (w / 2), y + (h / 2));
cairo_rotate(cr, angle * M_PI / 180);
cairo_translate(cr, -x - (w / 2), -y - (h / 2));
}
annoSetSourceColor(cr, fillColor);
cairo_rectangle(cr, x, y, w, h);
cairo_set_line_width(cr, strokeWidth);
cairo_fill_preserve(cr);
cairo_stroke_extents(cr, &ex1, &ey1, &ex2, &ey2);
annoSetSourceColor(cr, strokeColor);
cairo_stroke(cr);
if (angle != 0)
cairo_restore(cr);
reg.rects = ®.extents;
reg.numRects = 1;
reg.extents.x1 = ex1;
reg.extents.y1 = ey1;
reg.extents.x2 = ex2;
reg.extents.y2 = ey2;
as->content[contextID] = TRUE;
if (angle == 0)
damageScreenRegion(s, ®);
else
damageScreen(s);
}
}
typedef struct _AnnoSvgSizeCallbackData
{
char *filename;
CompDisplay *display;
int handleID;
} AnnoSvgSizeCallbackData;
static void
annoRsvgSizeCallback(gint * width, gint * height, gpointer user_data)
{
/*
fprintf(stderr, "load callback\n");
char *filename;
CompDisplay *display;
int nOption = 4;
int handleID;
CompOption option[4];
AnnoSvgSizeCallbackData *data;
data = (AnnoSvgSizeCallbackData *) user_data;
display = (CompDisplay *) data->display;
filename = (char *) data->filename;
handleID = (int) data->handleID;
option[0].name = "width";
option[0].type = CompOptionTypeInt;
option[0].value.i = *width;
option[1].name = "height";
option[1].type = CompOptionTypeInt;
option[1].value.i = *height;
option[2].name = "filename";
option[2].type = CompOptionTypeString;
option[2].value.s = filename;
option[3].name = "handle_id";
option[3].type = CompOptionTypeInt;
option[3].value.i = handleID;
fprintf(stderr, "load callback handle = %d\n", handleID);
(*display->handleBerylEvent) (display,
"annotate",
"svgLoaded",
option,
nOption);*/
}
static void
annoDrawSvg(CompScreen * s,
int contextID,
int handleID,
double x, double y, double angle, double scaleX, double scaleY)
{
RsvgHandle *svgh;
cairo_t *cr;
ANNO_SCREEN(s);
cr = annoCairoContext(s, contextID);
if (cr && handleID)
{
svgh = as->svgHandle[handleID];
cairo_save(cr);
cairo_translate(cr, x, y);
cairo_scale(cr, scaleX, scaleY);
rsvg_handle_render_cairo(svgh, cr);
cairo_restore(cr);
as->content[contextID] = TRUE;
}
damageScreen(s);
}
static Bool
annoLoadSvg(CompDisplay * d,
CompAction * action,
CompActionState state, CompOption * option, int nOption)
{
CompScreen *s;
Window xid;
char *filename;
xid = getIntOptionNamed(option, nOption, "root", 0);
s = findScreenAtDisplay(d, xid);
if (s)
{
GError *svgError = NULL;
RsvgHandle *svgh;
AnnoSvgSizeCallbackData callbackData;
ANNO_SCREEN(s);
filename = getStringOptionNamed(option, nOption, "filename", "");
as->nSvgHandle++;
callbackData.filename = filename;
callbackData.display = s->display;
callbackData.handleID = as->nSvgHandle;
svgh = rsvg_handle_new_from_file(filename, &svgError);
rsvg_handle_set_size_callback(svgh, annoRsvgSizeCallback,
&callbackData, NULL);
if (svgError)
{
fprintf(stderr, "%s: Error loading svg %s\n", getProgramName(),
filename);
as->nSvgHandle--;
rsvg_handle_free(svgh);
return FALSE;
}
as->svgHandle =
realloc(as->svgHandle, sizeof(RsvgHandle) * as->nSvgHandle);
as->svgHandle[as->nSvgHandle] = svgh;
option[0].name = "filename";
option[0].type = CompOptionTypeString;
option[0].value.s = filename;
option[1].name = "handle_id";
option[1].type = CompOptionTypeInt;
option[1].value.i = as->nSvgHandle;
(*d->handleBerylEvent) (d, "annotate", "svgLoaded", option, nOption);
return TRUE;
}
return FALSE;
}
static void
annoDrawLine(CompScreen * s,
int contextID,
double x1, double y1,
double x2, double y2, double width, unsigned short *color)
{
REGION reg;
cairo_t *cr;
ANNO_SCREEN(s);
cr = annoCairoContext(s, contextID);
if (cr)
{
double ex1, ey1, ex2, ey2;
cairo_set_line_width(cr, width);
cairo_move_to(cr, x1, y1);
cairo_line_to(cr, x2, y2);
cairo_stroke_extents(cr, &ex1, &ey1, &ex2, &ey2);
annoSetSourceColor(cr, color);
if (as->eraseMode)
{
cairo_set_operator(cr,CAIRO_OPERATOR_SOURCE);
cairo_pattern_t * cp = cairo_pattern_create_rgba(1.0f,1.0f,1.0f,0.0f);
cairo_set_source(cr,cp);
}
cairo_stroke(cr);
reg.rects = ®.extents;
reg.numRects = 1;
reg.extents.x1 = ex1;
reg.extents.y1 = ey1;
reg.extents.x2 = ex2;
reg.extents.y2 = ey2;
as->content[contextID] = TRUE;
//damageScreenRegion (s, ®);
damageScreen(s);
}
}
static void
annoDrawArrow(CompScreen * s,
int contextID,
double x1, double y1,
double x2, double y2, double width, unsigned short *color)
{
double startX = x1, endX = x2, startY = y1, endY = y2;
float shortLength = width * width;
float dx = startX - endX;
float dy = startY - endY;
float length = sqrt(dx * dx + dy * dy);
if (dx < 0)
dx *= -1;
if (dy < 0)
dy *= -1;
float shortX = (dx / length) * shortLength;
float shortY = (dy / length) * shortLength;
int triangleX[3];
int triangleY[3];
if (endX > startX && endY < startY)
{
endX -= shortX;
endY += shortY;
triangleX[0] = endX + shortY;
triangleY[0] = endY + shortX;
triangleX[1] = endX - shortY;
triangleY[1] = endY - shortX;
}
else if (endX < startX && endY > startY)
{
endX += shortX;
endY -= shortY;
triangleX[0] = endX + shortY;
triangleY[0] = endY + shortX;
triangleX[1] = endX - shortY;
triangleY[1] = endY - shortX;
}
else if (endX < startX && endY < startY)
{
endX += shortX;
endY += shortY;
triangleX[0] = endX + shortY;
triangleY[0] = endY - shortX;
triangleX[1] = endX - shortY;
triangleY[1] = endY + shortX;
}
else // if( endX > startX && endY > startY )
{
endX -= shortX;
endY -= shortY;
triangleX[0] = endX - shortY;
triangleY[0] = endY + shortX;
triangleX[1] = endX + shortY;
triangleY[1] = endY - shortX;
}
triangleX[2] = x2;
triangleY[2] = y2;
// Draw the arrow handle...
annoDrawLine(s, contextID, startX, startY, endX, endY, width, color);
// Draw the arrow
annoDrawLine(s, contextID,
triangleX[0], triangleY[0],
triangleX[1], triangleY[1], width, color);
annoDrawLine(s, contextID,
triangleX[0], triangleY[0],
triangleX[2], triangleY[2], width, color);
annoDrawLine(s, contextID,
triangleX[2], triangleY[2],
triangleX[1], triangleY[1], width, color);
}
static void
annoDrawText(CompScreen * s,
int contextID,
double x,
double y,
char *text,
char *fontFamily,
double fontSize,
int fontSlant,
int fontWeight,
unsigned short *fillColor,
unsigned short *strokeColor, double strokeWidth)
{
REGION reg;
cairo_t *cr;
ANNO_SCREEN(s);
cr = annoCairoContext(s, contextID);
if (cr)
{
cairo_text_extents_t extents;
cairo_set_line_width(cr, strokeWidth);
annoSetSourceColor(cr, fillColor);
cairo_select_font_face(cr, fontFamily, fontSlant, fontWeight);
cairo_set_font_size(cr, fontSize);
cairo_text_extents(cr, text, &extents);
cairo_save(cr);
cairo_move_to(cr, x, y);
cairo_text_path(cr, text);
cairo_fill_preserve(cr);
annoSetSourceColor(cr, strokeColor);
cairo_stroke(cr);
cairo_restore(cr);
reg.rects = ®.extents;
reg.numRects = 1;
reg.extents.x1 = x;
reg.extents.y1 = y + extents.y_bearing - 2.0;
reg.extents.x2 = x + extents.width + 20.0;
reg.extents.y2 = y + extents.height;
as->content[contextID] = TRUE;
damageScreenRegion(s, ®);
}
}
static Bool
annoCanvasTransform(CompDisplay * d,
CompAction * action,
CompActionState state, CompOption * option, int nOption)
{
CompScreen *s;
Window xid;
double p1, p2;
char *type;
xid = getIntOptionNamed(option, nOption, "root", 0);
s = findScreenAtDisplay(d, xid);
if (s)
{
cairo_t *cr;
int contextID;
ANNO_SCREEN(s);
contextID =
getIntOptionNamed(option, nOption, "context",
as->currentContext);
cr = annoCairoContext(s, contextID);
if (cr)
{
type = getStringOptionNamed(option, nOption, "type", "");
if (type)
{
if (strcasecmp(type, "save") == 0)
{
cairo_save(cr);
return TRUE;
}
else if (strcasecmp(type, "restore") == 0)
{
cairo_restore(cr);
return TRUE;
}
else if (strcasecmp(type, "translate") == 0)
{
p1 = getFloatOptionNamed(option, nOption, "x", 0.0);
p2 = getFloatOptionNamed(option, nOption, "y", 0.0);
if (p1 || p2)
{
cairo_translate(cr, p1, p2);
return TRUE;
}
return FALSE;
}
else if (strcasecmp(type, "scale") == 0)
{
p1 = getFloatOptionNamed(option, nOption, "x", 0.0);
p2 = getFloatOptionNamed(option, nOption, "y", 0.0);
if (p1 || p2)
{
cairo_scale(cr, p1, p2);
return TRUE;
}
return FALSE;
}
else if (strcasecmp(type, "rotate") == 0)
{
p1 = getFloatOptionNamed(option, nOption, "angle", 0.0);
if (p1)
{
cairo_rotate(cr, p1);
return TRUE;
}
return FALSE;
}
}
}
}
return FALSE;
}
static Bool
annoDraw(CompDisplay * d,
CompAction * action,
CompActionState state, CompOption * option, int nOption)
{
CompScreen *s;
Window xid;
xid = getIntOptionNamed(option, nOption, "root", 0);
s = findScreenAtDisplay(d, xid);
if (s)
{
cairo_t *cr;
int context;
ANNO_SCREEN(s);
context =
getIntOptionNamed(option, nOption, "context",
as->currentContext);
cr = annoCairoContext(s, context);
if (cr)
{
char *tool;
unsigned short *fillColor, *strokeColor;
double lineWidth, strokeWidth, angle;
int context;
ANNO_DISPLAY(d);
context =
getIntOptionNamed(option, nOption, "context",
as->currentContext);
tool = getStringOptionNamed(option, nOption, "tool", "line");
cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND);
fillColor = ad->opt[ANNO_DISPLAY_OPTION_FILL_COLOR].value.c;
fillColor = getColorOptionNamed(option, nOption, "fill_color",
fillColor);
strokeColor = ad->opt[ANNO_DISPLAY_OPTION_STROKE_COLOR].value.c;
strokeColor = getColorOptionNamed(option, nOption,
"stroke_color", strokeColor);
strokeWidth = ad->opt[ANNO_DISPLAY_OPTION_STROKE_WIDTH].value.f;
strokeWidth =
getFloatOptionNamed(option, nOption, "stroke_width",
strokeWidth);
lineWidth = ad->opt[ANNO_DISPLAY_OPTION_LINE_WIDTH].value.f;
lineWidth = getFloatOptionNamed(option, nOption, "line_width",
lineWidth);
angle = getFloatOptionNamed(option, nOption, "angle", 0.0);
if (strcasecmp(tool, "rectangle") == 0)
{
double x, y, w, h;
x = getFloatOptionNamed(option, nOption, "x", 0);
y = getFloatOptionNamed(option, nOption, "y", 0);
w = getFloatOptionNamed(option, nOption, "w", 100);
h = getFloatOptionNamed(option, nOption, "h", 100);
annoDrawRectangle(s, context, x, y, w, h, fillColor,
strokeColor, strokeWidth, angle);
}
else if (strcasecmp(tool, "circle") == 0)
{
double xc, yc, r;
xc = getFloatOptionNamed(option, nOption, "xc", 0);
yc = getFloatOptionNamed(option, nOption, "yc", 0);
r = getFloatOptionNamed(option, nOption, "radius", 100);
annoDrawCircle(s, context, xc, yc, r, fillColor,
strokeColor, strokeWidth);
}
else if (strcasecmp(tool, "line") == 0)
{
double x1, y1, x2, y2;
x1 = getFloatOptionNamed(option, nOption, "x1", 0);
y1 = getFloatOptionNamed(option, nOption, "y1", 0);
x2 = getFloatOptionNamed(option, nOption, "x2", 100);
y2 = getFloatOptionNamed(option, nOption, "y2", 100);
annoDrawLine(s, context, x1, y1, x2, y2, lineWidth,
fillColor);
}
else if (strcasecmp(tool, "text") == 0)
{
double x, y, size;
char *text, *family;
unsigned int slant, weight;
char *str;
str = getStringOptionNamed(option, nOption, "slant", "");
if (strcasecmp(str, "oblique") == 0)
slant = CAIRO_FONT_SLANT_OBLIQUE;
else if (strcasecmp(str, "italic") == 0)
slant = CAIRO_FONT_SLANT_ITALIC;
else
slant = CAIRO_FONT_SLANT_NORMAL;
str = getStringOptionNamed(option, nOption, "weight", "");
if (strcasecmp(str, "bold") == 0)
weight = CAIRO_FONT_WEIGHT_BOLD;
else
weight = CAIRO_FONT_WEIGHT_NORMAL;
x = getFloatOptionNamed(option, nOption, "x", 0);
y = getFloatOptionNamed(option, nOption, "y", 0);
text = getStringOptionNamed(option, nOption, "text", "");
family = getStringOptionNamed(option, nOption, "family",
"Sans");
size = getFloatOptionNamed(option, nOption, "size", 36.0);
annoDrawText(s, context, x, y, text, family, size,
slant, weight, fillColor,
strokeColor, strokeWidth);
}
else if (strcasecmp(tool, "svg") == 0)
{
double x, y, scaleX, scaleY;
int handleID;
x = getFloatOptionNamed(option, nOption, "x", 0);
y = getFloatOptionNamed(option, nOption, "y", 0);
scaleX = getFloatOptionNamed(option, nOption, "scale_x", 1.0);
scaleY = getFloatOptionNamed(option, nOption, "scale_y", 1.0);
handleID = getIntOptionNamed(option, nOption, "handle_id", 0);
annoDrawSvg(s, context, handleID, x, y, angle, scaleX,
scaleY);
}
}
}
return FALSE;
}
static Bool
annoInitiate(CompDisplay * d,
CompAction * action,
CompActionState state, CompOption * option, int nOption)
{
CompScreen *s;
Window xid;
xid = getIntOptionNamed(option, nOption, "root", 0);
s = findScreenAtDisplay(d, xid);
if (s)
{
ANNO_SCREEN(s);
if (otherScreenGrabExist(s, 0))
return FALSE;
if (!as->grabIndex)
as->grabIndex = pushScreenGrab(s, None, "annotate");
if (state & CompActionStateInitButton)
action->state |= CompActionStateTermButton;
if (state & CompActionStateInitKey)
action->state |= CompActionStateTermKey;
annoLastPointerX = d->pointerX;
annoLastPointerY = d->pointerY;
if (!as->isDrawing)
{
as->firstX = d->pointerX;
as->firstY = d->pointerY;
as->isDrawing = TRUE;
}
as->eraseMode = FALSE;
}
return TRUE;
}
static Bool
annoTerminate(CompDisplay * d,
CompAction * action,
CompActionState state, CompOption * option, int nOption)
{
CompScreen *s;
Window xid;
ANNO_DISPLAY(d);
xid = getIntOptionNamed(option, nOption, "root", 0);
for (s = d->screens; s; s = s->next)
{
ANNO_SCREEN(s);
if (xid && s->root != xid)
continue;
if (as->grabIndex)
{
removeScreenGrab(s, as->grabIndex, NULL);
as->grabIndex = 0;
}
if (as->tool == ANNO_TOOL_LINE)
{
annoDrawLine(s, as->currentContext,
as->firstX, as->firstY,
d->pointerX, d->pointerY,
ad->opt[ANNO_DISPLAY_OPTION_LINE_WIDTH].value.f,
ad->opt[ANNO_DISPLAY_OPTION_FILL_COLOR].value.c);
}
else if (as->tool == ANNO_TOOL_ARROW)
{
annoDrawArrow(s, as->currentContext, as->firstX, as->firstY,
d->pointerX, d->pointerY,
ad->opt[ANNO_DISPLAY_OPTION_LINE_WIDTH].value.f,
ad->opt[ANNO_DISPLAY_OPTION_FILL_COLOR].value.c);
}
damageScreen(s);
as->isDrawing = FALSE;
}
action->state &= ~(CompActionStateTermKey | CompActionStateTermButton);
return FALSE;
}
static Bool
annoEraseInitiate(CompDisplay * d,
CompAction * action,
CompActionState state, CompOption * option, int nOption)
{
CompScreen *s;
Window xid;
xid = getIntOptionNamed(option, nOption, "root", 0);
s = findScreenAtDisplay(d, xid);
if (s)
{
ANNO_SCREEN(s);
if (otherScreenGrabExist(s, 0))
return FALSE;
if (!as->grabIndex)
as->grabIndex = pushScreenGrab(s, None, "annotate");
if (state & CompActionStateInitButton)
action->state |= CompActionStateTermButton;
if (state & CompActionStateInitKey)
action->state |= CompActionStateTermKey;
annoLastPointerX = d->pointerX;
annoLastPointerY = d->pointerY;
as->eraseMode = TRUE;
}
return TRUE;
}
static Bool
annoClear(CompDisplay * d,
CompAction * action,
CompActionState state, CompOption * option, int nOption)
{
CompScreen *s;
Window xid;
xid = getIntOptionNamed(option, nOption, "root", 0);
s = findScreenAtDisplay(d, xid);
if (s)
{
int contextID;
ANNO_SCREEN(s);
contextID = getIntOptionNamed(option, nOption, "context",
as->currentContext);
if (as->content[contextID])
{
cairo_t *cr;
cr = annoCairoContext(s, contextID);
if (cr)
annoCairoClear(s, as->cairo[contextID], contextID);
as->content[contextID] = FALSE;
if (contextID == as->currentContext)
damageScreen(s);
}
return TRUE;
}
return FALSE;
}
static Bool
annoUsePaintbrush(CompDisplay * d,
CompAction * action,
CompActionState state, CompOption * option, int nOption)
{
CompScreen *s;
Window xid;
xid = getIntOptionNamed(option, nOption, "root", 0);
s = findScreenAtDisplay(d, xid);
if (!s)
return FALSE;
ANNO_SCREEN(s);
as->tool = ANNO_TOOL_PAINTBRUSH;
return TRUE;
}
static Bool
annoUseLine(CompDisplay * d,
CompAction * action,
CompActionState state, CompOption * option, int nOption)
{
CompScreen *s;
Window xid;
xid = getIntOptionNamed(option, nOption, "root", 0);
s = findScreenAtDisplay(d, xid);
if (!s)
return FALSE;
ANNO_SCREEN(s);
as->tool = ANNO_TOOL_LINE;
return TRUE;
}
static Bool
annoUseArrow(CompDisplay * d,
CompAction * action,
CompActionState state, CompOption * option, int nOption)
{
CompScreen *s;
Window xid;
xid = getIntOptionNamed(option, nOption, "root", 0);
s = findScreenAtDisplay(d, xid);
if (!s)
return FALSE;
ANNO_SCREEN(s);
as->tool = ANNO_TOOL_ARROW;
return TRUE;
}
static Bool
annoPutText(CompDisplay * d,
CompAction * action,
CompActionState state, CompOption * option, int nOption)
{
CompScreen *s;
Window xid;
xid = getIntOptionNamed(option, nOption, "root", 0);
s = findScreenAtDisplay(d, xid);
if (!s)
return FALSE;
ANNO_SCREEN(s);
ANNO_DISPLAY(d);
int x, y;
x = d->pointerX;
y = d->pointerY;
if (ad->opt[ANNO_DISPLAY_OPTION_TEXT_STRINGS].value.list.nValue == 0)
{
annoDrawText(s, as->currentContext, x, y,
"Undefined - Configure Annotate Text", "Sans", 24, 0, 0,
ad->opt[ANNO_DISPLAY_OPTION_FILL_COLOR].value.c,
ad->opt[ANNO_DISPLAY_OPTION_FILL_COLOR].value.c, 0);
}
else
{
annoDrawText(s, as->currentContext, x, y,
ad->opt[ANNO_DISPLAY_OPTION_TEXT_STRINGS].value.list.
value[as->stringIndex].s, "Sans", 24, 0, 0,
ad->opt[ANNO_DISPLAY_OPTION_FILL_COLOR].value.c,
ad->opt[ANNO_DISPLAY_OPTION_FILL_COLOR].value.c, 0);
as->stringIndex++;
as->stringIndex %=
ad->opt[ANNO_DISPLAY_OPTION_TEXT_STRINGS].value.list.nValue;
}
damageScreen(s);
as->firstX = 0; // Force damageScreen on PaintScreen
return TRUE;
}
static Bool
annoPaintScreen(CompScreen * s,
const ScreenPaintAttrib * sAttrib,
Region region, int output, unsigned int mask)
{
Bool status;
ANNO_SCREEN(s);
UNWRAP(as, s, paintScreen);
status = (*s->paintScreen) (s, sAttrib, region, output, mask);
WRAP(as, s, paintScreen, annoPaintScreen);
if (status && as->content[as->currentContext] && region->numRects)
{
BoxPtr pBox;
int nBox;
glPushMatrix();
prepareXCoords(s, output, -DEFAULT_Z_CAMERA);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glEnable(GL_BLEND);
enableTexture(s, &as->texture[as->currentContext],
COMP_TEXTURE_FILTER_FAST);
pBox = region->rects;
nBox = region->numRects;
glBegin(GL_QUADS);
while (nBox--)
{
glTexCoord2f(COMP_TEX_COORD_X
(&as->texture[as->currentContext].matrix, pBox->x1),
COMP_TEX_COORD_Y(&as->texture[as->currentContext].
matrix, pBox->y2));
glVertex2i(pBox->x1, pBox->y2);
glTexCoord2f(COMP_TEX_COORD_X
(&as->texture[as->currentContext].matrix, pBox->x2),
COMP_TEX_COORD_Y(&as->texture[as->currentContext].
matrix, pBox->y2));
glVertex2i(pBox->x2, pBox->y2);
glTexCoord2f(COMP_TEX_COORD_X
(&as->texture[as->currentContext].matrix, pBox->x2),
COMP_TEX_COORD_Y(&as->texture[as->currentContext].
matrix, pBox->y1));
glVertex2i(pBox->x2, pBox->y1);
glTexCoord2f(COMP_TEX_COORD_X
(&as->texture[as->currentContext].matrix, pBox->x1),
COMP_TEX_COORD_Y(&as->texture[as->currentContext].
matrix, pBox->y1));
glVertex2i(pBox->x1, pBox->y1);
pBox++;
}
glEnd();
disableTexture(s, &as->texture[as->currentContext]);
glDisable(GL_BLEND);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glPopMatrix();
}
if (as->firstX != -1 && !as->isDrawing)
{
as->firstX = -1;
as->firstY = -1;
damageScreen(s);
}
return status;
}
static void annoHandleMotionEvent(CompScreen * s, int xRoot, int yRoot)
{
ANNO_SCREEN(s);
if (as->grabIndex)
{
if (as->eraseMode)
{
static unsigned short color[] = { 0, 0, 0, 0 };
annoDrawLine(s, as->currentContext,
annoLastPointerX, annoLastPointerY,
xRoot, yRoot, 20.0, color);
}
else
{
char *currentTool;
ANNO_DISPLAY(s->display);
currentTool = ad->opt[ANNO_DISPLAY_OPTION_TOOL].value.s;
if (strcmp(currentTool, "svg") == 0)
{
/*annoDrawSvg (s, as->currentContext,
ad->opt[ANNO_DISPLAY_OPTION_SVG_FILE].value.s,
xRoot, yRoot,
0.0, 1.0, 1.0); */
}
else if (as->tool == ANNO_TOOL_PAINTBRUSH)
{
annoDrawLine(s, as->currentContext,
annoLastPointerX, annoLastPointerY,
xRoot, yRoot,
ad->opt[ANNO_DISPLAY_OPTION_LINE_WIDTH].value.f,
ad->opt[ANNO_DISPLAY_OPTION_FILL_COLOR].value.c);
}
}
annoLastPointerX = xRoot;
annoLastPointerY = yRoot;
}
}
static void annoHandleEvent(CompDisplay * d, XEvent * event)
{
CompScreen *s;
ANNO_DISPLAY(d);
switch (event->type)
{
case MotionNotify:
s = findScreenAtDisplay(d, event->xmotion.root);
if (s)
annoHandleMotionEvent(s, d->pointerX, d->pointerY);
break;
case EnterNotify:
case LeaveNotify:
s = findScreenAtDisplay(d, event->xcrossing.root);
if (s)
annoHandleMotionEvent(s, d->pointerX, d->pointerY);
default:
break;
}
UNWRAP(ad, d, handleEvent);
(*d->handleEvent) (d, event);
WRAP(ad, d, handleEvent, annoHandleEvent);
}
static void annoDisplayInitOptions(AnnoDisplay * ad)
{
CompOption *o;
o = &ad->opt[ANNO_DISPLAY_OPTION_INITIATE];
o->advanced = False;
o->name = "initiate";
o->group = N_("Tools");
o->subGroup = N_("Other");
o->displayHints = "";
o->shortDesc = N_("Initiate");
o->longDesc = N_("Initiate Annotate drawing.");
o->type = CompOptionTypeAction;
o->value.action.initiate = annoInitiate;
o->value.action.terminate = annoTerminate;
o->value.action.bell = FALSE;
o->value.action.edgeMask = 0;
o->value.action.type = CompBindingTypeButton;
o->value.action.state = CompActionStateInitButton;
o->value.action.state |= CompActionStateInitKey;
o->value.action.button.modifiers = ANNO_INITIATE_BUTTON_MODIFIERS_DEFAULT;
o->value.action.button.button = ANNO_INITIATE_BUTTON_DEFAULT;
o = &ad->opt[ANNO_DISPLAY_OPTION_DRAW];
o->advanced = False;
o->name = "draw";
o->group = N_("Tools");
o->subGroup = N_("");
o->displayHints = "";
o->shortDesc = N_("Draw");
o->longDesc = N_("Draw using tool.");
o->type = CompOptionTypeAction;
o->value.action.initiate = annoDraw;
o->value.action.terminate = 0;
o->value.action.bell = FALSE;
o->value.action.edgeMask = 0;
o->value.action.type = 0;
o->value.action.state = 0;
o = &ad->opt[ANNO_DISPLAY_OPTION_TRANSFORM];
o->advanced = False;
o->name = "transform";
o->group = N_("Style");
o->subGroup = N_("");
o->displayHints = "";
o->shortDesc = N_("Transform the canvas");
o->longDesc = N_("Transform the canvas, also used to save and restore.");
o->type = CompOptionTypeAction;
o->value.action.initiate = annoCanvasTransform;
o->value.action.terminate = 0;
o->value.action.bell = FALSE;
o->value.action.edgeMask = 0;
o->value.action.type = 0;
o->value.action.state = 0;
o = &ad->opt[ANNO_DISPLAY_OPTION_PRELOAD];
o->advanced = False;
o->name = "preload";
o->group = N_("Style");
o->subGroup = N_("");
o->displayHints = "";
o->shortDesc = N_("Preload a svg");
o->longDesc = N_("Preload a svg.");
o->type = CompOptionTypeAction;
o->value.action.initiate = annoLoadSvg;
o->value.action.terminate = 0;
o->value.action.bell = FALSE;
o->value.action.edgeMask = 0;
o->value.action.type = 0;
o->value.action.state = 0;
o = &ad->opt[ANNO_DISPLAY_OPTION_SWITCH_CONTEXT];
o->advanced = False;
o->name = "switch_context";
o->group = N_("Style");
o->subGroup = N_("");
o->displayHints = "";
o->shortDesc = N_("Switch to another canvas");
o->longDesc = N_("Switch to another canvas for drawing.");
o->type = CompOptionTypeAction;
o->value.action.initiate = annoCanvasSwitchContext;
o->value.action.terminate = 0;
o->value.action.bell = FALSE;
o->value.action.edgeMask = 0;
o->value.action.type = 0;
o->value.action.state = 0;
o = &ad->opt[ANNO_DISPLAY_OPTION_ERASE];
o->advanced = False;
o->name = "erase";
o->group = N_("Tools");
o->subGroup = N_("Eraser");
o->displayHints = "";
o->shortDesc = N_("Initiate erase");
o->longDesc = N_("Initiate Annotate erasing.");
o->type = CompOptionTypeAction;
o->value.action.initiate = annoEraseInitiate;
o->value.action.terminate = annoTerminate;
o->value.action.bell = FALSE;
o->value.action.edgeMask = 0;
o->value.action.type = CompBindingTypeButton;
o->value.action.state = CompActionStateInitButton;
o->value.action.state |= CompActionStateInitKey;
o->value.action.button.modifiers = ANNO_ERASE_BUTTON_MODIFIERS_DEFAULT;
o->value.action.button.button = ANNO_ERASE_BUTTON_DEFAULT;
o = &ad->opt[ANNO_DISPLAY_OPTION_CLEAR];
o->advanced = False;
o->name = "clear";
o->group = N_("Tools");
o->subGroup = N_("Clear");
o->displayHints = "";
o->shortDesc = N_("Clear");
o->longDesc = N_("Clear");
o->type = CompOptionTypeAction;
o->value.action.initiate = annoClear;
o->value.action.terminate = 0;
o->value.action.bell = FALSE;
o->value.action.edgeMask = 0;
o->value.action.type = CompBindingTypeKey;
o->value.action.state = CompActionStateInitEdge;
o->value.action.state |= CompActionStateInitButton;
o->value.action.state |= CompActionStateInitKey;
o->value.action.key.modifiers = ANNO_CLEAR_KEY_MODIFIERS_DEFAULT;
o->value.action.key.keysym = XStringToKeysym(ANNO_CLEAR_KEY_DEFAULT);
o = &ad->opt[ANNO_DISPLAY_OPTION_FILL_COLOR];
o->advanced = False;
o->name = "fill_color";
o->group = N_("Style");
o->subGroup = N_("Colors");
o->displayHints = "";
o->shortDesc = N_("Annotate Fill Color");
o->longDesc = N_("Fill color for Annotations.");
o->type = CompOptionTypeColor;
o->value.c[0] = ANNO_FILL_COLOR_RED_DEFAULT;
o->value.c[1] = ANNO_FILL_COLOR_GREEN_DEFAULT;
o->value.c[2] = ANNO_FILL_COLOR_BLUE_DEFAULT;
o->value.c[3] = 0xffff;
o = &ad->opt[ANNO_DISPLAY_OPTION_STROKE_COLOR];
o->advanced = False;
o->name = "stroke_color";
o->group = N_("Style");
o->subGroup = N_("Colors");
o->displayHints = "";
o->shortDesc = N_("Annotate Stroke Color");
o->longDesc = N_("Stroke color for Annotations.");
o->type = CompOptionTypeColor;
o->value.c[0] = ANNO_STROKE_COLOR_RED_DEFAULT;
o->value.c[1] = ANNO_STROKE_COLOR_GREEN_DEFAULT;
o->value.c[2] = ANNO_STROKE_COLOR_BLUE_DEFAULT;
o->value.c[3] = 0xffff;
o = &ad->opt[ANNO_DISPLAY_OPTION_LINE_WIDTH];
o->advanced = False;
o->name = "line_width";
o->group = N_("Style");
o->subGroup = N_("Size");
o->displayHints = "";
o->shortDesc = N_("Line width");
o->longDesc = N_("Line width for Annotations.");
o->type = CompOptionTypeFloat;
o->value.f = ANNO_LINE_WIDTH_DEFAULT;
o->rest.f.min = ANNO_LINE_WIDTH_MIN;
o->rest.f.max = ANNO_LINE_WIDTH_MAX;
o->rest.f.precision = ANNO_LINE_WIDTH_PRECISION;
o = &ad->opt[ANNO_DISPLAY_OPTION_STROKE_WIDTH];
o->advanced = False;
o->name = "stroke_width";
o->group = N_("Style");
o->subGroup = N_("Size");
o->displayHints = "";
o->shortDesc = N_("Stroke width");
o->longDesc = N_("Stroke width for Annotations.");
o->type = CompOptionTypeFloat;
o->value.f = ANNO_STROKE_WIDTH_DEFAULT;
o->rest.f.min = ANNO_STROKE_WIDTH_MIN;
o->rest.f.max = ANNO_STROKE_WIDTH_MAX;
o->rest.f.precision = ANNO_STROKE_WIDTH_PRECISION;
o = &ad->opt[ANNO_DISPLAY_OPTION_SVG_FILE];
o->advanced = False;
o->name = "svg_file";
o->group = N_("Style");
o->subGroup = N_("Files");
o->displayHints = "";
o->shortDesc = N_("SVG (custom brush) filename");
o->longDesc = N_("SVG (custom brush) filename.");
o->type = CompOptionTypeString;
o->value.s = strdup("");
o->rest.s.string = 0;
o->rest.s.nString = 0;
o = &ad->opt[ANNO_DISPLAY_OPTION_TOOL];
o->advanced = False;
o->name = "tool";
o->group = N_("Style");
o->subGroup = N_("Files");
o->displayHints = "";
o->shortDesc = N_("SVG (custom brush) filename");
o->longDesc = N_("SVG (custom brush) filename.");
o->type = CompOptionTypeString;
o->value.s = strdup("");
o->rest.s.string = 0;
o->rest.s.nString = 0;
o = &ad->opt[ANNO_DISPLAY_OPTION_USE_PAINTBRUSH];
o->advanced = False;
o->name = "use_pb";
o->group = N_("Tools");
o->subGroup = N_("Paintbrush");
o->displayHints = "";
o->shortDesc = N_("Use Paintbrush Tool");
o->longDesc = N_("Click and drag the paintbrush to draw figures.");
o->type = CompOptionTypeAction;
o->value.action.initiate = annoUsePaintbrush;
o->value.action.terminate = 0;
o->value.action.bell = FALSE;
o->value.action.edgeMask = 0;
o->value.action.type = CompBindingTypeKey;
o->value.action.state = CompActionStateInitButton;
o->value.action.state |= CompActionStateInitKey;
o->value.action.key.modifiers =
ANNO_SWITCH_PAINTBRUSH_KEY_MODIFIERS_DEFAULT;
o->value.action.key.keysym =
XStringToKeysym(ANNO_SWITCH_PAINTBRUSH_KEY_DEFAULT);
o = &ad->opt[ANNO_DISPLAY_OPTION_USE_LINE];
o->advanced = False;
o->name = "use_line";
o->group = N_("Tools");
o->subGroup = N_("Line");
o->displayHints = "";
o->shortDesc = N_("Use Line Tool");
o->longDesc = N_("Draw lines by clicking and dragging.");
o->type = CompOptionTypeAction;
o->value.action.initiate = annoUseLine;
o->value.action.terminate = 0;
o->value.action.bell = FALSE;
o->value.action.edgeMask = 0;
o->value.action.type = CompBindingTypeKey;
o->value.action.state = CompActionStateInitButton;
o->value.action.state |= CompActionStateInitKey;
o->value.action.key.modifiers = ANNO_SWITCH_LINE_KEY_MODIFIERS_DEFAULT;
o->value.action.key.keysym =
XStringToKeysym(ANNO_SWITCH_LINE_KEY_DEFAULT);
o = &ad->opt[ANNO_DISPLAY_OPTION_USE_ARROW];
o->advanced = False;
o->name = "use_line";
o->group = N_("Tools");
o->subGroup = N_("Arrow");
o->displayHints = "";
o->shortDesc = N_("Use Arrow Tool");
o->longDesc = N_("Draw arrows by clicking and dragging.");
o->type = CompOptionTypeAction;
o->value.action.initiate = annoUseArrow;
o->value.action.terminate = 0;
o->value.action.bell = FALSE;
o->value.action.edgeMask = 0;
o->value.action.type = CompBindingTypeKey;
o->value.action.state = CompActionStateInitButton;
o->value.action.state |= CompActionStateInitKey;
o->value.action.key.modifiers = ANNO_SWITCH_ARROW_KEY_MODIFIERS_DEFAULT;
o->value.action.key.keysym =
XStringToKeysym(ANNO_SWITCH_ARROW_KEY_DEFAULT);
o = &ad->opt[ANNO_DISPLAY_OPTION_TEXT_STRINGS];
o->advanced = False;
o->name = "text_strings";
o->group = N_("Tools");
o->subGroup = N_("Text");
o->displayHints = "";
o->shortDesc = N_("Text Strings");
o->longDesc =
N_
("Strings to be displayed when using the put string tool, in order entered (not in order on screen).");
o->type = CompOptionTypeList;
o->value.list.type = CompOptionTypeString;
o->value.list.nValue = 0;
o->value.list.value = NULL;
o->rest.s.string = 0;
o->rest.s.nString = 0;
o = &ad->opt[ANNO_DISPLAY_OPTION_PUT_TEXT];
o->advanced = False;
o->name = "put_text";
o->group = N_("Tools");
o->subGroup = N_("Text");
o->displayHints = "";
o->shortDesc = N_("Put Text");
o->longDesc = N_("Put text at the mouse cursor.");
o->type = CompOptionTypeAction;
o->value.action.initiate = annoPutText;
o->value.action.terminate = 0;
o->value.action.bell = FALSE;
o->value.action.edgeMask = 0;
o->value.action.type = CompBindingTypeNone; //CompBindingTypeKey;
o->value.action.state = CompActionStateInitButton;
o->value.action.state |= CompActionStateInitKey;
// o->value.action.key.modifiers = ANNO_PUT_TEXT_KEY_MODIFIERS_DEFAULT;
// o->value.action.key.keysym = XStringToKeysym(ANNO_PUT_TEXT_KEY_DEFAULT);
}
static CompOption *annoGetDisplayOptions(CompDisplay * display, int *count)
{
if (display)
{
ANNO_DISPLAY(display);
*count = NUM_OPTIONS(ad);
return ad->opt;
}
else
{
AnnoDisplay *ad = malloc(sizeof(AnnoDisplay));
annoDisplayInitOptions(ad);
*count = NUM_OPTIONS(ad);
return ad->opt;
}
}
static Bool
annoSetDisplayOption(CompDisplay * display,
char *name, CompOptionValue * value)
{
CompOption *o;
int index;
ANNO_DISPLAY(display);
o = compFindOption(ad->opt, NUM_OPTIONS(ad), name, &index);
if (!o)
return FALSE;
switch (index)
{
case ANNO_DISPLAY_OPTION_INITIATE:
case ANNO_DISPLAY_OPTION_ERASE:
case ANNO_DISPLAY_OPTION_CLEAR:
case ANNO_DISPLAY_OPTION_USE_PAINTBRUSH:
case ANNO_DISPLAY_OPTION_USE_LINE:
case ANNO_DISPLAY_OPTION_USE_ARROW:
if (setDisplayAction(display, o, value))
return TRUE;
break;
case ANNO_DISPLAY_OPTION_FILL_COLOR:
case ANNO_DISPLAY_OPTION_STROKE_COLOR:
if (compSetColorOption(o, value))
return TRUE;
break;
case ANNO_DISPLAY_OPTION_LINE_WIDTH:
case ANNO_DISPLAY_OPTION_STROKE_WIDTH:
if (compSetFloatOption(o, value))
return TRUE;
break;
case ANNO_DISPLAY_OPTION_TOOL:
case ANNO_DISPLAY_OPTION_SVG_FILE:
if (compSetStringOption(o, value))
return TRUE;
break;
case ANNO_DISPLAY_OPTION_TEXT_STRINGS:
if (compSetOptionList(o, value))
return TRUE;
break;
case ANNO_DISPLAY_OPTION_PUT_TEXT:
if (setDisplayAction(display, o, value))
return TRUE;
break;
default:
break;
}
return FALSE;
}
static Bool annoInitDisplay(CompPlugin * p, CompDisplay * d)
{
AnnoDisplay *ad;
ad = malloc(sizeof(AnnoDisplay));
if (!ad)
return FALSE;
ad->screenPrivateIndex = allocateScreenPrivateIndex(d);
if (ad->screenPrivateIndex < 0)
{
free(ad);
return FALSE;
}
WRAP(ad, d, handleEvent, annoHandleEvent);
annoDisplayInitOptions(ad);
d->privates[displayPrivateIndex].ptr = ad;
return TRUE;
}
static void annoFiniDisplay(CompPlugin * p, CompDisplay * d)
{
ANNO_DISPLAY(d);
freeScreenPrivateIndex(d, ad->screenPrivateIndex);
UNWRAP(ad, d, handleEvent);
free(ad);
}
static Bool annoInitScreen(CompPlugin * p, CompScreen * s)
{
AnnoScreen *as;
int i;
ANNO_DISPLAY(s->display);
as = malloc(sizeof(AnnoScreen));
if (!as)
return FALSE;
as->grabIndex = 0;
as->tool = ANNO_TOOL_PAINTBRUSH;
as->firstX = -1;
as->firstY = -1;
as->isDrawing = FALSE;
as->stringIndex = 0;
for (i = 0; i < ANNO_NUMBER_CONTEXTS; i++)
{
as->surface[i] = NULL;
as->pixmap[i] = None;
as->cairo[i] = NULL;
as->content[i] = FALSE;
initTexture(s, &as->texture[i]);
}
as->currentContext = 0;
addScreenAction(s, &ad->opt[ANNO_DISPLAY_OPTION_INITIATE].value.action);
addScreenAction(s, &ad->opt[ANNO_DISPLAY_OPTION_ERASE].value.action);
addScreenAction(s, &ad->opt[ANNO_DISPLAY_OPTION_CLEAR].value.action);
addScreenAction(s,
&ad->opt[ANNO_DISPLAY_OPTION_USE_PAINTBRUSH].value.
action);
addScreenAction(s, &ad->opt[ANNO_DISPLAY_OPTION_USE_LINE].value.action);
addScreenAction(s, &ad->opt[ANNO_DISPLAY_OPTION_USE_ARROW].value.action);
addScreenAction(s, &ad->opt[ANNO_DISPLAY_OPTION_PUT_TEXT].value.action);
WRAP(as, s, paintScreen, annoPaintScreen);
s->privates[ad->screenPrivateIndex].ptr = as;
return TRUE;
}
static void annoFiniScreen(CompPlugin * p, CompScreen * s)
{
int i;
ANNO_SCREEN(s);
ANNO_DISPLAY(s->display);
for (i = 0; i < ANNO_NUMBER_CONTEXTS; i++)
{
if (as->cairo[i])
cairo_destroy(as->cairo[i]);
if (as->surface[i])
cairo_surface_destroy(as->surface[i]);
finiTexture(s, &as->texture[i]);
if (as->pixmap[i])
XFreePixmap(s->display->display, as->pixmap[i]);
}
removeScreenAction(s,
&ad->opt[ANNO_DISPLAY_OPTION_INITIATE].value.action);
removeScreenAction(s, &ad->opt[ANNO_DISPLAY_OPTION_ERASE].value.action);
removeScreenAction(s, &ad->opt[ANNO_DISPLAY_OPTION_CLEAR].value.action);
removeScreenAction(s,
&ad->opt[ANNO_DISPLAY_OPTION_USE_PAINTBRUSH].value.
action);
removeScreenAction(s,
&ad->opt[ANNO_DISPLAY_OPTION_USE_LINE].value.action);
removeScreenAction(s,
&ad->opt[ANNO_DISPLAY_OPTION_USE_ARROW].value.action);
removeScreenAction(s,
&ad->opt[ANNO_DISPLAY_OPTION_PUT_TEXT].value.action);
UNWRAP(as, s, paintScreen);
free(as);
}
static Bool annoInit(CompPlugin * p)
{
displayPrivateIndex = allocateDisplayPrivateIndex();
if (displayPrivateIndex < 0)
return FALSE;
return TRUE;
}
static void annoFini(CompPlugin * p)
{
if (displayPrivateIndex >= 0)
freeDisplayPrivateIndex(displayPrivateIndex);
}
static CompPluginVTable annoVTable = {
"annotate",
N_("Annotate"),
N_("Annotate plugin"),
annoInit,
annoFini,
annoInitDisplay,
annoFiniDisplay,
annoInitScreen,
annoFiniScreen,
0, /* InitWindow */
0, /* FiniWindow */
annoGetDisplayOptions,
annoSetDisplayOption,
0, /* GetScreenOptions */
0, /* SetScreenOption */
0, /* Deps */
0, /* nDeps */
0, /* Features */
0, /* nFeatures */
BERYL_ABI_INFO,
"beryl-plugins",
"misc",
0,
0,
False,
};
CompPluginVTable *getCompPluginInfo(void)
{
return &annoVTable;
}
syntax highlighted by Code2HTML, v. 0.9.1