Merge lp:~unity-team/unity8/shellRotation into lp:unity8

Proposed by kevin gunn on 2015-02-03
Status: Superseded
Proposed branch: lp:~unity-team/unity8/shellRotation
Merge into: lp:unity8
Diff against target: 6882 lines (+4310/-659)
74 files modified
CMakeLists.txt (+2/-0)
data/unity8-dash.desktop.in (+1/-0)
debian/changelog (+6/-0)
debian/control (+5/-4)
debian/unity8.install (+3/-0)
plugins/Greeter/Unity/Launcher/CMakeLists.txt (+1/-1)
plugins/Unity/Launcher/CMakeLists.txt (+1/-1)
plugins/Utils/CMakeLists.txt (+1/-0)
plugins/Utils/plugin.cpp (+5/-2)
plugins/Utils/windowscreenshotprovider.cpp (+59/-0)
plugins/Utils/windowscreenshotprovider.h (+31/-0)
qml/CMakeLists.txt (+1/-0)
qml/Components/WindowScreenshot.qml (+35/-0)
qml/Dash/graphics/phone/screenshots/gmail-webapp.svg (+343/-0)
qml/Dash/graphics/phone/screenshots/ubuntu-weather-app.svg (+201/-0)
qml/DeviceConfiguration.qml (+81/-0)
qml/Greeter/Greeter.qml (+2/-0)
qml/Greeter/NarrowView.qml (+1/-0)
qml/Greeter/WideView.qml (+1/-0)
qml/OrientedShell.qml (+182/-0)
qml/Panel/Panel.qml (+9/-0)
qml/Rotation/HalfLoopRotationAnimation.qml (+46/-0)
qml/Rotation/ImmediateRotationAction.qml (+45/-0)
qml/Rotation/NinetyRotationAnimation.qml (+90/-0)
qml/Rotation/RotationStates.qml (+271/-0)
qml/Shell.qml (+110/-49)
qml/Stages/ApplicationWindow.qml (+53/-18)
qml/Stages/DesktopStage.qml (+23/-0)
qml/Stages/OrientationChangeAnimation.qml (+243/-0)
qml/Stages/PhoneStage.qml (+141/-41)
qml/Stages/SessionContainer.qml (+2/-8)
qml/Stages/SpreadDelegate.qml (+242/-25)
qml/Stages/SurfaceContainer.qml (+2/-2)
qml/Stages/TabletStage.qml (+154/-20)
qml/Stages/TransformedTabletSpreadDelegate.qml (+5/-2)
run.sh (+1/-1)
src/ApplicationArguments.cpp (+22/-0)
src/ApplicationArguments.h (+13/-9)
src/CMakeLists.txt (+7/-7)
src/Dash/CMakeLists.txt (+7/-1)
src/Dash/main.cpp (+1/-1)
src/UnityCommandLineParser.cpp (+118/-0)
src/UnityCommandLineParser.h (+50/-0)
src/main.cpp (+18/-70)
tests/mocks/Unity/Application/ApplicationInfo.cpp (+45/-4)
tests/mocks/Unity/Application/ApplicationInfo.h (+9/-1)
tests/mocks/Unity/Application/ApplicationManager.cpp (+39/-2)
tests/mocks/Unity/Application/CMakeLists.txt (+4/-1)
tests/mocks/Unity/Application/MirSurfaceItem.cpp (+12/-29)
tests/mocks/Unity/Application/MirSurfaceItem.h (+29/-29)
tests/mocks/Unity/Application/MirSurfaceItem.qml (+12/-14)
tests/mocks/Unity/Application/SurfaceManager.cpp (+4/-34)
tests/mocks/Unity/Application/SurfaceManager.h (+2/-5)
tests/mocks/Unity/Application/UbuntuKeyboardInfo.cpp (+33/-1)
tests/mocks/Unity/Application/UbuntuKeyboardInfo.h (+11/-5)
tests/mocks/Unity/Application/VirtualKeyboard.cpp (+44/-0)
tests/mocks/Unity/Application/VirtualKeyboard.h (+42/-0)
tests/mocks/Unity/Application/VirtualKeyboard.qml (+7/-1)
tests/mocks/Unity/Launcher/MockLauncherModel.cpp (+3/-1)
tests/plugins/Greeter/Unity/Launcher/CMakeLists.txt (+1/-1)
tests/plugins/Unity/Launcher/CMakeLists.txt (+1/-1)
tests/plugins/Unity/Launcher/launchermodeltest.cpp (+3/-1)
tests/qmltests/CMakeLists.txt (+1/-0)
tests/qmltests/Panel/tst_IndicatorsMenu.qml (+0/-2)
tests/qmltests/Panel/tst_Panel.qml (+0/-2)
tests/qmltests/Stages/tst_ApplicationWindow.qml (+14/-23)
tests/qmltests/Stages/tst_PhoneStage.qml (+5/-58)
tests/qmltests/Stages/tst_SessionContainer.qml (+1/-64)
tests/qmltests/Stages/tst_SpreadDelegate.qml (+173/-38)
tests/qmltests/Stages/tst_TabletStage.qml (+51/-0)
tests/qmltests/tst_OrientedShell.qml (+1097/-0)
tests/qmltests/tst_Shell.qml (+15/-69)
tests/qmltests/tst_ShellWithPin.qml (+6/-10)
tests/utils/modules/Unity/Test/UnityTestCase.qml (+11/-1)
To merge this branch: bzr merge lp:~unity-team/unity8/shellRotation
Reviewer Review Type Date Requested Status
PS Jenkins bot continuous-integration 2015-03-04 Needs Fixing on 2015-04-15
Michael Zanetti (community) 2015-02-03 Needs Fixing on 2015-03-05
Review via email: mp+248400@code.launchpad.net

This proposal has been superseded by a proposal from 2015-04-16.

Commit Message

Shell rotation

Description of the Change

* Are there any related MPs required for this MP to build/function as expected? Please list.
It's all in this PPA: https://launchpad.net/~unity-team/+archive/ubuntu/demo-stuff

https://code.launchpad.net/~dandrader/qtmir/supportedOrientations/+merge/242213
https://code.launchpad.net/~dandrader/qtubuntu/shellRotation/+merge/242215
https://code.launchpad.net/~phablet-team/ubuntu-keyboard/shellRotation/+merge/248399
https://code.launchpad.net/~dandrader/unity-api/shellRotation/+merge/242212

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

* Did you make sure that your branch does not contain spurious tags?
Yes

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

* If you changed the UI, has there been a design review?
Not sure, I guess they seen it by now. At least it's following the design spec for that.

To post a comment you must log in.
lp:~unity-team/unity8/shellRotation updated on 2015-03-04
1651. By CI Train Bot Account on 2015-03-03

Resync trunk.

1652. By Launchpad Translations on behalf of unity-team on 2015-03-04

Launchpad automatic translations update.

Albert Astals Cid (aacid) wrote :

Text conflict in tests/mocks/Unity/Application/ApplicationManager.h
Text conflict in tests/qmltests/tst_Shell.qml
2 conflicts encountered.

lp:~unity-team/unity8/shellRotation updated on 2015-03-04
1653. By Daniel d'Andrada on 2015-03-04

Shell rotation

Michael Zanetti (mzanetti) wrote :

1202 + d.transitioning = true;

I don't really like the fact that all the rotation animations reach out of context and operate on another object's "d" object. Can we make that more readable?

review: Needs Fixing
Michael Zanetti (mzanetti) wrote :

1627 + * Copyright (C) 2013-2014 Canonical, Ltd.

You probably want to do another round of updating those headers to 2015

review: Needs Fixing
lp:~unity-team/unity8/shellRotation updated on 2015-03-05
1654. By Daniel d'Andrada on 2015-03-05

Avoid having Rotation animations accessing context from parent

Make things more explicit

Daniel d'Andrada (dandrader) wrote :

On 05/03/15 08:22, Michael Zanetti wrote:
> Review: Needs Fixing
>
> 1202 + d.transitioning = true;
>
> I don't really like the fact that all the rotation animations reach out of context and operate on another object's "d" object. Can we make that more readable?
Done.

lp:~unity-team/unity8/shellRotation updated on 2015-03-05
1655. By Daniel d'Andrada on 2015-03-05

Update copyright year of all created or modified files

Daniel d'Andrada (dandrader) wrote :

On 05/03/15 08:45, Michael Zanetti wrote:
> Review: Needs Fixing
>
> 1627 + * Copyright (C) 2013-2014 Canonical, Ltd.
>
> You probably want to do another round of updating those headers to 2015
Done.

Michael Zanetti (mzanetti) wrote :

please don't rebase this branch any more. there are branches building on top of that which throw > 30 conflicts each time you rebase... thanks.

Daniel d'Andrada (dandrader) wrote :

On 09/03/15 08:54, Michael Zanetti wrote:
> please don't rebase this branch any more. there are branches building on top of that which throw > 30 conflicts each time you rebase... thanks.
Oh, that sucks. I thought bzr would be smarter than that. Sorry.

lp:~unity-team/unity8/shellRotation updated on 2015-03-10
1656. By Daniel d'Andrada on 2015-03-10

Remove unused signal

lp:~unity-team/unity8/shellRotation updated on 2015-03-11
1657. By Daniel d'Andrada on 2015-03-11

Fill the fake UbuntuKeyboardInfo with correct values

lp:~unity-team/unity8/shellRotation updated on 2015-03-11
1658. By Daniel d'Andrada on 2015-03-11

Clean up Unity.Application mocks regarging input method

Albert Astals Cid (aacid) wrote :

Text conflict in src/main.cpp
Text conflict in tests/qmltests/tst_Shell.qml
Contents conflict in tests/qmltests/tst_TabletShell.qml

lp:~unity-team/unity8/shellRotation updated on 2015-03-19
1659. By Daniel d'Andrada on 2015-03-19

Merge trunk

