~mc-return/compiz/compiz.merge-src-screen.cpp-improvements

« back to all changes in this revision

Viewing changes to plugins/composite/src/screen.cpp

  • Committer: Dennis kasprzyk
  • Author(s): Dennis Kasprzyk
  • Date: 2009-03-15 05:09:18 UTC
  • Revision ID: git-v1:163f6b6f3c3b7764987cbdf8e03cc355edeaa499
New generalized build system.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
CompWindow *lastDamagedWindow = 0;
 
47
 
 
48
 
 
49
void
 
50
PrivateCompositeScreen::handleEvent (XEvent *event)
 
51
{
 
52
    CompWindow      *w;
 
53
 
 
54
    switch (event->type) {
 
55
 
 
56
        case CreateNotify:
 
57
            if (screen->root () == event->xcreatewindow.parent)
 
58
            {
 
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
 
62
                 * ignore it. */
 
63
                if (overlay == event->xcreatewindow.window)
 
64
                    return;
 
65
            }
 
66
            break;
 
67
        case PropertyNotify:
 
68
            if (event->xproperty.atom == Atoms::winOpacity)
 
69
            {
 
70
                w = screen->findWindow (event->xproperty.window);
 
71
                if (w)
 
72
                    CompositeWindow::get (w)->updateOpacity ();
 
73
            }
 
74
            else if (event->xproperty.atom == Atoms::winBrightness)
 
75
            {
 
76
                w = screen->findWindow (event->xproperty.window);
 
77
                if (w)
 
78
                    CompositeWindow::get (w)->updateBrightness ();
 
79
            }
 
80
            else if (event->xproperty.atom == Atoms::winSaturation)
 
81
            {
 
82
                w = screen->findWindow (event->xproperty.window);
 
83
                if (w)
 
84
                    CompositeWindow::get (w)->updateSaturation ();
 
85
            }
 
86
            break;
 
87
        default:
 
88
            if (shapeExtension &&
 
89
                event->type == shapeEvent + ShapeNotify)
 
90
            {
 
91
                w = screen->findWindow (((XShapeEvent *) event)->window);
 
92
                if (w)
 
93
                {
 
94
                    if (w->mapNum ())
 
95
                    {
 
96
                        CompositeWindow::get (w)->addDamage ();
 
97
                    }
 
98
                }
 
99
            }
 
100
            break;
 
101
    }
 
102
        
 
103
    screen->handleEvent (event);
 
104
 
 
105
    switch (event->type) {
 
106
        case Expose:
 
107
            handleExposeEvent (&event->xexpose);
 
108
        break;
 
109
        case ClientMessage:
 
110
            if (event->xclient.message_type == Atoms::winOpacity)
 
111
            {
 
112
                w = screen->findWindow (event->xclient.window);
 
113
                if (w && (w->type () & CompWindowTypeDesktopMask) == 0)
 
114
                {
 
115
                    unsigned short opacity = event->xclient.data.l[0] >> 16;
 
116
 
 
117
                    screen->setWindowProp32 (w->id (),
 
118
                        Atoms::winOpacity, opacity);
 
119
                }
 
120
            }
 
121
            else if (event->xclient.message_type ==
 
122
                     Atoms::winBrightness)
 
123
            {
 
124
                w = screen->findWindow (event->xclient.window);
 
125
                if (w)
 
126
                {
 
127
                    unsigned short brightness = event->xclient.data.l[0] >> 16;
 
128
 
 
129
                    screen->setWindowProp32 (w->id (),
 
130
                        Atoms::winBrightness, brightness);
 
131
                }
 
132
            }
 
133
            else if (event->xclient.message_type ==
 
134
                     Atoms::winSaturation)
 
135
            {
 
136
                w = screen->findWindow (event->xclient.window);
 
137
                if (w)
 
138
                {
 
139
                    unsigned short saturation = event->xclient.data.l[0] >> 16;
 
140
 
 
141
                    screen->setWindowProp32 (w->id (),
 
142
                        Atoms::winSaturation, saturation);
 
143
                }
 
144
            }
 
145
            break;
 
146
        default:
 
147
            if (event->type == damageEvent + XDamageNotify)
 
148
            {
 
149
                XDamageNotifyEvent *de = (XDamageNotifyEvent *) event;
 
150
 
 
151
                if (lastDamagedWindow && de->drawable == lastDamagedWindow->id ())
 
152
                {
 
153
                    w = lastDamagedWindow;
 
154
                }
 
155
                else
 
156
                {
 
157
                    w = screen->findWindow (de->drawable);
 
158
                    if (w)
 
159
                        lastDamagedWindow = w;
 
160
                }
 
161
 
 
162
                if (w)
 
163
                    CompositeWindow::get (w)->processDamage (de);
 
164
            }
 
165
            else if (shapeExtension &&
 
166
                     event->type == shapeEvent + ShapeNotify)
 
167
            {
 
168
                w = screen->findWindow (((XShapeEvent *) event)->window);
 
169
                if (w)
 
170
                {
 
171
                    if (w->mapNum ())
 
172
                    {
 
173
                        CompositeWindow::get (w)->addDamage ();
 
174
                    }
 
175
                }
 
176
            }
 
177
            else if (randrExtension &&
 
178
                     event->type == randrEvent + RRScreenChangeNotify)
 
179
            {
 
180
                XRRScreenChangeNotifyEvent *rre;
 
181
 
 
182
                rre = (XRRScreenChangeNotifyEvent *) event;
 
183
 
 
184
                if (screen->root () == rre->root)
 
185
                    cScreen->detectRefreshRate ();
 
186
            }
 
187
            break;
 
188
    }
 
189
}
 
