/* * 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 * James Eady (Lines, arrows, text) */ #include #include #include #include #include #include #include #include #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) // #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) // #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; }