1 /*
2 * Copyright �� 2008 Dennis Kasprzyk
3 * Copyright �� 2007 Novell, Inc.
4 *
5 * Permission to use, copy, modify, distribute, and sell this software
6 * and its documentation for any purpose is hereby granted without
7 * fee, provided that the above copyright notice appear in all copies
8 * and that both that copyright notice and this permission notice
9 * appear in supporting documentation, and that the name of
10 * Dennis Kasprzyk not be used in advertising or publicity pertaining to
11 * distribution of the software without specific, written prior permission.
12 * Dennis Kasprzyk makes no representations about the suitability of this
13 * software for any purpose. It is provided "as is" without express or
14 * implied warranty.
15 *
16 * DENNIS KASPRZYK DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
18 * NO EVENT SHALL DENNIS KASPRZYK BE LIABLE FOR ANY SPECIAL, INDIRECT OR
19 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
20 * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
21 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
22 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 *
24 * Authors: Dennis Kasprzyk <onestone@compiz-fusion.org>
25 * David Reveman <davidr@novell.com>
26 */
27
28 #ifdef HAVE_CONFIG_H
29 # include <config.h>
30 #endif
31
32 #include <sys/time.h>
33
34 #include <X11/Xlib.h>
35 #include <X11/Xatom.h>
36 #include <X11/Xproto.h>
37 #include <X11/extensions/Xcomposite.h>
38 #include <X11/extensions/Xrandr.h>
39 #include <X11/extensions/shape.h>
40
41 #include "privates.h"
42
43 #include <X11/extensions/shape.h>
44 #include <X11/extensions/Xrandr.h>
45
46 #include <core/timer.h>
47
48 template class WrapableInterface<CompositeScreen, CompositeScreenInterface>;
49
50 static const int FALLBACK_REFRESH_RATE = 60; /* if all else fails */
51
52 CompWindow *lastDamagedWindow = 0;
53
54 void
55 PrivateCompositeScreen::handleEvent (XEvent *event)
56 {
57 CompWindow *w;
58
59 switch (event->type) {
60
61 case CreateNotify:
62 if (screen->root () == event->xcreatewindow.parent)
63 {
64 /* The first time some client asks for the composite
65 * overlay window, the X server creates it, which causes
66 * an errorneous CreateNotify event. We catch it and
67 * ignore it. */
68 if (overlay == event->xcreatewindow.window)
69 return;
70 }
71 break;
72 case PropertyNotify:
73 if (event->xproperty.atom == Atoms::winOpacity)
74 {
75 w = screen->findWindow (event->xproperty.window);
76 if (w)
77 CompositeWindow::get (w)->updateOpacity ();
78 }
79 else if (event->xproperty.atom == Atoms::winBrightness)
80 {
81 w = screen->findWindow (event->xproperty.window);
82 if (w)
83 CompositeWindow::get (w)->updateBrightness ();
84 }
85 else if (event->xproperty.atom == Atoms::winSaturation)
86 {
87 w = screen->findWindow (event->xproperty.window);
88 if (w)
89 CompositeWindow::get (w)->updateSaturation ();
90 }
91 break;
92 default:
93 if (shapeExtension &&
94 event->type == shapeEvent + ShapeNotify)
95 {
96 w = screen->findWindow (((XShapeEvent *) event)->window);
97 if (w)
98 {
99 if (w->mapNum ())
100 {
101 CompositeWindow::get (w)->addDamage ();
102 }
103 }
104 }
105 else if (event->type == damageEvent + XDamageNotify)
106 {
107 XDamageNotifyEvent *de = (XDamageNotifyEvent*)event;
108 damages[de->damage] = de->area;
109 }
110 break;
111 }
112
113 screen->handleEvent (event);
114
115 switch (event->type) {
116 case Expose:
117 handleExposeEvent (&event->xexpose);
118 break;
119 case ClientMessage:
120 if (event->xclient.message_type == Atoms::winOpacity)
121 {
122 w = screen->findWindow (event->xclient.window);
123 if (w && (w->type () & CompWindowTypeDesktopMask) == 0)
124 {
125 unsigned short opacity = event->xclient.data.l[0] >> 16;
126
127 screen->setWindowProp32 (w->id (),
128 Atoms::winOpacity, opacity);
129 }
130 }
131 else if (event->xclient.message_type ==
132 Atoms::winBrightness)
133 {
134 w = screen->findWindow (event->xclient.window);
135 if (w)
136 {
137 unsigned short brightness = event->xclient.data.l[0] >> 16;
138
139 screen->setWindowProp32 (w->id (),
140 Atoms::winBrightness, brightness);
141 }
142 }
143 else if (event->xclient.message_type ==
144 Atoms::winSaturation)
145 {
146 w = screen->findWindow (event->xclient.window);
147 if (w)
148 {
149 unsigned short saturation = event->xclient.data.l[0] >> 16;
150
151 screen->setWindowProp32 (w->id (),
152 Atoms::winSaturation, saturation);
153 }
154 }
155 break;
156 default:
157 if (event->type == damageEvent + XDamageNotify)
158 {
159 XDamageNotifyEvent *de = (XDamageNotifyEvent *) event;
160
161 if (lastDamagedWindow && de->drawable == lastDamagedWindow->id ())
162 {
163 w = lastDamagedWindow;
164 }
165 else
166 {
167 w = screen->findWindow (de->drawable);
168 if (w)
169 lastDamagedWindow = w;
170 }
171
172 if (w)
173 CompositeWindow::get (w)->processDamage (de);
174 }
175 else if (shapeExtension &&
176 event->type == shapeEvent + ShapeNotify)
177 {
178 w = screen->findWindow (((XShapeEvent *) event)->window);
179 if (w)
180 {
181 if (w->mapNum ())
182 {
183 CompositeWindow::get (w)->addDamage ();
184 }
185 }
186 }
187 else if (randrExtension &&
188 event->type == randrEvent + RRScreenChangeNotify)
189 {
190 XRRScreenChangeNotifyEvent *rre;
191
192 rre = (XRRScreenChangeNotifyEvent *) event;
193
194 if (screen->root () == rre->root)
195 detectRefreshRate ();
196 }
197 break;
198 }
199 }
200
201 int
202 CompositeScreen::damageEvent ()
203 {
204 return priv->damageEvent;
205 }
206
207
208 template class PluginClassHandler<CompositeScreen, CompScreen, COMPIZ_COMPOSITE_ABI>;
209
210 CompositeScreen::CompositeScreen (CompScreen *s) :
211 PluginClassHandler<CompositeScreen, CompScreen, COMPIZ_COMPOSITE_ABI> (s),
212 priv (new PrivateCompositeScreen (this))
213 {
214 if (!XQueryExtension (s->dpy (), COMPOSITE_NAME,
215 &priv->compositeOpcode,
216 &priv->compositeEvent,
217 &priv->compositeError))
218 {
219 compLogMessage ("core", CompLogLevelFatal,
220 "No composite extension");
221 setFailed ();
222 return;
223 }
224
225 int compositeMajor, compositeMinor;
226
227 XCompositeQueryVersion (s->dpy (), &compositeMajor, &compositeMinor);
228 if (compositeMajor == 0 && compositeMinor < 2)
229 {
230 compLogMessage ("core", CompLogLevelFatal,
231 "Old composite extension");
232 setFailed ();
233 return;
234 }
235
236 if (!XDamageQueryExtension (s->dpy (), &priv->damageEvent,
237 &priv->damageError))
238 {
239 compLogMessage ("core", CompLogLevelFatal,
240 "No damage extension");
241 setFailed ();
242 return;
243 }
244
245 if (!XFixesQueryExtension (s->dpy (), &priv->fixesEvent, &priv->fixesError))
246 {
247 compLogMessage ("core", CompLogLevelFatal,
248 "No fixes extension");
249 setFailed ();
250 return;
251 }
252
253 priv->shapeExtension = XShapeQueryExtension (s->dpy (), &priv->shapeEvent,
254 &priv->shapeError);
255 priv->randrExtension = XRRQueryExtension (s->dpy (), &priv->randrEvent,
256 &priv->randrError);
257
258 priv->makeOutputWindow ();
259
260 priv->detectRefreshRate ();
261
262 priv->slowAnimations = false;
263
264 if (!priv->init ())
265 {
266 setFailed ();
267 }
268
269 }
270
271 CompositeScreen::~CompositeScreen ()
272 {
273 priv->paintTimer.stop ();
274 XCompositeReleaseOverlayWindow (screen->dpy (),
275 screen->root ());
276 delete priv;
277 }
278
279
280 PrivateCompositeScreen::PrivateCompositeScreen (CompositeScreen *cs) :
281 cScreen (cs),
282 compositeEvent (0),
283 compositeError (0),
284 compositeOpcode (0),
285 damageEvent (0),
286 damageError (0),
287 fixesEvent (0),
288 fixesError (0),
289 fixesVersion (0),
290 shapeExtension (false),
291 shapeEvent (0),
292 shapeError (0),
293 randrExtension (false),
294 randrEvent (0),
295 randrError (0),
296 damageMask (COMPOSITE_SCREEN_DAMAGE_ALL_MASK),
297 overlay (None),
298 output (None),
299 exposeRects (),
300 windowPaintOffset (0, 0),
301 overlayWindowCount (0),
302 outputShapeChanged (false),
303 redrawTime (1000 / FALLBACK_REFRESH_RATE),
304 optimalRedrawTime (1000 / FALLBACK_REFRESH_RATE),
305 scheduled (false),
306 painting (false),
307 reschedule (false),
308 slowAnimations (false),
309 pHnd (NULL),
310 FPSLimiterMode (CompositeFPSLimiterModeDefault),
311 withDestroyedWindows (),
312 cmSnAtom (0),
313 newCmSnOwner (None)
314 {
315 gettimeofday (&lastRedraw, 0);
316 // wrap outputChangeNotify
317 ScreenInterface::setHandler (screen);
318
319 optionSetSlowAnimationsKeyInitiate (CompositeScreen::toggleSlowAnimations);
320 }
321
322 PrivateCompositeScreen::~PrivateCompositeScreen ()
323 {
324 Display *dpy = screen->dpy ();
325
326 if (cmSnAtom)
327 XSetSelectionOwner (dpy, cmSnAtom, None, CurrentTime);
328
329 if (newCmSnOwner != None)
330 XDestroyWindow (dpy, newCmSnOwner);
331 }
332
333 bool
334 PrivateCompositeScreen::init ()
335 {
336 Display *dpy = screen->dpy ();
337 Time cmSnTimestamp = 0;
338 XEvent event;
339 XSetWindowAttributes attr;
340 Window currentCmSnOwner;
341 char buf[128];
342
CID 12511 - SECURE_CODING
[VERY RISKY]. Using "sprintf" can cause a buffer overflow when done incorrectly. Because sprintf() assumes an arbitrarily long string, callers must be careful not to overflow the actual space of the destination. Use snprintf() instead, or correct precision specifiers.
343 sprintf (buf, "_NET_WM_CM_S%d", screen->screenNum ());
344 cmSnAtom = XInternAtom (dpy, buf, 0);
345
346 currentCmSnOwner = XGetSelectionOwner (dpy, cmSnAtom);
347
348 if (currentCmSnOwner != None)
349 {
350 if (!replaceCurrentWm)
351 {
352 compLogMessage (
353 "composite", CompLogLevelError,
354 "Screen %d on display \"%s\" already has a compositing "
355 "manager (%x); try using the --replace option to replace "
356 "the current compositing manager.",
357 screen->screenNum (), DisplayString (dpy), currentCmSnOwner);
358
359 return false;
360 }
361 }
362
363 attr.override_redirect = true;
364 attr.event_mask = PropertyChangeMask;
365
366 newCmSnOwner =
367 XCreateWindow (dpy, screen->root (),
368 -100, -100, 1, 1, 0,
369 CopyFromParent, CopyFromParent,
370 CopyFromParent,
371 CWOverrideRedirect | CWEventMask,
372 &attr);
373
374 XChangeProperty (dpy, newCmSnOwner, Atoms::wmName, Atoms::utf8String, 8,
375 PropModeReplace, (unsigned char *) PACKAGE,
376 strlen (PACKAGE));
377
378 XWindowEvent (dpy, newCmSnOwner, PropertyChangeMask, &event);
379
380 cmSnTimestamp = event.xproperty.time;
381
382 XSetSelectionOwner (dpy, cmSnAtom, newCmSnOwner, cmSnTimestamp);
383
384 if (XGetSelectionOwner (dpy, cmSnAtom) != newCmSnOwner)
385 {
386 compLogMessage ("core", CompLogLevelError,
387 "Could not acquire compositing manager "
388 "selection on screen %d display \"%s\"",
389 screen->screenNum (), DisplayString (dpy));
390
391 return false;
392 }
393
394 /* Send client message indicating that we are now the compositing manager */
395 event.xclient.type = ClientMessage;
396 event.xclient.window = screen->root ();
397 event.xclient.message_type = Atoms::manager;
398 event.xclient.format = 32;
399 event.xclient.data.l[0] = cmSnTimestamp;
400 event.xclient.data.l[1] = cmSnAtom;
401 event.xclient.data.l[2] = 0;
402 event.xclient.data.l[3] = 0;
403 event.xclient.data.l[4] = 0;
404
405 XSendEvent (dpy, screen->root (), FALSE, StructureNotifyMask, &event);
406
407 return true;
408 }
409
410
411 bool
412 CompositeScreen::registerPaintHandler (compiz::composite::PaintHandler *pHnd)
413 {
414 Display *dpy;
415
416 WRAPABLE_HND_FUNCTN_RETURN (bool, registerPaintHandler, pHnd);
417
418 dpy = screen->dpy ();
419
420 if (priv->pHnd)
421 return false;
422
423 CompScreen::checkForError (dpy);
424
425 XCompositeRedirectSubwindows (dpy, screen->root (),
426 CompositeRedirectManual);
427
428 priv->overlayWindowCount = 0;
429
430 if (CompScreen::checkForError (dpy))
431 {
432 compLogMessage ("composite", CompLogLevelError,
433 "Another composite manager is already "
434 "running on screen: %d", screen->screenNum ());
435
436 return false;
437 }
438
439 foreach (CompWindow *w, screen->windows ())
440 {
441 CompositeWindow *cw = CompositeWindow::get (w);
442 cw->priv->overlayWindow = false;
443 cw->priv->redirected = true;
444 }
445
446 priv->pHnd = pHnd;
447
448 priv->detectRefreshRate ();
449
450 showOutputWindow ();
451
452 return true;
453 }
454
455 void
456 CompositeScreen::unregisterPaintHandler ()
457 {
458 Display *dpy;
459
460 WRAPABLE_HND_FUNCTN (unregisterPaintHandler)
461
462 dpy = screen->dpy ();
463
464 foreach (CompWindow *w, screen->windows ())
465 {
466 CompositeWindow *cw = CompositeWindow::get (w);
467 cw->priv->overlayWindow = false;
468 cw->priv->redirected = false;
469 cw->release ();
470 }
471
472 priv->overlayWindowCount = 0;
473
474 XCompositeUnredirectSubwindows (dpy, screen->root (),
475 CompositeRedirectManual);
476
477 priv->pHnd = NULL;
478 priv->paintTimer.stop ();
479
480 priv->detectRefreshRate ();
481
482 hideOutputWindow ();
483 }
484
485 bool
486 CompositeScreen::compositingActive ()
487 {
488 if (priv->pHnd)
489 return priv->pHnd->compositingActive ();
490
491 return false;
492 }
493
494 void
495 CompositeScreen::damageScreen ()
496 {
497 bool alreadyDamaged = priv->damageMask & COMPOSITE_SCREEN_DAMAGE_ALL_MASK;
498
499 priv->damageMask |= COMPOSITE_SCREEN_DAMAGE_ALL_MASK;
500 priv->damageMask &= ~COMPOSITE_SCREEN_DAMAGE_REGION_MASK;
501
502 priv->scheduleRepaint ();
503
504 /*
505 * Call through damageRegion since plugins listening for incoming damage
506 * may need to know that the whole screen was redrawn
507 */
508
509 if (!alreadyDamaged)
510 damageRegion (CompRegion (0, 0, screen->width (), screen->height ()));
511 }
512
513 void
514 CompositeScreen::damageRegion (const CompRegion ®ion)
515 {
516 WRAPABLE_HND_FUNCTN (damageRegion, region);
517
518 if (priv->damageMask & COMPOSITE_SCREEN_DAMAGE_ALL_MASK)
519 return;
520
521 priv->damage += region;
522 priv->damageMask |= COMPOSITE_SCREEN_DAMAGE_REGION_MASK;
523
524 /* if the number of damage rectangles grows two much between repaints,
525 we have a lot of overhead just for doing the damage tracking -
526 in order to make sure we're not having too much overhead, damage
527 the whole screen if we have a lot of damage rects */
528
529 if (priv->damage.numRects () > 100)
530 damageScreen ();
531 priv->scheduleRepaint ();
532 }
533
534 void
535 CompositeScreen::damagePending ()
536 {
537 priv->damageMask |= COMPOSITE_SCREEN_DAMAGE_PENDING_MASK;
538 priv->scheduleRepaint ();
539 }
540
541 unsigned int
542 CompositeScreen::damageMask ()
543 {
544 return priv->damageMask;
545 }
546
547 void
548 CompositeScreen::showOutputWindow ()
549 {
550 if (priv->pHnd)
551 {
552 Display *dpy = screen->dpy ();
553 XserverRegion region;
554
555 region = XFixesCreateRegion (dpy, NULL, 0);
556
557 XFixesSetWindowShapeRegion (dpy,
558 priv->output,
559 ShapeBounding,
560 0, 0, 0);
561 XFixesSetWindowShapeRegion (dpy,
562 priv->output,
563 ShapeInput,
564 0, 0, region);
565
566 XFixesDestroyRegion (dpy, region);
567
568 damageScreen ();
569
570 priv->outputShapeChanged = true;
571 }
572 }
573
574 void
575 CompositeScreen::hideOutputWindow ()
576 {
577 Display *dpy = screen->dpy ();
578 XserverRegion region;
579
580 region = XFixesCreateRegion (dpy, NULL, 0);
581
582 XFixesSetWindowShapeRegion (dpy,
583 priv->output,
584 ShapeBounding,
585 0, 0, region);
586
587 XFixesDestroyRegion (dpy, region);
588 }
589
590 void
591 CompositeScreen::updateOutputWindow ()
592 {
593 if (priv->pHnd)
594 {
595 Display *dpy = screen->dpy ();
596 XserverRegion region;
597 CompRegion tmpRegion (screen->region ());
598
599 for (CompWindowList::reverse_iterator rit =
600 screen->windows ().rbegin ();
601 rit != screen->windows ().rend (); ++rit)
602 if (CompositeWindow::get (*rit)->overlayWindow ())
603 {
604 tmpRegion -= (*rit)->region ();
605 }
606
607 XShapeCombineRegion (dpy, priv->output, ShapeBounding,
608 0, 0, tmpRegion.handle (), ShapeSet);
609
610
611 region = XFixesCreateRegion (dpy, NULL, 0);
612
613 XFixesSetWindowShapeRegion (dpy,
614 priv->output,
615 ShapeInput,
616 0, 0, region);
617
618 XFixesDestroyRegion (dpy, region);
619
620 priv->outputShapeChanged = true;
621 }
622
623 }
624
625 bool
626 CompositeScreen::outputWindowChanged () const
627 {
628 return priv->outputShapeChanged;
629 }
630
631 void
632 PrivateCompositeScreen::makeOutputWindow ()
633 {
634 overlay = XCompositeGetOverlayWindow (screen->dpy (), screen->root ());
635 output = overlay;
636
637 XSelectInput (screen->dpy (), output, ExposureMask);
638
639 cScreen->hideOutputWindow ();
640 }
641
642 Window
643 CompositeScreen::output ()
644 {
645 return priv->output;
646 }
647
648 Window
649 CompositeScreen::overlay ()
650 {
651 return priv->overlay;
652 }
653
654 int &
655 CompositeScreen::overlayWindowCount ()
656 {
657 return priv->overlayWindowCount;
658 }
659
660 void
661 CompositeScreen::setWindowPaintOffset (int x, int y)
662 {
663 priv->windowPaintOffset = CompPoint (x, y);
664 }
665
666 CompPoint
667 CompositeScreen::windowPaintOffset ()
668 {
669 return priv->windowPaintOffset;
670 }
671
672 void
673 PrivateCompositeScreen::detectRefreshRate ()
674 {
675 const bool forceRefreshRate = (pHnd ? pHnd->requiredForcedRefreshRate () : false);
676 const bool detect = optionGetDetectRefreshRate () && !forceRefreshRate;
677
678 if (detect)
679 {
680 CompString name;
681 CompOption::Value value;
682
683 value.set ((int) 0);
684
685 if (randrExtension)
686 {
687 XRRScreenConfiguration *config;
688
689 config = XRRGetScreenInfo (screen->dpy (),
690 screen->root ());
691 value.set ((int) XRRConfigCurrentRate (config));
692
693 XRRFreeScreenConfigInfo (config);
694 }
695
696 if (value.i () == 0)
697 value.set ((int) FALLBACK_REFRESH_RATE);
698
699 mOptions[CompositeOptions::DetectRefreshRate].value ().set (false);
700 screen->setOptionForPlugin ("composite", "refresh_rate", value);
701 mOptions[CompositeOptions::DetectRefreshRate].value ().set (true);
702 optimalRedrawTime = redrawTime = 1000 / value.i ();
703 }
704 else
705 {
706 redrawTime = 1000 / optionGetRefreshRate ();
707 optimalRedrawTime = redrawTime;
708 }
709 }
710
711 CompositeFPSLimiterMode
712 CompositeScreen::FPSLimiterMode ()
713 {
714 return priv->FPSLimiterMode;
715 }
716
717 void
718 CompositeScreen::setFPSLimiterMode (CompositeFPSLimiterMode newMode)
719 {
720 priv->FPSLimiterMode = newMode;
721 }
722
723 void
724 PrivateCompositeScreen::scheduleRepaint ()
725 {
726 if (painting)
727 {
728 reschedule = true;
729 return;
730 }
731
732 if (scheduled)
733 return;
734
735 scheduled = true;
736
737 int delay;
738 if (FPSLimiterMode == CompositeFPSLimiterModeVSyncLike ||
739 (pHnd && pHnd->hasVSync ()))
740 {
741 delay = 1;
742 }
743 else
744 {
745 struct timeval now;
746 gettimeofday (&now, 0);
747 int elapsed = compiz::core::timer::timeval_diff (&now, &lastRedraw);
748 if (elapsed < 0)
749 elapsed = 0;
750 delay = elapsed < optimalRedrawTime ? optimalRedrawTime - elapsed : 1;
751 }
752
753 paintTimer.start
754 (boost::bind (&CompositeScreen::handlePaintTimeout, cScreen),
755 delay);
756 }
757
758 int
759 CompositeScreen::redrawTime ()
760 {
761 return priv->redrawTime;
762 }
763
764 int
765 CompositeScreen::optimalRedrawTime ()
766 {
767 return priv->optimalRedrawTime;
768 }
769
770 bool
771 CompositeScreen::handlePaintTimeout ()
772 {
773 struct timeval tv;
774
775 priv->painting = true;
776 priv->reschedule = false;
777 gettimeofday (&tv, 0);
778
779 if (priv->damageMask)
780 {
781 int timeDiff;
782
783 if (priv->pHnd)
784 priv->pHnd->prepareDrawing ();
785
786 timeDiff = compiz::core::timer::timeval_diff (&tv, &priv->lastRedraw);
787
788 /* handle clock rollback */
789 if (timeDiff < 0)
790 timeDiff = 0;
791 /*
792 * Now that we use a "tickless" timing algorithm, timeDiff could be
793 * very large if the screen is truely idle.
794 * However plugins expect the old behaviour where timeDiff is rarely
795 * larger than the frame rate (optimalRedrawTime).
796 * So enforce this to keep animations timed correctly and smooth...
797 */
798 if (timeDiff > 100)
799 timeDiff = priv->optimalRedrawTime;
800
801 priv->redrawTime = timeDiff;
802 preparePaint (priv->slowAnimations ? 1 : timeDiff);
803
804 /* substract top most overlay window region */
805 if (priv->overlayWindowCount)
806 {
807 for (CompWindowList::reverse_iterator rit =
808 screen->windows ().rbegin ();
809 rit != screen->windows ().rend (); ++rit)
810 {
811 CompWindow *w = (*rit);
812
813 if (w->destroyed () || w->invisible ())
814 continue;
815
816 if (!CompositeWindow::get (w)->redirected ())
817 priv->damage -= w->region ();
818
819 break;
820 }
821
822 if (priv->damageMask & COMPOSITE_SCREEN_DAMAGE_ALL_MASK)
823 {
824 priv->damageMask &= ~COMPOSITE_SCREEN_DAMAGE_ALL_MASK;
825 priv->damageMask |= COMPOSITE_SCREEN_DAMAGE_REGION_MASK;
826 }
827 }
828
829 priv->tmpRegion = priv->damage & screen->region ();
830
831 if (priv->damageMask & COMPOSITE_SCREEN_DAMAGE_REGION_MASK)
832 {
833 if (priv->tmpRegion == screen->region ())
834 damageScreen ();
835 }
836
837 Display *dpy = screen->dpy ();
838 std::map<Damage, XRectangle>::iterator d = priv->damages.begin ();
839 for (; d != priv->damages.end (); ++d)
840 {
841 XserverRegion sub = XFixesCreateRegion (dpy, &d->second, 1);
842 if (sub != None)
843 {
844 XDamageSubtract (dpy, d->first, sub, None);
845 XFixesDestroyRegion (dpy, sub);
846 }
847 }
848 XSync (dpy, False);
849 priv->damages.clear ();
850
851 priv->damage = CompRegion ();
852
853 int mask = priv->damageMask;
854 priv->damageMask = 0;
855
856 CompOutput::ptrList outputs (0);
857
858 if (priv->optionGetForceIndependentOutputPainting ()
859 || !screen->hasOverlappingOutputs ())
860 {
861 foreach (CompOutput &o, screen->outputDevs ())
862 outputs.push_back (&o);
863 }
864 else
865 outputs.push_back (&screen->fullscreenOutput ());
866
867 paint (outputs, mask);
868
869
870 donePaint ();
871
872 priv->outputShapeChanged = false;
873
874 foreach (CompWindow *w, screen->windows ())
875 {
876 if (w->destroyed ())
877 {
878 CompositeWindow::get (w)->addDamage ();
879 break;
880 }
881 }
882 }
883
884 priv->lastRedraw = tv;
885 priv->painting = false;
886 priv->scheduled = false;
887 if (priv->reschedule)
888 priv->scheduleRepaint ();
889
890 return false;
891 }
892
893
894
895 void
896 CompositeScreen::preparePaint (int msSinceLastPaint)
897 WRAPABLE_HND_FUNCTN (preparePaint, msSinceLastPaint)
898
899 void
900 CompositeScreen::donePaint ()
901 WRAPABLE_HND_FUNCTN (donePaint)
902
903 void
904 CompositeScreen::paint (CompOutput::ptrList &outputs,
905 unsigned int mask)
906 {
907 WRAPABLE_HND_FUNCTN (paint, outputs, mask)
908
909 if (priv->pHnd)
910 priv->pHnd->paintOutputs (outputs, mask, priv->tmpRegion);
911 }
912
913 const CompWindowList &
914 CompositeScreen::getWindowPaintList ()
915 {
916 WRAPABLE_HND_FUNCTN_RETURN (const CompWindowList &, getWindowPaintList)
917
918 /* Include destroyed windows */
919 if (screen->destroyedWindows ().empty ())
920 return screen->windows ();
921 else
922 {
923 CompWindowList destroyedWindows = screen->destroyedWindows ();
924
925 priv->withDestroyedWindows.resize (0);
926
927 foreach (CompWindow *w, screen->windows ())
928 {
929 foreach (CompWindow *dw, screen->destroyedWindows ())
930 {
931 if (dw->next == w)
932 {
933 priv->withDestroyedWindows.push_back (dw);
934 destroyedWindows.remove (dw);
935 break;
936 }
937 }
938
939 priv->withDestroyedWindows.push_back (w);
940 }
941
942 /* We need to put all the destroyed windows which didn't get
943 * inserted in the paint list at the top of the stack since
944 * w->next was probably either invalid or NULL */
945
946 foreach (CompWindow *dw, destroyedWindows)
947 priv->withDestroyedWindows.push_back (dw);
948
949 return priv->withDestroyedWindows;
950 }
951 }
952
953 void
954 PrivateCompositeScreen::handleExposeEvent (XExposeEvent *event)
955 {
956 if (output == event->window)
957 return;
958
959 exposeRects.push_back (CompRect (event->x,
960 event->y,
961 event->width,
962 event->height));
963
964 if (event->count == 0)
965 {
966 CompRect rect;
967 foreach (CompRect rect, exposeRects)
968 {
969 cScreen->damageRegion (CompRegion (rect));
970 }
971 exposeRects.clear ();
972 }
973 }
974
975 void
976 PrivateCompositeScreen::outputChangeNotify ()
977 {
978 screen->outputChangeNotify ();
979 XMoveResizeWindow (screen->dpy (), overlay, 0, 0,
980 screen->width (), screen->height ());
981 cScreen->damageScreen ();
982 }
983
984 bool
985 CompositeScreen::toggleSlowAnimations (CompAction *action,
986 CompAction::State state,
987 CompOption::Vector &options)
988 {
989 CompositeScreen *cs = CompositeScreen::get (screen);
990 if (cs)
991 cs->priv->slowAnimations = !cs->priv->slowAnimations;
992
993 return true;
994 }
995
996
997 void
998 CompositeScreenInterface::preparePaint (int msSinceLastPaint)
999 WRAPABLE_DEF (preparePaint, msSinceLastPaint)
1000
1001 void
1002 CompositeScreenInterface::donePaint ()
1003 WRAPABLE_DEF (donePaint)
1004
1005 void
1006 CompositeScreenInterface::paint (CompOutput::ptrList &outputs,
1007 unsigned int mask)
1008 WRAPABLE_DEF (paint, outputs, mask)
1009
1010 const CompWindowList &
1011 CompositeScreenInterface::getWindowPaintList ()
1012 WRAPABLE_DEF (getWindowPaintList)
1013
1014 bool
1015 CompositeScreenInterface::registerPaintHandler (compiz::composite::PaintHandler *pHnd)
1016 WRAPABLE_DEF (registerPaintHandler, pHnd);
1017
1018 void
1019 CompositeScreenInterface::unregisterPaintHandler ()
1020 WRAPABLE_DEF (unregisterPaintHandler);
1021
1022 void
1023 CompositeScreenInterface::damageRegion (const CompRegion &r)
1024 WRAPABLE_DEF (damageRegion, r);
1025
1026 const CompRegion &
1027 CompositeScreen::currentDamage () const
1028 {
1029 return priv->damage;
1030 }