190
 
 
191
int
 
192
CompositeScreen::damageEvent ()
 
193
{
 
194
    return priv->damageEvent;
 
195
}
 
196
 
 
197
 
 
198
CompositeScreen::CompositeScreen (CompScreen *s) :
 
199
    PrivateHandler<CompositeScreen, CompScreen, COMPIZ_COMPOSITE_ABI> (s),
 
200
    priv (new PrivateCompositeScreen (this))
 
201
{
 
202
    int compositeMajor, compositeMinor;
 
203
 
 
204
    if (!compositeVTable->getMetadata ()->initOptions (compositeOptionInfo,
 
205
                                                       COMPOSITE_OPTION_NUM,
 
206
                                                       priv->opt))
 
207
    {
 
208
        setFailed ();
 
209
        return;
 
210
    }
 
211
 
 
212
    if (!XQueryExtension (s->dpy (), COMPOSITE_NAME,
 
213
                          &priv->compositeOpcode,
 
214
                          &priv->compositeEvent,
 
215
                          &priv->compositeError))
 
216
    {
 
217
        compLogMessage ("core", CompLogLevelFatal,
 
218
                        "No composite extension");
 
219
        setFailed ();
 
220
        return;
 
221
    }
 
222
 
 
223
    XCompositeQueryVersion (s->dpy (), &compositeMajor, &compositeMinor);
 
224
    if (compositeMajor == 0 && compositeMinor < 2)
 
225
    {
 
226
        compLogMessage ("core", CompLogLevelFatal,
 
227
                        "Old composite extension");
 
228
        setFailed ();
 
229
        return;
 
230
    }
 
231
 
 
232
    if (!XDamageQueryExtension (s->dpy (), &priv->damageEvent,
 
233
                                &priv->damageError))
 
234
    {
 
235
        compLogMessage ("core", CompLogLevelFatal,
 
236
                        "No damage extension");
 
237
        setFailed ();
 
238
        return;
 
239
    }
 
240
 
 
241
    if (!XFixesQueryExtension (s->dpy (), &priv->fixesEvent, &priv->fixesError))
 
242
    {
 
243
        compLogMessage ("core", CompLogLevelFatal,
 
244
                        "No fixes extension");
 
245
        setFailed ();
 
246
        return;
 
247
    }
 
248
 
 
249
    priv->shapeExtension = XShapeQueryExtension (s->dpy (), &priv->shapeEvent,
 
250
                                                 &priv->shapeError);
 
251
    priv->randrExtension = XRRQueryExtension (s->dpy (), &priv->randrEvent,
 
252
                                              &priv->randrError);
 
253
 
 
254
    priv->makeOutputWindow ();
 
255
 
 
256
    detectRefreshRate ();
 
257
 
 
258
    priv->slowAnimations = false;
 
259
 
 
260
    if (!priv->init ())
 
261
    {
 
262
        setFailed ();
 
263
    }
 
264
 
 
265
}
 
