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

FAILED: Continuous integration, rev:1746 jenkins. qa.ubuntu. com/job/ unity8- ci/5675/ jenkins. qa.ubuntu. com/job/ generic- deb-autopilot- vivid-touch/ 2628/console jenkins. qa.ubuntu. com/job/ unity-phablet- qmluitests- vivid/840/ console jenkins. qa.ubuntu. com/job/ unity8- vivid-amd64- ci/840/ console jenkins. qa.ubuntu. com/job/ unity8- vivid-i386- ci/840/ console jenkins. qa.ubuntu. com/job/ generic- mediumtests- builder- vivid-armhf/ 2626/console
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/unity8- ci/5675/ rebuild
http://