Merge lp:~lukas-kde/unity8/hideCursorFullscreen into lp:unity8

Proposed by Lukáš Tinkl
Status: Superseded
Proposed branch: lp:~lukas-kde/unity8/hideCursorFullscreen
Merge into: lp:unity8
Diff against target: 12366 lines (+3516/-6154)
63 files modified
debian/changelog (+5/-3)
debian/unity8.install (+1/-1)
plugins/Ubuntu/Gestures/TouchGate.cpp (+4/-1)
plugins/WindowManager/TopLevelSurfaceList.cpp (+0/-5)
qml/CMakeLists.txt (+1/-1)
qml/Components/EdgeBarrier.qml (+2/-0)
qml/Components/FloatingFlickable.qml (+3/-0)
qml/Greeter/LoginAreaContainer.qml (+1/-1)
qml/Notifications/Notification.qml (+1/-1)
qml/Rotation/RotationStates.qml (+0/-6)
qml/Shell.qml (+64/-167)
qml/Stage/ApplicationWindow.qml (+13/-37)
qml/Stage/DecoratedWindow.qml (+123/-31)
qml/Stage/MoveHandler.qml (+2/-2)
qml/Stage/PromptSurfaceAnimations.qml (+2/-3)
qml/Stage/Spread/BezierCurve.qml (+45/-0)
qml/Stage/Spread/KeySpline.js (+66/-0)
qml/Stage/Spread/MathUtils.js (+95/-0)
qml/Stage/Spread/OpacityMask.qml (+82/-0)
qml/Stage/Spread/Spread.qml (+162/-0)
qml/Stage/Spread/SpreadDelegateInputArea.qml (+183/-0)
qml/Stage/Spread/SpreadMaths.qml (+78/-0)
qml/Stage/Spread/StagedRightEdgeMaths.qml (+174/-0)
qml/Stage/Spread/WindowedRightEdgeMaths.qml (+81/-0)
qml/Stage/Spread/cubic-bezier.js (+39/-0)
qml/Stage/Stage.qml (+1234/-185)
qml/Stage/StageMaths.qml (+79/-0)
qml/Stage/SurfaceContainer.qml (+5/-52)
qml/Stage/TopLevelSurfaceRepeater.qml (+9/-0)
qml/Stage/WindowDecoration.qml (+1/-1)
qml/Stage/WindowInfoItem.qml (+53/-0)
qml/Stage/WindowResizeArea.qml (+33/-32)
qml/Stages/AbstractStage.qml (+0/-93)
qml/Stages/DesktopSpread.qml (+0/-576)
qml/Stages/DesktopSpreadDelegate.qml (+0/-126)
qml/Stages/PhoneStage.qml (+0/-806)
qml/Stages/SpreadDelegate.qml (+0/-424)
qml/Stages/SpreadMaths.qml (+0/-164)
qml/Stages/TabletStage.qml (+0/-1201)
qml/Stages/TransformedSpreadDelegate.qml (+0/-391)
qml/Stages/TransformedTabletSpreadDelegate.qml (+0/-437)
qml/Tutorial/TutorialRight.qml (+1/-1)
tests/mocks/Cursor/Cursor.qml (+2/-0)
tests/mocks/Unity/Application/ApplicationInfo.cpp (+2/-2)
tests/mocks/Unity/Application/ApplicationManager.cpp (+2/-0)
tests/mocks/Unity/Application/MirSurface.cpp (+1/-0)
tests/mocks/Unity/Application/MirSurfaceItem.cpp (+13/-0)
tests/mocks/Unity/Application/MirSurfaceListModel.cpp (+0/-1)
tests/mocks/Unity/Application/VirtualKeyboard.cpp (+9/-7)
tests/mocks/Unity/Application/resources/MirSurfaceItem.qml (+2/-5)
tests/qmltests/CMakeLists.txt (+8/-8)
tests/qmltests/Stage/tst_ApplicationWindow.qml (+1/-1)
tests/qmltests/Stage/tst_DecoratedWindow.qml (+232/-0)
tests/qmltests/Stage/tst_DesktopStage.qml (+29/-71)
tests/qmltests/Stage/tst_PhoneStage.qml (+152/-219)
tests/qmltests/Stage/tst_Splash.qml (+1/-1)
tests/qmltests/Stage/tst_SurfaceContainer.qml (+2/-2)
tests/qmltests/Stage/tst_TabletStage.qml (+104/-241)
tests/qmltests/Stage/tst_WindowResizeArea.qml (+40/-36)
tests/qmltests/Stages/tst_SpreadDelegate.qml (+0/-423)
tests/qmltests/tst_OrientedShell.qml (+38/-198)
tests/qmltests/tst_Shell.qml (+227/-180)
tests/qmltests/tst_ShellWithPin.qml (+9/-11)
To merge this branch: bzr merge lp:~lukas-kde/unity8/hideCursorFullscreen
Reviewer Review Type Date Requested Status
Albert Astals Cid (community) Approve
Unity8 CI Bot continuous-integration Needs Fixing
Review via email: mp+304621@code.launchpad.net

This proposal has been superseded by a proposal from 2016-10-03.

Commit message

Hide the cursor for fullscreen apps after 3 seconds of inactivity

Description of the change

Hide the cursor for fullscreen apps after 3 seconds of inactivity.

The cursor is revealed again when the mouse is moved.

To test, launch the webbrowser app, navigate to youtube, play your favorite video in fullscreen

* Are there any related MPs required for this MP to build/function as expected? Please list.

No

* Did you perform an exploratory manual test run of your code change and any related functionality?

Yes

* If you changed the packaging (debian), did you subscribe the ubuntu-unity team to this MP?

N/A

* If you changed the UI, has there been a design review?

N/A, following unity7 behavior

To post a comment you must log in.
2606. By Lukáš Tinkl

fade in/out nicely

Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote :

FAILED: Continuous integration, rev:2605
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2083/
Executed test runs:
    FAILURE: https://unity8-jenkins.ubuntu.com/job/build/2729/console
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-0-fetch/2757
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/2630
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial+overlay/2630
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-1-sourcepkg/release=yakkety/2630
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=vivid+overlay/2622
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=vivid+overlay/2622/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/2622
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/2622/artifact/output/*zip*/output.zip
    FAILURE: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=yakkety/2622/console
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=vivid+overlay/2622
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=vivid+overlay/2622/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/2622
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/2622/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=yakkety/2622
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=yakkety/2622/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=vivid+overlay/2622
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=vivid+overlay/2622/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/2622
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/2622/artifact/output/*zip*/output.zip
    FAILURE: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=yakkety/2622/console

Click here to trigger a rebuild:
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2083/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote :

FAILED: Continuous integration, rev:2606
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2085/
Executed test runs:
    FAILURE: https://unity8-jenkins.ubuntu.com/job/build/2731/console
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-0-fetch/2759
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/2632
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial+overlay/2632
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-1-sourcepkg/release=yakkety/2632
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=vivid+overlay/2624
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=vivid+overlay/2624/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/2624
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/2624/artifact/output/*zip*/output.zip
    FAILURE: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=yakkety/2624/console
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=vivid+overlay/2624
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=vivid+overlay/2624/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/2624
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/2624/artifact/output/*zip*/output.zip
    FAILURE: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=yakkety/2624/console
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=vivid+overlay/2624
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=vivid+overlay/2624/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/2624
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/2624/artifact/output/*zip*/output.zip
    FAILURE: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=yakkety/2624/console

Click here to trigger a rebuild:
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2085/rebuild

review: Needs Fixing (continuous-integration)
2607. By Lukáš Tinkl

run only when cursor visible

Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote :

FAILED: Continuous integration, rev:2607
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2143/
Executed test runs:
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build/2818
    UNSTABLE: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=vivid+overlay,testname=qmluitests.sh/1563
    UNSTABLE: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=xenial+overlay,testname=qmluitests.sh/1563
    UNSTABLE: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=yakkety,testname=qmluitests.sh/1563
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-0-fetch/2846
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=vivid+overlay/2705
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=vivid+overlay/2705/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/2705
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/2705/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=yakkety/2705
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=yakkety/2705/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=vivid+overlay/2705
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=vivid+overlay/2705/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/2705
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/2705/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=yakkety/2705
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=yakkety/2705/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=vivid+overlay/2705
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=vivid+overlay/2705/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/2705
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/2705/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=yakkety/2705
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=yakkety/2705/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2143/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Albert Astals Cid (aacid) wrote :

Do we need a test for this?

Is there a bug/Design card/something where it says this is a wanted feature?

review: Needs Information
2608. By Lukáš Tinkl

merge trunk

Revision history for this message
Lukáš Tinkl (lukas-kde) wrote :

> Do we need a test for this?

I'll try to think of something, yeah

> Is there a bug/Design card/something where it says this is a wanted feature?

Well it's just filling the gaps for missing features compared to u7; I'm asking Paty for an informal UX approval as I'm writing this

2609. By Lukáš Tinkl

add a test

Revision history for this message
Lukáš Tinkl (lukas-kde) wrote :

Added the test, Paty's response:

Paty Davila, [29.09.16 13:28]
so go ahead, I think it's nice to have : )

Paty Davila, [29.09.16 13:29]
i don't see anything else that I could question or object

Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote :

FAILED: Continuous integration, rev:2608
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2282/
Executed test runs:
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build/3004
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=vivid+overlay,testname=qmluitests.sh/1662
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=xenial+overlay,testname=qmluitests.sh/1662
    UNSTABLE: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=yakkety,testname=qmluitests.sh/1662
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-0-fetch/3032
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=vivid+overlay/2889
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=vivid+overlay/2889/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/2889
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/2889/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=yakkety/2889
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=yakkety/2889/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=vivid+overlay/2889
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=vivid+overlay/2889/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/2889
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/2889/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=yakkety/2889
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=yakkety/2889/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=vivid+overlay/2889
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=vivid+overlay/2889/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/2889
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/2889/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=yakkety/2889
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=yakkety/2889/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2282/rebuild

review: Needs Fixing (continuous-integration)
2610. By Lukáš Tinkl

drop the repeat, not needed as "running" is a binding

adjust the test to prove that

Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote :

PASSED: Continuous integration, rev:2609
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2287/
Executed test runs:
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build/3010
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=vivid+overlay,testname=qmluitests.sh/1667
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=xenial+overlay,testname=qmluitests.sh/1667
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=yakkety,testname=qmluitests.sh/1667
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-0-fetch/3038
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=vivid+overlay/2895
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=vivid+overlay/2895/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/2895
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/2895/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=yakkety/2895
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=yakkety/2895/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=vivid+overlay/2895
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=vivid+overlay/2895/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/2895
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/2895/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=yakkety/2895
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=yakkety/2895/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=vivid+overlay/2895
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=vivid+overlay/2895/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/2895
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/2895/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=yakkety/2895
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=yakkety/2895/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2287/rebuild

review: Approve (continuous-integration)
Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote :

FAILED: Continuous integration, rev:2610
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2293/
Executed test runs:
    FAILURE: https://unity8-jenkins.ubuntu.com/job/build/3018/console
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-0-fetch/3046
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=vivid+overlay/2903
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=vivid+overlay/2903/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/2903
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/2903/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=yakkety/2903
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=yakkety/2903/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=vivid+overlay/2903
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=vivid+overlay/2903/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/2903
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/2903/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=yakkety/2903
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=yakkety/2903/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=vivid+overlay/2903
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=vivid+overlay/2903/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/2903
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/2903/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=yakkety/2903
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=yakkety/2903/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2293/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Albert Astals Cid (aacid) wrote :

 * Did you perform an exploratory manual test run of the code change and any related functionality?
Yes

 * Did CI run pass? If not, please explain why.
jenkins failing on its usual java stuff

review: Approve
2611. By Lukáš Tinkl

merge unified-stages

Unmerged revisions

2604. By Launchpad Translations on behalf of unity-team