266
 
 
267
CompositeScreen::~CompositeScreen ()
 
268
{
 
269
    priv->paintTimer.stop ();
 
270
 
 
271
#ifdef USE_COW
 
272
    if (useCow)
 
273
        XCompositeReleaseOverlayWindow (screen->dpy (),
 
274
                                        screen->root ());
 
275
#endif
 
276
 
 
277
    delete priv;
 
278
}
 
279
 
 
280
 
 
281
PrivateCompositeScreen::PrivateCompositeScreen (CompositeScreen *cs) :
 
282
    cScreen (cs),
 
283
    damageMask (COMPOSITE_SCREEN_DAMAGE_ALL_MASK),
 
284
    overlay (None),
 
285
    output (None),
 
286
    exposeRects (),
 
287
    windowPaintOffset (0, 0),
 
288
    overlayWindowCount (0),
 
289
    nextRedraw (0),
 
290
    redrawTime (1000 / 50),
 
291
    optimalRedrawTime (1000 / 50),
 
292
    frameStatus (0),
 
293
    timeMult (1),
 
294
    idle (true),
 
295
    timeLeft (0),
 
296
    slowAnimations (false),
 
297
    active (false),
 
298
    pHnd (NULL),
 
299
    opt (COMPOSITE_OPTION_NUM)
 
300
{
 
301
    gettimeofday (&lastRedraw, 0);
 
302
    // wrap outputChangeNotify
 
303
    ScreenInterface::setHandler (screen);
 
304
}
 
305
 
 
306
PrivateCompositeScreen::~PrivateCompositeScreen ()
 
307
{
 
308
}
 
309
 
 
310
bool
 
311
PrivateCompositeScreen::init ()
 
312
{
 
313
    Display              *dpy = screen->dpy ();
 
314
    Window               newCmSnOwner = None;
 
315
    Atom                 cmSnAtom = 0;
 
316
    Time                 cmSnTimestamp = 0;
 
317
    XEvent               event;
 
318
    XSetWindowAttributes attr;
 
319
    Window               currentCmSnOwner;
 
320
    char                 buf[128];
 
321
 
 
322
    sprintf (buf, "_NET_WM_CM_S%d", screen->screenNum ());
 
323
    cmSnAtom = XInternAtom (dpy, buf, 0);
 
324
 
 
325
    currentCmSnOwner = XGetSelectionOwner (dpy, cmSnAtom);
 
326
 
 
327
    if (currentCmSnOwner != None)
 
328
    {
 
329
        if (!replaceCurrentWm)
 
330
        {
 
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));
 
337
 
 
338
            return false;
 
339
        }
 
340
    }
 
341
 
 
342
    attr.override_redirect = TRUE;
 
343
    attr.event_mask        = PropertyChangeMask;
 
344
 
 
345
    newCmSnOwner =
 
346
        XCreateWindow (dpy, XRootWindow (dpy, screen->screenNum ()),
 
347
                       -100, -100, 1, 1, 0,
 
348
                       CopyFromParent, CopyFromParent,
 
349
                       CopyFromParent,
 
350
                       CWOverrideRedirect | CWEventMask,
 
351
                       &attr);
 
352
 
 
353
    XChangeProperty (dpy, newCmSnOwner, Atoms::wmName, Atoms::utf8String, 8,
 
354
                     PropModeReplace, (unsigned char *) PACKAGE,
 
355
                     strlen (PACKAGE));
 
356
 
 
357
    XWindowEvent (dpy, newCmSnOwner, PropertyChangeMask, &event);
 
358
 
 
359
    cmSnTimestamp = event.xproperty.time;
 
360
 
 
361
 
 
362
    XSetSelectionOwner (dpy, cmSnAtom, newCmSnOwner, cmSnTimestamp);
 
