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 = ®.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 ®ion,
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 }