2
* Copyright © 2008 Dennis Kasprzyk
3
* Copyright © 2007 Novell, Inc.
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
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.
24
* Authors: Dennis Kasprzyk <onestone@compiz-fusion.org>
25
* David Reveman <davidr@novell.com>
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>
43
#include <X11/extensions/shape.h>
44
#include <X11/extensions/Xrandr.h>
46
CompWindow *lastDamagedWindow = 0;
50
PrivateCompositeScreen::handleEvent (XEvent *event)
54
switch (event->type) {
57
if (screen->root () == event->xcreatewindow.parent)
59
/* The first time some client asks for the composite
60
* overlay window, the X server creates it, which causes
61
* an errorneous CreateNotify event. We catch it and
63
if (overlay == event->xcreatewindow.window)
68
if (event->xproperty.atom == Atoms::winOpacity)
70
w = screen->findWindow (event->xproperty.window);
72
CompositeWindow::get (w)->updateOpacity ();
74
else if (event->xproperty.atom == Atoms::winBrightness)
76
w = screen->findWindow (event->xproperty.window);
78
CompositeWindow::get (w)->updateBrightness ();
80
else if (event->xproperty.atom == Atoms::winSaturation)
82
w = screen->findWindow (event->xproperty.window);
84
CompositeWindow::get (w)->updateSaturation ();
89
event->type == shapeEvent + ShapeNotify)
91
w = screen->findWindow (((XShapeEvent *) event)->window);
96
CompositeWindow::get (w)->addDamage ();
103
screen->handleEvent (event);
105
switch (event->type) {
107
handleExposeEvent (&event->xexpose);
110
if (event->xclient.message_type == Atoms::winOpacity)
112
w = screen->findWindow (event->xclient.window);
113
if (w && (w->type () & CompWindowTypeDesktopMask) == 0)
115
unsigned short opacity = event->xclient.data.l[0] >> 16;
117
screen->setWindowProp32 (w->id (),
118
Atoms::winOpacity, opacity);
121
else if (event->xclient.message_type ==
122
Atoms::winBrightness)
124
w = screen->findWindow (event->xclient.window);
127
unsigned short brightness = event->xclient.data.l[0] >> 16;
129
screen->setWindowProp32 (w->id (),
130
Atoms::winBrightness, brightness);
133
else if (event->xclient.message_type ==
134
Atoms::winSaturation)
136
w = screen->findWindow (event->xclient.window);
139
unsigned short saturation = event->xclient.data.l[0] >> 16;
141
screen->setWindowProp32 (w->id (),
142
Atoms::winSaturation, saturation);
147
if (event->type == damageEvent + XDamageNotify)
149
XDamageNotifyEvent *de = (XDamageNotifyEvent *) event;
151
if (lastDamagedWindow && de->drawable == lastDamagedWindow->id ())
153
w = lastDamagedWindow;
157
w = screen->findWindow (de->drawable);
159
lastDamagedWindow = w;
163
CompositeWindow::get (w)->processDamage (de);
165
else if (shapeExtension &&
166
event->type == shapeEvent + ShapeNotify)
168
w = screen->findWindow (((XShapeEvent *) event)->window);
173
CompositeWindow::get (w)->addDamage ();
177
else if (randrExtension &&
178
event->type == randrEvent + RRScreenChangeNotify)
180
XRRScreenChangeNotifyEvent *rre;
182
rre = (XRRScreenChangeNotifyEvent *) event;
184
if (screen->root () == rre->root)
185
cScreen->detectRefreshRate ();
192
CompositeScreen::damageEvent ()
194
return priv->damageEvent;
198
CompositeScreen::CompositeScreen (CompScreen *s) :
199
PrivateHandler<CompositeScreen, CompScreen, COMPIZ_COMPOSITE_ABI> (s),
200
priv (new PrivateCompositeScreen (this))
202
int compositeMajor, compositeMinor;
204
if (!compositeVTable->getMetadata ()->initOptions (compositeOptionInfo,
205
COMPOSITE_OPTION_NUM,
212
if (!XQueryExtension (s->dpy (), COMPOSITE_NAME,
213
&priv->compositeOpcode,
214
&priv->compositeEvent,
215
&priv->compositeError))
217
compLogMessage ("core", CompLogLevelFatal,
218
"No composite extension");
223
XCompositeQueryVersion (s->dpy (), &compositeMajor, &compositeMinor);
224
if (compositeMajor == 0 && compositeMinor < 2)
226
compLogMessage ("core", CompLogLevelFatal,
227
"Old composite extension");
232
if (!XDamageQueryExtension (s->dpy (), &priv->damageEvent,
235
compLogMessage ("core", CompLogLevelFatal,
236
"No damage extension");
241
if (!XFixesQueryExtension (s->dpy (), &priv->fixesEvent, &priv->fixesError))
243
compLogMessage ("core", CompLogLevelFatal,
244
"No fixes extension");
249
priv->shapeExtension = XShapeQueryExtension (s->dpy (), &priv->shapeEvent,
251
priv->randrExtension = XRRQueryExtension (s->dpy (), &priv->randrEvent,
254
priv->makeOutputWindow ();
256
detectRefreshRate ();
258
priv->slowAnimations = false;
267
CompositeScreen::~CompositeScreen ()
269
priv->paintTimer.stop ();
273
XCompositeReleaseOverlayWindow (screen->dpy (),
281
PrivateCompositeScreen::PrivateCompositeScreen (CompositeScreen *cs) :
283
damageMask (COMPOSITE_SCREEN_DAMAGE_ALL_MASK),
287
windowPaintOffset (0, 0),
288
overlayWindowCount (0),
290
redrawTime (1000 / 50),
291
optimalRedrawTime (1000 / 50),
296
slowAnimations (false),
299
opt (COMPOSITE_OPTION_NUM)
301
gettimeofday (&lastRedraw, 0);
302
// wrap outputChangeNotify
303
ScreenInterface::setHandler (screen);
306
PrivateCompositeScreen::~PrivateCompositeScreen ()
311
PrivateCompositeScreen::init ()
313
Display *dpy = screen->dpy ();
314
Window newCmSnOwner = None;
316
Time cmSnTimestamp = 0;
318
XSetWindowAttributes attr;
319
Window currentCmSnOwner;
322
sprintf (buf, "_NET_WM_CM_S%d", screen->screenNum ());
323
cmSnAtom = XInternAtom (dpy, buf, 0);
325
currentCmSnOwner = XGetSelectionOwner (dpy, cmSnAtom);
327
if (currentCmSnOwner != None)
329
if (!replaceCurrentWm)
331
compLogMessage ("composite", CompLogLevelError,
332
"Screen %d on display \"%s\" already "
333
"has a compositing manager; try using the "
334
"--replace option to replace the current "
335
"compositing manager.",
336
screen->screenNum (), DisplayString (dpy));
342
attr.override_redirect = TRUE;
343
attr.event_mask = PropertyChangeMask;
346
XCreateWindow (dpy, XRootWindow (dpy, screen->screenNum ()),
348
CopyFromParent, CopyFromParent,
350
CWOverrideRedirect | CWEventMask,
353
XChangeProperty (dpy, newCmSnOwner, Atoms::wmName, Atoms::utf8String, 8,
354
PropModeReplace, (unsigned char *) PACKAGE,
357
XWindowEvent (dpy, newCmSnOwner, PropertyChangeMask, &event);
359
cmSnTimestamp = event.xproperty.time;
362
XSetSelectionOwner (dpy, cmSnAtom, newCmSnOwner, cmSnTimestamp);
364
if (XGetSelectionOwner (dpy, cmSnAtom) != newCmSnOwner)
366
compLogMessage ("composite", CompLogLevelError,
367
"Could not acquire compositing manager "
368
"selection on screen %d display \"%s\"",
369
screen->screenNum (), DisplayString (dpy));
379
CompositeScreen::registerPaintHandler (PaintHandler *pHnd)
381
Display *dpy = screen->dpy ();
386
CompScreen::checkForError (dpy);
388
XCompositeRedirectSubwindows (dpy, screen->root (),
389
CompositeRedirectManual);
391
priv->overlayWindowCount = 0;
393
if (CompScreen::checkForError (dpy))
395
compLogMessage ("composite", CompLogLevelError,
396
"Another composite manager is already "
397
"running on screen: %d", screen->screenNum ());
402
foreach (CompWindow *w, screen->windows ())
404
CompositeWindow *cw = CompositeWindow::get (w);
405
cw->priv->overlayWindow = false;
406
cw->priv->redirected = true;
414
priv->paintTimer.start
415
(boost::bind(&CompositeScreen::handlePaintTimeout, this),
416
priv->optimalRedrawTime, MAXSHORT);
421
CompositeScreen::unregisterPaintHandler ()
423
Display *dpy = screen->dpy ();
425
foreach (CompWindow *w, screen->windows ())
427
CompositeWindow *cw = CompositeWindow::get (w);
428
cw->priv->overlayWindow = false;
429
cw->priv->redirected = false;
433
priv->overlayWindowCount = 0;
435
XCompositeUnredirectSubwindows (dpy, screen->root (),
436
CompositeRedirectManual);
439
priv->active = false;
440
priv->paintTimer.stop ();
446
CompositeScreen::compositingActive ()
452
CompositeScreen::damageScreen ()
454
if (priv->damageMask == 0)
455
priv->paintTimer.setTimes (priv->paintTimer.minLeft ());
457
priv->damageMask |= COMPOSITE_SCREEN_DAMAGE_ALL_MASK;
458
priv->damageMask &= ~COMPOSITE_SCREEN_DAMAGE_REGION_MASK;
462
CompositeScreen::damageRegion (const CompRegion ®ion)
464
if (priv->damageMask & COMPOSITE_SCREEN_DAMAGE_ALL_MASK)
467
if (priv->damageMask == 0)
468
priv->paintTimer.setTimes (priv->paintTimer.minLeft ());
470
priv->damage += region;
472
priv->damageMask |= COMPOSITE_SCREEN_DAMAGE_REGION_MASK;
474
/* if the number of damage rectangles grows two much between repaints,
475
we have a lot of overhead just for doing the damage tracking -
476
in order to make sure we're not having too much overhead, damage
477
the whole screen if we have a lot of damage rects */
479
if (priv->damage.numRects () > 100)
484
CompositeScreen::damagePending ()
486
if (priv->damageMask == 0)
487
priv->paintTimer.setTimes (priv->paintTimer.minLeft ());
489
priv->damageMask |= COMPOSITE_SCREEN_DAMAGE_PENDING_MASK;
493
CompositeScreen::damageMask ()
495
return priv->damageMask;
499
CompositeScreen::showOutputWindow ()
502
if (useCow && priv->active)
504
Display *dpy = screen->dpy ();
505
XserverRegion region;
507
region = XFixesCreateRegion (dpy, NULL, 0);
509
XFixesSetWindowShapeRegion (dpy,
513
XFixesSetWindowShapeRegion (dpy,
518
XFixesDestroyRegion (dpy, region);
527
CompositeScreen::hideOutputWindow ()
532
Display *dpy = screen->dpy ();
533
XserverRegion region;
535
region = XFixesCreateRegion (dpy, NULL, 0);
537
XFixesSetWindowShapeRegion (dpy,
542
XFixesDestroyRegion (dpy, region);
549
CompositeScreen::updateOutputWindow ()
552
if (useCow && priv->active)
554
Display *dpy = screen->dpy ();
555
XserverRegion region;
556
CompRegion tmpRegion (screen->region ());
558
for (CompWindowList::reverse_iterator rit =
559
screen->windows ().rbegin ();
560
rit != screen->windows ().rend (); rit++)
561
if (CompositeWindow::get (*rit)->overlayWindow ())
563
tmpRegion -= (*rit)->region ();
566
XShapeCombineRegion (dpy, priv->output, ShapeBounding,
567
0, 0, tmpRegion.handle (), ShapeSet);
570
region = XFixesCreateRegion (dpy, NULL, 0);
572
XFixesSetWindowShapeRegion (dpy,
577
XFixesDestroyRegion (dpy, region);
584
PrivateCompositeScreen::makeOutputWindow ()
589
overlay = XCompositeGetOverlayWindow (screen->dpy (), screen->root ());
592
XSelectInput (screen->dpy (), output, ExposureMask);
596
output = overlay = screen->root ();
598
cScreen->hideOutputWindow ();
602
CompositeScreen::output ()
608
CompositeScreen::overlay ()
610
return priv->overlay;
614
CompositeScreen::overlayWindowCount ()
616
return priv->overlayWindowCount;
620
CompositeScreen::setWindowPaintOffset (int x, int y)
622
priv->windowPaintOffset = CompPoint (x, y);
626
CompositeScreen::windowPaintOffset ()
628
return priv->windowPaintOffset;
632
CompositeScreen::detectRefreshRate ()
635
priv->opt[COMPOSITE_OPTION_DETECT_REFRESH_RATE].value ().b ())
638
CompOption::Value value;
642
if (screen->XRandr())
644
XRRScreenConfiguration *config;
646
config = XRRGetScreenInfo (screen->dpy (),
648
value.set ((int) XRRConfigCurrentRate (config));
650
XRRFreeScreenConfigInfo (config);
654
value.set ((int) 50);
656
name = priv->opt[COMPOSITE_OPTION_REFRESH_RATE].name ();
658
priv->opt[COMPOSITE_OPTION_DETECT_REFRESH_RATE].value ().set (false);
659
screen->setOptionForPlugin ("composite", name.c_str (), value);
660
priv->opt[COMPOSITE_OPTION_DETECT_REFRESH_RATE].value ().set (true);
664
priv->redrawTime = 1000 /
665
priv->opt[COMPOSITE_OPTION_REFRESH_RATE].value ().i ();
666
priv->optimalRedrawTime = priv->redrawTime;
671
CompositeScreen::getTimeToNextRedraw (struct timeval *tv)
675
diff = TIMEVALDIFF (tv, &priv->lastRedraw);
677
/* handle clock rollback */
681
if (priv->idle || (priv->pHnd && priv->pHnd->hasVSync ()))
683
if (priv->timeMult > 1)
685
priv->frameStatus = -1;
686
priv->redrawTime = priv->optimalRedrawTime;
692
if (diff > priv->redrawTime)
694
if (priv->frameStatus > 0)
695
priv->frameStatus = 0;
697
next = priv->optimalRedrawTime * (priv->timeMult + 1);
701
if (priv->frameStatus < -1)
704
priv->redrawTime = diff = next;
708
else if (diff < priv->redrawTime)
710
if (priv->frameStatus < 0)
711
priv->frameStatus = 0;
713
if (priv->timeMult > 1)
715
next = priv->optimalRedrawTime * (priv->timeMult - 1);
719
if (priv->frameStatus > 4)
722
priv->redrawTime = next;
728
if (diff >= priv->redrawTime)
731
return priv->redrawTime - diff;
735
CompositeScreen::redrawTime ()
737
return priv->redrawTime;
741
CompositeScreen::handlePaintTimeout ()
746
gettimeofday (&tv, 0);
748
if (priv->damageMask)
751
priv->pHnd->prepareDrawing ();
753
timeDiff = TIMEVALDIFF (&tv, &priv->lastRedraw);
755
/* handle clock rollback */
759
if (priv->slowAnimations)
761
preparePaint (priv->idle ? 2 : (timeDiff * 2) / priv->redrawTime);
764
preparePaint (priv->idle ? priv->redrawTime : timeDiff);
766
/* substract top most overlay window region */
767
if (priv->overlayWindowCount)
769
for (CompWindowList::reverse_iterator rit =
770
screen->windows ().rbegin ();
771
rit != screen->windows ().rend (); rit++)
773
CompWindow *w = (*rit);
775
if (w->destroyed () || w->invisible ())
778
if (!CompositeWindow::get (w)->redirected ())
779
priv->damage -= w->region ();
784
if (priv->damageMask & COMPOSITE_SCREEN_DAMAGE_ALL_MASK)
786
priv->damageMask &= ~COMPOSITE_SCREEN_DAMAGE_ALL_MASK;
787
priv->damageMask |= COMPOSITE_SCREEN_DAMAGE_REGION_MASK;
791
priv->tmpRegion = priv->damage & screen->region ();
793
if (priv->damageMask & COMPOSITE_SCREEN_DAMAGE_REGION_MASK)
795
if (priv->tmpRegion == screen->region ())
799
priv->damage = CompRegion ();
801
int mask = priv->damageMask;
802
priv->damageMask = 0;
804
CompOutput::ptrList outputs (0);
806
if (priv->opt[COMPOSITE_OPTION_FORCE_INDEPENDENT].value ().b ()
807
|| !screen->hasOverlappingOutputs ())
809
foreach (CompOutput &o, screen->outputDevs ())
810
outputs.push_back (&o);
813
outputs.push_back (&screen->fullscreenOutput ());
815
paint (outputs, mask);
817
priv->lastRedraw = tv;
821
foreach (CompWindow *w, screen->windows ())
825
CompositeWindow::get (w)->addDamage ();
837
gettimeofday (&tv, 0);
840
priv->paintTimer.setTimes (getTimeToNextRedraw (&tv), MAXSHORT);
842
priv->paintTimer.setTimes (getTimeToNextRedraw (&tv));
847
CompositeScreen::preparePaint (int msSinceLastPaint)
848
WRAPABLE_HND_FUNC(0, preparePaint, msSinceLastPaint)
851
CompositeScreen::donePaint ()
852
WRAPABLE_HND_FUNC(1, donePaint)
855
CompositeScreen::paint (CompOutput::ptrList &outputs,
858
WRAPABLE_HND_FUNC(2, paint, outputs, mask)
861
priv->pHnd->paintOutputs (outputs, mask, priv->tmpRegion);
865
CompositeScreen::getWindowPaintList ()
867
WRAPABLE_HND_FUNC_RETURN (3, CompWindowList, getWindowPaintList)
869
return screen->windows ();
873
PrivateCompositeScreen::handleExposeEvent (XExposeEvent *event)
875
if (output == event->window)
878
exposeRects.push_back (CompRect (event->x,
883
if (event->count == 0)
886
foreach (CompRect rect, exposeRects)
888
cScreen->damageRegion (CompRegion (rect));
890
exposeRects.clear ();
895
PrivateCompositeScreen::outputChangeNotify ()
897
screen->outputChangeNotify ();
900
XMoveResizeWindow (screen->dpy (), overlay, 0, 0,
901
screen->width (), screen->height ());
903
cScreen->damageScreen ();
907
CompositeScreen::toggleSlowAnimations (CompAction *action,
908
CompAction::State state,
909
CompOption::Vector &options)
911
CompositeScreen *cs = CompositeScreen::get (screen);
913
cs->priv->slowAnimations = !cs->priv->slowAnimations;
920
CompositeScreenInterface::preparePaint (int msSinceLastPaint)
921
WRAPABLE_DEF (preparePaint, msSinceLastPaint)
924
CompositeScreenInterface::donePaint ()
925
WRAPABLE_DEF (donePaint)
928
CompositeScreenInterface::paint (CompOutput::ptrList &outputs,
930
WRAPABLE_DEF (paint, outputs, mask)
933
CompositeScreenInterface::getWindowPaintList ()
934
WRAPABLE_DEF (getWindowPaintList)
937
CompositeScreen::currentDamage () const