363
 
 
364
    if (XGetSelectionOwner (dpy, cmSnAtom) != newCmSnOwner)
 
365
    {
 
366
        compLogMessage ("composite", CompLogLevelError,
 
367
                        "Could not acquire compositing manager "
 
368
                        "selection on screen %d display \"%s\"",
 
369
                        screen->screenNum (), DisplayString (dpy));
 
370
 
 
371
        return false;
 
372
    }
 
373
 
 
374
    return true;
 
375
}
 
376
 
 
377
 
 
378
bool
 
379
CompositeScreen::registerPaintHandler (PaintHandler *pHnd)
 
380
{
 
381
    Display *dpy = screen->dpy ();
 
382
 
 
383
    if (priv->active)
 
384
        return false;
 
385
 
 
386
    CompScreen::checkForError (dpy);
 
387
 
 
388
    XCompositeRedirectSubwindows (dpy, screen->root (),
 
389
                                  CompositeRedirectManual);
 
390
 
 
391
    priv->overlayWindowCount = 0;
 
392
 
 
393
    if (CompScreen::checkForError (dpy))
 
394
    {
 
395
        compLogMessage ("composite", CompLogLevelError,
 
396
                        "Another composite manager is already "
 
397
                        "running on screen: %d", screen->screenNum ());
 
398
 
 
399
        return false;
 
400
    }
 
401
 
 
402
    foreach (CompWindow *w, screen->windows ())
 
403
    {
 
404
        CompositeWindow *cw = CompositeWindow::get (w);
 
405
        cw->priv->overlayWindow = false;
 
406
        cw->priv->redirected = true;
 
407
    }
 
408
 
 
409
    priv->pHnd = pHnd;
 
410
    priv->active = true;
 
411
 
 
412
    showOutputWindow ();
 
413
 
 
414
    priv->paintTimer.start
 
415
        (boost::bind(&CompositeScreen::handlePaintTimeout, this),
 
416
         priv->optimalRedrawTime, MAXSHORT);
 
417
    return true;
 
418
}
 
419
 
 
420
void
 
421
CompositeScreen::unregisterPaintHandler ()
 
422
{
 
423
    Display *dpy = screen->dpy ();
 
424
 
 
425
    foreach (CompWindow *w, screen->windows ())
 
426
    {
 
427
        CompositeWindow *cw = CompositeWindow::get (w);
 
428
        cw->priv->overlayWindow = false;
 
429
        cw->priv->redirected = false;
 
430
        cw->release ();
 
431
    }
 
432
 
 
433
    priv->overlayWindowCount = 0;
 
434
 
 
435
    XCompositeUnredirectSubwindows (dpy, screen->root (),
 
436
                                    CompositeRedirectManual);
 
437
 
 
438
    priv->pHnd = NULL;
 
439
    priv->active = false;
 
440
    priv->paintTimer.stop ();
 
441
 
 
442
    hideOutputWindow ();
 
443
}
 
444
 
 
445
bool
 
446
CompositeScreen::compositingActive ()
 
447
{
 
448
    return priv->active;
 
449
}
 
450
 
 
451
void
 
452
CompositeScreen::damageScreen ()
 
453
{
 
454
    if (priv->damageMask == 0)
 
455
        priv->paintTimer.setTimes (priv->paintTimer.minLeft ());
 
456
 
 
457
    priv->damageMask |= COMPOSITE_SCREEN_DAMAGE_ALL_MASK;
 
458
    priv->damageMask &= ~COMPOSITE_SCREEN_DAMAGE_REGION_MASK;
 
459
}
 
460
 
 
461
void
 
462
CompositeScreen::damageRegion (const CompRegion &region)
 
463
{
 
464
    if (priv->damageMask & COMPOSITE_SCREEN_DAMAGE_ALL_MASK)
 
465
        return;
 
466
 
 
467
    if (priv->damageMask == 0)
 
468
        priv->paintTimer.setTimes (priv->paintTimer.minLeft ());
 
469
 
 
470
    priv->damage += region;
 
471
 
 
472
    priv->damageMask |= COMPOSITE_SCREEN_DAMAGE_REGION_MASK;
 
473
 
 
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 */
 
478
 
 
479
    if (priv->damage.numRects () > 100)
 
480
       damageScreen ();
 
481
}
 