[ Albert Astals Cid ]
* Add some context to tr calls (LP: #1431497)
* Require binaries and .pc files we call from code
* Test: More stubborn flick to the end
[ Andrea Cimitan ]
* Refactor PreviewOverlay to fix weird zoom out/in animations when
  previewing images from the Previews
[ CI Train Bot ]
* Resync trunk.
[ Charles Kerr ]
* Re-enable a rotation lock test now that the bug that broke that test
  has been fixed. (LP: #1410915)
[ Daniel d'Andrada ]
* Darkened area behind indicators menu should eat input until it fully
  disappears (LP: #1417967)
* DesktopStage - fix focus switch when user taps on window (LP:
  #1431325)
* Fix warnings when launching tutorial
* Make MouseTouchAdaptor controllable from within QML
* Make tst_Shell absorb tst_TabletShell
[ Leo Arias ]
* Changed the autopilot dependencies so they do not require qt4. (LP:
  #1429158)
* Drop the support for python2 in autopilot tests. (LP: #1429163)
* Stop using the deprecated toolkit emulators namespace in autopilot
  tests. (LP: #1341681)
[ Michael Terry ]
* Don't close wizard & edge tutorial when the unity8-dash closes (LP:
  #1425484)
* Don't let the wizard sit indefinitely, waiting for a wizard page to
  finish preparing itself. (LP: #1425737)
* Fix two broken qmluitest files by waiting for everything to settle
  before starting the tests.
* Only call unlockAllModems once the wizard is done. (LP: #1425161)
  (LP: #1425161)
* When we are locking the user out from too many login failures,
  notice when time passes even if the device is suspended. (LP:
  #1396817) (LP: #1396817)
[ Michael Zanetti ]
* Add a mouse area to the indicators panel so we can open them by
  clicking. (LP: #1417650)
* fix launcher not reacting to first click when revealed by mouse
  hover, add tests
* performance improvements (LP: #1430233, #1425087)
[ Michał Sawicz ]
* Remove the activity indicator from tests
* Use targets instead of custom ld arguments for linking
[ Mirco Müller ]
* Updated the visuals of the SwipeToAct-widget for incoming-call snap-
  decision notifications according to new design-spec.
* Updated the visuals of the SwipeToAct-widget for incoming-call snap-
  decision notifications according to new design-spec.
* No-change rebuild against Qt 5.4.1.

1660. By Daniel d'Andrada on 2015-03-19

The GenericApp approach doesn't work

Daniel d'Andrada (dandrader) wrote :

On 19/03/2015 05:14, Albert Astals Cid wrote:
> Text conflict in src/main.cpp
> Text conflict in tests/qmltests/tst_Shell.qml
> Contents conflict in tests/qmltests/tst_TabletShell.qml
Fixed.

lp:~unity-team/unity8/shellRotation updated on 2015-03-20
1661. By Daniel d'Andrada on 2015-03-20

Fix tst_ShellWithPin.test_emergencyDialerLockOut

1662. By Daniel d'Andrada on 2015-03-20

Remove unused code

1663. By Daniel d'Andrada on 2015-03-20

Undo all tst_Showable changes

it's unrelated to shellRotation

lp:~unity-team/unity8/shellRotation updated on 2015-04-10
1664. By Michał Sawicz on 2015-04-10

Update application API versions

Albert Astals Cid (aacid) wrote :

Text conflict in plugins/Utils/plugin.cpp
Text conflict in qml/Shell.qml
Text conflict in qml/Stages/SurfaceContainer.qml
Text conflict in src/main.cpp
Conflict adding file tests/mocks/Unity/Application/MirSurfaceItem.cpp. Moved existing file to tests/mocks/Unity/Application/MirSurfaceItem.cpp.moved.
Conflict adding file tests/mocks/Unity/Application/MirSurfaceItem.h. Moved existing file to tests/mocks/Unity/Application/MirSurfaceItem.h.moved.
Text conflict in tests/qmltests/tst_Shell.qml
7 conflicts encountered.ly phase:adding file 0/89492

lp:~unity-team/unity8/shellRotation updated on 2015-04-14
1665. By Daniel d'Andrada on 2015-04-14

Merge trunk

[ Albert Astals Cid ]
* Focus the shutdown dialog (LP: #1417991)
* Make url-dispatching scope activation when the dash is not on the
  main scopes (LP: #1364306)
* We use autopilot3 now
[ CI Train Bot ]
* New rebuild forced.
* Resync trunk. added: po/or.po
[ Daniel d'Andrada ]
* Make tst_PreviewListView and tst_GenericScopeView work in out-of-
  source builds
* MouseArea that shows the indicators panel should cover the
  indicators bar only (LP: #1439318)
* Surface gets active focus also with mouse clicks
[ Josh Arenson ]
* Add a mode option to unity8 for selecting greeter mode in the future
* Remove PkgConfig include from Launcher plugin to fix cross-compile
  (LP: #1437702)
[ Leo Arias ]
* Fixed the check for string in the lock screen test. (LP: #1434518)
[ Michael Terry ]
* Make sure the edge tutorial is destroyed when we receive a call
  during the wizard. (LP: #1436349)
* Skip parts of the edge tutorial that require a touch device (like
  spread and bottom edge). (LP: #1434712)
[ Michael Zanetti ]
* Don't hide stages just because they're empty (LP: #1439615)
* [Launcher] fix bug where an item would disappear even though the app
  is running (LP: #1438172)
[ Nick Dedekind ]
* Fixed autopilot test failures related to udev input failure for
  power button.
* Made improvements for laggy indicator backends (lp#1390136). (LP:
  #1390136)
[ Pete Woods ]
* GPS only goes active when the Dash is in the foreground (LP:
  #1434379)
[ handsome_feng<email address hidden> ]
* Modified the wrong time format in ScreenGrabber (LP: #1436006)
[ Albert Astals Cid ]
* Fix regression making pan not possible in Zoomable Image (LP:
  #1433506)
* Make sure m_firstVisibleIndex is correctly set after processing
  changeSet.removes (LP: #1433056)
* make pot_file
[ Daniel d'Andrada ]
* Don't show the rotating rect in "make tryFoo".
[ Michael Zanetti ]
* make pinlockscreen adjust better to larger displays

Daniel d'Andrada (dandrader) wrote :

On 14/04/15 04:21, Albert Astals Cid wrote:
> Text conflict in plugins/Utils/plugin.cpp
> Text conflict in qml/Shell.qml
> Text conflict in qml/Stages/SurfaceContainer.qml
> Text conflict in src/main.cpp
> Conflict adding file tests/mocks/Unity/Application/MirSurfaceItem.cpp. Moved existing file to tests/mocks/Unity/Application/MirSurfaceItem.cpp.moved.
> Conflict adding file tests/mocks/Unity/Application/MirSurfaceItem.h. Moved existing file to tests/mocks/Unity/Application/MirSurfaceItem.h.moved.
> Text conflict in tests/qmltests/tst_Shell.qml
> 7 conflicts encountered.ly phase:adding file 0/89492
>
Fixed. Thanks for spotting that.

lp:~unity-team/unity8/shellRotation updated on 2015-04-15
1666. By Michał Sawicz on 2015-04-15

Bump version for shell rotation

lp:~unity-team/unity8/shellRotation updated on 2015-05-21
1667. By Daniel d'Andrada on 2015-04-16

Merge lp:~dandrader/unity8/unityCommandLineParser

1668. By Daniel d'Andrada on 2015-04-20

Fix bad merge (add UnityCommandLineParser::deviceName back)

1669. By Daniel d'Andrada on 2015-04-22

Refactor TransformedSpreadDelegate scaling logic into something I can understand

1670. By Daniel d'Andrada on 2015-04-22

Ensure that windows in the spread stack perfectly on the left of the spread

1671. By Daniel d'Andrada on 2015-04-23

Merge trunk

[ Albert Astals Cid ]
* Compile with Qt 5.5 (LP: #1437238)
* Different way of top aligning labels when the other one in the row
  is multiline (LP: #1442085)
* make pot_file
[ Andrea Cimitan ]
* Set sourceSize for DashBackground.qml Image
[ CI Train Bot ]
* New rebuild forced.
* Resync trunk. added: po/sk.po
[ Daniel d'Andrada ]
* Move handling of command line options to a separate class
* Refactor tst_PhysicalKeysMapper.qml
[ Leo Arias ]
* For autopilot tests, use the device simulation scenarios from the
  toolkit.
[ Leonardo Arias Fonseca ]
* For autopilot tests, use the device simulation scenarios from the
  toolkit.
[ Michael Zanetti ]
* Make sure dnd mode is ended properly when drag gesture is cancelled
  (LP: #1444949)
[ Michał Sawicz ]
* Fix flake8 warnings (LP: #1444170)
* Move mock indicator service to unity8-fake-env, as it's a binary-
  dependent package.
[ Nick Dedekind ]
* Use asynchronous dbus requests for property updates. (LP: #1436982)

1672. By Daniel d'Andrada on 2015-04-23

Fix the positioning of the application window screenshot

1673. By Michael Zanetti on 2015-04-23

[ CI Train Bot ]
* New rebuild forced.
[ Daniel d'Andrada ]
* Tapping home key shows unity8-dash home added:
  plugins/Utils/ElapsedTimer.h plugins/Utils/HomeKeyWatcher.cpp
  plugins/Utils/HomeKeyWatcher.h plugins/Utils/Timer.cpp
  plugins/Utils/Timer.h tests/plugins/Utils/homekeywatchertest.cpp
[ Michał Sawicz ]
* Tapping home key shows unity8-dash home added:
  plugins/Utils/ElapsedTimer.h plugins/Utils/HomeKeyWatcher.cpp
  plugins/Utils/HomeKeyWatcher.h plugins/Utils/Timer.cpp
  plugins/Utils/Timer.h tests/plugins/Utils/homekeywatchertest.cpp

1674. By Michael Zanetti on 2015-04-23

fix bad merge

1675. By Daniel d'Andrada on 2015-04-24

Don't animate rotation when greeter is shown or while display is off

1676. By Daniel d'Andrada on 2015-04-28

Make all items in the spread have the very same size when stacked on the left side

1677. By Daniel d'Andrada on 2015-05-11

Merge trunk

[ Albert Astals Cid ]
* Make runtests fake a test error if make fails
* Make the test more stable
* Use dbus-test-runner instead of dbus-launch
* DirectionalDragArea: improvements & API grooming (LP: #1417920)
* Fix EdgeDragEvaluator when a drag can happen both ways
  (Direction.Horizontal)
[ Josh Arenson ]
* Remove panelHeight property as it is unused.
[ Leo Arias ]
* Initial clean up of the autopilot tests set up. Removed the touch
  device from the test case. Moved the restart of unity to a fixture.
  Removed the unused DragMixin. Updated the setUpClass to use
  process_helpers. Removed the workaround for bug #1238417, already
  fixed. Use the toolkit helper to set the testability environment
  variable. Fixed the indicators base class that was restarting unity
  twice. (LP: #1238417, #1447206)
* Use the base class from the toolkit in autopilot tests.
[ Michael Zanetti ]
* emit application-stop when we're going down (LP: #1326513)
[ Michał Sawicz ]
* UNITY_SCOPES_LIST is no more
[ handsome_feng<email address hidden> ]
* When click the favorite scope in Dash Manager , it just return to
  the corresponding scope page. (LP: #1447056)

1678. By Daniel d'Andrada on 2015-05-11

Improve test code

1679. By Daniel d'Andrada on 2015-05-12

Make -windowgeometry work again

1680. By Daniel d'Andrada on 2015-05-21

Merge trunk

[ Albert Astals Cid ]
* Add overrides to override functions
* Implement "rating-edit" preview widget (LP: #1318144)
* Make the DashContent::test_mainNavigation test more stable (LP:
  #1450809)
* Use art height as implicitHeight when the header is overlayed and
  there's no summary
[ CI Train Bot ]
* New rebuild forced.
* Resync trunk.
[ Daniel d'Andrada ]
* Introducing FloatingFlickable
* Make Ubuntu.Gestures components install TouchRegistry by themselves
[ Michael Terry ]
* Fix a possible crash in our PAM threading code. (LP: #1425362) (LP:
  #1425362)
* Fix the lockscreen becoming unresponsive after testing an app on the
  device from QtCreator. (LP: #1435364)
[ Nick Dedekind ]
* Fixed desktop stage app focus.
* Fixed issue in laggy indicator autpilot tests (LP: #1446846)
[ Albert Astals Cid ]
* Workarounds for concierge mode.
[ CI Train Bot ]
* New rebuild forced.
* Resync trunk.

1681. By Daniel d'Andrada on 2015-05-21

Fix build regarding unity-api and add screenshot provider to the mock Utils plugin

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'CMakeLists.txt'
2--- CMakeLists.txt 2015-03-12 13:59:07 +0000
3+++ CMakeLists.txt 2015-04-16 14:12:24 +0000
4@@ -56,6 +56,8 @@
5 find_package(Qt5Concurrent 5.2 REQUIRED)
6 find_package(Qt5Sql 5.2 REQUIRED)
7
8+pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=6)
9+
10 # Standard install paths
11 include(GNUInstallDirs)
12
13
14=== modified file 'data/unity8-dash.desktop.in'
15--- data/unity8-dash.desktop.in 2014-09-04 13:23:09 +0000
16+++ data/unity8-dash.desktop.in 2015-04-16 14:12:24 +0000
17@@ -7,3 +7,4 @@
18 Icon=
19 NoDisplay=true
20 X-Ubuntu-Touch=true
21+X-Ubuntu-Supported-Orientations=primary
22
23=== modified file 'debian/changelog'
24--- debian/changelog 2015-04-13 20:13:53 +0000
25+++ debian/changelog 2015-04-16 14:12:24 +0000
26@@ -1,3 +1,9 @@
27+unity8 (8.10-0ubuntu1) UNRELEASED; urgency=medium
28+
29+ * Implement full-shell rotation (LP: #1210199)
30+
31+ -- Michał Sawicz <michal.sawicz@canonical.com> Wed, 15 Apr 2015 14:47:17 +0200
32+
33 unity8 (8.02+15.04.20150409.1-0ubuntu1) vivid; urgency=medium
34
35 [ Albert Astals Cid ]
36
37=== modified file 'debian/control'
38--- debian/control 2015-04-02 13:09:18 +0000
39+++ debian/control 2015-04-16 14:12:24 +0000
40@@ -14,6 +14,7 @@
41 # append :native to g++-4.9 so we don't try to run armhf g++
42 # on an x86 CPU for eaxmple, when cross-compiling.
43 g++-4.9:native,
44+ libandroid-properties-dev,
45 libconnectivity-qt1-dev,
46 libgl1-mesa-dev[!armhf] | libgl-dev[!armhf],
47 libgl1-mesa-dri,
48@@ -27,7 +28,7 @@
49 libqmenumodel-dev (>= 0.2.9),
50 libqt5xmlpatterns5-dev,
51 libsystemsettings-dev,
52- libunity-api-dev (>= 7.96),
53+ libunity-api-dev (>= 7.97),
54 libusermetricsoutput1-dev,
55 libxcb1-dev,
56 pkg-config,
57@@ -94,7 +95,7 @@
58 qml-module-qtquick-xmllistmodel,
59 qml-module-qtsysteminfo,
60 qtdeclarative5-gsettings1.0,
61- qtdeclarative5-qtmir-plugin (>= 0.4.4),
62+ qtdeclarative5-qtmir-plugin (>= 0.4.5),
63 qtdeclarative5-ubuntu-telephony0.1,
64 qtdeclarative5-ubuntu-web-plugin,
65 ubuntu-system-settings,
66@@ -124,7 +125,7 @@
67 qtdeclarative5-ubuntu-ui-toolkit-plugin (>= 1.1.1239) | qtdeclarative5-ubuntu-ui-toolkit-plugin-gles (>= 1.1.1239),
68 qtdeclarative5-unity-notifications-plugin (>= 0.1.2) | unity-notifications-impl,
69 ubuntu-thumbnailer-impl-0,
70- unity-application-impl-4,
71+ unity-application-impl-6,
72 unity-notifications-impl-3,
73 unity-plugin-scopes | unity-scopes-impl,
74 unity-scopes-impl-6,
75@@ -168,7 +169,7 @@
76 Depends: ${misc:Depends},
77 ${shlibs:Depends},
78 Provides: unity-application-impl,
79- unity-application-impl-4,
80+ unity-application-impl-6,
81 Description: Fake environment for running Unity 8 shell
82 Provides fake implementations of some QML modules used by Unity 8 shell
83 (e.g Ubuntu.Application) so that you can run it in a sandboxed environment.
84
85=== modified file 'debian/unity8.install'
86--- debian/unity8.install 2014-12-16 16:49:49 +0000
87+++ debian/unity8.install 2015-04-16 14:12:24 +0000
88@@ -8,6 +8,9 @@
89 usr/share/unity8/Greeter
90 usr/share/unity8/Launcher
91 usr/share/unity8/Panel
92+usr/share/unity8/Rotation
93+usr/share/unity8/DeviceConfiguration.qml
94+usr/share/unity8/OrientedShell.qml
95 usr/share/unity8/Shell.qml
96 usr/share/unity8/Stages
97 usr/share/unity8/Tutorial
98
99=== modified file 'plugins/Greeter/Unity/Launcher/CMakeLists.txt'
100--- plugins/Greeter/Unity/Launcher/CMakeLists.txt 2015-03-31 01:03:55 +0000
101+++ plugins/Greeter/Unity/Launcher/CMakeLists.txt 2015-04-16 14:12:24 +0000
102@@ -1,5 +1,5 @@
103 pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=6)
104-pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=5)
105+pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=6)
106 pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)
107
108 add_definitions(-DSM_BUSNAME=systemBus)
109
110=== modified file 'plugins/Unity/Launcher/CMakeLists.txt'
111--- plugins/Unity/Launcher/CMakeLists.txt 2015-02-11 14:02:16 +0000
112+++ plugins/Unity/Launcher/CMakeLists.txt 2015-04-16 14:12:24 +0000
113@@ -1,5 +1,5 @@
114 pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=6)
115-pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=5)
116+pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=6)
117 pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)
118
119 add_definitions(-DSM_BUSNAME=systemBus)
120
121=== modified file 'plugins/Utils/CMakeLists.txt'
122--- plugins/Utils/CMakeLists.txt 2015-04-02 10:32:43 +0000
123+++ plugins/Utils/CMakeLists.txt 2015-04-16 14:12:24 +0000
124@@ -16,6 +16,7 @@
125 timeformatter.cpp
126 unitymenumodelpaths.cpp
127 windowkeysfilter.cpp
128+ windowscreenshotprovider.cpp
129 easingcurve.cpp
130 windowstatestorage.cpp
131 plugin.cpp
132
133=== modified file 'plugins/Utils/plugin.cpp'
134--- plugins/Utils/plugin.cpp 2015-04-07 11:50:48 +0000
135+++ plugins/Utils/plugin.cpp 2015-04-16 14:12:24 +0000
136@@ -1,5 +1,5 @@
137 /*
138- * Copyright (C) 2012 Canonical, Ltd.
139+ * Copyright (C) 2012-2015 Canonical, Ltd.
140 *
141 * This program is free software; you can redistribute it and/or modify
142 * it under the terms of the GNU General Public License as published by
143@@ -26,6 +26,7 @@
144 #include "plugin.h"
145
146 // local
147+#include "easingcurve.h"
148 #include "inputwatcher.h"
149 #include "qlimitproxymodelqml.h"
150 #include "unitysortfilterproxymodelqml.h"
151@@ -33,7 +34,7 @@
152 #include "timeformatter.h"
153 #include "unitymenumodelpaths.h"
154 #include "windowkeysfilter.h"
155-#include "easingcurve.h"
156+#include "windowscreenshotprovider.h"
157 #include "windowstatestorage.h"
158 #include "constants.h"
159
160@@ -71,4 +72,6 @@
161 void UtilsPlugin::initializeEngine(QQmlEngine *engine, const char *uri)
162 {
163 QQmlExtensionPlugin::initializeEngine(engine, uri);
164+
165+ engine->addImageProvider(QLatin1String("window"), new WindowScreenshotProvider);
166 }
167
168=== added file 'plugins/Utils/windowscreenshotprovider.cpp'
169--- plugins/Utils/windowscreenshotprovider.cpp 1970-01-01 00:00:00 +0000
170+++ plugins/Utils/windowscreenshotprovider.cpp 2015-04-16 14:12:24 +0000
171@@ -0,0 +1,59 @@
172+/*
173+ * Copyright (C) 2015 Canonical, Ltd.
174+ *
175+ * This program is free software; you can redistribute it and/or modify
176+ * it under the terms of the GNU General Public License as published by
177+ * the Free Software Foundation; version 3.
178+ *
179+ * This program is distributed in the hope that it will be useful,
180+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
181+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
182+ * GNU General Public License for more details.
183+ *
184+ * You should have received a copy of the GNU General Public License
185+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
186+ */
187+
188+#include "windowscreenshotprovider.h"
189+
190+#include <QGuiApplication>
191+#include <QQuickWindow>
192+
193+WindowScreenshotProvider::WindowScreenshotProvider()
194+ : QQuickImageProvider(QQmlImageProviderBase::Image, 0)
195+{
196+}
197+
198+// A very simple implementation where we assume that there's only one window and that it's a
199+// QQuickWindow. Thus the id parameter is irrelevant.
200+//
201+// Idea: Make the id contain the objectName of the QQuickWindow once we care about a multi-display
202+// compositor?
203+// Strictly speaking that could be the actual QWindow::winId(), but that's mostly a
204+// meaningless arbitrary number.
205+QImage WindowScreenshotProvider::requestImage(const QString &id, QSize *size, const QSize &requestedSize)
206+{
207+ Q_UNUSED(id);
208+ Q_UNUSED(requestedSize);
209+
210+ QWindowList windows = QGuiApplication::topLevelWindows();
211+
212+ if (windows.count() != 1) {
213+ size->rwidth() = 0;
214+ size->rheight() = 0;
215+ return QImage();
216+ }
217+
218+ QQuickWindow *quickWindow = qobject_cast<QQuickWindow *>(windows[0]);
219+
220+ if (!quickWindow) {
221+ size->rwidth() = 0;
222+ size->rheight() = 0;
223+ return QImage();
224+ }
225+
226+ QImage image = quickWindow->grabWindow();
227+ size->rwidth() = image.width();
228+ size->rheight() = image.height();
229+ return image;
230+}
231
232=== added file 'plugins/Utils/windowscreenshotprovider.h'
233--- plugins/Utils/windowscreenshotprovider.h 1970-01-01 00:00:00 +0000
234+++ plugins/Utils/windowscreenshotprovider.h 2015-04-16 14:12:24 +0000
235@@ -0,0 +1,31 @@
236+/*
237+ * Copyright (C) 2015 Canonical, Ltd.
238+ *
239+ * This program is free software; you can redistribute it and/or modify
240+ * it under the terms of the GNU General Public License as published by
241+ * the Free Software Foundation; version 3.
242+ *
243+ * This program is distributed in the hope that it will be useful,
244+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
245+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
246+ * GNU General Public License for more details.
247+ *
248+ * You should have received a copy of the GNU General Public License
249+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
250+ */
251+
252+#ifndef WINDOW_SCREENSHOT_PROVIDER_H_
253+#define WINDOW_SCREENSHOT_PROVIDER_H_
254+
255+#include <QQuickImageProvider>
256+
257+class WindowScreenshotProvider : public QQuickImageProvider
258+{
259+public:
260+ WindowScreenshotProvider();
261+
262+ // id is ignored for now
263+ QImage requestImage(const QString &id, QSize *size, const QSize &requestedSize) override;
264+};
265+
266+#endif // WINDOW_SCREENSHOT_PROVIDER_H_
267
268=== modified file 'qml/CMakeLists.txt'
269--- qml/CMakeLists.txt 2014-12-16 16:49:49 +0000
270+++ qml/CMakeLists.txt 2015-04-16 14:12:24 +0000
271@@ -13,6 +13,7 @@
272 Notifications
273 Panel
274 Stages
275+ Rotation
276 Tutorial
277 Wizard
278 )
279
280=== added file 'qml/Components/WindowScreenshot.qml'
281--- qml/Components/WindowScreenshot.qml 1970-01-01 00:00:00 +0000
282+++ qml/Components/WindowScreenshot.qml 2015-04-16 14:12:24 +0000
283@@ -0,0 +1,35 @@
284+/*
285+ * Copyright (C) 2015 Canonical, Ltd.
286+ *
287+ * This program is free software; you can redistribute it and/or modify
288+ * it under the terms of the GNU General Public License as published by
289+ * the Free Software Foundation; version 3.
290+ *
291+ * This program is distributed in the hope that it will be useful,
292+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
293+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
294+ * GNU General Public License for more details.
295+ *
296+ * You should have received a copy of the GNU General Public License
297+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
298+ */
299+
300+import QtQuick 2.2
301+
302+Item {
303+ id: root
304+
305+ function take() {
306+ var timeNow = new Date().getTime();
307+ image.source = "image://window/" + timeNow;
308+ }
309+
310+ // Unload the image to free up memory
311+ function discard() {
312+ image.source = "";
313+ }
314+
315+ Image {
316+ id: image
317+ }
318+}
319
320=== added file 'qml/Dash/graphics/phone/screenshots/gmail-webapp.svg'
321--- qml/Dash/graphics/phone/screenshots/gmail-webapp.svg 1970-01-01 00:00:00 +0000
322+++ qml/Dash/graphics/phone/screenshots/gmail-webapp.svg 2015-04-16 14:12:24 +0000
323@@ -0,0 +1,343 @@
324+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
325+<!-- Created with Inkscape (http://www.inkscape.org/) -->
326+
327+<svg
328+ xmlns:dc="http://purl.org/dc/elements/1.1/"
329+ xmlns:cc="http://creativecommons.org/ns#"
330+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
331+ xmlns:svg="http://www.w3.org/2000/svg"
332+ xmlns="http://www.w3.org/2000/svg"
333+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
334+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
335+ width="768"
336+ height="1280"
337+ id="svg2"
338+ version="1.1"
339+ inkscape:version="0.48.5 r10040"
340+ sodipodi:docname="gmail-webapp.svg">
341+ <defs
342+ id="defs4" />
343+ <sodipodi:namedview
344+ id="base"
345+ pagecolor="#ffffff"
346+ bordercolor="#666666"
347+ borderopacity="1.0"
348+ inkscape:pageopacity="0.0"
349+ inkscape:pageshadow="2"
350+ inkscape:zoom="0.49497475"
351+ inkscape:cx="117.33439"
352+ inkscape:cy="668.80479"
353+ inkscape:document-units="px"
354+ inkscape:current-layer="layer1"
355+ showgrid="false"
356+ inkscape:window-width="1920"
357+ inkscape:window-height="1056"
358+ inkscape:window-x="0"
359+ inkscape:window-y="24"
360+ inkscape:window-maximized="1" />
361+ <metadata
362+ id="metadata7">
363+ <rdf:RDF>
364+ <cc:Work
365+ rdf:about="">
366+ <dc:format>image/svg+xml</dc:format>
367+ <dc:type
368+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
369+ <dc:title></dc:title>
370+ </cc:Work>
371+ </rdf:RDF>
372+ </metadata>
373+ <g
374+ inkscape:label="Layer 1"
375+ inkscape:groupmode="layer"
376+ id="layer1"
377+ transform="translate(0,227.63782)">
378+ <rect
379+ style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.69999999000000002;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
380+ id="rect2985"
381+ width="769.73627"
382+ height="1276.8328"
383+ x="-2.0203052"
384+ y="3.1671834"
385+ transform="translate(0,-227.63782)" />
386+ <rect
387+ style="fill:#e6e6e6;fill-opacity:1;stroke:none;stroke-width:4;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
388+ id="rect3797"
389+ width="773.77686"
390+ height="129.29953"
391+ x="-6.0609155"
392+ y="-0.87342685"
393+ transform="translate(0,-227.63782)" />
394+ <text
395+ xml:space="preserve"
396+ style="font-size:72px;font-style:normal;font-weight:500;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Ubuntu;-inkscape-font-specification:Ubuntu Medium;font-stretch:normal;font-variant:normal"
397+ x="20.203053"
398+ y="-139.61781"
399+ id="text3755"
400+ sodipodi:linespacing="125%"><tspan
401+ sodipodi:role="line"
402+ id="tspan3757"
403+ x="20.203053"
404+ y="-139.61781">GMail</tspan></text>
405+ <text
406+ xml:space="preserve"
407+ style="font-size:72px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Ubuntu;-inkscape-font-specification:Ubuntu"
408+ x="14.142137"
409+ y="-28.501045"
410+ id="text3759"
411+ sodipodi:linespacing="125%"><tspan
412+ sodipodi:role="line"
413+ id="tspan3761"
414+ x="14.142137"
415+ y="-28.501045">Inbox</tspan></text>
416+ <path
417+ sodipodi:type="arc"
418+ style="fill:#8effff;fill-opacity:1;stroke:#000000;stroke-width:0.69999999;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
419+ id="path3765"
420+ sodipodi:cx="107.07617"
421+ sodipodi:cy="337.52768"
422+ sodipodi:rx="64.649765"
423+ sodipodi:ry="61.619305"
424+ d="m 171.72594,337.52768 a 64.649765,61.619305 0 1 1 -129.299533,0 64.649765,61.619305 0 1 1 129.299533,0 z"
425+ transform="translate(-28.284271,-251.88148)" />
426+ <path
427+ style="fill:none;stroke:#000000;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
428+ d="m 14.142136,237.52257 729.330134,0"
429+ id="path3769"
430+ inkscape:connector-curvature="0"
431+ transform="translate(0,-227.63782)" />
432+ <text
433+ xml:space="preserve"
434+ style="font-size:64px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Ubuntu;-inkscape-font-specification:Ubuntu"
435+ x="167.68533"
436+ y="78.575127"
437+ id="text3771"
438+ sodipodi:linespacing="125%"><tspan
439+ sodipodi:role="line"
440+ id="tspan3773"
441+ x="167.68533"
442+ y="78.575127">Lorem ipsum</tspan></text>
443+ <text
444+ xml:space="preserve"
445+ style="font-size:64px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Ubuntu;-inkscape-font-specification:Ubuntu"
446+ x="167.68532"
447+ y="131.10306"
448+ id="text3775"
449+ sodipodi:linespacing="125%"><tspan
450+ sodipodi:role="line"
451+ id="tspan3777"
452+ x="167.68532"
453+ y="131.10306"
454+ style="font-size:48px;fill:#b3b3b3">bla bla bla bla bla bla bla ...</tspan></text>
455+ <path
456+ style="fill:none;stroke:#000000;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
457+ d="m 13.13199,165.44825 729.33013,0"
458+ id="path3769-2"
459+ inkscape:connector-curvature="0" />
460+ <path
461+ sodipodi:type="arc"
462+ style="fill:#8eff58;fill-opacity:1;stroke:#000000;stroke-width:0.69999999000000002;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
463+ id="path3765-3"
464+ sodipodi:cx="107.07617"
465+ sodipodi:cy="337.52768"
466+ sodipodi:rx="64.649765"
467+ sodipodi:ry="61.619305"
468+ d="m 171.72594,337.52768 a 64.649765,61.619305 0 1 1 -129.299533,0 64.649765,61.619305 0 1 1 129.299533,0 z"
469+ transform="translate(-26.263969,-93.102383)" />
470+ <text
471+ xml:space="preserve"
472+ style="font-size:64px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Ubuntu;-inkscape-font-specification:Ubuntu"
473+ x="169.70564"
474+ y="237.35422"
475+ id="text3771-9"
476+ sodipodi:linespacing="125%"><tspan
477+ sodipodi:role="line"
478+ id="tspan3773-7"
479+ x="169.70564"
480+ y="237.35422">Lorem ipsum</tspan></text>
481+ <text
482+ xml:space="preserve"
483+ style="font-size:64px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Ubuntu;-inkscape-font-specification:Ubuntu"
484+ x="169.70561"
485+ y="289.88217"
486+ id="text3775-1"
487+ sodipodi:linespacing="125%"><tspan
488+ sodipodi:role="line"
489+ id="tspan3777-1"
490+ x="169.70561"
491+ y="289.88217"
492+ style="font-size:48px;fill:#b3b3b3">bla bla bla bla bla bla bla ...</tspan></text>
493+ <path
494+ style="fill:none;stroke:#000000;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
495+ d="m 15.152292,324.22735 729.330128,0"
496+ id="path3769-2-6"
497+ inkscape:connector-curvature="0" />
498+ <path
499+ sodipodi:type="arc"
500+ style="fill:#8effff;fill-opacity:1;stroke:#000000;stroke-width:0.69999999;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
501+ id="path3765-7"
502+ sodipodi:cx="107.07617"
503+ sodipodi:cy="337.52768"
504+ sodipodi:rx="64.649765"
505+ sodipodi:ry="61.619305"
506+ d="m 171.72594,337.52768 a 64.649765,61.619305 0 1 1 -129.299533,0 64.649765,61.619305 0 1 1 129.299533,0 z"
507+ transform="translate(-28.284274,64.481414)" />
508+ <text
509+ xml:space="preserve"
510+ style="font-size:64px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Ubuntu;-inkscape-font-specification:Ubuntu"
511+ x="167.68533"
512+ y="394.93799"
513+ id="text3771-92"
514+ sodipodi:linespacing="125%"><tspan
515+ sodipodi:role="line"
516+ id="tspan3773-0"
517+ x="167.68533"
518+ y="394.93799">Lorem ipsum</tspan></text>
519+ <text
520+ xml:space="preserve"
521+ style="font-size:64px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Ubuntu;-inkscape-font-specification:Ubuntu"
522+ x="167.68532"
523+ y="447.46594"
524+ id="text3775-9"
525+ sodipodi:linespacing="125%"><tspan
526+ sodipodi:role="line"
527+ id="tspan3777-8"
528+ x="167.68532"
529+ y="447.46594"
530+ style="font-size:48px;fill:#b3b3b3">bla bla bla bla bla bla bla ...</tspan></text>
531+ <path
532+ style="fill:none;stroke:#000000;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
533+ d="m 13.131986,481.81114 729.330124,0"
534+ id="path3769-2-3"
535+ inkscape:connector-curvature="0" />
536+ <path
537+ sodipodi:type="arc"
538+ style="fill:#8ea2ff;fill-opacity:1;stroke:#000000;stroke-width:0.69999999000000002;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
539+ id="path3765-2"
540+ sodipodi:cx="107.07617"
541+ sodipodi:cy="337.52768"
542+ sodipodi:rx="64.649765"
543+ sodipodi:ry="61.619305"
544+ d="m 171.72594,337.52768 a 64.649765,61.619305 0 1 1 -129.299533,0 64.649765,61.619305 0 1 1 129.299533,0 z"
545+ transform="translate(-26.263969,226.10582)" />
546+ <text
547+ xml:space="preserve"
548+ style="font-size:64px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Ubuntu;-inkscape-font-specification:Ubuntu"
549+ x="169.70564"
550+ y="556.56238"
551+ id="text3771-1"
552+ sodipodi:linespacing="125%"><tspan
553+ sodipodi:role="line"
554+ id="tspan3773-1"
555+ x="169.70564"
556+ y="556.56238">Lorem ipsum</tspan></text>
557+ <text
558+ xml:space="preserve"
559+ style="font-size:64px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Ubuntu;-inkscape-font-specification:Ubuntu"
560+ x="169.70563"
561+ y="609.09033"
562+ id="text3775-8"
563+ sodipodi:linespacing="125%"><tspan
564+ sodipodi:role="line"
565+ id="tspan3777-85"
566+ x="169.70563"
567+ y="609.09033"
568+ style="font-size:48px;fill:#b3b3b3">bla bla bla bla bla bla bla ...</tspan></text>
569+ <path
570+ style="fill:none;stroke:#000000;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
571+ d="m 15.152292,643.43555 729.330128,0"
572+ id="path3769-2-1"
573+ inkscape:connector-curvature="0" />
574+ <path
575+ sodipodi:type="arc"
576+ style="fill:#8effff;fill-opacity:1;stroke:#000000;stroke-width:0.69999999;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
577+ id="path3765-8"
578+ sodipodi:cx="107.07617"
579+ sodipodi:cy="337.52768"
580+ sodipodi:rx="64.649765"
581+ sodipodi:ry="61.619305"
582+ d="m 171.72594,337.52768 a 64.649765,61.619305 0 1 1 -129.299533,0 64.649765,61.619305 0 1 1 129.299533,0 z"
583+ transform="translate(-24.243664,391.77084)" />
584+ <text
585+ xml:space="preserve"
586+ style="font-size:64px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Ubuntu;-inkscape-font-specification:Ubuntu"
587+ x="171.72594"
588+ y="722.22742"
589+ id="text3771-7"
590+ sodipodi:linespacing="125%"><tspan
591+ sodipodi:role="line"
592+ id="tspan3773-6"
593+ x="171.72594"
594+ y="722.22742">Lorem ipsum</tspan></text>
595+ <text
596+ xml:space="preserve"
597+ style="font-size:64px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Ubuntu;-inkscape-font-specification:Ubuntu"
598+ x="171.72592"
599+ y="774.75537"
600+ id="text3775-5"
601+ sodipodi:linespacing="125%"><tspan
602+ sodipodi:role="line"
603+ id="tspan3777-2"
604+ x="171.72592"
605+ y="774.75537"
606+ style="font-size:48px;fill:#b3b3b3">bla bla bla bla bla bla bla ...</tspan></text>
607+ <path
608+ style="fill:none;stroke:#000000;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
609+ d="m 17.172597,809.10057 729.330133,0"
610+ id="path3769-2-13"
611+ inkscape:connector-curvature="0" />
612+ <path
613+ sodipodi:type="arc"
614+ style="fill:#e44738;fill-opacity:1;stroke:#000000;stroke-width:0.69999999000000002;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
615+ id="path3765-9"
616+ sodipodi:cx="107.07617"
617+ sodipodi:cy="337.52768"
618+ sodipodi:rx="64.649765"
619+ sodipodi:ry="61.619305"
620+ d="m 171.72594,337.52768 a 64.649765,61.619305 0 1 1 -129.299533,0 64.649765,61.619305 0 1 1 129.299533,0 z"
621+ transform="translate(-24.243664,557.43585)" />
622+ <text
623+ xml:space="preserve"
624+ style="font-size:64px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Ubuntu;-inkscape-font-specification:Ubuntu"
625+ x="171.72594"
626+ y="887.89246"
627+ id="text3771-2"
628+ sodipodi:linespacing="125%"><tspan
629+ sodipodi:role="line"
630+ id="tspan3773-8"
631+ x="171.72594"
632+ y="887.89246">Lorem ipsum</tspan></text>
633+ <text
634+ xml:space="preserve"
635+ style="font-size:64px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Ubuntu;-inkscape-font-specification:Ubuntu"
636+ x="171.72592"
637+ y="940.42041"
638+ id="text3775-3"
639+ sodipodi:linespacing="125%"><tspan
640+ sodipodi:role="line"
641+ id="tspan3777-7"
642+ x="171.72592"
643+ y="940.42041"
644+ style="font-size:48px;fill:#b3b3b3">bla bla bla bla bla bla bla ...</tspan></text>
645+ <path
646+ style="fill:none;stroke:#000000;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
647+ d="m 17.172597,974.76558 729.330123,0"
648+ id="path3769-2-9"
649+ inkscape:connector-curvature="0" />
650+ <path
651+ sodipodi:type="arc"
652+ style="fill:none;stroke:#000000;stroke-width:8;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
653+ id="path3929"
654+ sodipodi:cx="590.93921"
655+ sodipodi:cy="-119.06127"
656+ sodipodi:rx="33.335033"
657+ sodipodi:ry="33.335033"
658+ d="m 624.27424,-119.06127 a 33.335033,33.335033 0 1 1 -66.67006,0 33.335033,33.335033 0 1 1 66.67006,0 z"
659+ transform="matrix(0.85096826,0,0,0.85096826,175.43863,-68.81729)" />
660+ <path
661+ style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:3.40387297;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
662+ d="m 692.92249,-145.20602 20.63059,24.06901 12.03451,-13.75372 -20.63059,-17.19215"
663+ id="path3931"
664+ inkscape:connector-curvature="0" />
665+ </g>
666+</svg>
667
668=== removed file 'qml/Dash/graphics/phone/screenshots/settings@12.png'
669Binary files qml/Dash/graphics/phone/screenshots/settings@12.png 2013-06-20 13:42:39 +0000 and qml/Dash/graphics/phone/screenshots/settings@12.png 1970-01-01 00:00:00 +0000 differ
670=== added file 'qml/Dash/graphics/phone/screenshots/ubuntu-weather-app.svg'
671--- qml/Dash/graphics/phone/screenshots/ubuntu-weather-app.svg 1970-01-01 00:00:00 +0000
672+++ qml/Dash/graphics/phone/screenshots/ubuntu-weather-app.svg 2015-04-16 14:12:24 +0000
673@@ -0,0 +1,201 @@
674+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
675+<!-- Created with Inkscape (http://www.inkscape.org/) -->
676+
677+<svg
678+ xmlns:dc="http://purl.org/dc/elements/1.1/"
679+ xmlns:cc="http://creativecommons.org/ns#"
680+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
681+ xmlns:svg="http://www.w3.org/2000/svg"
682+ xmlns="http://www.w3.org/2000/svg"
683+ xmlns:xlink="http://www.w3.org/1999/xlink"
684+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
685+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
686+ width="829"
687+ height="480"
688+ id="svg2740"
689+ sodipodi:version="0.32"
690+ inkscape:version="0.48.5 r10040"
691+ version="1.0"
692+ sodipodi:docname="ubuntu-weather-app.svg"
693+ inkscape:output_extension="org.inkscape.output.svg.inkscape">
694+ <defs
695+ id="defs2742">
696+ <linearGradient
697+ id="linearGradient3824">
698+ <stop
699+ style="stop-color:#e6e6e6;stop-opacity:1;"
700+ offset="0"
701+ id="stop3826" />
702+ <stop
703+ style="stop-color:#23abff;stop-opacity:1;"
704+ offset="1"
705+ id="stop3828" />
706+ </linearGradient>
707+ <linearGradient
708+ inkscape:collect="always"
709+ xlink:href="#linearGradient3824"
710+ id="linearGradient3830"
711+ x1="348.55862"
712+ y1="343.23914"
713+ x2="348.55862"
714+ y2="-17.422215"
715+ gradientUnits="userSpaceOnUse" />
716+ </defs>
717+ <sodipodi:namedview
718+ id="base"
719+ pagecolor="#ffffff"
720+ bordercolor="#666666"
721+ borderopacity="1.0"
722+ gridtolerance="10000"
723+ guidetolerance="10"
724+ objecttolerance="10"
725+ inkscape:pageopacity="0.0"
726+ inkscape:pageshadow="2"
727+ inkscape:zoom="0.82625984"
728+ inkscape:cx="331.28234"
729+ inkscape:cy="125.54212"
730+ inkscape:document-units="px"
731+ inkscape:current-layer="layer1"
732+ showgrid="false"
733+ inkscape:window-width="1145"
734+ inkscape:window-height="847"
735+ inkscape:window-x="268"
736+ inkscape:window-y="63"
737+ inkscape:window-maximized="0" />
738+ <metadata
739+ id="metadata2745">
740+ <rdf:RDF>
741+ <cc:Work
742+ rdf:about="">
743+ <dc:format>image/svg+xml</dc:format>
744+ <dc:type
745+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
746+ </cc:Work>
747+ </rdf:RDF>
748+ </metadata>
749+ <g
750+ inkscape:label="Layer 1"
751+ inkscape:groupmode="layer"
752+ id="layer1"
753+ transform="translate(-321.13452,-104.68346)">
754+ <rect
755+ style="fill:url(#linearGradient3830);fill-opacity:1;stroke:#000000;stroke-width:0.69999999000000002;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
756+ id="rect2990"
757+ width="832.66785"
758+ height="480.47839"
759+ x="-1.210273"
760+ y="0.73188055"
761+ transform="translate(321.13452,104.68346)" />
762+ <path
763+ d="m 310.66382,132.06057 c -1.82703,2.0443 -22.21039,-18.38308 -24.89334,-17.37811 -2.68295,1.00497 -6.73783,33.64192 -9.57527,34.01165 -2.83744,0.36973 -7.71546,-33.08881 -10.48084,-33.88783 -2.76539,-0.79903 -18.7793,19.34152 -21.17964,17.82892 -2.40034,-1.51259 5.69972,-26.09808 4.36486,-28.67057 -1.33487,-2.57249 -31.86305,-3.78032 -32.49182,-6.6501 -0.62876,-2.86978 27.66855,-10.399376 27.90248,-13.241764 0.23394,-2.842387 -18.99828,-18.90215 -17.89698,-21.393798 1.10131,-2.491647 26.85456,8.177399 28.59429,5.99159 1.73972,-2.185809 -3.39182,-29.683489 -0.75169,-30.507098 2.64013,-0.823608 18.50306,18.485327 21.32153,18.392972 2.81847,-0.09235 11.30312,-24.287685 14.18258,-23.722317 2.87947,0.565368 1.44329,25.667631 3.67226,27.34365 2.22897,1.676019 24.27161,-6.28288 25.90675,-4.004945 1.63514,2.277936 -12.63923,24.445025 -11.77955,27.07291 0.85968,2.627885 27.01183,5.1355 26.65457,7.852474 -0.35726,2.716973 -32.69913,3.875594 -34.04684,6.507203 -1.3477,2.631613 12.32368,32.410863 10.49665,34.455163 z"
764+ id="path11949"
765+ inkscape:flatsided="false"
766+ inkscape:randomized="-0.092"
767+ inkscape:rounded="0.1"
768+ sodipodi:arg1="0.79570711"
769+ sodipodi:arg2="1.144773"
770+ sodipodi:cx="275.15002"
771+ sodipodi:cy="88.090233"
772+ sodipodi:r1="57.019234"
773+ sodipodi:r2="32.818508"
774+ sodipodi:sides="9"
775+ sodipodi:type="star"
776+ style="fill:#f5ff12;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.2;marker:none;visibility:visible;display:inline;overflow:visible"
777+ transform="matrix(2.527571,0,0,2.527571,85.214779,60.619097)" />
778+ <path
779+ d="m 194.51692,77.283737 c 0,20.659371 -17.86424,37.407103 -39.90091,37.407103 -22.03666,0 -39.90091,-16.747732 -39.90091,-37.407103 0,-20.659371 17.86425,-37.4071 39.90091,-37.4071 22.03667,0 39.90091,16.747729 39.90091,37.4071 z"
780+ id="path11951"
781+ sodipodi:cx="154.61601"
782+ sodipodi:cy="77.283737"
783+ sodipodi:rx="39.900909"
784+ sodipodi:ry="37.407101"
785+ sodipodi:type="arc"
786+ style="fill:#f5ff12;fill-opacity:1;fill-rule:nonzero;stroke:#f5ff12;stroke-width:10.27388287;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:0.5;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible"
787+ transform="matrix(2.4568175,0,0,2.1990879,404.91256,120.05076)" />
788+ <path
789+ transform="matrix(3.2663208,0,0,3.4016021,515.92101,-254.59331)"
790+ style="fill:#6798e9;fill-opacity:1;fill-rule:nonzero;stroke:#6798e9;stroke-width:7.30059433;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:0.5;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible"
791+ sodipodi:type="inkscape:offset"
792+ inkscape:radius="0"
793+ inkscape:original="M 110.53125 144.96875 C 100.76599 144.96875 92.384060 150.03292 88.281250 157.34375 C 86.642607 156.42892 84.835190 155.87500 82.906250 155.87500 C 77.073071 155.87500 72.219030 160.56753 70.718750 166.93750 C 68.157973 165.92533 65.180470 165.31250 62.000000 165.31250 C 52.458571 165.31250 44.718750 170.53296 44.718750 176.96875 C 44.718749 182.77816 51.066430 187.55402 59.312500 188.43750 C 58.942922 189.06456 58.656250 189.68551 58.656250 190.34375 C 58.656248 196.50568 75.538140 201.53125 96.343750 201.53125 C 117.14936 201.53125 134.03126 196.50568 134.03125 190.34375 C 134.03125 189.92916 133.77393 189.55916 133.62500 189.15625 C 134.53629 189.38287 135.43860 189.62500 136.43750 189.62500 C 142.00333 189.62501 146.53125 185.84318 146.53125 181.18750 C 146.53125 176.53182 142.00332 172.75000 136.43750 172.75000 C 135.75542 172.75000 135.17544 172.98560 134.53125 173.09375 C 135.09454 171.23218 135.46875 169.33268 135.46875 167.31250 C 135.46875 154.98864 124.31330 144.96875 110.53125 144.96875 z "
794+ id="path11953"
795+ d="m 110.53125,144.96875 c -9.76526,0 -18.14719,5.06417 -22.25,12.375 -1.638643,-0.91483 -3.44606,-1.46875 -5.375,-1.46875 -5.833179,0 -10.68722,4.69253 -12.1875,11.0625 -2.560777,-1.01217 -5.53828,-1.625 -8.71875,-1.625 -9.541429,0 -17.28125,5.22046 -17.28125,11.65625 -10e-7,5.80941 6.34768,10.58527 14.59375,11.46875 -0.369578,0.62706 -0.65625,1.24801 -0.65625,1.90625 -2e-6,6.16193 16.88189,11.1875 37.6875,11.1875 20.80561,0 37.68751,-5.02557 37.6875,-11.1875 0,-0.41459 -0.25732,-0.78459 -0.40625,-1.1875 0.91129,0.22662 1.8136,0.46875 2.8125,0.46875 5.56583,1e-5 10.09375,-3.78182 10.09375,-8.4375 0,-4.65568 -4.52793,-8.4375 -10.09375,-8.4375 -0.68208,0 -1.26206,0.2356 -1.90625,0.34375 0.56329,-1.86157 0.9375,-3.76107 0.9375,-5.78125 0,-12.32386 -11.15545,-22.34375 -24.9375,-22.34375 z" />
796+ <path
797+ inkscape:connector-curvature="0"
798+ style="fill:#386195;fill-opacity:1;fill-rule:nonzero;stroke:#386195;stroke-width:24.07697487;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:0.5;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible"
799+ id="path11963"
800+ d="m 975.70833,305.75079 c -17.87875,0 -33.1897,9.10731 -40.70137,22.18913 -3.00012,-1.63696 -6.34124,-2.6392 -9.87286,-2.6392 -10.67967,0 -19.5639,8.39604 -22.31073,19.7943 -4.6884,-1.81117 -10.09942,-2.93251 -15.92242,-2.93251 -17.46892,0 -31.65122,9.35352 -31.65122,20.86955 0,10.39528 11.61748,18.9466 26.71485,20.52749 -0.67665,1.12204 -1.20995,2.24338 -1.20995,3.42121 0,11.02604 30.92124,19.98985 69.01327,19.98985 38.09195,0 69.0132,-8.96381 69.0132,-19.98985 0,-0.74183 -0.5017,-1.42952 -0.7743,-2.15046 1.6684,0.40556 3.3496,0.83088 5.1784,0.83088 10.1902,0 18.439,-6.7716 18.439,-15.10234 0,-8.33078 -8.2488,-15.05348 -18.439,-15.05348 -1.2488,0 -2.3535,0.39297 -3.5329,0.58647 1.0312,-3.33102 1.7422,-6.7466 1.7422,-10.36143 0,-22.05212 -20.4533,-39.97961 -45.68617,-39.97961 z" />
801+ <path
802+ inkscape:connector-curvature="0"
803+ style="fill:#6798e9;fill-opacity:1;fill-rule:nonzero;stroke:#6798e9;stroke-width:15.64964962;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:3.20000005;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible"
804+ sodipodi:nodetypes="cccc"
805+ id="path11965"
806+ d="m 717.80594,482.73655 c -32.27924,28.4432 5.62151,52.69793 20.03284,13.63938 l 11.08203,-36.22961 -31.11487,22.59023 z" />
807+ <path
808+ inkscape:connector-curvature="0"
809+ style="fill:#6798e9;fill-opacity:1;fill-rule:nonzero;stroke:#6798e9;stroke-width:15.64964962;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:3.20000005;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible"
810+ sodipodi:nodetypes="cccc"
811+ id="path11967"
812+ d="m 799.47,485.76116 c -32.27925,28.4432 5.62151,52.69792 20.03284,13.63937 l 11.08202,-36.2296 -31.11486,22.59023 z" />
813+ <text
814+ xml:space="preserve"
815+ style="font-size:32px;font-style:normal;font-weight:bold;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans Bold"
816+ x="68.985565"
817+ y="92.712631"
818+ id="text2992"
819+ sodipodi:linespacing="125%"
820+ transform="translate(321.13452,104.68346)"><tspan
821+ sodipodi:role="line"
822+ id="tspan2994"
823+ x="68.985565"
824+ y="92.712631" /></text>
825+ <text
826+ xml:space="preserve"
827+ style="font-size:10px;font-style:normal;font-weight:bold;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans Bold"
828+ x="-202.1156"
829+ y="155.64684"
830+ id="text2996"
831+ sodipodi:linespacing="125%"
832+ transform="translate(321.13452,104.68346)"><tspan
833+ sodipodi:role="line"
834+ id="tspan2998"
835+ x="-202.1156"
836+ y="155.64684" /></text>
837+ <text
838+ xml:space="preserve"
839+ style="font-size:24px;font-style:normal;font-weight:bold;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans Bold"
840+ x="342.91943"
841+ y="155.03653"
842+ id="text3000"
843+ sodipodi:linespacing="125%"><tspan
844+ sodipodi:role="line"
845+ id="tspan3002"
846+ x="342.91943"
847+ y="155.03653"
848+ style="font-size:32px;font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-family:Ubuntu;-inkscape-font-specification:Ubuntu Medium">Wheather App</tspan></text>
849+ <text
850+ xml:space="preserve"
851+ style="font-size:24px;font-style:normal;font-weight:bold;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ff0000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans Bold"
852+ x="460.31592"
853+ y="358.3624"
854+ id="text3004"
855+ sodipodi:linespacing="125%"><tspan
856+ sodipodi:role="line"
857+ id="tspan3006"
858+ x="460.31592"
859+ y="358.3624"
860+ style="font-size:48px;fill:#ff0000;-inkscape-font-specification:Ubuntu;font-family:Ubuntu;font-weight:normal;font-style:normal;font-stretch:normal;font-variant:normal">22C</tspan></text>
861+ <text
862+ xml:space="preserve"
863+ style="font-size:24px;font-style:normal;font-weight:bold;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#0000ff;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans Bold"
864+ x="460.19751"
865+ y="412.14325"
866+ id="text3004-0"
867+ sodipodi:linespacing="125%"><tspan
868+ sodipodi:role="line"
869+ id="tspan3006-4"
870+ x="460.19751"
871+ y="412.14325"
872+ style="font-size:48px;fill:#0000ff;-inkscape-font-specification:Ubuntu Medium;font-family:Ubuntu;font-weight:500;font-style:normal;font-stretch:normal;font-variant:normal">14C</tspan></text>
873+ </g>
874+</svg>
875
876=== added file 'qml/DeviceConfiguration.qml'
877--- qml/DeviceConfiguration.qml 1970-01-01 00:00:00 +0000
878+++ qml/DeviceConfiguration.qml 2015-04-16 14:12:24 +0000
879@@ -0,0 +1,81 @@
880+/*
881+ * Copyright (C) 2015 Canonical, Ltd.
882+ *
883+ * This program is free software; you can redistribute it and/or modify
884+ * it under the terms of the GNU General Public License as published by
885+ * the Free Software Foundation; version 3.
886+ *
887+ * This program is distributed in the hope that it will be useful,
888+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
889+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
890+ * GNU General Public License for more details.
891+ *
892+ * You should have received a copy of the GNU General Public License
893+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
894+ */
895+
896+import QtQuick 2.0
897+
898+StateGroup {
899+ id: root
900+
901+ readonly property int useNativeOrientation: -1
902+
903+ property int primaryOrientation: useNativeOrientation
904+
905+ property int supportedOrientations: Qt.PortraitOrientation
906+ | Qt.InvertedPortraitOrientation
907+ | Qt.LandscapeOrientation
908+ | Qt.InvertedLandscapeOrientation
909+
910+ // Supported values so far:
911+ // "phone", "tablet" or "desktop"
912+ property string category: "phone"
913+
914+
915+ property alias name: root.state
916+
917+ states: [
918+ State {
919+ name: "mako"
920+ PropertyChanges {
921+ target: root
922+ supportedOrientations: Qt.PortraitOrientation
923+ | Qt.LandscapeOrientation
924+ | Qt.InvertedLandscapeOrientation
925+ }
926+ },
927+ State {
928+ name: "krillin"
929+ PropertyChanges {
930+ target: root
931+ supportedOrientations: Qt.PortraitOrientation
932+ | Qt.LandscapeOrientation
933+ | Qt.InvertedLandscapeOrientation
934+ }
935+ },
936+ State {
937+ name: "manta"
938+ PropertyChanges {
939+ target: root
940+ category: "tablet"
941+ }
942+ },
943+ State {
944+ name: "flo"
945+ PropertyChanges {
946+ target: root
947+ primaryOrientation: Qt.InvertedLandscapeOrientation
948+ category: "tablet"
949+ }
950+ },
951+ State {
952+ name: "desktop"
953+ PropertyChanges {
954+ target: root
955+ category: "desktop"
956+ }
957+ }
958+ ]
959+
960+}
961
962=== modified file 'qml/Greeter/Greeter.qml'
963--- qml/Greeter/Greeter.qml 2015-03-18 10:17:28 +0000
964+++ qml/Greeter/Greeter.qml 2015-04-16 14:12:24 +0000
965@@ -52,6 +52,8 @@
966 property int failedLoginsDelayAttempts: 7 // number of failed logins
967 property real failedLoginsDelayMinutes: 5 // minutes of forced waiting
968
969+ readonly property bool animating: loader.item ? loader.item.animating : false
970+
971 signal tease()
972 signal sessionStarted()
973 signal emergencyCall()
974
975=== modified file 'qml/Greeter/NarrowView.qml'
976--- qml/Greeter/NarrowView.qml 2015-02-23 15:43:41 +0000
977+++ qml/Greeter/NarrowView.qml 2015-04-16 14:12:24 +0000
978@@ -33,6 +33,7 @@
979 property alias infographicModel: coverPage.infographicModel
980 readonly property bool fullyShown: coverPage.showProgress === 1 || lockscreen.shown
981 readonly property bool required: coverPage.required || lockscreen.required
982+ readonly property bool animating: coverPage.showAnimation.running || coverPage.hideAnimation.running
983
984 signal selected(int index) // unused
985 signal responded(string response)
986
987=== modified file 'qml/Greeter/WideView.qml'
988--- qml/Greeter/WideView.qml 2015-02-23 15:43:41 +0000
989+++ qml/Greeter/WideView.qml 2015-04-16 14:12:24 +0000
990@@ -32,6 +32,7 @@
991 property alias infographicModel: coverPage.infographicModel
992 readonly property bool fullyShown: coverPage.showProgress === 1
993 readonly property bool required: coverPage.required
994+ readonly property bool animating: coverPage.showAnimation.running || coverPage.hideAnimation.running
995
996 // so that it can be replaced in tests with a mock object
997 property var inputMethod: Qt.inputMethod
998
999=== added file 'qml/OrientedShell.qml'
1000--- qml/OrientedShell.qml 1970-01-01 00:00:00 +0000
1001+++ qml/OrientedShell.qml 2015-04-16 14:12:24 +0000
1002@@ -0,0 +1,182 @@
1003+/*
1004+ * Copyright (C) 2015 Canonical, Ltd.
1005+ *
1006+ * This program is free software; you can redistribute it and/or modify
1007+ * it under the terms of the GNU General Public License as published by
1008+ * the Free Software Foundation; version 3.
1009+ *
1010+ * This program is distributed in the hope that it will be useful,
1011+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1012+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1013+ * GNU General Public License for more details.
1014+ *
1015+ * You should have received a copy of the GNU General Public License
1016+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1017+ */
1018+
1019+import QtQuick 2.0
1020+import QtQuick.Window 2.0
1021+import Unity.Session 0.1
1022+import GSettings 1.0
1023+import "Components"
1024+import "Rotation"
1025+
1026+Rectangle {
1027+ id: root
1028+ color: "black"
1029+
1030+ // NB: native and primary orientations here don't map exactly to their QScreen counterparts
1031+ readonly property int nativeOrientation: width > height ? Qt.LandscapeOrientation : Qt.PortraitOrientation
1032+
1033+ readonly property int primaryOrientation:
1034+ deviceConfiguration.primaryOrientation == deviceConfiguration.useNativeOrientation
1035+ ? nativeOrientation : deviceConfiguration.primaryOrientation
1036+
1037+ DeviceConfiguration {
1038+ id: deviceConfiguration
1039+ name: applicationArguments.deviceName
1040+ }
1041+
1042+ // to be overwritten by tests
1043+ property var usageModeSettings: GSettings { schema.id: "com.canonical.Unity8" }
1044+ property int physicalOrientation: Screen.orientation
1045+ property bool orientationLocked: OrientationLock.enabled
1046+ property var orientationLock: OrientationLock
1047+
1048+ property int orientation
1049+ onPhysicalOrientationChanged: {
1050+ if (!orientationLocked) {
1051+ orientation = physicalOrientation;
1052+ }
1053+ }
1054+ onOrientationLockedChanged: {
1055+ if (orientationLocked) {
1056+ orientationLock.savedOrientation = physicalOrientation;
1057+ } else {
1058+ orientation = physicalOrientation;
1059+ }
1060+ }
1061+ Component.onCompleted: {
1062+ if (orientationLocked) {
1063+ orientation = orientationLock.savedOrientation;
1064+ }
1065+ }
1066+
1067+ readonly property int supportedOrientations: shell.supportedOrientations
1068+ & deviceConfiguration.supportedOrientations
1069+ property int acceptedOrientationAngle: {
1070+ if (orientation & supportedOrientations) {
1071+ return Screen.angleBetween(nativeOrientation, orientation);
1072+ } else if (shell.orientation & supportedOrientations) {
1073+ // stay where we are
1074+ return shell.orientationAngle;
1075+ } else if (angleToOrientation(shell.mainAppWindowOrientationAngle) & supportedOrientations) {
1076+ return shell.mainAppWindowOrientationAngle;
1077+ } else {
1078+ // rotate to some supported orientation as we can't stay where we currently are
1079+ // TODO: Choose the closest to the current one
1080+ if (supportedOrientations & Qt.PortraitOrientation) {
1081+ return Screen.angleBetween(nativeOrientation, Qt.PortraitOrientation);
1082+ } else if (supportedOrientations & Qt.LandcscapeOrientation) {
1083+ return Screen.angleBetween(nativeOrientation, Qt.LandscapeOrientation);
1084+ } else if (supportedOrientations & Qt.InvertedPortraitOrientation) {
1085+ return Screen.angleBetween(nativeOrientation, Qt.InvertedPortraitOrientation);
1086+ } else if (supportedOrientations & Qt.InvertedLandscapeOrientation) {
1087+ return Screen.angleBetween(nativeOrientation, Qt.InvertedLandscapeOrientation);
1088+ } else {
1089+ // if all fails, fallback to primary orientation
1090+ return Screen.angleBetween(nativeOrientation, primaryOrientation);
1091+ }
1092+ }
1093+ }
1094+
1095+ function angleToOrientation(angle) {
1096+ switch (angle) {
1097+ case 0:
1098+ return nativeOrientation;
1099+ break;
1100+ case 90:
1101+ return nativeOrientation === Qt.PortraitOrientation ? Qt.InvertedLandscapeOrientation
1102+ : Qt.PortraitOrientation;
1103+ break;
1104+ case 180:
1105+ return nativeOrientation === Qt.PortraitOrientation ? Qt.InvertedPortraitOrientation
1106+ : Qt.InvertedLandscapeOrientation;
1107+ break;
1108+ case 270:
1109+ return nativeOrientation === Qt.PortraitOrientation ? Qt.LandscapeOrientation
1110+ : Qt.InvertedPortraitOrientation;
1111+ break;
1112+ default:
1113+ console.warn("angleToOrientation: Invalid orientation angle: " + angle);
1114+ return primaryOrientation;
1115+ }
1116+ }
1117+
1118+ RotationStates {
1119+ id: rotationStates
1120+ objectName: "rotationStates"
1121+ orientedShell: root
1122+ shell: shell
1123+ shellCover: shellCover
1124+ windowScreenshot: windowScreenshot
1125+ }
1126+
1127+ Shell {
1128+ id: shell
1129+ objectName: "shell"
1130+ width: root.width
1131+ height: root.height
1132+ orientation: root.angleToOrientation(orientationAngle)
1133+ primaryOrientation: root.primaryOrientation
1134+ nativeOrientation: root.nativeOrientation
1135+ nativeWidth: root.width
1136+ nativeHeight: root.height
1137+
1138+ // TODO: Factor in the connected input devices (eg: physical keyboard, mouse, touchscreen),
1139+ // what's the output device (eg: big TV, desktop monitor, phone display), etc.
1140+ usageScenario: {
1141+ if (root.usageModeSettings.usageMode === "Windowed") {
1142+ return "desktop";
1143+ } else if (root.usageModeSettings.usageMode === "Staged"
1144+ && deviceConfiguration.category === "desktop") {
1145+ return "tablet";
1146+ } else {
1147+ return deviceConfiguration.category;
1148+ }
1149+ }
1150+
1151+ property real transformRotationAngle
1152+ property real transformOriginX
1153+ property real transformOriginY
1154+
1155+ transform: Rotation {
1156+ origin.x: shell.transformOriginX; origin.y: shell.transformOriginY; axis { x: 0; y: 0; z: 1 }
1157+ angle: shell.transformRotationAngle
1158+ }
1159+ }
1160+
1161+ Rectangle {
1162+ id: shellCover
1163+ color: "black"
1164+ anchors.fill: parent
1165+ visible: false
1166+ }
1167+
1168+ WindowScreenshot {
1169+ id: windowScreenshot
1170+ visible: false
1171+ width: root.width
1172+ height: root.height
1173+
1174+ property real transformRotationAngle
1175+ property real transformOriginX
1176+ property real transformOriginY
1177+
1178+ transform: Rotation {
1179+ origin.x: windowScreenshot.transformOriginX; origin.y: windowScreenshot.transformOriginY;
1180+ axis { x: 0; y: 0; z: 1 }
1181+ angle: windowScreenshot.transformRotationAngle
1182+ }
1183+ }
1184+}
1185
1186=== modified file 'qml/Panel/Panel.qml'
1187--- qml/Panel/Panel.qml 2015-04-02 15:08:05 +0000
1188+++ qml/Panel/Panel.qml 2015-04-16 14:12:24 +0000
1189@@ -27,6 +27,9 @@
1190 property alias indicators: __indicators
1191 property alias callHint: __callHint
1192 property bool fullscreenMode: false
1193+ property real indicatorAreaShowProgress: 1.0
1194+
1195+ opacity: fullscreenMode && indicators.fullyClosed ? 0.0 : 1.0
1196
1197 Rectangle {
1198 id: darkenedArea
1199@@ -58,6 +61,12 @@
1200 NumberAnimation { duration: UbuntuAnimation.FastDuration; easing: UbuntuAnimation.StandardEasing }
1201 }
1202
1203+ transform: Translate {
1204+ y: indicators.state === "initial"
1205+ ? (1.0 - indicatorAreaShowProgress) * -d.indicatorHeight
1206+ : 0
1207+ }
1208+
1209 BorderImage {
1210 id: dropShadow
1211 anchors {
1212
1213=== added directory 'qml/Rotation'
1214=== added file 'qml/Rotation/HalfLoopRotationAnimation.qml'
1215--- qml/Rotation/HalfLoopRotationAnimation.qml 1970-01-01 00:00:00 +0000
1216+++ qml/Rotation/HalfLoopRotationAnimation.qml 2015-04-16 14:12:24 +0000
1217@@ -0,0 +1,46 @@
1218+/*
1219+ * Copyright (C) 2015 Canonical, Ltd.
1220+ *
1221+ * This program is free software; you can redistribute it and/or modify
1222+ * it under the terms of the GNU General Public License as published by
1223+ * the Free Software Foundation; version 3.
1224+ *
1225+ * This program is distributed in the hope that it will be useful,
1226+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1227+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1228+ * GNU General Public License for more details.
1229+ *
1230+ * You should have received a copy of the GNU General Public License
1231+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1232+ */
1233+
1234+import QtQuick 2.3
1235+
1236+SequentialAnimation {
1237+ id: root
1238+
1239+ // set from outside
1240+ property int fromAngle
1241+ property int toAngle
1242+ property var info
1243+ property var shell
1244+
1245+ readonly property bool flipShellDimensions: toAngle == 90 || toAngle == 270
1246+
1247+ ScriptAction { script: {
1248+ info.transitioning = true;
1249+ shell.orientationAngle = root.toAngle;
1250+ shell.x = (orientedShell.width - shell.width) / 2
1251+ shell.y = (orientedShell.height - shell.height) / 2;
1252+ shell.transformOriginX = shell.width / 2;
1253+ shell.transformOriginY = shell.height / 2;
1254+ shell.updateFocusedAppOrientation();
1255+ } }
1256+ NumberAnimation {
1257+ target: shell
1258+ property: "transformRotationAngle"
1259+ from: root.fromAngle; to: root.toAngle
1260+ duration: rotationDuration; easing.type: rotationEasing
1261+ }
1262+ ScriptAction { script: { info.transitioning = false; } }
1263+}
1264
1265=== added file 'qml/Rotation/ImmediateRotationAction.qml'
1266--- qml/Rotation/ImmediateRotationAction.qml 1970-01-01 00:00:00 +0000
1267+++ qml/Rotation/ImmediateRotationAction.qml 2015-04-16 14:12:24 +0000
1268@@ -0,0 +1,45 @@
1269+/*
1270+ * Copyright (C) 2015 Canonical, Ltd.
1271+ *
1272+ * This program is free software; you can redistribute it and/or modify
1273+ * it under the terms of the GNU General Public License as published by
1274+ * the Free Software Foundation; version 3.
1275+ *
1276+ * This program is distributed in the hope that it will be useful,
1277+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1278+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1279+ * GNU General Public License for more details.
1280+ *
1281+ * You should have received a copy of the GNU General Public License
1282+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1283+ */
1284+
1285+import QtQuick 2.3
1286+
1287+ScriptAction {
1288+ property var info
1289+ property var shell
1290+
1291+ script: {
1292+ info.transitioning = true;
1293+ shell.orientationAngle = info.requestedOrientationAngle;
1294+ shell.transformRotationAngle = info.requestedOrientationAngle;
1295+
1296+ // Making bindings as orientedShell's dimensions might wiggle during startup.
1297+ if (info.requestedOrientationAngle === 90 || info.requestedOrientationAngle === 270) {
1298+ shell.width = Qt.binding(function() { return orientedShell.height; });
1299+ shell.height = Qt.binding(function() { return orientedShell.width; });
1300+ } else {
1301+ shell.width = Qt.binding(function() { return orientedShell.width; });
1302+ shell.height = Qt.binding(function() { return orientedShell.height; });
1303+ }
1304+
1305+ shell.x = Qt.binding(function() { return (orientedShell.width - shell.width) / 2; });
1306+ shell.y = Qt.binding(function() { return (orientedShell.height - shell.height) / 2; });
1307+ shell.transformOriginX = Qt.binding(function() { return shell.width / 2; });
1308+ shell.transformOriginY = Qt.binding(function() { return shell.height / 2; });
1309+
1310+ shell.updateFocusedAppOrientation();
1311+ info.transitioning = false;
1312+ }
1313+}
1314
1315=== added file 'qml/Rotation/NinetyRotationAnimation.qml'
1316--- qml/Rotation/NinetyRotationAnimation.qml 1970-01-01 00:00:00 +0000
1317+++ qml/Rotation/NinetyRotationAnimation.qml 2015-04-16 14:12:24 +0000
1318@@ -0,0 +1,90 @@
1319+/*
1320+ * Copyright (C) 2015 Canonical, Ltd.
1321+ *
1322+ * This program is free software; you can redistribute it and/or modify
1323+ * it under the terms of the GNU General Public License as published by
1324+ * the Free Software Foundation; version 3.
1325+ *
1326+ * This program is distributed in the hope that it will be useful,
1327+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1328+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1329+ * GNU General Public License for more details.
1330+ *
1331+ * You should have received a copy of the GNU General Public License
1332+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1333+ */
1334+
1335+import QtQuick 2.3
1336+
1337+SequentialAnimation {
1338+ id: root
1339+
1340+ property int fromAngle
1341+ property int toAngle
1342+ property var info
1343+ property var shell
1344+
1345+ readonly property real fromY: fromAngle === 0 || fromAngle === 90 ? 0 : orientedShell.height - orientedShell.width;
1346+ readonly property real toY: toAngle === 0 || toAngle === 90 ? 0 : orientedShell.height - orientedShell.width;
1347+ readonly property bool flipShellDimensions: toAngle == 90 || toAngle == 270
1348+
1349+ ScriptAction { script: {
1350+ info.transitioning = true;
1351+ windowScreenshot.take();
1352+ windowScreenshot.visible = true;
1353+ shell.orientationAngle = root.toAngle;
1354+ shell.x = 0;
1355+ shell.width = flipShellDimensions ? orientedShell.height : orientedShell.width;
1356+ shell.height = flipShellDimensions ? orientedShell.width : orientedShell.height;
1357+ shell.transformOriginX = orientedShell.width / 2;
1358+ shell.transformOriginY = orientedShell.width / 2;
1359+ shell.updateFocusedAppOrientation();
1360+ shellCover.visible = true;
1361+
1362+ windowScreenshot.transformOriginX = orientedShell.width / 2;
1363+ if (fromAngle == 180 || fromAngle == 270) {
1364+ windowScreenshot.transformOriginY = orientedShell.height - (orientedShell.width / 2);
1365+ } else {
1366+ windowScreenshot.transformOriginY = orientedShell.width / 2;
1367+ }
1368+ } }
1369+ ParallelAnimation {
1370+ NumberAnimation {
1371+ target: shellCover; property: "opacity"; from: 1; to: 0;
1372+ duration: rotationDuration; easing.type: rotationEasing
1373+ }
1374+ RotationAnimation {
1375+ target: shell; property: "transformRotationAngle";
1376+ from: root.fromAngle; to: root.toAngle
1377+ direction: RotationAnimation.Shortest
1378+ duration: rotationDuration; easing.type: rotationEasing
1379+ }
1380+ NumberAnimation {
1381+ target: shell; property: "y"
1382+ from: root.fromY; to: root.toY
1383+ duration: rotationDuration; easing.type: rotationEasing
1384+ }
1385+
1386+ NumberAnimation {
1387+ target: windowScreenshot; property: "opacity"; from: 1; to: 0;
1388+ duration: rotationDuration; easing.type: rotationEasing
1389+ }
1390+ RotationAnimation {
1391+ target: windowScreenshot; property: "transformRotationAngle";
1392+ from: 0; to: root.toAngle - root.fromAngle
1393+ direction: RotationAnimation.Shortest
1394+ duration: rotationDuration; easing.type: rotationEasing
1395+ }
1396+ NumberAnimation {
1397+ target: windowScreenshot; property: "y"
1398+ from: 0; to: root.toY - root.fromY
1399+ duration: rotationDuration; easing.type: rotationEasing
1400+ }
1401+ }
1402+ ScriptAction { script: {
1403+ windowScreenshot.visible = false;
1404+ windowScreenshot.discard();
1405+ shellCover.visible = false;
1406+ info.transitioning = false;
1407+ } }
1408+}
1409
1410=== added file 'qml/Rotation/RotationStates.qml'
1411--- qml/Rotation/RotationStates.qml 1970-01-01 00:00:00 +0000
1412+++ qml/Rotation/RotationStates.qml 2015-04-16 14:12:24 +0000
1413@@ -0,0 +1,271 @@
1414+/*
1415+ * Copyright (C) 2015 Canonical, Ltd.
1416+ *
1417+ * This program is free software; you can redistribute it and/or modify
1418+ * it under the terms of the GNU General Public License as published by
1419+ * the Free Software Foundation; version 3.
1420+ *
1421+ * This program is distributed in the hope that it will be useful,
1422+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1423+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1424+ * GNU General Public License for more details.
1425+ *
1426+ * You should have received a copy of the GNU General Public License
1427+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1428+ */
1429+
1430+import QtQuick 2.0
1431+import Ubuntu.Components 1.1
1432+
1433+// Why the state machine is done that way:
1434+// We cannot use regular PropertyChanges{} inside the State elements as steps in the
1435+// transition animations must take place in a well defined order.
1436+// Which means that we also cannot jump to a new state in the middle of a transition
1437+// as that would make hell brake loose.
1438+StateGroup {
1439+ id: root
1440+
1441+ // to be set from the outside
1442+ property Item orientedShell
1443+ property Item shell
1444+ property Item shellCover
1445+ property Item windowScreenshot
1446+
1447+ property int rotationDuration: 450
1448+ property int rotationEasing: Easing.InOutCubic
1449+ // Those values are good for debugging/development
1450+ //property int rotationDuration: 3000
1451+ //property int rotationEasing: Easing.Linear
1452+
1453+ state: "0"
1454+ states: [
1455+ State { name: "0" },
1456+ State { name: "90" },
1457+ State { name: "180" },
1458+ State { name: "270" }
1459+ ]
1460+
1461+ property QtObject d: QtObject {
1462+ id: d
1463+
1464+ property bool startingUp: true
1465+ property var finishStartUpTimer: Timer {
1466+ interval: 500
1467+ onTriggered: d.startingUp = false
1468+ }
1469+ Component.onCompleted: {
1470+ finishStartUpTimer.start();
1471+ }
1472+
1473+ property bool transitioning: false
1474+ onTransitioningChanged: {
1475+ d.tryUpdateState();
1476+ }
1477+
1478+ readonly property int requestedOrientationAngle: root.orientedShell.acceptedOrientationAngle
1479+
1480+ // Avoiding a direct call to tryUpdateState() as the state change might trigger an immediate
1481+ // change to Shell.orientationAngle which, in its turn, causes a reevaluation of
1482+ // requestedOrientationAngle (ie., OrientedShell.acceptedOrientationAngle). A reentrant evaluation
1483+ // of a binding is detected by QML as a binding loop and QML will deny the reevalutation, which
1484+ // will leave us in a bogus state.
1485+ //
1486+ // To avoid this mess we update the state in the next event loop iteration, ensuring a clean
1487+ // call stack.
1488+ onRequestedOrientationAngleChanged: {
1489+ stateUpdateTimer.start();
1490+ }
1491+ property Timer stateUpdateTimer: Timer {
1492+ id: stateUpdateTimer
1493+ interval: 1
1494+ onTriggered: { d.tryUpdateState(); }
1495+ }
1496+
1497+ function tryUpdateState() {
1498+ if (d.transitioning || (!d.startingUp && !root.shell.orientationChangesEnabled)) {
1499+ return;
1500+ }
1501+
1502+ var requestedState = d.requestedOrientationAngle.toString();
1503+ if (requestedState !== root.state) {
1504+ d.resolveAnimationType();
1505+ root.state = requestedState;
1506+ }
1507+ }
1508+
1509+ property Connections shellConnections: Connections {
1510+ target: root.shell
1511+ onOrientationChangesEnabledChanged: {
1512+ d.tryUpdateState();
1513+ }
1514+ }
1515+
1516+ property var shellBeingResized: Binding {
1517+ target: root.shell
1518+ property: "beingResized"
1519+ value: d.transitioning
1520+ }
1521+
1522+ readonly property int fullAnimation: 0
1523+ readonly property int indicatorsBarAnimation: 1
1524+ readonly property int noAnimation: 2
1525+
1526+ property int animationType
1527+
1528+ // animationType update *must* take place *before* the state update.
1529+ // If animationType and state were updated through bindings, as with normal qml code,
1530+ // there would be no guarantee in the order of the binding updates, which could then
1531+ // cause the wrong transitions to be chosen for the state changes.
1532+ function resolveAnimationType() {
1533+ if (d.startingUp) {
1534+ // During start up, inital property values are still settling while we're still
1535+ // to render the very first frame
1536+ d.animationType = d.noAnimation;
1537+ } else {
1538+ if (!root.shell.mainApp) {
1539+ // shouldn't happen but, anyway
1540+ d.animationType = d.fullAnimation;
1541+ return;
1542+ }
1543+
1544+ if (root.shell.mainApp.rotatesWindowContents) {
1545+ // The application will animate its own GUI, so we don't have to do anything ourselves.
1546+ d.animationType = d.noAnimation;
1547+ } else if (root.shell.mainAppWindowOrientationAngle == d.requestedOrientationAngle) {
1548+ // The app window is already on its final orientation angle.
1549+ // So we just animate the indicators bar
1550+ // TODO: what if the app is fullscreen?
1551+ d.animationType = d.indicatorsBarAnimation;
1552+ } else {
1553+ d.animationType = d.fullAnimation;
1554+ }
1555+ }
1556+ }
1557+
1558+ // When an application switch takes place, d.requestedOrientationAngle and
1559+ // root.shell.mainAppWindowOrientationAngle get updated separately, at different moments.
1560+ // So, when one of those properties change, we shouldn't make a decision straight away
1561+ // as the other might be stale and about to be changed. So let's give it a bit of time for
1562+ // them to get properly updated.
1563+ // This approach is indeed a bit hacky.
1564+ property bool appWindowOrientationAngleNeedsUpdateUnstable:
1565+ root.shell.orientationAngle === d.requestedOrientationAngle
1566+ && root.shell.mainApp
1567+ && root.shell.mainAppWindowOrientationAngle !== root.shell.orientationAngle
1568+ && !d.transitioning
1569+ onAppWindowOrientationAngleNeedsUpdateUnstableChanged: {
1570+ stableTimer.restart();
1571+ }
1572+ property Timer stableTimer: Timer {
1573+ interval: 200
1574+ onTriggered: {
1575+ if (d.appWindowOrientationAngleNeedsUpdateUnstable) {
1576+ shell.updateFocusedAppOrientationAnimated();
1577+ }
1578+ }
1579+ }
1580+ }
1581+
1582+ transitions: [
1583+ Transition {
1584+ from: "90"; to: "0"
1585+ enabled: d.animationType == d.fullAnimation
1586+ NinetyRotationAnimation { fromAngle: 90; toAngle: 0
1587+ info: d; shell: root.shell }
1588+ },
1589+ Transition {
1590+ from: "0"; to: "90"
1591+ enabled: d.animationType == d.fullAnimation
1592+ NinetyRotationAnimation { fromAngle: 0; toAngle: 90
1593+ info: d; shell: root.shell }
1594+ },
1595+ Transition {
1596+ from: "0"; to: "270"
1597+ enabled: d.animationType == d.fullAnimation
1598+ NinetyRotationAnimation { fromAngle: 0; toAngle: 270
1599+ info: d; shell: root.shell }
1600+ },
1601+ Transition {
1602+ from: "270"; to: "0"
1603+ enabled: d.animationType == d.fullAnimation
1604+ NinetyRotationAnimation { fromAngle: 270; toAngle: 0
1605+ info: d; shell: root.shell }
1606+ },
1607+ Transition {
1608+ from: "90"; to: "180"
1609+ enabled: d.animationType == d.fullAnimation
1610+ NinetyRotationAnimation { fromAngle: 90; toAngle: 180
1611+ info: d; shell: root.shell }
1612+ },
1613+ Transition {
1614+ from: "180"; to: "90"
1615+ enabled: d.animationType == d.fullAnimation
1616+ NinetyRotationAnimation { fromAngle: 180; toAngle: 90
1617+ info: d; shell: root.shell }
1618+ },
1619+ Transition {
1620+ from: "180"; to: "270"
1621+ enabled: d.animationType == d.fullAnimation
1622+ NinetyRotationAnimation { fromAngle: 180; toAngle: 270
1623+ info: d; shell: root.shell }
1624+ },
1625+ Transition {
1626+ from: "270"; to: "180"
1627+ enabled: d.animationType == d.fullAnimation
1628+ NinetyRotationAnimation { fromAngle: 270; toAngle: 180
1629+ info: d; shell: root.shell }
1630+ },
1631+ Transition {
1632+ from: "0"; to: "180"
1633+ enabled: d.animationType == d.fullAnimation
1634+ HalfLoopRotationAnimation { fromAngle: 0; toAngle: 180
1635+ info: d; shell: root.shell }
1636+ },
1637+ Transition {
1638+ from: "180"; to: "0"
1639+ enabled: d.animationType == d.fullAnimation
1640+ HalfLoopRotationAnimation { fromAngle: 180; toAngle: 0
1641+ info: d; shell: root.shell }
1642+ },
1643+ Transition {
1644+ from: "90"; to: "270"
1645+ enabled: d.animationType == d.fullAnimation
1646+ HalfLoopRotationAnimation { fromAngle: 90; toAngle: 270
1647+ info: d; shell: root.shell }
1648+ },
1649+ Transition {
1650+ from: "270"; to: "90"
1651+ enabled: d.animationType == d.fullAnimation
1652+ HalfLoopRotationAnimation { fromAngle: 270; toAngle: 90
1653+ info: d; shell: root.shell }
1654+ },
1655+ Transition {
1656+ objectName: "immediateTransition"
1657+ enabled: d.animationType == d.noAnimation
1658+ ImmediateRotationAction { info: d; shell: root.shell }
1659+ },
1660+ Transition {
1661+ enabled: d.animationType == d.indicatorsBarAnimation
1662+ SequentialAnimation {
1663+ ScriptAction { script: {
1664+ d.transitioning = true;
1665+ } }
1666+ NumberAnimation {
1667+ duration: UbuntuAnimation.FastDuration; easing: UbuntuAnimation.StandardEasing
1668+ target: root.shell; property: "indicatorAreaShowProgress"
1669+ from: 1.0; to: 0.0
1670+ }
1671+ ImmediateRotationAction { info: d; shell: root.shell }
1672+ NumberAnimation {
1673+ duration: UbuntuAnimation.FastDuration; easing: UbuntuAnimation.StandardEasing
1674+ target: root.shell; property: "indicatorAreaShowProgress"
1675+ from: 0.0; to: 1.0
1676+ }
1677+ ScriptAction { script: {
1678+ d.transitioning = false;
1679+ }}
1680+ }
1681+ }
1682+ ]
1683+
1684+}
1685
1686=== modified file 'qml/Shell.qml'
1687--- qml/Shell.qml 2015-04-09 14:01:00 +0000
1688+++ qml/Shell.qml 2015-04-16 14:12:24 +0000
1689@@ -1,5 +1,5 @@
1690 /*
1691- * Copyright (C) 2013 Canonical, Ltd.
1692+ * Copyright (C) 2013-2015 Canonical, Ltd.
1693 *
1694 * This program is free software; you can redistribute it and/or modify
1695 * it under the terms of the GNU General Public License as published by
1696@@ -45,40 +45,68 @@
1697 Item {
1698 id: shell
1699
1700+ // to be set from outside
1701+ property int orientationAngle: 0
1702+ property int orientation
1703+ property int primaryOrientation
1704+ property int nativeOrientation
1705+ property real nativeWidth
1706+ property real nativeHeight
1707+ property alias indicatorAreaShowProgress: panel.indicatorAreaShowProgress
1708+ property bool beingResized
1709+ property string usageScenario: "phone" // supported values: "phone", "tablet" or "desktop"
1710+ function updateFocusedAppOrientation() {
1711+ applicationsDisplayLoader.item.updateFocusedAppOrientation();
1712+ }
1713+ function updateFocusedAppOrientationAnimated() {
1714+ applicationsDisplayLoader.item.updateFocusedAppOrientationAnimated();
1715+ }
1716+
1717+ // to be read from outside
1718+ readonly property int mainAppWindowOrientationAngle:
1719+ applicationsDisplayLoader.item ? applicationsDisplayLoader.item.mainAppWindowOrientationAngle : 0
1720+
1721+ readonly property bool orientationChangesEnabled: panel.indicators.fullyClosed
1722+ && (applicationsDisplayLoader.item && applicationsDisplayLoader.item.orientationChangesEnabled)
1723+ && !greeter.animating
1724+
1725+ property bool startingUp: true
1726+ Timer { id: finishStartUpTimer; interval: 500; onTriggered: startingUp = false }
1727+
1728+ property int supportedOrientations: {
1729+ if (startingUp) {
1730+ // Ensure we don't rotate during start up
1731+ return Qt.PrimaryOrientation;
1732+ } else if (greeter.shown) {
1733+ return Qt.PrimaryOrientation;
1734+ } else if (mainApp) {
1735+ return mainApp.supportedOrientations;
1736+ } else {
1737+ // we just don't care
1738+ return Qt.PortraitOrientation
1739+ | Qt.LandscapeOrientation
1740+ | Qt.InvertedPortraitOrientation
1741+ | Qt.InvertedLandscapeOrientation;
1742+ }
1743+ }
1744+
1745+ // For autopilot consumption
1746+ readonly property string focusedApplicationId: ApplicationManager.focusedApplicationId
1747+
1748+ // internal props from here onwards
1749+ readonly property var mainApp:
1750+ applicationsDisplayLoader.item ? applicationsDisplayLoader.item.mainApp : null
1751+
1752 // Disable everything while greeter is waiting, so that the user can't swipe
1753 // the greeter or launcher until we know whether the session is locked.
1754 enabled: !greeter.waiting
1755
1756- // this is only here to select the width / height of the window if not running fullscreen
1757- property bool tablet: false
1758- width: tablet ? units.gu(160) : applicationArguments.hasGeometry() ? applicationArguments.width() : units.gu(40)
1759- height: tablet ? units.gu(100) : applicationArguments.hasGeometry() ? applicationArguments.height() : units.gu(71)
1760-
1761 property real edgeSize: units.gu(2)
1762 property url defaultBackground: Qt.resolvedUrl(shell.width >= units.gu(60) ? "graphics/tablet_background.jpg" : "graphics/phone_background.jpg")
1763 property url background: asImageTester.status == Image.Ready ? asImageTester.source
1764 : gsImageTester.status == Image.Ready ? gsImageTester.source : defaultBackground
1765 readonly property real panelHeight: panel.panelHeight
1766
1767- property bool sideStageEnabled: shell.width >= units.gu(100)
1768- readonly property string focusedApplicationId: ApplicationManager.focusedApplicationId
1769-
1770- property int orientation
1771- readonly property int deviceOrientationAngle: Screen.angleBetween(Screen.primaryOrientation, Screen.orientation)
1772- onDeviceOrientationAngleChanged: {
1773- if (!OrientationLock.enabled) {
1774- orientation = Screen.orientation;
1775- }
1776- }
1777- readonly property bool orientationLockEnabled: OrientationLock.enabled
1778- onOrientationLockEnabledChanged: {
1779- if (orientationLockEnabled) {
1780- OrientationLock.savedOrientation = Screen.orientation;
1781- } else {
1782- orientation = Screen.orientation;
1783- }
1784- }
1785-
1786 // This is _only_ used to expose the property to autopilot tests
1787 readonly property string testShellMode: shellMode
1788
1789@@ -86,7 +114,8 @@
1790 if (ApplicationManager.findApplication(appId)) {
1791 ApplicationManager.requestFocusApplication(appId);
1792 } else {
1793- var execFlags = shell.sideStageEnabled ? ApplicationManager.NoFlag : ApplicationManager.ForceMainStage;
1794+ var execFlags = shell.usageScenario === "phone" ? ApplicationManager.ForceMainStage
1795+ : ApplicationManager.NoFlag;
1796 ApplicationManager.startApplication(appId, execFlags);
1797 }
1798 }
1799@@ -124,11 +153,6 @@
1800 sourceSize.width: 0
1801 }
1802
1803- GSettings {
1804- id: usageModeSettings
1805- schema.id: "com.canonical.Unity8"
1806- }
1807-
1808 Binding {
1809 target: LauncherModel
1810 property: "applicationManager"
1811@@ -140,9 +164,7 @@
1812 if (ApplicationManager.count > 0) {
1813 ApplicationManager.focusApplication(ApplicationManager.get(0).appId);
1814 }
1815- if (orientationLockEnabled) {
1816- orientation = OrientationLock.savedOrientation;
1817- }
1818+ finishStartUpTimer.start();
1819 }
1820
1821 VolumeControl {
1822@@ -231,9 +253,19 @@
1823 // theoretical attack where user enters lockedApp mode, then makes
1824 // the screen larger (maybe connects to monitor) and tries to enter
1825 // tablet mode.
1826- property bool tabletMode: shell.sideStageEnabled && !greeter.hasLockedApp
1827- source: usageModeSettings.usageMode === "Windowed" ? "Stages/DesktopStage.qml"
1828- : tabletMode ? "Stages/TabletStage.qml" : "Stages/PhoneStage.qml"
1829+
1830+ property string usageScenario: shell.usageScenario === "phone" || greeter.hasLockedApp
1831+ ? "phone"
1832+ : shell.usageScenario
1833+ source: {
1834+ if (applicationsDisplayLoader.usageScenario === "phone") {
1835+ return "Stages/PhoneStage.qml";
1836+ } else if (applicationsDisplayLoader.usageScenario === "tablet") {
1837+ return "Stages/TabletStage.qml";
1838+ } else {
1839+ return "Stages/DesktopStage.qml";
1840+ }
1841+ }
1842
1843 property bool interactive: tutorial.spreadEnabled
1844 && !greeter.shown
1845@@ -276,7 +308,12 @@
1846 }
1847 Binding {
1848 target: applicationsDisplayLoader.item
1849- property: "orientation"
1850+ property: "shellOrientationAngle"
1851+ value: shell.orientationAngle
1852+ }
1853+ Binding {
1854+ target: applicationsDisplayLoader.item
1855+ property: "shellOrientation"
1856 value: shell.orientation
1857 }
1858 Binding {
1859@@ -284,6 +321,31 @@
1860 property: "background"
1861 value: shell.background
1862 }
1863+ Binding {
1864+ target: applicationsDisplayLoader.item
1865+ property: "shellPrimaryOrientation"
1866+ value: shell.primaryOrientation
1867+ }
1868+ Binding {
1869+ target: applicationsDisplayLoader.item
1870+ property: "nativeOrientation"
1871+ value: shell.nativeOrientation
1872+ }
1873+ Binding {
1874+ target: applicationsDisplayLoader.item
1875+ property: "nativeWidth"
1876+ value: shell.nativeWidth
1877+ }
1878+ Binding {
1879+ target: applicationsDisplayLoader.item
1880+ property: "nativeHeight"
1881+ value: shell.nativeHeight
1882+ }
1883+ Binding {
1884+ target: applicationsDisplayLoader.item
1885+ property: "beingResized"
1886+ value: shell.beingResized
1887+ }
1888 }
1889
1890 Tutorial {
1891@@ -353,7 +415,7 @@
1892 objectName: "greeter"
1893
1894 hides: [launcher, panel.indicators]
1895- tabletMode: shell.sideStageEnabled
1896+ tabletMode: shell.usageScenario !== "phone"
1897 launcherOffset: launcher.progress
1898 forcedUnlock: tutorial.running
1899 background: shell.background
1900@@ -480,20 +542,18 @@
1901 expandedPanelHeight: units.gu(7)
1902
1903 indicatorsModel: Indicators.IndicatorsModel {
1904- // TODO: This should be sourced by device type (e.g. "desktop", "tablet", "phone"...)
1905- profile: indicatorProfile
1906- Component.onCompleted: load()
1907+ // tablet and phone both use the same profile
1908+ profile: shell.usageScenario === "desktop" ? "desktop" : "phone"
1909+ Component.onCompleted: load();
1910 }
1911 }
1912+
1913 callHint {
1914 greeterShown: greeter.shown
1915 }
1916
1917- property bool topmostApplicationIsFullscreen:
1918- ApplicationManager.focusedApplicationId &&
1919- ApplicationManager.findApplication(ApplicationManager.focusedApplicationId).fullscreen
1920-
1921- fullscreenMode: (topmostApplicationIsFullscreen && !LightDM.Greeter.active && launcher.progress == 0)
1922+ property bool mainAppIsFullscreen: shell.mainApp && shell.mainApp.fullscreen
1923+ fullscreenMode: (mainAppIsFullscreen && !LightDM.Greeter.active && launcher.progress == 0)
1924 || greeter.hasLockedApp
1925 }
1926
1927@@ -511,7 +571,7 @@
1928 available: tutorial.launcherEnabled
1929 && (!greeter.locked || AccountsService.enableLauncherWhileLocked)
1930 && !greeter.hasLockedApp
1931- inverted: usageModeSettings.usageMode === "Staged"
1932+ inverted: shell.usageScenario !== "desktop"
1933 shadeBackground: !tutorial.running
1934
1935 onShowDashHome: showHome()
1936@@ -553,7 +613,7 @@
1937 Rectangle {
1938 id: modalNotificationBackground
1939
1940- visible: notifications.useModal && (notifications.state == "narrow")
1941+ visible: notifications.useModal
1942 color: "#000000"
1943 anchors.fill: parent
1944 opacity: 0.9
1945@@ -598,6 +658,7 @@
1946
1947 Dialogs {
1948 id: dialogs
1949+ objectName: "dialogs"
1950 anchors.fill: parent
1951 z: overlay.z + 10
1952 onPowerOffClicked: {
1953
1954=== modified file 'qml/Stages/ApplicationWindow.qml'
1955--- qml/Stages/ApplicationWindow.qml 2015-02-26 22:35:53 +0000
1956+++ qml/Stages/ApplicationWindow.qml 2015-04-16 14:12:24 +0000
1957@@ -1,5 +1,5 @@
1958 /*
1959- * Copyright 2014 Canonical Ltd.
1960+ * Copyright 2014-2015 Canonical Ltd.
1961 *
1962 * This program is free software; you can redistribute it and/or modify
1963 * it under the terms of the GNU Lesser General Public License as published by
1964@@ -24,10 +24,11 @@
1965 // to be read from outside
1966 readonly property bool fullscreen: application ? application.fullscreen : false
1967 property alias interactive: sessionContainer.interactive
1968+ property bool orientationChangesEnabled: d.supportsSurfaceResize ? d.surfaceOldEnoughToBeResized : true
1969
1970 // to be set from outside
1971 property QtObject application
1972- property int orientation
1973+ property int surfaceOrientationAngle
1974
1975 QtObject {
1976 id: d
1977@@ -62,6 +63,15 @@
1978 // Remove this when possible
1979 property bool surfaceInitialized: false
1980
1981+ property bool supportsSurfaceResize:
1982+ application &&
1983+ ((application.supportedOrientations & Qt.PortraitOrientation)
1984+ || (application.supportedOrientations & Qt.InvertedPortraitOrientation))
1985+ &&
1986+ ((application.supportedOrientations & Qt.LandscapeOrientation)
1987+ || (application.supportedOrientations & Qt.InvertedLandscapeOrientation))
1988+
1989+ property bool surfaceOldEnoughToBeResized: false
1990 }
1991
1992 Timer {
1993@@ -70,6 +80,12 @@
1994 onTriggered: { if (sessionContainer.surface) {d.surfaceInitialized = true;} }
1995 }
1996
1997+ Timer {
1998+ id: surfaceIsOldTimer
1999+ interval: 1000
2000+ onTriggered: { if (stateGroup.state === "surface") { d.surfaceOldEnoughToBeResized = true; } }
2001+ }
2002+
2003 Image {
2004 id: screenshotImage
2005 objectName: "screenshotImage"
2006@@ -113,7 +129,8 @@
2007 // A fake application might not even have a session property.
2008 session: application && application.session ? application.session : null
2009 anchors.fill: parent
2010- orientation: root.orientation
2011+
2012+ surfaceOrientationAngle: application && application.rotatesWindowContents ? root.surfaceOrientationAngle : 0
2013
2014 onSurfaceChanged: {
2015 if (sessionContainer.surface) {
2016@@ -179,15 +196,21 @@
2017 UbuntuNumberAnimation { target: sessionContainer.surfaceContainer; property: "opacity";
2018 from: 0.0; to: 1.0
2019 duration: UbuntuAnimation.BriskDuration }
2020- PropertyAction { target: splashLoader; property: "active"; value: false }
2021+ ScriptAction { script: {
2022+ splashLoader.active = false;
2023+ surfaceIsOldTimer.start();
2024+ } }
2025 }
2026 },
2027 Transition {
2028 from: "surface"; to: "splashScreen"
2029 SequentialAnimation {
2030- PropertyAction { target: splashLoader; property: "active"; value: true }
2031- PropertyAction { target: sessionContainer.surfaceContainer
2032- property: "visible"; value: true }
2033+ ScriptAction { script: {
2034+ surfaceIsOldTimer.stop();
2035+ d.surfaceOldEnoughToBeResized = false;
2036+ splashLoader.active = true;
2037+ sessionContainer.surfaceContainer.visible = true;
2038+ } }
2039 UbuntuNumberAnimation { target: splashLoader; property: "opacity";
2040 from: 0.0; to: 1.0
2041 duration: UbuntuAnimation.BriskDuration }
2042@@ -198,14 +221,18 @@
2043 Transition {
2044 from: "surface"; to: "screenshot"
2045 SequentialAnimation {
2046- PropertyAction { target: screenshotImage
2047- property: "visible"; value: true }
2048+ ScriptAction { script: {
2049+ surfaceIsOldTimer.stop();
2050+ d.surfaceOldEnoughToBeResized = false;
2051+ screenshotImage.visible = true;
2052+ } }
2053 UbuntuNumberAnimation { target: screenshotImage; property: "opacity";
2054 from: 0.0; to: 1.0
2055 duration: UbuntuAnimation.BriskDuration }
2056- PropertyAction { target: sessionContainer.surfaceContainer
2057- property: "visible"; value: false }
2058- ScriptAction { script: { if (sessionContainer.session) { sessionContainer.session.release(); } } }
2059+ ScriptAction { script: {
2060+ sessionContainer.surfaceContainer.visible = false;
2061+ if (sessionContainer.session) { sessionContainer.session.release(); }
2062+ } }
2063 }
2064 },
2065 Transition {
2066@@ -216,8 +243,11 @@
2067 UbuntuNumberAnimation { target: screenshotImage; property: "opacity";
2068 from: 1.0; to: 0.0
2069 duration: UbuntuAnimation.BriskDuration }
2070- PropertyAction { target: screenshotImage; property: "visible"; value: false }
2071- PropertyAction { target: screenshotImage; property: "source"; value: "" }
2072+ ScriptAction { script: {
2073+ screenshotImage.visible = false;
2074+ screenshotImage.source = "";
2075+ surfaceIsOldTimer.start();
2076+ } }
2077 }
2078 },
2079 Transition {
2080@@ -233,10 +263,12 @@
2081 },
2082 Transition {
2083 from: "surface"; to: "void"
2084- SequentialAnimation {
2085- PropertyAction { target: sessionContainer.surfaceContainer; property: "visible"; value: false }
2086- ScriptAction { script: { if (sessionContainer.session) { sessionContainer.session.release(); } } }
2087- }
2088+ ScriptAction { script: {
2089+ surfaceIsOldTimer.stop();
2090+ d.surfaceOldEnoughToBeResized = false;
2091+ sessionContainer.surfaceContainer.visible = false;
2092+ if (sessionContainer.session) { sessionContainer.session.release(); }
2093+ } }
2094 },
2095 Transition {
2096 from: "void"; to: "surface"
2097@@ -246,6 +278,9 @@
2098 UbuntuNumberAnimation { target: sessionContainer.surfaceContainer; property: "opacity";
2099 from: 0.0; to: 1.0
2100 duration: UbuntuAnimation.BriskDuration }
2101+ ScriptAction { script: {
2102+ surfaceIsOldTimer.start();
2103+ } }
2104 }
2105 }
2106 ]
2107
2108=== modified file 'qml/Stages/DesktopStage.qml'
2109--- qml/Stages/DesktopStage.qml 2015-03-13 19:18:35 +0000
2110+++ qml/Stages/DesktopStage.qml 2015-04-16 14:12:24 +0000
2111@@ -27,6 +27,29 @@
2112
2113 anchors.fill: parent
2114
2115+ // Controls to be set from outside
2116+ property int dragAreaWidth // just to comply with the interface shared between stages
2117+ property real maximizedAppTopMargin
2118+ property bool interactive
2119+ property bool spreadEnabled // just to comply with the interface shared between stages
2120+ property real inverseProgress: 0 // just to comply with the interface shared between stages
2121+ property int shellOrientationAngle: 0
2122+ property int shellOrientation
2123+ property int shellPrimaryOrientation
2124+ property int nativeOrientation
2125+ property bool beingResized: false
2126+
2127+ // functions to be called from outside
2128+ function updateFocusedAppOrientation() { /* TODO */ }
2129+ function updateFocusedAppOrientationAnimated() { /* TODO */}
2130+
2131+ // To be read from outside
2132+ readonly property var mainApp: ApplicationManager.focusedApplicationId
2133+ ? ApplicationManager.findApplication(ApplicationManager.focusedApplicationId)
2134+ : null
2135+ property int mainAppWindowOrientationAngle: 0
2136+ readonly property bool orientationChangesEnabled: false
2137+
2138 property alias background: wallpaper.source
2139
2140 property var windowStateStorage: WindowStateStorage
2141
2142=== added file 'qml/Stages/OrientationChangeAnimation.qml'
2143--- qml/Stages/OrientationChangeAnimation.qml 1970-01-01 00:00:00 +0000
2144+++ qml/Stages/OrientationChangeAnimation.qml 2015-04-16 14:12:24 +0000
2145@@ -0,0 +1,243 @@
2146+/*
2147+ * Copyright 2015 Canonical Ltd.
2148+ *
2149+ * This program is free software; you can redistribute it and/or modify
2150+ * it under the terms of the GNU Lesser General Public License as published by
2151+ * the Free Software Foundation; version 3.
2152+ *
2153+ * This program is distributed in the hope that it will be useful,
2154+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2155+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2156+ * GNU Lesser General Public License for more details.
2157+ *
2158+ * You should have received a copy of the GNU Lesser General Public License
2159+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2160+ */
2161+
2162+import QtQuick 2.3
2163+
2164+QtObject {
2165+ id: root
2166+
2167+ // to be set from outside
2168+ property Item spreadDelegate
2169+ property Item background
2170+ property Item window
2171+ property Image screenshot
2172+
2173+ function start() {
2174+ if (window.orientationAngle === 0) {
2175+ if (spreadDelegate.shellOrientationAngle === 90) {
2176+ chosenAnimation = simple90Animation;
2177+ } else if (spreadDelegate.shellOrientationAngle === 180) {
2178+ chosenAnimation = halfLoopAnimation;
2179+ } else if (spreadDelegate.shellOrientationAngle === 270) {
2180+ chosenAnimation = moving90Animation;
2181+ } else {
2182+ chosenAnimation = null;
2183+ }
2184+ } else if (window.orientationAngle === 90) {
2185+ if (spreadDelegate.shellOrientationAngle === 0) {
2186+ chosenAnimation = simple90Animation;
2187+ } else if (spreadDelegate.shellOrientationAngle === 180) {
2188+ chosenAnimation = moving90Animation;
2189+ } else if (spreadDelegate.shellOrientationAngle === 270) {
2190+ chosenAnimation = halfLoopAnimation;
2191+ } else {
2192+ chosenAnimation = null;
2193+ }
2194+ } else if (window.orientationAngle === 180) {
2195+ if (spreadDelegate.shellOrientationAngle === 0) {
2196+ chosenAnimation = halfLoopAnimation;
2197+ } else if (spreadDelegate.shellOrientationAngle === 90) {
2198+ chosenAnimation = moving90Animation;
2199+ } else if (spreadDelegate.shellOrientationAngle === 270) {
2200+ chosenAnimation = simple90Animation;
2201+ } else {
2202+ chosenAnimation = null;
2203+ }
2204+ } else if (window.orientationAngle === 270) {
2205+ if (spreadDelegate.shellOrientationAngle === 0) {
2206+ chosenAnimation = moving90Animation;
2207+ } else if (spreadDelegate.shellOrientationAngle === 90) {
2208+ chosenAnimation = halfLoopAnimation;
2209+ } else if (spreadDelegate.shellOrientationAngle === 180) {
2210+ chosenAnimation = simple90Animation;
2211+ } else {
2212+ chosenAnimation = null;
2213+ }
2214+ }
2215+
2216+ if (chosenAnimation)
2217+ chosenAnimation.start();
2218+ }
2219+
2220+ // to be read from outside
2221+ property bool running: chosenAnimation ? chosenAnimation.running : false
2222+
2223+ property int duration: 450
2224+ property int easingType: Easing.InOutCubic
2225+ // Those values are good for debugging/development
2226+ //property int duration: 6000
2227+ //property int easingType: Easing.Linear
2228+
2229+ property int shortestDimension: spreadDelegate.width < spreadDelegate.height
2230+ ? spreadDelegate.width : spreadDelegate.height
2231+ property int longestDimension: spreadDelegate.width > spreadDelegate.height
2232+ ? spreadDelegate.width : spreadDelegate.height
2233+ property string longestAxis: spreadDelegate.width > spreadDelegate.height ? "x" : "y"
2234+
2235+ property QtObject chosenAnimation
2236+
2237+ function setup90Animation() {
2238+ background.visible = true;
2239+
2240+ screenshot.width = window.width
2241+ screenshot.height = window.height
2242+ screenshot.take();
2243+ screenshot.transformOriginX = root.shortestDimension / 2
2244+ screenshot.transformOriginY = root.shortestDimension / 2
2245+ screenshot.visible = true;
2246+
2247+ window.rotation = 0;
2248+ window.width = spreadDelegate.width;
2249+ window.height = spreadDelegate.height;
2250+ window.transformOriginX = root.shortestDimension / 2
2251+ window.transformOriginY = root.shortestDimension / 2
2252+ }
2253+
2254+ function tearDown90Animation() {
2255+ window.orientationAngle = spreadDelegate.shellOrientationAngle;
2256+ screenshot.source = "";
2257+ screenshot.visible = false;
2258+ background.visible = false;
2259+ }
2260+
2261+ property QtObject simple90Animation: SequentialAnimation {
2262+ id: simple90Animation
2263+
2264+ ScriptAction { script: setup90Animation() }
2265+ ParallelAnimation {
2266+ RotationAnimation {
2267+ target: root.window
2268+ duration: root.duration
2269+ easing.type: root.easingType
2270+ from: window.orientationAngle - spreadDelegate.shellOrientationAngle
2271+ to: 0
2272+ property: "transformRotationAngle"
2273+ }
2274+ RotationAnimation {
2275+ target: root.screenshot
2276+ duration: root.duration
2277+ easing.type: root.easingType
2278+ from: window.orientationAngle - spreadDelegate.shellOrientationAngle
2279+ to: 0
2280+ property: "transformRotationAngle"
2281+ }
2282+ NumberAnimation {
2283+ target: root.screenshot
2284+ duration: root.duration
2285+ easing.type: root.easingType
2286+ property: "opacity"
2287+ from: 1.0
2288+ to: 0.0
2289+ }
2290+ NumberAnimation {
2291+ target: root.window
2292+ duration: root.duration
2293+ easing.type: root.easingType
2294+ property: "opacity"
2295+ from: 0.0
2296+ to: 1.0
2297+ }
2298+ }
2299+ ScriptAction { script: tearDown90Animation() }
2300+ }
2301+
2302+ property QtObject moving90Animation: SequentialAnimation {
2303+ id: moving90Animation
2304+
2305+ ScriptAction { script: setup90Animation() }
2306+ ParallelAnimation {
2307+ RotationAnimation {
2308+ target: root.window
2309+ duration: root.duration
2310+ easing.type: root.easingType
2311+ direction: RotationAnimation.Shortest
2312+ from: window.orientationAngle - spreadDelegate.shellOrientationAngle
2313+ to: 0
2314+ property: "transformRotationAngle"
2315+ }
2316+ RotationAnimation {
2317+ target: root.screenshot
2318+ duration: root.duration
2319+ easing.type: root.easingType
2320+ direction: RotationAnimation.Shortest
2321+ from: window.orientationAngle - spreadDelegate.shellOrientationAngle
2322+ to: 0
2323+ property: "transformRotationAngle"
2324+ }
2325+ NumberAnimation {
2326+ target: root.screenshot
2327+ duration: root.duration
2328+ easing.type: root.easingType
2329+ property: "opacity"
2330+ from: 1.0
2331+ to: 0.0
2332+ }
2333+ NumberAnimation {
2334+ target: root.window
2335+ duration: root.duration
2336+ easing.type: root.easingType
2337+ property: "opacity"
2338+ from: 0.0
2339+ to: 1.0
2340+ }
2341+ NumberAnimation {
2342+ target: root.window
2343+ duration: root.duration
2344+ easing.type: root.easingType
2345+ property: root.longestAxis
2346+ from: root.longestDimension - root.shortestDimension
2347+ to: 0
2348+ }
2349+ NumberAnimation {
2350+ target: root.screenshot
2351+ duration: root.duration
2352+ easing.type: root.easingType
2353+ property: root.longestAxis
2354+ from: root.longestDimension - root.shortestDimension
2355+ to: 0
2356+ }
2357+ }
2358+ ScriptAction { script: tearDown90Animation() }
2359+ }
2360+
2361+ property QtObject halfLoopAnimation: SequentialAnimation {
2362+ id: halfLoopAnimation
2363+
2364+ ScriptAction { script: {
2365+ background.visible = true;
2366+
2367+ window.rotation = 0;
2368+ window.width = spreadDelegate.width;
2369+ window.height = spreadDelegate.height;
2370+ window.transformOriginX = window.width / 2
2371+ window.transformOriginY = window.height / 2
2372+ } }
2373+ ParallelAnimation {
2374+ RotationAnimation {
2375+ target: root.window
2376+ duration: root.duration
2377+ easing.type: root.easingType
2378+ from: window.orientationAngle - spreadDelegate.shellOrientationAngle
2379+ to: 0
2380+ property: "transformRotationAngle"
2381+ }
2382+ }
2383+ ScriptAction { script: {
2384+ window.orientationAngle = spreadDelegate.shellOrientationAngle;
2385+ background.visible = false;
2386+ } }
2387+ }
2388+}
2389
2390=== modified file 'qml/Stages/PhoneStage.qml'
2391--- qml/Stages/PhoneStage.qml 2015-02-18 18:29:03 +0000
2392+++ qml/Stages/PhoneStage.qml 2015-04-16 14:12:24 +0000
2393@@ -1,5 +1,5 @@
2394 /*
2395- * Copyright (C) 2014 Canonical, Ltd.
2396+ * Copyright (C) 2014-2015 Canonical, Ltd.
2397 *
2398 * This program is free software; you can redistribute it and/or modify
2399 * it under the terms of the GNU General Public License as published by
2400@@ -31,12 +31,64 @@
2401 property bool interactive
2402 property bool spreadEnabled: true // If false, animations and right edge will be disabled
2403 property real inverseProgress: 0 // This is the progress for left edge drags, in pixels.
2404- property int orientation: Qt.PortraitOrientation
2405 property QtObject applicationManager: ApplicationManager
2406 property bool focusFirstApp: true // If false, focused app will appear on right edge like other apps
2407 property bool altTabEnabled: true
2408 property real startScale: 1.1
2409 property real endScale: 0.7
2410+ property int shellOrientationAngle: 0
2411+ property int shellOrientation
2412+ property int shellPrimaryOrientation
2413+ property int nativeOrientation
2414+ property real nativeWidth
2415+ property real nativeHeight
2416+ property bool beingResized: false
2417+ onBeingResizedChanged: {
2418+ if (beingResized) {
2419+ // Brace yourselves for impact!
2420+ spreadView.selectedIndex = -1;
2421+ spreadView.phase = 0;
2422+ spreadView.contentX = -spreadView.shift;
2423+ }
2424+ }
2425+ function updateFocusedAppOrientation() {
2426+ if (spreadRepeater.count > 0) {
2427+ spreadRepeater.itemAt(0).matchShellOrientation();
2428+ }
2429+
2430+ for (var i = 1; i < spreadRepeater.count; ++i) {
2431+
2432+ var spreadDelegate = spreadRepeater.itemAt(i);
2433+
2434+ var delta = spreadDelegate.appWindowOrientationAngle - root.shellOrientationAngle;
2435+ if (delta < 0) { delta += 360; }
2436+ delta = delta % 360;
2437+
2438+ var supportedOrientations = spreadDelegate.application.supportedOrientations;
2439+ if (supportedOrientations === Qt.PrimaryOrientation) {
2440+ supportedOrientations = spreadDelegate.shellPrimaryOrientation;
2441+ }
2442+
2443+ if (delta === 180 && (supportedOrientations & spreadDelegate.shellOrientation)) {
2444+ spreadDelegate.matchShellOrientation();
2445+ }
2446+ }
2447+ }
2448+ function updateFocusedAppOrientationAnimated() {
2449+ if (spreadRepeater.count > 0) {
2450+ spreadRepeater.itemAt(0).animateToShellOrientation();
2451+ }
2452+ }
2453+
2454+ // To be read from outside
2455+ readonly property var mainApp: applicationManager.focusedApplicationId
2456+ ? applicationManager.findApplication(applicationManager.focusedApplicationId)
2457+ : null
2458+ property int mainAppWindowOrientationAngle: 0
2459+ readonly property bool orientationChangesEnabled: priv.focusedAppOrientationChangesEnabled
2460+ && !priv.focusedAppDelegateIsDislocated
2461+ && !(priv.focusedAppDelegate && priv.focusedAppDelegate.xBehavior.running)
2462+ && spreadView.phase === 0
2463
2464 // How far left the stage has been dragged
2465 readonly property real dragProgress: spreadRepeater.count > 0 ? -spreadRepeater.itemAt(0).xTranslate : 0
2466@@ -54,12 +106,6 @@
2467 spreadView.snapTo(priv.indexOf(appId));
2468 }
2469
2470- onWidthChanged: {
2471- spreadView.selectedIndex = -1;
2472- spreadView.phase = 0;
2473- spreadView.contentX = -spreadView.shift;
2474- }
2475-
2476 onInverseProgressChanged: {
2477 // This can't be a simple binding because that would be triggered after this handler
2478 // while we need it active before doing the anition left/right
2479@@ -73,6 +119,20 @@
2480 priv.oldInverseProgress = inverseProgress;
2481 }
2482
2483+ // <FIXME-contentX> See rationale in the next comment with this tag
2484+ onWidthChanged: {
2485+ if (!root.beingResized) {
2486+ // we're being resized without a warning (ie, the corresponding property wasn't set
2487+ root.beingResized = true;
2488+ beingResizedTimer.start();
2489+ }
2490+ }
2491+ Timer {
2492+ id: beingResizedTimer
2493+ interval: 100
2494+ onTriggered: { root.beingResized = false; }
2495+ }
2496+
2497 Connections {
2498 target: applicationManager
2499
2500@@ -115,10 +175,10 @@
2501 QtObject {
2502 id: priv
2503
2504- readonly property int firstSpreadIndex: root.focusFirstApp ? 1 : 0
2505- property string focusedAppId: applicationManager.focusedApplicationId
2506- property var focusedApplication: applicationManager.findApplication(focusedAppId)
2507+ property string focusedAppId: root.applicationManager.focusedApplicationId
2508+ property var focusedApplication: root.applicationManager.findApplication(focusedAppId)
2509 property var focusedAppDelegate: null
2510+ property bool focusedAppOrientationChangesEnabled: false
2511
2512 property real oldInverseProgress: 0
2513 property bool animateX: false
2514@@ -131,15 +191,27 @@
2515 }
2516 }
2517
2518+ property bool focusedAppDelegateIsDislocated: focusedAppDelegate && focusedAppDelegate.x !== 0
2519+
2520 function indexOf(appId) {
2521- for (var i = 0; i < applicationManager.count; i++) {
2522- if (applicationManager.get(i).appId == appId) {
2523+ for (var i = 0; i < root.applicationManager.count; i++) {
2524+ if (root.applicationManager.get(i).appId == appId) {
2525 return i;
2526 }
2527 }
2528 return -1;
2529 }
2530
2531+ // Is more stable than "spreadView.shiftedContentX === 0" as it filters out noise caused by
2532+ // Flickable.contentX changing due to resizes.
2533+ property bool fullyShowingFocusedApp: true
2534+ }
2535+ Timer {
2536+ id: fullyShowingFocusedAppUpdateTimer
2537+ interval: 100
2538+ onTriggered: {
2539+ priv.fullyShowingFocusedApp = spreadView.shiftedContentX === 0;
2540+ }
2541 }
2542
2543 Flickable {
2544@@ -153,7 +225,9 @@
2545
2546 // This indicates when the spreadView is active. That means, all the animations
2547 // are activated and tiles need to line up for the spread.
2548- readonly property bool active: shiftedContentX > 0 || spreadDragArea.status === DirectionalDragArea.Recognized || !root.focusFirstApp
2549+ readonly property bool active: shiftedContentX > 0
2550+ || spreadDragArea.status === DirectionalDragArea.Recognized
2551+ || !root.focusFirstApp
2552
2553 // The flickable needs to fill the screen in order to get touch events all over.
2554 // However, we don't want to the user to be able to scroll back all the way. For
2555@@ -188,9 +262,25 @@
2556 property int draggedDelegateCount: 0
2557 property int closingIndex: -1
2558
2559- property bool focusChanging: false
2560+ // <FIXME-contentX> Workaround Flickable's behavior of bringing contentX back between valid boundaries
2561+ // when resized. The proper way to fix this is refactoring PhoneStage so that it doesn't
2562+ // rely on having Flickable.contentX keeping an out-of-bounds value when it's set programatically
2563+ // (as opposed to having contentX reaching an out-of-bounds value through dragging, which will trigger
2564+ // the Flickable.boundsBehavior upon release).
2565+ onContentXChanged: { forceItToRemainStillIfBeingResized(); }
2566+ onShiftChanged: { forceItToRemainStillIfBeingResized(); }
2567+ function forceItToRemainStillIfBeingResized() {
2568+ if (root.beingResized && contentX != -spreadView.shift) {
2569+ contentX = -spreadView.shift;
2570+ }
2571+ }
2572
2573 onShiftedContentXChanged: {
2574+ if (root.beingResized) {
2575+ // Flickabe.contentX wiggles during resizes. Don't react to it.
2576+ return;
2577+ }
2578+
2579 switch (phase) {
2580 case 0:
2581 if (shiftedContentX > width * positionMarker2) {
2582@@ -205,6 +295,7 @@
2583 }
2584 break;
2585 }
2586+ fullyShowingFocusedAppUpdateTimer.restart();
2587 }
2588
2589 function snap() {
2590@@ -229,7 +320,7 @@
2591 snapAnimation.start();
2592 return;
2593 }
2594- if (applicationManager.count <= index) {
2595+ if (root.applicationManager.count <= index) {
2596 // In case we're trying to snap to some non existing app, lets snap back to the first one
2597 index = 0;
2598 }
2599@@ -266,7 +357,7 @@
2600 ScriptAction {
2601 script: {
2602 if (spreadView.selectedIndex >= 0) {
2603- applicationManager.focusApplication(applicationManager.get(spreadView.selectedIndex).appId);
2604+ root.applicationManager.focusApplication(root.applicationManager.get(spreadView.selectedIndex).appId);
2605
2606 spreadView.selectedIndex = -1;
2607 spreadView.phase = 0;
2608@@ -281,7 +372,7 @@
2609 // This width controls how much the spread can be flicked left/right. It's composed of:
2610 // tileDistance * app count (with a minimum of 3 apps, in order to also allow moving 1 and 2 apps a bit)
2611 // + some constant value (still scales with the screen width) which looks good and somewhat fills the screen
2612- width: Math.max(3, applicationManager.count) * spreadView.tileDistance + (spreadView.width - spreadView.tileDistance) * 1.5
2613+ width: Math.max(3, root.applicationManager.count) * spreadView.tileDistance + (spreadView.width - spreadView.tileDistance) * 1.5
2614 height: parent.height
2615 Behavior on width {
2616 enabled: spreadView.closingIndex >= 0
2617@@ -304,7 +395,7 @@
2618 Repeater {
2619 id: spreadRepeater
2620 objectName: "spreadRepeater"
2621- model: applicationManager
2622+ model: root.applicationManager
2623 delegate: TransformedSpreadDelegate {
2624 id: appDelegate
2625 objectName: "appDelegate" + index
2626@@ -319,11 +410,10 @@
2627 selected: spreadView.selectedIndex == index
2628 otherSelected: spreadView.selectedIndex >= 0 && !selected
2629 interactive: !spreadView.interactive && spreadView.phase === 0
2630- && spreadView.shiftedContentX === 0 && root.interactive && isFocused
2631+ && priv.fullyShowingFocusedApp && root.interactive && isFocused
2632 swipeToCloseEnabled: spreadView.interactive && root.interactive && !snapAnimation.running
2633 maximizedAppTopMargin: root.maximizedAppTopMargin
2634- dropShadow: spreadView.active ||
2635- (priv.focusedAppDelegate && priv.focusedAppDelegate.x !== 0)
2636+ dropShadow: spreadView.active || priv.focusedAppDelegateIsDislocated
2637 focusFirstApp: root.focusFirstApp
2638
2639 readonly property bool isDash: model.appId == "unity8-dash"
2640@@ -346,7 +436,7 @@
2641 return spreadView.width + spreadIndex * spreadView.tileDistance;
2642 }
2643
2644- application: applicationManager.get(index)
2645+ application: root.applicationManager.get(index)
2646 closeable: !isDash
2647
2648 property real behavioredIndex: index
2649@@ -362,18 +452,16 @@
2650 }
2651 }
2652
2653+ property var xBehavior: xBehavior
2654 Behavior on x {
2655+ id: xBehavior
2656 enabled: root.spreadEnabled &&
2657 !spreadView.active &&
2658 !snapAnimation.running &&
2659- priv.animateX
2660+ priv.animateX &&
2661+ !root.beingResized
2662 UbuntuNumberAnimation {
2663 duration: UbuntuAnimation.BriskDuration
2664- onRunningChanged: {
2665- if (!running && root.inverseProgress == 0) {
2666- spreadView.focusChanging = false;
2667- }
2668- }
2669 }
2670 }
2671
2672@@ -413,22 +501,21 @@
2673 }
2674
2675 // Hiding tiles when their progress is negative or reached the maximum
2676- visible: (progress >= 0 && progress < 1.7) ||
2677- (isDash && priv.focusedAppDelegate.x !== 0)
2678-
2679- Binding {
2680- target: appDelegate
2681- property: "orientation"
2682- when: appDelegate.interactive
2683- value: root.orientation
2684- }
2685+ visible: (progress >= 0 && progress < 1.7)
2686+ || (isDash && priv.focusedAppDelegateIsDislocated)
2687+
2688+
2689+ shellOrientationAngle: root.shellOrientationAngle
2690+ shellOrientation: root.shellOrientation
2691+ shellPrimaryOrientation: root.shellPrimaryOrientation
2692+ nativeOrientation: root.nativeOrientation
2693
2694 onClicked: {
2695 if (root.altTabEnabled && spreadView.phase == 2) {
2696- if (applicationManager.focusedApplicationId == applicationManager.get(index).appId) {
2697+ if (root.applicationManager.focusedApplicationId == root.applicationManager.get(index).appId) {
2698 spreadView.snapTo(index);
2699 } else {
2700- applicationManager.requestFocusApplication(applicationManager.get(index).appId);
2701+ root.applicationManager.requestFocusApplication(root.applicationManager.get(index).appId);
2702 }
2703 }
2704 }
2705@@ -443,7 +530,20 @@
2706
2707 onClosed: {
2708 spreadView.closingIndex = index;
2709- applicationManager.stopApplication(applicationManager.get(index).appId);
2710+ root.applicationManager.stopApplication(root.applicationManager.get(index).appId);
2711+ }
2712+
2713+ Binding {
2714+ target: root
2715+ when: index == 0
2716+ property: "mainAppWindowOrientationAngle"
2717+ value: appWindowOrientationAngle
2718+ }
2719+ Binding {
2720+ target: priv
2721+ when: index == 0
2722+ property: "focusedAppOrientationChangesEnabled"
2723+ value: orientationChangesEnabled
2724 }
2725 }
2726 }
2727
2728=== modified file 'qml/Stages/SessionContainer.qml'
2729--- qml/Stages/SessionContainer.qml 2015-01-28 12:59:21 +0000
2730+++ qml/Stages/SessionContainer.qml 2015-04-16 14:12:24 +0000
2731@@ -1,5 +1,5 @@
2732 /*
2733- * Copyright 2014 Canonical Ltd.
2734+ * Copyright 2014-2015 Canonical Ltd.
2735 *
2736 * This program is free software; you can redistribute it and/or modify
2737 * it under the terms of the GNU Lesser General Public License as published by
2738@@ -24,14 +24,13 @@
2739 readonly property var childSessions: session ? session.childSessions : null
2740 readonly property alias surface: _surfaceContainer.surface
2741 property alias interactive: _surfaceContainer.interactive
2742- property int orientation
2743+ property alias surfaceOrientationAngle: _surfaceContainer.surfaceOrientationAngle
2744
2745 readonly property alias surfaceContainer: _surfaceContainer
2746 SurfaceContainer {
2747 id: _surfaceContainer
2748 anchors.fill: parent
2749 surface: session ? session.surface : null
2750- orientation: root.orientation
2751 }
2752
2753 Repeater {
2754@@ -72,11 +71,6 @@
2755 target: item; when: item
2756 property: "height"; value: root.height
2757 }
2758-
2759- Binding {
2760- target: item; when: item
2761- property: "orientation"; value: root.orientation
2762- }
2763 }
2764 }
2765
2766
2767=== modified file 'qml/Stages/SpreadDelegate.qml'
2768--- qml/Stages/SpreadDelegate.qml 2015-01-28 12:59:21 +0000
2769+++ qml/Stages/SpreadDelegate.qml 2015-04-16 14:12:24 +0000
2770@@ -1,5 +1,5 @@
2771 /*
2772- * Copyright 2014 Canonical Ltd.
2773+ * Copyright 2014-2015 Canonical Ltd.
2774 *
2775 * This program is free software; you can redistribute it and/or modify
2776 * it under the terms of the GNU Lesser General Public License as published by
2777@@ -18,6 +18,7 @@
2778 */
2779
2780 import QtQuick 2.0
2781+import QtQuick.Window 2.0
2782 import Ubuntu.Components 1.1
2783 import "../Components"
2784
2785@@ -28,6 +29,8 @@
2786 readonly property bool dragged: dragArea.moving
2787 signal clicked()
2788 signal closed()
2789+ readonly property alias appWindowOrientationAngle: appWindowWithShadow.orientationAngle
2790+ readonly property alias orientationChangesEnabled: appWindow.orientationChangesEnabled
2791
2792 // to be set from outside
2793 property bool interactive: true
2794@@ -36,10 +39,54 @@
2795 property alias swipeToCloseEnabled: dragArea.enabled
2796 property bool closeable
2797 property alias application: appWindow.application
2798- property int orientation
2799+ property int shellOrientationAngle
2800+ property int shellOrientation
2801+ property int shellPrimaryOrientation
2802+ property int nativeOrientation
2803+
2804+ function matchShellOrientation() {
2805+ if (!root.application)
2806+ return;
2807+ appWindowWithShadow.orientationAngle = root.shellOrientationAngle;
2808+ }
2809+
2810+ function animateToShellOrientation() {
2811+ if (!root.application)
2812+ return;
2813+
2814+ if (root.application.rotatesWindowContents) {
2815+ appWindowWithShadow.orientationAngle = root.shellOrientationAngle;
2816+ } else {
2817+ orientationChangeAnimation.start();
2818+ }
2819+ }
2820+
2821+ OrientationChangeAnimation {
2822+ id: orientationChangeAnimation
2823+ objectName: "orientationChangeAnimation"
2824+ spreadDelegate: root
2825+ background: background
2826+ window: appWindowWithShadow
2827+ screenshot: appWindowScreenshot
2828+ }
2829+
2830+ QtObject {
2831+ id: priv
2832+ property bool startingUp: true
2833+ }
2834+
2835+ Component.onCompleted: { finishStartUpTimer.start(); }
2836+ Timer { id: finishStartUpTimer; interval: 400; onTriggered: priv.startingUp = false }
2837+
2838+ Rectangle {
2839+ id: background
2840+ color: "black"
2841+ anchors.fill: parent
2842+ visible: false
2843+ }
2844
2845 Item {
2846- objectName: "appWindowWithShadow"
2847+ objectName: "displacedAppWindowWithShadow"
2848
2849 readonly property real limit: root.height / 4
2850
2851@@ -52,28 +99,198 @@
2852 return k * (1 - Math.pow((k - 1) / k, distance))
2853 }
2854
2855- BorderImage {
2856- anchors {
2857- fill: appWindow
2858- margins: -units.gu(2)
2859- }
2860- source: "graphics/dropshadow2gu.sci"
2861- opacity: root.dropShadow ? .3 : 0
2862- Behavior on opacity { UbuntuNumberAnimation {} }
2863- }
2864-
2865- ApplicationWindow {
2866- id: appWindow
2867- objectName: application ? "appWindow_" + application.appId : "appWindow_null"
2868- focus: true
2869- anchors {
2870- fill: parent
2871- topMargin: appWindow.fullscreen ? 0 : maximizedAppTopMargin
2872- }
2873-
2874- interactive: root.interactive
2875- orientation: root.orientation
2876- }
2877+ Item {
2878+ id: appWindowWithShadow
2879+ objectName: "appWindowWithShadow"
2880+
2881+ property int orientationAngle
2882+
2883+ property real transformRotationAngle: 0
2884+ property real transformOriginX
2885+ property real transformOriginY
2886+
2887+ transform: Rotation {
2888+ origin.x: appWindowWithShadow.transformOriginX
2889+ origin.y: appWindowWithShadow.transformOriginY
2890+ axis { x: 0; y: 0; z: 1 }
2891+ angle: appWindowWithShadow.transformRotationAngle
2892+ }
2893+
2894+ state: {
2895+ if (priv.startingUp) {
2896+ return "startingUp";
2897+ } else if (root.application && root.application.rotatesWindowContents) {
2898+ return "counterRotate";
2899+ } else if (orientationChangeAnimation.running) {
2900+ return "animatingRotation";
2901+ } else {
2902+ return "keepSceneRotation";
2903+ }
2904+ }
2905+
2906+ states: [
2907+ // Sets the initial orientationAngle of the window, when it first slides into view
2908+ // (with the splash screen likely being displayed). At that point we just try to
2909+ // match shell's current orientation. We need a bit of time in this state as the
2910+ // information we need to decide orientationAngle may take a few cycles to
2911+ // be set.
2912+ State {
2913+ name: "startingUp"
2914+ PropertyChanges {
2915+ target: appWindowWithShadow
2916+ restoreEntryValues: false
2917+ orientationAngle: {
2918+ if (!root.application || root.application.rotatesWindowContents) {
2919+ return 0;
2920+ }
2921+ var supportedOrientations = root.application.supportedOrientations;
2922+
2923+ if (supportedOrientations === Qt.PrimaryOrientation) {
2924+ supportedOrientations = root.shellPrimaryOrientation;
2925+ }
2926+
2927+ // If it doesn't support shell's current orientation
2928+ // then simply pick some arbitraty one that it does support
2929+ var chosenOrientation = 0;
2930+ if (supportedOrientations & root.shellOrientation) {
2931+ chosenOrientation = root.shellOrientation;
2932+ } else if (supportedOrientations & Qt.PortraitOrientation) {
2933+ chosenOrientation = Qt.PortraitOrientation;
2934+ } else if (supportedOrientations & Qt.LandscapeOrientation) {
2935+ chosenOrientation = Qt.LandscapeOrientation;
2936+ } else if (supportedOrientations & Qt.InvertedPortraitOrientation) {
2937+ chosenOrientation = Qt.InvertedPortraitOrientation;
2938+ } else if (supportedOrientations & Qt.InvertedLandscapeOrientation) {
2939+ chosenOrientation = Qt.InvertedLandscapeOrientation;
2940+ } else {
2941+ chosenOrientation = root.shellPrimaryOrientation;
2942+ }
2943+
2944+ return Screen.angleBetween(root.nativeOrientation, chosenOrientation);
2945+ }
2946+
2947+ rotation: appWindowWithShadow.orientationAngle - root.shellOrientationAngle
2948+ width: {
2949+ if (rotation == 0 || Math.abs(rotation) == 180) {
2950+ return root.width;
2951+ } else {
2952+ return root.height;
2953+ }
2954+ }
2955+ height: {
2956+ if (rotation == 0 || Math.abs(rotation) == 180)
2957+ return root.height;
2958+ else
2959+ return root.width;
2960+ }
2961+ }
2962+ },
2963+ // In this state we stick to our currently set orientationAngle, which may change only due
2964+ // to calls made to matchShellOrientation() or animateToShellOrientation()
2965+ State {
2966+ id: keepSceneRotationState
2967+ name: "keepSceneRotation"
2968+
2969+ StateChangeScript { script: {
2970+ // break binding
2971+ appWindowWithShadow.orientationAngle = appWindowWithShadow.orientationAngle;
2972+ } }
2973+ PropertyChanges {
2974+ target: appWindowWithShadow
2975+ restoreEntryValues: false
2976+ rotation: appWindowWithShadow.orientationAngle - root.shellOrientationAngle
2977+ width: {
2978+ if (rotation == 0 || Math.abs(rotation) == 180) {
2979+ return root.width;
2980+ } else {
2981+ return root.height;
2982+ }
2983+ }
2984+ height: {
2985+ if (rotation == 0 || Math.abs(rotation) == 180)
2986+ return root.height;
2987+ else
2988+ return root.width;
2989+ }
2990+ }
2991+ },
2992+ // In this state we counteract any shell rotation so that the window, in scene coordinates,
2993+ // remains unrotated.
2994+ State {
2995+ name: "counterRotate"
2996+ StateChangeScript { script: {
2997+ // break binding
2998+ appWindowWithShadow.orientationAngle = appWindowWithShadow.orientationAngle;
2999+ } }
3000+ PropertyChanges {
3001+ target: appWindowWithShadow
3002+ width: root.shellOrientationAngle == 0 || root.shellOrientationAngle == 180 ? root.width : root.height
3003+ height: root.shellOrientationAngle == 0 || root.shellOrientationAngle == 180 ? root.height : root.width
3004+ rotation: -root.shellOrientationAngle
3005+ }
3006+ PropertyChanges {
3007+ target: appWindow
3008+ surfaceOrientationAngle: orientationAngle
3009+ }
3010+ },
3011+ State {
3012+ name: "animatingRotation"
3013+ }
3014+ ]
3015+
3016+ x: (parent.width - width) / 2
3017+ y: (parent.height - height) / 2
3018+
3019+ BorderImage {
3020+ anchors {
3021+ fill: appWindow
3022+ margins: -units.gu(2)
3023+ }
3024+ source: "graphics/dropshadow2gu.sci"
3025+ opacity: root.dropShadow ? .3 : 0
3026+ Behavior on opacity { UbuntuNumberAnimation {} }
3027+ }
3028+
3029+ ApplicationWindow {
3030+ id: appWindow
3031+ objectName: application ? "appWindow_" + application.appId : "appWindow_null"
3032+ focus: true
3033+ anchors {
3034+ fill: parent
3035+ topMargin: appWindow.fullscreen || application.rotatesWindowContents
3036+ ? 0 : maximizedAppTopMargin
3037+ }
3038+
3039+ interactive: root.interactive
3040+ }
3041+ }
3042+ }
3043+
3044+ Image {
3045+ id: appWindowScreenshot
3046+ source: ""
3047+ visible: false
3048+
3049+ property real transformRotationAngle: 0
3050+ property real transformOriginX
3051+ property real transformOriginY
3052+
3053+ transform: Rotation {
3054+ origin.x: appWindowScreenshot.transformOriginX
3055+ origin.y: appWindowScreenshot.transformOriginY
3056+ axis { x: 0; y: 0; z: 1 }
3057+ angle: appWindowScreenshot.transformRotationAngle
3058+ }
3059+
3060+ function take() {
3061+ // Format: "image://application/$APP_ID/$CURRENT_TIME_MS"
3062+ // eg: "image://application/calculator-app/123456"
3063+ var timeMs = new Date().getTime();
3064+ source = "image://application/" + root.application.appId + "/" + timeMs;
3065+ }
3066+
3067+ sourceSize.width: width
3068+ sourceSize.height: height
3069 }
3070
3071 DraggingArea {
3072
3073=== modified file 'qml/Stages/SurfaceContainer.qml'
3074--- qml/Stages/SurfaceContainer.qml 2015-03-12 18:55:52 +0000
3075+++ qml/Stages/SurfaceContainer.qml 2015-04-16 14:12:24 +0000
3076@@ -24,8 +24,8 @@
3077 objectName: "surfaceContainer"
3078 property Item surface: null
3079 property bool hadSurface: false
3080- property int orientation
3081 property bool interactive
3082+ property int surfaceOrientationAngle: 0
3083
3084 onSurfaceChanged: {
3085 if (surface) {
3086@@ -39,10 +39,10 @@
3087 }
3088 }
3089 Binding { target: surface; property: "anchors.fill"; value: root }
3090- Binding { target: surface; property: "orientation"; value: root.orientation }
3091 Binding { target: surface; property: "z"; value: 1 }
3092 Binding { target: surface; property: "enabled"; value: root.interactive; when: surface }
3093 Binding { target: surface; property: "antialiasing"; value: !root.interactive; when: surface }
3094+ Binding { target: surface; property: "orientationAngle"; value: root.surfaceOrientationAngle; when: surface }
3095
3096 InputWatcher {
3097 target: root.surface
3098
3099=== modified file 'qml/Stages/TabletStage.qml'
3100--- qml/Stages/TabletStage.qml 2015-02-02 16:28:03 +0000
3101+++ qml/Stages/TabletStage.qml 2015-04-16 14:12:24 +0000
3102@@ -1,5 +1,5 @@
3103 /*
3104- * Copyright (C) 2014 Canonical, Ltd.
3105+ * Copyright (C) 2014-2015 Canonical, Ltd.
3106 *
3107 * This program is free software; you can redistribute it and/or modify
3108 * it under the terms of the GNU General Public License as published by
3109@@ -28,13 +28,79 @@
3110 color: "#111111"
3111
3112 // Controls to be set from outside
3113- property bool shown: false
3114- property bool moving: false
3115 property int dragAreaWidth
3116 property real maximizedAppTopMargin
3117 property bool interactive
3118+ property alias beingResized: spreadView.beingResized
3119+
3120+ property bool spreadEnabled: true // If false, animations and right edge will be disabled
3121+
3122 property real inverseProgress: 0 // This is the progress for left edge drags, in pixels.
3123- property int orientation: Qt.PortraitOrientation
3124+ property int shellOrientationAngle: 0
3125+ property int shellOrientation
3126+ property int shellPrimaryOrientation
3127+ property int nativeOrientation
3128+ property real nativeWidth
3129+ property real nativeHeight
3130+ function updateFocusedAppOrientation() {
3131+ var mainStageAppIndex = priv.indexOf(priv.mainStageAppId);
3132+ if (mainStageAppIndex >= 0 && mainStageAppIndex < spreadRepeater.count) {
3133+ spreadRepeater.itemAt(mainStageAppIndex).matchShellOrientation();
3134+ }
3135+
3136+ for (var i = 0; i < spreadRepeater.count; ++i) {
3137+
3138+ if (i === mainStageAppIndex) {
3139+ continue;
3140+ }
3141+
3142+ var spreadDelegate = spreadRepeater.itemAt(i);
3143+
3144+ var delta = spreadDelegate.appWindowOrientationAngle - root.shellOrientationAngle;
3145+ if (delta < 0) { delta += 360; }
3146+ delta = delta % 360;
3147+
3148+ var supportedOrientations = spreadDelegate.application.supportedOrientations;
3149+ if (supportedOrientations === Qt.PrimaryOrientation) {
3150+ supportedOrientations = spreadDelegate.shellPrimaryOrientation;
3151+ }
3152+
3153+ if (delta === 180 && (supportedOrientations & spreadDelegate.shellOrientation)) {
3154+ spreadDelegate.matchShellOrientation();
3155+ }
3156+ }
3157+ }
3158+ function updateFocusedAppOrientationAnimated() {
3159+ var mainStageAppIndex = priv.indexOf(priv.mainStageAppId);
3160+ if (mainStageAppIndex >= 0 && mainStageAppIndex < spreadRepeater.count) {
3161+ spreadRepeater.itemAt(mainStageAppIndex).animateToShellOrientation();
3162+ }
3163+
3164+ if (priv.sideStageAppId) {
3165+ var sideStageAppIndex = priv.indexOf(priv.sideStageAppId);
3166+ if (sideStageAppIndex >= 0 && sideStageAppIndex < spreadRepeater.count) {
3167+ spreadRepeater.itemAt(sideStageAppIndex).matchShellOrientation();
3168+ }
3169+ }
3170+ }
3171+
3172+ // To be read from outside
3173+ property var mainApp: null
3174+ property int mainAppWindowOrientationAngle: 0
3175+ readonly property bool orientationChangesEnabled: priv.mainAppOrientationChangesEnabled
3176+
3177+ onWidthChanged: {
3178+ spreadView.selectedIndex = -1;
3179+ spreadView.phase = 0;
3180+ spreadView.contentX = -spreadView.shift;
3181+ }
3182+
3183+ onShellOrientationChanged: {
3184+ if (shellOrientation == Qt.PortraitOrientation || shellOrientation == Qt.InvertedPortraitOrientation) {
3185+ ApplicationManager.focusApplication(priv.mainStageAppId);
3186+ priv.sideStageAppId = "";
3187+ }
3188+ }
3189
3190 onInverseProgressChanged: {
3191 // This can't be a simple binding because that would be triggered after this handler
3192@@ -54,6 +120,13 @@
3193
3194 property string focusedAppId: ApplicationManager.focusedApplicationId
3195 property string oldFocusedAppId: ""
3196+ property bool mainAppOrientationChangesEnabled: false
3197+
3198+ property real landscapeHeight: root.nativeOrientation == Qt.LandscapeOrientation ?
3199+ root.nativeHeight : root.nativeWidth
3200+
3201+ property bool shellIsLandscape: root.shellOrientation === Qt.LandscapeOrientation
3202+ || root.shellOrientation === Qt.InvertedLandscapeOrientation
3203
3204 property string mainStageAppId
3205 property string sideStageAppId
3206@@ -71,6 +144,7 @@
3207 priv.sideStageAppId = focusedAppId;
3208 } else {
3209 priv.mainStageAppId = focusedAppId;
3210+ root.mainApp = focusedApp;
3211 }
3212 }
3213
3214@@ -169,6 +243,7 @@
3215
3216 Flickable {
3217 id: spreadView
3218+ objectName: "spreadView"
3219 anchors.fill: parent
3220 interactive: (spreadDragArea.status == DirectionalDragArea.Recognized || phase > 1)
3221 && draggedDelegateCount === 0
3222@@ -218,7 +293,25 @@
3223 property int draggedDelegateCount: 0
3224 property int closingIndex: -1
3225
3226+ // FIXME: Workaround Flickable's not keepping its contentX still when resized
3227+ onContentXChanged: { forceItToRemainStillIfBeingResized(); }
3228+ onShiftChanged: { forceItToRemainStillIfBeingResized(); }
3229+ function forceItToRemainStillIfBeingResized() {
3230+ if (root.beingResized && contentX != -shift) {
3231+ contentX = -shift;
3232+ }
3233+ }
3234+
3235 property bool animateX: true
3236+ property bool beingResized: false
3237+ onBeingResizedChanged: {
3238+ if (beingResized) {
3239+ // Brace yourselves for impact!
3240+ selectedIndex = -1;
3241+ phase = 0;
3242+ contentX = -shift;
3243+ }
3244+ }
3245
3246 property bool sideStageDragging: sideStageDragHandle.dragging
3247 property real sideStageDragProgress: sideStageDragHandle.progress
3248@@ -257,7 +350,6 @@
3249 case "overlay":
3250 return 1;
3251 }
3252- print("Unhandled nextInStack case! This shouldn't happen any more when the Dash is an app!");
3253 return -1;
3254 }
3255 property int nextZInStack: indexToZIndex(nextInStack)
3256@@ -293,6 +385,10 @@
3257 }
3258
3259 onShiftedContentXChanged: {
3260+ if (root.beingResized) {
3261+ // Flickabe.contentX wiggles during resizes. Don't react to it.
3262+ return;
3263+ }
3264 if (spreadView.phase == 0 && spreadView.shiftedContentX > spreadView.width * spreadView.positionMarker2) {
3265 spreadView.phase = 1;
3266 } else if (spreadView.phase == 1 && spreadView.shiftedContentX > spreadView.width * spreadView.positionMarker4) {
3267@@ -402,8 +498,8 @@
3268 MouseArea {
3269 id: spreadRow
3270 x: spreadView.contentX
3271+ width: spreadView.width + Math.max(spreadView.width, ApplicationManager.count * spreadView.tileDistance)
3272 height: root.height
3273- width: spreadView.width + Math.max(spreadView.width, ApplicationManager.count * spreadView.tileDistance)
3274
3275 onClicked: {
3276 spreadView.snapTo(0);
3277@@ -412,8 +508,9 @@
3278 Rectangle {
3279 id: sideStageBackground
3280 color: "black"
3281- anchors.fill: parent
3282- anchors.leftMargin: spreadView.width - (1 - sideStageDragHandle.progress) * spreadView.sideStageWidth
3283+ width: spreadView.sideStageWidth * (1 - sideStageDragHandle.progress)
3284+ height: priv.landscapeHeight
3285+ x: spreadView.width - width
3286 z: spreadView.indexToZIndex(priv.indexOf(priv.sideStageAppId))
3287 opacity: spreadView.phase == 0 ? 1 : 0
3288 Behavior on opacity { UbuntuNumberAnimation {} }
3289@@ -421,8 +518,10 @@
3290
3291 Item {
3292 id: sideStageDragHandle
3293- anchors { top: parent.top; bottom: parent.bottom; left: parent.left; leftMargin: spreadView.width - spreadView.sideStageWidth - width }
3294+ anchors.right: sideStageBackground.left
3295+ anchors.top: sideStageBackground.top
3296 width: units.gu(2)
3297+ height: priv.landscapeHeight
3298 z: sideStageBackground.z
3299 opacity: spreadView.phase <= 0 && spreadView.sideStageVisible ? 1 : 0
3300 property real progress: 0
3301@@ -441,7 +540,6 @@
3302
3303 Image {
3304 anchors.centerIn: parent
3305- anchors.horizontalCenterOffset: parent.progress * spreadView.sideStageWidth - (width - parent.width) / 2
3306 width: sideStageDragHandleMouseArea.pressed ? parent.width * 2 : parent.width
3307 height: parent.height
3308 source: "graphics/sidestage_handle@20.png"
3309@@ -454,16 +552,19 @@
3310 enabled: spreadView.shiftedContentX == 0
3311 property int startX
3312 property var gesturePoints: new Array()
3313+ property real totalDiff
3314
3315 onPressed: {
3316 gesturePoints = [];
3317 startX = mouseX;
3318+ totalDiff = 0.0;
3319 sideStageDragHandle.progress = 0;
3320 sideStageDragHandle.dragging = true;
3321 }
3322 onMouseXChanged: {
3323+ totalDiff += mouseX - startX;
3324 if (priv.mainStageAppId) {
3325- sideStageDragHandle.progress = Math.max(0, (-startX + mouseX) / spreadView.sideStageWidth);
3326+ sideStageDragHandle.progress = Math.max(0, totalDiff / spreadView.sideStageWidth);
3327 }
3328 gesturePoints.push(mouseX);
3329 }
3330@@ -492,12 +593,26 @@
3331
3332 Repeater {
3333 id: spreadRepeater
3334+ objectName: "spreadRepeater"
3335 model: ApplicationManager
3336
3337 delegate: TransformedTabletSpreadDelegate {
3338 id: spreadTile
3339- height: spreadView.height
3340- width: model.stage == ApplicationInfoInterface.MainStage ? spreadView.width : spreadView.sideStageWidth
3341+ objectName: "spreadDelegate_" + model.appId
3342+ width: {
3343+ if (wantsMainStage) {
3344+ return spreadView.width;
3345+ } else {
3346+ return spreadView.sideStageWidth;
3347+ }
3348+ }
3349+ height: {
3350+ if (wantsMainStage) {
3351+ return spreadView.height;
3352+ } else {
3353+ return priv.landscapeHeight;
3354+ }
3355+ }
3356 active: model.appId == priv.mainStageAppId || model.appId == priv.sideStageAppId
3357 zIndex: spreadView.indexToZIndex(index)
3358 selected: spreadView.selectedIndex == index
3359@@ -510,6 +625,8 @@
3360 application: ApplicationManager.get(index)
3361 closeable: !isDash
3362
3363+ readonly property bool wantsMainStage: model.stage == ApplicationInfoInterface.MainStage
3364+
3365 readonly property bool isDash: model.appId == "unity8-dash"
3366
3367 // FIXME: A regular binding doesn't update any more after closing an app.
3368@@ -561,12 +678,11 @@
3369 return progress;
3370 }
3371
3372- Binding {
3373- target: spreadTile
3374- property: "orientation"
3375- when: spreadTile.interactive
3376- value: root.orientation
3377- }
3378+ shellOrientationAngle: wantsMainStage ? root.shellOrientationAngle : 0
3379+ shellOrientation: wantsMainStage ? root.shellOrientation : Qt.PortraitOrientation
3380+ shellPrimaryOrientation: wantsMainStage ? root.shellPrimaryOrientation : Qt.PortraitOrientation
3381+ nativeOrientation: wantsMainStage ? root.nativeOrientation : Qt.PortraitOrientation
3382+
3383
3384 onClicked: {
3385 if (spreadView.phase == 2) {
3386@@ -587,6 +703,19 @@
3387 ApplicationManager.stopApplication(ApplicationManager.get(index).appId);
3388 }
3389
3390+ Binding {
3391+ target: root
3392+ when: model.appId == priv.mainStageAppId
3393+ property: "mainAppWindowOrientationAngle"
3394+ value: appWindowOrientationAngle
3395+ }
3396+ Binding {
3397+ target: priv
3398+ when: model.appId == priv.mainStageAppId
3399+ property: "mainAppOrientationChangesEnabled"
3400+ value: orientationChangesEnabled
3401+ }
3402+
3403 EasingCurve {
3404 id: snappingCurve
3405 type: EasingCurve.Linear
3406@@ -603,6 +732,7 @@
3407 anchors { top: parent.top; right: parent.right; bottom: parent.bottom }
3408 width: root.dragAreaWidth
3409 direction: Direction.Leftwards
3410+ enabled: (spreadView.phase != 2 && root.spreadEnabled) || dragging
3411
3412 property var gesturePoints: new Array()
3413
3414@@ -631,11 +761,15 @@
3415 var oneWayFlick = priv.evaluateOneWayFlick(gesturePoints);
3416 gesturePoints = [];
3417
3418+ var nextAppInStackIsInMainStage =
3419+ spreadView.nextInStack !== -1 &&
3420+ ApplicationManager.get(spreadView.nextInStack).stage === ApplicationInfoInterface.MainStage;
3421+
3422 if (oneWayFlick && spreadView.shiftedContentX < spreadView.positionMarker1 * spreadView.width) {
3423 // If it was a short one-way movement, do the Alt+Tab switch
3424 // no matter if we didn't cross positionMarker1 yet.
3425 spreadView.snapTo(spreadView.nextInStack);
3426- } else if (!dragging) {
3427+ } else {
3428 if (spreadView.shiftedContentX < spreadView.width * spreadView.positionMarker1) {
3429 spreadView.snap();
3430 } else if (spreadView.shiftedContentX < spreadView.width * spreadView.positionMarker2) {
3431
3432=== modified file 'qml/Stages/TransformedTabletSpreadDelegate.qml'
3433--- qml/Stages/TransformedTabletSpreadDelegate.qml 2015-02-02 16:23:34 +0000
3434+++ qml/Stages/TransformedTabletSpreadDelegate.qml 2015-04-16 14:12:24 +0000
3435@@ -50,7 +50,9 @@
3436 property int dragOffset: 0
3437
3438 dropShadow: spreadView.active ||
3439- (active && model.stage == ApplicationInfoInterface.MainStage && priv.xTranslate != 0)
3440+ (active
3441+ && (model.stage == ApplicationInfoInterface.MainStage || !priv.shellIsLandscape)
3442+ && priv.xTranslate != 0)
3443
3444 onSelectedChanged: {
3445 if (selected) {
3446@@ -139,7 +141,8 @@
3447 !snapAnimation.running &&
3448 model.appId !== "unity8-dash" &&
3449 !spreadView.sideStageDragging &&
3450- spreadView.animateX
3451+ spreadView.animateX &&
3452+ !spreadView.beingResized
3453 UbuntuNumberAnimation {
3454 duration: UbuntuAnimation.FastDuration
3455 }
3456
3457=== modified file 'run.sh'
3458--- run.sh 2015-03-11 08:07:31 +0000
3459+++ run.sh 2015-04-16 14:12:24 +0000
3460@@ -44,7 +44,7 @@
3461 export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD/builddir/plugins/LightDM/liblightdm
3462 fi
3463
3464-QML_PHONE_SHELL_ARGS=""
3465+QML_PHONE_SHELL_ARGS="-windowgeometry=40gux68gu -devicename=mako"
3466 if $MOUSE_TOUCH; then
3467 QML_PHONE_SHELL_ARGS="$QML_PHONE_SHELL_ARGS -mousetouch"
3468 fi
3469
3470=== added file 'src/ApplicationArguments.cpp'
3471--- src/ApplicationArguments.cpp 1970-01-01 00:00:00 +0000
3472+++ src/ApplicationArguments.cpp 2015-04-16 14:12:24 +0000
3473@@ -0,0 +1,22 @@
3474+/*
3475+ * Copyright (C) 2015 Canonical, Ltd.
3476+ *
3477+ * This program is free software; you can redistribute it and/or modify
3478+ * it under the terms of the GNU General Public License as published by
3479+ * the Free Software Foundation; version 3.
3480+ *
3481+ * This program is distributed in the hope that it will be useful,
3482+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3483+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3484+ * GNU General Public License for more details.
3485+ *
3486+ * You should have received a copy of the GNU General Public License
3487+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3488+ */
3489+
3490+#include "ApplicationArguments.h"
3491+
3492+ApplicationArguments::ApplicationArguments(QObject *parent)
3493+ : QObject(parent)
3494+{
3495+}
3496
3497=== modified file 'src/ApplicationArguments.h'
3498--- src/ApplicationArguments.h 2014-07-08 19:04:17 +0000
3499+++ src/ApplicationArguments.h 2015-04-16 14:12:24 +0000
3500@@ -1,5 +1,5 @@
3501 /*
3502- * Copyright (C) 2013 Canonical, Ltd.
3503+ * Copyright (C) 2013,2015 Canonical, Ltd.
3504 *
3505 * This program is free software; you can redistribute it and/or modify
3506 * it under the terms of the GNU General Public License as published by
3507@@ -13,7 +13,6 @@
3508 * You should have received a copy of the GNU General Public License
3509 * along with this program. If not, see <http://www.gnu.org/licenses/>.
3510 *
3511- * Authored by: Nick Dedekind <nick.dedekind@canonical.com>
3512 */
3513
3514
3515@@ -22,24 +21,29 @@
3516
3517 #include <QObject>
3518 #include <QSize>
3519-#include <QStringList>
3520+#include <QString>
3521
3522 class ApplicationArguments : public QObject
3523 {
3524 Q_OBJECT
3525+ Q_PROPERTY(QString deviceName READ deviceName CONSTANT)
3526 public:
3527- // Not exposed to the app as setSize isn't invokable
3528- void setSize(int width, int height) {
3529- m_size.rwidth() = width;
3530- m_size.rheight() = height;
3531+ ApplicationArguments(QObject *parent = nullptr);
3532+
3533+ void setDeviceName(QString deviceName) { m_deviceName = deviceName; }
3534+
3535+ void setSize(const QSize &size) {
3536+ m_size = size;
3537 }
3538
3539- Q_INVOKABLE bool hasGeometry() const { return m_size.isValid(); }
3540 Q_INVOKABLE int width() const { return m_size.width(); }
3541 Q_INVOKABLE int height() const { return m_size.height(); }
3542
3543+ QString deviceName() const { return m_deviceName; }
3544+
3545 private:
3546- QSize m_size;
3547+ QSize m_size;
3548+ QString m_deviceName;
3549 };
3550
3551 #endif // APPLICATION_ARGUMENTS_H
3552
3553=== modified file 'src/CMakeLists.txt'
3554--- src/CMakeLists.txt 2014-10-27 09:40:01 +0000
3555+++ src/CMakeLists.txt 2015-04-16 14:12:24 +0000
3556@@ -17,21 +17,21 @@
3557 )
3558
3559 add_executable(${SHELL_APP}
3560- ApplicationArguments.h
3561+ ApplicationArguments.cpp
3562 main.cpp
3563 MouseTouchAdaptor.cpp
3564 CachingNetworkManagerFactory.cpp
3565+ UnityCommandLineParser.cpp
3566 ${QML_FILES} # This is to make qml and image files appear in the IDE's project tree
3567 )
3568
3569 qt5_use_modules(${SHELL_APP} Gui Qml Quick Test)
3570-pkg_check_modules(XCB REQUIRED xcb)
3571-
3572-if (NOT "${XCB_INCLUDE_DIRS}" STREQUAL "")
3573- set_target_properties(${SHELL_APP} PROPERTIES INCLUDE_DIRECTORIES ${XCB_INCLUDE_DIRS})
3574-
3575- target_link_libraries(${SHELL_APP} ${XCB_LDFLAGS})
3576+
3577+pkg_check_modules(NEEDED_LIBS REQUIRED xcb libandroid-properties)
3578+if (NOT "${NEEDED_LIBS_INCLUDE_DIRS}" STREQUAL "")
3579+ set_target_properties(${SHELL_APP} PROPERTIES INCLUDE_DIRECTORIES ${NEEDED_LIBS_INCLUDE_DIRS})
3580 endif()
3581+target_link_libraries(${SHELL_APP} ${NEEDED_LIBS_LDFLAGS})
3582
3583 target_link_libraries(${SHELL_APP} UbuntuGestures connectivity-qt1)
3584
3585
3586=== modified file 'src/Dash/CMakeLists.txt'
3587--- src/Dash/CMakeLists.txt 2014-10-27 09:40:01 +0000
3588+++ src/Dash/CMakeLists.txt 2015-04-16 14:12:24 +0000
3589@@ -1,6 +1,6 @@
3590 set(DASH_SRCS
3591 main.cpp
3592- ../ApplicationArguments.h
3593+ ../ApplicationArguments.cpp
3594 ../MouseTouchAdaptor.cpp
3595 ../CachingNetworkManagerFactory.cpp
3596 )
3597@@ -9,6 +9,12 @@
3598
3599 qt5_use_modules(unity8-dash Gui Qml Quick Test)
3600
3601+pkg_check_modules(NEEDED_LIBS REQUIRED xcb libandroid-properties)
3602+if (NOT "${NEEDED_LIBS_INCLUDE_DIRS}" STREQUAL "")
3603+ set_target_properties(unity8-dash PROPERTIES INCLUDE_DIRECTORIES ${NEEDED_LIBS_INCLUDE_DIRS})
3604+endif()
3605+target_link_libraries(unity8-dash ${NEEDED_LIBS_LDFLAGS})
3606+
3607 # For it to find libUbuntuGestures.so, needed by Ubuntu.Gestures QML module.
3608 set_target_properties(unity8-dash PROPERTIES INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${SHELL_PRIVATE_LIBDIR}")
3609
3610
3611=== modified file 'src/Dash/main.cpp'
3612--- src/Dash/main.cpp 2015-03-02 12:41:17 +0000
3613+++ src/Dash/main.cpp 2015-04-16 14:12:24 +0000
3614@@ -65,7 +65,7 @@
3615 parser.value(windowGeometryOption).split('x').size() == 2)
3616 {
3617 QStringList geom = parser.value(windowGeometryOption).split('x');
3618- qmlArgs.setSize(geom.at(0).toInt(), geom.at(1).toInt());
3619+ qmlArgs.setSize(QSize(geom.at(0).toInt(), geom.at(1).toInt()));
3620 }
3621
3622 if (getenv("QT_LOAD_TESTABILITY")) {
3623
3624=== added file 'src/UnityCommandLineParser.cpp'
3625--- src/UnityCommandLineParser.cpp 1970-01-01 00:00:00 +0000
3626+++ src/UnityCommandLineParser.cpp 2015-04-16 14:12:24 +0000
3627@@ -0,0 +1,118 @@
3628+/*
3629+ * Copyright (C) 2015 Canonical, Ltd.
3630+ *
3631+ * This program is free software; you can redistribute it and/or modify
3632+ * it under the terms of the GNU General Public License as published by
3633+ * the Free Software Foundation; version 3.
3634+ *
3635+ * This program is distributed in the hope that it will be useful,
3636+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3637+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3638+ * GNU General Public License for more details.
3639+ *
3640+ * You should have received a copy of the GNU General Public License
3641+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3642+ */
3643+
3644+#include "UnityCommandLineParser.h"
3645+
3646+#include <QDebug>
3647+
3648+#define ENV_GRID_UNIT_PX "GRID_UNIT_PX"
3649+#define DEFAULT_GRID_UNIT_PX 8
3650+
3651+UnityCommandLineParser::UnityCommandLineParser(const QCoreApplication &app)
3652+{
3653+ m_gridUnit = getenvFloat(ENV_GRID_UNIT_PX, DEFAULT_GRID_UNIT_PX);
3654+
3655+ QCommandLineParser parser;
3656+ parser.setApplicationDescription("Description: Unity 8 Shell");
3657+ parser.addHelpOption();
3658+
3659+ QCommandLineOption fullscreenOption("fullscreen",
3660+ "Run in fullscreen");
3661+ parser.addOption(fullscreenOption);
3662+
3663+ QCommandLineOption framelessOption("frameless",
3664+ "Run without window borders");
3665+ parser.addOption(framelessOption);
3666+
3667+ QCommandLineOption mousetouchOption("mousetouch",
3668+ "Allow the mouse to provide touch input");
3669+ parser.addOption(mousetouchOption);
3670+
3671+ QCommandLineOption windowGeometryOption(QStringList() << "windowgeometry",
3672+ "Specify the window geometry as [<width>x<height>]", "windowgeometry", "1");
3673+ parser.addOption(windowGeometryOption);
3674+
3675+ QCommandLineOption testabilityOption("testability",
3676+ "DISCOURAGED: Please set QT_LOAD_TESTABILITY instead.\nLoad the testability driver");
3677+ parser.addOption(testabilityOption);
3678+
3679+ QCommandLineOption modeOption("mode",
3680+ "Whether to run greeter and/or shell [full-greeter, full-shell, greeter, shell]",
3681+ "mode", "full-greeter");
3682+ parser.addOption(modeOption);
3683+
3684+ // Treat args with single dashes the same as arguments with two dashes
3685+ // Ex: -fullscreen == --fullscreen
3686+ parser.setSingleDashWordOptionMode(QCommandLineParser::ParseAsLongOptions);
3687+
3688+ parser.process(app);
3689+
3690+ if (parser.isSet(windowGeometryOption))
3691+ {
3692+ QStringList geom = parser.value(windowGeometryOption).split('x');
3693+ if (geom.count() == 2) {
3694+ m_windowGeometry.rwidth() = parsePixelsValue(geom[0]);
3695+ m_windowGeometry.rheight() = parsePixelsValue(geom[1]);
3696+ }
3697+ }
3698+
3699+ m_hasTestability = parser.isSet(testabilityOption);
3700+ m_hasFrameless = parser.isSet(framelessOption);
3701+ m_hasMouseToTouch = parser.isSet(mousetouchOption);
3702+ m_hasFullscreen = parser.isSet(fullscreenOption);
3703+ resolveMode(parser, modeOption);
3704+}
3705+
3706+int UnityCommandLineParser::parsePixelsValue(const QString &str)
3707+{
3708+ if (str.endsWith("gu", Qt::CaseInsensitive)) {
3709+ QString numStr = str;
3710+ numStr.remove(numStr.size() - 2, 2);
3711+ return numStr.toInt() * m_gridUnit;
3712+ } else {
3713+ return str.toInt();
3714+ }
3715+}
3716+
3717+float UnityCommandLineParser::getenvFloat(const char* name, float defaultValue)
3718+{
3719+ QByteArray stringValue = qgetenv(name);
3720+ bool ok;
3721+ float value = stringValue.toFloat(&ok);
3722+ return ok ? value : defaultValue;
3723+}
3724+
3725+void UnityCommandLineParser::resolveMode(QCommandLineParser &parser, QCommandLineOption &modeOption)
3726+{
3727+ // If an invalid option was specified, set it to the default
3728+ // If no default was provided in the QCommandLineOption constructor, abort.
3729+ if (!parser.isSet(modeOption) ||
3730+ (parser.value(modeOption) != "full-greeter" &&
3731+ parser.value(modeOption) != "full-shell" &&
3732+ parser.value(modeOption) != "greeter" &&
3733+ parser.value(modeOption) != "shell")) {
3734+
3735+ if (modeOption.defaultValues().first() != nullptr) {
3736+ m_mode = modeOption.defaultValues().first();
3737+ qWarning() << "Mode argument was not provided or was set to an illegal value."
3738+ " Using default value of --mode=" << m_mode;
3739+ } else {
3740+ qFatal("Shell mode argument was not provided and there is no default mode.");
3741+ }
3742+ } else {
3743+ m_mode = parser.value(modeOption);
3744+ }
3745+}
3746
3747=== added file 'src/UnityCommandLineParser.h'
3748--- src/UnityCommandLineParser.h 1970-01-01 00:00:00 +0000
3749+++ src/UnityCommandLineParser.h 2015-04-16 14:12:24 +0000
3750@@ -0,0 +1,50 @@
3751+/*
3752+ * Copyright (C) 2015 Canonical, Ltd.
3753+ *
3754+ * This program is free software; you can redistribute it and/or modify
3755+ * it under the terms of the GNU General Public License as published by
3756+ * the Free Software Foundation; version 3.
3757+ *
3758+ * This program is distributed in the hope that it will be useful,
3759+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3760+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3761+ * GNU General Public License for more details.
3762+ *
3763+ * You should have received a copy of the GNU General Public License
3764+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3765+ */
3766+
3767+#ifndef UNITY_COMMAND_LINE_PARSER_H
3768+#define UNITY_COMMAND_LINE_PARSER_H
3769+
3770+#include <QCommandLineParser>
3771+#include <QSize>
3772+#include <QString>
3773+
3774+class UnityCommandLineParser {
3775+public:
3776+ UnityCommandLineParser(const QCoreApplication &app);
3777+
3778+ QSize windowGeometry() const { return m_windowGeometry; }
3779+ bool hasTestability() const { return m_hasTestability; }
3780+ bool hasFrameless() const { return m_hasFrameless; }
3781+ bool hasMouseToTouch() const { return m_hasMouseToTouch; }
3782+ bool hasFullscreen() const { return m_hasFullscreen; }
3783+ QString mode() const { return m_mode; }
3784+private:
3785+
3786+ int parsePixelsValue(const QString &str);
3787+ static float getenvFloat(const char* name, float defaultValue);
3788+ void resolveMode(QCommandLineParser &parser, QCommandLineOption &modeOption);
3789+
3790+ float m_gridUnit;
3791+
3792+ QSize m_windowGeometry;
3793+ bool m_hasTestability;
3794+ bool m_hasFrameless;
3795+ bool m_hasMouseToTouch;
3796+ bool m_hasFullscreen;
3797+ QString m_mode;
3798+};
3799+
3800+#endif // UNITY_COMMAND_LINE_PARSER_H
3801
3802=== modified file 'src/main.cpp'
3803--- src/main.cpp 2015-03-23 23:40:27 +0000
3804+++ src/main.cpp 2015-04-16 14:12:24 +0000
3805@@ -25,11 +25,15 @@
3806 #include <csignal>
3807 #include <libintl.h>
3808
3809+// libandroid-properties
3810+#include <hybris/properties/properties.h>
3811+
3812 // local
3813 #include <paths.h>
3814 #include "MouseTouchAdaptor.h"
3815 #include "ApplicationArguments.h"
3816 #include "CachingNetworkManagerFactory.h"
3817+#include "UnityCommandLineParser.h"
3818
3819 // Ubuntu Gestures
3820 #include <TouchRegistry.h>
3821@@ -45,79 +49,24 @@
3822 QGuiApplication::setApplicationName("unity8");
3823 QGuiApplication *application;
3824
3825- QCommandLineParser parser;
3826- parser.setApplicationDescription("Description: Unity 8 Shell");
3827- parser.addHelpOption();
3828-
3829- QCommandLineOption fullscreenOption("fullscreen",
3830- "Run in fullscreen");
3831- parser.addOption(fullscreenOption);
3832-
3833- QCommandLineOption framelessOption("frameless",
3834- "Run without window borders");
3835- parser.addOption(framelessOption);
3836-
3837- QCommandLineOption mousetouchOption("mousetouch",
3838- "Allow the mouse to provide touch input");
3839- parser.addOption(mousetouchOption);
3840-
3841- QCommandLineOption windowGeometryOption(QStringList() << "windowgeometry",
3842- "Specify the window geometry as [<width>x<height>]", "windowgeometry", "1");
3843- parser.addOption(windowGeometryOption);
3844-
3845- QCommandLineOption testabilityOption("testability",
3846- "DISCOURAGED: Please set QT_LOAD_TESTABILITY instead. \n \
3847-Load the testability driver");
3848- parser.addOption(testabilityOption);
3849-
3850- QCommandLineOption modeOption("mode",
3851- "Whether to run greeter and/or shell [full-greeter, full-shell, greeter, shell]",
3852- "mode", "full-greeter");
3853- parser.addOption(modeOption);
3854-
3855 application = new QGuiApplication(argc, (char**)argv);
3856
3857- // Treat args with single dashes the same as arguments with two dashes
3858- // Ex: -fullscreen == --fullscreen
3859- parser.setSingleDashWordOptionMode(QCommandLineParser::ParseAsLongOptions);
3860- parser.process(*application);
3861-
3862- QString indicatorProfile = qgetenv("UNITY_INDICATOR_PROFILE");
3863- if (indicatorProfile.isEmpty()) {
3864- indicatorProfile = "phone";
3865- }
3866+ UnityCommandLineParser parser(*application);
3867
3868 ApplicationArguments qmlArgs;
3869- if (parser.isSet(windowGeometryOption) &&
3870- parser.value(windowGeometryOption).split('x').size() == 2)
3871- {
3872- QStringList geom = parser.value(windowGeometryOption).split('x');
3873- qmlArgs.setSize(geom.at(0).toInt(), geom.at(1).toInt());
3874- }
3875-
3876- // If an invalid option was specified, set it to the default
3877- // If no default was provided in the QCommandLineOption constructor, abort.
3878- QString shellMode;
3879- if(!parser.isSet(modeOption) ||
3880- (parser.value(modeOption) != "full-greeter" &&
3881- parser.value(modeOption) != "full-shell" &&
3882- parser.value(modeOption) != "greeter" &&
3883- parser.value(modeOption) != "shell"))
3884- {
3885- if (modeOption.defaultValues().first() != nullptr) {
3886- shellMode = modeOption.defaultValues().first();
3887- qWarning() << "Mode argument was not provided or was set to an illegal value. Using default value of --mode=" << shellMode;
3888- } else {
3889- qFatal("Shell mode argument was not provided and there is no default mode,");
3890- }
3891-
3892+ qmlArgs.setSize(parser.windowGeometry());
3893+
3894+ if (!parser.deviceName().isEmpty()) {
3895+ qmlArgs.setDeviceName(parser.deviceName());
3896 } else {
3897- shellMode = parser.value(modeOption);
3898+ char buffer[200];
3899+ property_get("ro.product.device", buffer /* value */, "desktop" /* default_value*/);
3900+ qmlArgs.setDeviceName(QString(buffer));
3901 }
3902
3903 // The testability driver is only loaded by QApplication but not by QGuiApplication.
3904 // However, QApplication depends on QWidget which would add some unneeded overhead => Let's load the testability driver on our own.
3905- if (parser.isSet(testabilityOption) || getenv("QT_LOAD_TESTABILITY")) {
3906+ if (parser.hasTestability() || getenv("QT_LOAD_TESTABILITY")) {
3907 QLibrary testLib(QLatin1String("qttestability"));
3908 if (testLib.load()) {
3909 typedef void (*TasInitialize)(void);
3910@@ -141,9 +90,8 @@
3911 view->setTitle("Unity8 Shell");
3912 view->engine()->setBaseUrl(QUrl::fromLocalFile(::qmlDirectory()));
3913 view->rootContext()->setContextProperty("applicationArguments", &qmlArgs);
3914- view->rootContext()->setContextProperty("indicatorProfile", indicatorProfile);
3915- view->rootContext()->setContextProperty("shellMode", shellMode);
3916- if (parser.isSet(framelessOption)) {
3917+ view->rootContext()->setContextProperty("shellMode", parser.mode());
3918+ if (parser.hasFrameless()) {
3919 view->setFlags(Qt::FramelessWindowHint);
3920 }
3921 TouchRegistry touchRegistry;
3922@@ -152,11 +100,11 @@
3923 // You will need this if you want to interact with touch-only components using a mouse
3924 // Needed only when manually testing on a desktop.
3925 MouseTouchAdaptor *mouseTouchAdaptor = 0;
3926- if (parser.isSet(mousetouchOption)) {
3927+ if (parser.hasMouseToTouch()) {
3928 mouseTouchAdaptor = MouseTouchAdaptor::instance();
3929 }
3930
3931- QUrl source(::qmlDirectory()+"Shell.qml");
3932+ QUrl source(::qmlDirectory()+"OrientedShell.qml");
3933 prependImportPaths(view->engine(), ::overrideImportPaths());
3934 if (!isMirServer) {
3935 prependImportPaths(view->engine(), ::nonMirImportPaths());
3936@@ -169,7 +117,7 @@
3937 view->setSource(source);
3938 QObject::connect(view->engine(), SIGNAL(quit()), application, SLOT(quit()));
3939
3940- if (isMirServer || parser.isSet(fullscreenOption)) {
3941+ if (isMirServer || parser.hasFullscreen()) {
3942 view->showFullScreen();
3943 } else {
3944 view->show();
3945
3946=== modified file 'tests/mocks/Unity/Application/ApplicationInfo.cpp'
3947--- tests/mocks/Unity/Application/ApplicationInfo.cpp 2014-08-28 23:16:07 +0000
3948+++ tests/mocks/Unity/Application/ApplicationInfo.cpp 2015-04-16 14:12:24 +0000
3949@@ -1,5 +1,5 @@
3950 /*
3951- * Copyright (C) 2013-2014 Canonical, Ltd.
3952+ * Copyright (C) 2013-2015 Canonical, Ltd.
3953 *
3954 * This program is free software; you can redistribute it and/or modify
3955 * it under the terms of the GNU General Public License as published by
3956@@ -34,6 +34,11 @@
3957 , m_focused(false)
3958 , m_fullscreen(false)
3959 , m_session(0)
3960+ , m_supportedOrientations(Qt::PortraitOrientation |
3961+ Qt::LandscapeOrientation |
3962+ Qt::InvertedPortraitOrientation |
3963+ Qt::InvertedLandscapeOrientation)
3964+ , m_rotatesWindowContents(false)
3965 , m_manualSurfaceCreation(false)
3966 {
3967 }
3968@@ -45,6 +50,11 @@
3969 , m_focused(false)
3970 , m_fullscreen(false)
3971 , m_session(0)
3972+ , m_supportedOrientations(Qt::PortraitOrientation |
3973+ Qt::LandscapeOrientation |
3974+ Qt::InvertedPortraitOrientation |
3975+ Qt::InvertedLandscapeOrientation)
3976+ , m_rotatesWindowContents(false)
3977 , m_manualSurfaceCreation(false)
3978 {
3979 }
3980@@ -99,9 +109,17 @@
3981
3982 void ApplicationInfo::setScreenshotId(const QString &screenshotId)
3983 {
3984- QString screenshotFileName = QString("%1/Dash/graphics/phone/screenshots/%2@12.png")
3985- .arg(qmlDirectory())
3986- .arg(screenshotId);
3987+ QString screenshotFileName;
3988+
3989+ if (screenshotId.endsWith(".svg")) {
3990+ screenshotFileName = QString("%1/Dash/graphics/phone/screenshots/%2")
3991+ .arg(qmlDirectory())
3992+ .arg(screenshotId);
3993+ } else {
3994+ screenshotFileName = QString("%1/Dash/graphics/phone/screenshots/%2@12.png")
3995+ .arg(qmlDirectory())
3996+ .arg(screenshotId);
3997+ }
3998
3999 if (screenshotFileName != m_screenshotFileName) {
4000 m_screenshotFileName = screenshotFileName;
4001@@ -145,6 +163,9 @@
4002
4003 if (!m_manualSurfaceCreation && m_state == ApplicationInfo::Running) {
4004 QTimer::singleShot(500, this, SLOT(createSession()));
4005+ } else if (m_state == ApplicationInfo::Stopped) {
4006+ delete m_session;
4007+ m_session = nullptr;
4008 }
4009 }
4010 }
4011@@ -172,3 +193,23 @@
4012 Q_EMIT manualSurfaceCreationChanged(value);
4013 }
4014 }
4015+
4016+Qt::ScreenOrientations ApplicationInfo::supportedOrientations() const
4017+{
4018+ return m_supportedOrientations;
4019+}
4020+
4021+void ApplicationInfo::setSupportedOrientations(Qt::ScreenOrientations orientations)
4022+{
4023+ m_supportedOrientations = orientations;
4024+}
4025+
4026+bool ApplicationInfo::rotatesWindowContents() const
4027+{
4028+ return m_rotatesWindowContents;
4029+}
4030+
4031+void ApplicationInfo::setRotatesWindowContents(bool value)
4032+{
4033+ m_rotatesWindowContents = value;
4034+}
4035
4036=== modified file 'tests/mocks/Unity/Application/ApplicationInfo.h'
4037--- tests/mocks/Unity/Application/ApplicationInfo.h 2014-09-15 19:05:32 +0000
4038+++ tests/mocks/Unity/Application/ApplicationInfo.h 2015-04-16 14:12:24 +0000
4039@@ -1,5 +1,5 @@
4040 /*
4041- * Copyright (C) 2013-2014 Canonical, Ltd.
4042+ * Copyright (C) 2013-2015 Canonical, Ltd.
4043 *
4044 * This program is free software; you can redistribute it and/or modify
4045 * it under the terms of the GNU General Public License as published by
4046@@ -80,6 +80,12 @@
4047 void setFullscreen(bool value);
4048 bool fullscreen() const { return m_fullscreen; }
4049
4050+ Qt::ScreenOrientations supportedOrientations() const override;
4051+ void setSupportedOrientations(Qt::ScreenOrientations orientations);
4052+
4053+ bool rotatesWindowContents() const override;
4054+ void setRotatesWindowContents(bool value);
4055+
4056 bool manualSurfaceCreation() const { return m_manualSurfaceCreation; }
4057 void setManualSurfaceCreation(bool value);
4058
4059@@ -108,6 +114,8 @@
4060 bool m_focused;
4061 bool m_fullscreen;
4062 Session* m_session;
4063+ Qt::ScreenOrientations m_supportedOrientations;
4064+ bool m_rotatesWindowContents;
4065
4066 bool m_manualSurfaceCreation;
4067 };
4068
4069=== modified file 'tests/mocks/Unity/Application/ApplicationManager.cpp'
4070--- tests/mocks/Unity/Application/ApplicationManager.cpp 2015-03-10 14:25:12 +0000
4071+++ tests/mocks/Unity/Application/ApplicationManager.cpp 2015-04-16 14:12:24 +0000
4072@@ -1,5 +1,5 @@
4073 /*
4074- * Copyright (C) 2013-2014 Canonical, Ltd.
4075+ * Copyright (C) 2013-2015 Canonical, Ltd.
4076 *
4077 * This program is free software; you can redistribute it and/or modify
4078 * it under the terms of the GNU General Public License as published by
4079@@ -348,6 +348,13 @@
4080
4081 void ApplicationManager::buildListOfAvailableApplications()
4082 {
4083+ /*
4084+ ATTENTION!
4085+ Be careful when changing application properties here as some qmltests
4086+ rely on them being the way it's specified here (e.g. that camera-app
4087+ is fullscreen, that twitter-webapp can rotate in all directions, etc)
4088+ */
4089+
4090 ApplicationInfo *application;
4091
4092 application = new ApplicationInfo(this);
4093@@ -355,6 +362,7 @@
4094 application->setName("Unity 8 Mock Dash");
4095 application->setScreenshotId("unity8-dash");
4096 application->setStage(ApplicationInfo::MainStage);
4097+ application->setSupportedOrientations(Qt::PrimaryOrientation);
4098 m_availableApplications.append(application);
4099
4100 application = new ApplicationInfo(this);
4101@@ -363,6 +371,8 @@
4102 application->setScreenshotId("dialer");
4103 application->setIconId("dialer-app");
4104 application->setStage(ApplicationInfo::SideStage);
4105+ application->setSupportedOrientations(Qt::PortraitOrientation
4106+ | Qt::InvertedPortraitOrientation);
4107 m_availableApplications.append(application);
4108
4109 application = new ApplicationInfo(this);
4110@@ -371,6 +381,11 @@
4111 application->setScreenshotId("camera");
4112 application->setIconId("camera");
4113 application->setFullscreen(true);
4114+ application->setSupportedOrientations(Qt::PortraitOrientation
4115+ | Qt::LandscapeOrientation
4116+ | Qt::InvertedPortraitOrientation
4117+ | Qt::InvertedLandscapeOrientation);
4118+ application->setRotatesWindowContents(true);
4119 m_availableApplications.append(application);
4120
4121 application = new ApplicationInfo(this);
4122@@ -416,13 +431,35 @@
4123 application->setAppId("gmail-webapp");
4124 application->setName("GMail");
4125 application->setIconId("gmail");
4126+ application->setScreenshotId("gmail-webapp.svg");
4127+ application->setFullscreen(false);
4128+ application->setStage(ApplicationInfo::MainStage);
4129+ application->setSupportedOrientations(Qt::PortraitOrientation
4130+ | Qt::LandscapeOrientation
4131+ | Qt::InvertedPortraitOrientation
4132+ | Qt::InvertedLandscapeOrientation);
4133+ m_availableApplications.append(application);
4134+
4135+ application = new ApplicationInfo(this);
4136+ application->setAppId("music-app");
4137+ application->setName("Music");
4138+ application->setIconId("soundcloud");
4139+ application->setScreenshotId("music");
4140+ application->setFullscreen(false);
4141+ application->setStage(ApplicationInfo::MainStage);
4142+ application->setSupportedOrientations(Qt::PortraitOrientation
4143+ | Qt::LandscapeOrientation
4144+ | Qt::InvertedPortraitOrientation
4145+ | Qt::InvertedLandscapeOrientation);
4146 m_availableApplications.append(application);
4147
4148 application = new ApplicationInfo(this);
4149 application->setAppId("ubuntu-weather-app");
4150 application->setName("Weather");
4151 application->setIconId("weather");
4152- application->setStage(ApplicationInfo::SideStage);
4153+ application->setScreenshotId("ubuntu-weather-app.svg");
4154+ application->setSupportedOrientations(Qt::LandscapeOrientation
4155+ | Qt::InvertedLandscapeOrientation);
4156 m_availableApplications.append(application);
4157
4158 application = new ApplicationInfo(this);
4159
4160=== modified file 'tests/mocks/Unity/Application/CMakeLists.txt'
4161--- tests/mocks/Unity/Application/CMakeLists.txt 2014-10-06 15:45:25 +0000
4162+++ tests/mocks/Unity/Application/CMakeLists.txt 2015-04-16 14:12:24 +0000
4163@@ -1,4 +1,6 @@
4164-pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=5)
4165+include_directories(
4166+ ${APPLICATION_API_INCLUDE_DIRS}
4167+)
4168
4169 set(FakeUnityApplicationQml_SOURCES
4170 plugin.cpp
4171@@ -14,6 +16,7 @@
4172 SurfaceManager.cpp
4173 SessionModel.h
4174 UbuntuKeyboardInfo.cpp
4175+ VirtualKeyboard.cpp
4176 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationInfoInterface.h
4177 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationManagerInterface.h
4178 )
4179
4180=== modified file 'tests/mocks/Unity/Application/MirSurfaceItem.cpp'
4181--- tests/mocks/Unity/Application/MirSurfaceItem.cpp 2015-03-12 14:45:44 +0000
4182+++ tests/mocks/Unity/Application/MirSurfaceItem.cpp 2015-04-16 14:12:24 +0000
4183@@ -1,5 +1,5 @@
4184 /*
4185- * Copyright (C) 2014 Canonical, Ltd.
4186+ * Copyright (C) 2014-2015 Canonical, Ltd.
4187 *
4188 * This program is free software; you can redistribute it and/or modify
4189 * it under the terms of the GNU General Public License as published by
4190@@ -39,14 +39,12 @@
4191 , m_type(type)
4192 , m_state(state)
4193 , m_live(true)
4194- , m_orientation(Qt::PortraitOrientation)
4195+ , m_orientationAngle(Angle0)
4196+ , m_qmlItem(nullptr)
4197+ , m_screenshotUrl(screenshot)
4198 , m_touchPressCount(0)
4199 , m_touchReleaseCount(0)
4200- , m_qmlItem(nullptr)
4201- , m_screenshotUrl(screenshot)
4202 {
4203- qDebug() << "MirSurfaceItem::MirSurfaceItem() " << this->name();
4204-
4205 setAcceptedMouseButtons(Qt::LeftButton | Qt::MiddleButton | Qt::RightButton |
4206 Qt::ExtraButton1 | Qt::ExtraButton2 | Qt::ExtraButton3 | Qt::ExtraButton4 |
4207 Qt::ExtraButton5 | Qt::ExtraButton6 | Qt::ExtraButton7 | Qt::ExtraButton8 |
4208@@ -55,9 +53,6 @@
4209
4210 QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership);
4211
4212- connect(this, &QQuickItem::focusChanged,
4213- this, &MirSurfaceItem::onFocusChanged);
4214-
4215 // The assumptions I make here really should hold.
4216 QQuickView *quickView =
4217 qobject_cast<QQuickView*>(QGuiApplication::topLevelWindows()[0]);
4218@@ -117,17 +112,17 @@
4219 }
4220 }
4221
4222-void MirSurfaceItem::setOrientation(const Qt::ScreenOrientation orientation)
4223+void MirSurfaceItem::setOrientationAngle(OrientationAngle angle)
4224 {
4225- if (m_orientation == orientation)
4226+ if (m_orientationAngle == angle)
4227 return;
4228
4229- m_orientation = orientation;
4230-
4231- QQmlProperty orientationProp(m_qmlItem, "orientation");
4232- orientationProp.write(QVariant::fromValue(orientation));
4233-
4234- Q_EMIT orientationChanged();
4235+ m_orientationAngle = angle;
4236+
4237+ QQmlProperty orientationProp(m_qmlItem, "orientationAngle");
4238+ orientationProp.write(QVariant::fromValue(m_orientationAngle));
4239+
4240+ Q_EMIT orientationAngleChanged(m_orientationAngle);
4241 }
4242
4243 void MirSurfaceItem::setSession(Session* session)
4244@@ -152,15 +147,6 @@
4245 }
4246 }
4247
4248-void MirSurfaceItem::onFocusChanged()
4249-{
4250- if (!hasFocus()) {
4251- // Causes a crash in tst_Shell.qml, inside the mock Unity.Application itself.
4252- // Didn't have time to debug yet.
4253- //Q_EMIT inputMethodDismissed();
4254- }
4255-}
4256-
4257 void MirSurfaceItem::setState(MirSurfaceItem::State newState)
4258 {
4259 if (newState != m_state) {
4260@@ -197,9 +183,6 @@
4261 if (event->touchPointStates() & Qt::TouchPointPressed) {
4262 ++m_touchPressCount;
4263 Q_EMIT touchPressCountChanged(m_touchPressCount);
4264- // Causes a crash in tst_Shell.qml, inside the mock Unity.Application itself.
4265- // Didn't have time to debug yet.
4266- // Q_EMIT inputMethodRequested();
4267 } else if (event->touchPointStates() & Qt::TouchPointReleased) {
4268 ++m_touchReleaseCount;
4269 Q_EMIT touchReleaseCountChanged(m_touchReleaseCount);
4270
4271=== modified file 'tests/mocks/Unity/Application/MirSurfaceItem.h'
4272--- tests/mocks/Unity/Application/MirSurfaceItem.h 2015-03-12 14:45:44 +0000
4273+++ tests/mocks/Unity/Application/MirSurfaceItem.h 2015-04-16 14:12:24 +0000
4274@@ -1,5 +1,5 @@
4275 /*
4276- * Copyright (C) 2014 Canonical, Ltd.
4277+ * Copyright (C) 2014-2015 Canonical, Ltd.
4278 *
4279 * This program is free software; you can redistribute it and/or modify
4280 * it under the terms of the GNU General Public License as published by
4281@@ -29,17 +29,18 @@
4282 Q_OBJECT
4283 Q_ENUMS(Type)
4284 Q_ENUMS(State)
4285+ Q_ENUMS(OrientationAngle)
4286
4287 Q_PROPERTY(Type type READ type NOTIFY typeChanged)
4288 Q_PROPERTY(State state READ state NOTIFY stateChanged)
4289 Q_PROPERTY(QString name READ name CONSTANT)
4290 Q_PROPERTY(bool live READ live NOTIFY liveChanged)
4291- Q_PROPERTY(Qt::ScreenOrientation orientation READ orientation WRITE setOrientation NOTIFY orientationChanged DESIGNABLE false)
4292-
4293- Q_PROPERTY(int touchPressCount READ touchPressCount WRITE setTouchPressCount NOTIFY touchPressCountChanged
4294- DESIGNABLE false)
4295- Q_PROPERTY(int touchReleaseCount READ touchReleaseCount WRITE setTouchReleaseCount NOTIFY touchReleaseCountChanged
4296- DESIGNABLE false)
4297+ Q_PROPERTY(OrientationAngle orientationAngle READ orientationAngle WRITE setOrientationAngle
4298+ NOTIFY orientationAngleChanged DESIGNABLE false)
4299+ Q_PROPERTY(int touchPressCount READ touchPressCount WRITE setTouchPressCount
4300+ NOTIFY touchPressCountChanged DESIGNABLE false)
4301+ Q_PROPERTY(int touchReleaseCount READ touchReleaseCount WRITE setTouchReleaseCount
4302+ NOTIFY touchReleaseCountChanged DESIGNABLE false)
4303
4304 public:
4305 enum Type {
4306@@ -62,6 +63,13 @@
4307 Fullscreen,
4308 };
4309
4310+ enum OrientationAngle {
4311+ Angle0 = 0,
4312+ Angle90 = 90,
4313+ Angle180 = 180,
4314+ Angle270 = 270
4315+ };
4316+
4317 ~MirSurfaceItem();
4318
4319 //getters
4320@@ -70,9 +78,9 @@
4321 State state() const { return m_state; }
4322 QString name() const { return m_name; }
4323 bool live() const { return m_live; }
4324- Qt::ScreenOrientation orientation() const { return m_orientation; }
4325+ OrientationAngle orientationAngle() const { return m_orientationAngle; }
4326
4327- void setOrientation(const Qt::ScreenOrientation orientation);
4328+ void setOrientationAngle(OrientationAngle angle);
4329
4330 void setSession(Session* item);
4331 void setScreenshot(const QUrl& screenshot);
4332@@ -91,29 +99,14 @@
4333 void typeChanged(Type);
4334 void stateChanged(State);
4335 void liveChanged(bool live);
4336- void orientationChanged();
4337+ void orientationAngleChanged(OrientationAngle angle);
4338 void touchPressCountChanged(int count);
4339 void touchReleaseCountChanged(int count);
4340
4341- void inputMethodRequested();
4342- void inputMethodDismissed();
4343-
4344 // internal mock use
4345 void deregister();
4346
4347 protected:
4348- void touchEvent(QTouchEvent * event) override;
4349-
4350- // becaue the default implementation ignores the events
4351- void mousePressEvent(QMouseEvent *) override {}
4352- void mouseMoveEvent(QMouseEvent *) override {}
4353- void mouseReleaseEvent(QMouseEvent *) override {}
4354-
4355-private Q_SLOTS:
4356- void onFocusChanged();
4357- void onComponentStatusChanged(QQmlComponent::Status status);
4358-
4359-private:
4360 explicit MirSurfaceItem(const QString& name,
4361 Type type,
4362 State state,
4363@@ -121,6 +114,12 @@
4364 const QString &qmlFilePath = QString(),
4365 QQuickItem *parent = 0);
4366
4367+ void touchEvent(QTouchEvent * event) override;
4368+
4369+private Q_SLOTS:
4370+ void onComponentStatusChanged(QQmlComponent::Status status);
4371+
4372+private:
4373 void createQmlContentItem();
4374 void printComponentErrors();
4375
4376@@ -129,19 +128,20 @@
4377 const Type m_type;
4378 State m_state;
4379 bool m_live;
4380- Qt::ScreenOrientation m_orientation;
4381- int m_touchPressCount;
4382- int m_touchReleaseCount;
4383+ OrientationAngle m_orientationAngle;
4384
4385 QQmlComponent *m_qmlContentComponent;
4386 QQuickItem *m_qmlItem;
4387 QUrl m_screenshotUrl;
4388
4389+ int m_touchPressCount;
4390+ int m_touchReleaseCount;
4391+
4392 friend class SurfaceManager;
4393 };
4394
4395 Q_DECLARE_METATYPE(MirSurfaceItem*)
4396 Q_DECLARE_METATYPE(QList<MirSurfaceItem*>)
4397-Q_DECLARE_METATYPE(Qt::ScreenOrientation)
4398+Q_DECLARE_METATYPE(MirSurfaceItem::OrientationAngle)
4399
4400 #endif // MIRSURFACEITEM_H
4401
4402=== modified file 'tests/mocks/Unity/Application/MirSurfaceItem.qml'
4403--- tests/mocks/Unity/Application/MirSurfaceItem.qml 2015-01-28 12:59:21 +0000
4404+++ tests/mocks/Unity/Application/MirSurfaceItem.qml 2015-04-16 14:12:24 +0000
4405@@ -1,5 +1,5 @@
4406 /*
4407- * Copyright 2014 Canonical Ltd.
4408+ * Copyright 2014-2015 Canonical Ltd.
4409 *
4410 * This program is free software; you can redistribute it and/or modify
4411 * it under the terms of the GNU Lesser General Public License as published by
4412@@ -23,19 +23,11 @@
4413 implicitWidth: units.gu(40)
4414 implicitHeight: units.gu(70)
4415
4416- rotation: {
4417- if (orientation == Qt.PortraitOrientation) return 0;
4418- else if (orientation == Qt.LandscapeOrientation) return 90;
4419- else if (orientation == Qt.InvertedPortraitOrientation) return 180;
4420- else return 270;
4421- }
4422- x: parent ? (parent.width - width) / 2 : 0
4423- y: parent ? (parent.height - height) / 2 : 0
4424- width: parent ? (rotation == 0 || rotation == 180 ? parent.width : parent.height) : implicitWidth
4425- height: parent ? (rotation == 0 || rotation == 180 ? parent.height : parent.width) : implicitHeight
4426+ width: parent ? parent.width : implicitWidth
4427+ height: parent ? parent.height : implicitHeight
4428
4429 property alias screenshotSource: screenshotImage.source
4430- property int orientation: Qt.PortraitOrientation
4431+ property int orientationAngle
4432
4433 Image {
4434 id: screenshotImage
4435@@ -50,6 +42,7 @@
4436 fontSizeMode: Text.Fit
4437 minimumPixelSize: 10
4438 verticalAlignment: Text.AlignVCenter
4439+ rotation: surfaceText.rotation
4440 x: surfaceText.x
4441 y: surfaceText.y
4442 width: surfaceText.width
4443@@ -59,12 +52,17 @@
4444 }
4445 Text {
4446 id: surfaceText
4447- anchors.fill: parent
4448- text: "SURFACE"
4449+ text: "SURFACE " + root.width + "," + root.height
4450 color: root.parent && root.parent.activeFocus ? "yellow" : "blue"
4451 font.bold: true
4452 fontSizeMode: Text.Fit
4453 minimumPixelSize: 10; font.pixelSize: 200
4454 verticalAlignment: Text.AlignVCenter
4455+
4456+ rotation: root.orientationAngle
4457+ x: (parent.width - width) / 2
4458+ y: (parent.height - height) / 2
4459+ width: (rotation == 0 || rotation == 180 ? parent.width : parent.height)
4460+ height:(rotation == 0 || rotation == 180 ? parent.height : parent.width)
4461 }
4462 }
4463
4464=== modified file 'tests/mocks/Unity/Application/SurfaceManager.cpp'
4465--- tests/mocks/Unity/Application/SurfaceManager.cpp 2014-08-29 14:50:49 +0000
4466+++ tests/mocks/Unity/Application/SurfaceManager.cpp 2015-04-16 14:12:24 +0000
4467@@ -16,8 +16,9 @@
4468
4469 #include "SurfaceManager.h"
4470
4471+#include "VirtualKeyboard.h"
4472+
4473 #include <paths.h>
4474-#include "MirSurfaceItem.h"
4475
4476 SurfaceManager *SurfaceManager::the_surface_manager = nullptr;
4477
4478@@ -40,10 +41,7 @@
4479 MirSurfaceItem::State state,
4480 const QUrl& screenshot)
4481 {
4482- MirSurfaceItem* surface = new MirSurfaceItem(name,
4483- type,
4484- state,
4485- screenshot);
4486+ MirSurfaceItem* surface = new MirSurfaceItem(name, type, state, screenshot);
4487 Q_EMIT surfaceCreated(surface);
4488 return surface;
4489 }
4490@@ -57,40 +55,12 @@
4491 surface->setLive(false);
4492 Q_EMIT surfaceDestroyed(surface);
4493 });
4494- connect(surface, &MirSurfaceItem::inputMethodRequested,
4495- this, &SurfaceManager::showInputMethod);
4496- connect(surface, &MirSurfaceItem::inputMethodDismissed,
4497- this, &SurfaceManager::hideInputMethod);
4498-}
4499-
4500-void SurfaceManager::showInputMethod()
4501-{
4502- inputMethodSurface()->setState(MirSurfaceItem::Restored);
4503-}
4504-
4505-void SurfaceManager::hideInputMethod()
4506-{
4507- if (m_virtualKeyboard) {
4508- m_virtualKeyboard->setState(MirSurfaceItem::Minimized);
4509- }
4510 }
4511
4512 MirSurfaceItem *SurfaceManager::inputMethodSurface()
4513 {
4514 if (!m_virtualKeyboard) {
4515-
4516- QString screenshotPath = QString("file://%1/Dash/graphics/phone/screenshots/vkb_portrait.png")
4517- .arg(qmlDirectory());
4518-
4519- QString qmlFilePath = QString("%1/Unity/Application/VirtualKeyboard.qml")
4520- .arg(mockPluginsDir());
4521-
4522- m_virtualKeyboard = new MirSurfaceItem(
4523- "input-method",
4524- MirSurfaceItem::InputMethod,
4525- MirSurfaceItem::Minimized,
4526- screenshotPath,
4527- qmlFilePath);
4528+ m_virtualKeyboard = new VirtualKeyboard;
4529 Q_EMIT surfaceCreated(m_virtualKeyboard);
4530 }
4531 return m_virtualKeyboard;
4532
4533=== modified file 'tests/mocks/Unity/Application/SurfaceManager.h'
4534--- tests/mocks/Unity/Application/SurfaceManager.h 2014-08-28 23:16:07 +0000
4535+++ tests/mocks/Unity/Application/SurfaceManager.h 2015-04-16 14:12:24 +0000
4536@@ -20,6 +20,7 @@
4537 #include <QObject>
4538
4539 #include "MirSurfaceItem.h"
4540+#include "VirtualKeyboard.h"
4541
4542 class SurfaceManager : public QObject
4543 {
4544@@ -45,13 +46,9 @@
4545 void surfaceCreated(MirSurfaceItem *surface);
4546 void surfaceDestroyed(MirSurfaceItem *surface);
4547
4548-private Q_SLOTS:
4549- void showInputMethod();
4550- void hideInputMethod();
4551-
4552 private:
4553 static SurfaceManager *the_surface_manager;
4554- MirSurfaceItem *m_virtualKeyboard;
4555+ VirtualKeyboard *m_virtualKeyboard;
4556 };
4557
4558 #endif // SURFACEMANAGER_H
4559
4560=== modified file 'tests/mocks/Unity/Application/UbuntuKeyboardInfo.cpp'
4561--- tests/mocks/Unity/Application/UbuntuKeyboardInfo.cpp 2014-10-02 08:50:52 +0000
4562+++ tests/mocks/Unity/Application/UbuntuKeyboardInfo.cpp 2015-04-16 14:12:24 +0000
4563@@ -1,5 +1,5 @@
4564 /*
4565- * Copyright (C) 2014 Canonical, Ltd.
4566+ * Copyright (C) 2014-2015 Canonical, Ltd.
4567 *
4568 * This program is free software: you can redistribute it and/or modify it under
4569 * the terms of the GNU Lesser General Public License version 3, as published by
4570@@ -26,3 +26,35 @@
4571 m_height(200)
4572 {
4573 }
4574+
4575+void UbuntuKeyboardInfo::setX(qreal value)
4576+{
4577+ if (value != m_x) {
4578+ m_x = value;
4579+ Q_EMIT xChanged(m_x);
4580+ }
4581+}
4582+
4583+void UbuntuKeyboardInfo::setY(qreal value)
4584+{
4585+ if (value != m_y) {
4586+ m_y = value;
4587+ Q_EMIT yChanged(m_y);
4588+ }
4589+}
4590+
4591+void UbuntuKeyboardInfo::setWidth(qreal value)
4592+{
4593+ if (value != m_width) {
4594+ m_width = value;
4595+ Q_EMIT widthChanged(m_width);
4596+ }
4597+}
4598+
4599+void UbuntuKeyboardInfo::setHeight(qreal value)
4600+{
4601+ if (value != m_height) {
4602+ m_height = value;
4603+ Q_EMIT heightChanged(m_height);
4604+ }
4605+}
4606
4607=== modified file 'tests/mocks/Unity/Application/UbuntuKeyboardInfo.h'
4608--- tests/mocks/Unity/Application/UbuntuKeyboardInfo.h 2014-10-02 08:50:52 +0000
4609+++ tests/mocks/Unity/Application/UbuntuKeyboardInfo.h 2015-04-16 14:12:24 +0000
4610@@ -1,5 +1,5 @@
4611 /*
4612- * Copyright (C) 2014 Canonical, Ltd.
4613+ * Copyright (C) 2014-2015 Canonical, Ltd.
4614 *
4615 * This program is free software: you can redistribute it and/or modify it under
4616 * the terms of the GNU Lesser General Public License version 3, as published by
4617@@ -22,10 +22,10 @@
4618
4619 class UbuntuKeyboardInfo : public QObject {
4620 Q_OBJECT
4621- Q_PROPERTY(qreal x READ x NOTIFY xChanged)
4622- Q_PROPERTY(qreal y READ y NOTIFY yChanged)
4623- Q_PROPERTY(qreal width READ width NOTIFY widthChanged)
4624- Q_PROPERTY(qreal height READ height NOTIFY heightChanged)
4625+ Q_PROPERTY(qreal x READ x WRITE setX NOTIFY xChanged)
4626+ Q_PROPERTY(qreal y READ y WRITE setY NOTIFY yChanged)
4627+ Q_PROPERTY(qreal width READ width WRITE setWidth NOTIFY widthChanged)
4628+ Q_PROPERTY(qreal height READ height WRITE setHeight NOTIFY heightChanged)
4629 public:
4630 UbuntuKeyboardInfo(QObject *parent = 0);
4631 virtual ~UbuntuKeyboardInfo() {}
4632@@ -34,6 +34,12 @@
4633 qreal width() const { return m_width; }
4634 qreal height() const { return m_height; }
4635
4636+ // Just in the fake implementation
4637+ void setX(qreal value);
4638+ void setY(qreal value);
4639+ void setWidth(qreal value);
4640+ void setHeight(qreal value);
4641+
4642 static UbuntuKeyboardInfo *singleton() {
4643 if (!m_instance) {
4644 m_instance = new UbuntuKeyboardInfo;
4645
4646=== added file 'tests/mocks/Unity/Application/VirtualKeyboard.cpp'
4647--- tests/mocks/Unity/Application/VirtualKeyboard.cpp 1970-01-01 00:00:00 +0000
4648+++ tests/mocks/Unity/Application/VirtualKeyboard.cpp 2015-04-16 14:12:24 +0000
4649@@ -0,0 +1,44 @@
4650+/*
4651+ * Copyright (C) 2015 Canonical, Ltd.
4652+ *
4653+ * This program is free software; you can redistribute it and/or modify
4654+ * it under the terms of the GNU General Public License as published by
4655+ * the Free Software Foundation; version 3.
4656+ *
4657+ * This program is distributed in the hope that it will be useful,
4658+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
4659+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4660+ * GNU General Public License for more details.
4661+ *
4662+ * You should have received a copy of the GNU General Public License
4663+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
4664+ */
4665+
4666+#include "VirtualKeyboard.h"
4667+
4668+#include <paths.h>
4669+
4670+#include <QString>
4671+
4672+#include <QDebug>
4673+
4674+VirtualKeyboard::VirtualKeyboard(QQuickItem *parent)
4675+ : MirSurfaceItem("input-method",
4676+ MirSurfaceItem::InputMethod,
4677+ MirSurfaceItem::Minimized,
4678+ QString("file://%1/Dash/graphics/phone/screenshots/vkb_portrait.png")
4679+ .arg(qmlDirectory()),
4680+ QString("%1/Unity/Application/VirtualKeyboard.qml")
4681+ .arg(mockPluginsDir()),
4682+ parent)
4683+{
4684+}
4685+
4686+VirtualKeyboard::~VirtualKeyboard()
4687+{
4688+}
4689+
4690+void VirtualKeyboard::touchEvent(QTouchEvent *event)
4691+{
4692+ event->setAccepted(false);
4693+}
4694
4695=== added file 'tests/mocks/Unity/Application/VirtualKeyboard.h'
4696--- tests/mocks/Unity/Application/VirtualKeyboard.h 1970-01-01 00:00:00 +0000
4697+++ tests/mocks/Unity/Application/VirtualKeyboard.h 2015-04-16 14:12:24 +0000
4698@@ -0,0 +1,42 @@
4699+/*
4700+ * Copyright (C) 2015 Canonical, Ltd.
4701+ *
4702+ * This program is free software; you can redistribute it and/or modify
4703+ * it under the terms of the GNU General Public License as published by
4704+ * the Free Software Foundation; version 3.
4705+ *
4706+ * This program is distributed in the hope that it will be useful,
4707+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
4708+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4709+ * GNU General Public License for more details.
4710+ *
4711+ * You should have received a copy of the GNU General Public License
4712+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
4713+ */
4714+
4715+#ifndef VIRTUALKEYBOARD_H
4716+#define VIRTUALKEYBOARD_H
4717+
4718+#include "MirSurfaceItem.h"
4719+#include "MirSurfaceItemModel.h"
4720+
4721+#include <QQuickItem>
4722+#include <QUrl>
4723+
4724+class Session;
4725+
4726+class VirtualKeyboard : public MirSurfaceItem
4727+{
4728+ Q_OBJECT
4729+public:
4730+ explicit VirtualKeyboard(QQuickItem *parent = 0);
4731+ ~VirtualKeyboard();
4732+
4733+protected:
4734+ void touchEvent(QTouchEvent * event) override;
4735+};
4736+
4737+Q_DECLARE_METATYPE(VirtualKeyboard*)
4738+Q_DECLARE_METATYPE(QList<VirtualKeyboard*>)
4739+
4740+#endif // VIRTUALKEYBOARD_H
4741
4742=== modified file 'tests/mocks/Unity/Application/VirtualKeyboard.qml'
4743--- tests/mocks/Unity/Application/VirtualKeyboard.qml 2014-08-19 13:26:00 +0000
4744+++ tests/mocks/Unity/Application/VirtualKeyboard.qml 2015-04-16 14:12:24 +0000
4745@@ -1,5 +1,5 @@
4746 /*
4747- * Copyright 2014 Canonical Ltd.
4748+ * Copyright 2014-2015 Canonical Ltd.
4749 *
4750 * This program is free software; you can redistribute it and/or modify
4751 * it under the terms of the GNU Lesser General Public License as published by
4752@@ -15,6 +15,7 @@
4753 */
4754
4755 import QtQuick 2.0
4756+import Unity.Application 0.1
4757
4758 Item {
4759 implicitWidth: units.gu(40)
4760@@ -37,4 +38,9 @@
4761 anchors.fill: parent
4762 }
4763 }
4764+
4765+ Binding { target: UbuntuKeyboardInfo; property: "x"; value: screenshotImage.x}
4766+ Binding { target: UbuntuKeyboardInfo; property: "y"; value: screenshotImage.y}
4767+ Binding { target: UbuntuKeyboardInfo; property: "width"; value: screenshotImage.width}
4768+ Binding { target: UbuntuKeyboardInfo; property: "height"; value: screenshotImage.height}
4769 }
4770
4771=== modified file 'tests/mocks/Unity/Launcher/MockLauncherModel.cpp'
4772--- tests/mocks/Unity/Launcher/MockLauncherModel.cpp 2015-02-09 17:17:59 +0000
4773+++ tests/mocks/Unity/Launcher/MockLauncherModel.cpp 2015-04-16 14:12:24 +0000
4774@@ -1,5 +1,5 @@
4775 /*
4776- * Copyright 2013 Canonical Ltd.
4777+ * Copyright 2013,2015 Canonical Ltd.
4778 *
4779 * This program is free software; you can redistribute it and/or modify
4780 * it under the terms of the GNU Lesser General Public License as published by
4781@@ -35,6 +35,8 @@
4782 item->setProgress(50);
4783 item->setCountVisible(true);
4784 m_list.append(item);
4785+ item = new MockLauncherItem("music-app", "/usr/share/applications/music-app.desktop", "Music", "soundcloud", this);
4786+ m_list.append(item);
4787 item = new MockLauncherItem("facebook-webapp", "/usr/share/applications/facebook-webapp.desktop", "Facebook", "facebook", this);
4788 item->setProgress(150);
4789 m_list.append(item);
4790
4791=== modified file 'tests/plugins/Greeter/Unity/Launcher/CMakeLists.txt'
4792--- tests/plugins/Greeter/Unity/Launcher/CMakeLists.txt 2015-02-11 13:43:17 +0000
4793+++ tests/plugins/Greeter/Unity/Launcher/CMakeLists.txt 2015-04-16 14:12:24 +0000
4794@@ -1,5 +1,5 @@
4795 pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=6)
4796-pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=5)
4797+pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=6)
4798
4799 include_directories(
4800 ${CMAKE_CURRENT_SOURCE_DIR}
4801
4802=== modified file 'tests/plugins/Unity/Launcher/CMakeLists.txt'
4803--- tests/plugins/Unity/Launcher/CMakeLists.txt 2015-02-11 13:43:17 +0000
4804+++ tests/plugins/Unity/Launcher/CMakeLists.txt 2015-04-16 14:12:24 +0000
4805@@ -1,8 +1,8 @@
4806 pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)
4807 pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=6)
4808-pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=5)
4809
4810 include_directories(
4811+ ${APPLICATION_API_INCLUDE_DIRS}
4812 ${CMAKE_CURRENT_BINARY_DIR}
4813 ${CMAKE_SOURCE_DIR}/plugins/AccountsService
4814 ${CMAKE_SOURCE_DIR}/plugins/Unity/Launcher
4815
4816=== modified file 'tests/plugins/Unity/Launcher/launchermodeltest.cpp'
4817--- tests/plugins/Unity/Launcher/launchermodeltest.cpp 2015-03-30 17:36:42 +0000
4818+++ tests/plugins/Unity/Launcher/launchermodeltest.cpp 2015-04-16 14:12:24 +0000
4819@@ -1,5 +1,5 @@
4820 /*
4821- * Copyright 2013-2014 Canonical Ltd.
4822+ * Copyright 2013-2015 Canonical Ltd.
4823 *
4824 * This program is free software; you can redistribute it and/or modify
4825 * it under the terms of the GNU Lesser General Public License as published by
4826@@ -52,6 +52,8 @@
4827 QColor splashColor() const override { return QColor(0,0,0,0); }
4828 QColor splashColorHeader() const override { return QColor(0,0,0,0); }
4829 QColor splashColorFooter() const override { return QColor(0,0,0,0); }
4830+ Qt::ScreenOrientations supportedOrientations() const override { return Qt::PortraitOrientation; }
4831+ bool rotatesWindowContents() const override { return false; }
4832
4833 // Methods used for mocking (not in the interface)
4834 void setFocused(bool focused) { m_focused = focused; Q_EMIT focusedChanged(focused); }
4835
4836=== modified file 'tests/qmltests/CMakeLists.txt'
4837--- tests/qmltests/CMakeLists.txt 2015-03-18 10:18:52 +0000
4838+++ tests/qmltests/CMakeLists.txt 2015-04-16 14:12:24 +0000
4839@@ -19,6 +19,7 @@
4840 set(qmltest_DEFAULT_NO_ADD_TEST TRUE)
4841 set(qmltest_DEFAULT_PROPERTIES ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/libusermetrics:${CMAKE_BINARY_DIR}/tests/mocks/LightDM/liblightdm:${CMAKE_BINARY_DIR}/tests/mocks/QMenuModel")
4842
4843+add_qml_test(. OrientedShell)
4844 add_qml_test(. Shell)
4845 add_qml_test(. ShellWithPin)
4846 add_qml_test(Components Background)
4847
4848=== modified file 'tests/qmltests/Panel/tst_IndicatorsMenu.qml'
4849--- tests/qmltests/Panel/tst_IndicatorsMenu.qml 2014-11-25 12:53:03 +0000
4850+++ tests/qmltests/Panel/tst_IndicatorsMenu.qml 2015-04-16 14:12:24 +0000
4851@@ -28,8 +28,6 @@
4852 height: units.gu(71)
4853 color: "white"
4854
4855- property string indicatorProfile: "phone"
4856-
4857 RowLayout {
4858 anchors.fill: parent
4859 anchors.margins: units.gu(1)
4860
4861=== modified file 'tests/qmltests/Panel/tst_Panel.qml'
4862--- tests/qmltests/Panel/tst_Panel.qml 2015-04-02 15:08:05 +0000
4863+++ tests/qmltests/Panel/tst_Panel.qml 2015-04-16 14:12:24 +0000
4864@@ -29,8 +29,6 @@
4865 height: units.gu(71)
4866 color: "white"
4867
4868- property string indicatorProfile: "phone"
4869-
4870 RowLayout {
4871 anchors.fill: parent
4872 anchors.margins: units.gu(1)
4873
4874=== modified file 'tests/qmltests/Stages/tst_ApplicationWindow.qml'
4875--- tests/qmltests/Stages/tst_ApplicationWindow.qml 2015-01-28 12:59:21 +0000
4876+++ tests/qmltests/Stages/tst_ApplicationWindow.qml 2015-04-16 14:12:24 +0000
4877@@ -1,5 +1,5 @@
4878 /*
4879- * Copyright 2014 Canonical Ltd.
4880+ * Copyright 2014-2015 Canonical Ltd.
4881 *
4882 * This program is free software; you can redistribute it and/or modify
4883 * it under the terms of the GNU General Public License as published by
4884@@ -50,7 +50,7 @@
4885 ApplicationWindow {
4886 anchors.fill: parent
4887 application: fakeApplication
4888- orientation: Qt.PortraitOrientation
4889+ surfaceOrientationAngle: 0
4890 interactive: true
4891 focus: true
4892 }
4893@@ -210,15 +210,6 @@
4894 stateGroup = null;
4895 }
4896
4897- // wait until any transition animation has finished
4898- function waitUntilTransitionsEnd() {
4899- var transitions = stateGroup.transitions;
4900- for (var i = 0; i < transitions.length; ++i) {
4901- var transition = transitions[i];
4902- tryCompare(transition, "running", false, 2000);
4903- }
4904- }
4905-
4906 function init() {
4907 findInterestingApplicationWindowChildren();
4908 }
4909@@ -280,12 +271,12 @@
4910
4911 tryCompare(stateGroup, "state", "surface");
4912
4913- waitUntilTransitionsEnd();
4914+ waitUntilTransitionsEnd(stateGroup);
4915
4916 setApplicationState(appSuspended);
4917
4918 verify(stateGroup.state === "surface");
4919- waitUntilTransitionsEnd();
4920+ waitUntilTransitionsEnd(stateGroup);
4921 }
4922
4923 function test_killedAppShowsScreenshot() {
4924@@ -311,7 +302,7 @@
4925 initSession();
4926 setApplicationState(appRunning);
4927 tryCompare(stateGroup, "state", "surface");
4928- waitUntilTransitionsEnd();
4929+ waitUntilTransitionsEnd(stateGroup);
4930
4931 setApplicationState(appSuspended);
4932
4933@@ -319,19 +310,19 @@
4934 setApplicationState(appStopped);
4935
4936 tryCompare(stateGroup, "state", "screenshot");
4937- waitUntilTransitionsEnd();
4938+ waitUntilTransitionsEnd(stateGroup);
4939 tryCompare(fakeApplication, "session", null);
4940
4941 // and restart it
4942 setApplicationState(appStarting);
4943
4944- waitUntilTransitionsEnd();
4945+ waitUntilTransitionsEnd(stateGroup);
4946 verify(stateGroup.state === "screenshot");
4947 verify(fakeSession === null);
4948
4949 setApplicationState(appRunning);
4950
4951- waitUntilTransitionsEnd();
4952+ waitUntilTransitionsEnd(stateGroup);
4953 verify(stateGroup.state === "screenshot");
4954
4955 initSession();
4956@@ -344,7 +335,7 @@
4957 initSession();
4958 setApplicationState(appRunning);
4959 tryCompare(stateGroup, "state", "surface");
4960- waitUntilTransitionsEnd();
4961+ waitUntilTransitionsEnd(stateGroup);
4962
4963 // oh, it crashed...
4964 setApplicationState(appStopped);
4965@@ -357,18 +348,18 @@
4966 initSession();
4967 setApplicationState(appRunning);
4968 tryCompare(stateGroup, "state", "surface");
4969- waitUntilTransitionsEnd();
4970+ waitUntilTransitionsEnd(stateGroup);
4971 verify(fakeSession.surface !== null);
4972
4973 applicationWindowLoader.item.visible = false;
4974
4975- waitUntilTransitionsEnd();
4976+ waitUntilTransitionsEnd(stateGroup);
4977 verify(stateGroup.state === "surface");
4978 verify(fakeSession.surface !== null);
4979
4980 applicationWindowLoader.item.visible = true;
4981
4982- waitUntilTransitionsEnd();
4983+ waitUntilTransitionsEnd(stateGroup);
4984 verify(stateGroup.state === "surface");
4985 verify(fakeSession.surface !== null);
4986 }
4987@@ -379,7 +370,7 @@
4988
4989 tryCompare(stateGroup, "state", "surface");
4990
4991- waitUntilTransitionsEnd();
4992+ waitUntilTransitionsEnd(stateGroup);
4993
4994 var fakeSurface = fakeSession.surface;
4995 fakeSurface.touchPressCount = 0;
4996@@ -396,7 +387,7 @@
4997 initSession();
4998 setApplicationState(appRunning);
4999 tryCompare(stateGroup, "state", "surface");
5000- waitUntilTransitionsEnd();
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches