~compiz-team/compiz-core/compiz-core.fix_796594

« back to all changes in this revision

Viewing changes to src/screen.cpp

  • Committer: Sam Spilsbury
  • Date: 2011-09-19 12:34:21 UTC
  • mfrom: (2800.2.17)
  • Revision ID: git-v1:06de32fbb7c893f6d051073985588b38b5193cc6
MergeĀ lp:~compiz-team/compiz-core/compiz-core.stack_sync_fix

Show diffs side-by-side

added added

removed removed

Lines of Context:
14
14
 *
15
15
 * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16
16
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
17
 
 * NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECI<<<<<fAL, INDIRECT OR
 
17
 * NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
18
18
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
19
19
 * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
20
20
 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
60
60
#include "privatescreen.h"
61
61
#include "privatewindow.h"
62
62
#include "privateaction.h"
 
63
#include "privatestackdebugger.h"
63
64
 
64
65
bool inHandleEvent = false;
65
66
 
620
621
    return rv;
621
622
}
622
623
 
 
624
std::list <XEvent>
 
625
PrivateScreen::queueEvents ()
 
626
{
 
627
    std::list <XEvent> events;
 
628
 
 
629
    while (XPending (dpy))
 
630
    {
 
631
        XEvent event, peekEvent;
 
632
        XNextEvent (dpy, &event);
 
633
 
 
634
        /* Skip to the last MotionNotify
 
635
         * event in this sequence */
 
636
        if (event.type == MotionNotify)
 
637
        {
 
638
            while (XPending (dpy))
 
639
            {
 
640
                XPeekEvent (dpy, &peekEvent);
 
641
 
 
642
                if (peekEvent.type != MotionNotify)
 
643
                    break;
 
644
 
 
645
                XNextEvent (dpy, &event);
 
646
            }
 
647
        }
 
648
 
 
649
        events.push_back (event);
 
650
    }
 
651
 
 
652
    return events;
 
653
}
 
654
 