482
 
 
483
void
 
484
CompositeScreen::damagePending ()
 
485
{
 
486
    if (priv->damageMask == 0)
 
487
        priv->paintTimer.setTimes (priv->paintTimer.minLeft ());
 
488
 
 
489
    priv->damageMask |= COMPOSITE_SCREEN_DAMAGE_PENDING_MASK;
 
490
}
 
491
 
 
492
unsigned int
 
493
CompositeScreen::damageMask ()
 
494
{
 
495
    return priv->damageMask;
 
496
}
 
497
 
 
498
void
 
499
CompositeScreen::showOutputWindow ()
 
500
{
 
501
#ifdef USE_COW
 
502
    if (useCow && priv->active)
 
503
    {
 
504
        Display       *dpy = screen->dpy ();
 
505
        XserverRegion region;
 
506
 
 
507
        region = XFixesCreateRegion (dpy, NULL, 0);
 
508
 
 
509
        XFixesSetWindowShapeRegion (dpy,
 
510
                                    priv->output,
 
511
                                    ShapeBounding,
 
512
                                    0, 0, 0);
 
513
        XFixesSetWindowShapeRegion (dpy,
 
514
                                    priv->output,
 
515
                                    ShapeInput,
 
516
                                    0, 0, region);
 
517
 
 
518
        XFixesDestroyRegion (dpy, region);
 
519
 
 
520
        damageScreen ();
 
521
    }
 
522
#endif
 
523
 
 
524
}
 
525
 
 
526
void
 
527
CompositeScreen::hideOutputWindow ()
 
528
{
 
529
#ifdef USE_COW
 
530
    if (useCow)
 
531
    {
 
532
        Display       *dpy = screen->dpy ();
 
533
        XserverRegion region;
 
534
 
 
535
        region = XFixesCreateRegion (dpy, NULL, 0);
 
536
 
 
537
        XFixesSetWindowShapeRegion (dpy,
 
538
                                    priv->output,
 
539
                                    ShapeBounding,
 
540
                                    0, 0, region);
 
541
 
 
542
        XFixesDestroyRegion (dpy, region);
 
543
    }
 
544
#endif
 
545
 
 
546
}
 
547
 
 
548
void
 
549
CompositeScreen::updateOutputWindow ()
 
550
{
 
551
#ifdef USE_COW
 
552
    if (useCow && priv->active)
 
553
    {
 
554
        Display       *dpy = screen->dpy ();
 
555
        XserverRegion region;
 
556
        CompRegion    tmpRegion (screen->region ());
 
557
        
 
558
        for (CompWindowList::reverse_iterator rit =
 
559
             screen->windows ().rbegin ();
 
560
             rit != screen->windows ().rend (); rit++)
 
561
            if (CompositeWindow::get (*rit)->overlayWindow ())
 
562
            {
 
563
                tmpRegion -= (*rit)->region ();
 
564
            }
 
565
        
 
566
        XShapeCombineRegion (dpy, priv->output, ShapeBounding,
 
567
                             0, 0, tmpRegion.handle (), ShapeSet);
 
568
 
 
569
 
 
570
        region = XFixesCreateRegion (dpy, NULL, 0);
 
571
 
 
572
        XFixesSetWindowShapeRegion (dpy,
 
573
                                    priv->output,
 
574
                                    ShapeInput,
 
575
                                    0, 0, region);
 
576
 
 
577
        XFixesDestroyRegion (dpy, region);
 
578
    }
 
579
#endif
 
580
 
 
581
}
 
582
 
 
583
void
 
584
PrivateCompositeScreen::makeOutputWindow ()
 
585
{
 
586
#ifdef USE_COW
 
587
    if (useCow)
 
588
    {
 
589
        overlay = XCompositeGetOverlayWindow (screen->dpy (), screen->root ());
 
590
        output  = overlay;
 
591
 
 
592
        XSelectInput (screen->dpy (), output, ExposureMask);
 
593
    }
 
594
    else
 
595
#endif
 
596
        output = overlay = screen->root ();
 
597
 
 
598
    cScreen->hideOutputWindow ();
 
599
}
 