Launchpad automatic translations update.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'debian/changelog'
2--- debian/changelog 2016-09-22 07:46:57 +0000
3+++ debian/changelog 2016-10-03 11:16:14 +0000
4@@ -1,4 +1,4 @@
5-unity8 (8.14+16.10.20160922-0ubuntu1) yakkety; urgency=medium
6+unity8 (8.14+16.10.20160914-0ubuntu1) yakkety; urgency=medium
7
8 [ Albert Astals Cid ]
9 * LVWPH: update clipItem height when list height changes (LP:
10@@ -46,12 +46,14 @@
11 the greeter.
12
13 [ Lukáš Tinkl ]
14- * Implement edge maximizing (aka window snapping) (LP: #1602628)
15 * On the PC platform (as opposed to running on $devices), use the
16 "mute" action instead of silent mode
17 * Respect Fitt's law wrt the window control buttons in panel (LP:
18 #1611959)
19 * Fix 2 failing color-related tests
20+ * Implement edge maximizing (aka window snapping) (LP: #1602628,
21+ #1611859)
22+ * Implement moving windows by Alt + left mouse button
23
24 [ Marco Trevisan (Treviño) ]
25 * Indicators, mocks: add fake indicators menuitem to populate mocks
26@@ -73,7 +75,7 @@
27 * Update look of infographic a bit
28 * Make infographic bubbles white even on the default wallpaper.
29
30- -- Michał Sawicz <michal.sawicz@canonical.com> Thu, 22 Sep 2016 07:46:57 +0000
31+ -- Michał Sawicz <michal.sawicz@canonical.com> Wed, 14 Sep 2016 00:46:45 +0000
32
33 unity8 (8.14+16.10.20160831.3-0ubuntu1) yakkety; urgency=medium
34
35
36=== modified file 'debian/unity8.install'
37--- debian/unity8.install 2016-06-20 22:42:46 +0000
38+++ debian/unity8.install 2016-10-03 11:16:14 +0000
39@@ -16,7 +16,7 @@
40 usr/share/unity8/OrientedShell.qml
41 usr/share/unity8/DisabledScreenNotice.qml
42 usr/share/unity8/Shell.qml
43-usr/share/unity8/Stages
44+usr/share/unity8/Stage
45 usr/share/unity8/Tutorial
46 usr/share/unity8/Wizard
47 usr/share/url-dispatcher/urls/unity8-dash.url-dispatcher
48
49=== modified file 'plugins/Ubuntu/Gestures/TouchGate.cpp'
50--- plugins/Ubuntu/Gestures/TouchGate.cpp 2016-07-13 07:29:00 +0000
51+++ plugins/Ubuntu/Gestures/TouchGate.cpp 2016-10-03 11:16:14 +0000
52@@ -61,7 +61,10 @@
53 const QTouchEvent::TouchPoint &touchPoint = touchPoints[i];
54
55 if (touchPoint.state() == Qt::TouchPointPressed) {
56- Q_ASSERT(!m_touchInfoMap.contains(touchPoint.id()));
57+// FIXME: This assert triggers frequently in make trySomething. We have verified
58+// that it's a bug in the mouse to touch conversion of the test environment
59+// and not in the actual product. Still, it probably should be cleaned up eventually.
60+// Q_ASSERT(!m_touchInfoMap.contains(touchPoint.id()));
61 m_touchInfoMap[touchPoint.id()].ownership = OwnershipRequested;
62 m_touchInfoMap[touchPoint.id()].ended = false;
63 TouchRegistry::instance()->requestTouchOwnership(touchPoint.id(), this);
64
65=== modified file 'plugins/WindowManager/TopLevelSurfaceList.cpp'
66--- plugins/WindowManager/TopLevelSurfaceList.cpp 2016-04-04 13:43:41 +0000
67+++ plugins/WindowManager/TopLevelSurfaceList.cpp 2016-10-03 11:16:14 +0000
68@@ -133,11 +133,6 @@
69
70 void TopLevelSurfaceList::connectSurface(MirSurfaceInterface *surface)
71 {
72- connect(surface, &MirSurfaceInterface::focusedChanged, this, [this, surface](bool focused){
73- if (focused) {
74- this->raise(surface);
75- }
76- });
77 connect(surface, &MirSurfaceInterface::liveChanged, this, [this, surface](bool live){
78 if (!live) {
79 onSurfaceDied(surface);
80
81=== modified file 'qml/CMakeLists.txt'
82--- qml/CMakeLists.txt 2015-03-06 04:44:11 +0000
83+++ qml/CMakeLists.txt 2016-10-03 11:16:14 +0000
84@@ -12,7 +12,7 @@
85 Launcher
86 Notifications
87 Panel
88- Stages
89+ Stage
90 Rotation
91 Tutorial
92 Wizard
93
94=== modified file 'qml/Components/EdgeBarrier.qml'
95--- qml/Components/EdgeBarrier.qml 2016-02-15 16:43:56 +0000
96+++ qml/Components/EdgeBarrier.qml 2016-10-03 11:16:14 +0000
97@@ -29,6 +29,8 @@
98 // Supported values are: Qt.LeftEdge, Qt.RightEdge
99 property int edge: Qt.LeftEdge
100
101+ readonly property alias progress: controller.progress
102+
103 property Item target: parent
104 function push(amount) { controller.push(amount); }
105 signal passed()
106
107=== modified file 'qml/Components/FloatingFlickable.qml'
108--- qml/Components/FloatingFlickable.qml 2016-08-08 10:41:38 +0000
109+++ qml/Components/FloatingFlickable.qml 2016-10-03 11:16:14 +0000
110@@ -35,6 +35,9 @@
111 property alias contentX: flickable.contentX
112 property alias contentY: flickable.contentY
113 property alias direction: swipeArea.direction
114+ property alias leftMargin: flickable.leftMargin
115+ property alias rightMargin: flickable.rightMargin
116+ property alias dragging: flickable.dragging
117
118 MouseEventGenerator {
119 id: mouseEventGenerator
120
121=== modified file 'qml/Greeter/LoginAreaContainer.qml'
122--- qml/Greeter/LoginAreaContainer.qml 2016-06-14 17:34:35 +0000
123+++ qml/Greeter/LoginAreaContainer.qml 2016-10-03 11:16:14 +0000
124@@ -26,7 +26,7 @@
125 rightMargin: -units.gu(1.5)
126 bottomMargin: -units.gu(1.5)
127 }
128- source: "../Stages/graphics/dropshadow2gu.sci"
129+ source: "../graphics/dropshadow2gu.sci"
130 opacity: 0.35
131 }
132
133
134=== modified file 'qml/Notifications/Notification.qml'
135--- qml/Notifications/Notification.qml 2016-08-19 13:27:05 +0000
136+++ qml/Notifications/Notification.qml 2016-10-03 11:16:14 +0000
137@@ -143,7 +143,7 @@
138 fill: contents
139 margins: shapedBack.visible ? -units.gu(1) : -units.gu(1.5)
140 }
141- source: "../Stages/graphics/dropshadow2gu.sci"
142+ source: "../graphics/dropshadow2gu.sci"
143 opacity: notification.opacity * 0.5
144 enabled: !fullscreen
145 }
146
147=== modified file 'qml/Rotation/RotationStates.qml'
148--- qml/Rotation/RotationStates.qml 2016-04-29 12:52:53 +0000
149+++ qml/Rotation/RotationStates.qml 2016-10-03 11:16:14 +0000
150@@ -121,12 +121,6 @@
151 }
152 }
153
154- property var shellBeingResized: Binding {
155- target: root.shell
156- property: "beingResized"
157- value: d.transitioning
158- }
159-
160 readonly property int fullAnimation: 0
161 readonly property int indicatorsBarAnimation: 1
162 readonly property int noAnimation: 2
163
164=== modified file 'qml/Shell.qml'
165--- qml/Shell.qml 2016-09-22 07:42:01 +0000
166+++ qml/Shell.qml 2016-10-03 11:16:14 +0000
167@@ -35,7 +35,7 @@
168 import "Panel"
169 import "Components"
170 import "Notifications"
171-import "Stages"
172+import "Stage"
173 import "Tutorial"
174 import "Wizard"
175 import Unity.Notifications 1.0 as NotificationBackend
176@@ -58,24 +58,22 @@
177 property real nativeWidth
178 property real nativeHeight
179 property alias indicatorAreaShowProgress: panel.indicatorAreaShowProgress
180- property bool beingResized
181 property string usageScenario: "phone" // supported values: "phone", "tablet" or "desktop"
182 property string mode: "full-greeter"
183 property alias oskEnabled: inputMethod.enabled
184 function updateFocusedAppOrientation() {
185- applicationsDisplayLoader.item.updateFocusedAppOrientation();
186+ stage.updateFocusedAppOrientation();
187 }
188 function updateFocusedAppOrientationAnimated() {
189- applicationsDisplayLoader.item.updateFocusedAppOrientationAnimated();
190+ stage.updateFocusedAppOrientationAnimated();
191 }
192 property bool hasMouse: false
193
194 // to be read from outside
195- readonly property int mainAppWindowOrientationAngle:
196- applicationsDisplayLoader.item ? applicationsDisplayLoader.item.mainAppWindowOrientationAngle : 0
197+ readonly property int mainAppWindowOrientationAngle: stage.mainAppWindowOrientationAngle
198
199 readonly property bool orientationChangesEnabled: panel.indicators.fullyClosed
200- && (applicationsDisplayLoader.item && applicationsDisplayLoader.item.orientationChangesEnabled)
201+ && stage.orientationChangesEnabled
202 && (!greeter || !greeter.animating)
203
204 readonly property bool showingGreeter: greeter && greeter.shown
205@@ -89,19 +87,13 @@
206 return Qt.PrimaryOrientation;
207 } else if (showingGreeter || notifications.topmostIsFullscreen) {
208 return Qt.PrimaryOrientation;
209- } else if (applicationsDisplayLoader.item) {
210- return shell.orientations.map(applicationsDisplayLoader.item.supportedOrientations);
211 } else {
212- // we just don't care
213- return Qt.PortraitOrientation
214- | Qt.LandscapeOrientation
215- | Qt.InvertedPortraitOrientation
216- | Qt.InvertedLandscapeOrientation;
217+ return shell.orientations.map(stage.supportedOrientations);
218 }
219 }
220
221- readonly property var mainApp:
222- applicationsDisplayLoader.item ? applicationsDisplayLoader.item.mainApp : null
223+ readonly property var mainApp: stage.mainApp
224+
225 onMainAppChanged: {
226 if (mainApp) {
227 _onMainAppChanged(mainApp.appId);
228@@ -278,154 +270,50 @@
229 applicationsModel: ApplicationManager
230 }
231
232- Loader {
233- id: applicationsDisplayLoader
234- objectName: "applicationsDisplayLoader"
235+ Stage {
236+ id: stage
237+ objectName: "stage"
238 anchors.fill: parent
239-
240- // When we have a locked app, we only want to show that one app.
241- // FIXME: do this in a less traumatic way. We currently only allow
242- // locked apps in phone mode (see FIXME in Lockscreen component in
243- // this same file). When that changes, we need to do something
244- // nicer here. But this code is currently just to prevent a
245- // theoretical attack where user enters lockedApp mode, then makes
246- // the screen larger (maybe connects to monitor) and tries to enter
247- // tablet mode.
248+ focus: true
249+
250+ dragAreaWidth: shell.edgeSize
251+ background: wallpaperResolver.background
252+ leftEdgeDragProgress: !greeter || greeter.locked || !tutorial.launcherLongSwipeEnabled ? 0 :
253+ Math.max(0, (launcher.dragDistance * (stage.width - launcher.panelWidth) / stage.width) - launcher.panelWidth)
254+
255+ applicationManager: ApplicationManager
256+ topLevelSurfaceList: topLevelSurfaceList
257+ inputMethodRect: inputMethod.visibleRect
258
259 property string usageScenario: shell.usageScenario === "phone" || greeter.hasLockedApp
260- ? "phone"
261- : shell.usageScenario
262- readonly property string qmlComponent: {
263- if (applicationsDisplayLoader.usageScenario === "phone") {
264- return "Stages/PhoneStage.qml";
265- } else if (applicationsDisplayLoader.usageScenario === "tablet") {
266- return "Stages/TabletStage.qml";
267- } else {
268- return "Stages/DesktopStage.qml";
269- }
270- }
271- // TODO: Ensure the current stage is destroyed before the new one gets loaded.
272- // Currently the new one will get loaded while the old is still hanging
273- // around for a bit, which might lead to conflicts where both stages
274- // change the model simultaneously.
275- onQmlComponentChanged: {
276- if (item) item.stageAboutToBeUnloaded();
277- source = qmlComponent;
278- }
279-
280- property bool interactive: (!greeter || !greeter.shown)
281+ ? "phone"
282+ : shell.usageScenario
283+
284+ mode: usageScenario == "phone" ? "staged"
285+ : usageScenario == "tablet" ? "stagedWithSideStage"
286+ : "windowed"
287+
288+ shellOrientation: shell.orientation
289+ shellOrientationAngle: shell.orientationAngle
290+ orientations: shell.orientations
291+ nativeWidth: shell.nativeWidth
292+ nativeHeight: shell.nativeHeight
293+
294+ interactive: (!greeter || !greeter.shown)
295 && panel.indicators.fullyClosed
296 && launcher.progress == 0
297 && !notifications.useModal
298
299 onInteractiveChanged: { if (interactive) { focus = true; } }
300
301- Binding {
302- target: applicationsDisplayLoader.item
303- property: "focus"
304- value: true
305- }
306- Binding {
307- target: applicationsDisplayLoader.item
308- property: "objectName"
309- value: "stage"
310- }
311- Binding {
312- target: applicationsDisplayLoader.item
313- property: "dragAreaWidth"
314- value: shell.edgeSize
315- }
316- Binding {
317- target: applicationsDisplayLoader.item
318- property: "maximizedAppTopMargin"
319- // Not just using panel.panelHeight as that changes depending on the focused app.
320- value: panel.indicators.minimizedPanelHeight
321- }
322- Binding {
323- target: applicationsDisplayLoader.item
324- property: "interactive"
325- value: applicationsDisplayLoader.interactive
326- }
327- Binding {
328- target: applicationsDisplayLoader.item
329- property: "spreadEnabled"
330- value: tutorial.spreadEnabled && (!greeter || (!greeter.hasLockedApp && !greeter.shown))
331- }
332- Binding {
333- target: applicationsDisplayLoader.item
334- property: "inverseProgress"
335- value: !greeter || greeter.locked || !tutorial.launcherLongSwipeEnabled ? 0 : launcher.progress
336- }
337- Binding {
338- target: applicationsDisplayLoader.item
339- property: "shellOrientationAngle"
340- value: shell.orientationAngle
341- }
342- Binding {
343- target: applicationsDisplayLoader.item
344- property: "shellOrientation"
345- value: shell.orientation
346- }
347- Binding {
348- target: applicationsDisplayLoader.item
349- property: "orientations"
350- value: shell.orientations
351- }
352- Binding {
353- target: applicationsDisplayLoader.item
354- property: "background"
355- value: wallpaperResolver.cachedBackground
356- }
357- Binding {
358- target: applicationsDisplayLoader.item
359- property: "nativeWidth"
360- value: shell.nativeWidth
361- }
362- Binding {
363- target: applicationsDisplayLoader.item
364- property: "nativeHeight"
365- value: shell.nativeHeight
366- }
367- Binding {
368- target: applicationsDisplayLoader.item
369- property: "beingResized"
370- value: shell.beingResized
371- }
372- Binding {
373- target: applicationsDisplayLoader.item
374- property: "keepDashRunning"
375- value: launcher.shown || launcher.dashSwipe
376- }
377- Binding {
378- target: applicationsDisplayLoader.item
379- property: "suspended"
380- value: greeter.shown
381- }
382- Binding {
383- target: applicationsDisplayLoader.item
384- property: "altTabPressed"
385- value: physicalKeysMapper.altTabPressed
386- }
387- Binding {
388- target: applicationsDisplayLoader.item
389- property: "leftMargin"
390- value: shell.usageScenario == "desktop" && !settings.autohideLauncher ? launcher.panelWidth: 0
391- }
392- Binding {
393- target: applicationsDisplayLoader.item
394- property: "applicationManager"
395- value: ApplicationManager
396- }
397- Binding {
398- target: applicationsDisplayLoader.item
399- property: "topLevelSurfaceList"
400- value: topLevelSurfaceList
401- }
402- Binding {
403- target: applicationsDisplayLoader.item
404- property: "oskEnabled"
405- value: shell.oskEnabled
406- }
407+ leftMargin: shell.usageScenario == "desktop" && !settings.autohideLauncher ? launcher.panelWidth: 0
408+ suspended: greeter.shown
409+ keepDashRunning: launcher.shown || launcher.dashSwipe
410+ altTabPressed: physicalKeysMapper.altTabPressed
411+ oskEnabled: shell.oskEnabled
412+
413+ // TODO: This is not implemented yet in the new stage...
414+ spreadEnabled: tutorial.spreadEnabled && (!greeter || (!greeter.hasLockedApp && !greeter.shown))
415 }
416 }
417
418@@ -442,6 +330,7 @@
419
420 Loader {
421 id: greeterLoader
422+ objectName: "greeterLoader"
423 anchors.fill: parent
424 anchors.topMargin: panel.panelHeight
425 sourceComponent: shell.mode != "shell" ? integratedGreeter :
426@@ -650,7 +539,7 @@
427 }
428 onFocusChanged: {
429 if (!focus) {
430- applicationsDisplayLoader.focus = true;
431+ stage.focus = true;
432 }
433 }
434
435@@ -706,12 +595,12 @@
436 delayed: dialogs.hasActiveDialog || notifications.hasNotification ||
437 inputMethod.visible ||
438 (launcher.shown && !launcher.lockedVisible) ||
439- panel.indicators.shown || stage.dragProgress > 0
440+ panel.indicators.shown || stage.rightEdgeDragProgress > 0
441 usageScenario: shell.usageScenario
442 lastInputTimestamp: inputFilter.lastInputTimestamp
443 launcher: launcher
444 panel: panel
445- stage: applicationsDisplayLoader.item
446+ stage: stage
447 }
448
449 Wizard {
450@@ -802,19 +691,27 @@
451 z: dialogs.z + 10
452 GlobalShortcut { shortcut: Qt.Key_Print; onTriggered: itemGrabber.capture(shell) }
453 Connections {
454- target: applicationsDisplayLoader.item
455+ target: stage
456 ignoreUnknownSignals: true
457 onItemSnapshotRequested: itemGrabber.capture(item)
458 }
459 }
460
461+ Timer {
462+ id: cursorHidingTimer
463+ interval: 3000
464+ running: panel.focusedSurfaceIsFullscreen && cursor.opacity > 0
465+ onTriggered: cursor.opacity = 0;
466+ }
467+
468 Cursor {
469 id: cursor
470+ objectName: "cursor"
471 visible: shell.hasMouse
472 z: itemGrabber.z + 1
473 topBoundaryOffset: panel.panelHeight
474
475- confiningItem: applicationsDisplayLoader.item ? applicationsDisplayLoader.item.itemConfiningMouseCursor : null
476+ confiningItem: stage.itemConfiningMouseCursor
477
478 property bool mouseNeverMoved: true
479 Binding {
480@@ -828,10 +725,9 @@
481
482 height: units.gu(3)
483
484- readonly property var previewRectangle: applicationsDisplayLoader.item && applicationsDisplayLoader.item.previewRectangle &&
485- applicationsDisplayLoader.item.previewRectangle.target &&
486- applicationsDisplayLoader.item.previewRectangle.target.dragging ?
487- applicationsDisplayLoader.item.previewRectangle : null
488+ readonly property var previewRectangle: stage.previewRectangle.target &&
489+ stage.previewRectangle.target.dragging ?
490+ stage.previewRectangle : null
491
492 onPushedLeftBoundary: {
493 if (buttons === Qt.NoButton) {
494@@ -842,9 +738,8 @@
495 }
496
497 onPushedRightBoundary: {
498- if (buttons === Qt.NoButton && applicationsDisplayLoader.item
499- && applicationsDisplayLoader.item.pushRightEdge) {
500- applicationsDisplayLoader.item.pushRightEdge(amount);
501+ if (buttons === Qt.NoButton) {
502+ stage.pushRightEdge(amount);
503 } else if (buttons === Qt.LeftButton && previewRectangle && previewRectangle.target.canBeMaximizedLeftRight) {
504 previewRectangle.maximizeRight(amount);
505 }
506@@ -885,6 +780,8 @@
507 mouseNeverMoved = false;
508 cursor.opacity = 1;
509 }
510+
511+ Behavior on opacity { UbuntuNumberAnimation {} }
512 }
513
514 // non-visual object
515
516=== renamed directory 'qml/Stages' => 'qml/Stage'
517=== modified file 'qml/Stage/ApplicationWindow.qml'
518--- qml/Stages/ApplicationWindow.qml 2016-08-08 11:18:19 +0000
519+++ qml/Stage/ApplicationWindow.qml 2016-10-03 11:16:14 +0000
520@@ -20,8 +20,8 @@
521
522 FocusScope {
523 id: root
524- implicitWidth: surfaceContainer.implicitWidth
525- implicitHeight: surfaceContainer.implicitHeight
526+ implicitWidth: requestedWidth
527+ implicitHeight: requestedHeight
528
529 // to be read from outside
530 property alias interactive: surfaceContainer.interactive
531@@ -29,22 +29,10 @@
532 readonly property string title: surface && surface.name !== "" ? surface.name : d.name
533 readonly property QtObject focusedSurface: d.focusedSurface.surface
534
535- // overridable from outside
536- property bool fullscreen: {
537- if (surface) {
538- return surface.state === Mir.FullscreenState;
539- } else if (application) {
540- return application.fullscreen;
541- } else {
542- return false;
543- }
544- }
545-
546 // to be set from outside
547 property QtObject surface
548 property QtObject application
549 property int surfaceOrientationAngle
550- property alias resizeSurface: surfaceContainer.resizeSurface
551 property int requestedWidth: -1
552 property int requestedHeight: -1
553 property real splashRotation: 0
554@@ -156,6 +144,9 @@
555 id: screenshotImage
556 objectName: "screenshotImage"
557 anchors.fill: parent
558+ fillMode: Image.PreserveAspectCrop
559+ horizontalAlignment: Image.AlignLeft
560+ verticalAlignment: Image.AlignTop
561 antialiasing: !root.interactive
562 z: 1
563
564@@ -197,6 +188,7 @@
565
566 SurfaceContainer {
567 id: surfaceContainer
568+ anchors.fill: parent
569 z: splashLoader.z + 1
570 requestedWidth: root.requestedWidth
571 requestedHeight: root.requestedHeight
572@@ -220,6 +212,8 @@
573 surface: model.surface
574 width: root.width
575 height: root.height
576+ requestedWidth: root.requestedWidth
577+ requestedHeight: root.requestedHeight
578 isPromptSurface: true
579 z: surfaceContainer.z + (promptSurfacesRepeater.count - index)
580 property int index: model.index
581@@ -239,28 +233,6 @@
582 property Item first: null
583 }
584
585- // SurfaceContainer size drives ApplicationWindow size
586- Binding {
587- target: root; property: "width"
588- value: stateGroup.state === "surface" ? surfaceContainer.width : root.requestedWidth
589- when: root.requestedWidth >= 0
590- }
591- Binding {
592- target: root; property: "height"
593- value: stateGroup.state === "surface" ? surfaceContainer.height : root.requestedHeight
594- when: root.requestedHeight >= 0
595- }
596-
597- // ApplicationWindow size drives SurfaceContainer size
598- Binding {
599- target: surfaceContainer; property: "width"; value: root.width
600- when: root.requestedWidth < 0
601- }
602- Binding {
603- target: surfaceContainer; property: "height"; value: root.height
604- when: root.requestedHeight < 0
605- }
606-
607 StateGroup {
608 id: stateGroup
609 objectName: "applicationWindowStateGroup"
610@@ -287,6 +259,11 @@
611 (d.liveSurface ||
612 (d.applicationState !== ApplicationInfoInterface.Running
613 && screenshotImage.status !== Image.Ready))
614+ PropertyChanges {
615+ target: root
616+ implicitWidth: surfaceContainer.implicitWidth
617+ implicitHeight: surfaceContainer.implicitHeight
618+ }
619 },
620 State {
621 name: "screenshot"
622@@ -424,5 +401,4 @@
623 }
624 ]
625 }
626-
627 }
628
629=== modified file 'qml/Stage/DecoratedWindow.qml'
630--- qml/Stages/DecoratedWindow.qml 2016-09-08 14:13:27 +0000
631+++ qml/Stage/DecoratedWindow.qml 2016-10-03 11:16:14 +0000
632@@ -17,34 +17,46 @@
633 import QtQuick 2.4
634 import Ubuntu.Components 1.3
635 import Unity.Application 0.1
636+import "Spread/MathUtils.js" as MathUtils
637
638 FocusScope {
639 id: root
640
641- width: !counterRotate ? applicationWindow.width : applicationWindow.height
642- height: visibleDecorationHeight + (!counterRotate ? applicationWindow.height : applicationWindow.width)
643+ // The DecoratedWindow takes requestedWidth/requestedHeight and asks its surface to be resized to that
644+ // (minus the window decoration size in case hasDecoration and showDecoration are true)
645+ // The surface might not be able to resize to the requested values. It will return its actual size
646+ // in implicitWidth/implicitHeight.
647
648 property alias application: applicationWindow.application
649 property alias surface: applicationWindow.surface
650 readonly property alias focusedSurface: applicationWindow.focusedSurface
651 property alias active: decoration.active
652 readonly property alias title: applicationWindow.title
653- property alias fullscreen: applicationWindow.fullscreen
654 property alias maximizeButtonShown: decoration.maximizeButtonShown
655+ property alias interactive: applicationWindow.interactive
656+ readonly property alias orientationChangesEnabled: applicationWindow.orientationChangesEnabled
657
658- readonly property bool decorationShown: !fullscreen
659- property bool highlightShown: false
660- property real shadowOpacity: 1
661+ // Changing this will actually add/remove a decoration, meaning, requestedHeight will take the decoration into account.
662+ property bool hasDecoration: true
663+ // This will temporarily show/hide the decoration without actually changing the surface's dimensions
664+ property real showDecoration: 1
665+ property bool animateDecoration: false
666+ property bool showHighlight: false
667+ property int highlightSize: units.gu(1)
668+ property real shadowOpacity: 0
669+ property bool darkening: false
670
671 property real requestedWidth
672 property real requestedHeight
673+ property real scaleToPreviewProgress: 0
674+ property int scaleToPreviewSize: units.gu(30)
675
676 property alias surfaceOrientationAngle: applicationWindow.surfaceOrientationAngle
677- readonly property real visibleDecorationHeight: root.decorationShown ? decoration.height : 0
678+ readonly property real decorationHeight: Math.min(d.visibleDecorationHeight, d.requestedDecorationHeight)
679 readonly property bool counterRotate: surfaceOrientationAngle != 0 && surfaceOrientationAngle != 180
680
681 readonly property int minimumWidth: !counterRotate ? applicationWindow.minimumWidth : applicationWindow.minimumHeight
682- readonly property int minimumHeight: visibleDecorationHeight + (!counterRotate ? applicationWindow.minimumHeight : applicationWindow.minimumWidth)
683+ readonly property int minimumHeight: decorationHeight + (!counterRotate ? applicationWindow.minimumHeight : applicationWindow.minimumWidth)
684 readonly property int maximumWidth: !counterRotate ? applicationWindow.maximumWidth : applicationWindow.maximumHeight
685 readonly property int maximumHeight: (root.decorationShown && applicationWindow.maximumHeight > 0 ? decoration.height : 0)
686 + (!counterRotate ? applicationWindow.maximumHeight : applicationWindow.maximumWidth)
687@@ -66,40 +78,97 @@
688 signal decorationPressed()
689 signal decorationReleased()
690
691+ QtObject {
692+ id: d
693+ property int requestedDecorationHeight: root.hasDecoration ? decoration.height : 0
694+ Behavior on requestedDecorationHeight { enabled: root.animateDecoration; UbuntuNumberAnimation { } }
695+
696+ property int visibleDecorationHeight: root.hasDecoration ? root.showDecoration * decoration.height : 0
697+ Behavior on visibleDecorationHeight { enabled: root.animateDecoration; UbuntuNumberAnimation { } }
698+ }
699+
700+ StateGroup {
701+ states: [
702+ State {
703+ name: "normal"; when: root.scaleToPreviewProgress <= 0 && root.application.state === ApplicationInfoInterface.Running
704+ PropertyChanges {
705+ target: root
706+ implicitWidth: counterRotate ? applicationWindow.implicitHeight : applicationWindow.implicitWidth
707+ implicitHeight: root.decorationHeight + (counterRotate ? applicationWindow.implicitWidth: applicationWindow.implicitHeight)
708+ }
709+ },
710+ State {
711+ name: "normalSuspended"; when: root.scaleToPreviewProgress <= 0 && root.application.state !== ApplicationInfoInterface.Running
712+ PropertyChanges {
713+ target: root
714+ implicitWidth: counterRotate ? applicationWindow.requestedHeight : applicationWindow.requestedWidth
715+ implicitHeight: root.decorationHeight + (counterRotate ? applicationWindow.requestedWidth: applicationWindow.requestedHeight)
716+ }
717+// PropertyChanges { target: applicationWindow; anchors.topMargin: (root.height - applicationWindow.implicitHeight) / 2 }
718+// PropertyChanges { target: dropShadow; anchors.topMargin: (root.height - applicationWindow.implicitHeight) / 2 }
719+ },
720+ State {
721+ name: "preview"; when: root.scaleToPreviewProgress > 0 && root.application.state === ApplicationInfoInterface.Running
722+ PropertyChanges {
723+ target: root
724+ implicitWidth: MathUtils.linearAnimation(0, 1, applicationWindow.oldRequestedWidth, root.scaleToPreviewSize, root.scaleToPreviewProgress)
725+ implicitHeight: MathUtils.linearAnimation(0, 1, applicationWindow.oldRequestedHeight, root.scaleToPreviewSize, root.scaleToPreviewProgress)
726+ }
727+ PropertyChanges {
728+ target: applicationWindow;
729+ requestedWidth: applicationWindow.oldRequestedWidth
730+ requestedHeight: applicationWindow.oldRequestedHeight
731+ width: MathUtils.linearAnimation(0, 1, applicationWindow.oldRequestedWidth, applicationWindow.minSize, root.scaleToPreviewProgress)
732+ height: MathUtils.linearAnimation(0, 1, applicationWindow.oldRequestedHeight, applicationWindow.minSize, root.scaleToPreviewProgress)
733+ itemScale: root.implicitWidth / width
734+ }
735+ },
736+ State {
737+ name: "previewSuspended"; when: root.scaleToPreviewProgress > 0 && root.application.state !== ApplicationInfoInterface.Running
738+ extend: "preview"
739+ PropertyChanges { target: applicationWindow;
740+ anchors.verticalCenterOffset: applicationWindow.implicitHeight < applicationWindow.height ?
741+ (root.height / applicationWindow.itemScale - applicationWindow.implicitHeight) / 2
742+ : (root.height / applicationWindow.itemScale - applicationWindow.height) / 2
743+ }
744+// PropertyChanges { target: dropShadow; anchors.topMargin: (root.height - root.implicitHeight) / 2 * (1 - root.scaleToPreviewProgress) }
745+ }
746+ ]
747+ }
748+
749 Rectangle {
750 id: selectionHighlight
751+ objectName: "selectionHighlight"
752 anchors.fill: parent
753- anchors.margins: -units.gu(1)
754+ anchors.margins: -root.highlightSize
755 color: "white"
756- opacity: highlightShown ? 0.15 : 0
757- }
758-
759- Rectangle {
760- anchors { left: selectionHighlight.left; right: selectionHighlight.right; bottom: selectionHighlight.bottom; }
761- height: units.dp(2)
762- color: theme.palette.normal.focus
763- visible: highlightShown
764+ opacity: showHighlight ? 0.55 : 0
765+ visible: opacity > 0
766 }
767
768 BorderImage {
769+ id: dropShadow
770 anchors {
771- fill: root
772+ left: parent.left; top: parent.top; right: parent.right
773 margins: active ? -units.gu(2) : -units.gu(1.5)
774 }
775- source: "graphics/dropshadow2gu.sci"
776- opacity: root.shadowOpacity * .3
777- visible: !fullscreen
778+ height: Math.min(applicationWindow.implicitHeight, applicationWindow.height) * applicationWindow.itemScale
779+ + root.decorationHeight * Math.min(1, root.showDecoration) + (active ? units.gu(4) : units.gu(3))
780+ source: "../graphics/dropshadow2gu.sci"
781+ opacity: root.shadowOpacity
782 }
783
784 WindowDecoration {
785 id: decoration
786- target: root.parent
787+ target: root.parent || null
788 objectName: "appWindowDecoration"
789 anchors { left: parent.left; top: parent.top; right: parent.right }
790 height: units.gu(3)
791 width: root.width
792 title: applicationWindow.title
793- visible: root.decorationShown
794+ opacity: root.hasDecoration ? Math.min(1, root.showDecoration) : 0
795+
796+ Behavior on opacity { UbuntuNumberAnimation { } }
797
798 onCloseClicked: root.closeClicked();
799 onMaximizeClicked: { root.decorationPressed(); root.maximizeClicked(); }
800@@ -126,16 +195,25 @@
801 ApplicationWindow {
802 id: applicationWindow
803 objectName: "appWindow"
804- anchors.top: parent.top
805- anchors.topMargin: decoration.height
806+ anchors.verticalCenter: parent.verticalCenter
807+ anchors.verticalCenterOffset: (root.decorationHeight * Math.min(1, root.showDecoration)) / 2
808 anchors.left: parent.left
809- readonly property real requestedHeightMinusDecoration: root.requestedHeight - root.visibleDecorationHeight
810- requestedHeight: !counterRotate ? requestedHeightMinusDecoration : root.requestedWidth
811- requestedWidth: !counterRotate ? root.requestedWidth : requestedHeightMinusDecoration
812- interactive: true
813+ width: implicitWidth
814+ height: implicitHeight
815+ requestedHeight: !counterRotate ? root.requestedHeight - d.requestedDecorationHeight : root.requestedWidth
816+ requestedWidth: !counterRotate ? root.requestedWidth : root.requestedHeight - d.requestedDecorationHeight
817+ property int oldRequestedWidth: requestedWidth
818+ property int oldRequestedHeight: requestedHeight
819+ onRequestedWidthChanged: oldRequestedWidth = requestedWidth
820+ onRequestedHeightChanged: oldRequestedHeight = requestedHeight
821 focus: true
822
823- transform: Rotation {
824+ property real itemScale: 1
825+ property real minSize: Math.min(root.scaleToPreviewSize, Math.min(requestedHeight, Math.min(requestedWidth, Math.min(implicitHeight, implicitWidth))))
826+
827+ transform: [
828+ Rotation {
829+ id: rotationTransform
830 readonly property int rotationAngle: applicationWindow.application &&
831 applicationWindow.application.rotatesWindowContents
832 ? ((360 - applicationWindow.surfaceOrientationAngle) % 360) : 0
833@@ -152,6 +230,20 @@
834 else return 0;
835 }
836 angle: rotationAngle
837- }
838+ },
839+ Scale {
840+ origin.y: (applicationWindow.implicitHeight < applicationWindow.height ? applicationWindow.implicitHeight : applicationWindow.height) / 2
841+ xScale: applicationWindow.itemScale
842+ yScale: applicationWindow.itemScale
843+ }
844+ ]
845+
846+ }
847+
848+ Rectangle {
849+ anchors.fill: parent
850+ color: "black"
851+ opacity: root.darkening && !root.showHighlight ? 0.05 : 0
852+ Behavior on opacity { UbuntuNumberAnimation { duration: UbuntuAnimation.SnapDuration } }
853 }
854 }
855
856=== modified file 'qml/Stage/MoveHandler.qml'
857--- qml/Stages/MoveHandler.qml 2016-09-08 14:13:27 +0000
858+++ qml/Stage/MoveHandler.qml 2016-10-03 11:16:14 +0000
859@@ -112,8 +112,8 @@
860 // Use integer coordinate values to ensure that target is left in a pixel-aligned
861 // position. Mouse movement could have subpixel precision, yielding a fractional
862 // mouse position.
863- target.requestedX = Math.round(pos.x - priv.distanceX);
864- target.requestedY = Math.round(Math.max(pos.y - priv.distanceY, PanelState.panelHeight));
865+ target.windowedX = Math.round(pos.x - priv.distanceX);
866+ target.windowedY = Math.round(Math.max(pos.y - priv.distanceY, PanelState.panelHeight));
867
868 if (sensingPoints) { // edge/corner detection when dragging via the touch overlay
869 if (sensingPoints.topLeft.x < priv.triggerArea && sensingPoints.topLeft.y < PanelState.panelHeight + priv.triggerArea
870
871=== modified file 'qml/Stage/PromptSurfaceAnimations.qml'
872--- qml/Stages/PromptSurfaceAnimations.qml 2016-04-04 13:38:56 +0000
873+++ qml/Stage/PromptSurfaceAnimations.qml 2016-10-03 11:16:14 +0000
874@@ -43,7 +43,7 @@
875 SequentialAnimation {
876 // clip so we don't go out of parent's bounds during spread
877 PropertyAction { target: root.container.parent; property: "clip"; value: true }
878- UbuntuNumberAnimation { target: root.surfaceItem; property: "y"; to: root.container.height
879+ UbuntuNumberAnimation { target: root.surfaceItem; property: "anchors.topMargin"; to: root.container.height
880 duration: UbuntuAnimation.BriskDuration }
881 PropertyAction { target: root.surfaceItem; property: "visible"; value: false }
882 PropertyAction { target: container.parent; property: "clip"; value: false }
883@@ -61,11 +61,10 @@
884 // clip so we don't go out of parent's bounds during spread
885 PropertyAction { target: root.container.parent; property: "clip"; value: true }
886 ScriptAction { script: {
887- root.surfaceItem.y = root.container.height;
888 root.surfaceItem.visible = true;
889 } }
890 UbuntuNumberAnimation {
891- target: root.surfaceItem; property: "y"; to: 0
892+ target: root.surfaceItem; property: "anchors.topMargin"; from: root.container.height; to: 0
893 duration: UbuntuAnimation.BriskDuration
894 }
895 PropertyAction { target: container.parent; property: "clip"; value: false }
896
897=== added directory 'qml/Stage/Spread'
898=== added file 'qml/Stage/Spread/BezierCurve.qml'
899--- qml/Stage/Spread/BezierCurve.qml 1970-01-01 00:00:00 +0000
900+++ qml/Stage/Spread/BezierCurve.qml 2016-10-03 11:16:14 +0000
901@@ -0,0 +1,45 @@
902+/*
903+ * Copyright (C) 2016 Canonical, Ltd.
904+ *
905+ * This program is free software; you can redistribute it and/or modify
906+ * it under the terms of the GNU General Public License as published by
907+ * the Free Software Foundation; version 3.
908+ *
909+ * This program is distributed in the hope that it will be useful,
910+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
911+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
912+ * GNU General Public License for more details.
913+ *
914+ * You should have received a copy of the GNU General Public License
915+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
916+ */
917+
918+import QtQuick 2.4
919+import Ubuntu.Components 1.3
920+import QtQuick.Window 2.2
921+import 'cubic-bezier.js' as Bezier
922+import 'KeySpline.js' as KeySpline
923+
924+Item {
925+ id: root
926+
927+ property var controlPoint1: {'x':0, 'y':0}
928+ property var controlPoint2: {'x':0, 'y':0}
929+ property var controlPoint3: {'x':0.58, 'y':1}
930+ property var controlPoint4: {'x':1, 'y':1}
931+
932+ function getValues(t) {
933+ if (t<0) t=0
934+ else if (t>1)t=1
935+
936+ return Bezier.getBezier(t, controlPoint1, controlPoint2, controlPoint3, controlPoint4)
937+ }
938+
939+ function getYFromX(x) {
940+ var spline = new KeySpline.keySpline(controlPoint2.x, controlPoint2.y, controlPoint3.x, controlPoint3.y)
941+ if (x<0) x=0
942+ else if (x>1)x=1
943+
944+ return spline.get(x)
945+ }
946+}
947
948=== added file 'qml/Stage/Spread/KeySpline.js'
949--- qml/Stage/Spread/KeySpline.js 1970-01-01 00:00:00 +0000
950+++ qml/Stage/Spread/KeySpline.js 2016-10-03 11:16:14 +0000
951@@ -0,0 +1,66 @@
952+/** MIT License
953+ *
954+ * KeySpline - use bezier curve for transition easing function
955+ * Copyright (c) 2012 Gaetan Renaudeau <renaudeau.gaetan@gmail.com>
956+ *
957+ * Permission is hereby granted, free of charge, to any person obtaining a
958+ * copy of this software and associated documentation files (the "Software"),
959+ * to deal in the Software without restriction, including without limitation
960+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
961+ * and/or sell copies of the Software, and to permit persons to whom the
962+ * Software is furnished to do so, subject to the following conditions:
963+ *
964+ * The above copyright notice and this permission notice shall be included in
965+ * all copies or substantial portions of the Software.
966+ *
967+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
968+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
969+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
970+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
971+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
972+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
973+ * DEALINGS IN THE SOFTWARE.
974+ */
975+/**
976+* KeySpline - use bezier curve for transition easing function
977+* is inspired from Firefox's nsSMILKeySpline.cpp
978+* Usage:
979+* var spline = new KeySpline(0.25, 0.1, 0.25, 1.0)
980+* spline.get(x) => returns the easing value | x must be in [0, 1] range
981+*/
982+
983+.pragma library
984+
985+function keySpline (mX1, mY1, mX2, mY2) {
986+
987+ this.get = function(aX) {
988+ if (mX1 == mY1 && mX2 == mY2) return aX; // linear
989+ return CalcBezier(GetTForX(aX), mY1, mY2);
990+ }
991+
992+ function A(aA1, aA2) { return 1.0 - 3.0 * aA2 + 3.0 * aA1; }
993+ function B(aA1, aA2) { return 3.0 * aA2 - 6.0 * aA1; }
994+ function C(aA1) { return 3.0 * aA1; }
995+
996+ // Returns x(t) given t, x1, and x2, or y(t) given t, y1, and y2.
997+ function CalcBezier(aT, aA1, aA2) {
998+ return ((A(aA1, aA2)*aT + B(aA1, aA2))*aT + C(aA1))*aT;
999+ }
1000+
1001+ // Returns dx/dt given t, x1, and x2, or dy/dt given t, y1, and y2.
1002+ function GetSlope(aT, aA1, aA2) {
1003+ return 3.0 * A(aA1, aA2)*aT*aT + 2.0 * B(aA1, aA2) * aT + C(aA1);
1004+ }
1005+
1006+ function GetTForX(aX) {
1007+ // Newton raphson iteration
1008+ var aGuessT = aX;
1009+ for (var i = 0; i < 4; ++i) {
1010+ var currentSlope = GetSlope(aGuessT, mX1, mX2);
1011+ if (currentSlope == 0.0) return aGuessT;
1012+ var currentX = CalcBezier(aGuessT, mX1, mX2) - aX;
1013+ aGuessT -= currentX / currentSlope;
1014+ }
1015+ return aGuessT;
1016+ }
1017+}
1018
1019=== added file 'qml/Stage/Spread/MathUtils.js'
1020--- qml/Stage/Spread/MathUtils.js 1970-01-01 00:00:00 +0000
1021+++ qml/Stage/Spread/MathUtils.js 2016-10-03 11:16:14 +0000
1022@@ -0,0 +1,95 @@
1023+/*
1024+ * Copyright (C) 2016 Canonical, Ltd.
1025+ *
1026+ * This program is free software; you can redistribute it and/or modify
1027+ * it under the terms of the GNU General Public License as published by
1028+ * the Free Software Foundation; version 3.
1029+ *
1030+ * This program is distributed in the hope that it will be useful,
1031+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1032+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1033+ * GNU General Public License for more details.
1034+ *
1035+ * You should have received a copy of the GNU General Public License
1036+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1037+ */
1038+
1039+.pragma library
1040+
1041+/**
1042+ * From processing.js: https://raw.githubusercontent.com/processing-js/processing-js/v1.4.8/processing.js
1043+ *
1044+ * Re-map a number from one range to another. In the example above, the number
1045+ * '25' is converted from a value in the range 0..100 into a value that
1046+ * ranges from the left edge (0) to the right edge (width) of the screen.
1047+ * Numbers outside the range are not clamped to 0 and 1, because out-of-range
1048+ * values are often intentional and useful.
1049+ *
1050+ * @param {Number} value The incoming value to be converted
1051+ * @param {Number} istart Lower bound of the value's current range
1052+ * @param {Number} istop Upper bound of the value's current range
1053+ * @param {Number} ostart Lower bound of the value's target range
1054+ * @param {Number} ostop Upper bound of the value's target range
1055+ *
1056+ * @returns {Number}
1057+ */
1058+function map(value, istart, istop, ostart, ostop) {
1059+ return ostart + (ostop - ostart) * ((value - istart) / (istop - istart))
1060+}
1061+
1062+/**
1063+ * Return a value which is always between `min` and `max`
1064+ *
1065+ * @param {Number} value The current value
1066+ * @param {Number} min The minimum value
1067+ * @param {Number} max The maximum value
1068+ *
1069+ * @returns {Number}
1070+ */
1071+function clamp(value, min, max) {
1072+ if (value < min) return min
1073+ if (value > max) return max
1074+ return value
1075+}
1076+
1077+// calculates the distance from the middle of one rect to middle of other rect
1078+function rectDistance(rect1, rect2) {
1079+ return pointDistance(Qt.point(rect1.x + rect1.width / 2, rect1.y + rect1.height / 2),
1080+ Qt.point(rect2.x + rect2.width / 2, rect2.y + rect2.height / 2))
1081+}
1082+
1083+// calculates the distance between two points
1084+function pointDistance(point1, point2) {
1085+ return Math.sqrt(Math.pow(point1.x - point2.x, 2) +
1086+ Math.pow(point1.y - point2.y, 2)
1087+ )
1088+}
1089+
1090+// from http://stackoverflow.com/questions/14616829/java-method-to-find-the-rectangle-that-is-the-intersection-of-two-rectangles-usi
1091+function intersectionRect(r1, r2) {
1092+ var xmin = Math.max(r1.x, r2.x);
1093+ var xmax1 = r1.x + r1.width;
1094+ var xmax2 = r2.x + r2.width;
1095+ var xmax = Math.min(xmax1, xmax2);
1096+ var out = {x:0, y:0, width:0, height:0}
1097+ if (xmax > xmin) {
1098+ var ymin = Math.max(r1.y, r2.y);
1099+ var ymax1 = r1.y + r1.height;
1100+ var ymax2 = r2.y + r2.height;
1101+ var ymax = Math.min(ymax1, ymax2);
1102+ if (ymax > ymin) {
1103+ out.x = xmin;
1104+ out.y = ymin;
1105+ out.width = xmax - xmin;
1106+ out.height = ymax - ymin;
1107+ }
1108+ }
1109+ return out;
1110+}
1111+
1112+function easeOutCubic(t) { return (--t)*t*t+1 }
1113+
1114+function linearAnimation(startProgress, endProgress, startValue, endValue, progress) {
1115+ // progress : progressDiff = value : valueDiff => value = progress * valueDiff / progressDiff
1116+ return (progress - startProgress) * (endValue - startValue) / (endProgress - startProgress) + startValue;
1117+}
1118
1119=== added file 'qml/Stage/Spread/OpacityMask.qml'
1120--- qml/Stage/Spread/OpacityMask.qml 1970-01-01 00:00:00 +0000
1121+++ qml/Stage/Spread/OpacityMask.qml 2016-10-03 11:16:14 +0000
1122@@ -0,0 +1,82 @@
1123+/*
1124+ * Copyright (C) 2016 Canonical, Ltd.
1125+ *
1126+ * This program is free software; you can redistribute it and/or modify
1127+ * it under the terms of the GNU General Public License as published by
1128+ * the Free Software Foundation; version 3.
1129+ *
1130+ * This program is distributed in the hope that it will be useful,
1131+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1132+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1133+ * GNU General Public License for more details.
1134+ *
1135+ * You should have received a copy of the GNU General Public License
1136+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1137+ */
1138+
1139+import QtQuick 2.4
1140+
1141+Item {
1142+ id: root
1143+ anchors.fill: sourceItem
1144+ anchors.margins: -units.gu(2)
1145+ visible: sourceItem !== null
1146+
1147+ property var sourceItem: null
1148+ property int maskX: 0
1149+ property int maskY: 0
1150+ property int maskWidth: 0
1151+ property int maskHeight: 0
1152+
1153+ property real opacityValue: 1
1154+
1155+ Item {
1156+ id: opacityMask
1157+ anchors.fill: parent
1158+
1159+ Rectangle {
1160+ id: clipRect
1161+ color: "black"
1162+ x: root.maskX - root.anchors.margins
1163+ y: root.maskY - root.anchors.margins
1164+ width: root.maskWidth
1165+ height: root.maskHeight
1166+ opacity: 1 - root.opacityValue
1167+ }
1168+ }
1169+
1170+ ShaderEffect {
1171+ id: opacityEffect
1172+ anchors.fill: parent
1173+
1174+ property variant source: ShaderEffectSource {
1175+ id: shaderEffectSource
1176+ sourceItem: root.sourceItem
1177+ sourceRect: root.sourceItem ? Qt.rect(sourceItem.x + root.anchors.margins,
1178+ sourceItem.y + root.anchors.margins,
1179+ sourceItem.width - root.anchors.margins * 2,
1180+ sourceItem.height - root.anchors.margins * 2)
1181+ : Qt.rect(0,0,0,0)
1182+ hideSource: true
1183+ }
1184+
1185+ property var mask: ShaderEffectSource {
1186+ sourceItem: opacityMask
1187+ hideSource: true
1188+ }
1189+
1190+ fragmentShader: "
1191+ varying highp vec2 qt_TexCoord0;
1192+ uniform sampler2D source;
1193+ uniform sampler2D mask;
1194+ void main(void)
1195+ {
1196+ highp vec4 sourceColor = texture2D(source, qt_TexCoord0);
1197+ highp vec4 maskColor = texture2D(mask, qt_TexCoord0);
1198+
1199+ sourceColor *= 1.0 - maskColor.a;
1200+
1201+ gl_FragColor = sourceColor;
1202+ }"
1203+ }
1204+}
1205
1206=== added file 'qml/Stage/Spread/Spread.qml'
1207--- qml/Stage/Spread/Spread.qml 1970-01-01 00:00:00 +0000
1208+++ qml/Stage/Spread/Spread.qml 2016-10-03 11:16:14 +0000
1209@@ -0,0 +1,162 @@
1210+/*
1211+ * Copyright (C) 2016 Canonical, Ltd.
1212+ *
1213+ * This program is free software; you can redistribute it and/or modify
1214+ * it under the terms of the GNU General Public License as published by
1215+ * the Free Software Foundation; version 3.
1216+ *
1217+ * This program is distributed in the hope that it will be useful,
1218+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1219+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1220+ * GNU General Public License for more details.
1221+ *
1222+ * You should have received a copy of the GNU General Public License
1223+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1224+ */
1225+
1226+import QtQuick 2.4
1227+import Ubuntu.Components 1.3
1228+import "MathUtils.js" as MathUtils
1229+
1230+Item {
1231+ id: root
1232+
1233+ // Information about the environment
1234+ property int highlightedIndex: -1
1235+ property var model: null
1236+ property int leftMargin: 0
1237+ property var spreadFlickable
1238+
1239+ // some config options
1240+ property real contentMargin: 0.16 * root.height
1241+ property real contentTopMargin: contentMargin
1242+ property real contentBottomMargin: 0.35 * contentMargin
1243+ property real windowTitleTopMargin: 3/4 * (contentTopMargin - windowTitle.height)
1244+ property int stackItemCount: 3
1245+ property real leftRotationAngle: 22
1246+ property real rightRotationAngle: 32
1247+ property real leftStackScale: .82
1248+ property real rightStackScale: 1
1249+ property real rightEdgeBreakPoint: Math.min(units.gu(40) / root.width, .35)
1250+
1251+ signal leaveSpread()
1252+
1253+ // Calculated stuff
1254+ readonly property int totalItemCount: model.count
1255+ readonly property real leftStackXPos: 0.03 * root.width + leftMargin
1256+ readonly property real rightStackXPos: root.width - 1.5 * leftStackXPos + leftMargin
1257+
1258+ readonly property real stackHeight: spreadItemHeight - appInfoHeight
1259+ readonly property real stackWidth: Math.min(leftStackXPos/3, units.gu(1.5))
1260+
1261+ readonly property real spreadWidth: rightStackXPos - leftStackXPos
1262+ readonly property real spreadHeight: root.height
1263+ readonly property real spreadItemHeight: spreadHeight - contentTopMargin - contentBottomMargin
1264+ readonly property real spreadItemWidth: stackHeight
1265+
1266+ readonly property real dynamicLeftRotationAngle: leftRotationAngle * rotationAngleFactor
1267+ readonly property real dynamicRightRotationAngle: rightRotationAngle * rotationAngleFactor
1268+
1269+ readonly property real appInfoHeight: {
1270+ var screenHeightReferencePoint = 40 // ref screen height in gu
1271+ var valueAtReferencePoint = 0.17 // of screen height at the reference point
1272+ var appInfoHeightValueChange = -0.0014 // units / gu
1273+ var minAppInfoHeight = 0.08
1274+ var maxAppInfoHeight = 0.2
1275+ var screenHeightInGU = root.height / units.gu(1) // screenHeight in gu
1276+
1277+ return MathUtils.clamp(valueAtReferencePoint + appInfoHeightValueChange * (screenHeightInGU - screenHeightReferencePoint), minAppInfoHeight, maxAppInfoHeight) * root.height
1278+ }
1279+
1280+ property real rotationAngleFactor: {
1281+ var spreadHeightReferencePoint = 28 // reference spread height in gu
1282+ var valueAtReferencePoint = 1.3
1283+ var rotationAngleValueChange = -0.008 // units / gu
1284+ var minRotationAngleFactor = 0.6
1285+ var maxRotationAngleFactor = 1.5
1286+ var spreadHeightInGU = spreadHeight / units.gu(1)
1287+
1288+ return MathUtils.clamp(valueAtReferencePoint + rotationAngleValueChange * (spreadHeightInGU - spreadHeightReferencePoint), minRotationAngleFactor, maxRotationAngleFactor)
1289+ }
1290+ readonly property real itemOverlap: {
1291+ var spreadAspectRatioReferencePoint = 1.0 // ref screen height in gu
1292+ var valueAtReferencePoint = 0.74 // of screen height at the reference point
1293+ var itemOverlapValueChange = -0.068
1294+ var minOverlap = 0.55
1295+ var maxOverlap = 0.82
1296+ var spreadAspectRatio = spreadWidth / stackHeight // spread stack aspect ratio (app info not included)
1297+
1298+ return MathUtils.clamp(valueAtReferencePoint + itemOverlapValueChange * (spreadAspectRatio - spreadAspectRatioReferencePoint), minOverlap, maxOverlap)
1299+ }
1300+
1301+ readonly property real visibleItemCount: (spreadWidth / spreadItemWidth) / (1 - itemOverlap)
1302+
1303+ readonly property real spreadTotalWidth: totalItemCount * spreadWidth / visibleItemCount
1304+
1305+ readonly property real centeringOffset: Math.max(spreadWidth - spreadTotalWidth ,0) / (2 * spreadWidth)
1306+
1307+
1308+ readonly property var curve: BezierCurve {
1309+ controlPoint2: {'x': 0.19, 'y': 0.00}
1310+ controlPoint3: {'x': 0.91, 'y': 1.00}
1311+ }
1312+
1313+ Label {
1314+ id: windowTitle
1315+
1316+ width: Math.min(implicitWidth, 0.5*root.width)
1317+ elide: Qt.ElideMiddle
1318+ anchors.horizontalCenter: parent.horizontalCenter
1319+ y: windowTitleTopMargin
1320+ readonly property var highlightedSurface: root.model ? root.model.surfaceAt(root.highlightedIndex) : null
1321+ readonly property var highlightedApp: root.model ? root.model.applicationAt(root.highlightedIndex) : null
1322+ text: root.highlightedIndex >= 0 && highlightedSurface && highlightedSurface.name != "" ? highlightedSurface.name :
1323+ highlightedApp ? highlightedApp.name : ""
1324+ fontSize: root.height < units.gu(85) ? 'medium' : 'large'
1325+ color: "white"
1326+ opacity: root.highlightedIndex >= 0 ? 1 : 0
1327+ Behavior on opacity { UbuntuNumberAnimation { } }
1328+ }
1329+
1330+ Keys.onPressed: {
1331+ switch (event.key) {
1332+ case Qt.Key_Left:
1333+ case Qt.Key_Backtab:
1334+ selectPrevious(event.isAutoRepeat)
1335+ event.accepted = true;
1336+ break;
1337+ case Qt.Key_Right:
1338+ case Qt.Key_Tab:
1339+ selectNext(event.isAutoRepeat)
1340+ event.accepted = true;
1341+ break;
1342+ case Qt.Key_Escape:
1343+ highlightedIndex = -1
1344+ // Falling through intentionally
1345+ case Qt.Key_Enter:
1346+ case Qt.Key_Return:
1347+ case Qt.Key_Space:
1348+ root.leaveSpread();
1349+ event.accepted = true;
1350+ }
1351+ }
1352+
1353+
1354+ function selectNext(isAutoRepeat) {
1355+ if (isAutoRepeat && highlightedIndex >= totalItemCount -1) {
1356+ return; // AutoRepeat is not allowed to wrap around
1357+ }
1358+
1359+ highlightedIndex = (highlightedIndex + 1) % totalItemCount;
1360+ spreadFlickable.snap(highlightedIndex)
1361+ }
1362+
1363+ function selectPrevious(isAutoRepeat) {
1364+ if (isAutoRepeat && highlightedIndex == 0) {
1365+ return; // AutoRepeat is not allowed to wrap around
1366+ }
1367+
1368+ highlightedIndex = highlightedIndex - 1 >= 0 ? highlightedIndex - 1 : totalItemCount - 1;
1369+ spreadFlickable.snap(highlightedIndex)
1370+ }
1371+}
1372
1373=== added file 'qml/Stage/Spread/SpreadDelegateInputArea.qml'
1374--- qml/Stage/Spread/SpreadDelegateInputArea.qml 1970-01-01 00:00:00 +0000
1375+++ qml/Stage/Spread/SpreadDelegateInputArea.qml 2016-10-03 11:16:14 +0000
1376@@ -0,0 +1,183 @@
1377+/*
1378+ * Copyright (C) 2016 Canonical, Ltd.
1379+ *
1380+ * This program is free software; you can redistribute it and/or modify
1381+ * it under the terms of the GNU General Public License as published by
1382+ * the Free Software Foundation; version 3.
1383+ *
1384+ * This program is distributed in the hope that it will be useful,
1385+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1386+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1387+ * GNU General Public License for more details.
1388+ *
1389+ * You should have received a copy of the GNU General Public License
1390+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1391+ */
1392+
1393+import QtQuick 2.4
1394+import Ubuntu.Components 1.3
1395+import Ubuntu.Gestures 0.1
1396+import "../../Components"
1397+
1398+Item {
1399+ id: root
1400+
1401+ property bool closeable: true
1402+ readonly property real minSpeedToClose: units.gu(40)
1403+ property bool zeroVelocityCounts: false
1404+
1405+ readonly property alias distance: d.distance
1406+
1407+ signal clicked()
1408+ signal close()
1409+
1410+ QtObject {
1411+ id: d
1412+ property real distance: 0
1413+ property bool moving: false
1414+ property var dragEvents: []
1415+ property real dragVelocity: 0
1416+ property int threshold: units.gu(2)
1417+
1418+ // Can be replaced with a fake implementation during tests
1419+ // property var __getCurrentTimeMs: function () { return new Date().getTime() }
1420+ property var __dateTime: new function() {
1421+ this.getCurrentTimeMs = function() {return new Date().getTime()}
1422+ }
1423+
1424+ function pushDragEvent(event) {
1425+ var currentTime = __dateTime.getCurrentTimeMs()
1426+ dragEvents.push([currentTime, event.x, event.y, getEventSpeed(currentTime, event)])
1427+ cullOldDragEvents(currentTime)
1428+ updateSpeed()
1429+ }
1430+
1431+ function cullOldDragEvents(currentTime) {
1432+ // cull events older than 50 ms but always keep the latest 2 events
1433+ for (var numberOfCulledEvents = 0; numberOfCulledEvents < dragEvents.length-2; numberOfCulledEvents++) {
1434+ // dragEvents[numberOfCulledEvents][0] is the dragTime
1435+ if (currentTime - dragEvents[numberOfCulledEvents][0] <= 50) break
1436+ }
1437+
1438+ dragEvents.splice(0, numberOfCulledEvents)
1439+ }
1440+
1441+ function updateSpeed() {
1442+ var totalSpeed = 0
1443+ for (var i = 0; i < dragEvents.length; i++) {
1444+ totalSpeed += dragEvents[i][3]
1445+ }
1446+
1447+ if (zeroVelocityCounts || Math.abs(totalSpeed) > 0.001) {
1448+ dragVelocity = totalSpeed / dragEvents.length * 1000
1449+ }
1450+ }
1451+
1452+ function getEventSpeed(currentTime, event) {
1453+ if (dragEvents.length != 0) {
1454+ var lastDrag = dragEvents[dragEvents.length-1]
1455+ var duration = Math.max(1, currentTime - lastDrag[0])
1456+ return (event.y - lastDrag[2]) / duration
1457+ } else {
1458+ return 0
1459+ }
1460+ }
1461+ }
1462+
1463+ // Event eater
1464+ MouseArea {
1465+ anchors.fill: parent
1466+ onClicked: root.clicked()
1467+ onWheel: wheel.accepted = true
1468+ }
1469+
1470+ MultiPointTouchArea {
1471+ anchors.fill: parent
1472+ mouseEnabled: false
1473+ maximumTouchPoints: 1
1474+ property int offset: 0
1475+
1476+ touchPoints: [
1477+ TouchPoint {
1478+ id: tp
1479+ }
1480+ ]
1481+
1482+ onCanceled: {
1483+ d.moving = false
1484+ animation.animate("center");
1485+ }
1486+
1487+ onTouchUpdated: {
1488+ if (!d.moving) {
1489+ if (Math.abs(tp.startY - tp.y) > d.threshold) {
1490+ d.moving = true;
1491+ d.dragEvents = []
1492+ offset = tp.y - tp.startY;
1493+ } else {
1494+ return;
1495+ }
1496+ }
1497+
1498+ d.distance = tp.y - tp.startY - offset
1499+ d.pushDragEvent(tp);
1500+ }
1501+
1502+ onReleased: {
1503+ if (!d.moving) {
1504+ root.clicked()
1505+ }
1506+
1507+ if (!root.closeable) {
1508+ animation.animate("center")
1509+ return;
1510+ }
1511+
1512+ var touchPoint = touchPoints[0];
1513+
1514+ if ((d.dragVelocity < -root.minSpeedToClose && d.distance < -units.gu(8)) || d.distance < -root.height / 2) {
1515+ animation.animate("up")
1516+ } else if ((d.dragVelocity > root.minSpeedToClose && d.distance > units.gu(8)) || d.distance > root.height / 2) {
1517+ animation.animate("down")
1518+ } else {
1519+ animation.animate("center")
1520+ }
1521+ }
1522+ }
1523+
1524+ UbuntuNumberAnimation {
1525+ id: animation
1526+ objectName: "closeAnimation"
1527+ target: d
1528+ property: "distance"
1529+ property bool requestClose: false
1530+
1531+ function animate(direction) {
1532+ animation.from = dragArea.distance;
1533+ switch (direction) {
1534+ case "up":
1535+ animation.to = -root.height * 1.5;
1536+ requestClose = true;
1537+ break;
1538+ case "down":
1539+ animation.to = root.height * 1.5;
1540+ requestClose = true;
1541+ break;
1542+ default:
1543+ animation.to = 0
1544+ }
1545+ animation.start();
1546+ }
1547+
1548+ onRunningChanged: {
1549+ if (!running) {
1550+ d.moving = false;
1551+ if (requestClose) {
1552+ root.close();
1553+ } else {
1554+ d.distance = 0;
1555+ }
1556+ }
1557+ }
1558+ }
1559+}
1560
1561=== added file 'qml/Stage/Spread/SpreadMaths.qml'
1562--- qml/Stage/Spread/SpreadMaths.qml 1970-01-01 00:00:00 +0000
1563+++ qml/Stage/Spread/SpreadMaths.qml 2016-10-03 11:16:14 +0000
1564@@ -0,0 +1,78 @@
1565+/*
1566+ * Copyright (C) 2016 Canonical, Ltd.
1567+ *
1568+ * This program is free software; you can redistribute it and/or modify
1569+ * it under the terms of the GNU General Public License as published by
1570+ * the Free Software Foundation; version 3.
1571+ *
1572+ * This program is distributed in the hope that it will be useful,
1573+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1574+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1575+ * GNU General Public License for more details.
1576+ *
1577+ * You should have received a copy of the GNU General Public License
1578+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1579+ */
1580+
1581+import QtQuick 2.4
1582+import Ubuntu.Components 1.3
1583+import Utils 0.1
1584+import "MathUtils.js" as MathUtils
1585+
1586+Item {
1587+ id: root
1588+ anchors { left: parent.left; top: parent.top; margins: units.gu(1) }
1589+
1590+ // Information about the environment
1591+ property Item flickable: null
1592+ property Spread spread: null
1593+ property int itemIndex: 0
1594+
1595+ // Internal
1596+ property real spreadPosition: itemIndex/spread.visibleItemCount - flickable.contentX/spread.spreadWidth // 0 -> left stack, 1 -> right stack
1597+ property real leftStackingProgress: MathUtils.clamp(MathUtils.map(spreadPosition, 0, -spread.stackItemCount/spread.visibleItemCount , 0, 1), 0, 1)
1598+ property real rightStackingProgress: MathUtils.clamp(MathUtils.map(spreadPosition, 1, 1 + spread.stackItemCount/spread.visibleItemCount , 0, 1), 0, 1)
1599+ property real stackingX: (MathUtils.easeOutCubic(rightStackingProgress) - MathUtils.easeOutCubic(leftStackingProgress)) * spread.stackWidth
1600+
1601+
1602+ QtObject {
1603+ id: d
1604+ property real spreadScale: MathUtils.clamp(
1605+ MathUtils.map(spreadPosition, 0, 1, spread.leftStackScale, spread.rightStackScale),
1606+ spread.leftStackScale, spread.rightStackScale)
1607+
1608+ property real selectedScale: (spread.highlightedIndex == itemIndex ? 1.01 : 1)
1609+ Behavior on selectedScale { UbuntuNumberAnimation { duration: UbuntuAnimation.SnapDuration } }
1610+
1611+ }
1612+
1613+ // Output
1614+ readonly property int targetX: spread.leftStackXPos +
1615+ spread.spreadWidth * spread.curve.getYFromX(spreadPosition + spread.centeringOffset) +
1616+ stackingX
1617+
1618+ readonly property int targetY: spread.contentTopMargin
1619+
1620+ readonly property real targetAngle: MathUtils.clamp(
1621+ MathUtils.map(targetX, spread.leftStackXPos, spread.rightStackXPos, spread.dynamicLeftRotationAngle, spread.dynamicRightRotationAngle),
1622+ Math.min(spread.dynamicLeftRotationAngle, spread.dynamicRightRotationAngle), Math.max(spread.dynamicLeftRotationAngle, spread.dynamicRightRotationAngle))
1623+
1624+
1625+ readonly property real targetScale: d.spreadScale * d.selectedScale
1626+
1627+ readonly property real shadowOpacity: 0.2 * (1 - rightStackingProgress) * (1 - leftStackingProgress)
1628+
1629+
1630+ readonly property real closeIconOffset: (targetScale - 1) * (-spread.stackHeight / 2)
1631+
1632+ readonly property real tileInfoOpacity: Math.min(MathUtils.clamp(MathUtils.map(leftStackingProgress, 0 , 1/(spread.stackItemCount*3), 1, 0), 0 , 1),
1633+ MathUtils.clamp(MathUtils.map(spreadPosition, 0.9 , 1, 1, 0), 0 , 1)) /** MathUtils.map(curvedSwitcherProgress, 0.7, 0.9, 0, 1)*/
1634+
1635+ readonly property bool itemVisible: {
1636+ var leftStackHidden = spreadPosition < -(spread.stackItemCount + 1)/spread.visibleItemCount
1637+ // don't hide the rightmost
1638+ var rightStackHidden = (spreadPosition > 1 + (spread.stackItemCount)/spread.visibleItemCount) && itemIndex !== spread.totalItemCount - 1
1639+ return !leftStackHidden && !rightStackHidden
1640+ }
1641+
1642+}
1643
1644=== added file 'qml/Stage/Spread/StagedRightEdgeMaths.qml'
1645--- qml/Stage/Spread/StagedRightEdgeMaths.qml 1970-01-01 00:00:00 +0000
1646+++ qml/Stage/Spread/StagedRightEdgeMaths.qml 2016-10-03 11:16:14 +0000
1647@@ -0,0 +1,174 @@
1648+/*
1649+ * Copyright (C) 2016 Canonical, Ltd.
1650+ *
1651+ * This program is free software; you can redistribute it and/or modify
1652+ * it under the terms of the GNU General Public License as published by
1653+ * the Free Software Foundation; version 3.
1654+ *
1655+ * This program is distributed in the hope that it will be useful,
1656+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1657+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1658+ * GNU General Public License for more details.
1659+ *
1660+ * You should have received a copy of the GNU General Public License
1661+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1662+ */
1663+
1664+import QtQuick 2.4
1665+import Ubuntu.Components 1.3
1666+import Unity.Application 0.1
1667+import "MathUtils.js" as MathUtils
1668+
1669+QtObject {
1670+ id: root
1671+
1672+ // Input
1673+ property int itemIndex: 0
1674+ property real progress: 0
1675+ property int sceneWidth: 0
1676+ property int sideStageWidth: 0
1677+ property int sceneHeight: 0
1678+ property int targetX: 0
1679+ property int startY: 0
1680+ property int targetY: 0
1681+ property real startAngle: 30
1682+ property real targetAngle: 0
1683+ property int targetHeight: 0
1684+ property real startScale: 1.3
1685+ property real targetScale: 0
1686+ property real breakPoint: units.gu(15) / sceneWidth
1687+
1688+ property bool isMainStageApp: false
1689+ property bool isSideStageApp: false
1690+ property bool sideStageOpen: false
1691+ property int nextInStack: 0
1692+ property int shuffledZ: 0
1693+
1694+
1695+ // Config
1696+ property int tileDistance: units.gu(10)
1697+
1698+ // Output
1699+
1700+ readonly property real scaleToPreviewProgress: {
1701+ return progress < breakPoint ? 0 : MathUtils.clamp(MathUtils.linearAnimation(breakPoint, 1, 0, 1, progress), 0, 1)
1702+ }
1703+ readonly property int animatedWidth: {
1704+ return progress < breakPoint ? root.sceneHeight : MathUtils.linearAnimation(breakPoint, 1, root.sceneWidth, targetHeight, progress)
1705+ }
1706+
1707+ readonly property int animatedHeight: {
1708+ return progress < breakPoint ? root.sceneHeight : MathUtils.linearAnimation(breakPoint, 1, root.sceneHeight, targetHeight, progress)
1709+ }
1710+
1711+
1712+ readonly property int animatedX: {
1713+ var nextStage = appRepeater.itemAt(nextInStack) ? appRepeater.itemAt(nextInStack).stage : ApplicationInfoInterface.MainStage;
1714+
1715+ var startX = 0;
1716+ if (isMainStageApp) {
1717+ if (progress < breakPoint) {
1718+ if (nextStage == ApplicationInfoInterface.MainStage) {
1719+ return MathUtils.linearAnimation(0, breakPoint, 0, -units.gu(4), progress);
1720+ } else {
1721+ return 0;
1722+ }
1723+ } else {
1724+ if (nextStage == ApplicationInfoInterface.MainStage) {
1725+ return MathUtils.linearAnimation(breakPoint, 1, -units.gu(4), targetX, progress);
1726+ } else {
1727+ return MathUtils.linearAnimation(breakPoint, 1, 0, targetX, progress);
1728+ }
1729+ }
1730+ } else if (isSideStageApp) {
1731+ startX = sceneWidth - sideStageWidth;
1732+ } else if (itemIndex == nextInStack && itemIndex <= 2 && priv.sideStageDelegate && nextStage == ApplicationInfoInterface.MainStage) {
1733+ startX = sceneWidth - sideStageWidth;
1734+ } else {
1735+ var stageCount = (priv.mainStageDelegate ? 1 : 0) + (priv.sideStageDelegate ? 1 : 0)
1736+ startX = sceneWidth + Math.max(0, itemIndex - stageCount - 1) * tileDistance;
1737+ }
1738+
1739+ if (itemIndex == nextInStack) {
1740+ if (progress < breakPoint) {
1741+ return MathUtils.linearAnimation(0, breakPoint, startX, startX * (1 - breakPoint), progress)
1742+ }
1743+ return MathUtils.linearAnimation(breakPoint, 1, startX * (1 - breakPoint), targetX, progress)
1744+ }
1745+
1746+ if (progress < breakPoint) {
1747+ return startX;
1748+ }
1749+
1750+ return MathUtils.linearAnimation(breakPoint, 1, startX, targetX, progress)
1751+
1752+ }
1753+
1754+ readonly property int animatedY: progress < breakPoint ? startY : MathUtils.linearAnimation(breakPoint, 1, startY, targetY, progress)
1755+
1756+ readonly property int animatedZ: {
1757+ if (progress < breakPoint + (1 - breakPoint) / 2) {
1758+ return shuffledZ
1759+ }
1760+ return itemIndex;
1761+ }
1762+
1763+ readonly property real animatedAngle: {
1764+ var nextStage = appRepeater.itemAt(nextInStack) ? appRepeater.itemAt(nextInStack).stage : ApplicationInfoInterface.MainStage;
1765+
1766+ var startAngle = 0;
1767+ if (isMainStageApp) {
1768+ startAngle = 0;
1769+ } else if (isSideStageApp) {
1770+ startAngle = 0;
1771+ } else {
1772+ if (stage == ApplicationInfoInterface.SideStage && itemIndex == nextInStack && !sideStageOpen) {
1773+ startAngle = 0;
1774+ } else {
1775+ startAngle = root.startAngle;
1776+ }
1777+ }
1778+
1779+ if ((itemIndex == nextInStack)
1780+ || (isMainStageApp && nextStage === ApplicationInfoInterface.MainStage)
1781+ || (isSideStageApp && nextStage === ApplicationInfoInterface.SideStage)) {
1782+ return MathUtils.linearAnimation(0, 1, startAngle, targetAngle, progress);
1783+ }
1784+
1785+ if (progress < breakPoint) {
1786+ return 0;
1787+ }
1788+ return MathUtils.linearAnimation(breakPoint, 1, startAngle, targetAngle, progress);
1789+ }
1790+
1791+ readonly property real animatedScale: {
1792+ var pullingInSideStage = itemIndex == nextInStack && stage == ApplicationInfoInterface.SideStage && !sideStageOpen;
1793+
1794+ var startScale = 1;
1795+ if (isMainStageApp) {
1796+ startScale = 1;
1797+ } else if (isSideStageApp) {
1798+ startScale = 1;
1799+ } else {
1800+ if (pullingInSideStage) {
1801+ startScale = 1
1802+ } else {
1803+ startScale = root.startScale;
1804+ }
1805+ }
1806+
1807+ if (progress < breakPoint) {
1808+ if (itemIndex == nextInStack && (sideStageOpen || stage == ApplicationInfoInterface.MainStage)) {
1809+ return MathUtils.linearAnimation(0, 1, startScale, targetScale, progress);
1810+ }
1811+ return startScale;
1812+ }
1813+ if (itemIndex == nextInStack) {
1814+ return MathUtils.linearAnimation(0, 1, startScale, targetScale, progress)
1815+ }
1816+
1817+ return MathUtils.linearAnimation(breakPoint, 1, startScale, targetScale, progress)
1818+ }
1819+
1820+ readonly property bool itemVisible: true //animatedX < sceneWidth
1821+}
1822
1823=== added file 'qml/Stage/Spread/WindowedRightEdgeMaths.qml'
1824--- qml/Stage/Spread/WindowedRightEdgeMaths.qml 1970-01-01 00:00:00 +0000
1825+++ qml/Stage/Spread/WindowedRightEdgeMaths.qml 2016-10-03 11:16:14 +0000
1826@@ -0,0 +1,81 @@
1827+/*
1828+ * Copyright (C) 2016 Canonical, Ltd.
1829+ *
1830+ * This program is free software; you can redistribute it and/or modify
1831+ * it under the terms of the GNU General Public License as published by
1832+ * the Free Software Foundation; version 3.
1833+ *
1834+ * This program is distributed in the hope that it will be useful,
1835+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1836+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1837+ * GNU General Public License for more details.
1838+ *
1839+ * You should have received a copy of the GNU General Public License
1840+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1841+ */
1842+
1843+import QtQuick 2.4
1844+import Ubuntu.Components 1.3
1845+import Unity.Application 0.1
1846+import "MathUtils.js" as MathUtils
1847+
1848+QtObject {
1849+ id: root
1850+
1851+ // Input
1852+ property int itemIndex: 0
1853+ property int normalZ: 0
1854+ property real progress: 0
1855+ property int startWidth: 0
1856+ property int startHeight: 0
1857+ property int startX: 0
1858+ property int targetX: 0
1859+ property int startY: 0
1860+ property int targetY: 0
1861+// property real startAngle: 40
1862+ property real targetAngle: 0
1863+ property int targetHeight: 0
1864+ property real targetScale: 0
1865+
1866+ // Config
1867+ property real breakPoint: 0.4
1868+
1869+ // Output
1870+
1871+ readonly property real scaleToPreviewProgress: {
1872+ return progress < breakPoint ? 0 : MathUtils.clamp(MathUtils.linearAnimation(breakPoint, 1, 0, 1, progress), 0, 1)
1873+ }
1874+ readonly property int animatedWidth: {
1875+ return progress < breakPoint ? root.startWidth : MathUtils.linearAnimation(breakPoint, 1, root.startWidth, targetHeight, progress)
1876+ }
1877+
1878+ readonly property int animatedHeight: {
1879+ return progress < breakPoint ? root.startHeight : MathUtils.linearAnimation(breakPoint, 1, root.startHeight, targetHeight, progress)
1880+ }
1881+
1882+ readonly property int animatedX: {
1883+ if (progress < breakPoint) {
1884+ return startX;
1885+ }
1886+ return MathUtils.linearAnimation(breakPoint, 1, startX, targetX, progress)
1887+ }
1888+
1889+ readonly property int animatedY: progress < breakPoint ? startY : MathUtils.linearAnimation(breakPoint, 1, startY, targetY, progress)
1890+
1891+ readonly property real animatedAngle: progress < breakPoint ? 0 : MathUtils.linearAnimation(breakPoint, 1, 0, targetAngle, progress);
1892+
1893+ readonly property real decorationHeight: progress < breakPoint ? 1 : MathUtils.linearAnimation(breakPoint, 1, 1, 0, progress);
1894+
1895+ readonly property int animatedZ: {
1896+ if (progress < breakPoint + (1 - breakPoint) / 2) {
1897+ return itemIndex == 1 ? normalZ + 2 : normalZ
1898+ }
1899+ return itemIndex
1900+ }
1901+
1902+ readonly property real opacityMask: itemIndex == 1 ? MathUtils.linearAnimation(0, breakPoint, 0, 1, progress) : 1
1903+
1904+ readonly property real animatedScale: progress < breakPoint ? 1 : MathUtils.linearAnimation(breakPoint, 1, 1, targetScale, progress)
1905+
1906+// readonly property bool itemVisible: true //animatedX < sceneWidth
1907+}
1908
1909=== added file 'qml/Stage/Spread/cubic-bezier.js'
1910--- qml/Stage/Spread/cubic-bezier.js 1970-01-01 00:00:00 +0000
1911+++ qml/Stage/Spread/cubic-bezier.js 2016-10-03 11:16:14 +0000
1912@@ -0,0 +1,39 @@
1913+/*
1914+ * Copyright (C) 2016 Canonical, Ltd.
1915+ *
1916+ * This program is free software; you can redistribute it and/or modify
1917+ * it under the terms of the GNU General Public License as published by
1918+ * the Free Software Foundation; version 3.
1919+ *
1920+ * This program is distributed in the hope that it will be useful,
1921+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1922+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1923+ * GNU General Public License for more details.
1924+ *
1925+ * You should have received a copy of the GNU General Public License
1926+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1927+ */
1928+
1929+//====================================\\
1930+// 13thParallel.org Beziér Curve Code \\
1931+// by Dan Pupius (www.pupius.net) \\
1932+//====================================\\
1933+
1934+
1935+var coord = function (x,y) {
1936+ if(!x) var x=0;
1937+ if(!y) var y=0;
1938+ return {x: x, y: y};
1939+}
1940+
1941+function B4(t) { return t*t*t }
1942+function B3(t) { return 3*t*t*(1-t) }
1943+function B2(t) { return 3*t*(1-t)*(1-t) }
1944+function B1(t) { return (1-t)*(1-t)*(1-t) }
1945+
1946+var getBezier = function(percent,C1,C2,C3,C4) {
1947+ var pos = new coord();
1948+ pos.x = C1.x*B1(percent) + C2.x*B2(percent) + C3.x*B3(percent) + C4.x*B4(percent);
1949+ pos.y = C1.y*B1(percent) + C2.y*B2(percent) + C3.y*B3(percent) + C4.y*B4(percent);
1950+ return pos;
1951+}
1952
1953=== renamed file 'qml/Stages/DesktopStage.qml' => 'qml/Stage/Stage.qml'
1954--- qml/Stages/DesktopStage.qml 2016-09-07 08:36:59 +0000
1955+++ qml/Stage/Stage.qml 2016-10-03 11:16:14 +0000
1956@@ -22,75 +22,152 @@
1957 import Utils 0.1
1958 import Ubuntu.Gestures 0.1
1959 import GlobalShortcut 1.0
1960+import GSettings 1.0
1961+import "Spread"
1962+import "Spread/MathUtils.js" as MathUtils
1963
1964-AbstractStage {
1965+FocusScope {
1966 id: root
1967 anchors.fill: parent
1968- paintBackground: false
1969-
1970- // functions to be called from outside
1971- function updateFocusedAppOrientation() { /* TODO */ }
1972- function updateFocusedAppOrientationAnimated() { /* TODO */}
1973- function pushRightEdge(amount) {
1974- if (spread.state === "") {
1975- edgeBarrier.push(amount);
1976- }
1977- }
1978- function closeFocusedDelegate() {
1979- if (priv.focusedAppDelegate && !priv.focusedAppDelegate.isDash) {
1980- priv.focusedAppDelegate.close();
1981- }
1982- }
1983-
1984- // Used by TutorialRight
1985- property bool spreadShown: spread.state == "altTab"
1986+
1987+ property QtObject applicationManager
1988+ property QtObject topLevelSurfaceList
1989+ property bool altTabPressed
1990+ property url background
1991+ property int dragAreaWidth
1992+ property bool interactive
1993+ property bool keepDashRunning: true
1994+ property real nativeHeight
1995+ property real nativeWidth
1996+ property QtObject orientations
1997+ property int shellOrientation
1998+ property int shellOrientationAngle
1999+ property bool spreadEnabled: true // If false, animations and right edge will be disabled
2000+ property bool suspended
2001+ property int leftMargin: 0
2002+ property bool oskEnabled: false
2003+ property rect inputMethodRect
2004+
2005+ // Configuration
2006+ property string mode: "staged"
2007+ property real leftEdgeDragProgress: 0
2008+
2009+ // Used by the tutorial code
2010+ readonly property bool spreadShown: state == "spread"
2011+ readonly property real rightEdgeDragProgress: rightEdgeDragArea.progress // How far left the stage has been dragged
2012
2013 // used by the snap windows (edge maximize) feature
2014 readonly property alias previewRectangle: fakeRectangle
2015
2016- mainApp: priv.focusedAppDelegate ? priv.focusedAppDelegate.application : null
2017+ readonly property var mainApp: priv.focusedAppDelegate ? priv.focusedAppDelegate.application : null
2018
2019 // application windows never rotate independently
2020- mainAppWindowOrientationAngle: shellOrientationAngle
2021-
2022- orientationChangesEnabled: true
2023-
2024-
2025- itemConfiningMouseCursor: !spreadShown && priv.focusedAppDelegate && priv.focusedAppDelegate.surface &&
2026+ property int mainAppWindowOrientationAngle: shellOrientationAngle
2027+
2028+ property bool orientationChangesEnabled: priv.focusedAppDelegate && priv.focusedAppDelegate.orientationChangesEnabled
2029+
2030+ property int supportedOrientations: {
2031+ if (mainApp) {
2032+ switch (mode) {
2033+ case "staged":
2034+ return mainApp.supportedOrientations;
2035+ case "stagedWithSideStage":
2036+ var orientations = mainApp.supportedOrientations;
2037+ orientations |= Qt.LandscapeOrientation | Qt.InvertedLandscapeOrientation;
2038+ if (priv.sideStageItemId) {
2039+ // If we have a sidestage app, support Portrait orientation
2040+ // so that it will switch the sidestage app to mainstage on rotate to portrait
2041+ orientations |= Qt.PortraitOrientation|Qt.InvertedPortraitOrientation;
2042+ }
2043+ return orientations;
2044+ }
2045+ }
2046+
2047+ return Qt.PortraitOrientation |
2048+ Qt.LandscapeOrientation |
2049+ Qt.InvertedPortraitOrientation |
2050+ Qt.InvertedLandscapeOrientation;
2051+ }
2052+
2053+
2054+ onAltTabPressedChanged: priv.goneToSpread = altTabPressed
2055+
2056+ property Item itemConfiningMouseCursor: !spreadShown && priv.focusedAppDelegate && priv.focusedAppDelegate.surface &&
2057 priv.focusedAppDelegate.surface.confinesMousePointer ?
2058 priv.focusedAppDelegate.clientAreaItem : null;
2059
2060+ signal itemSnapshotRequested(Item item)
2061+
2062+ // functions to be called from outside
2063+ function updateFocusedAppOrientation() { /* TODO */ }
2064+ function updateFocusedAppOrientationAnimated() { /* TODO */}
2065+ function pushRightEdge(amount) {
2066+ edgeBarrier.push(amount);
2067+ }
2068+
2069+ onSpreadEnabledChanged: {
2070+ if (!spreadEnabled && root.state == "spread") {
2071+ priv.goneToSpread = false;
2072+ }
2073+ }
2074+
2075+ GSettings {
2076+ id: lifecycleExceptions
2077+ schema.id: "com.canonical.qtmir"
2078+ }
2079+
2080+ function isExemptFromLifecycle(appId) {
2081+ var shortAppId = appId.split('_')[0];
2082+ for (var i = 0; i < lifecycleExceptions.lifecycleExemptAppids.length; i++) {
2083+ if (shortAppId === lifecycleExceptions.lifecycleExemptAppids[i]) {
2084+ return true;
2085+ }
2086+ }
2087+ return false;
2088+ }
2089+
2090+ GlobalShortcut {
2091+ id: closeFocusedShortcut
2092+ shortcut: Qt.AltModifier|Qt.Key_F4
2093+ onTriggered: {
2094+ if (priv.focusedAppDelegate && !priv.focusedAppDelegate.isDash) {
2095+ priv.focusedAppDelegate.close();
2096+ }
2097+ }
2098+ }
2099+
2100 GlobalShortcut {
2101 id: showSpreadShortcut
2102 shortcut: Qt.MetaModifier|Qt.Key_W
2103- onTriggered: spread.state = "altTab"
2104+ onTriggered: priv.goneToSpread = true
2105 }
2106
2107 GlobalShortcut {
2108 id: minimizeAllShortcut
2109 shortcut: Qt.MetaModifier|Qt.ControlModifier|Qt.Key_D
2110 onTriggered: priv.minimizeAllWindows()
2111+ active: root.state == "windowed"
2112 }
2113
2114 GlobalShortcut {
2115 id: maximizeWindowShortcut
2116 shortcut: Qt.MetaModifier|Qt.ControlModifier|Qt.Key_Up
2117 onTriggered: priv.focusedAppDelegate.maximize()
2118- active: priv.focusedAppDelegate !== null && priv.focusedAppDelegate.canBeMaximized
2119+ active: root.state == "windowed" && priv.focusedAppDelegate && priv.focusedAppDelegate.canBeMaximized
2120 }
2121
2122 GlobalShortcut {
2123 id: maximizeWindowLeftShortcut
2124 shortcut: Qt.MetaModifier|Qt.ControlModifier|Qt.Key_Left
2125 onTriggered: priv.focusedAppDelegate.maximizeLeft()
2126- active: priv.focusedAppDelegate !== null && priv.focusedAppDelegate.canBeMaximizedLeftRight
2127+ active: root.state == "windowed" && priv.focusedAppDelegate && priv.focusedAppDelegate.canBeMaximizedLeftRight
2128 }
2129
2130 GlobalShortcut {
2131 id: maximizeWindowRightShortcut
2132 shortcut: Qt.MetaModifier|Qt.ControlModifier|Qt.Key_Right
2133 onTriggered: priv.focusedAppDelegate.maximizeRight()
2134- active: priv.focusedAppDelegate !== null && priv.focusedAppDelegate.canBeMaximizedLeftRight
2135+ active: root.state == "windowed" && priv.focusedAppDelegate && priv.focusedAppDelegate.canBeMaximizedLeftRight
2136 }
2137
2138 GlobalShortcut {
2139@@ -98,7 +175,7 @@
2140 shortcut: Qt.MetaModifier|Qt.ControlModifier|Qt.Key_Down
2141 onTriggered: priv.focusedAppDelegate.anyMaximized
2142 ? priv.focusedAppDelegate.restoreFromMaximized() : priv.focusedAppDelegate.minimize()
2143- active: priv.focusedAppDelegate !== null
2144+ active: root.state == "windowed" && priv.focusedAppDelegate
2145 }
2146
2147 GlobalShortcut {
2148@@ -107,28 +184,17 @@
2149 active: priv.focusedAppDelegate !== null
2150 }
2151
2152- Connections {
2153- target: root.topLevelSurfaceList
2154- onCountChanged: {
2155- if (spread.state == "altTab") {
2156- spread.cancel();
2157- }
2158- }
2159- }
2160-
2161 QtObject {
2162 id: priv
2163 objectName: "DesktopStagePrivate"
2164
2165 property var focusedAppDelegate: null
2166- onFocusedAppDelegateChanged: {
2167- if (spread.state == "altTab") {
2168- spread.state = "";
2169- }
2170- }
2171-
2172 property var foregroundMaximizedAppDelegate: null // for stuff like drop shadow and focusing maximized app by clicking panel
2173
2174+ property bool goneToSpread: false
2175+ property int closingIndex: -1
2176+ property int animationDuration: UbuntuAnimation.FastDuration
2177+
2178 function updateForegroundMaximizedApp() {
2179 var found = false;
2180 for (var i = 0; i < appRepeater.count && !found; i++) {
2181@@ -162,11 +228,86 @@
2182 }
2183 }
2184
2185- readonly property real virtualKeyboardHeight: SurfaceManager.inputMethodSurface
2186- ? SurfaceManager.inputMethodSurface.inputBounds.height
2187- : 0
2188+ readonly property bool sideStageEnabled: root.shellOrientation == Qt.LandscapeOrientation ||
2189+ root.shellOrientation == Qt.InvertedLandscapeOrientation
2190+
2191+ property var mainStageDelegate: null
2192+ property var sideStageDelegate: null
2193+ property int mainStageItemId: 0
2194+ property int sideStageItemId: 0
2195+ property string mainStageAppId: ""
2196+ property string sideStageAppId: ""
2197+
2198+ onSideStageDelegateChanged: {
2199+ if (!sideStageDelegate) {
2200+ sideStage.hide();
2201+ }
2202+ }
2203+
2204+ function updateMainAndSideStageIndexes() {
2205+ if (root.mode != "stagedWithSideStage") {
2206+ priv.sideStageDelegate = null;
2207+ priv.sideStageItemId = 0;
2208+ priv.sideStageAppId = "";
2209+ priv.mainStageDelegate = appRepeater.itemAt(0);
2210+ priv.mainStageAppId = topLevelSurfaceList.idAt(0);
2211+ priv.mainStageAppId = topLevelSurfaceList.applicationAt(0) ? topLevelSurfaceList.applicationAt(0).appId : ""
2212+ return;
2213+ }
2214+
2215+ var choseMainStage = false;
2216+ var choseSideStage = false;
2217+
2218+ if (!root.topLevelSurfaceList)
2219+ return;
2220+
2221+ for (var i = 0; i < appRepeater.count && (!choseMainStage || !choseSideStage); ++i) {
2222+ var appDelegate = appRepeater.itemAt(i);
2223+ if (sideStage.shown && appDelegate.stage == ApplicationInfoInterface.SideStage
2224+ && !choseSideStage) {
2225+ priv.sideStageDelegate = appDelegate
2226+ priv.sideStageItemId = root.topLevelSurfaceList.idAt(i);
2227+ priv.sideStageAppId = root.topLevelSurfaceList.applicationAt(i).appId;
2228+ choseSideStage = true;
2229+ } else if (!choseMainStage && appDelegate.stage == ApplicationInfoInterface.MainStage) {
2230+ priv.mainStageDelegate = appDelegate;
2231+ priv.mainStageItemId = root.topLevelSurfaceList.idAt(i);
2232+ priv.mainStageAppId = root.topLevelSurfaceList.applicationAt(i).appId;
2233+ choseMainStage = true;
2234+ }
2235+ }
2236+ if (!choseMainStage && priv.mainStageDelegate) {
2237+ priv.mainStageDelegate = null;
2238+ priv.mainStageItemId = 0;
2239+ priv.mainStageAppId = "";
2240+ }
2241+ if (!choseSideStage && priv.sideStageDelegate) {
2242+ priv.sideStageDelegate = null;
2243+ priv.sideStageItemId = 0;
2244+ priv.sideStageAppId = "";
2245+ }
2246+ }
2247+
2248+ property int nextInStack: {
2249+ var mainStageIndex = priv.mainStageDelegate ? priv.mainStageDelegate.itemIndex : -1;
2250+ var sideStageIndex = priv.sideStageDelegate ? priv.sideStageDelegate.itemIndex : -1;
2251+ if (sideStageIndex == -1) {
2252+ return topLevelSurfaceList.count > 1 ? 1 : -1;
2253+ }
2254+ if (mainStageIndex == 0 || sideStageIndex == 0) {
2255+ if (mainStageIndex == 1 || sideStageIndex == 1) {
2256+ return topLevelSurfaceList.count > 2 ? 2 : -1;
2257+ }
2258+ return 1;
2259+ }
2260+ return -1;
2261+ }
2262+
2263+ readonly property real virtualKeyboardHeight: root.inputMethodRect.height
2264 }
2265
2266+ Component.onCompleted: priv.updateMainAndSideStageIndexes();
2267+
2268 Connections {
2269 target: PanelState
2270 onCloseClicked: { if (priv.focusedAppDelegate) { priv.focusedAppDelegate.close(); } }
2271@@ -178,14 +319,13 @@
2272 target: PanelState
2273 property: "buttonsVisible"
2274 value: priv.focusedAppDelegate !== null && priv.focusedAppDelegate.maximized // FIXME for Locally integrated menus
2275- && spread.state == ""
2276 }
2277
2278 Binding {
2279 target: PanelState
2280 property: "title"
2281 value: {
2282- if (priv.focusedAppDelegate !== null && spread.state == "") {
2283+ if (priv.focusedAppDelegate !== null) {
2284 if (priv.focusedAppDelegate.maximized)
2285 return priv.focusedAppDelegate.title
2286 else
2287@@ -199,7 +339,7 @@
2288 Binding {
2289 target: PanelState
2290 property: "dropShadow"
2291- value: priv.focusedAppDelegate && !priv.focusedAppDelegate.maximized && priv.foregroundMaximizedAppDelegate !== null
2292+ value: priv.focusedAppDelegate && !priv.focusedAppDelegate.maximized && priv.foregroundMaximizedAppDelegate !== null && mode == "windowed"
2293 }
2294
2295 Binding {
2296@@ -216,16 +356,34 @@
2297
2298 Instantiator {
2299 model: root.applicationManager
2300- delegate: Binding {
2301- target: model.application
2302- property: "requestedState"
2303-
2304- // TODO: figure out some lifecycle policy, like suspending minimized apps
2305- // if running on a tablet or something.
2306- // TODO: If the device has a dozen suspended apps because it was running
2307- // in staged mode, when it switches to Windowed mode it will suddenly
2308- // resume all those apps at once. We might want to avoid that.
2309- value: ApplicationInfoInterface.RequestedRunning // Always running for now
2310+ delegate: QtObject {
2311+ property var stateBinding: Binding {
2312+ readonly property bool isDash: model.application ? model.application.appId == "unity8-dash" : false
2313+ target: model.application
2314+ property: "requestedState"
2315+
2316+ // TODO: figure out some lifecycle policy, like suspending minimized apps
2317+ // or something if running windowed.
2318+ // TODO: If the device has a dozen suspended apps because it was running
2319+ // in staged mode, when it switches to Windowed mode it will suddenly
2320+ // resume all those apps at once. We might want to avoid that.
2321+ value: root.mode === "windowed"
2322+ || (isDash && root.keepDashRunning)
2323+ || (!root.suspended && model.application && priv.focusedAppDelegate &&
2324+ (priv.focusedAppDelegate.appId === model.application.appId ||
2325+ priv.mainStageAppId === model.application.appId ||
2326+ priv.sideStageAppId === model.application.appId))
2327+ ? ApplicationInfoInterface.RequestedRunning
2328+ : ApplicationInfoInterface.RequestedSuspended
2329+ }
2330+
2331+ property var lifecycleBinding: Binding {
2332+ target: model.application
2333+ property: "exemptFromLifecycle"
2334+ value: model.application
2335+ ? (!model.application.isTouchApp || isExemptFromLifecycle(model.application.appId))
2336+ : false
2337+ }
2338 }
2339 }
2340
2341@@ -236,16 +394,203 @@
2342 when: !appRepeater.startingUp && root.parent
2343 }
2344
2345+ states: [
2346+ State {
2347+ name: "spread"; when: priv.goneToSpread
2348+ PropertyChanges { target: floatingFlickable; enabled: true }
2349+ PropertyChanges { target: spreadItem; focus: true }
2350+ PropertyChanges { target: hoverMouseArea; enabled: true }
2351+ PropertyChanges { target: rightEdgeDragArea; enabled: false }
2352+ PropertyChanges { target: cancelSpreadMouseArea; enabled: true }
2353+ },
2354+ State {
2355+ name: "stagedRightEdge"; when: (rightEdgeDragArea.dragging || edgeBarrier.progress > 0) && root.mode == "staged"
2356+ },
2357+ State {
2358+ name: "sideStagedRightEdge"; when: (rightEdgeDragArea.dragging || edgeBarrier.progress > 0) && root.mode == "stagedWithSideStage"
2359+ PropertyChanges {
2360+ target: sideStage
2361+ opacity: priv.sideStageDelegate.x === sideStage.x ? 1 : 0
2362+ visible: true
2363+ }
2364+ },
2365+ State {
2366+ name: "windowedRightEdge"; when: (rightEdgeDragArea.dragging || edgeBarrier.progress > 0) && root.mode == "windowed"
2367+ },
2368+ State {
2369+ name: "staged"; when: root.mode === "staged"
2370+ },
2371+ State {
2372+ name: "stagedWithSideStage"; when: root.mode === "stagedWithSideStage"
2373+ PropertyChanges { target: triGestureArea; enabled: true }
2374+ PropertyChanges { target: sideStage; visible: true }
2375+ },
2376+ State {
2377+ name: "windowed"; when: root.mode === "windowed"
2378+ }
2379+ ]
2380+ transitions: [
2381+ Transition {
2382+ from: "stagedRightEdge,sideStagedRightEdge,windowedRightEdge"; to: "spread"
2383+ PropertyAction { target: spreadItem; property: "highlightedIndex"; value: -1 }
2384+ },
2385+ Transition {
2386+ to: "spread"
2387+ PropertyAction { target: spreadItem; property: "highlightedIndex"; value: appRepeater.count > 1 ? 1 : 0 }
2388+ PropertyAction { target: floatingFlickable; property: "contentX"; value: 0 }
2389+ },
2390+ Transition {
2391+ from: "spread"
2392+ SequentialAnimation {
2393+ ScriptAction {
2394+ script: {
2395+ var item = appRepeater.itemAt(Math.max(0, spreadItem.highlightedIndex));
2396+ if (item.stage == ApplicationInfoInterface.SideStage && !sideStage.shown) {
2397+ sideStage.show();
2398+ }
2399+ item.playFocusAnimation();
2400+ }
2401+ }
2402+ PropertyAction { target: spreadItem; property: "highlightedIndex"; value: -1 }
2403+ }
2404+ },
2405+ Transition {
2406+ to: "stagedRightEdge"
2407+ PropertyAction { target: floatingFlickable; property: "contentX"; value: 0 }
2408+ },
2409+ Transition {
2410+ to: "stagedWithSideStage"
2411+ ScriptAction { script: priv.updateMainAndSideStageIndexes(); }
2412+ }
2413+
2414+ ]
2415+
2416+ MouseArea {
2417+ id: cancelSpreadMouseArea
2418+ anchors.fill: parent
2419+ enabled: false
2420+ onClicked: priv.goneToSpread = false
2421+ }
2422+
2423 FocusScope {
2424 id: appContainer
2425 objectName: "appContainer"
2426 anchors.fill: parent
2427- focus: spread.state !== "altTab"
2428+ focus: true
2429
2430 Wallpaper {
2431 id: wallpaper
2432 anchors.fill: parent
2433 source: root.background
2434+ // Make sure it's the lowest item. Due to the left edge drag we sometimes need
2435+ // to put the dash at -1 and we don't want it behind the Wallpaper
2436+ z: -2
2437+ }
2438+
2439+ Spread {
2440+ id: spreadItem
2441+ objectName: "spreadItem"
2442+ anchors.fill: appContainer
2443+ leftMargin: root.leftMargin
2444+ model: root.topLevelSurfaceList
2445+ spreadFlickable: floatingFlickable
2446+ z: 10
2447+
2448+ onLeaveSpread: {
2449+ priv.goneToSpread = false;
2450+ }
2451+ }
2452+
2453+ Connections {
2454+ target: root.topLevelSurfaceList
2455+ onListChanged: priv.updateMainAndSideStageIndexes()
2456+ }
2457+
2458+
2459+ DropArea {
2460+ objectName: "MainStageDropArea"
2461+ anchors {
2462+ left: parent.left
2463+ top: parent.top
2464+ bottom: parent.bottom
2465+ }
2466+ width: appContainer.width - sideStage.width
2467+ enabled: sideStage.enabled
2468+
2469+ onDropped: {
2470+ drop.source.appDelegate.saveStage(ApplicationInfoInterface.MainStage);
2471+ drop.source.appDelegate.focus = true;
2472+ }
2473+ keys: "SideStage"
2474+ }
2475+
2476+ SideStage {
2477+ id: sideStage
2478+ objectName: "sideStage"
2479+ shown: false
2480+ height: appContainer.height
2481+ x: appContainer.width - width
2482+ visible: false
2483+ Behavior on opacity { UbuntuNumberAnimation {} }
2484+ z: {
2485+ if (!priv.mainStageItemId) return 0;
2486+
2487+ if (priv.sideStageItemId && priv.nextInStack > 0) {
2488+
2489+ // Due the order in which bindings are evaluated, this might be triggered while shuffling
2490+ // the list and index doesn't yet match with itemIndex (even though itemIndex: index)
2491+ // Let's walk the list and compare itemIndex to make sure we have the correct one.
2492+ var nextDelegateInStack = -1;
2493+ for (var i = 0; i < appRepeater.count; i++) {
2494+ if (appRepeater.itemAt(i).itemIndex == priv.nextInStack) {
2495+ nextDelegateInStack = appRepeater.itemAt(i);
2496+ break;
2497+ }
2498+ }
2499+
2500+ if (nextDelegateInStack.stage === ApplicationInfoInterface.MainStage) {
2501+ // if the next app in stack is a main stage app, put the sidestage on top of it.
2502+ return 2;
2503+ }
2504+ return 1;
2505+ }
2506+
2507+ return 1;
2508+ }
2509+
2510+ onShownChanged: {
2511+ if (!shown && priv.mainStageDelegate) {
2512+ priv.mainStageDelegate.claimFocus();
2513+ }
2514+ }
2515+
2516+ DropArea {
2517+ id: sideStageDropArea
2518+ objectName: "SideStageDropArea"
2519+ anchors.fill: parent
2520+
2521+ property bool dropAllowed: true
2522+
2523+ onEntered: {
2524+ dropAllowed = drag.keys != "Disabled";
2525+ }
2526+ onExited: {
2527+ dropAllowed = true;
2528+ }
2529+ onDropped: {
2530+ if (drop.keys == "MainStage") {
2531+ drop.source.appDelegate.saveStage(ApplicationInfoInterface.SideStage);
2532+ drop.source.appDelegate.focus = true;
2533+ }
2534+ }
2535+ drag {
2536+ onSourceChanged: {
2537+ if (!sideStageDropArea.drag.source) {
2538+ dropAllowed = true;
2539+ }
2540+ }
2541+ }
2542+ }
2543 }
2544
2545 TopLevelSurfaceRepeater {
2546@@ -256,6 +601,7 @@
2547 delegate: FocusScope {
2548 id: appDelegate
2549 objectName: "appDelegate_" + model.id
2550+ property int itemIndex: index // We need this from outside the repeater
2551 // z might be overriden in some cases by effects, but we need z ordering
2552 // to calculate occlusion detection
2553 property int normalZ: topLevelSurfaceList.count - index
2554@@ -265,10 +611,33 @@
2555 }
2556 }
2557 z: normalZ
2558- x: requestedX // may be overridden in some states. Do not directly write to this.
2559- y: requestedY // may be overridden in some states. Do not directly write to this.
2560- property real requestedX: priv.focusedAppDelegate ? priv.focusedAppDelegate.x + units.gu(3) : (normalZ - 1) * units.gu(3)
2561- property real requestedY: priv.focusedAppDelegate ? priv.focusedAppDelegate.y + units.gu(3) : normalZ * units.gu(3)
2562+
2563+ // Normally we want x/y where we request it to be. Width/height of our delegate will
2564+ // match what the actual surface size is.
2565+ // Don't write to those, they will be set by states
2566+ x: requestedX
2567+ y: requestedY
2568+ width: decoratedWindow.implicitWidth
2569+ height: decoratedWindow.implicitHeight
2570+
2571+ // requestedX/Y/width/height is what we ask the actual surface to be.
2572+ // Do not write to those, they will be set by states
2573+ property real requestedX: windowedX
2574+ property real requestedY: windowedY
2575+ property real requestedWidth: windowedWidth
2576+ property real requestedHeight: windowedHeight
2577+
2578+ // In those are for windowed mode. Those values basically store the window's properties
2579+ // when having a floating window. If you want to move/resize a window in normal mode, this is what you want to write to.
2580+ property real windowedX
2581+ property real windowedY
2582+ property real windowedWidth
2583+ property real windowedHeight
2584+
2585+ // unlike windowedX/Y, this is the last known grab position before being pushed against edges/corners
2586+ // when restoring, the window should return to these, not to the place where it was dropped near the edge
2587+ property real restoredX
2588+ property real restoredY
2589
2590 Binding {
2591 target: appDelegate
2592@@ -277,27 +646,24 @@
2593 Math.min(appDelegate.requestedY - PanelState.panelHeight,
2594 Math.max(0, priv.virtualKeyboardHeight - (appContainer.height - (appDelegate.requestedY + appDelegate.height))))
2595 when: root.oskEnabled && appDelegate.focus && (appDelegate.state == "normal" || appDelegate.state == "restored")
2596- && SurfaceManager.inputMethodSurface
2597- && SurfaceManager.inputMethodSurface.state != Mir.HiddenState
2598- && SurfaceManager.inputMethodSurface.state != Mir.MinimizedState
2599+ && root.inputMethodRect.height > 0
2600
2601 }
2602
2603- width: decoratedWindow.width
2604- height: decoratedWindow.height
2605+ Behavior on x { id: xBehavior; enabled: priv.closingIndex >= 0; UbuntuNumberAnimation { onRunningChanged: if (!running) priv.closingIndex = -1} }
2606
2607 Connections {
2608 target: root
2609 onShellOrientationAngleChanged: {
2610 // at this point decoratedWindow.surfaceOrientationAngle is the old shellOrientationAngle
2611 if (application && application.rotatesWindowContents) {
2612- if (state == "normal" || state == "restored") {
2613+ if (root.state == "windowed") {
2614 var angleDiff = decoratedWindow.surfaceOrientationAngle - shellOrientationAngle;
2615 angleDiff = (360 + angleDiff) % 360;
2616 if (angleDiff === 90 || angleDiff === 270) {
2617 var aux = decoratedWindow.requestedHeight;
2618- decoratedWindow.requestedHeight = decoratedWindow.requestedWidth + decoratedWindow.visibleDecorationHeight;
2619- decoratedWindow.requestedWidth = aux - decoratedWindow.visibleDecorationHeight;
2620+ decoratedWindow.requestedHeight = decoratedWindow.requestedWidth + decoratedWindow.decorationHeight;
2621+ decoratedWindow.requestedWidth = aux - decoratedWindow.decorationHeight;
2622 }
2623 }
2624 decoratedWindow.surfaceOrientationAngle = shellOrientationAngle;
2625@@ -306,6 +672,10 @@
2626 }
2627 }
2628 }
2629+ Connections {
2630+ target: priv
2631+ onSideStageEnabledChanged: refreshStage()
2632+ }
2633
2634 readonly property alias application: decoratedWindow.application
2635 readonly property alias minimumWidth: decoratedWindow.minimumWidth
2636@@ -314,8 +684,6 @@
2637 readonly property alias maximumHeight: decoratedWindow.maximumHeight
2638 readonly property alias widthIncrement: decoratedWindow.widthIncrement
2639 readonly property alias heightIncrement: decoratedWindow.heightIncrement
2640- property int requestedWidth: -1
2641- property int requestedHeight: -1
2642
2643 readonly property bool maximized: windowState === WindowStateStorage.WindowStateMaximized
2644 readonly property bool maximizedLeft: windowState === WindowStateStorage.WindowStateMaximizedLeft
2645@@ -330,7 +698,7 @@
2646 maximizedTopLeft || maximizedTopRight || maximizedBottomLeft || maximizedBottomRight
2647
2648 readonly property bool minimized: windowState & WindowStateStorage.WindowStateMinimized
2649- readonly property alias fullscreen: decoratedWindow.fullscreen
2650+ readonly property bool fullscreen: surface ? surface.state === Mir.FullscreenState : application.fullscreen
2651
2652 readonly property bool canBeMaximized: canBeMaximizedHorizontally && canBeMaximizedVertically
2653 readonly property bool canBeMaximizedLeftRight: (maximumWidth == 0 || maximumWidth >= appContainer.width/2) &&
2654@@ -339,6 +707,7 @@
2655 (maximumHeight == 0 || maximumHeight >= appContainer.height/2)
2656 readonly property bool canBeMaximizedHorizontally: maximumWidth == 0 || maximumWidth >= appContainer.width
2657 readonly property bool canBeMaximizedVertically: maximumHeight == 0 || maximumHeight >= appContainer.height
2658+ readonly property alias orientationChangesEnabled: decoratedWindow.orientationChangesEnabled
2659
2660 property int windowState: WindowStateStorage.WindowStateNormal
2661 property bool animationsEnabled: true
2662@@ -347,23 +716,45 @@
2663 property bool visuallyMaximized: false
2664 property bool visuallyMinimized: false
2665
2666+ property int stage: ApplicationInfoInterface.MainStage
2667+ function saveStage(newStage) {
2668+ appDelegate.stage = newStage;
2669+ WindowStateStorage.saveStage(appId, newStage);
2670+ priv.updateMainAndSideStageIndexes()
2671+ }
2672+
2673 readonly property var surface: model.surface
2674 readonly property alias resizeArea: resizeArea
2675 readonly property alias focusedSurface: decoratedWindow.focusedSurface
2676 readonly property bool dragging: touchControls.overlayShown ? touchControls.dragging : decoratedWindow.dragging
2677
2678- readonly property bool isDash: model.application.appId == "unity8-dash"
2679+ readonly property string appId: model.application.appId
2680+ readonly property bool isDash: appId == "unity8-dash"
2681 readonly property alias clientAreaItem: decoratedWindow.clientAreaItem
2682
2683 function claimFocus() {
2684- if (spread.state == "altTab") {
2685- spread.cancel();
2686- }
2687- appDelegate.restore(true /* animated */, appDelegate.windowState);
2688+ if (root.state == "spread") {
2689+ spreadItem.highlightedIndex = index
2690+ priv.goneToSpread = false;
2691+ }
2692+ if (root.mode == "stagedWithSideStage") {
2693+ if (appDelegate.stage == ApplicationInfoInterface.SideStage && !sideStage.shown) {
2694+ sideStage.show();
2695+ }
2696+ priv.updateMainAndSideStageIndexes();
2697+ }
2698+
2699+ if (root.mode == "windowed") {
2700+ appDelegate.restore(true /* animated */, appDelegate.windowState);
2701+ } else {
2702+ appDelegate.focus = true;
2703+ }
2704 }
2705 Connections {
2706 target: model.surface
2707- onFocusRequested: claimFocus();
2708+ onFocusRequested: {
2709+ claimFocus();
2710+ }
2711 }
2712 Connections {
2713 target: model.application
2714@@ -383,14 +774,9 @@
2715 return;
2716
2717 if (focus) {
2718- // If we're orphan (!parent) it means this stage is no longer the current one
2719- // and will be deleted shortly. So we should no longer have a say over the model
2720- if (root.parent) {
2721- topLevelSurfaceList.raiseId(model.id);
2722- }
2723-
2724+ topLevelSurfaceList.raiseId(model.id);
2725 priv.focusedAppDelegate = appDelegate;
2726- } else if (!focus && priv.focusedAppDelegate === appDelegate) {
2727+ } else if (!focus && priv.focusedAppDelegate === appDelegate && root.state != "spread") {
2728 priv.focusedAppDelegate = null;
2729 // FIXME: No idea why the Binding{} doens't update when focusedAppDelegate turns null
2730 MirFocusController.focusedSurface = null;
2731@@ -403,13 +789,25 @@
2732 decoratedWindow.surfaceOrientationAngle = 0;
2733 }
2734
2735+ // First, cascade the newly created window, relative to the currently/old focused window.
2736+ windowedX = priv.focusedAppDelegate ? priv.focusedAppDelegate.windowedX + units.gu(3) : (normalZ - 1) * units.gu(3)
2737+ windowedY = priv.focusedAppDelegate ? priv.focusedAppDelegate.windowedY + units.gu(3) : normalZ * units.gu(3)
2738+ // Now load any saved state. This needs to happen *after* the cascading!
2739+ resizeArea.loadWindowState();
2740+
2741 // NB: We're differentiating if this delegate was created in response to a new entry in the model
2742 // or if the Repeater is just populating itself with delegates to match the model it received.
2743 if (!appRepeater.startingUp) {
2744 // a top level window is always the focused one when it first appears, unfocusing
2745 // any preexisting one
2746- focus = true;
2747+ if (root.state == "spread") {
2748+ spreadItem.highlightedIndex = index;
2749+ }
2750+ claimFocus();
2751 }
2752+
2753+ refreshStage();
2754+ _constructing = false;
2755 }
2756 Component.onDestruction: {
2757 if (!root.parent) {
2758@@ -435,13 +833,20 @@
2759
2760 onVisuallyMaximizedChanged: priv.updateForegroundMaximizedApp()
2761
2762+ property bool _constructing: true;
2763+ onStageChanged: {
2764+ if (!_constructing) {
2765+ priv.updateMainAndSideStageIndexes();
2766+ }
2767+ }
2768+
2769 visible: (
2770 !visuallyMinimized
2771 && !greeter.fullyShown
2772 && (priv.foregroundMaximizedAppDelegate === null || priv.foregroundMaximizedAppDelegate.normalZ <= z)
2773 )
2774- || decoratedWindow.fullscreen
2775- || (spread.state == "altTab" && index === spread.highlightedIndex)
2776+ || appDelegate.fullscreen
2777+ || focusAnimation.running || rightEdgeFocusAnimation.running || hidingAnimation.running
2778
2779 function close() {
2780 model.surface.close();
2781@@ -499,7 +904,44 @@
2782 }
2783
2784 function playFocusAnimation() {
2785- focusAnimation.start()
2786+ if (state == "stagedRightEdge") {
2787+ // TODO: Can we drop this if and find something that always works?
2788+ if (root.mode == "staged") {
2789+ rightEdgeFocusAnimation.targetX = 0
2790+ rightEdgeFocusAnimation.start()
2791+ } else if (root.mode == "stagedWithSideStage") {
2792+ rightEdgeFocusAnimation.targetX = appDelegate.stage == ApplicationInfoInterface.SideStage ? sideStage.x : 0
2793+ rightEdgeFocusAnimation.start()
2794+ }
2795+ } else if (state == "windowedRightEdge") {
2796+ claimFocus();
2797+ } else {
2798+ focusAnimation.start()
2799+ }
2800+ }
2801+ function playHidingAnimation() {
2802+ if (state != "windowedRightEdge") {
2803+ hidingAnimation.start()
2804+ }
2805+ }
2806+
2807+ function refreshStage() {
2808+ var newStage = ApplicationInfoInterface.MainStage;
2809+ if (priv.sideStageEnabled) { // we're in lanscape rotation.
2810+ if (!isDash && application && application.supportedOrientations & (Qt.PortraitOrientation|Qt.InvertedPortraitOrientation)) {
2811+ var defaultStage = ApplicationInfoInterface.SideStage; // if application supports portrait, it defaults to sidestage.
2812+ if (application.supportedOrientations & (Qt.LandscapeOrientation|Qt.InvertedLandscapeOrientation)) {
2813+ // if it supports lanscape, it defaults to mainstage.
2814+ defaultStage = ApplicationInfoInterface.MainStage;
2815+ }
2816+ newStage = WindowStateStorage.getStage(application.appId, defaultStage);
2817+ }
2818+ }
2819+
2820+ stage = newStage;
2821+ if (focus && stage == ApplicationInfoInterface.SideStage && !sideStage.shown) {
2822+ sideStage.show();
2823+ }
2824 }
2825
2826 UbuntuNumberAnimation {
2827@@ -509,32 +951,255 @@
2828 from: 0.98
2829 to: 1
2830 duration: UbuntuAnimation.SnapDuration
2831- }
2832-
2833- // unlike requestedX/Y, this is the last known grab position before being pushed against edges/corners
2834- // when restoring, the window should return to these, not to the place where it was dropped near the edge
2835- property real restoredX
2836- property real restoredY
2837+ onStarted: {
2838+ topLevelSurfaceList.raiseId(model.id);
2839+ }
2840+ onStopped: {
2841+ appDelegate.claimFocus();
2842+ }
2843+ }
2844+ ParallelAnimation {
2845+ id: rightEdgeFocusAnimation
2846+ property int targetX: 0
2847+ UbuntuNumberAnimation { target: appDelegate; properties: "x"; to: rightEdgeFocusAnimation.targetX; duration: priv.animationDuration }
2848+ UbuntuNumberAnimation { target: decoratedWindow; properties: "angle"; to: 0; duration: priv.animationDuration }
2849+ UbuntuNumberAnimation { target: decoratedWindow; properties: "itemScale"; to: 1; duration: priv.animationDuration }
2850+ onStopped: {
2851+ appDelegate.focus = true
2852+ }
2853+ }
2854+ ParallelAnimation {
2855+ id: hidingAnimation
2856+ UbuntuNumberAnimation { target: appDelegate; property: "opacity"; to: 0; duration: priv.animationDuration }
2857+ onStopped: appDelegate.opacity = 1
2858+ }
2859+
2860+ SpreadMaths {
2861+ id: spreadMaths
2862+ spread: spreadItem
2863+ itemIndex: index
2864+ flickable: floatingFlickable
2865+ }
2866+ StageMaths {
2867+ id: stageMaths
2868+ sceneWidth: root.width
2869+ stage: appDelegate.stage
2870+ thisDelegate: appDelegate
2871+ mainStageDelegate: priv.mainStageDelegate
2872+ sideStageDelegate: priv.sideStageDelegate
2873+ sideStageWidth: sideStage.panelWidth
2874+ sideStageX: sideStage.x
2875+ itemIndex: appDelegate.itemIndex
2876+ nextInStack: priv.nextInStack
2877+ leftEdgeDragProgress: root.leftEdgeDragProgress
2878+ }
2879+
2880+ StagedRightEdgeMaths {
2881+ id: stagedRightEdgeMaths
2882+ sceneWidth: appContainer.width - root.leftMargin
2883+ sceneHeight: appContainer.height
2884+ isMainStageApp: priv.mainStageDelegate == appDelegate
2885+ isSideStageApp: priv.sideStageDelegate == appDelegate
2886+ sideStageWidth: sideStage.width
2887+ sideStageOpen: sideStage.shown
2888+ itemIndex: index
2889+ nextInStack: priv.nextInStack
2890+ progress: 0
2891+ targetHeight: spreadItem.stackHeight
2892+ targetX: spreadMaths.targetX
2893+ startY: appDelegate.fullscreen ? 0 : PanelState.panelHeight
2894+ targetY: spreadMaths.targetY
2895+ targetAngle: spreadMaths.targetAngle
2896+ targetScale: spreadMaths.targetScale
2897+ shuffledZ: stageMaths.itemZ
2898+ breakPoint: spreadItem.rightEdgeBreakPoint
2899+ }
2900+
2901+ WindowedRightEdgeMaths {
2902+ id: windowedRightEdgeMaths
2903+ itemIndex: index
2904+ startWidth: appDelegate.requestedWidth
2905+ startHeight: appDelegate.requestedHeight
2906+ targetHeight: spreadItem.stackHeight
2907+ targetX: spreadMaths.targetX
2908+ targetY: spreadMaths.targetY
2909+ normalZ: appDelegate.normalZ
2910+ targetAngle: spreadMaths.targetAngle
2911+ targetScale: spreadMaths.targetScale
2912+ breakPoint: spreadItem.rightEdgeBreakPoint
2913+ }
2914
2915 states: [
2916 State {
2917+ name: "spread"; when: root.state == "spread"
2918+ PropertyChanges {
2919+ target: decoratedWindow;
2920+ showDecoration: false;
2921+ angle: spreadMaths.targetAngle
2922+ itemScale: spreadMaths.targetScale
2923+ scaleToPreviewSize: spreadItem.stackHeight
2924+ scaleToPreviewProgress: 1
2925+ hasDecoration: root.mode === "windowed"
2926+ shadowOpacity: spreadMaths.shadowOpacity
2927+ showHighlight: spreadItem.highlightedIndex === index
2928+ darkening: spreadItem.highlightedIndex >= 0
2929+ anchors.topMargin: dragArea.distance
2930+ }
2931+ PropertyChanges {
2932+ target: appDelegate
2933+ x: spreadMaths.targetX
2934+ y: spreadMaths.targetY
2935+ z: index
2936+ height: spreadItem.spreadItemHeight
2937+ requestedWidth: decoratedWindow.oldRequestedWidth
2938+ requestedHeight: decoratedWindow.oldRequestedHeight
2939+ visible: spreadMaths.itemVisible
2940+ }
2941+ PropertyChanges { target: dragArea; enabled: true }
2942+ PropertyChanges { target: windowInfoItem; opacity: spreadMaths.tileInfoOpacity; visible: spreadMaths.itemVisible }
2943+ },
2944+ State {
2945+ name: "stagedRightEdge"
2946+ when: (root.mode == "staged" || root.mode == "stagedWithSideStage") && (root.state == "sideStagedRightEdge" || root.state == "stagedRightEdge" || rightEdgeFocusAnimation.running || hidingAnimation.running)
2947+ PropertyChanges {
2948+ target: stagedRightEdgeMaths
2949+ progress: Math.max(edgeBarrier.progress, rightEdgeDragArea.draggedProgress)
2950+ }
2951+ PropertyChanges {
2952+ target: appDelegate
2953+ x: stagedRightEdgeMaths.animatedX
2954+ y: stagedRightEdgeMaths.animatedY
2955+ z: stagedRightEdgeMaths.animatedZ
2956+ height: stagedRightEdgeMaths.animatedHeight
2957+ requestedWidth: decoratedWindow.oldRequestedWidth
2958+ requestedHeight: decoratedWindow.oldRequestedHeight
2959+ visible: appDelegate.x < root.width
2960+ }
2961+ PropertyChanges {
2962+ target: decoratedWindow
2963+ hasDecoration: false
2964+ angle: stagedRightEdgeMaths.animatedAngle
2965+ itemScale: stagedRightEdgeMaths.animatedScale
2966+ scaleToPreviewSize: spreadItem.stackHeight
2967+ scaleToPreviewProgress: stagedRightEdgeMaths.scaleToPreviewProgress
2968+ shadowOpacity: .3
2969+ }
2970+ },
2971+ State {
2972+ name: "windowedRightEdge"
2973+ when: root.mode == "windowed" && (root.state == "windowedRightEdge" || rightEdgeFocusAnimation.running || hidingAnimation.running || edgeBarrier.progress > 0)
2974+ PropertyChanges {
2975+ target: windowedRightEdgeMaths
2976+ progress: Math.max(rightEdgeDragArea.progress, edgeBarrier.progress)
2977+ }
2978+ PropertyChanges {
2979+ target: appDelegate
2980+ x: windowedRightEdgeMaths.animatedX
2981+ y: windowedRightEdgeMaths.animatedY
2982+ z: windowedRightEdgeMaths.animatedZ
2983+ height: stagedRightEdgeMaths.animatedHeight
2984+ requestedWidth: decoratedWindow.oldRequestedWidth
2985+ requestedHeight: decoratedWindow.oldRequestedHeight
2986+ }
2987+ PropertyChanges {
2988+ target: decoratedWindow
2989+ showDecoration: windowedRightEdgeMaths.decorationHeight
2990+ angle: windowedRightEdgeMaths.animatedAngle
2991+ itemScale: windowedRightEdgeMaths.animatedScale
2992+ scaleToPreviewSize: spreadItem.stackHeight
2993+ scaleToPreviewProgress: windowedRightEdgeMaths.scaleToPreviewProgress
2994+ shadowOpacity: .3
2995+ }
2996+ PropertyChanges {
2997+ target: opacityEffect;
2998+ opacityValue: windowedRightEdgeMaths.opacityMask
2999+ sourceItem: windowedRightEdgeMaths.opacityMask < 1 ? decoratedWindow : null
3000+ }
3001+ },
3002+ State {
3003+ name: "staged"; when: root.state == "staged"
3004+ PropertyChanges {
3005+ target: appDelegate
3006+ x: stageMaths.itemX
3007+ y: appDelegate.fullscreen ? 0 : PanelState.panelHeight
3008+ requestedWidth: appContainer.width
3009+ requestedHeight: appDelegate.fullscreen ? appContainer.height : appContainer.height - PanelState.panelHeight
3010+ visuallyMaximized: true
3011+ visible: appDelegate.x < root.width
3012+ }
3013+ PropertyChanges {
3014+ target: decoratedWindow
3015+ hasDecoration: false
3016+ }
3017+ PropertyChanges {
3018+ target: resizeArea
3019+ enabled: false
3020+ }
3021+ PropertyChanges {
3022+ target: stageMaths
3023+ animateX: !focusAnimation.running && itemIndex !== spreadItem.highlightedIndex
3024+ }
3025+ },
3026+ State {
3027+ name: "stagedWithSideStage"; when: root.state == "stagedWithSideStage"
3028+ PropertyChanges {
3029+ target: stageMaths
3030+ itemIndex: index
3031+ }
3032+ PropertyChanges {
3033+ target: appDelegate
3034+ x: stageMaths.itemX
3035+ y: appDelegate.fullscreen ? 0 : PanelState.panelHeight
3036+ z: stageMaths.itemZ
3037+ requestedWidth: stageMaths.itemWidth
3038+ requestedHeight: appDelegate.fullscreen ? appContainer.height : appContainer.height - PanelState.panelHeight
3039+ visuallyMaximized: true
3040+ visible: appDelegate.x < root.width
3041+ }
3042+ PropertyChanges {
3043+ target: decoratedWindow
3044+ hasDecoration: false
3045+ }
3046+ PropertyChanges {
3047+ target: resizeArea
3048+ enabled: false
3049+ }
3050+ },
3051+ State {
3052+ name: "maximized"; when: appDelegate.windowState == WindowStateStorage.WindowStateMaximized
3053+ PropertyChanges {
3054+ target: appDelegate;
3055+ requestedX: root.leftMargin;
3056+ requestedY: 0;
3057+ visuallyMinimized: false;
3058+ visuallyMaximized: true
3059+ requestedWidth: appContainer.width - root.leftMargin;
3060+ requestedHeight: appContainer.height;
3061+ }
3062+ PropertyChanges { target: touchControls; enabled: true }
3063+ },
3064+ State {
3065 name: "fullscreen"; when: appDelegate.fullscreen && !appDelegate.minimized
3066 PropertyChanges {
3067 target: appDelegate;
3068- x: rotation == 0 ? 0 : (parent.width - width) / 2 + (shellOrientationAngle == 90 ? -PanelState.panelHeight : PanelState.panelHeight)
3069- y: rotation == 0 ? -PanelState.panelHeight : (parent.height - height) / 2
3070+ requestedX: 0
3071+ requestedY: 0
3072 requestedWidth: appContainer.width;
3073 requestedHeight: appContainer.height;
3074 }
3075+ PropertyChanges { target: decoratedWindow; hasDecoration: false }
3076 },
3077 State {
3078 name: "normal";
3079 when: appDelegate.windowState == WindowStateStorage.WindowStateNormal
3080 PropertyChanges {
3081- target: appDelegate;
3082- visuallyMinimized: false;
3083+ target: appDelegate
3084+ visuallyMinimized: false
3085 visuallyMaximized: false
3086 }
3087+ PropertyChanges { target: touchControls; enabled: true }
3088+ PropertyChanges { target: resizeArea; enabled: true }
3089+ PropertyChanges { target: decoratedWindow; shadowOpacity: .3}
3090 },
3091 State {
3092 name: "restored";
3093@@ -542,30 +1207,25 @@
3094 extend: "normal"
3095 PropertyChanges {
3096 target: appDelegate;
3097- requestedX: restoredX;
3098- requestedY: restoredY;
3099+ windowedX: restoredX;
3100+ windowedY: restoredY;
3101 }
3102 },
3103 State {
3104- name: "maximized"; when: appDelegate.maximized && !appDelegate.minimized
3105- PropertyChanges {
3106- target: appDelegate;
3107- requestedX: root.leftMargin;
3108- requestedY: 0;
3109- requestedWidth: appContainer.width - root.leftMargin;
3110- requestedHeight: appContainer.height;
3111- visuallyMinimized: false;
3112- visuallyMaximized: true
3113- }
3114+ name: "semiMaximized"
3115+ PropertyChanges { target: touchControls; enabled: true }
3116+ PropertyChanges { target: resizeArea; enabled: true }
3117+ PropertyChanges { target: decoratedWindow; shadowOpacity: .3 }
3118 },
3119 State {
3120 name: "maximizedLeft"; when: appDelegate.maximizedLeft && !appDelegate.minimized
3121+ extend: "semiMaximized"
3122 PropertyChanges {
3123 target: appDelegate
3124- requestedX: root.leftMargin
3125- requestedY: PanelState.panelHeight
3126- requestedWidth: (appContainer.width - root.leftMargin)/2
3127- requestedHeight: appContainer.height - PanelState.panelHeight
3128+ windowedX: root.leftMargin
3129+ windowedY: PanelState.panelHeight
3130+ windowedWidth: (appContainer.width - root.leftMargin)/2
3131+ windowedHeight: appContainer.height - PanelState.panelHeight
3132 }
3133 },
3134 State {
3135@@ -573,17 +1233,18 @@
3136 extend: "maximizedLeft"
3137 PropertyChanges {
3138 target: appDelegate;
3139- requestedX: (appContainer.width + root.leftMargin)/2
3140+ windowedX: (appContainer.width + root.leftMargin)/2
3141 }
3142 },
3143 State {
3144 name: "maximizedTopLeft"; when: appDelegate.maximizedTopLeft && !appDelegate.minimized
3145+ extend: "semiMaximized"
3146 PropertyChanges {
3147 target: appDelegate
3148- requestedX: root.leftMargin
3149- requestedY: PanelState.panelHeight
3150- requestedWidth: (appContainer.width - root.leftMargin)/2
3151- requestedHeight: (appContainer.height - PanelState.panelHeight)/2
3152+ windowedX: root.leftMargin
3153+ windowedY: PanelState.panelHeight
3154+ windowedWidth: (appContainer.width - root.leftMargin)/2
3155+ windowedHeight: (appContainer.height - PanelState.panelHeight)/2
3156 }
3157 },
3158 State {
3159@@ -591,17 +1252,18 @@
3160 extend: "maximizedTopLeft"
3161 PropertyChanges {
3162 target: appDelegate
3163- requestedX: (appContainer.width + root.leftMargin)/2
3164+ windowedX: (appContainer.width + root.leftMargin)/2
3165 }
3166 },
3167 State {
3168 name: "maximizedBottomLeft"; when: appDelegate.maximizedBottomLeft && !appDelegate.minimized
3169+ extend: "semiMaximized"
3170 PropertyChanges {
3171 target: appDelegate
3172- requestedX: root.leftMargin
3173- requestedY: (appContainer.height + PanelState.panelHeight)/2
3174- requestedWidth: (appContainer.width - root.leftMargin)/2
3175- requestedHeight: appContainer.height/2
3176+ windowedX: root.leftMargin
3177+ windowedY: (appContainer.height + PanelState.panelHeight)/2
3178+ windowedWidth: (appContainer.width - root.leftMargin)/2
3179+ windowedHeight: appContainer.height/2
3180 }
3181 },
3182 State {
3183@@ -609,35 +1271,52 @@
3184 extend: "maximizedBottomLeft"
3185 PropertyChanges {
3186 target: appDelegate
3187- requestedX: (appContainer.width + root.leftMargin)/2
3188+ windowedX: (appContainer.width + root.leftMargin)/2
3189 }
3190 },
3191 State {
3192 name: "maximizedHorizontally"; when: appDelegate.maximizedHorizontally && !appDelegate.minimized
3193- PropertyChanges { target: appDelegate; requestedX: root.leftMargin; requestedY: requestedY; requestedWidth: appContainer.width - root.leftMargin }
3194+ extend: "semiMaximized"
3195+ PropertyChanges { target: appDelegate; requestedX: root.leftMargin; requestedY: windowedY;
3196+ requestedWidth: appContainer.width - root.leftMargin; requestedHeight: appDelegate.windowedHeight }
3197 },
3198 State {
3199 name: "maximizedVertically"; when: appDelegate.maximizedVertically && !appDelegate.minimized
3200- PropertyChanges { target: appDelegate; requestedX: requestedX; requestedY: PanelState.panelHeight; requestedHeight: appContainer.height - PanelState.panelHeight }
3201+ extend: "semiMaximized"
3202+ PropertyChanges { target: appDelegate; requestedX: windowedX; requestedY: PanelState.panelHeight;
3203+ requestedWidth: appDelegate.windowedWidth; requestedHeight: appContainer.height - PanelState.panelHeight }
3204 },
3205 State {
3206 name: "minimized"; when: appDelegate.minimized
3207 PropertyChanges {
3208- target: appDelegate;
3209- requestedX: -appDelegate.width / 2;
3210- scale: units.gu(5) / appDelegate.width;
3211+ target: appDelegate
3212+ requestedX: -appDelegate.width / 2
3213+ scale: units.gu(5) / appDelegate.width
3214 opacity: 0;
3215- visuallyMinimized: true;
3216+ visuallyMinimized: true
3217 visuallyMaximized: false
3218 }
3219 }
3220 ]
3221 transitions: [
3222 Transition {
3223+ from: "staged,stagedWithSideStage"; to: "normal"
3224+ enabled: appDelegate.animationsEnabled
3225+ PropertyAction { target: appDelegate; properties: "visuallyMinimized,visuallyMaximized" }
3226+ UbuntuNumberAnimation { target: appDelegate; properties: "x,y,requestedX,requestedY,opacity,requestedWidth,requestedHeight,scale"; duration: priv.animationDuration }
3227+ },
3228+ Transition {
3229+ from: "normal,maximized,maximizedHorizontally,maximizedVertically,maximizedLeft,maximizedRight,maximizedTopLeft,maximizedBottomLeft,maximizedTopRight,maximizedBottomRight";
3230+ to: "staged,stagedWithSideStage"
3231+ UbuntuNumberAnimation { target: appDelegate; properties: "x,y,requestedX,requestedY,requestedWidth,requestedHeight"; duration: priv.animationDuration}
3232+ },
3233+ Transition {
3234+ from: "maximized,maximizedHorizontally,maximizedVertically,maximizedLeft,maximizedRight,maximizedTopLeft,maximizedBottomLeft,maximizedTopRight,maximizedBottomRight,minimized";
3235 to: "normal,restored"
3236 enabled: appDelegate.animationsEnabled
3237 PropertyAction { target: appDelegate; properties: "visuallyMinimized,visuallyMaximized" }
3238- UbuntuNumberAnimation { target: appDelegate; properties: "requestedX,requestedY,opacity,scale,requestedWidth,requestedHeight" }
3239+ UbuntuNumberAnimation { target: appDelegate; properties: "requestedX,requestedY,windowedX,windowedY,requestedWidth,requestedHeight,windowedWidth,windowedHeight,scale";
3240+ duration: priv.animationDuration }
3241 },
3242 Transition {
3243 to: "minimized"
3244@@ -657,11 +1336,60 @@
3245 }
3246 },
3247 Transition {
3248- to: "*" //maximized and fullscreen
3249+ to: "spread"
3250+ // DecoratedWindow wants the scaleToPreviewSize set before enabling scaleToPreview
3251+ PropertyAction { target: appDelegate; properties: "z,visible" }
3252+ PropertyAction { target: decoratedWindow; property: "scaleToPreviewSize" }
3253+ UbuntuNumberAnimation { target: appDelegate; properties: "x,y,height"; duration: priv.animationDuration }
3254+ UbuntuNumberAnimation { target: decoratedWindow; properties: "width,height,itemScale,angle,scaleToPreviewProgress"; duration: priv.animationDuration }
3255+ },
3256+ Transition {
3257+ from: "normal,staged"; to: "stagedWithSideStage"
3258+ UbuntuNumberAnimation { target: appDelegate; properties: "x,y"; duration: priv.animationDuration }
3259+ UbuntuNumberAnimation { target: appDelegate; properties: "requestedWidth,requestedHeight"; duration: priv.animationDuration }
3260+ },
3261+ Transition {
3262+ to: "windowedRightEdge"
3263+ ScriptAction {
3264+ script: {
3265+ windowedRightEdgeMaths.startX = appDelegate.requestedX
3266+ windowedRightEdgeMaths.startY = appDelegate.requestedY
3267+
3268+ if (index == 1) {
3269+ var thisRect = { x: appDelegate.windowedX, y: appDelegate.windowedY, width: appDelegate.requestedWidth, height: appDelegate.requestedHeight }
3270+ var otherDelegate = appRepeater.itemAt(0);
3271+ var otherRect = { x: otherDelegate.windowedX, y: otherDelegate.windowedY, width: otherDelegate.requestedWidth, height: otherDelegate.requestedHeight }
3272+ var intersectionRect = MathUtils.intersectionRect(thisRect, otherRect)
3273+ var mappedInterSectionRect = appDelegate.mapFromItem(root, intersectionRect.x, intersectionRect.y)
3274+ opacityEffect.maskX = mappedInterSectionRect.x
3275+ opacityEffect.maskY = mappedInterSectionRect.y
3276+ opacityEffect.maskWidth = intersectionRect.width
3277+ opacityEffect.maskHeight = intersectionRect.height
3278+ }
3279+ }
3280+ }
3281+ },
3282+ Transition {
3283+ from: "stagedRightEdge"; to: "staged"
3284+ enabled: rightEdgeDragArea.cancelled // only transition back to state if the gesture was cancelled, in the other cases we play the focusAnimations.
3285+ SequentialAnimation {
3286+ ParallelAnimation {
3287+ UbuntuNumberAnimation { target: appDelegate; properties: "x,y,height,width,scale"; duration: priv.animationDuration }
3288+ UbuntuNumberAnimation { target: decoratedWindow; properties: "width,height,itemScale,angle,scaleToPreviewProgress"; duration: priv.animationDuration }
3289+ }
3290+ // We need to release scaleToPreviewSize at last
3291+ PropertyAction { target: decoratedWindow; property: "scaleToPreviewSize" }
3292+ PropertyAction { target: appDelegate; property: "visible" }
3293+ }
3294+ },
3295+ Transition {
3296+ from: "normal,maximized,maximizedLeft,maximizedRight,maximizedTop,maximizedBottom,maximizedTopLeft,maximizedTopRight,maximizedBottomLeft,maximizedBottomRight,maximizedHorizontally,maximizedVertically,fullscreen"
3297+ to: "normal,maximized,maximizedLeft,maximizedRight,maximizedTop,maximizedBottom,maximizedTopLeft,maximizedTopRight,maximizedBottomLeft,maximizedBottomRight,maximizedHorizontally,maximizedVertically,fullscreen"
3298 enabled: appDelegate.animationsEnabled
3299- PropertyAction { target: appDelegate; property: "visuallyMinimized" }
3300 SequentialAnimation {
3301- UbuntuNumberAnimation { target: appDelegate; properties: "requestedX,requestedY,opacity,scale,requestedWidth,requestedHeight" }
3302+ PropertyAction { target: appDelegate; property: "visuallyMinimized" }
3303+ UbuntuNumberAnimation { target: appDelegate; properties: "requestedX,requestedY,windowedX,windowedY,opacity,scale,requestedWidth,requestedHeight,windowedWidth,windowedHeight";
3304+ duration: priv.animationDuration }
3305 PropertyAction { target: appDelegate; property: "visuallyMaximized" }
3306 ScriptAction { script: { fakeRectangle.stop(); } }
3307 }
3308@@ -669,14 +1397,6 @@
3309 ]
3310
3311 Binding {
3312- id: previewBinding
3313- target: appDelegate
3314- property: "z"
3315- value: topLevelSurfaceList.count + 1
3316- when: index == spread.highlightedIndex && spread.ready
3317- }
3318-
3319- Binding {
3320 target: PanelState
3321 property: "buttonsAlwaysVisible"
3322 value: appDelegate && appDelegate.maximized && touchControls.overlayShown
3323@@ -697,26 +1417,15 @@
3324 screenWidth: appContainer.width
3325 screenHeight: appContainer.height
3326 leftMargin: root.leftMargin
3327-
3328- onPressed: { appDelegate.focus = true; }
3329-
3330- Component.onCompleted: {
3331- loadWindowState();
3332- }
3333-
3334- property bool saveStateOnDestruction: true
3335- Connections {
3336- target: root
3337- onStageAboutToBeUnloaded: {
3338- resizeArea.saveWindowState();
3339- resizeArea.saveStateOnDestruction = false;
3340- fullscreenPolicy.active = false;
3341- }
3342- }
3343+ enabled: false
3344+ visible: enabled
3345+
3346+ onPressed: {
3347+ appDelegate.focus = true;
3348+ }
3349+
3350 Component.onDestruction: {
3351- if (saveStateOnDestruction) {
3352- saveWindowState();
3353- }
3354+ saveWindowState();
3355 }
3356 }
3357
3358@@ -729,14 +1438,25 @@
3359 surface: model.surface
3360 active: appDelegate.focus
3361 focus: true
3362+ interactive: root.interactive
3363+ showDecoration: 1
3364 maximizeButtonShown: appDelegate.canBeMaximized
3365 overlayShown: touchControls.overlayShown
3366+ width: implicitWidth
3367+ height: implicitHeight
3368+ highlightSize: windowInfoItem.iconMargin / 2
3369 stageWidth: appContainer.width
3370 stageHeight: appContainer.height
3371
3372 requestedWidth: appDelegate.requestedWidth
3373 requestedHeight: appDelegate.requestedHeight
3374
3375+ property int oldRequestedWidth: -1
3376+ property int oldRequestedHeight: -1
3377+
3378+ onRequestedWidthChanged: oldRequestedWidth = requestedWidth
3379+ onRequestedHeightChanged: oldRequestedHeight = requestedHeight
3380+
3381 onCloseClicked: { appDelegate.close(); }
3382 onMaximizeClicked: appDelegate.anyMaximized ? appDelegate.restoreFromMaximized() : appDelegate.maximize();
3383 onMaximizeHorizontallyClicked: appDelegate.maximizedHorizontally ? appDelegate.restoreFromMaximized() : appDelegate.maximizeHorizontally()
3384@@ -744,11 +1464,34 @@
3385 onMinimizeClicked: appDelegate.minimize()
3386 onDecorationPressed: { appDelegate.focus = true; }
3387 onDecorationReleased: fakeRectangle.commit();
3388+
3389+ property real angle: 0
3390+ property real itemScale: 1
3391+ transform: [
3392+ Scale {
3393+ origin.x: 0
3394+ origin.y: decoratedWindow.implicitHeight / 2
3395+ xScale: decoratedWindow.itemScale
3396+ yScale: decoratedWindow.itemScale
3397+ },
3398+ Rotation {
3399+ origin { x: 0; y: (decoratedWindow.height / 2) }
3400+ axis { x: 0; y: 1; z: 0 }
3401+ angle: decoratedWindow.angle
3402+ }
3403+ ]
3404+ }
3405+
3406+ OpacityMask {
3407+ id: opacityEffect
3408+ anchors.fill: decoratedWindow
3409 }
3410
3411 WindowControlsOverlay {
3412 id: touchControls
3413 target: appDelegate
3414+ enabled: false
3415+ visible: enabled
3416 stageWidth: appContainer.width
3417 stageHeight: appContainer.height
3418
3419@@ -764,9 +1507,89 @@
3420 }
3421
3422 WindowedFullscreenPolicy {
3423- id: fullscreenPolicy
3424- active: true
3425- surface: model.surface
3426+ id: windowedFullscreenPolicy
3427+ active: root.mode == "windowed"
3428+ surface: model.surface
3429+ }
3430+ StagedFullscreenPolicy {
3431+ id: stagedFullscreenPolicy
3432+ active: root.mode == "staged" || root.mode == "stagedWithSideStage"
3433+ surface: model.surface
3434+ }
3435+
3436+ SpreadDelegateInputArea {
3437+ id: dragArea
3438+ objectName: "dragArea"
3439+ anchors.fill: decoratedWindow
3440+ enabled: false
3441+ closeable: !appDelegate.isDash
3442+
3443+ onClicked: {
3444+ spreadItem.highlightedIndex = index;
3445+ if (distance == 0) {
3446+ priv.goneToSpread = false;
3447+ }
3448+ }
3449+ onClose: {
3450+ priv.closingIndex = index
3451+ if (model.surface) { // could be stopped by OOM
3452+ model.surface.close()
3453+ } else if (model.application) {
3454+ root.applicationManager.stopApplication(model.application.appId);
3455+ }
3456+ }
3457+ }
3458+
3459+ WindowInfoItem {
3460+ id: windowInfoItem
3461+ objectName: "windowInfoItem"
3462+ anchors { left: parent.left; top: decoratedWindow.bottom; topMargin: units.gu(1) }
3463+ title: model.application.name
3464+ iconSource: model.application.icon
3465+ height: spreadItem.appInfoHeight
3466+ opacity: 0
3467+ z: 1
3468+ visible: opacity > 0
3469+ maxWidth: {
3470+ var nextApp = appRepeater.itemAt(index + 1);
3471+ if (nextApp) {
3472+ return nextApp.x - appDelegate.x - units.gu(1)
3473+ }
3474+ return appDelegate.width;
3475+ }
3476+
3477+ onClicked: {
3478+ spreadItem.highlightedIndex = index;
3479+ priv.goneToSpread = false;
3480+ }
3481+ }
3482+
3483+ Image {
3484+ id: closeImage
3485+ anchors { left: parent.left; top: parent.top; leftMargin: -height / 2; topMargin: -height / 2 + spreadMaths.closeIconOffset }
3486+ source: "graphics/window-close.svg"
3487+ readonly property var mousePos: hoverMouseArea.mapToItem(appDelegate, hoverMouseArea.mouseX, hoverMouseArea.mouseY)
3488+ visible: !appDelegate.isDash
3489+ && index == spreadItem.highlightedIndex
3490+ && mousePos.y < (decoratedWindow.height / 3)
3491+ && mousePos.y > -units.gu(4)
3492+ && mousePos.x > -units.gu(4)
3493+ && mousePos.x < (decoratedWindow.width * 2 / 3)
3494+ height: units.gu(2)
3495+ width: height
3496+ sourceSize.width: width
3497+ sourceSize.height: height
3498+
3499+ MouseArea {
3500+ id: closeMouseArea
3501+ objectName: "closeMouseArea"
3502+ anchors.fill: closeImage
3503+ anchors.margins: -units.gu(2)
3504+ onClicked: {
3505+ priv.closingIndex = index;
3506+ appDelegate.close();
3507+ }
3508+ }
3509 }
3510 }
3511 }
3512@@ -786,7 +1609,8 @@
3513 // NB: it does its own positioning according to the specified edge
3514 edge: Qt.RightEdge
3515
3516- onPassed: { spread.show(); }
3517+ onPassed: priv.goneToSpread = true;
3518+
3519 material: Component {
3520 Item {
3521 Rectangle {
3522@@ -803,23 +1627,248 @@
3523 }
3524 }
3525
3526+ MouseArea {
3527+ id: hoverMouseArea
3528+ objectName: "hoverMouseArea"
3529+ anchors.fill: appContainer
3530+ propagateComposedEvents: true
3531+ hoverEnabled: true
3532+ enabled: false
3533+ visible: enabled
3534+
3535+ property int scrollAreaWidth: width / 3
3536+ property bool progressiveScrollingEnabled: false
3537+
3538+ onMouseXChanged: {
3539+ mouse.accepted = false
3540+
3541+ if (hoverMouseArea.pressed) {
3542+ return;
3543+ }
3544+
3545+ // Find the hovered item and mark it active
3546+ var mapped = mapToItem(appContainer, hoverMouseArea.mouseX, hoverMouseArea.mouseY)
3547+ var itemUnder = appContainer.childAt(mapped.x, mapped.y)
3548+ if (itemUnder) {
3549+ mapped = mapToItem(itemUnder, hoverMouseArea.mouseX, hoverMouseArea.mouseY)
3550+ var delegateChild = itemUnder.childAt(mapped.x, mapped.y)
3551+ if (delegateChild && (delegateChild.objectName === "dragArea" || delegateChild.objectName === "windowInfoItem")) {
3552+ spreadItem.highlightedIndex = appRepeater.indexOf(itemUnder)
3553+ }
3554+ }
3555+
3556+ if (floatingFlickable.contentWidth > floatingFlickable.width) {
3557+ var margins = floatingFlickable.width * 0.05;
3558+
3559+ if (!progressiveScrollingEnabled && mouseX < floatingFlickable.width - scrollAreaWidth) {
3560+ progressiveScrollingEnabled = true
3561+ }
3562+
3563+ // do we need to scroll?
3564+ if (mouseX < scrollAreaWidth + margins) {
3565+ var progress = Math.min(1, (scrollAreaWidth + margins - mouseX) / (scrollAreaWidth - margins));
3566+ var contentX = (1 - progress) * (floatingFlickable.contentWidth - floatingFlickable.width)
3567+ floatingFlickable.contentX = Math.max(0, Math.min(floatingFlickable.contentX, contentX))
3568+ }
3569+ if (mouseX > floatingFlickable.width - scrollAreaWidth && progressiveScrollingEnabled) {
3570+ var progress = Math.min(1, (mouseX - (floatingFlickable.width - scrollAreaWidth)) / (scrollAreaWidth - margins))
3571+ var contentX = progress * (floatingFlickable.contentWidth - floatingFlickable.width)
3572+ floatingFlickable.contentX = Math.min(floatingFlickable.contentWidth - floatingFlickable.width, Math.max(floatingFlickable.contentX, contentX))
3573+ }
3574+ }
3575+ }
3576+
3577+ onPressed: mouse.accepted = false
3578+ }
3579+
3580+ FloatingFlickable {
3581+ id: floatingFlickable
3582+ objectName: "spreadFlickable"
3583+ anchors.fill: appContainer
3584+ enabled: false
3585+ contentWidth: spreadItem.spreadTotalWidth
3586+
3587+ function snap(toIndex) {
3588+ var delegate = appRepeater.itemAt(toIndex)
3589+ var targetContentX = floatingFlickable.contentWidth / spreadItem.totalItemCount * toIndex;
3590+ if (targetContentX - floatingFlickable.contentX > spreadItem.rightStackXPos - (spreadItem.spreadItemWidth / 2)) {
3591+ var offset = (spreadItem.rightStackXPos - (spreadItem.spreadItemWidth / 2)) - (targetContentX - floatingFlickable.contentX)
3592+ snapAnimation.to = floatingFlickable.contentX - offset;
3593+ snapAnimation.start();
3594+ } else if (targetContentX - floatingFlickable.contentX < spreadItem.leftStackXPos + units.gu(1)) {
3595+ var offset = (spreadItem.leftStackXPos + units.gu(1)) - (targetContentX - floatingFlickable.contentX);
3596+ snapAnimation.to = floatingFlickable.contentX - offset;
3597+ snapAnimation.start();
3598+ }
3599+ }
3600+ UbuntuNumberAnimation {id: snapAnimation; target: floatingFlickable; property: "contentX"}
3601+ }
3602+
3603+ PropertyAnimation {
3604+ id: shortRightEdgeSwipeAnimation
3605+ property: "x"
3606+ to: 0
3607+ duration: priv.animationDuration
3608+ }
3609+
3610 SwipeArea {
3611+ id: rightEdgeDragArea
3612+ objectName: "rightEdgeDragArea"
3613 direction: Direction.Leftwards
3614 anchors { top: parent.top; right: parent.right; bottom: parent.bottom }
3615- width: units.gu(1)
3616- onDraggingChanged: { if (dragging) { spread.show(); } }
3617+ width: root.dragAreaWidth
3618+
3619+ property var gesturePoints: []
3620+ property bool cancelled: false
3621+
3622+ property real progress: dragging ? -touchPosition.x / root.width : 0
3623+ onProgressChanged: {
3624+ if (dragging) {
3625+ draggedProgress = progress;
3626+ }
3627+ }
3628+
3629+ property real draggedProgress: 0
3630+
3631+ onTouchPositionChanged: {
3632+ gesturePoints.push(touchPosition.x);
3633+ if (gesturePoints.length > 10) {
3634+ gesturePoints.splice(0, gesturePoints.length - 10)
3635+ }
3636+ }
3637+
3638+ onDraggingChanged: {
3639+ if (dragging) {
3640+ // A potential edge-drag gesture has started. Start recording it
3641+ gesturePoints = [];
3642+ cancelled = false;
3643+ draggedProgress = 0;
3644+ } else {
3645+ // Ok. The user released. Did he drag far enough to go to full spread?
3646+ if (gesturePoints[gesturePoints.length - 1] < -spreadItem.rightEdgeBreakPoint * spreadItem.width ) {
3647+
3648+ // He dragged far enough, but if the last movement was a flick to the right again, he wants to cancel the spread again.
3649+ var oneWayFlickToRight = true;
3650+ var smallestX = gesturePoints[0]-1;
3651+ for (var i = 0; i < gesturePoints.length; i++) {
3652+ if (gesturePoints[i] <= smallestX) {
3653+ oneWayFlickToRight = false;
3654+ break;
3655+ }
3656+ smallestX = gesturePoints[i];
3657+ }
3658+
3659+ if (!oneWayFlickToRight) {
3660+ // Ok, the user made it, let's go to spread!
3661+ priv.goneToSpread = true;
3662+ } else {
3663+ cancelled = true;
3664+ }
3665+ } else {
3666+ // Ok, the user didn't drag far enough to cross the breakPoint
3667+ // Find out if it was a one-way movement to the left, in which case we just switch directly to next app.
3668+ var oneWayFlick = true;
3669+ var smallestX = rightEdgeDragArea.width;
3670+ for (var i = 0; i < gesturePoints.length; i++) {
3671+ if (gesturePoints[i] >= smallestX) {
3672+ oneWayFlick = false;
3673+ break;
3674+ }
3675+ smallestX = gesturePoints[i];
3676+ }
3677+
3678+ if (appRepeater.count > 1 &&
3679+ (oneWayFlick && rightEdgeDragArea.distance > units.gu(2) || rightEdgeDragArea.distance > spreadItem.rightEdgeBreakPoint * spreadItem.width)) {
3680+ var nextStage = appRepeater.itemAt(priv.nextInStack).stage
3681+ for (var i = 0; i < appRepeater.count; i++) {
3682+ if (i != priv.nextInStack && appRepeater.itemAt(i).stage == nextStage) {
3683+ appRepeater.itemAt(i).playHidingAnimation()
3684+ break;
3685+ }
3686+ }
3687+ appRepeater.itemAt(priv.nextInStack).playFocusAnimation()
3688+ if (appRepeater.itemAt(priv.nextInStack).stage == ApplicationInfoInterface.SideStage && !sideStage.shown) {
3689+ sideStage.show();
3690+ }
3691+
3692+ } else {
3693+ cancelled = true;
3694+ }
3695+
3696+ gesturePoints = [];
3697+ }
3698+ }
3699+ }
3700 }
3701
3702- DesktopSpread {
3703- id: spread
3704- objectName: "spread"
3705- anchors.fill: appContainer
3706- workspace: appContainer
3707- focus: state == "altTab"
3708- altTabPressed: root.altTabPressed
3709-
3710- onPlayFocusAnimation: {
3711- appRepeater.itemAt(index).playFocusAnimation();
3712+ TabletSideStageTouchGesture {
3713+ id: triGestureArea
3714+ objectName: "triGestureArea"
3715+ anchors.fill: parent
3716+ enabled: false
3717+ property Item appDelegate
3718+
3719+ dragComponent: dragComponent
3720+ dragComponentProperties: { "appDelegate": appDelegate }
3721+
3722+ onPressed: {
3723+ function matchDelegate(obj) { return String(obj.objectName).indexOf("appDelegate") >= 0; }
3724+
3725+ var delegateAtCenter = Functions.itemAt(appContainer, x, y, matchDelegate);
3726+ if (!delegateAtCenter) return;
3727+
3728+ appDelegate = delegateAtCenter;
3729+ }
3730+
3731+ onClicked: {
3732+ if (sideStage.shown) {
3733+ sideStage.hide();
3734+ } else {
3735+ sideStage.show();
3736+ priv.updateMainAndSideStageIndexes()
3737+ }
3738+ }
3739+
3740+ onDragStarted: {
3741+ // If we're dragging to the sidestage.
3742+ if (!sideStage.shown) {
3743+ sideStage.show();
3744+ }
3745+ }
3746+
3747+ Component {
3748+ id: dragComponent
3749+ SurfaceContainer {
3750+ property Item appDelegate
3751+
3752+ surface: appDelegate ? appDelegate.surface : null
3753+
3754+ consumesInput: false
3755+ interactive: false
3756+ focus: false
3757+ requestedWidth: appDelegate.requestedWidth
3758+ requestedHeight: appDelegate.requestedHeight
3759+
3760+ width: units.gu(40)
3761+ height: units.gu(40)
3762+
3763+ Drag.hotSpot.x: width/2
3764+ Drag.hotSpot.y: height/2
3765+ // only accept opposite stage.
3766+ Drag.keys: {
3767+ if (!surface) return "Disabled";
3768+ if (appDelegate.isDash) return "Disabled";
3769+
3770+ if (appDelegate.stage === ApplicationInfo.MainStage) {
3771+ if (appDelegate.application.supportedOrientations
3772+ & (Qt.PortraitOrientation|Qt.InvertedPortraitOrientation)) {
3773+ return "MainStage";
3774+ }
3775+ return "Disabled";
3776+ }
3777+ return "SideStage";
3778+ }
3779+ }
3780 }
3781 }
3782 }
3783
3784=== added file 'qml/Stage/StageMaths.qml'
3785--- qml/Stage/StageMaths.qml 1970-01-01 00:00:00 +0000
3786+++ qml/Stage/StageMaths.qml 2016-10-03 11:16:14 +0000
3787@@ -0,0 +1,79 @@
3788+import QtQuick 2.4
3789+import Unity.Application 0.1
3790+import Ubuntu.Components 1.3
3791+
3792+QtObject {
3793+ id: root
3794+
3795+ // input
3796+ property int itemIndex: 0
3797+ property int nextInStack: 0
3798+ property int sceneWidth: 0
3799+ property int sideStageWidth: 0
3800+ property int sideStageX: sceneWidth
3801+ property bool animateX: false
3802+ property int leftEdgeDragProgress: 0
3803+
3804+ property int stage: ApplicationInfoInterface.MainStage
3805+ property var thisDelegate: null
3806+ property var mainStageDelegate: null
3807+ property var sideStageDelegate: null
3808+
3809+ // output
3810+
3811+ // We need to shuffle z ordering a bit in order to keep side stage apps above main stage apps.
3812+ // We don't want to really reorder them in the model because that allows us to keep track
3813+ // of the last focused order.
3814+ readonly property int itemZ: {
3815+ // only shuffle when we've got a main and side stage
3816+ if (thisDelegate.isDash && thisDelegate != mainStageDelegate && leftEdgeDragProgress > 0) {
3817+ return -1; // Keep the dash behind all other apps for the left edge gesture
3818+ }
3819+
3820+ if (!sideStageDelegate) return itemIndex;
3821+
3822+ // don't shuffle indexes greater than "actives or next"
3823+ if (itemIndex > 2) return itemIndex;
3824+
3825+ if (thisDelegate == mainStageDelegate) {
3826+ // Active main stage always at 0
3827+ return 0;
3828+ }
3829+
3830+ if (nextInStack > 0) {
3831+ var stageOfNextInStack = appRepeater.itemAt(nextInStack).stage;
3832+
3833+ if (itemIndex === nextInStack) {
3834+ // this is the next app in stack.
3835+
3836+ if (stage === ApplicationInfoInterface.SideStage) {
3837+ // if the next app in stack is a sidestage app, it must order on top of other side stage app
3838+ return Math.min(2, topLevelSurfaceList.count-1);
3839+ }
3840+ return 1;
3841+ }
3842+ if (stageOfNextInStack === ApplicationInfoInterface.SideStage) {
3843+ // if the next app in stack is a sidestage app, it must order on top of other side stage app
3844+ return 1;
3845+ }
3846+ return Math.min(2, topLevelSurfaceList.count-1);
3847+ }
3848+ return Math.min(index+1, topLevelSurfaceList.count-1);
3849+ }
3850+
3851+
3852+ property int itemX: {
3853+ if (mainStageDelegate == thisDelegate) {
3854+ return thisDelegate.isDash ? 0 : leftEdgeDragProgress;
3855+ }
3856+ if (sideStageDelegate == thisDelegate) {
3857+ return sideStageX;
3858+ }
3859+ return thisDelegate.isDash && leftEdgeDragProgress > 0 ? 0 : sceneWidth;
3860+ }
3861+ Behavior on itemX { enabled: root.animateX; UbuntuNumberAnimation {} }
3862+
3863+ readonly property int itemWidth: stage == ApplicationInfoInterface.MainStage ?
3864+ sideStageDelegate != null ? sideStageX : sceneWidth :
3865+ stage == ApplicationInfoInterface.SideStage ? sideStageWidth : sceneWidth
3866+}
3867
3868=== modified file 'qml/Stage/SurfaceContainer.qml'
3869--- qml/Stages/SurfaceContainer.qml 2016-05-18 21:58:39 +0000
3870+++ qml/Stage/SurfaceContainer.qml 2016-10-03 11:16:14 +0000
3871@@ -23,6 +23,8 @@
3872 FocusScope {
3873 id: root
3874 objectName: "surfaceContainer"
3875+ implicitWidth: surfaceItem.implicitWidth
3876+ implicitHeight: surfaceItem.implicitHeight
3877
3878 // Must be set from outside
3879 property var surface: null
3880@@ -32,7 +34,6 @@
3881 property int requestedHeight: -1
3882 property bool interactive
3883 property int surfaceOrientationAngle: 0
3884- property bool resizeSurface: true
3885 property bool isPromptSurface: false
3886 // FIME - dont export, use interactive property. Need to fix qtmir to handle consumesInputChanged
3887 // to update surface activeFocus. See mock MirSurfaceItem.
3888@@ -58,35 +59,15 @@
3889 MirSurfaceItem {
3890 id: surfaceItem
3891 objectName: "surfaceItem"
3892+ anchors.fill: parent
3893
3894 focus: true
3895
3896 fillMode: MirSurfaceItem.PadOrCrop
3897 consumesInput: true
3898
3899- surfaceWidth: {
3900- if (root.resizeSurface) {
3901- if (root.requestedWidth >= 0) {
3902- return root.requestedWidth;
3903- } else {
3904- return width;
3905- }
3906- } else {
3907- return -1;
3908- }
3909- }
3910-
3911- surfaceHeight: {
3912- if (root.resizeSurface) {
3913- if (root.requestedHeight >= 0) {
3914- return root.requestedHeight;
3915- } else {
3916- return height;
3917- }
3918- } else {
3919- return -1;
3920- }
3921- }
3922+ surfaceWidth: root.requestedWidth
3923+ surfaceHeight: root.requestedHeight
3924
3925 enabled: root.interactive
3926 antialiasing: !root.interactive
3927@@ -99,34 +80,6 @@
3928 enabled: surfaceItem.enabled
3929 }
3930
3931- // MirSurface size drives SurfaceContainer size
3932- Binding {
3933- target: surfaceItem; property: "width"; value: root.surface ? root.surface.size.width : 0
3934- when: root.requestedWidth >= 0 && root.surface
3935- }
3936- Binding {
3937- target: surfaceItem; property: "height"; value: root.surface ? root.surface.size.height : 0
3938- when: root.requestedHeight >= 0 && root.surface
3939- }
3940- Binding {
3941- target: root; property: "width"; value: surfaceItem.width
3942- when: root.requestedWidth >= 0
3943- }
3944- Binding {
3945- target: root; property: "height"; value: surfaceItem.height
3946- when: root.requestedHeight >= 0
3947- }
3948-
3949- // SurfaceContainer size drives MirSurface size
3950- Binding {
3951- target: surfaceItem; property: "width"; value: root.width
3952- when: root.requestedWidth < 0
3953- }
3954- Binding {
3955- target: surfaceItem; property: "height"; value: root.height
3956- when: root.requestedHeight < 0
3957- }
3958-
3959 Loader {
3960 id: animationsLoader
3961 objectName: "animationsLoader"
3962
3963=== modified file 'qml/Stage/TopLevelSurfaceRepeater.qml'
3964--- qml/Stages/TopLevelSurfaceRepeater.qml 2016-09-07 09:48:56 +0000
3965+++ qml/Stage/TopLevelSurfaceRepeater.qml 2016-10-03 11:16:14 +0000
3966@@ -55,4 +55,13 @@
3967 startingUp = false;
3968 }
3969 }
3970+
3971+ function indexOf(delegateItem) {
3972+ for (var i = 0; i < count; i++) {
3973+ if (itemAt(i) === delegateItem) {
3974+ return i;
3975+ }
3976+ }
3977+ return -1;
3978+ }
3979 }
3980
3981=== modified file 'qml/Stage/WindowDecoration.qml'
3982--- qml/Stages/WindowDecoration.qml 2016-09-22 07:42:18 +0000
3983+++ qml/Stage/WindowDecoration.qml 2016-10-03 11:16:14 +0000
3984@@ -79,7 +79,7 @@
3985 onMaximizeClicked: root.maximizeClicked();
3986 onMaximizeHorizontallyClicked: if (root.target.canBeMaximizedHorizontally) root.maximizeHorizontallyClicked();
3987 onMaximizeVerticallyClicked: if (root.target.canBeMaximizedVertically) root.maximizeVerticallyClicked();
3988- closeButtonShown: root.target.application.appId !== "unity8-dash"
3989+ closeButtonShown: root.target.appId !== "unity8-dash"
3990 }
3991
3992 Label {
3993
3994=== added file 'qml/Stage/WindowInfoItem.qml'
3995--- qml/Stage/WindowInfoItem.qml 1970-01-01 00:00:00 +0000
3996+++ qml/Stage/WindowInfoItem.qml 2016-10-03 11:16:14 +0000
3997@@ -0,0 +1,53 @@
3998+import QtQuick 2.4
3999+import Ubuntu.Components 1.3
4000+
4001+Item {
4002+ id: root
4003+ implicitWidth: Math.max(iconShape.width, titleLabel.width)
4004+ implicitHeight: iconShape.height + titleLabel.height + labelMargin + iconMargin
4005+ property alias title: titleLabel.text
4006+ property alias iconSource: icon.source
4007+
4008+ property real iconHeight: (height - titleLabel.height) * 0.65
4009+ property real iconMargin: (height - titleLabel.height) * 0.25
4010+ property real labelMargin: (height - titleLabel.height) * 0.1
4011+ property int maxWidth: units.gu(10)
4012+
4013+ signal clicked()
4014+
4015+ ProportionalShape {
4016+ id: iconShape
4017+ anchors {
4018+ top: parent.top
4019+ topMargin: iconMargin
4020+ left: parent.left
4021+ }
4022+ height: iconHeight
4023+ borderSource: "undefined"
4024+ aspect: UbuntuShape.Flat
4025+ source: Image {
4026+ id: icon
4027+ sourceSize.width: iconShape.width
4028+ sourceSize.height: iconShape.height
4029+ cache: false // see lpbug#1543290 why no cache
4030+ }
4031+ }
4032+
4033+ MouseArea {
4034+ anchors.fill: iconShape
4035+ onClicked: root.clicked()
4036+ }
4037+
4038+ Label {
4039+ id: titleLabel
4040+ anchors {
4041+ left: iconShape.left
4042+ top: iconShape.bottom
4043+ topMargin: labelMargin
4044+ }
4045+ width: root.maxWidth
4046+ fontSize: 'small'
4047+ color: 'white'
4048+ elide: Label.ElideRight
4049+ }
4050+}
4051
4052=== modified file 'qml/Stage/WindowResizeArea.qml'
4053--- qml/Stages/WindowResizeArea.qml 2016-08-31 13:00:26 +0000
4054+++ qml/Stage/WindowResizeArea.qml 2016-10-03 11:16:14 +0000
4055@@ -75,14 +75,15 @@
4056
4057 function loadWindowState() {
4058 var windowGeometry = windowStateStorage.getGeometry(root.windowId,
4059- Qt.rect(target.requestedX, target.requestedY, defaultWidth, defaultHeight));
4060-
4061- target.requestedWidth = Qt.binding(function() { return Math.min(Math.max(windowGeometry.width, d.minimumWidth), screenWidth - root.leftMargin); });
4062- target.requestedHeight = Qt.binding(function() { return Math.min(Math.max(windowGeometry.height, d.minimumHeight),
4063+ Qt.rect(target.windowedX, target.windowedY, defaultWidth, defaultHeight));
4064+
4065+
4066+ target.windowedWidth = Qt.binding(function() { return Math.min(Math.max(windowGeometry.width, d.minimumWidth), screenWidth - root.leftMargin); });
4067+ target.windowedHeight = Qt.binding(function() { return Math.min(Math.max(windowGeometry.height, d.minimumHeight),
4068 root.screenHeight - (target.fullscreen ? 0 : PanelState.panelHeight)); });
4069- target.requestedX = Qt.binding(function() { return Math.max(Math.min(windowGeometry.x, root.screenWidth - root.leftMargin - target.requestedWidth),
4070+ target.windowedX = Qt.binding(function() { return Math.max(Math.min(windowGeometry.x, root.screenWidth - root.leftMargin - target.windowedWidth),
4071 (target.fullscreen ? 0 : root.leftMargin)); });
4072- target.requestedY = Qt.binding(function() { return Math.max(Math.min(windowGeometry.y, root.screenHeight - target.requestedHeight), PanelState.panelHeight); });
4073+ target.windowedY = Qt.binding(function() { return Math.max(Math.min(windowGeometry.y, root.screenHeight - target.windowedHeight), PanelState.panelHeight); });
4074
4075 var windowState = windowStateStorage.getState(root.windowId, WindowStateStorage.WindowStateNormal)
4076 target.restore(false /* animated */, windowState);
4077@@ -111,28 +112,28 @@
4078
4079 readonly property int minimumWidth: root.target ? Math.max(root.minWidth, root.target.minimumWidth) : root.minWidth
4080 onMinimumWidthChanged: {
4081- if (target.requestedWidth < minimumWidth) {
4082- target.requestedWidth = minimumWidth;
4083+ if (target.windowedWidth < minimumWidth) {
4084+ target.windowedWidth = minimumWidth;
4085 }
4086 }
4087 readonly property int minimumHeight: root.target ? Math.max(root.minHeight, root.target.minimumHeight) : root.minHeight
4088 onMinimumHeightChanged: {
4089- if (target.requestedHeight < minimumHeight) {
4090- target.requestedHeight = minimumHeight;
4091+ if (target.windowedHeight < minimumHeight) {
4092+ target.windowedHeight = minimumHeight;
4093 }
4094 }
4095 readonly property int maximumWidth: root.target && root.target.maximumWidth >= minimumWidth && root.target.maximumWidth > 0
4096 ? root.target.maximumWidth : maxSafeInt
4097 onMaximumWidthChanged: {
4098- if (target.requestedWidth > maximumWidth) {
4099- target.requestedWidth = maximumWidth;
4100+ if (target.windowedWidth > maximumWidth) {
4101+ target.windowedWidth = maximumWidth;
4102 }
4103 }
4104 readonly property int maximumHeight: root.target && root.target.maximumHeight >= minimumHeight && root.target.maximumHeight > 0
4105 ? root.target.maximumHeight : maxSafeInt
4106 onMaximumHeightChanged: {
4107- if (target.requestedHeight > maximumHeight) {
4108- target.requestedHeight = maximumHeight;
4109+ if (target.windowedHeight > maximumHeight) {
4110+ target.windowedHeight = maximumHeight;
4111 }
4112 }
4113 readonly property int widthIncrement: {
4114@@ -247,8 +248,8 @@
4115 var pos = mapToItem(root.target.parent, mouseX, mouseY);
4116 d.startMousePosX = pos.x;
4117 d.startMousePosY = pos.y;
4118- d.startX = target.requestedX;
4119- d.startY = target.requestedY;
4120+ d.startX = target.windowedX;
4121+ d.startY = target.windowedY;
4122 d.startWidth = target.width;
4123 d.startHeight = target.height;
4124 d.currentWidth = target.width;
4125@@ -285,53 +286,53 @@
4126
4127 if (d.leftBorder) {
4128 var newTargetX = d.startX + deltaX;
4129- var rightBorderX = target.requestedX + target.width;
4130+ var rightBorderX = target.windowedX + target.width;
4131 if (rightBorderX > newTargetX + d.minimumWidth) {
4132 if (rightBorderX < newTargetX + d.maximumWidth) {
4133- target.requestedWidth = rightBorderX - newTargetX;
4134+ target.windowedWidth = rightBorderX - newTargetX;
4135 } else {
4136- target.requestedWidth = d.maximumWidth;
4137+ target.windowedWidth = d.maximumWidth;
4138 }
4139 } else {
4140- target.requestedWidth = d.minimumWidth;
4141+ target.windowedWidth = d.minimumWidth;
4142 }
4143
4144 } else if (d.rightBorder) {
4145 var newWidth = d.startWidth + deltaX;
4146 if (newWidth > d.minimumWidth) {
4147 if (newWidth < d.maximumWidth) {
4148- target.requestedWidth = newWidth;
4149+ target.windowedWidth = newWidth;
4150 } else {
4151- target.requestedWidth = d.maximumWidth;
4152+ target.windowedWidth = d.maximumWidth;
4153 }
4154 } else {
4155- target.requestedWidth = d.minimumWidth;
4156+ target.windowedWidth = d.minimumWidth;
4157 }
4158 }
4159
4160 if (d.topBorder) {
4161 var newTargetY = Math.max(d.startY + deltaY, PanelState.panelHeight); // disallow resizing up past Panel
4162- var bottomBorderY = target.requestedY + target.height;
4163+ var bottomBorderY = target.windowedY + target.height;
4164 if (bottomBorderY > newTargetY + d.minimumHeight) {
4165 if (bottomBorderY < newTargetY + d.maximumHeight) {
4166- target.requestedHeight = bottomBorderY - newTargetY;
4167+ target.windowedHeight = bottomBorderY - newTargetY;
4168 } else {
4169- target.requestedHeight = d.maximumHeight;
4170+ target.windowedHeight = d.maximumHeight;
4171 }
4172 } else {
4173- target.requestedHeight = d.minimumHeight;
4174+ target.windowedHeight = d.minimumHeight;
4175 }
4176
4177 } else if (d.bottomBorder) {
4178 var newHeight = d.startHeight + deltaY;
4179 if (newHeight > d.minimumHeight) {
4180 if (newHeight < d.maximumHeight) {
4181- target.requestedHeight = newHeight;
4182+ target.windowedHeight = newHeight;
4183 } else {
4184- target.requestedHeight = d.maximumHeight;
4185+ target.windowedHeight = d.maximumHeight;
4186 }
4187 } else {
4188- target.requestedHeight = d.minimumHeight;
4189+ target.windowedHeight = d.minimumHeight;
4190 }
4191 }
4192 }
4193@@ -340,13 +341,13 @@
4194 target: root.target
4195 onWidthChanged: {
4196 if (d.moveLeftBorder) {
4197- target.requestedX += d.currentWidth - target.width;
4198+ target.windowedX += d.currentWidth - target.width;
4199 }
4200 d.currentWidth = target.width;
4201 }
4202 onHeightChanged: {
4203 if (d.moveTopBorder) {
4204- target.requestedY += d.currentHeight - target.height;
4205+ target.windowedY += d.currentHeight - target.height;
4206 }
4207 d.currentHeight = target.height;
4208 }
4209
4210=== removed file 'qml/Stages/AbstractStage.qml'
4211--- qml/Stages/AbstractStage.qml 2016-09-07 08:36:59 +0000
4212+++ qml/Stages/AbstractStage.qml 1970-01-01 00:00:00 +0000
4213@@ -1,93 +0,0 @@
4214-/*
4215- * Copyright (C) 2015-2016 Canonical, Ltd.
4216- *
4217- * This program is free software; you can redistribute it and/or modify
4218- * it under the terms of the GNU General Public License as published by
4219- * the Free Software Foundation; version 3.
4220- *
4221- * This program is distributed in the hope that it will be useful,
4222- * but WITHOUT ANY WARRANTY; without even the implied warranty of
4223- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4224- * GNU General Public License for more details.
4225- *
4226- * You should have received a copy of the GNU General Public License
4227- * along with this program. If not, see <http://www.gnu.org/licenses/>.
4228- */
4229-
4230-import QtQuick 2.4
4231-import Ubuntu.Components 1.3
4232-import GlobalShortcut 1.0
4233-import GSettings 1.0
4234-
4235-FocusScope {
4236- id: root
4237-
4238- // Controls to be set from outside
4239- property QtObject applicationManager
4240- property QtObject topLevelSurfaceList
4241- property bool altTabPressed
4242- property url background
4243- property bool beingResized
4244- property int dragAreaWidth
4245- property real dragProgress // How far left the stage has been dragged, used externally by tutorial code
4246- property bool interactive
4247- property real inverseProgress // This is the progress for left edge drags, in pixels.
4248- property bool keepDashRunning: true
4249- property real maximizedAppTopMargin
4250- property real nativeHeight
4251- property real nativeWidth
4252- property QtObject orientations
4253- property int shellOrientation
4254- property int shellOrientationAngle
4255- property bool spreadEnabled: true // If false, animations and right edge will be disabled
4256- property bool suspended
4257- // A Stage should paint a wallpaper etc over its full size but not use the margins for window placement
4258- property int leftMargin: 0
4259- property alias paintBackground: background.visible
4260- property bool oskEnabled: false
4261-
4262- // To be read from outside
4263- property var mainApp: null
4264- property int mainAppWindowOrientationAngle: 0
4265- property bool orientationChangesEnabled
4266- property int supportedOrientations: Qt.PortraitOrientation
4267- | Qt.LandscapeOrientation
4268- | Qt.InvertedPortraitOrientation
4269- | Qt.InvertedLandscapeOrientation
4270-
4271- property Item itemConfiningMouseCursor: null
4272-
4273-
4274- signal stageAboutToBeUnloaded
4275- signal itemSnapshotRequested(Item item)
4276-
4277- // Shared code for use in stage implementations
4278- GSettings {
4279- id: lifecycleExceptions
4280- schema.id: "com.canonical.qtmir"
4281- }
4282-
4283- function isExemptFromLifecycle(appId) {
4284- var shortAppId = appId.split('_')[0];
4285- for (var i = 0; i < lifecycleExceptions.lifecycleExemptAppids.length; i++) {
4286- if (shortAppId === lifecycleExceptions.lifecycleExemptAppids[i]) {
4287- return true;
4288- }
4289- }
4290- return false;
4291- }
4292-
4293- Rectangle {
4294- id: background
4295- color: "#060606"
4296- anchors.fill: parent
4297- }
4298-
4299- // shared Alt+F4 functionality
4300- function closeFocusedDelegate() {} // to be implemented by stages
4301-
4302- GlobalShortcut {
4303- shortcut: Qt.AltModifier|Qt.Key_F4
4304- onTriggered: closeFocusedDelegate()
4305- }
4306-}
4307
4308=== removed file 'qml/Stages/DesktopSpread.qml'
4309--- qml/Stages/DesktopSpread.qml 2016-06-15 14:08:18 +0000
4310+++ qml/Stages/DesktopSpread.qml 1970-01-01 00:00:00 +0000
4311@@ -1,576 +0,0 @@
4312-/*
4313- * Copyright (C) 2015-2016 Canonical, Ltd.
4314- *
4315- * This program is free software; you can redistribute it and/or modify
4316- * it under the terms of the GNU General Public License as published by
4317- * the Free Software Foundation; version 3.
4318- *
4319- * This program is distributed in the hope that it will be useful,
4320- * but WITHOUT ANY WARRANTY; without even the implied warranty of
4321- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4322- * GNU General Public License for more details.
4323- *
4324- * You should have received a copy of the GNU General Public License
4325- * along with this program. If not, see <http://www.gnu.org/licenses/>.
4326- */
4327-
4328-import QtQuick 2.4
4329-import QtQuick.Layouts 1.1
4330-import Ubuntu.Components 1.3
4331-import Ubuntu.Gestures 0.1
4332-import Unity.Application 0.1
4333-import "../Components"
4334-import Utils 0.1
4335-
4336-FocusScope {
4337- id: root
4338-
4339- property bool altTabPressed: false
4340- property Item workspace: null
4341-
4342- readonly property alias ready: blurLayer.ready
4343- readonly property alias highlightedIndex: spreadRepeater.highlightedIndex
4344-
4345- signal playFocusAnimation(int index)
4346-
4347- function show() {
4348- spreadContainer.animateIn = true;
4349- root.state = "altTab";
4350- }
4351-
4352- onFocusChanged: {
4353- // When the spread comes active, we want to keep focus to the input handler below
4354- // Make sure nothing inside the ApplicationWindow grabs our focus!
4355- if (focus) {
4356- forceActiveFocus();
4357- }
4358- }
4359-
4360- Keys.onPressed: {
4361- switch (event.key) {
4362- case Qt.Key_Left:
4363- case Qt.Key_Backtab:
4364- selectPrevious(event.isAutoRepeat)
4365- event.accepted = true;
4366- break;
4367- case Qt.Key_Right:
4368- case Qt.Key_Tab:
4369- selectNext(event.isAutoRepeat)
4370- event.accepted = true;
4371- break;
4372- case Qt.Key_Escape:
4373- spreadRepeater.highlightedIndex = -1
4374- // Falling through intentionally
4375- case Qt.Key_Enter:
4376- case Qt.Key_Return:
4377- case Qt.Key_Space:
4378- root.state = ""
4379- event.accepted = true;
4380- }
4381- }
4382-
4383- function selectNext(isAutoRepeat) {
4384- if (isAutoRepeat && spreadRepeater.highlightedIndex >= topLevelSurfaceList.count -1) {
4385- return; // AutoRepeat is not allowed to wrap around
4386- }
4387-
4388- spreadRepeater.highlightedIndex = (spreadRepeater.highlightedIndex + 1) % topLevelSurfaceList.count;
4389- var newContentX = ((spreadFlickable.contentWidth) / (topLevelSurfaceList.count + 1)) * Math.max(0, Math.min(topLevelSurfaceList.count - 5, spreadRepeater.highlightedIndex - 3));
4390- if (spreadFlickable.contentX < newContentX || spreadRepeater.highlightedIndex == 0) {
4391- spreadFlickable.snapTo(newContentX)
4392- }
4393- }
4394-
4395- function selectPrevious(isAutoRepeat) {
4396- if (isAutoRepeat && spreadRepeater.highlightedIndex == 0) {
4397- return; // AutoRepeat is not allowed to wrap around
4398- }
4399-
4400- var newIndex = spreadRepeater.highlightedIndex - 1 >= 0 ? spreadRepeater.highlightedIndex - 1 : topLevelSurfaceList.count - 1;
4401- spreadRepeater.highlightedIndex = newIndex;
4402- var newContentX = ((spreadFlickable.contentWidth) / (topLevelSurfaceList.count + 1)) * Math.max(0, Math.min(topLevelSurfaceList.count - 5, spreadRepeater.highlightedIndex - 1));
4403- if (spreadFlickable.contentX > newContentX || newIndex == topLevelSurfaceList.count -1) {
4404- spreadFlickable.snapTo(newContentX)
4405- }
4406- }
4407-
4408- function focusSelected() {
4409- if (spreadRepeater.highlightedIndex != -1) {
4410- if (spreadContainer.visible) {
4411- root.playFocusAnimation(spreadRepeater.highlightedIndex)
4412- }
4413- var surface = topLevelSurfaceList.surfaceAt(spreadRepeater.highlightedIndex);
4414- surface.requestFocus();
4415- }
4416- }
4417-
4418- function cancel() {
4419- spreadRepeater.highlightedIndex = -1;
4420- state = ""
4421- }
4422-
4423- BlurLayer {
4424- id: blurLayer
4425- anchors.fill: parent
4426- source: root.workspace
4427- visible: false
4428- }
4429-
4430- Rectangle {
4431- id: spreadBackground
4432- anchors.fill: parent
4433- color: "#B2000000"
4434- visible: false
4435- opacity: visible ? 1 : 0
4436- Behavior on opacity {
4437- UbuntuNumberAnimation { duration: UbuntuAnimation.SnapDuration }
4438- }
4439- }
4440-
4441- MouseArea {
4442- id: eventEater
4443- anchors.fill: parent
4444- visible: spreadBackground.visible
4445- enabled: visible
4446- acceptedButtons: Qt.AllButtons
4447- onWheel: wheel.accepted = true;
4448- }
4449-
4450- Item {
4451- id: spreadContainer
4452- objectName: "spreadContainer"
4453- anchors.fill: parent
4454- visible: false
4455-
4456- property bool animateIn: false
4457-
4458- Repeater {
4459- id: spreadRepeater
4460- objectName: "spreadRepeater"
4461- model: topLevelSurfaceList
4462-
4463- property int highlightedIndex: -1
4464- property int closingIndex: -1
4465-
4466- function indexOf(delegateItem) {
4467- for (var i = 0; i < spreadRepeater.count; i++) {
4468- if (spreadRepeater.itemAt(i) === delegateItem) {
4469- return i;
4470- }
4471- }
4472- return -1;
4473- }
4474-
4475- delegate: Item {
4476- id: spreadDelegate
4477- objectName: "spreadDelegate"
4478- width: units.gu(20)
4479- height: units.gu(20)
4480-
4481- property real angle: 0
4482- property real itemScale: 1
4483- property int itemScaleOriginX: 0
4484- property int itemScaleOriginY: 0
4485-
4486- readonly property string windowTitle: clippedSpreadDelegate.window.title
4487-
4488- Behavior on x {
4489- id: closeBehavior
4490- enabled: spreadRepeater.closingIndex >= 0
4491- UbuntuNumberAnimation {
4492- onRunningChanged: if (!running) spreadRepeater.closingIndex = -1
4493- }
4494- }
4495-
4496- DesktopSpreadDelegate {
4497- id: clippedSpreadDelegate
4498- objectName: "clippedSpreadDelegate"
4499- anchors.left: parent.left
4500- anchors.top: parent.top
4501- application: model.application
4502- surface: model.surface
4503- width: spreadMaths.spreadHeight
4504- height: spreadMaths.spreadHeight
4505-
4506- transform: [
4507- Scale {
4508- origin.x: itemScaleOriginX
4509- origin.y: itemScaleOriginY
4510- xScale: itemScale
4511- yScale: itemScale
4512- },
4513- Rotation {
4514- origin { x: 0; y: (clippedSpreadDelegate.height - (clippedSpreadDelegate.height * itemScale / 2)) }
4515- axis { x: 0; y: 1; z: 0 }
4516- angle: spreadDelegate.angle
4517- }
4518- ]
4519-
4520- MouseArea {
4521- id: spreadSelectArea
4522- anchors.fill: parent
4523- anchors.margins: -units.gu(2)
4524- enabled: false
4525- onClicked: {
4526- spreadRepeater.highlightedIndex = index;
4527- root.state = "";
4528- }
4529- }
4530- }
4531-
4532- SpreadMaths {
4533- id: spreadMaths
4534- flickable: spreadFlickable
4535- itemIndex: index
4536- totalItems: Math.max(6, topLevelSurfaceList.count)
4537- sceneHeight: root.height
4538- itemHeight: spreadDelegate.height
4539- }
4540-
4541- states: [
4542- State {
4543- name: "altTab"; when: root.state == "altTab" && spreadContainer.visible
4544- PropertyChanges {
4545- target: spreadDelegate
4546- x: spreadMaths.animatedX
4547- y: spreadMaths.animatedY + (spreadDelegate.height - clippedSpreadDelegate.height) - units.gu(2)
4548- width: spreadMaths.spreadHeight
4549- height: spreadMaths.sceneHeight
4550- angle: spreadMaths.animatedAngle
4551- itemScale: spreadMaths.scale
4552- itemScaleOriginY: clippedSpreadDelegate.height / 2;
4553- z: index
4554- visible: spreadMaths.itemVisible
4555- }
4556- PropertyChanges {
4557- target: clippedSpreadDelegate
4558- highlightShown: index == spreadRepeater.highlightedIndex
4559- state: "transformed"
4560- shadowOpacity: spreadMaths.shadowOpacity
4561- anchors.topMargin: units.gu(2)
4562- }
4563- PropertyChanges {
4564- target: tileInfo
4565- visible: true
4566- opacity: spreadMaths.tileInfoOpacity
4567- }
4568- PropertyChanges {
4569- target: spreadSelectArea
4570- enabled: true
4571- }
4572- }
4573- ]
4574- transitions: [
4575- Transition {
4576- from: ""
4577- to: "altTab"
4578- SequentialAnimation {
4579- ParallelAnimation {
4580- PropertyAction { target: spreadDelegate; properties: "y,height,width,angle,z,itemScale,itemScaleOriginY,visible" }
4581- PropertyAction { target: clippedSpreadDelegate; properties: "anchors.topMargin" }
4582- PropertyAnimation {
4583- target: spreadDelegate; properties: "x"
4584- from: root.width
4585- duration: spreadContainer.animateIn ? UbuntuAnimation.FastDuration :0
4586- easing: UbuntuAnimation.StandardEasing
4587- }
4588- UbuntuNumberAnimation { target: clippedSpreadDelegate; property: "shadowOpacity"; from: 0; to: spreadMaths.shadowOpacity; duration: spreadContainer.animateIn ? UbuntuAnimation.FastDuration : 0 }
4589- UbuntuNumberAnimation { target: tileInfo; property: "opacity"; from: 0; to: spreadMaths.tileInfoOpacity; duration: spreadContainer.animateIn ? UbuntuAnimation.FastDuration : 0 }
4590- }
4591- PropertyAction { target: spreadSelectArea; property: "enabled" }
4592- }
4593- }
4594- ]
4595-
4596- MouseArea {
4597- id: tileInfo
4598- objectName: "tileInfo"
4599- anchors {
4600- left: parent.left
4601- top: clippedSpreadDelegate.bottom
4602- topMargin: ((spreadMaths.sceneHeight - spreadDelegate.y) - clippedSpreadDelegate.height) * 0.2
4603- }
4604- property int nextItemX: spreadRepeater.count > index + 1 ? spreadRepeater.itemAt(index + 1).x : spreadDelegate.x + units.gu(30)
4605- width: Math.min(units.gu(30), nextItemX - spreadDelegate.x)
4606- height: titleInfoColumn.height
4607- visible: false
4608- hoverEnabled: true
4609-
4610- onContainsMouseChanged: {
4611- if (containsMouse) {
4612- spreadRepeater.highlightedIndex = index
4613- }
4614- }
4615-
4616- onClicked: {
4617- root.state = ""
4618- }
4619-
4620- ColumnLayout {
4621- id: titleInfoColumn
4622- anchors { left: parent.left; top: parent.top; right: parent.right }
4623- spacing: units.gu(1)
4624-
4625- UbuntuShapeForItem {
4626- Layout.preferredHeight: Math.min(units.gu(6), root.height * .05)
4627- Layout.preferredWidth: height * 8 / 7.6
4628- image: Image {
4629- anchors.fill: parent
4630- source: model.application.icon
4631- Rectangle {
4632- anchors.fill: parent
4633- color: "black"
4634- opacity: clippedSpreadDelegate.highlightShown ? 0 : .1
4635- Behavior on opacity {
4636- UbuntuNumberAnimation { duration: UbuntuAnimation.SnapDuration }
4637- }
4638- }
4639- }
4640- }
4641- Label {
4642- Layout.fillWidth: true
4643- Layout.preferredHeight: units.gu(6)
4644- text: model.application ? model.application.name : spreadDelegate.windowTitle
4645- wrapMode: Text.WordWrap
4646- elide: Text.ElideRight
4647- maximumLineCount: 2
4648- }
4649- }
4650- }
4651-
4652- Image {
4653- id: closeImage
4654- anchors { left: parent.left; top: parent.top; leftMargin: -height / 2; topMargin: -height / 2 + spreadMaths.closeIconOffset + units.gu(2) }
4655- source: "graphics/window-close.svg"
4656- readonly property var mousePos: hoverMouseArea.mapToItem(spreadDelegate, hoverMouseArea.mouseX, hoverMouseArea.mouseY)
4657- visible: index == spreadRepeater.highlightedIndex
4658- && mousePos.y < (clippedSpreadDelegate.height / 3)
4659- && mousePos.y > -units.gu(4)
4660- && mousePos.x > -units.gu(4)
4661- && mousePos.x < (clippedSpreadDelegate.width * 2 / 3)
4662- height: units.gu(1.5)
4663- width: height
4664- sourceSize.width: width
4665- sourceSize.height: height
4666-
4667- MouseArea {
4668- id: closeMouseArea
4669- objectName: "closeMouseArea"
4670- anchors.fill: closeImage
4671- anchors.margins: -units.gu(2)
4672- onClicked: {
4673- spreadRepeater.closingIndex = index;
4674- model.surface.close();
4675- }
4676- }
4677- }
4678- }
4679- }
4680- }
4681-
4682-
4683- MouseArea {
4684- id: hoverMouseArea
4685- objectName: "hoverMouseArea"
4686- anchors.fill: spreadContainer
4687- propagateComposedEvents: true
4688- hoverEnabled: true
4689- enabled: false
4690- visible: enabled
4691-
4692- property int scrollAreaWidth: root.width / 3
4693- property bool progressiveScrollingEnabled: false
4694-
4695- onMouseXChanged: {
4696- mouse.accepted = false
4697-
4698- if (hoverMouseArea.pressed) {
4699- return;
4700- }
4701-
4702- // Find the hovered item and mark it active
4703- var mapped = mapToItem(spreadContainer, hoverMouseArea.mouseX, hoverMouseArea.mouseY)
4704- var itemUnder = spreadContainer.childAt(mapped.x, mapped.y)
4705- if (itemUnder) {
4706- mapped = mapToItem(itemUnder, hoverMouseArea.mouseX, hoverMouseArea.mouseY)
4707- var delegateChild = itemUnder.childAt(mapped.x, mapped.y)
4708- if (delegateChild && (delegateChild.objectName === "clippedSpreadDelegate" || delegateChild.objectName === "tileInfo")) {
4709- spreadRepeater.highlightedIndex = spreadRepeater.indexOf(itemUnder)
4710- }
4711- }
4712-
4713- if (spreadFlickable.contentWidth > spreadFlickable.minContentWidth) {
4714- var margins = spreadFlickable.width * 0.05;
4715-
4716- if (!progressiveScrollingEnabled && mouseX < spreadFlickable.width - scrollAreaWidth) {
4717- progressiveScrollingEnabled = true
4718- }
4719-
4720- // do we need to scroll?
4721- if (mouseX < scrollAreaWidth + margins) {
4722- var progress = Math.min(1, (scrollAreaWidth + margins - mouseX) / (scrollAreaWidth - margins));
4723- var contentX = (1 - progress) * (spreadFlickable.contentWidth - spreadFlickable.width)
4724- spreadFlickable.contentX = Math.max(0, Math.min(spreadFlickable.contentX, contentX))
4725- }
4726- if (mouseX > spreadFlickable.width - scrollAreaWidth && progressiveScrollingEnabled) {
4727- var progress = Math.min(1, (mouseX - (spreadFlickable.width - scrollAreaWidth)) / (scrollAreaWidth - margins))
4728- var contentX = progress * (spreadFlickable.contentWidth - spreadFlickable.width)
4729- spreadFlickable.contentX = Math.min(spreadFlickable.contentWidth - spreadFlickable.width, Math.max(spreadFlickable.contentX, contentX))
4730- }
4731- }
4732- }
4733- onPressed: mouse.accepted = false
4734- }
4735-
4736- FloatingFlickable {
4737- id: spreadFlickable
4738- objectName: "spreadFlickable"
4739- anchors.fill: parent
4740- property int minContentWidth: 6 * Math.min(height / 4, width / 5)
4741- contentWidth: Math.max(6, topLevelSurfaceList.count) * Math.min(height / 4, width / 5)
4742- enabled: false
4743-
4744- function snapTo(contentX) {
4745- snapAnimation.stop();
4746- snapAnimation.to = contentX
4747- snapAnimation.start();
4748- }
4749-
4750- UbuntuNumberAnimation {
4751- id: snapAnimation
4752- target: spreadFlickable
4753- property: "contentX"
4754- }
4755- }
4756-
4757- Item {
4758- id: workspaceSelector
4759- anchors {
4760- left: parent.left
4761- top: parent.top
4762- right: parent.right
4763- topMargin: units.gu(3.5)
4764- }
4765- height: root.height * 0.25
4766- visible: false
4767-
4768- RowLayout {
4769- anchors.fill: parent
4770- spacing: units.gu(1)
4771- Item { Layout.fillWidth: true }
4772- Repeater {
4773- model: 1 // TODO: will be a workspacemodel in the future
4774- Item {
4775- Layout.fillHeight: true
4776- Layout.preferredWidth: ((height - units.gu(6)) * root.width / root.height)
4777- Image {
4778- source: root.background
4779- anchors {
4780- left: parent.left
4781- right: parent.right
4782- verticalCenter: parent.verticalCenter
4783- }
4784- height: parent.height * 0.75
4785-
4786- ShaderEffect {
4787- anchors.fill: parent
4788-
4789- property var source: ShaderEffectSource {
4790- id: shaderEffectSource
4791- sourceItem: root.workspace
4792- }
4793-
4794- fragmentShader: "
4795- varying highp vec2 qt_TexCoord0;
4796- uniform sampler2D source;
4797- void main(void)
4798- {
4799- highp vec4 sourceColor = texture2D(source, qt_TexCoord0);
4800- gl_FragColor = sourceColor;
4801- }"
4802- }
4803- }
4804-
4805- // TODO: This is the bar for the currently selected workspace
4806- // Enable this once the workspace stuff is implemented
4807- // Rectangle {
4808- // anchors { left: parent.left; right: parent.right; bottom: parent.bottom }
4809- // height: units.dp(2)
4810- // color: theme.palette.normal.focus
4811- // visible: index == 0 // TODO: should be active workspace index
4812- // }
4813- }
4814-
4815- }
4816- // TODO: This is the "new workspace" button. Enable this once workspaces are implemented
4817- // Item {
4818- // Layout.fillHeight: true
4819- // Layout.preferredWidth: ((height - units.gu(6)) * root.width / root.height)
4820- // Rectangle {
4821- // anchors {
4822- // left: parent.left
4823- // right: parent.right
4824- // verticalCenter: parent.verticalCenter
4825- // }
4826- // height: parent.height * 0.75
4827- // color: "#22ffffff"
4828-
4829- // Label {
4830- // anchors.centerIn: parent
4831- // font.pixelSize: parent.height / 2
4832- // text: "+"
4833- // }
4834- // }
4835- // }
4836- Item { Layout.fillWidth: true }
4837- }
4838- }
4839-
4840- Label {
4841- id: currentSelectedLabel
4842- anchors { bottom: parent.bottom; bottomMargin: root.height * 0.625; horizontalCenter: parent.horizontalCenter }
4843- text: spreadRepeater.highlightedIndex >= 0 ? spreadRepeater.itemAt(spreadRepeater.highlightedIndex).windowTitle: ""
4844- visible: false
4845- fontSize: "large"
4846- }
4847-
4848- states: [
4849- State {
4850- name: "altTab"; when: root.altTabPressed
4851- PropertyChanges { target: blurLayer; saturation: 0.8; blurRadius: 60; visible: true }
4852- PropertyChanges { target: workspaceSelector; visible: true }
4853- PropertyChanges { target: spreadContainer; visible: true }
4854- PropertyChanges { target: spreadFlickable; enabled: spreadFlickable.contentWidth > spreadFlickable.minContentWidth }
4855- PropertyChanges { target: currentSelectedLabel; visible: true }
4856- PropertyChanges { target: spreadBackground; visible: true }
4857- PropertyChanges { target: hoverMouseArea; enabled: true }
4858- }
4859- ]
4860- transitions: [
4861- Transition {
4862- from: "*"
4863- to: "altTab"
4864- SequentialAnimation {
4865- PropertyAction { target: spreadRepeater; property: "highlightedIndex"; value: Math.min(topLevelSurfaceList.count - 1, 1) }
4866- PauseAnimation { duration: spreadContainer.animateIn ? 0 : 140 }
4867- PropertyAction { target: workspaceSelector; property: "visible" }
4868- PropertyAction { target: spreadContainer; property: "visible" }
4869- ParallelAnimation {
4870- UbuntuNumberAnimation { target: blurLayer; properties: "saturation,blurRadius"; duration: UbuntuAnimation.SnapDuration }
4871- PropertyAction { target: spreadFlickable; property: "visible" }
4872- PropertyAction { targets: [currentSelectedLabel,spreadBackground]; property: "visible" }
4873- PropertyAction { target: spreadFlickable; property: "contentX"; value: 0 }
4874- }
4875- PropertyAction { target: hoverMouseArea; properties: "enabled,progressiveScrollingEnabled"; value: false }
4876- }
4877- },
4878- Transition {
4879- from: "*"
4880- to: "*"
4881- PropertyAnimation { property: "opacity" }
4882- ScriptAction { script: { root.focusSelected() } }
4883- PropertyAction { target: spreadRepeater; property: "highlightedIndex"; value: -1 }
4884- PropertyAction { target: spreadContainer; property: "animateIn"; value: false }
4885- }
4886- ]
4887-}
4888
4889=== removed file 'qml/Stages/DesktopSpreadDelegate.qml'
4890--- qml/Stages/DesktopSpreadDelegate.qml 2016-05-17 20:46:51 +0000
4891+++ qml/Stages/DesktopSpreadDelegate.qml 1970-01-01 00:00:00 +0000
4892@@ -1,126 +0,0 @@
4893-/*
4894- * Copyright (C) 2014-2016 Canonical, Ltd.
4895- *
4896- * This program is free software; you can redistribute it and/or modify
4897- * it under the terms of the GNU General Public License as published by
4898- * the Free Software Foundation; version 3.
4899- *
4900- * This program is distributed in the hope that it will be useful,
4901- * but WITHOUT ANY WARRANTY; without even the implied warranty of
4902- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4903- * GNU General Public License for more details.
4904- *
4905- * You should have received a copy of the GNU General Public License
4906- * along with this program. If not, see <http://www.gnu.org/licenses/>.
4907- *
4908- * Authors: Michael Zanetti <michael.zanetti@canonical.com>
4909- */
4910-
4911-import QtQuick 2.4
4912-import Ubuntu.Components 1.3
4913-import Unity.Application 0.1
4914-
4915-Item {
4916- id: root
4917-
4918- property alias window: applicationWindow
4919- property alias application: applicationWindow.application
4920- property alias surface: applicationWindow.surface
4921-
4922- property bool highlightShown: false
4923- property real shadowOpacity: 1
4924-
4925- property int windowWidth: surface ? surface.size.width : 0
4926- property int windowHeight: surface ? surface.size.height : 0
4927-
4928- state: "normal"
4929- states: [
4930- State {
4931- name: "normal"
4932- PropertyChanges {
4933- target: root
4934- width: windowWidth
4935- height: windowHeight
4936- }
4937- },
4938- State {
4939- name: "transformed"
4940- PropertyChanges {
4941- target: applicationWindow
4942- itemScale: Math.max(root.width / root.windowWidth, root.height / root.windowHeight)
4943- interactive: false
4944- }
4945- PropertyChanges {
4946- target: clipper
4947- clip: true
4948- }
4949- }
4950- ]
4951-
4952- scale: highlightShown ? 1.025 : 1
4953- Behavior on scale {
4954- UbuntuNumberAnimation { duration: UbuntuAnimation.SnapDuration }
4955- }
4956-
4957- BorderImage {
4958- anchors {
4959- fill: root
4960- margins: -units.gu(2)
4961- }
4962- source: "graphics/dropshadow2gu.sci"
4963- opacity: root.shadowOpacity * .3
4964- }
4965-
4966- Rectangle {
4967- id: selectionHighlight
4968- anchors.fill: parent
4969- anchors.margins: -units.gu(1)
4970- color: "white"
4971- opacity: highlightShown ? 0.55 : 0
4972- antialiasing: true
4973- }
4974-
4975- Rectangle {
4976- anchors { left: selectionHighlight.left; right: selectionHighlight.right; bottom: selectionHighlight.bottom; }
4977- height: units.dp(2)
4978- color: theme.palette.normal.focus
4979- visible: root.highlightShown
4980- antialiasing: true
4981- }
4982-
4983- Item {
4984- id: clipper
4985- anchors.fill: parent
4986-
4987- ApplicationWindow {
4988- id: applicationWindow
4989- objectName: application ? "appWindow_" + application.appId : "appWindow_null"
4990- anchors.top: parent.top
4991- anchors.topMargin: 0
4992- anchors.left: parent.left
4993- width: root.windowWidth
4994- height: root.windowHeight
4995- interactive: false
4996- resizeSurface: false
4997- focus: false
4998-
4999- property real itemScale: 1
5000- transform: [
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches