Logo Search packages:      
Sourcecode: beryl-plugins version File versions

annotate.c

/*
 * 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 = &reg.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, &reg);
      }
}

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 = &reg.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, &reg);
            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 = &reg.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, &reg);
            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 = &reg.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, &reg);
      }
}

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;
}

Generated by  Doxygen 1.6.0   Back to index