600
 
 
601
Window
 
602
CompositeScreen::output ()
 
603
{
 
604
    return priv->output;
 
605
}
 
606
 
 
607
Window
 
608
CompositeScreen::overlay ()
 
609
{
 
610
    return priv->overlay;
 
611
}
 
612
 
 
613
int &
 
614
CompositeScreen::overlayWindowCount ()
 
615
{
 
616
    return priv->overlayWindowCount;
 
617
}
 
618
 
 
619
void
 
620
CompositeScreen::setWindowPaintOffset (int x, int y)
 
621
{
 
622
    priv->windowPaintOffset = CompPoint (x, y);
 
623
}
 
624
 
 
625
CompPoint
 
626
CompositeScreen::windowPaintOffset ()
 
627
{
 
628
    return priv->windowPaintOffset;
 
629
}
 
630
 
 
631
void
 
632
CompositeScreen::detectRefreshRate ()
 
633
{
 
634
    if (!noDetection &&
 
635
        priv->opt[COMPOSITE_OPTION_DETECT_REFRESH_RATE].value ().b ())
 
636
    {
 
637
        CompString        name;
 
638
        CompOption::Value value;
 
639
 
 
640
        value.set ((int) 0);
 
641
 
 
642
        if (screen->XRandr())
 
643
        {
 
644
            XRRScreenConfiguration *config;
 
645
 
 
646
            config  = XRRGetScreenInfo (screen->dpy (),
 
647
                                        screen->root ());
 
648
            value.set ((int) XRRConfigCurrentRate (config));
 
649
 
 
650
            XRRFreeScreenConfigInfo (config);
 
651
        }
 
652
 
 
653
        if (value.i () == 0)
 
654
            value.set ((int) 50);
 
655
 
 
656
        name = priv->opt[COMPOSITE_OPTION_REFRESH_RATE].name ();
 
657
 
 
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);
 
661
    }
 
662
    else
 
663
    {
 
664
        priv->redrawTime = 1000 /
 
665
            priv->opt[COMPOSITE_OPTION_REFRESH_RATE].value ().i ();
 
666
        priv->optimalRedrawTime = priv->redrawTime;
 
667
    }
 
668
}
 
669
 
 
670
int
 
671
CompositeScreen::getTimeToNextRedraw (struct timeval *tv)
 
672
{
 
673
    int diff, next;
 
674
 
 
675
    diff = TIMEVALDIFF (tv, &priv->lastRedraw);
 
676
 
 
677
    /* handle clock rollback */
 
678
    if (diff < 0)
 
679
        diff = 0;
 
680
 
 
681
    if (priv->idle || (priv->pHnd && priv->pHnd->hasVSync ()))
 
682
    {
 
683
        if (priv->timeMult > 1)
 
684
        {
 
685
            priv->frameStatus = -1;
 
686
            priv->redrawTime = priv->optimalRedrawTime;
 
687
            priv->timeMult--;
 
688
        }
 
689
    }
 
690
    else
 
691
    {
 
692
        if (diff > priv->redrawTime)
 
693
        {
 
694
            if (priv->frameStatus > 0)
 
695
                priv->frameStatus = 0;
 
696
 
 
697
            next = priv->optimalRedrawTime * (priv->timeMult + 1);
 
698
            if (diff > next)
 
699
            {
 
700
                priv->frameStatus--;
 
701
                if (priv->frameStatus < -1)
 
702
                {
 
703
                    priv->timeMult++;
 
704
                    priv->redrawTime = diff = next;
 
705
                }
 
706
            }
 
707
        }
 
708
        else if (diff < priv->redrawTime)
 
709
        {
 
710
            if (priv->frameStatus < 0)
 
711
                priv->frameStatus = 0;
 
712
 
 
713
            if (priv->timeMult > 1)
 
714
            {
 
715
                next = priv->optimalRedrawTime * (priv->timeMult - 1);
 
716
                if (diff < next)
 
717
                {
 
718
                    priv->frameStatus++;
 
719
                    if (priv->frameStatus > 4)
 
720
                    {
 
721
                        priv->timeMult--;
 
722
                        priv->redrawTime = next;
 
723
                    }
 
724
                }
 
725
            }
 
726
        }
 
727
    }
 
728
    if (diff >= priv->redrawTime)
 
729
        return 1;
 
730
 
 
731
    return priv->redrawTime - diff;
 
732
}
 
