1 /*
   2  * Copyright �� 2006 Novell, Inc.
   3  *
   4  * Permission to use, copy, modify, distribute, and sell this software
   5  * and its documentation for any purpose is hereby granted without
   6  * fee, provided that the above copyright notice appear in all copies
   7  * and that both that copyright notice and this permission notice
   8  * appear in supporting documentation, and that the name of
   9  * Novell, Inc. not be used in advertising or publicity pertaining to
  10  * distribution of the software without specific, written prior permission.
  11  * Novell, Inc. makes no representations about the suitability of this
  12  * software for any purpose. It is provided "as is" without express or
  13  * implied warranty.
  14  *
  15  * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
  16  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
  17  * NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
  18  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
  19  * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
  20  * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
  21  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  22  *
  23  * Author: David Reveman <davidr@novell.com>
  24  */
  25 
  26 #include "annotate.h"
  27 
  28 COMPIZ_PLUGIN_20090315 (annotate, AnnoPluginVTable)
  29 
  30 #define DEG2RAD (M_PI / 180.0f)
  31 
  32 void
  33 AnnoScreen::cairoClear (cairo_t    *cr)
  34 {
  35     cairo_save (cr);
  36     cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
  37     cairo_paint (cr);
  38     cairo_restore (cr);
  39 
  40     content = false;
  41 }
  42 
  43 cairo_t *
  44 AnnoScreen::cairoContext ()
  45 {
  46     if (!cairo)
  47     {
  48 	XRenderPictFormat *format;
  49 	Screen		  *xScreen;
  50 	int		  w, h;
  51 
  52 	xScreen = ScreenOfDisplay (screen->dpy (), screen->screenNum ());
  53 
  54 	w = screen->width ();
  55 	h = screen->height ();
  56 
  57 	format = XRenderFindStandardFormat (screen->dpy (),
  58 					    PictStandardARGB32);
  59 
  60 	pixmap = XCreatePixmap (screen->dpy (), screen->root (), w, h, 32);
  61 
  62 	texture = GLTexture::bindPixmapToTexture (pixmap, w, h, 32);
  63 
  64 	if (texture.empty ())
  65 	{
  66 	    compLogMessage ("annotate", CompLogLevelError,
  67 			    "Couldn't bind pixmap 0x%x to texture",
  68 			    (int) pixmap);
  69 
  70 	    XFreePixmap (screen->dpy (), pixmap);
  71 
  72 	    return NULL;
  73 	}
  74 
  75 	damage = XDamageCreate (screen->dpy (), pixmap,
  76 				XDamageReportBoundingBox);
  77 
  78 	surface =
  79 	    cairo_xlib_surface_create_with_xrender_format (screen->dpy (),
  80 							   pixmap, xScreen,
  81 							   format, w, h);
  82 
  83 	cairo = cairo_create (surface);
  84 	
  85 	if (cairoBuffer.size ())
  86 	{
  87 	    cairo_t *cr = cairo_create (surface);
  88 	    int stride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32, w);
  89 	    cairo_surface_t *raw_source =
  90 		cairo_image_surface_create_for_data ((unsigned char *)
  91 						     cairoBuffer.c_str (),
  92 						     CAIRO_FORMAT_ARGB32,
  93 						     w, h, stride);
  94 	    
  95 	    if (cr && raw_source)
  96 	    {	      
  97 		cairo_set_source_surface (cr, raw_source, 0, 0);
  98 		cairo_paint (cr);
  99 		
 100 		cairo_surface_destroy (raw_source);
 101 		cairo_destroy (cr);
 102 		cairoBuffer.clear ();
 103 	    }
 104 	}
 105 	else	    
 106 	    cairoClear (cairo);
 107     }
 108 
 109     return cairo;
 110 }
 111 
 112 void
 113 AnnoScreen::setSourceColor (cairo_t	   *cr,
 114 		    	    unsigned short *color)
 115 {
 116     cairo_set_source_rgba (cr,
 117 			   (double) color[0] / 0xffff,
 118 			   (double) color[1] / 0xffff,
 119 			   (double) color[2] / 0xffff,
 120 			   (double) color[3] / 0xffff);
 121 }
 122 
 123 void
 124 AnnoScreen::drawEllipse (double		xc,
 125 			 double		yc,
 126 			 double		radiusX,
 127 			 double		radiusY,
 128 			 unsigned short	*fillColor,
 129 			 unsigned short	*strokeColor,
 130 			 double		strokeWidth)
 131 {
 132     cairo_t *cr;
 133 
 134     cr = cairoContext ();
 135     if (cr)
 136     {
 137 	setSourceColor (cr, fillColor);
 138 	cairo_save (cr);
 139 	cairo_translate (cr, xc, yc);
 140 	if (radiusX > radiusY)
 141 	{
 142 	    cairo_scale (cr, 1.0, radiusY/radiusX);
 143 	    cairo_arc (cr, 0, 0, radiusX, 0, 2 * M_PI);
 144 	}
 145 	else
 146 	{
 147 	    cairo_scale (cr, radiusX/radiusY, 1.0);
 148 	    cairo_arc (cr, 0, 0, radiusY, 0, 2 * M_PI);
 149 	}
 150 	cairo_restore (cr);
 151 	cairo_fill_preserve (cr);
 152 	cairo_set_line_width (cr, strokeWidth);
 153 	setSourceColor (cr, strokeColor);
 154 	cairo_stroke (cr);
 155 
 156 	content = true;
 157     }
 158 }
 159 
 160 void
 161 AnnoScreen::drawRectangle (double	  x,
 162 			   double	  y,
 163 			   double	  w,
 164 			   double	  h,
 165 			   unsigned short *fillColor,
 166 			   unsigned short *strokeColor,
 167 			   double	  strokeWidth)
 168 {
 169     cairo_t *cr;
 170 
 171     cr = cairoContext ();
 172     if (cr)
 173     {
 174 	double  ex1, ey1, ex2, ey2;
 175 
 176 	setSourceColor (cr, fillColor);
 177 	cairo_rectangle (cr, x, y, w, h);
 178 	cairo_fill_preserve (cr);
 179 	cairo_set_line_width (cr, strokeWidth);
 180 	cairo_stroke_extents (cr, &ex1, &ey1, &ex2, &ey2);
 181 	setSourceColor (cr, strokeColor);
 182 	cairo_stroke (cr);
 183 
 184 	content = true;
 185     }
 186 }
 187 
 188 void
 189 AnnoScreen::drawLine (double	     x1,
 190 		      double	     y1,
 191 		      double	     x2,
 192 		      double	     y2,
 193 		      double	     width,
 194 		      unsigned short *color)
 195 {
 196     cairo_t *cr;
 197 
 198     cr = cairoContext ();
 199     if (cr)
 200     {
 201 	double ex1, ey1, ex2, ey2;
 202 
 203 	cairo_set_line_width (cr, width);
 204 	cairo_move_to (cr, x1, y1);
 205 	cairo_line_to (cr, x2, y2);
 206 	cairo_stroke_extents (cr, &ex1, &ey1, &ex2, &ey2);
 207 	cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
 208 	setSourceColor (cr, color);
 209 	cairo_stroke (cr);
 210 
 211 	content = true;
 212     }
 213 }
 214 
 215 void
 216 AnnoScreen::drawText (double	     		     x,
 217 		      double	     		     y,
 218 		      const char	     	     *text,
 219 		      const char	     	     *fontFamily,
 220 		      double	     		     fontSize,
 221 		      cairo_font_slant_t	     fontSlant,
 222 		      cairo_font_weight_t	     fontWeight,
 223 		      unsigned short 		     *fillColor,
 224 		      unsigned short 		     *strokeColor,
 225 		      double	     		     strokeWidth)
 226 {
 227     REGION reg;
 228     cairo_t *cr;
 229 
 230     cr = cairoContext ();
 231     if (cr)
 232     {
 233 	cairo_text_extents_t extents;
 234 
 235 	cairo_set_line_width (cr, strokeWidth);
 236 	setSourceColor (cr, fillColor);
 237 	cairo_select_font_face (cr, fontFamily, fontSlant, fontWeight);
 238 	cairo_set_font_size (cr, fontSize);
 239 	cairo_text_extents (cr, text, &extents);
 240 	cairo_save (cr);
 241 	cairo_move_to (cr, x, y);
 242 	cairo_text_path (cr, text);
 243 	cairo_fill_preserve (cr);
 244 	setSourceColor (cr, strokeColor);
 245 	cairo_stroke (cr);
 246 	cairo_restore (cr);
 247 
 248 	reg.rects    = &reg.extents;
 249 	reg.numRects = 1;
 250 
 251 	reg.extents.x1 = x;
 252 	reg.extents.y1 = y + extents.y_bearing - 2.0;
 253 	reg.extents.x2 = x + extents.width + 20.0;
 254 	reg.extents.y2 = y + extents.height;
 255 
 256 	content = true;
 257     }
 258 }
 259 
 260 /* DBUS Interface (TODO: plugin interface) */
 261 
 262 /* Here, you can use DBUS or any other plugin via the action system to draw on
 263  * the screen using cairo. Parameters are as follows:
 264  * "tool": ["rectangle", "circle", "line", "text"] default: "line"
 265  * - This allows you to select what you want to draw
 266  * Tool-specific parameters:
 267  * - * "circle"
 268  * - * - "xc" float, default: 0 - X Center
 269  * - * - "yc" float, default: 0 - Y Center
 270  * - * - "radius" float, default: 0 - Radius
 271  * - * "rectangle"
 272  * - * - "x" float, default: 0 - X Point
 273  * - * - "y" float, default: 0 - Y Point
 274  * - * - "width" float, default: 0 - Width
 275  * - * - "height" float, default: 0 - Height
 276  * - * "line"
 277  * - * - "x1" float, default: 0 - X Point 1
 278  * - * - "y1" float, default: 0 - Y Point 1
 279  * - * - "x2" float, default: 0 - X Point 2
 280  * - * - "y2" float, default: 0 - Y Point 2
 281  * - * "text"
 282  * - * - "slant" string, default: "" - ["oblique", "italic", ""] - Text Slant
 283  * - * - "weight" string, default: " - ["bold", ""] - Text Weight
 284  * - * - "text" string, default: "" - Any Character - The text to display
 285  * - * - "family" float, default: "Sans" - The font family
 286  * - * - "size" float, default: 36.0 - Font Size
 287  * - * - "x" float, default: 0 - X Point
 288  * - * - "u" float, default: 0 - Y Point
 289  * Other parameters are:
 290  * - * - "fill_color" float, default: 0 - Drawing Fill Color
 291  * - * - "stroke_color" float, default: 0 - Drawing Border Color
 292  * - * - "line_width" float, default: 0 - Drawing Width
 293  * - * - "stroke_width" float, default: 0 - Drawing Height
 294  * - * - All of these are taken from the builtin options if not provided
 295  */ 
 296 
 297 bool
 298 AnnoScreen::draw (CompAction         *action,
 299 		  CompAction::State  state,
 300 		  CompOption::Vector& options)
 301 {
 302     cairo_t *cr;
 303 
 304     cr = cairoContext ();
Condition "cr", taking true branch
Condition "cr", taking true branch
Condition "cr", taking true branch
Condition "cr", taking true branch
Condition "cr", taking true branch
 305     if (cr)
 306     {
 307         const char	*tool;
 308         unsigned short	*fillColor, *strokeColor;
 309         double		strokeWidth;
 310 
CID 12604 - WRAPPER_ESCAPE
Assigning: "tool" = "CompString(CompOption::getStringOptionNamed(options, CompString const("tool", std::allocator()), CompString const("line", std::allocator()))).c_str()", which extracts wrapped state from temporary "".
The internal representation of "" is freed by its destructor.
 311         tool =
 312 	 CompOption::getStringOptionNamed (options, "tool", "line").c_str ();
 313 
 314         cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
 315         cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
 316 
 317         fillColor = optionGetFillColor ();
 318         fillColor = CompOption::getColorOptionNamed (options, "fill_color",
 319 				         fillColor);
 320 
 321         strokeColor = optionGetStrokeColor ();
 322         strokeColor = CompOption::getColorOptionNamed (options,
 323 				           "stroke_color", strokeColor);
 324 
 325         strokeWidth = optionGetStrokeWidth ();
 326         strokeWidth = CompOption::getFloatOptionNamed (options, "stroke_width",
 327 				           strokeWidth);
 328 
CID 12604 - WRAPPER_ESCAPE
Using internal representation of destroyed object "temporary".
Condition "strcasecmp(tool, "rectangle") == 0", taking false branch
Condition "strcasecmp(tool, "rectangle") == 0", taking false branch
Condition "strcasecmp(tool, "rectangle") == 0", taking false branch
Condition "strcasecmp(tool, "rectangle") == 0", taking false branch
 329         if (strcasecmp (tool, "rectangle") == 0)
 330         {
 331 	    double x, y, w, h;
 332 
 333 	    x = CompOption::getFloatOptionNamed (options, "x", 0);
 334 	    y = CompOption::getFloatOptionNamed (options, "y", 0);
 335 	    w = CompOption::getFloatOptionNamed (options, "w", 100);
 336 	    h = CompOption::getFloatOptionNamed (options, "h", 100);
 337 
 338 	    drawRectangle (x, y, w, h, fillColor, strokeColor,
 339 			       strokeWidth);
 340         }
Condition "strcasecmp(tool, "ellipse") == 0", taking false branch
Condition "strcasecmp(tool, "ellipse") == 0", taking false branch
Condition "strcasecmp(tool, "ellipse") == 0", taking false branch
Condition "strcasecmp(tool, "ellipse") == 0", taking false branch
 341         else if (strcasecmp (tool, "ellipse") == 0)
 342         {
 343 	    double xc, yc, xr, yr;
 344 
 345 	    xc = CompOption::getFloatOptionNamed (options, "xc", 0);
 346 	    yc = CompOption::getFloatOptionNamed (options, "yc", 0);
 347 	    xr = CompOption::getFloatOptionNamed (options, "radiusX", 100);
 348 	    yr = CompOption::getFloatOptionNamed (options, "radiusY", 100);
 349 
 350 	    drawEllipse (xc, yc, xr, yr, fillColor, strokeColor,
 351 			    strokeWidth);
 352         }
Condition "strcasecmp(tool, "line") == 0", taking false branch
Condition "strcasecmp(tool, "line") == 0", taking false branch
Condition "strcasecmp(tool, "line") == 0", taking false branch
Condition "strcasecmp(tool, "line") == 0", taking false branch
 353         else if (strcasecmp (tool, "line") == 0)
 354         {
 355 	    double x1, y1, x2, y2;
 356 
 357 	    x1 = CompOption::getFloatOptionNamed (options, "x1", 0);
 358 	    y1 = CompOption::getFloatOptionNamed (options, "y1", 0);
 359 	    x2 = CompOption::getFloatOptionNamed (options, "x2", 100);
 360 	    y2 = CompOption::getFloatOptionNamed (options, "y2", 100);
 361 
 362 	    drawLine (x1, y1, x2, y2, strokeWidth, fillColor);
 363         }
Condition "strcasecmp(tool, "text") == 0", taking true branch
Condition "strcasecmp(tool, "text") == 0", taking true branch
Condition "strcasecmp(tool, "text") == 0", taking true branch
Condition "strcasecmp(tool, "text") == 0", taking true branch
 364         else if (strcasecmp (tool, "text") == 0)
 365         {
 366 	    double	     x, y, size;
 367 	    const char	     *text, *family;
 368 	    cairo_font_slant_t slant;
 369 	    cairo_font_weight_t weight;
 370 	    const char	     *str;
 371 
CID 12604 - WRAPPER_ESCAPE
Assigning: "str" = "CompString(CompOption::getStringOptionNamed(options, CompString const("slant", std::allocator()), CompString const("", std::allocator()))).c_str()", which extracts wrapped state from temporary "".
The internal representation of "" is freed by its destructor.
 372 	    str =
 373 	       CompOption::getStringOptionNamed (options, "slant", "").c_str ();
CID 12604 - WRAPPER_ESCAPE
Using internal representation of destroyed object "temporary".
Condition "strcasecmp(str, "oblique") == 0", taking true branch
Condition "strcasecmp(str, "oblique") == 0", taking true branch
Condition "strcasecmp(str, "oblique") == 0", taking true branch
 374 	    if (strcasecmp (str, "oblique") == 0)
 375 	        slant = CAIRO_FONT_SLANT_OBLIQUE;
 376 	    else if (strcasecmp (str, "italic") == 0)
 377 	        slant = CAIRO_FONT_SLANT_ITALIC;
 378 	    else
 379 	        slant = CAIRO_FONT_SLANT_NORMAL;
 380 
CID 12604 - WRAPPER_ESCAPE
Assigning: "str" = "CompString(CompOption::getStringOptionNamed(options, CompString const("weight", std::allocator()), CompString const("", std::allocator()))).c_str()", which extracts wrapped state from temporary "".
The internal representation of "" is freed by its destructor.
 381 	    str = 
 382 	      CompOption::getStringOptionNamed (options, "weight", "").c_str ();
CID 12604 - WRAPPER_ESCAPE
Using internal representation of destroyed object "temporary".
Condition "strcasecmp(str, "bold") == 0", taking true branch
Condition "strcasecmp(str, "bold") == 0", taking true branch
 383 	    if (strcasecmp (str, "bold") == 0)
 384 	        weight = CAIRO_FONT_WEIGHT_BOLD;
 385 	    else
 386 	        weight = CAIRO_FONT_WEIGHT_NORMAL;
 387 
 388 	    x      = CompOption::getFloatOptionNamed (options, "x", 0);
 389 	    y      = CompOption::getFloatOptionNamed (options, "y", 0);
CID 12604 - WRAPPER_ESCAPE
Assigning: "text" = "CompString(CompOption::getStringOptionNamed(options, CompString const("text", std::allocator()), CompString const("", std::allocator()))).c_str()", which extracts wrapped state from temporary "".
The internal representation of "" is freed by its destructor.
 390 	    text   = 
 391 		CompOption::getStringOptionNamed (options, "text", "").c_str ();
CID 12604 - WRAPPER_ESCAPE
Assigning: "family" = "CompString(CompOption::getStringOptionNamed(options, CompString const("family", std::allocator()), CompString const("Sans", std::allocator()))).c_str()", which extracts wrapped state from temporary "".
The internal representation of "" is freed by its destructor.
The internal representation of "" is freed by its destructor.
 392 	    family = CompOption::getStringOptionNamed (options, "family",
 393 				           "Sans").c_str ();
 394 	    size   = CompOption::getFloatOptionNamed (options, "size", 36.0);
 395 
CID 12604 - WRAPPER_ESCAPE
Using internal representation of destroyed object "temporary".
Using internal representation of destroyed object "temporary".
 396 	    drawText (x, y, text, family, size, slant, weight,
 397 		          fillColor, strokeColor, strokeWidth);
 398         }
 399     }
 400 
 401     return true;
 402 }
 403 
 404 bool
 405 AnnoScreen::terminate (CompAction         *action,
 406 		       CompAction::State  state,
 407 		       CompOption::Vector& options)
 408 {
 409     if (grabIndex)
 410     {
 411         screen->removeGrab (grabIndex, NULL);
 412         grabIndex = 0;
 413     }
 414 
 415     action->setState (action->state () & ~(CompAction::StateTermKey |
 416 					   CompAction::StateTermButton));
 417 
 418     switch (drawMode)
 419     {
 420     case LineMode:
 421 	drawLine (initialPointerX, initialPointerY,
 422 		  lineVector.x (), lineVector.y (),
 423 		  optionGetStrokeWidth (),
 424 		  optionGetStrokeColor ());
 425 	break;
 426 
 427     case RectangleMode:
 428 	drawRectangle (rectangle.x (),
 429 		       rectangle.y (),
 430 		       rectangle.width (),
 431 		       rectangle.height (),
 432 		       optionGetFillColor (),
 433 		       optionGetStrokeColor (),
 434 		       optionGetStrokeWidth ());
 435 	break;
 436 
 437     case EllipseMode:
 438 	drawEllipse (ellipse.center.x (),
 439 		     ellipse.center.y (),
 440 		     ellipse.radiusX,
 441 		     ellipse.radiusY,
 442 		     optionGetFillColor (),
 443 		     optionGetStrokeColor (),
 444 		     optionGetStrokeWidth ());
 445 	break;
 446 
 447     default:
 448 	break;
 449     }
 450 
 451     drawMode = NoMode;
 452 
 453     return false;
 454 }
 455 
 456 bool
 457 AnnoScreen::initiateErase (CompAction         *action,
 458 		           CompAction::State  state,
 459 		           CompOption::Vector& options)
 460 {
 461     if (screen->otherGrabExist (NULL))
 462         return false;
 463 
 464     if (!grabIndex)
 465         grabIndex = screen->pushGrab (None, "annotate");
 466 
 467     if (state & CompAction::StateInitButton)
 468         action->setState (action->state () | CompAction::StateTermButton);
 469 
 470     if (state & CompAction::StateInitKey)
 471         action->setState (action->state () | CompAction::StateTermKey);
 472 
 473     annoLastPointerX = pointerX;
 474     annoLastPointerY = pointerY;
 475 
 476     drawMode = EraseMode;
 477 
 478     screen->handleEventSetEnabled (this, true);
 479 
 480     return false;
 481 }
 482 
 483 bool
 484 AnnoScreen::initiateFreeDraw (CompAction         *action,
 485 			      CompAction::State  state,
 486 			      CompOption::Vector& options)
 487 {
 488     if (screen->otherGrabExist (NULL))
 489         return false;
 490 
 491     if (!grabIndex)
 492         grabIndex = screen->pushGrab (None, "annotate");
 493 
 494     if (state & CompAction::StateInitButton)
 495         action->setState (action->state () | CompAction::StateTermButton);
 496 
 497     if (state & CompAction::StateInitKey)
 498         action->setState (action->state () | CompAction::StateTermKey);
 499 
 500     annoLastPointerX = pointerX;
 501     annoLastPointerY = pointerY;
 502 
 503     drawMode = FreeDrawMode;
 504 
 505     screen->handleEventSetEnabled (this, true);
 506 
 507     return true;
 508 }
 509 
 510 bool
 511 AnnoScreen::initiateLine (CompAction         *action,
 512 			  CompAction::State  state,
 513 			  CompOption::Vector& options)
 514 {
 515     if (screen->otherGrabExist (NULL))
 516         return false;
 517 
 518     if (!grabIndex)
 519         grabIndex = screen->pushGrab (None, "annotate");
 520 
 521     if (state & CompAction::StateInitButton)
 522         action->setState (action->state () | CompAction::StateTermButton);
 523 
 524     if (state & CompAction::StateInitKey)
 525         action->setState (action->state () | CompAction::StateTermKey);
 526 
 527     initialPointerX = pointerX;
 528     initialPointerY = pointerY;
 529 
 530     drawMode = LineMode;
 531 
 532     screen->handleEventSetEnabled (this, true);
 533 
 534     return true;
 535 }
 536 
 537 bool
 538 AnnoScreen::initiateRectangle (CompAction         *action,
 539 			       CompAction::State  state,
 540 			       CompOption::Vector& options)
 541 {
 542     if (screen->otherGrabExist (NULL))
 543         return false;
 544 
 545     if (!grabIndex)
 546         grabIndex = screen->pushGrab (None, "annotate");
 547 
 548     if (state & CompAction::StateInitButton)
 549         action->setState (action->state () | CompAction::StateTermButton);
 550 
 551     if (state & CompAction::StateInitKey)
 552         action->setState (action->state () | CompAction::StateTermKey);
 553 
 554     drawMode = RectangleMode;
 555 
 556     initialPointerX = pointerX;
 557     initialPointerY = pointerY;
 558     rectangle.setGeometry (initialPointerX, initialPointerY, 0, 0);
 559     lastRect = rectangle;
 560 
 561     screen->handleEventSetEnabled (this, true);
 562 
 563     return true;
 564 }
 565 
 566 bool
 567 AnnoScreen::initiateEllipse (CompAction         *action,
 568 			     CompAction::State  state,
 569 			     CompOption::Vector& options)
 570 {
 571     if (screen->otherGrabExist (NULL))
 572         return false;
 573 
 574     if (!grabIndex)
 575         grabIndex = screen->pushGrab (None, "annotate");
 576 
 577     if (state & CompAction::StateInitButton)
 578         action->setState (action->state () | CompAction::StateTermButton);
 579 
 580     if (state & CompAction::StateInitKey)
 581         action->setState (action->state () | CompAction::StateTermKey);
 582 
 583     drawMode = EllipseMode;
 584 
 585     initialPointerX = pointerX;
 586     initialPointerY = pointerY;
 587     ellipse.radiusX = 0;
 588     ellipse.radiusY = 0;
 589     lastRect.setGeometry (initialPointerX, initialPointerY, 0, 0);
 590 
 591     screen->handleEventSetEnabled (this, true);
 592 
 593     return true;
 594 }
 595 
 596 bool
 597 AnnoScreen::clear (CompAction         *action,
 598 		   CompAction::State  state,
 599 		   CompOption::Vector& options)
 600 {
 601     if (content)
 602     {
 603         cairo_t *cr;
 604 
 605         cr = cairoContext ();
 606         if (cr)
 607 	    cairoClear (cairo);
 608 
 609         cScreen->damageScreen ();
 610 
 611 	/* We don't need to refresh the screen or handle events anymore */
 612 	screen->handleEventSetEnabled (this, false);
 613 	gScreen->glPaintOutputSetEnabled (this, false);
 614     }
 615 
 616     return true;
 617 }
 618 
 619 bool
 620 AnnoScreen::glPaintOutput (const GLScreenPaintAttrib &attrib,
 621 			   const GLMatrix	     &transform,
 622 			   const CompRegion	     &region,
 623 			   CompOutput 		     *output,
 624 			   unsigned int		     mask)
 625 {
 626     bool status;
 627 
 628     status = gScreen->glPaintOutput (attrib, transform, region, output, mask);
 629 
 630     if (status)
 631     {
 632 	GLVertexBuffer *streamingBuffer = GLVertexBuffer::streamingBuffer ();
 633 	GLfloat         vertexData[18];
 634 	GLfloat         textureData[12];
 635 	CompRect	rect;
 636 	GLMatrix	sTransform = transform;
 637 	int		numRect;
 638 	int		pos = 0;
 639 	float		offset;
 640 	int		angle;
 641 
 642 	offset = optionGetStrokeWidth () / 2;
 643 
 644 	/* This replaced prepareXCoords (s, output, -DEFAULT_Z_CAMERA) */
 645 	sTransform.toScreenSpace (output, -DEFAULT_Z_CAMERA);
 646 
 647 	glEnable (GL_BLEND);
 648 
 649 	if (content && !region.isEmpty ())
 650 	{
 651 	    foreach (GLTexture *tex, texture)
 652 	    {
 653 	        CompRect::vector rect = region.rects ();
 654 	        numRect = region.rects ().size ();
 655 
 656 	        tex->enable (GLTexture::Fast);
 657 
 658 	        streamingBuffer->begin (GL_TRIANGLES);
 659 
 660 	        while (numRect--)
 661 	        {
 662 		    GLfloat tx1 = COMP_TEX_COORD_X (tex->matrix (),
 663 		                                       rect.at (pos).x1 ());
 664 		    GLfloat tx2 = COMP_TEX_COORD_X (tex->matrix (),
 665 		                                       rect.at (pos).x2 ());
 666 		    GLfloat ty1 = COMP_TEX_COORD_Y (tex->matrix (),
 667 		                                       rect.at (pos).y1 ());
 668 		    GLfloat ty2 = COMP_TEX_COORD_Y (tex->matrix (),
 669 		                                       rect.at (pos).y2 ());
 670 
 671 		    vertexData[0]  = rect.at (pos).x1 ();
 672 		    vertexData[1]  = rect.at (pos).y1 ();
 673 		    vertexData[2]  = 0.0f;
 674 		    vertexData[3]  = rect.at (pos).x1 ();
 675 		    vertexData[4]  = rect.at (pos).y2 ();
 676 		    vertexData[5]  = 0.0f;
 677 		    vertexData[6]  = rect.at (pos).x2 ();
 678 		    vertexData[7]  = rect.at (pos).y1 ();
 679 		    vertexData[8]  = 0.0f;
 680 		    vertexData[9]  = rect.at (pos).x1 ();
 681 		    vertexData[10] = rect.at (pos).y2 ();
 682 		    vertexData[11] = 0.0f;
 683 
 684 		    vertexData[12] = rect.at (pos).x2 ();
 685 		    vertexData[13] = rect.at (pos).y2 ();
 686 		    vertexData[14] = 0.0f;
 687 
 688 		    vertexData[15] = rect.at (pos).x2 ();
 689 		    vertexData[16] = rect.at (pos).y1 ();
 690 		    vertexData[17] = 0.0f;
 691 
 692 		    textureData[0]  = tx1;
 693 		    textureData[1]  = ty1;
 694 
 695 		    textureData[2]  = tx1;
 696 		    textureData[3]  = ty2;
 697 
 698 		    textureData[4]  = tx2;
 699 		    textureData[5]  = ty1;
 700 
 701 		    textureData[6]  = tx1;
 702 		    textureData[7]  = ty2;
 703 
 704 		    textureData[8]  = tx2;
 705 		    textureData[9]  = ty2;
 706 
 707 		    textureData[10] = tx2;
 708 		    textureData[11] = ty1;
 709 
 710 		    streamingBuffer->addVertices (6, vertexData);
 711 		    streamingBuffer->addTexCoords (0, 6, textureData);
 712 	            pos++;
 713 	        }
 714 
 715 		streamingBuffer->end ();
 716 		streamingBuffer->render (sTransform);
 717 
 718 	        tex->disable ();
 719 	    }
 720 	}
 721 
 722 	switch (drawMode)
 723 	{
 724 	case LineMode:
 725 	    glLineWidth (optionGetStrokeWidth ());
 726 
 727 	    streamingBuffer->begin (GL_LINES);
 728 
 729 	    streamingBuffer->addColors (1, optionGetStrokeColor ());
 730 
 731 	    vertexData[0] = initialPointerX;
 732 	    vertexData[1] = initialPointerY;
 733 	    vertexData[2] = 0.0f;
 734 	    vertexData[3] = lineVector.x ();
 735 	    vertexData[4] = lineVector.y ();
 736 	    vertexData[5] = 0.0f;
 737 	    streamingBuffer->addVertices (2, vertexData);
 738 
 739 	    streamingBuffer->end ();
 740 	    streamingBuffer->render (sTransform);
 741 	    break;
 742 
 743 	case RectangleMode:
 744 	    vertexData[0]  = rectangle.x1 ();
 745 	    vertexData[1]  = rectangle.y1 ();
 746 	    vertexData[2]  = 0.0f;
 747 	    vertexData[3]  = rectangle.x1 ();
 748 	    vertexData[4]  = rectangle.y2 ();
 749 	    vertexData[5]  = 0.0f;
 750 	    vertexData[6]  = rectangle.x2 ();
 751 	    vertexData[7]  = rectangle.y1 ();
 752 	    vertexData[8]  = 0.0f;
 753 	    vertexData[9]  = rectangle.x2 ();
 754 	    vertexData[10] = rectangle.y2 ();
 755 	    vertexData[11] = 0.0f;
 756 
 757 	    /* fill rectangle */
 758 	    streamingBuffer->begin (GL_TRIANGLE_STRIP);
 759 
 760 	    streamingBuffer->addColors (1, optionGetFillColor ());
 761 	    streamingBuffer->addVertices (4, vertexData);
 762 
 763 	    streamingBuffer->end ();
 764 	    streamingBuffer->render (sTransform);
 765 
 766 	    /* draw rectangle outline */
 767 /*	    streamingBuffer->begin ();
 768 
 769 	    streamingBuffer->addColors (1, optionGetStrokeColor ());
 770 
 771 	    vertexData[0] = rectangle.x1 () - offset;
 772 	    vertexData[3] = rectangle.x1 () - offset;
 773 	    streamingBuffer->addVertices (4, vertexData);
 774 
 775 	    glRecti (rectangle.x2 () - offset, rectangle.y2 (),
 776 		     rectangle.x2 () + offset, rectangle.y1 ());
 777 	    glRecti (rectangle.x1 () - offset, rectangle.y1 () + offset,
 778 		     rectangle.x2 () + offset, rectangle.y1 () - offset);
 779 	    glRecti (rectangle.x1 () - offset, rectangle.y2 () + offset,
 780 		     rectangle.x2 () + offset, rectangle.y2 () - offset);*/
 781 	    break;
 782 
 783 	case EllipseMode:
 784 	    /* fill ellipse */
 785 	    streamingBuffer->begin (GL_TRIANGLE_FAN);
 786 
 787 	    streamingBuffer->addColors (1, optionGetFillColor ());
 788 
 789 	    vertexData[0] = ellipse.center.x ();
 790 	    vertexData[1] = ellipse.center.y ();
 791 	    vertexData[2] = 0.0f;
 792 	    streamingBuffer->addVertices (1, vertexData);
 793 
 794 	    for (angle = 0; angle <= 360; angle += 1)
 795 	    {
 796 		vertexData[0] = ellipse.center.x () +
 797 			 (ellipse.radiusX * sinf (angle * DEG2RAD));
 798 		vertexData[1] = ellipse.center.y () +
 799 			 (ellipse.radiusY * cosf (angle * DEG2RAD));
 800 		streamingBuffer->addVertices (1, vertexData);
 801 	    }
 802 
 803 	    vertexData[0] = ellipse.center.x ();
 804 	    vertexData[1] = ellipse.center.y () + ellipse.radiusY;
 805 	    streamingBuffer->addVertices (1, vertexData);
 806 
 807 	    streamingBuffer->end ();
 808 	    streamingBuffer->render (sTransform);
 809 
 810 	    /* draw ellipse outline */
 811 	    glLineWidth (optionGetStrokeWidth ());
 812 
 813 	    streamingBuffer->begin (GL_TRIANGLE_STRIP);
 814 
 815 	    streamingBuffer->addColors (1, optionGetStrokeColor ());
 816 
 817 
 818 	    vertexData[0] = ellipse.center.x ();
 819 	    vertexData[1] = ellipse.center.y () + ellipse.radiusY - offset;
 820 	    vertexData[2] = 0.0f;
 821 	    streamingBuffer->addVertices (1, vertexData);
 822 
 823 	    for (angle = 360; angle >= 0; angle -= 1)
 824 	    {
 825 		vertexData[0] = ellipse.center.x () + ((ellipse.radiusX -
 826 			  offset) * sinf (angle * DEG2RAD));
 827 		vertexData[1] = ellipse.center.y () + ((ellipse.radiusY -
 828 			  offset) * cosf (angle * DEG2RAD));
 829 		vertexData[2] = 0.0f;
 830 		vertexData[3] = ellipse.center.x () + ((ellipse.radiusX +
 831 			  offset) * sinf (angle * DEG2RAD));
 832 		vertexData[4] = ellipse.center.y () + ((ellipse.radiusY +
 833 			  offset) * cosf (angle * DEG2RAD));
 834 		vertexData[5] = 0.0f;
 835 		streamingBuffer->addVertices (2, vertexData);
 836 	    }
 837 
 838 	    vertexData[0] = ellipse.center.x ();
 839 	    vertexData[1] = ellipse.center.y () + ellipse.radiusY + offset;
 840 	    streamingBuffer->addVertices (1, vertexData);
 841 
 842 	    streamingBuffer->end ();
 843 	    streamingBuffer->render (sTransform);
 844 	    break;
 845 
 846 	default:
 847 	    break;
 848 	}
 849 
 850 	glDisable (GL_BLEND);
 851     }
 852 
 853     return status;
 854 }
 855 
 856 void
 857 AnnoScreen::handleMotionEvent (int	  xRoot,
 858 		       	       int	  yRoot)
 859 {
 860     CompRect damageRect;
 861 
 862     if (grabIndex)
 863     {
 864 	static unsigned short clearColor[] = { 0, 0, 0, 0 };
 865 	switch (drawMode)
 866 	{
 867 	case EraseMode:
 868 	    drawLine (annoLastPointerX, annoLastPointerY,
 869 		      xRoot, yRoot,
 870 		      optionGetEraseWidth (), clearColor);
 871 	    break;
 872 
 873 	case FreeDrawMode:
 874 	    drawLine (annoLastPointerX, annoLastPointerY,
 875 		      xRoot, yRoot,
 876 		      optionGetStrokeWidth (),
 877 		      optionGetStrokeColor ());
 878 	    break;
 879 
 880 	case LineMode:
 881 	    lineVector.setX (xRoot);
 882 	    lineVector.setY (yRoot);
 883 
 884 	    damageRect.setGeometry (MIN(initialPointerX, lineVector.x ()),
 885 				    MIN(initialPointerY, lineVector.y ()),
 886 				    abs (lineVector.x () - initialPointerX),
 887 				    abs (lineVector.y () - initialPointerY));
 888 	    break;
 889 
 890 	case RectangleMode:
 891 	    if (optionGetDrawShapesFromCenter ())
 892 		rectangle.setGeometry (initialPointerX -
 893 				       abs (xRoot - initialPointerX),
 894 				       initialPointerY -
 895 				       abs (yRoot - initialPointerY),
 896 				      (abs (xRoot - initialPointerX)) * 2,
 897 				      (abs (yRoot - initialPointerY)) * 2);
 898 	    else
 899 		rectangle.setGeometry (MIN(initialPointerX, xRoot),
 900 				       MIN(initialPointerY, yRoot),
 901 				       abs (xRoot - initialPointerX),
 902 				       abs (yRoot - initialPointerY));
 903 
 904 	    damageRect = rectangle;
 905 	    break;
 906 
 907 	case EllipseMode:
 908 	    if (optionGetDrawShapesFromCenter ())
 909 	    {
 910 		ellipse.center.setX (initialPointerX);
 911 		ellipse.center.setY (initialPointerY);
 912 	    }
 913 	    else
 914 	    {
 915 		ellipse.center.setX (initialPointerX +
 916 				    (xRoot - initialPointerX) / 2);
 917 		ellipse.center.setY (initialPointerY +
 918 				    (yRoot - initialPointerY) / 2);
 919 	    }
 920 
 921 	    ellipse.radiusX = abs (xRoot - ellipse.center.x ());
 922 	    ellipse.radiusY = abs (yRoot - ellipse.center.y ());
 923 
 924 	    damageRect = CompRect (ellipse.center.x () - ellipse.radiusX,
 925 				   ellipse.center.y () - ellipse.radiusY,
 926 				   ellipse.radiusX * 2,
 927 				   ellipse.radiusY * 2);
 928 	    break;
 929 
 930 	default:
 931 	    break;
 932 	}
 933 
 934 	if (cScreen && (drawMode == LineMode ||
 935 			drawMode == RectangleMode ||
 936 			drawMode == EllipseMode))
 937 	{
 938 	    /* Add border width to the damage region */
 939 	    damageRect.setGeometry (damageRect.x () -
 940 				    (optionGetStrokeWidth () / 2),
 941 				    damageRect.y () -
 942 				    (optionGetStrokeWidth () / 2),
 943 				    damageRect.width () +
 944 				    optionGetStrokeWidth () + 1,
 945 				    damageRect.height () +
 946 				    optionGetStrokeWidth () + 1);
 947 
 948 	    cScreen->damageRegion (damageRect);
 949 	    cScreen->damageRegion (lastRect);
 950 
 951 	    lastRect = damageRect;
 952 	}
 953 
 954 	annoLastPointerX = xRoot;
 955 	annoLastPointerY = yRoot;
 956 
 957 	gScreen->glPaintOutputSetEnabled (this, true);
 958     }
 959 }
 960 
 961 void
 962 AnnoScreen::handleEvent (XEvent      *event)
 963 {
 964     switch (event->type) {
 965     case MotionNotify:
 966 	handleMotionEvent (pointerX, pointerY);
 967     case EnterNotify:
 968     case LeaveNotify:
 969 	handleMotionEvent (pointerX, pointerY);
 970     default:
 971 	if (event->type == cScreen->damageEvent () + XDamageNotify)
 972 	{
 973 	    XDamageNotifyEvent *de = (XDamageNotifyEvent *) event;
 974 	    if (pixmap == de->drawable)
 975 		cScreen->damageRegion (CompRegion (CompRect (de->area)));
 976 	}
 977 	break;
 978     }
 979 
 980     screen->handleEvent (event);
 981 }
 982 
 983 AnnoScreen::AnnoScreen (CompScreen *screen) :
 984     PluginClassHandler <AnnoScreen, CompScreen> (screen),
 985     cScreen (CompositeScreen::get (screen)),
 986     gScreen (GLScreen::get (screen)),
 987     grabIndex (0),
 988     pixmap (None),
 989     surface (NULL),
 990     cairo (NULL),
 991     content (false),
 992     damage (None)
 993 {
 994     ScreenInterface::setHandler (screen, false);
 995     GLScreenInterface::setHandler (gScreen, false);
 996 
 997     optionSetDrawInitiate
 998 	(boost::bind (&AnnoScreen::draw, this, _1, _2, _3));
 999     optionSetEraseButtonInitiate
1000 	(boost::bind (&AnnoScreen::initiateErase, this, _1, _2, _3));
1001     optionSetEraseButtonTerminate
1002 	(boost::bind (&AnnoScreen::terminate, this, _1, _2, _3));
1003     optionSetInitiateFreeDrawButtonInitiate
1004 	(boost::bind (&AnnoScreen::initiateFreeDraw, this, _1, _2, _3));
1005     optionSetInitiateFreeDrawButtonTerminate
1006 	(boost::bind (&AnnoScreen::terminate, this, _1, _2, _3));
1007     optionSetInitiateLineButtonInitiate
1008 	(boost::bind (&AnnoScreen::initiateLine, this, _1, _2, _3));
1009     optionSetInitiateLineButtonTerminate
1010 	(boost::bind (&AnnoScreen::terminate, this, _1, _2, _3));
1011     optionSetInitiateRectangleButtonInitiate
1012 	(boost::bind (&AnnoScreen::initiateRectangle, this, _1, _2, _3));
1013     optionSetInitiateRectangleButtonTerminate
1014 	(boost::bind (&AnnoScreen::terminate, this, _1, _2, _3));
1015     optionSetInitiateEllipseButtonInitiate
1016 	(boost::bind (&AnnoScreen::initiateEllipse, this, _1, _2, _3));
1017     optionSetInitiateEllipseButtonTerminate
1018 	(boost::bind (&AnnoScreen::terminate, this, _1, _2, _3));
1019     optionSetClearKeyInitiate
1020 	(boost::bind (&AnnoScreen::clear, this, _1, _2, _3));
1021     drawMode = NoMode;
1022 }
1023 
1024 AnnoScreen::~AnnoScreen ()
1025 {
1026     if (cairo)
1027 	cairo_destroy (cairo);
1028     if (surface)
1029 	cairo_surface_destroy (surface);
1030     if (pixmap)
1031 	XFreePixmap (screen->dpy (), pixmap);
1032     if (damage)
1033 	XDamageDestroy (screen->dpy (), damage);
1034 }
1035 
1036 bool
1037 AnnoPluginVTable::init ()
1038 {
1039     if (!CompPlugin::checkPluginABI ("core", CORE_ABIVERSION) ||
1040 	!CompPlugin::checkPluginABI ("composite", COMPIZ_COMPOSITE_ABI) ||
1041 	!CompPlugin::checkPluginABI ("opengl", COMPIZ_OPENGL_ABI))
1042 	return false;
1043 
1044     return true;
1045 }