623
655
void
624
656
PrivateScreen::processEvents ()
625
657
{
626
 
    XEvent event, peekEvent;
627
 
 
628
 
    /* remove destroyed windows */
629
 
    removeDestroyed ();
 
658
    std::list <XEvent> events;
 
659
    StackDebugger *dbg = StackDebugger::Default ();
630
660
 
631
661
    if (dirtyPluginList)
632
662
        updatePlugins ();
633
663
 
634
 
    while (XPending (dpy))
635
 
    {
636
 
        XNextEvent (dpy, &event);
637
 
 
 
664
    /* Restacks recently processed, ensure that
 
665
     * plugins use the stack last received from
 
666
     * the server */
 
667
    if (stackIsFresh)
 
668
    {
 
669
        priv->serverWindows.clear ();
 
670
 
 
671
        foreach (CompWindow *sw, priv->windows)
 
672
        {
 
673
            sw->serverPrev = sw->prev;
 
674
            sw->serverNext = sw->next;
 
675
            priv->serverWindows.push_back (sw);
 
676
        }
 
677
    }
 
678
 
 
679
    if (dbg)
 
680
    {
 
681
        dbg->windowsChanged (false);
 
682
        dbg->serverWindowsChanged (false);
 
683
        events = dbg->loadStack (priv->serverWindows);
 
684
    }
 
685
    else
 
686
        events = queueEvents ();
 
687
 
 
688
    stackIsFresh = false;
 
689
 
 
690
    foreach (XEvent &event, events)
 
691
    {
638
692
        switch (event.type) {
639
693
        case ButtonPress:
640
694
        case ButtonRelease:
646
700
        case KeyRelease:
647
701
            pointerX = event.xkey.x_root;
648
702
            pointerY = event.xkey.y_root;
649
 
            pointerMods = event.xbutton.state;
 
703
            pointerMods = event.xkey.state;
650
704
            break;
651
705
        case MotionNotify:
652
 
            while (XPending (dpy))
653
 
            {
654
 
                XPeekEvent (dpy, &peekEvent);
655
 
 
656
 
                if (peekEvent.type != MotionNotify)
657
 
                    break;
658
 
 
659
 
                XNextEvent (dpy, &event);
660
 
            }
661
706
 
662
707
            pointerX = event.xmotion.x_root;
663
708
            pointerY = event.xmotion.y_root;
664
 
            pointerMods = event.xbutton.state;
 
709
            pointerMods = event.xmotion.state;
665
710
            break;
666
711
        case EnterNotify:
667
712
        case LeaveNotify:
668
713
            pointerX = event.xcrossing.x_root;
669
714
            pointerY = event.xcrossing.y_root;
670
 
            pointerMods = event.xbutton.state;
 
715
            pointerMods = event.xcrossing.state;
671
716
            break;
672
717
        case ClientMessage:
673
718
            if (event.xclient.message_type == Atoms::xdndPosition)
707
752
        lastPointerY = pointerY;
708
753
        lastPointerMods = pointerMods;
709
754
    }
 
755
 
 
756
    /* remove destroyed windows */
 
757
    removeDestroyed ();
 
758
 
 
759
    if (dbg)
 
760
    {
 
761
        if (dbg->windowsChanged () && dbg->cmpStack (priv->windows, priv->serverWindows))
 
762
        {
 
763
            compLogMessage ("core", CompLogLevelDebug, "stacks are out of sync");
 
764
            if (dbg->timedOut ())
 
765
                compLogMessage ("core", CompLogLevelDebug, "however, this may be a false positive");
 
766
        }
 
767
 
 
768
        if (dbg->serverWindowsChanged () && dbg->checkSanity (priv->serverWindows))
 
769
            compLogMessage ("core", CompLogLevelDebug, "windows are stacked incorrectly");
 
770
    }
710
771
}
711
772
 
712
773
void
2496
2557
    }
2497
2558
 
2498
2559
    foreach (CompWindow *w, priv->windows)
2499
 
        if (w->frame () == id)
 
2560
        if (w->priv->frame == id)
2500
2561
        {
2501
2562
            if (w->overrideRedirect () && !override_redirect)
2502
2563
                return NULL;
2510
2571
void
2511
2572
CompScreen::insertWindow (CompWindow *w, Window aboveId)
2512
2573
{
 
2574
    StackDebugger *dbg = StackDebugger::Default ();
 
2575
 
 
2576
    if (dbg)
 
2577
        dbg->windowsChanged (true);
 
2578
 
 
2579
    priv->stackIsFresh = true;
 
2580
 
2513
2581
    w->prev = NULL;
2514
2582
    w->next = NULL;
2515
2583
 
2532
2600
    while (it != priv->windows.end ())
2533
2601
    {
2534
2602
        if ((*it)->id () == aboveId ||
2535
 
            ((*it)->frame () && (*it)->frame () == aboveId))
 
2603
            ((*it)->priv->frame && (*it)->priv->frame == aboveId))
2536
2604
        {
2537
2605
            break;
2538
2606
        }
2541
2609
 
2542
2610
    if (it == priv->windows.end ())
2543
2611
    {
 
2612
        compLogMessage ("core", CompLogLevelDebug, "could not insert 0x%x above 0x%x",
 
2613
                        (unsigned int) (*it)->priv->serverId, aboveId);
2544
2614
#ifdef DEBUG
2545
2615
        abort ();
2546
2616
#endif
2562
2632
}
2563
2633
 
2564
2634
void
 
2635
CompScreen::insertServerWindow (CompWindow *w, Window   aboveId)
 
2636
{
 
2637
    StackDebugger *dbg = StackDebugger::Default ();
 
2638
 
 
2639
    if (dbg)
 
2640
        dbg->serverWindowsChanged (true);
 
2641
 
 
2642
    w->serverPrev = NULL;
 
2643
    w->serverNext = NULL;
 
2644
 
 
2645
    if (!aboveId || priv->serverWindows.empty ())
 
2646
    {
 
2647
        if (!priv->serverWindows.empty ())
 
2648
        {
 
2649
            priv->serverWindows.front ()->serverPrev = w;
 
2650
            w->serverNext = priv->serverWindows.front ();
 
2651
        }
 
2652
        priv->serverWindows.push_front (w);
 
2653
 
 
2654
        return;
 
2655
    }
 
2656
 
 
2657
    CompWindowList::iterator it = priv->serverWindows.begin ();
 
2658
 
 
2659
    while (it != priv->serverWindows.end ())
 
2660
    {
 
2661
        if ((*it)->priv->serverId == aboveId ||
 
2662
            ((*it)->priv->serverFrame && (*it)->priv->serverFrame == aboveId))
 
2663
        {
 
2664
            break;
 
2665
        }
 
2666
        it++;
 
2667
    }
 
2668
 
 
2669
    if (it == priv->serverWindows.end ())
 
2670
    {
 
2671
        compLogMessage ("core", CompLogLevelDebug, "could not insert 0x%x above 0x%x",
 
2672
                        (unsigned int) (*it)->priv->serverId, aboveId);
 
2673
#ifdef DEBUG
 
2674
        abort ();
 
2675
#endif
 
2676
        return;
 
2677
    }
 
2678
 
 
2679
    w->serverNext = (*it)->serverNext;
 
2680
    w->serverPrev = (*it);
 
2681
    (*it)->serverNext = w;
 
2682
 
 
2683
    if (w->serverNext)
 
2684
    {
 
2685
        w->serverNext->serverPrev = w;
 
2686
    }
 
2687
 
 
2688
    priv->serverWindows.insert (++it, w);
 
2689
}
 
2690
 
 
2691
void
2565
2692
PrivateScreen::eraseWindowFromMap (Window id)
2566
2693
{
2567
2694
    if (id != 1)
2571
2698
void
2572
2699
CompScreen::unhookWindow (CompWindow *w)
2573
2700
{
 
2701
    StackDebugger *dbg = StackDebugger::Default ();
 
2702
 
 
2703
    if (dbg)
 
2704
        dbg->windowsChanged (true);
 
2705
 
2574
2706
    CompWindowList::iterator it =
2575
2707
        std::find (priv->windows.begin (), priv->windows.end (), w);
2576
2708
 
2590
2722
        lastFoundWindow = NULL;
2591
2723
}
2592
2724
 
 
2725
void
 
2726
CompScreen::unhookServerWindow (CompWindow *w)
 
2727
{
 
2728
    StackDebugger *dbg = StackDebugger::Default ();
 
2729
 
 
2730
    if (dbg)
 
2731
        dbg->serverWindowsChanged (true);
 
2732
 
 
2733
    CompWindowList::iterator it =
 
2734
        std::find (priv->serverWindows.begin (), priv->serverWindows.end (), w);
 
2735
 
 
2736
    priv->serverWindows.erase (it);
 
2737
 
 
2738
    if (w->serverNext)
 
2739
        w->serverNext->serverPrev = w->serverPrev;
 
2740
 
 
2741
    if (w->serverPrev)
 
2742
        w->serverPrev->serverNext = w->serverNext;
 
2743
 
 
2744
    w->serverNext = NULL;
 
2745
    w->serverPrev = NULL;
 
2746
}
 
2747
 
2593
2748
Cursor
2594
2749
CompScreen::normalCursor ()
2595
2750
{
3505
3660
PrivateScreen::getTopWindow ()
3506
3661
{
3507
3662
    /* return first window that has not been destroyed */
3508
 
    for (CompWindowList::reverse_iterator rit = priv->windows.rbegin ();
3509
 
             rit != priv->windows.rend (); rit++)
3510
 
    {
3511
 
        if ((*rit)->id () > 1)
3512
 
            return (*rit)->id ();
3513
 
    }
 
3663
    if (priv->windows.size ())
 
3664
        return priv->windows.back ()->id ();
3514
3665
 
3515
3666
    return None;
3516
3667
}
3931
4082
    return priv->windows;
3932
4083
}
3933
4084
 
 
4085
CompWindowList &
 
4086
CompScreen::serverWindows ()
 
4087
{
 
4088
    return priv->serverWindows;
 
4089
}
 
4090
 
 
4091
CompWindowList &
 
4092
CompScreen::destroyedWindows ()
 
4093
{
 
4094
    return priv->destroyedWindows;
 
4095
}
 
4096
 
 
4097
 
3934
4098
Time
3935
4099
CompScreen::getCurrentTime ()
3936
4100
{
4029
4193
{
4030
4194
    while (pendingDestroys)
4031
4195
    {
4032
 
        foreach (CompWindow *w, windows)
 
4196
        foreach (CompWindow *w, destroyedWindows)
4033
4197
        {
4034
4198
            if (w->destroyed ())
4035
4199
            {
4145
4309
    if (!priv->dpy)
4146
4310
    {
4147
4311
        compLogMessage ("core", CompLogLevelFatal,
4148
 
                        "Couldn't open display %s", XDisplayName (name));
 
4312
                        "Couldn't open display %s", XDisplayName (name));
4149
4313
        return false;
4150
4314
    }
4151
4315
 
4171
4335
    if (!XSyncQueryExtension (dpy, &priv->syncEvent, &priv->syncError))
4172
4336
    {
4173
4337
        compLogMessage ("core", CompLogLevelFatal,
4174
 
                        "No sync extension");
 
4338
                        "No sync extension");
4175
4339
        return false;
4176
4340
    }
4177
4341
 
4193
4357
    else
4194
4358
    {
4195
4359
        compLogMessage ("core", CompLogLevelFatal,
4196
 
                        "No XKB extension");
 
4360
                        "No XKB extension");
4197
4361
 
4198
4362
        priv->xkbEvent = priv->xkbError = -1;
4199
4363
    }
4290
4454
 
4291
4455
    XGrabServer (dpy);
4292
4456
 
 
4457
    /* Don't select for SubstructureRedirectMask or
 
4458
     * SubstructureNotifyMask yet since we need to
 
4459
     * act in complete synchronization here when
 
4460
     * doing the initial window init in order to ensure
 
4461
     * that windows don't receive invalid stack positions
 
4462
     * but we don't want to receive an invalid CreateNotify
 
4463
     * when we create windows like edge windows here either */
4293
4464
    XSelectInput (dpy, root,
4294
 
                  SubstructureRedirectMask |
4295
 
                  SubstructureNotifyMask   |
4296
4465
                  StructureNotifyMask      |
4297
4466
                  PropertyChangeMask       |
4298
4467
                  LeaveWindowMask          |
4325
4494
    if (CompScreen::checkForError (dpy))
4326
4495
    {
4327
4496
        compLogMessage ("core", CompLogLevelError,
4328
 
                        "Another window manager is "
4329
 
                        "already running on screen: %d", DefaultScreen (dpy));
 
4497
                        "Another window manager is "
 
4498
                        "already running on screen: %d", DefaultScreen (dpy));
4330
4499
 
4331
4500
        XUngrabServer (dpy);
 
4501
        XSync (dpy, false);
4332
4502
        return false;
4333
4503
    }
4334
4504
 
4335
 
    /* We only care about windows we're not going to
4336
 
     * get a CreateNotify for later, so query the tree
4337
 
     * here, init plugin screens, and then init windows */
4338
 
 
4339
 
    XQueryTree (dpy, root,
4340
 
                &rootReturn, &parentReturn,
4341
 
                &children, &nchildren);
4342
 
 
4343
4505
    for (i = 0; i < SCREEN_EDGE_NUM; i++)
4344
4506
    {
4345
4507
        priv->screenEdge[i].id    = None;
4431
4593
 
4432
4594
        priv->screenEdge[i].id = XCreateWindow (dpy, priv->root,
4433
4595
                                                -100, -100, 1, 1, 0,
4434
 
                                                CopyFromParent, InputOnly,
4435
 
                                                CopyFromParent,
 
4596
                                                CopyFromParent, InputOnly,
 
4597
                                                CopyFromParent,
4436
4598
                                                CWOverrideRedirect,
4437
 
                                                &attrib);
 
4599
                                                &attrib);
4438
4600
 
4439
4601
        XChangeProperty (dpy, priv->screenEdge[i].id, Atoms::xdndAware,
4440
4602
                         XA_ATOM, 32, PropModeReplace,
4445
4607
         * CreateNotify of this window, so no need
4446
4608
         * to select for them here */
4447
4609
        XSelectInput (dpy, priv->screenEdge[i].id,
 
4610
                      StructureNotifyMask |
4448
4611
                      ButtonPressMask   |
4449
4612
                      ButtonReleaseMask |
4450
4613
                      PointerMotionMask);
4461
4624
 
4462
4625
    XDefineCursor (dpy, priv->root, priv->normalCursor);
4463
4626
 
 
4627
    /* We should get DestroyNotify events for any windows that were
 
4628
     * destroyed while initializing windows here now */
 
4629
    XSelectInput (dpy, root, priv->attrib.your_event_mask |
 
4630
                  SubstructureRedirectMask | SubstructureNotifyMask);
 
4631
 
 
4632
    XQueryTree (dpy, root,
 
4633
                &rootReturn, &parentReturn,
 
4634
                &children, &nchildren);
 
4635
 
4464
4636
    XUngrabServer (dpy);
4465
4637
    XSync (dpy, FALSE);
4466
4638
 
4467
 
    priv->setAudibleBell (priv->optionGetAudibleBell ());
4468
 
 
4469
 
    priv->pingTimer.setTimes (priv->optionGetPingDelay (),
4470
 
                              priv->optionGetPingDelay () + 500);
4471
 
 
4472
 
    priv->pingTimer.start ();
4473
 
 
4474
 
    priv->addScreenActions ();
4475
 
 
4476
 
    /* Need to set a default here so that the value isn't uninitialized
4477
 
     * when loading plugins FIXME: Should find a way to initialize options
4478
 
     * first and then set this value, or better yet, tie this value directly
4479
 
     * to the option */
4480
 
    priv->vpSize.setWidth (priv->optionGetHsize ());
4481
 
    priv->vpSize.setHeight (priv->optionGetVsize ());
4482
 
 
4483
 
    priv->initialized = true;
4484
 
 
4485
 
    /* TODO: Bailout properly when screenInitPlugins fails
4486
 
     * TODO: It would be nicer if this line could mean
4487
 
     * "init all the screens", but unfortunately it only inits
4488
 
     * plugins loaded on the command line screen's and then
4489
 
     * we need to call updatePlugins () to init the remaining
4490
 
     * screens from option changes */
4491
 
    assert (CompPlugin::screenInitPlugins (this));
4492
 
 
4493
 
    /* The active plugins list might have been changed - load any
4494
 
     * new plugins */
4495
 
 
4496
 
    priv->vpSize.setWidth (priv->optionGetHsize ());
4497
 
    priv->vpSize.setHeight (priv->optionGetVsize ());
4498
 
 
4499
 
    if (priv->dirtyPluginList)
4500
 
        priv->updatePlugins ();
4501
 
 
4502
4639
    /* Start initializing windows here */
4503
4640
 
4504
4641
    for (unsigned int i = 0; i < nchildren; i++)
4505
4642
    {
4506
4643
        XWindowAttributes attrib;
4507
4644
 
4508
 
        /* Failure means the window has been destroyed, but
4509
 
         * still add it to the window list anyways since we
4510
 
         * will soon handle the DestroyNotify event for it
4511
 
         * and in between CreateNotify time and DestroyNotify
4512
 
         * time there might be ConfigureRequests asking us
4513
 
         * to stack windows relative to it
 
4645
        /* Failure means the window has been destroyed, do not
 
4646
         * manage this window since we will not receive a DestroyNotify
 
4647
         * for it
4514
4648
         */
4515
4649
 
4516
4650
        if (!XGetWindowAttributes (screen->dpy (), children[i], &attrib))
4517
 
            priv->setDefaultWindowAttributes (&attrib);
 
4651
            priv->setDefaultWindowAttributes(&attrib);
4518
4652
 
4519
 
        CoreWindow *cw = new CoreWindow (children[i]);
 
4653
        CoreWindow *cw = new CoreWindow (children[i]);
4520
4654
        cw->manage (i ? children[i - 1] : 0, attrib);
4521
 
 
 
4655
        delete cw;
4522
4656
        priv->createdWindows.remove (cw);
4523
 
        delete cw;
4524
4657
    }
4525
4658
 
4526
 
    i = 0;
4527
 
 
4528
 
    /* enforce restack on all windows */
4529
 
    i = 0;
4530
 
    for (CompWindowList::reverse_iterator rit = priv->windows.rbegin ();
4531
 
         rit != priv->windows.rend (); rit++)
4532
 
        children[i++] = (*rit)->id ();
 
4659
    /* enforce restack on all windows
 
4660
     * using list last sent to server
 
4661
    i = 0;
 
4662
    for (CompWindowList::reverse_iterator rit = priv->serverWindows.rbegin ();
 
4663
         rit != priv->serverWindows.rend (); rit++)
 
4664
        children[i++] = ROOTPARENT ((*rit));
4533
4665
 
4534
4666
    XRestackWindows (dpy, children, i);
4535
 
 
 
4667
    */
4536
4668
    XFree (children);
4537
4669
 
4538
4670
    foreach (CompWindow *w, priv->windows)
4562
4694
            focusDefaultWindow ();
4563
4695
    }
4564
4696
 
 
4697
    /* Need to set a default here so that the value isn't uninitialized
 
4698
     * when loading plugins FIXME: Should find a way to initialize options
 
4699
     * first and then set this value, or better yet, tie this value directly
 
4700
     * to the option */
 
4701
    priv->vpSize.setWidth (priv->optionGetHsize ());
 
4702
    priv->vpSize.setHeight (priv->optionGetVsize ());
 
4703
 
 
4704
    priv->initialized = true;
 
4705
 
 
4706
    /* TODO: Bailout properly when screenInitPlugins fails
 
4707
     * TODO: It would be nicer if this line could mean
 
4708
     * "init all the screens", but unfortunately it only inits
 
4709
     * plugins loaded on the command line screen's and then
 
4710
     * we need to call updatePlugins () to init the remaining
 
4711
     * screens from option changes */
 
4712
    assert (CompPlugin::screenInitPlugins (this));
 
4713
 
 
4714
    /* The active plugins list might have been changed - load any
 
4715
     * new plugins */
 
4716
 
 
4717
    priv->vpSize.setWidth (priv->optionGetHsize ());
 
4718
    priv->vpSize.setHeight (priv->optionGetVsize ());
 
4719
 
 
4720
    priv->setAudibleBell (priv->optionGetAudibleBell ());
 
4721
 
 
4722
    priv->pingTimer.setTimes (priv->optionGetPingDelay (),
 
4723
                              priv->optionGetPingDelay () + 500);
 
4724
 
 
4725
    priv->pingTimer.start ();
 
4726
 
 
4727
    priv->addScreenActions ();
 
4728
 
 
4729
    if (priv->dirtyPluginList)
 
4730
        priv->updatePlugins ();
 
4731
 
4565
4732
    return true;
4566
4733
}
4567
4734
 
4624
4791
    plugin (),
4625
4792
    dirtyPluginList (true),
4626
4793
    screen (screen),
 
4794
    serverWindows (),
4627
4795
    windows (),
 
4796
    destroyedWindows (),
 
4797
    stackIsFresh (false),
4628
4798
    vp (0, 0),
4629
4799
    vpSize (1, 1),
4630
4800
    nDesktop (1),