733
 
 
734
int
 
735
CompositeScreen::redrawTime ()
 
736
{
 
737
    return priv->redrawTime;
 
738
}
 
739
 
 
740
bool
 
741
CompositeScreen::handlePaintTimeout ()
 
742
{
 
743
    int         timeDiff;
 
744
    struct      timeval tv;
 
745
 
 
746
    gettimeofday (&tv, 0);
 
747
 
 
748
    if (priv->damageMask)
 
749
    {
 
750
        if (priv->pHnd)
 
751
            priv->pHnd->prepareDrawing ();
 
752
 
 
753
        timeDiff = TIMEVALDIFF (&tv, &priv->lastRedraw);
 
754
 
 
755
        /* handle clock rollback */
 
756
        if (timeDiff < 0)
 
757
            timeDiff = 0;
 
758
 
 
759
        if (priv->slowAnimations)
 
760
        {
 
761
            preparePaint (priv->idle ? 2 : (timeDiff * 2) / priv->redrawTime);
 
762
        }
 
763
        else
 
764
            preparePaint (priv->idle ? priv->redrawTime : timeDiff);
 
765
 
 
766
        /* substract top most overlay window region */
 
767
        if (priv->overlayWindowCount)
 
768
        {
 
769
            for (CompWindowList::reverse_iterator rit =
 
770
                 screen->windows ().rbegin ();
 
771
                 rit != screen->windows ().rend (); rit++)
 
772
            {
 
773
                CompWindow *w = (*rit);
 
774
 
 
775
                if (w->destroyed () || w->invisible ())
 
776
                    continue;
 
777
 
 
778
                if (!CompositeWindow::get (w)->redirected ())
 
779
                    priv->damage -= w->region ();
 
780
 
 
781
                break;
 
782
            }
 
783
 
 
784
            if (priv->damageMask & COMPOSITE_SCREEN_DAMAGE_ALL_MASK)
 
785
            {
 
786
                priv->damageMask &= ~COMPOSITE_SCREEN_DAMAGE_ALL_MASK;
 
787
                priv->damageMask |= COMPOSITE_SCREEN_DAMAGE_REGION_MASK;
 
788
            }
 
789
        }
 
790
 
 
791
        priv->tmpRegion = priv->damage & screen->region ();
 
792
        
 
793
        if (priv->damageMask & COMPOSITE_SCREEN_DAMAGE_REGION_MASK)
 
794
        {
 
795
            if (priv->tmpRegion == screen->region ())
 
796
                damageScreen ();
 
797
        }
 
798
 
 
799
        priv->damage = CompRegion ();
 
800
 
 
801
        int mask = priv->damageMask;
 
802
        priv->damageMask = 0;
 
803
 
 
804
        CompOutput::ptrList outputs (0);
 
805
        
 
806
        if (priv->opt[COMPOSITE_OPTION_FORCE_INDEPENDENT].value ().b ()
 
807
            || !screen->hasOverlappingOutputs ())
 
808
        {
 
809
            foreach (CompOutput &o, screen->outputDevs ())
 
810
                outputs.push_back (&o);
 
811
        }
 
812
        else
 
813
            outputs.push_back (&screen->fullscreenOutput ());
 
814
 
 
815
        paint (outputs, mask);
 
816
        
 
817
        priv->lastRedraw = tv;
 
818
 
 
819
        donePaint ();
 
820
 
 
821
        foreach (CompWindow *w, screen->windows ())
 
822
        {
 
823
            if (w->destroyed ())
 
824
            {
 
825
                CompositeWindow::get (w)->addDamage ();
 
826
                break;
 
827
            }
 
828
        }
 
829
 
 
830
        priv->idle = false;
 
831
    }
 
832
    else
 
833
    {
 
834
        priv->idle = true;
 
835
    }
 
836
 
 
837
    gettimeofday (&tv, 0);
 
838
 
 
839
    if (priv->idle)
 
840
        priv->paintTimer.setTimes (getTimeToNextRedraw (&tv), MAXSHORT);
 
841
    else
 
842
        priv->paintTimer.setTimes (getTimeToNextRedraw (&tv));
 
843
    return true;
 
844
}
 
845
 
 
846
void
 
847
CompositeScreen::preparePaint (int msSinceLastPaint)
 
848
    WRAPABLE_HND_FUNC(0, preparePaint, msSinceLastPaint)
 
849
 
 
850
void
 
851
CompositeScreen::donePaint ()
 
852
    WRAPABLE_HND_FUNC(1, donePaint)
 
853
 
 
854
void
 
855
CompositeScreen::paint (CompOutput::ptrList &outputs,
 
856
                        unsigned int        mask)
 
857
{
 
858
    WRAPABLE_HND_FUNC(2, paint, outputs, mask)
 
859
 
 
860
    if (priv->pHnd)
 
861
        priv->pHnd->paintOutputs (outputs, mask, priv->tmpRegion);
 
862
}
 
863
 
 
864
CompWindowList
 
865
CompositeScreen::getWindowPaintList ()
 
866
{
 
867
    WRAPABLE_HND_FUNC_RETURN (3, CompWindowList, getWindowPaintList)
 
868
 
 
869
    return screen->windows ();
 
870
}
 
871
 
 
872
void
 
873
PrivateCompositeScreen::handleExposeEvent (XExposeEvent *event)
 
874
{
 
875
    if (output == event->window)
 
876
        return;
 
877
 
 
878
    exposeRects.push_back (CompRect (event->x,
 
879
                                     event->y,
 
880
                                     event->width,
 
881
                                     event->height));
 
882
 
 
883
    if (event->count == 0)
 
884
    {
 
885
        CompRect rect;
 
886
        foreach (CompRect rect, exposeRects)
 
887
        {
 
888
            cScreen->damageRegion (CompRegion (rect));
 
889
        }
 
890
        exposeRects.clear ();
 
891
    }
 
892
}
 
893
 
 
894
void
 
895
PrivateCompositeScreen::outputChangeNotify ()
 
896
{
 
897
    screen->outputChangeNotify ();
 
898
#ifdef USE_COW
 
899
    if (useCow)
 
900
        XMoveResizeWindow (screen->dpy (), overlay, 0, 0,
 
901
                           screen->width (), screen->height ());
 
902
#endif
 
903
    cScreen->damageScreen ();
 
904
}
 
905
 
 
906
bool
 
907
CompositeScreen::toggleSlowAnimations (CompAction         *action,
 
908
                                       CompAction::State  state,
 
909
                                       CompOption::Vector &options)
 
910
{
 
911
    CompositeScreen *cs = CompositeScreen::get (screen);
 
912
    if (cs)
 
913
        cs->priv->slowAnimations = !cs->priv->slowAnimations;
 
914
 
 
915
    return true;
 
916
}
 
917
 
 
918
 
 
919
void
 
920
CompositeScreenInterface::preparePaint (int msSinceLastPaint)
 
921
    WRAPABLE_DEF (preparePaint, msSinceLastPaint)
 
922
 
 
923
void
 
924
CompositeScreenInterface::donePaint ()
 
925
    WRAPABLE_DEF (donePaint)
 
926
 
 
927
void
 
928
CompositeScreenInterface::paint (CompOutput::ptrList &outputs,
 
929
                                 unsigned int        mask)
 
930
    WRAPABLE_DEF (paint, outputs, mask)
 
931
 
 
932
CompWindowList
 
933
CompositeScreenInterface::getWindowPaintList ()
 
934
    WRAPABLE_DEF (getWindowPaintList)
 
935
 
 
936
const CompRegion &
 
937
CompositeScreen::currentDamage () const
 
938
{
 
939
    return priv->damage;
 
940
}