Merge lp:~mzanetti/unity8/inputinfo-plugin into lp:unity8

Proposed by Michael Zanetti
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
Reviewer Review Type Date Requested Status
PS Jenkins bot (community) continuous-integration Needs Fixing
Unity Team Pending
Review via email: mp+258241@code.launchpad.net

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://codereview.qt-project.org/#/c/101049/

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.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
lp:~mzanetti/unity8/inputinfo-plugin updated
1747. By Michael Zanetti

[ 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)

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
lp:~mzanetti/unity8/inputinfo-plugin updated
1748. By Michael Zanetti

rebase on shellRotation

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
lp:~mzanetti/unity8/inputinfo-plugin updated
1749. By Michael Zanetti

merge trunk

1750. By Michael Zanetti

drop debug print

1751. By Michael Zanetti

merge trunk

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'CMakeLists.txt'
--- CMakeLists.txt 2015-03-12 13:59:07 +0000
+++ CMakeLists.txt 2015-05-18 22:06:13 +0000
@@ -56,6 +56,8 @@
56find_package(Qt5Concurrent 5.2 REQUIRED)56find_package(Qt5Concurrent 5.2 REQUIRED)
57find_package(Qt5Sql 5.2 REQUIRED)57find_package(Qt5Sql 5.2 REQUIRED)
5858
59pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=6)
60
59# Standard install paths61# Standard install paths
60include(GNUInstallDirs)62include(GNUInstallDirs)
6163
6264
=== modified file 'data/unity8-dash.desktop.in'
--- data/unity8-dash.desktop.in 2014-09-04 13:23:09 +0000
+++ data/unity8-dash.desktop.in 2015-05-18 22:06:13 +0000
@@ -7,3 +7,4 @@
7Icon=7Icon=
8NoDisplay=true8NoDisplay=true
9X-Ubuntu-Touch=true9X-Ubuntu-Touch=true
10X-Ubuntu-Supported-Orientations=primary
1011
=== modified file 'debian/changelog'
--- debian/changelog 2015-05-11 08:29:58 +0000
+++ debian/changelog 2015-05-18 22:06:13 +0000
@@ -1,3 +1,9 @@
1unity8 (8.10-0ubuntu1) UNRELEASED; urgency=medium
2
3 * Implement full-shell rotation (LP: #1210199)
4
5 -- Michał Sawicz <michal.sawicz@canonical.com> Wed, 15 Apr 2015 14:47:17 +0200
6
1unity8 (8.02+15.04.20150511-0ubuntu1) vivid; urgency=medium7unity8 (8.02+15.04.20150511-0ubuntu1) vivid; urgency=medium
28
3 [ Albert Astals Cid ]9 [ Albert Astals Cid ]
410
=== modified file 'debian/control'
--- debian/control 2015-04-22 14:43:17 +0000
+++ debian/control 2015-05-18 22:06:13 +0000
@@ -12,9 +12,11 @@
12# append :native to g++-4.9 so we don't try to run armhf g++12# append :native to g++-4.9 so we don't try to run armhf g++
13# on an x86 CPU for eaxmple, when cross-compiling.13# on an x86 CPU for eaxmple, when cross-compiling.
14 g++-4.9:native,14 g++-4.9:native,
15 libandroid-properties-dev,
15 graphviz,16 graphviz,
16 gsettings-ubuntu-schemas (>= 0.0.2+14.10.20140815),17 gsettings-ubuntu-schemas (>= 0.0.2+14.10.20140815),
17 libconnectivity-qt1-dev,18 libconnectivity-qt1-dev,
19 libevdev-dev,
18 libgl1-mesa-dev[!armhf] | libgl-dev[!armhf],20 libgl1-mesa-dev[!armhf] | libgl-dev[!armhf],
19 libgl1-mesa-dri,21 libgl1-mesa-dri,
20 libgles2-mesa-dev[armhf],22 libgles2-mesa-dev[armhf],
@@ -27,7 +29,8 @@
27 libqmenumodel-dev (>= 0.2.9),29 libqmenumodel-dev (>= 0.2.9),
28 libqt5xmlpatterns5-dev,30 libqt5xmlpatterns5-dev,
29 libsystemsettings-dev,31 libsystemsettings-dev,
30 libunity-api-dev (>= 7.96),32 libudev-dev,
33 libunity-api-dev (>= 7.97),
31 libusermetricsoutput1-dev,34 libusermetricsoutput1-dev,
32 libxcb1-dev,35 libxcb1-dev,
33 pkg-config,36 pkg-config,
@@ -94,7 +97,7 @@
94 qml-module-qtquick-xmllistmodel,97 qml-module-qtquick-xmllistmodel,
95 qml-module-qtsysteminfo,98 qml-module-qtsysteminfo,
96 qtdeclarative5-gsettings1.0,99 qtdeclarative5-gsettings1.0,
97 qtdeclarative5-qtmir-plugin (>= 0.4.4),100 qtdeclarative5-qtmir-plugin (>= 0.4.5),
98 qtdeclarative5-ubuntu-telephony0.1,101 qtdeclarative5-ubuntu-telephony0.1,
99 qtdeclarative5-ubuntu-web-plugin,102 qtdeclarative5-ubuntu-web-plugin,
100 ubuntu-system-settings,103 ubuntu-system-settings,
@@ -124,7 +127,7 @@
124 qtdeclarative5-ubuntu-ui-toolkit-plugin (>= 1.1.1239) | qtdeclarative5-ubuntu-ui-toolkit-plugin-gles (>= 1.1.1239),127 qtdeclarative5-ubuntu-ui-toolkit-plugin (>= 1.1.1239) | qtdeclarative5-ubuntu-ui-toolkit-plugin-gles (>= 1.1.1239),
125 qtdeclarative5-unity-notifications-plugin (>= 0.1.2) | unity-notifications-impl,128 qtdeclarative5-unity-notifications-plugin (>= 0.1.2) | unity-notifications-impl,
126 ubuntu-thumbnailer-impl-0,129 ubuntu-thumbnailer-impl-0,
127 unity-application-impl-4,130 unity-application-impl-6,
128 unity-notifications-impl-3,131 unity-notifications-impl-3,
129 unity-plugin-scopes | unity-scopes-impl,132 unity-plugin-scopes | unity-scopes-impl,
130 unity-scopes-impl-6,133 unity-scopes-impl-6,
@@ -168,7 +171,7 @@
168Depends: ${misc:Depends},171Depends: ${misc:Depends},
169 ${shlibs:Depends},172 ${shlibs:Depends},
170Provides: unity-application-impl,173Provides: unity-application-impl,
171 unity-application-impl-4,174 unity-application-impl-6,
172Replaces: unity8-autopilot (<< 8.02+15.04.20150422-0ubuntu1)175Replaces: unity8-autopilot (<< 8.02+15.04.20150422-0ubuntu1)
173Description: Fake environment for running Unity 8 shell176Description: Fake environment for running Unity 8 shell
174 Provides fake implementations of some QML modules used by Unity 8 shell177 Provides fake implementations of some QML modules used by Unity 8 shell
175178
=== modified file 'debian/unity8.install'
--- debian/unity8.install 2015-04-21 15:22:53 +0000
+++ debian/unity8.install 2015-05-18 22:06:13 +0000
@@ -8,6 +8,9 @@
8usr/share/unity8/Greeter8usr/share/unity8/Greeter
9usr/share/unity8/Launcher9usr/share/unity8/Launcher
10usr/share/unity8/Panel10usr/share/unity8/Panel
11usr/share/unity8/Rotation
12usr/share/unity8/DeviceConfiguration.qml
13usr/share/unity8/OrientedShell.qml
11usr/share/unity8/Shell.qml14usr/share/unity8/Shell.qml
12usr/share/unity8/Stages15usr/share/unity8/Stages
13usr/share/unity8/Tutorial16usr/share/unity8/Tutorial
1417
=== modified file 'plugins/Greeter/Unity/Launcher/CMakeLists.txt'
--- plugins/Greeter/Unity/Launcher/CMakeLists.txt 2015-04-22 14:45:11 +0000
+++ plugins/Greeter/Unity/Launcher/CMakeLists.txt 2015-05-18 22:06:13 +0000
@@ -1,5 +1,5 @@
1pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=6)1pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=6)
2pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=5)2pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=6)
3pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)3pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)
44
5add_definitions(-DSM_BUSNAME=systemBus)5add_definitions(-DSM_BUSNAME=systemBus)
66
=== modified file 'plugins/Unity/CMakeLists.txt'
--- plugins/Unity/CMakeLists.txt 2014-08-25 10:05:13 +0000
+++ plugins/Unity/CMakeLists.txt 2015-05-18 22:06:13 +0000
@@ -3,3 +3,4 @@
3add_subdirectory(Launcher)3add_subdirectory(Launcher)
4add_subdirectory(Session)4add_subdirectory(Session)
5add_subdirectory(DashCommunicator)5add_subdirectory(DashCommunicator)
6add_subdirectory(InputInfo)
67
=== added directory 'plugins/Unity/InputInfo'
=== added file 'plugins/Unity/InputInfo/CMakeLists.txt'
--- plugins/Unity/InputInfo/CMakeLists.txt 1970-01-01 00:00:00 +0000
+++ plugins/Unity/InputInfo/CMakeLists.txt 2015-05-18 22:06:13 +0000
@@ -0,0 +1,41 @@
1# This is a temporary snapshot of the WIP QInputInfo API as we
2# require this in unity now but upstream isn't finished yet.
3# Eventually this should be dropped in favor of the upstream
4# QInputInfo API.
5
6project(InputInfo)
7
8find_package(Qt5Core REQUIRED)
9find_package(Qt5Quick REQUIRED)
10
11pkg_check_modules(LIBUDEV REQUIRED libudev)
12pkg_check_modules(LIBEVDEV REQUIRED libevdev)
13
14message("blabla ${LIBUDEV_INCLUDE_DIRS} ${LIBEVDEV_INCLUDE_DIRS} ${LIBUDEV_LDFLAGS} ${LIBEVDEV_LDFLAGS}")
15
16include_directories(
17 ${CMAKE_CURRENT_SOURCE_DIR}
18 ${CMAKE_CURRENT_BINARY_DIR}
19 ${LIBUDEV_INCLUDE_DIRS}
20 ${LIBEVDEV_INCLUDE_DIRS}
21)
22
23set(InputInfo_SOURCES
24 plugin.cpp
25 qinputinfo.cpp
26 qdeclarativeinputdeviceinfo.cpp
27 linux/qinputdeviceinfo_linux.cpp
28)
29
30add_library(InputInfo SHARED
31 ${InputInfo_SOURCES}
32)
33
34target_link_libraries(InputInfo
35 ${LIBUDEV_LDFLAGS}
36 ${LIBEVDEV_LDFLAGS}
37)
38
39qt5_use_modules(InputInfo Core Qml Quick)
40
41add_unity8_plugin(Unity.InputInfo 0.1 Unity/InputInfo TARGETS InputInfo)
042
=== added directory 'plugins/Unity/InputInfo/linux'
=== added file 'plugins/Unity/InputInfo/linux/qinputdeviceinfo_linux.cpp'
--- plugins/Unity/InputInfo/linux/qinputdeviceinfo_linux.cpp 1970-01-01 00:00:00 +0000
+++ plugins/Unity/InputInfo/linux/qinputdeviceinfo_linux.cpp 2015-05-18 22:06:13 +0000
@@ -0,0 +1,249 @@
1/****************************************************************************
2**
3** Copyright (C) 2014 Canonical, Ltd. and/or its subsidiary(-ies).
4** Contact: http://www.qt-project.org/legal
5**
6** This file is part of the QtSystems module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Digia. For licensing terms and
14** conditions see http://qt.digia.com/licensing. For further information
15** use the contact form at http://qt.digia.com/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 2.1 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 2.1 requirements
23** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24**
25** In addition, as a special exception, Digia gives you certain additional
26** rights. These rights are described in the Digia Qt LGPL Exception
27** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28**
29** GNU General Public License Usage
30** Alternatively, this file may be used under the terms of the GNU
31** General Public License version 3.0 as published by the Free Software
32** Foundation and appearing in the file LICENSE.GPL included in the
33** packaging of this file. Please review the following information to
34** ensure the GNU General Public License version 3.0 requirements will be
35** met: http://www.gnu.org/copyleft/gpl.html.
36**
37**
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qinputdeviceinfo_linux_p.h"
43
44#include <libudev.h>
45#include <libevdev/libevdev.h>
46#include <fcntl.h>
47#include <QDebug>
48#include <QSocketNotifier>
49#include <QTimer>
50
51QInputDeviceInfoPrivate::QInputDeviceInfoPrivate(QObject *parent) :
52 QObject(parent)
53 , udev(0)
54{
55 QTimer::singleShot(250,this,SLOT(init()));
56}
57
58void QInputDeviceInfoPrivate::init()
59{
60 if (!udev)
61 udev = udev_new();
62
63 struct udev_list_entry *devices, *dev_list_entry;
64 struct udev_device *dev;
65
66 QString subsystem = QStringLiteral("input");
67 struct udev_enumerate *enumerate = 0;
68
69 if (udev) {
70
71 udevMonitor = udev_monitor_new_from_netlink(udev, "udev");
72 udev_monitor_filter_add_match_subsystem_devtype(udevMonitor, subsystem.toLatin1(), NULL);
73 enumerate = udev_enumerate_new(udev);
74 udev_enumerate_add_match_subsystem(enumerate, subsystem.toLatin1());
75
76
77 udev_monitor_enable_receiving(udevMonitor);
78 notifierFd = udev_monitor_get_fd(udevMonitor);
79
80 notifier = new QSocketNotifier(notifierFd, QSocketNotifier::Read, this);
81 connect(notifier, SIGNAL(activated(int)), this, SLOT(onUDevChanges()));
82
83
84 udev_enumerate_scan_devices(enumerate);
85 devices = udev_enumerate_get_list_entry(enumerate);
86
87 udev_list_entry_foreach(dev_list_entry, devices) {
88 const char *path;
89 path = udev_list_entry_get_name(dev_list_entry);
90
91 dev = udev_device_new_from_syspath(udev, path);
92
93 QString eventPath = QString::fromLatin1(udev_device_get_sysname(dev));
94
95 if (qstrcmp(udev_device_get_subsystem(dev), "input") == 0 ) {
96
97 if (eventPath.contains(QStringLiteral("event"))) {
98 eventPath.prepend(QStringLiteral("/dev/input/"));
99
100 QInputDevice *iDevice = addDevice(eventPath);
101 if (!iDevice)
102 continue;
103
104 qDebug() << "*** ADDING DEVICE" << eventPath;
105
106 iDevice->setTypes(getInputTypes(dev));
107
108 if (iDevice->switches().count() > 0 && iDevice->buttons().count() == 0)
109 iDevice->setTypes(iDevice->types() | QInputDeviceInfo::Switch);
110
111 if (iDevice->buttons().count() > 0 && iDevice->types() == QInputDeviceInfo::Unknown)
112 iDevice->setTypes(iDevice->types() | QInputDeviceInfo::Button);
113
114 deviceList.append(iDevice);
115 deviceMap.insert(eventPath,iDevice);
116 Q_EMIT newDevice(eventPath);
117
118 }
119 }
120 }
121 udev_enumerate_unref(enumerate);
122 }
123 Q_EMIT ready();
124}
125
126QInputDeviceInfo::InputTypes QInputDeviceInfoPrivate::getInputTypes( struct udev_device *dev)
127{
128 qDebug() << "******* have input type Keyboard" << udev_device_get_property_value(dev, "ID_INPUT_KEYBOARD");
129 qDebug() << "******* have input type Mouse" << udev_device_get_property_value(dev, "ID_INPUT_MOUSE");
130 qDebug() << "******* have input type Touchpad" << udev_device_get_property_value(dev, "ID_INPUT_TOUCHPAD");
131 qDebug() << "******* have input type Touchscreen" << udev_device_get_property_value(dev, "ID_INPUT_TOUCHSCREEN");
132 qDebug() << "******* have input type Tablet" << udev_device_get_property_value(dev, "ID_INPUT_TABLET");
133 qDebug() << "******* have input type joystick" << udev_device_get_property_value(dev, "ID_INPUT_JOYSTICK");
134 QInputDeviceInfo::InputTypes types = QInputDeviceInfo::Unknown;
135 if (qstrcmp(udev_device_get_property_value(dev, "ID_INPUT_KEYBOARD"), "1") == 0 )
136 types |= QInputDeviceInfo::Keyboard;
137
138 if (qstrcmp(udev_device_get_property_value(dev, "ID_INPUT_MOUSE"), "1") == 0)
139 types |= QInputDeviceInfo::Mouse;
140
141 if (qstrcmp(udev_device_get_property_value(dev, "ID_INPUT_TOUCHPAD"), "1") == 0)
142 types |= QInputDeviceInfo::TouchPad;
143
144 if (qstrcmp(udev_device_get_property_value(dev, "ID_INPUT_TOUCHSCREEN"), "1") == 0
145 || qstrcmp(udev_device_get_property_value(dev, "ID_INPUT_TABLET"), "1") == 0)
146 types |= QInputDeviceInfo::TouchScreen;
147
148 return types;
149}
150
151QInputDevice *QInputDeviceInfoPrivate::addDevice(const QString &path)
152{
153 QInputDevice *inputDevice = new QInputDevice(this);
154
155 struct libevdev *dev = NULL;
156 int fd;
157 int rc = 1;
158 fd = open(path.toLatin1(), O_RDONLY|O_NONBLOCK);
159
160 if (fd == -1) {
161 qDebug() << "Failed to open";
162 return inputDevice;
163 }
164 rc = libevdev_new_from_fd(fd, &dev);
165 if (rc < 0) {
166 qDebug() << "Failed to init libevdev ("<< strerror(-rc) << ")";
167 return inputDevice;
168 }
169
170 inputDevice->setName(QString::fromLatin1(libevdev_get_name(dev)));
171 inputDevice->setDevicePath(path);
172 for (int i = 0; i < EV_MAX; i++) {
173 if (i == EV_KEY || i == EV_SW || i == EV_REL
174 || i == EV_REL || i == EV_ABS) {
175 for (int j = 0; j < libevdev_event_type_get_max(i); j++) {
176 if (libevdev_has_event_code(dev, i, j)) {
177 switch (i) {
178 case EV_KEY:
179 inputDevice->addButton(j);
180 break;
181 case EV_SW:
182 inputDevice->addSwitch(j);
183 break;
184 case EV_REL:
185 inputDevice->addRelativeAxis(j);
186 break;
187 case EV_ABS:
188 inputDevice->addAbsoluteAxis(j);
189 break;
190 };
191 }
192 }
193 }
194 }
195 return inputDevice;
196}
197
198void QInputDeviceInfoPrivate::removeDevice(const QString &path)
199{
200 for (int i = 0; i < deviceList.size(); ++i) {
201 if (deviceList.at(i)->devicePath() == path) {
202 delete deviceList.takeAt(i);
203 deviceMap.remove(path);
204 Q_EMIT deviceRemoved(path);
205 }
206 }
207}
208
209void QInputDeviceInfoPrivate::onUDevChanges()
210{
211 struct udev_device *dev = udev_monitor_receive_device(udevMonitor);
212 if (dev) {
213 if (qstrcmp(udev_device_get_subsystem(dev), "input") == 0 ) {
214 QString eventPath = QString::fromLatin1(udev_device_get_sysname(dev));
215
216 if (eventPath.contains(QStringLiteral("input")))
217 return;
218
219 QString action = QString::fromStdString(udev_device_get_action(dev));
220
221 if (!eventPath.contains(QStringLiteral("/dev/input/")))
222 eventPath.prepend(QStringLiteral("/dev/input/"));
223
224 if (action == QStringLiteral("add")) {
225
226 QInputDevice *iDevice = addDevice(eventPath);
227 if (!iDevice)
228 return;
229
230 iDevice->setTypes(getInputTypes(dev));
231 udev_device_unref(dev);
232
233 if (iDevice->switches().count() > 0 && iDevice->buttons().count() == 0)
234 iDevice->setTypes(iDevice->types() | QInputDeviceInfo::Switch);
235
236 if (iDevice->buttons().count() > 0 && iDevice->types() == QInputDeviceInfo::Unknown)
237 iDevice->setTypes(iDevice->types() | QInputDeviceInfo::Button);
238
239 deviceList.append(iDevice);
240 deviceMap.insert(eventPath,iDevice);
241
242 Q_EMIT newDevice(eventPath);
243
244 } else if (action == QStringLiteral("remove")) {
245 removeDevice(eventPath);
246 }
247 }
248 }
249}
0250
=== added file 'plugins/Unity/InputInfo/linux/qinputdeviceinfo_linux_p.h'
--- plugins/Unity/InputInfo/linux/qinputdeviceinfo_linux_p.h 1970-01-01 00:00:00 +0000
+++ plugins/Unity/InputInfo/linux/qinputdeviceinfo_linux_p.h 2015-05-18 22:06:13 +0000
@@ -0,0 +1,91 @@
1/****************************************************************************
2**
3** Copyright (C) 2014 Canonical, Ltd. and/or its subsidiary(-ies).
4** Contact: http://www.qt-project.org/legal
5**
6** This file is part of the QtSystems module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Digia. For licensing terms and
14** conditions see http://qt.digia.com/licensing. For further information
15** use the contact form at http://qt.digia.com/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 2.1 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 2.1 requirements
23** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24**
25** In addition, as a special exception, Digia gives you certain additional
26** rights. These rights are described in the Digia Qt LGPL Exception
27** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28**
29** GNU General Public License Usage
30** Alternatively, this file may be used under the terms of the GNU
31** General Public License version 3.0 as published by the Free Software
32** Foundation and appearing in the file LICENSE.GPL included in the
33** packaging of this file. Please review the following information to
34** ensure the GNU General Public License version 3.0 requirements will be
35** met: http://www.gnu.org/copyleft/gpl.html.
36**
37**
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#ifndef QINPUTDEVICEINFO_LINUX_P_H
43#define QINPUTDEVICEINFO_LINUX_P_H
44
45#include <QObject>
46#include "qinputinfo.h"
47#include <libudev.h>
48
49class QInputDevicePrivate : public QObject
50{
51 Q_OBJECT
52public:
53 explicit QInputDevicePrivate(QObject *parent = 0);
54
55 QString name;
56 QString devicePath;
57 QList <int> buttons; //keys
58 QList <int> switches;
59 QList <int> relativeAxis;
60 QList <int> absoluteAxis;
61 QInputDeviceInfo::InputTypes types;
62};
63
64class QInputDeviceInfoPrivate : public QObject
65{
66 Q_OBJECT
67public:
68 explicit QInputDeviceInfoPrivate(QObject *parent = 0);
69 QVector <QInputDevice *> deviceList;
70 QMap <QString, QInputDevice *> deviceMap;
71
72Q_SIGNALS:
73 void newDevice(const QString &);
74 void deviceRemoved(const QString &);
75 void ready();
76
77private:
78 struct udev *udev;
79 QInputDevice *addDevice(const QString &path);
80 void removeDevice(const QString &path);
81 QSocketNotifier *notifier;
82 int notifierFd;
83 struct udev_monitor *udevMonitor;
84 QInputDeviceInfo::InputTypes getInputTypes( struct udev_device *);
85
86private Q_SLOTS:
87 void onUDevChanges();
88 void init();
89};
90
91#endif // QINPUTDEVICEINFO_LINUX_P_H
092
=== added file 'plugins/Unity/InputInfo/plugin.cpp'
--- plugins/Unity/InputInfo/plugin.cpp 1970-01-01 00:00:00 +0000
+++ plugins/Unity/InputInfo/plugin.cpp 2015-05-18 22:06:13 +0000
@@ -0,0 +1,32 @@
1/*
2 * Copyright 2015 Canonical Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17// Qt
18#include <QtQml/qqml.h>
19
20// self
21#include "plugin.h"
22
23// local
24#include "qdeclarativeinputdeviceinfo_p.h"
25
26void InputInfoPlugin::registerTypes(const char *uri)
27{
28 int major = 0;
29 int minor = 1;
30 qmlRegisterType<QDeclarativeInputDeviceInfo>(uri, major, minor, "InputDeviceInfo");
31 qmlRegisterType<QInputDevice>(uri, major, minor, "InputInfo");
32}
033
=== added file 'plugins/Unity/InputInfo/plugin.h'
--- plugins/Unity/InputInfo/plugin.h 1970-01-01 00:00:00 +0000
+++ plugins/Unity/InputInfo/plugin.h 2015-05-18 22:06:13 +0000
@@ -0,0 +1,30 @@
1/*
2 * Copyright 2015 Canonical Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#ifndef INPUTINFO_PLUGIN_H
18#define INPUTINFO_PLUGIN_H
19
20#include <QtQml/QQmlExtensionPlugin>
21
22class InputInfoPlugin : public QQmlExtensionPlugin
23{
24 Q_OBJECT
25 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
26public:
27 void registerTypes(const char *uri);
28};
29
30#endif // INPUTINFO_PLUGIN_H
031
=== added file 'plugins/Unity/InputInfo/qdeclarativeinputdeviceinfo.cpp'
--- plugins/Unity/InputInfo/qdeclarativeinputdeviceinfo.cpp 1970-01-01 00:00:00 +0000
+++ plugins/Unity/InputInfo/qdeclarativeinputdeviceinfo.cpp 2015-05-18 22:06:13 +0000
@@ -0,0 +1,143 @@
1/****************************************************************************
2**
3** Copyright (C) 2015 Jolla.
4** Contact: http://www.qt-project.org/legal
5**
6** This file is part of the QtSystems module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Digia. For licensing terms and
14** conditions see http://qt.digia.com/licensing. For further information
15** use the contact form at http://qt.digia.com/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 2.1 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 2.1 requirements
23** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24**
25** In addition, as a special exception, Digia gives you certain additional
26** rights. These rights are described in the Digia Qt LGPL Exception
27** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28**
29** GNU General Public License Usage
30** Alternatively, this file may be used under the terms of the GNU
31** General Public License version 3.0 as published by the Free Software
32** Foundation and appearing in the file LICENSE.GPL included in the
33** packaging of this file. Please review the following information to
34** ensure the GNU General Public License version 3.0 requirements will be
35** met: http://www.gnu.org/copyleft/gpl.html.
36**
37**
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41#include "qdeclarativeinputdeviceinfo_p.h"
42
43QDeclarativeInputDeviceInfo::QDeclarativeInputDeviceInfo(QObject *parent) :
44 QAbstractListModel(parent),
45 deviceInfo(new QInputDeviceInfo)
46{
47 connect(deviceInfo,SIGNAL(ready()),this,SLOT(updateDeviceList()));
48 connect(deviceInfo, &QInputDeviceInfo::deviceAdded,this,&QDeclarativeInputDeviceInfo::addedDevice);
49 connect(deviceInfo, &QInputDeviceInfo::deviceRemoved,this,&QDeclarativeInputDeviceInfo::removedDevice);
50}
51
52QDeclarativeInputDeviceInfo::~QDeclarativeInputDeviceInfo()
53{
54 delete deviceInfo;
55}
56
57QVariant QDeclarativeInputDeviceInfo::data(const QModelIndex &index, int role) const
58{
59 switch (role) {
60 case ServiceRole:
61 return QVariant::fromValue(static_cast<QObject *>(inputDevices.value(index.row())));
62 }
63
64 return QVariant();
65}
66
67int QDeclarativeInputDeviceInfo::rowCount(const QModelIndex &parent) const
68{
69 Q_UNUSED(parent);
70
71 return inputDevices.count();
72}
73
74int QDeclarativeInputDeviceInfo::indexOf(const QString &devicePath) const
75{
76 int idx(-1);
77 Q_FOREACH (QInputDevice *device, inputDevices) {
78 idx++;
79 if (device->devicePath() == devicePath) return idx;
80 }
81
82 return -1;
83}
84
85QInputDevice *QDeclarativeInputDeviceInfo::get(int index) const
86{
87 if (index < 0 || index > inputDevices.count())
88 return 0;
89 return inputDevices.value(index);
90}
91
92void QDeclarativeInputDeviceInfo::updateDeviceList()
93{
94 QVector <QInputDevice *> newDevices = deviceInfo->deviceList();
95
96 int numNew = newDevices.count();
97
98 for (int i = 0; i < numNew; i++) {
99 int j = inputDevices.indexOf(newDevices.value(i));
100 if (j == -1) {
101 // not found -> remove from list
102 beginInsertRows(QModelIndex(), i, i);
103 inputDevices.insert(i, newDevices.value(i));
104 endInsertRows();
105 } else if (i != j) {
106 // changed its position -> move it
107 QInputDevice* device = inputDevices.value(j);
108 beginMoveRows(QModelIndex(), j, j, QModelIndex(), i);
109 inputDevices.remove(j);
110 inputDevices.insert(i, device);
111 endMoveRows();
112 } else {
113 QModelIndex changedIndex(this->index(j, 0, QModelIndex()));
114 Q_EMIT dataChanged(changedIndex, changedIndex);
115 }
116 }
117
118 int numOld = inputDevices.count();
119 if (numOld > numNew) {
120 beginRemoveRows(QModelIndex(), numNew, numOld - 1);
121 inputDevices.remove(numNew, numOld - numNew);
122 endRemoveRows();
123 }
124}
125
126void QDeclarativeInputDeviceInfo::addedDevice(const QString &devicePath)
127{
128 updateDeviceList();
129 Q_EMIT newDevice(devicePath);
130}
131
132void QDeclarativeInputDeviceInfo::removedDevice(const QString &devicePath)
133{
134 updateDeviceList();
135 Q_EMIT deviceRemoved(devicePath);
136}
137
138QHash<int, QByteArray> QDeclarativeInputDeviceInfo::roleNames() const
139{
140 QHash<int, QByteArray> roles;
141 roles.insert(ServiceRole, "service");
142 return roles;
143}
0144
=== added file 'plugins/Unity/InputInfo/qdeclarativeinputdeviceinfo_p.h'
--- plugins/Unity/InputInfo/qdeclarativeinputdeviceinfo_p.h 1970-01-01 00:00:00 +0000
+++ plugins/Unity/InputInfo/qdeclarativeinputdeviceinfo_p.h 2015-05-18 22:06:13 +0000
@@ -0,0 +1,86 @@
1/****************************************************************************
2**
3** Copyright (C) 2015 Jolla.
4** Contact: http://www.qt-project.org/legal
5**
6** This file is part of the QtSystems module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Digia. For licensing terms and
14** conditions see http://qt.digia.com/licensing. For further information
15** use the contact form at http://qt.digia.com/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 2.1 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 2.1 requirements
23** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24**
25** In addition, as a special exception, Digia gives you certain additional
26** rights. These rights are described in the Digia Qt LGPL Exception
27** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28**
29** GNU General Public License Usage
30** Alternatively, this file may be used under the terms of the GNU
31** General Public License version 3.0 as published by the Free Software
32** Foundation and appearing in the file LICENSE.GPL included in the
33** packaging of this file. Please review the following information to
34** ensure the GNU General Public License version 3.0 requirements will be
35** met: http://www.gnu.org/copyleft/gpl.html.
36**
37**
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#ifndef QDECLARATIVEINPUTDEVICEINFO_H
43#define QDECLARATIVEINPUTDEVICEINFO_H
44
45#include <QObject>
46#include <QAbstractListModel>
47#include "qinputinfo.h"
48
49class QDeclarativeInputDeviceInfo : public QAbstractListModel
50{
51 Q_OBJECT
52 Q_DISABLE_COPY(QDeclarativeInputDeviceInfo)
53
54public:
55 enum ItemRoles {
56 ServiceRole = Qt::UserRole + 1
57 };
58
59 explicit QDeclarativeInputDeviceInfo(QObject *parent = 0);
60 virtual ~QDeclarativeInputDeviceInfo();
61
62 QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
63 int rowCount(const QModelIndex &parent = QModelIndex()) const;
64
65 QHash<int, QByteArray> roleNames() const;
66
67 Q_INVOKABLE int indexOf(const QString &devicePath) const;
68
69 Q_INVOKABLE QInputDevice *get(int index) const;
70
71Q_SIGNALS:
72 void newDevice(const QString &devicePath);
73 void deviceRemoved(const QString &devicePath);
74
75public Q_SLOTS:
76 void updateDeviceList();
77private:
78 QInputDeviceInfo *deviceInfo;
79 QVector<QInputDevice *> inputDevices;
80private Q_SLOTS:
81 void addedDevice(const QString &);
82 void removedDevice(const QString &path);
83
84};
85
86#endif // QDECLARATIVEINPUTDEVICEINFO_H
087
=== added file 'plugins/Unity/InputInfo/qinputinfo.cpp'
--- plugins/Unity/InputInfo/qinputinfo.cpp 1970-01-01 00:00:00 +0000
+++ plugins/Unity/InputInfo/qinputinfo.cpp 2015-05-18 22:06:13 +0000
@@ -0,0 +1,159 @@
1/****************************************************************************
2**
3** Copyright (C) 2014 Canonical, Ltd. and/or its subsidiary(-ies).
4** Contact: http://www.qt-project.org/legal
5**
6** This file is part of the QtSystems module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Digia. For licensing terms and
14** conditions see http://qt.digia.com/licensing. For further information
15** use the contact form at http://qt.digia.com/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 2.1 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 2.1 requirements
23** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24**
25** In addition, as a special exception, Digia gives you certain additional
26** rights. These rights are described in the Digia Qt LGPL Exception
27** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28**
29** GNU General Public License Usage
30** Alternatively, this file may be used under the terms of the GNU
31** General Public License version 3.0 as published by the Free Software
32** Foundation and appearing in the file LICENSE.GPL included in the
33** packaging of this file. Please review the following information to
34** ensure the GNU General Public License version 3.0 requirements will be
35** met: http://www.gnu.org/copyleft/gpl.html.
36**
37**
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qinputinfo.h"
43
44#if defined(Q_OS_LINUX)
45#include "linux/qinputdeviceinfo_linux_p.h"
46#endif
47
48QT_BEGIN_NAMESPACE
49
50
51QInputDevicePrivate::QInputDevicePrivate(QObject *parent) :
52 QObject(parent),
53 types(QInputDeviceInfo::Unknown)
54{
55}
56
57QInputDevice::QInputDevice(QObject *parent) :
58 QObject(parent),
59 d_ptr(new QInputDevicePrivate(this))
60{
61}
62
63QString QInputDevice::name() const
64{
65 return d_ptr->name;
66}
67
68void QInputDevice::setName(const QString &name)
69{
70 d_ptr->name = name;
71}
72
73QString QInputDevice::devicePath() const
74{
75 return d_ptr->devicePath;
76}
77
78void QInputDevice::setDevicePath(const QString &path)
79{
80 d_ptr->devicePath = path;
81}
82
83QList <int> QInputDevice::buttons() const
84{
85 return d_ptr->buttons;
86}
87
88void QInputDevice::addButton(int buttonCode)
89{
90 d_ptr->buttons.append(buttonCode);
91}
92
93QList <int> QInputDevice::switches() const
94{
95 return d_ptr->switches;
96}
97
98void QInputDevice::addSwitch(int switchCode)
99{
100 d_ptr->switches.append(switchCode);
101}
102
103QList <int> QInputDevice::relativeAxis() const
104{
105 return d_ptr->relativeAxis;
106}
107
108void QInputDevice::addRelativeAxis(int axisCode)
109{
110 d_ptr->relativeAxis.append(axisCode);
111}
112
113QList <int> QInputDevice::absoluteAxis() const
114{
115 return d_ptr->absoluteAxis;
116}
117
118void QInputDevice::addAbsoluteAxis(int axisCode)
119{
120 d_ptr->absoluteAxis.append(axisCode);
121}
122
123QInputDeviceInfo::InputTypes QInputDevice::types()
124{
125 return d_ptr->types;
126}
127
128void QInputDevice::setTypes(QInputDeviceInfo::InputTypes types)
129{
130 d_ptr->types = types;
131}
132
133
134QInputDeviceInfo::QInputDeviceInfo(QObject *parent) :
135 QObject(parent),
136 d_ptr(new QInputDeviceInfoPrivate(this))
137{
138 connect(d_ptr, &QInputDeviceInfoPrivate::newDevice,this,&QInputDeviceInfo::addedDevice);
139 connect(d_ptr, &QInputDeviceInfoPrivate::deviceRemoved,this,&QInputDeviceInfo::deviceRemoved);
140
141 connect(d_ptr,SIGNAL(ready()),this,SIGNAL(ready()));
142}
143
144QVector <QInputDevice *> QInputDeviceInfo::deviceList()
145{
146 return d_ptr->deviceList;
147}
148
149QMap <QString, QInputDevice *> QInputDeviceInfo::deviceMap()
150{
151 return d_ptr->deviceMap;
152}
153
154void QInputDeviceInfo::addedDevice(const QString & devicePath)
155{
156 Q_EMIT deviceAdded(devicePath);
157}
158
159QT_END_NAMESPACE
0160
=== added file 'plugins/Unity/InputInfo/qinputinfo.h'
--- plugins/Unity/InputInfo/qinputinfo.h 1970-01-01 00:00:00 +0000
+++ plugins/Unity/InputInfo/qinputinfo.h 2015-05-18 22:06:13 +0000
@@ -0,0 +1,143 @@
1/****************************************************************************
2**
3** Copyright (C) 2014 Canonical, Ltd. and/or its subsidiary(-ies).
4** Contact: http://www.qt-project.org/legal
5**
6** This file is part of the QtSystems module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Digia. For licensing terms and
14** conditions see http://qt.digia.com/licensing. For further information
15** use the contact form at http://qt.digia.com/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 2.1 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 2.1 requirements
23** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24**
25** In addition, as a special exception, Digia gives you certain additional
26** rights. These rights are described in the Digia Qt LGPL Exception
27** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28**
29** GNU General Public License Usage
30** Alternatively, this file may be used under the terms of the GNU
31** General Public License version 3.0 as published by the Free Software
32** Foundation and appearing in the file LICENSE.GPL included in the
33** packaging of this file. Please review the following information to
34** ensure the GNU General Public License version 3.0 requirements will be
35** met: http://www.gnu.org/copyleft/gpl.html.
36**
37**
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#ifndef QINPUTINFO_H
43#define QINPUTINFO_H
44
45#include <QObject>
46#include <QVector>
47#include <QMap>
48#include <QSocketNotifier>
49#include <QDebug>
50
51class QInputDeviceInfoPrivate;
52class QInputDevicePrivate;
53class QInputDevice;
54
55class QInputDeviceInfoPrivate;
56class QInputDeviceInfo : public QObject
57{
58 Q_OBJECT
59 Q_PROPERTY(int deviceCount READ deviceCount)
60public:
61
62 enum InputType {
63 Unknown = 0,
64 Button = 1,
65 Mouse = 2,
66 TouchPad = 4,
67 TouchScreen = 8,
68 Keyboard = 16,
69 Switch = 32
70 };
71 Q_ENUMS(InputType)
72 Q_FLAGS(InputTypes)
73 Q_DECLARE_FLAGS(InputTypes, InputType)
74
75 explicit QInputDeviceInfo(QObject *parent = 0);
76
77 Q_INVOKABLE QVector <QInputDevice *> deviceList();
78
79 Q_INVOKABLE QMap <QString, QInputDevice *> deviceMap();
80 int deviceCount() { return deviceList().count(); }
81Q_SIGNALS:
82
83 void deviceAdded(const QString & devicePath);
84 void deviceRemoved(const QString & devicePath);
85
86 void ready();
87
88public Q_SLOTS:
89 void addedDevice(const QString & devicePath);
90
91private:
92 Q_DISABLE_COPY(QInputDeviceInfo)
93#if !defined(QT_SIMULATOR)
94 QInputDeviceInfoPrivate *const d_ptr;
95 Q_DECLARE_PRIVATE(QInputDeviceInfo)
96#endif
97};
98
99class QInputDevice : public QObject
100{
101 friend class QInputDeviceInfoPrivate;
102 Q_OBJECT
103 Q_ENUMS(InputType)
104 Q_FLAGS(InputTypes)
105 Q_PROPERTY(QString name READ name NOTIFY nameChanged)
106 Q_PROPERTY(QString devicePath READ devicePath NOTIFY devicePathChanged)
107 Q_PROPERTY(QList <int> buttons READ buttons NOTIFY buttonsChanged)
108 Q_PROPERTY(QList <int> switches READ switches NOTIFY switchesChanged)
109 Q_PROPERTY(QList <int> relativeAxis READ relativeAxis NOTIFY relativeAxisChanged)
110 Q_PROPERTY(QList <int> absoluteAxis READ absoluteAxis NOTIFY absoluteAxisChanged)
111 Q_PROPERTY(QInputDeviceInfo::InputTypes types READ types NOTIFY typesChanged)
112
113public:
114 explicit QInputDevice(QObject *parent = 0);
115
116 QString name() const;
117 QString devicePath() const;
118 QList <int> buttons() const; //keys event code
119 QList <int> switches() const;
120 QList <int> relativeAxis() const;
121 QList <int> absoluteAxis() const;
122
123 QInputDeviceInfo::InputTypes types();
124Q_SIGNALS:
125 void nameChanged();
126 void devicePathChanged();
127 void buttonsChanged();
128 void switchesChanged();
129 void relativeAxisChanged();
130 void absoluteAxisChanged();
131 void typesChanged();
132private:
133 QInputDevicePrivate *d_ptr;
134 void setName(const QString &);
135 void setDevicePath(const QString &);
136 void addButton(int);
137 void addSwitch(int);
138 void addRelativeAxis(int);
139 void addAbsoluteAxis(int);
140 void setTypes(QInputDeviceInfo::InputTypes);
141};
142
143#endif // QINPUTINFO_H
0144
=== added file 'plugins/Unity/InputInfo/qmldir'
--- plugins/Unity/InputInfo/qmldir 1970-01-01 00:00:00 +0000
+++ plugins/Unity/InputInfo/qmldir 2015-05-18 22:06:13 +0000
@@ -0,0 +1,3 @@
1module Unity.InputInfo
2plugin InputInfo
3typeinfo InputInfo.qmltypes
04
=== modified file 'plugins/Unity/Launcher/CMakeLists.txt'
--- plugins/Unity/Launcher/CMakeLists.txt 2015-04-13 09:33:28 +0000
+++ plugins/Unity/Launcher/CMakeLists.txt 2015-05-18 22:06:13 +0000
@@ -1,5 +1,5 @@
1pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=6)1pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=6)
2pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=5)2pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=6)
3pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)3pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)
44
5add_definitions(-DSM_BUSNAME=systemBus)5add_definitions(-DSM_BUSNAME=systemBus)
66
=== modified file 'plugins/Utils/CMakeLists.txt'
--- plugins/Utils/CMakeLists.txt 2015-04-22 10:40:54 +0000
+++ plugins/Utils/CMakeLists.txt 2015-05-18 22:06:13 +0000
@@ -18,6 +18,7 @@
18 Timer.cpp18 Timer.cpp
19 unitymenumodelpaths.cpp19 unitymenumodelpaths.cpp
20 windowkeysfilter.cpp20 windowkeysfilter.cpp
21 windowscreenshotprovider.cpp
21 easingcurve.cpp22 easingcurve.cpp
22 windowstatestorage.cpp23 windowstatestorage.cpp
23 plugin.cpp24 plugin.cpp
2425
=== modified file 'plugins/Utils/plugin.cpp'
--- plugins/Utils/plugin.cpp 2015-04-22 10:40:54 +0000
+++ plugins/Utils/plugin.cpp 2015-05-18 22:06:13 +0000
@@ -23,6 +23,7 @@
23#include "plugin.h"23#include "plugin.h"
2424
25// local25// local
26#include "easingcurve.h"
26#include "HomeKeyWatcher.h"27#include "HomeKeyWatcher.h"
27#include "inputwatcher.h"28#include "inputwatcher.h"
28#include "qlimitproxymodelqml.h"29#include "qlimitproxymodelqml.h"
@@ -31,7 +32,7 @@
31#include "timeformatter.h"32#include "timeformatter.h"
32#include "unitymenumodelpaths.h"33#include "unitymenumodelpaths.h"
33#include "windowkeysfilter.h"34#include "windowkeysfilter.h"
34#include "easingcurve.h"35#include "windowscreenshotprovider.h"
35#include "windowstatestorage.h"36#include "windowstatestorage.h"
36#include "constants.h"37#include "constants.h"
3738
@@ -70,4 +71,6 @@
70void UtilsPlugin::initializeEngine(QQmlEngine *engine, const char *uri)71void UtilsPlugin::initializeEngine(QQmlEngine *engine, const char *uri)
71{72{
72 QQmlExtensionPlugin::initializeEngine(engine, uri);73 QQmlExtensionPlugin::initializeEngine(engine, uri);
74
75 engine->addImageProvider(QLatin1String("window"), new WindowScreenshotProvider);
73}76}
7477
=== added file 'plugins/Utils/windowscreenshotprovider.cpp'
--- plugins/Utils/windowscreenshotprovider.cpp 1970-01-01 00:00:00 +0000
+++ plugins/Utils/windowscreenshotprovider.cpp 2015-05-18 22:06:13 +0000
@@ -0,0 +1,59 @@
1/*
2 * Copyright (C) 2015 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include "windowscreenshotprovider.h"
18
19#include <QGuiApplication>
20#include <QQuickWindow>
21
22WindowScreenshotProvider::WindowScreenshotProvider()
23 : QQuickImageProvider(QQmlImageProviderBase::Image, 0)
24{
25}
26
27// A very simple implementation where we assume that there's only one window and that it's a
28// QQuickWindow. Thus the id parameter is irrelevant.
29//
30// Idea: Make the id contain the objectName of the QQuickWindow once we care about a multi-display
31// compositor?
32// Strictly speaking that could be the actual QWindow::winId(), but that's mostly a
33// meaningless arbitrary number.
34QImage WindowScreenshotProvider::requestImage(const QString &id, QSize *size, const QSize &requestedSize)
35{
36 Q_UNUSED(id);
37 Q_UNUSED(requestedSize);
38
39 QWindowList windows = QGuiApplication::topLevelWindows();
40
41 if (windows.count() != 1) {
42 size->rwidth() = 0;
43 size->rheight() = 0;
44 return QImage();
45 }
46
47 QQuickWindow *quickWindow = qobject_cast<QQuickWindow *>(windows[0]);
48
49 if (!quickWindow) {
50 size->rwidth() = 0;
51 size->rheight() = 0;
52 return QImage();
53 }
54
55 QImage image = quickWindow->grabWindow();
56 size->rwidth() = image.width();
57 size->rheight() = image.height();
58 return image;
59}
060
=== added file 'plugins/Utils/windowscreenshotprovider.h'
--- plugins/Utils/windowscreenshotprovider.h 1970-01-01 00:00:00 +0000
+++ plugins/Utils/windowscreenshotprovider.h 2015-05-18 22:06:13 +0000
@@ -0,0 +1,31 @@
1/*
2 * Copyright (C) 2015 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#ifndef WINDOW_SCREENSHOT_PROVIDER_H_
18#define WINDOW_SCREENSHOT_PROVIDER_H_
19
20#include <QQuickImageProvider>
21
22class WindowScreenshotProvider : public QQuickImageProvider
23{
24public:
25 WindowScreenshotProvider();
26
27 // id is ignored for now
28 QImage requestImage(const QString &id, QSize *size, const QSize &requestedSize) override;
29};
30
31#endif // WINDOW_SCREENSHOT_PROVIDER_H_
032
=== modified file 'qml/CMakeLists.txt'
--- qml/CMakeLists.txt 2014-12-16 16:49:49 +0000
+++ qml/CMakeLists.txt 2015-05-18 22:06:13 +0000
@@ -13,6 +13,7 @@
13 Notifications13 Notifications
14 Panel14 Panel
15 Stages15 Stages
16 Rotation
16 Tutorial17 Tutorial
17 Wizard18 Wizard
18 )19 )
1920
=== added file 'qml/Components/WindowScreenshot.qml'
--- qml/Components/WindowScreenshot.qml 1970-01-01 00:00:00 +0000
+++ qml/Components/WindowScreenshot.qml 2015-05-18 22:06:13 +0000
@@ -0,0 +1,35 @@
1/*
2 * Copyright (C) 2015 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17import QtQuick 2.2
18
19Item {
20 id: root
21
22 function take() {
23 var timeNow = new Date().getTime();
24 image.source = "image://window/" + timeNow;
25 }
26
27 // Unload the image to free up memory
28 function discard() {
29 image.source = "";
30 }
31
32 Image {
33 id: image
34 }
35}
036
=== modified file 'qml/Dash/DashApplication.qml'
--- qml/Dash/DashApplication.qml 2014-09-18 21:22:37 +0000
+++ qml/Dash/DashApplication.qml 2015-05-18 22:06:13 +0000
@@ -1,5 +1,5 @@
1/*1/*
2 * Copyright (C) 2014 Canonical, Ltd.2 * Copyright (C) 2014,2015 Canonical, Ltd.
3 *3 *
4 * This program is free software; you can redistribute it and/or modify4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by5 * it under the terms of the GNU General Public License as published by
@@ -19,8 +19,8 @@
19import Ubuntu.Thumbnailer 0.1 // Register support for image://thumbnailer/ and image://albumart/19import Ubuntu.Thumbnailer 0.1 // Register support for image://thumbnailer/ and image://albumart/
2020
21MainView {21MainView {
22 width: applicationArguments.hasGeometry() ? applicationArguments.width() : units.gu(40)22 implicitWidth: units.gu(40)
23 height: applicationArguments.hasGeometry() ? applicationArguments.height() : units.gu(68)23 implicitHeight: units.gu(68)
2424
25 useDeprecatedToolbar: false25 useDeprecatedToolbar: false
2626
2727
=== added file 'qml/Dash/graphics/phone/screenshots/gmail-webapp.svg'
--- qml/Dash/graphics/phone/screenshots/gmail-webapp.svg 1970-01-01 00:00:00 +0000
+++ qml/Dash/graphics/phone/screenshots/gmail-webapp.svg 2015-05-18 22:06:13 +0000
@@ -0,0 +1,343 @@
1<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2<!-- Created with Inkscape (http://www.inkscape.org/) -->
3
4<svg
5 xmlns:dc="http://purl.org/dc/elements/1.1/"
6 xmlns:cc="http://creativecommons.org/ns#"
7 xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
8 xmlns:svg="http://www.w3.org/2000/svg"
9 xmlns="http://www.w3.org/2000/svg"
10 xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
11 xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
12 width="768"
13 height="1280"
14 id="svg2"
15 version="1.1"
16 inkscape:version="0.48.5 r10040"
17 sodipodi:docname="gmail-webapp.svg">
18 <defs
19 id="defs4" />
20 <sodipodi:namedview
21 id="base"
22 pagecolor="#ffffff"
23 bordercolor="#666666"
24 borderopacity="1.0"
25 inkscape:pageopacity="0.0"
26 inkscape:pageshadow="2"
27 inkscape:zoom="0.49497475"
28 inkscape:cx="117.33439"
29 inkscape:cy="668.80479"
30 inkscape:document-units="px"
31 inkscape:current-layer="layer1"
32 showgrid="false"
33 inkscape:window-width="1920"
34 inkscape:window-height="1056"
35 inkscape:window-x="0"
36 inkscape:window-y="24"
37 inkscape:window-maximized="1" />
38 <metadata
39 id="metadata7">
40 <rdf:RDF>
41 <cc:Work
42 rdf:about="">
43 <dc:format>image/svg+xml</dc:format>
44 <dc:type
45 rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
46 <dc:title></dc:title>
47 </cc:Work>
48 </rdf:RDF>
49 </metadata>
50 <g
51 inkscape:label="Layer 1"
52 inkscape:groupmode="layer"
53 id="layer1"
54 transform="translate(0,227.63782)">
55 <rect
56 style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.69999999000000002;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
57 id="rect2985"
58 width="769.73627"
59 height="1276.8328"
60 x="-2.0203052"
61 y="3.1671834"
62 transform="translate(0,-227.63782)" />
63 <rect
64 style="fill:#e6e6e6;fill-opacity:1;stroke:none;stroke-width:4;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
65 id="rect3797"
66 width="773.77686"
67 height="129.29953"
68 x="-6.0609155"
69 y="-0.87342685"
70 transform="translate(0,-227.63782)" />
71 <text
72 xml:space="preserve"
73 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"
74 x="20.203053"
75 y="-139.61781"
76 id="text3755"
77 sodipodi:linespacing="125%"><tspan
78 sodipodi:role="line"
79 id="tspan3757"
80 x="20.203053"
81 y="-139.61781">GMail</tspan></text>
82 <text
83 xml:space="preserve"
84 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"
85 x="14.142137"
86 y="-28.501045"
87 id="text3759"
88 sodipodi:linespacing="125%"><tspan
89 sodipodi:role="line"
90 id="tspan3761"
91 x="14.142137"
92 y="-28.501045">Inbox</tspan></text>
93 <path
94 sodipodi:type="arc"
95 style="fill:#8effff;fill-opacity:1;stroke:#000000;stroke-width:0.69999999;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
96 id="path3765"
97 sodipodi:cx="107.07617"
98 sodipodi:cy="337.52768"
99 sodipodi:rx="64.649765"
100 sodipodi:ry="61.619305"
101 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"
102 transform="translate(-28.284271,-251.88148)" />
103 <path
104 style="fill:none;stroke:#000000;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
105 d="m 14.142136,237.52257 729.330134,0"
106 id="path3769"
107 inkscape:connector-curvature="0"
108 transform="translate(0,-227.63782)" />
109 <text
110 xml:space="preserve"
111 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"
112 x="167.68533"
113 y="78.575127"
114 id="text3771"
115 sodipodi:linespacing="125%"><tspan
116 sodipodi:role="line"
117 id="tspan3773"
118 x="167.68533"
119 y="78.575127">Lorem ipsum</tspan></text>
120 <text
121 xml:space="preserve"
122 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"
123 x="167.68532"
124 y="131.10306"
125 id="text3775"
126 sodipodi:linespacing="125%"><tspan
127 sodipodi:role="line"
128 id="tspan3777"
129 x="167.68532"
130 y="131.10306"
131 style="font-size:48px;fill:#b3b3b3">bla bla bla bla bla bla bla ...</tspan></text>
132 <path
133 style="fill:none;stroke:#000000;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
134 d="m 13.13199,165.44825 729.33013,0"
135 id="path3769-2"
136 inkscape:connector-curvature="0" />
137 <path
138 sodipodi:type="arc"
139 style="fill:#8eff58;fill-opacity:1;stroke:#000000;stroke-width:0.69999999000000002;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
140 id="path3765-3"
141 sodipodi:cx="107.07617"
142 sodipodi:cy="337.52768"
143 sodipodi:rx="64.649765"
144 sodipodi:ry="61.619305"
145 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"
146 transform="translate(-26.263969,-93.102383)" />
147 <text
148 xml:space="preserve"
149 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"
150 x="169.70564"
151 y="237.35422"
152 id="text3771-9"
153 sodipodi:linespacing="125%"><tspan
154 sodipodi:role="line"
155 id="tspan3773-7"
156 x="169.70564"
157 y="237.35422">Lorem ipsum</tspan></text>
158 <text
159 xml:space="preserve"
160 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"
161 x="169.70561"
162 y="289.88217"
163 id="text3775-1"
164 sodipodi:linespacing="125%"><tspan
165 sodipodi:role="line"
166 id="tspan3777-1"
167 x="169.70561"
168 y="289.88217"
169 style="font-size:48px;fill:#b3b3b3">bla bla bla bla bla bla bla ...</tspan></text>
170 <path
171 style="fill:none;stroke:#000000;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
172 d="m 15.152292,324.22735 729.330128,0"
173 id="path3769-2-6"
174 inkscape:connector-curvature="0" />
175 <path
176 sodipodi:type="arc"
177 style="fill:#8effff;fill-opacity:1;stroke:#000000;stroke-width:0.69999999;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
178 id="path3765-7"
179 sodipodi:cx="107.07617"
180 sodipodi:cy="337.52768"
181 sodipodi:rx="64.649765"
182 sodipodi:ry="61.619305"
183 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"
184 transform="translate(-28.284274,64.481414)" />
185 <text
186 xml:space="preserve"
187 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"
188 x="167.68533"
189 y="394.93799"
190 id="text3771-92"
191 sodipodi:linespacing="125%"><tspan
192 sodipodi:role="line"
193 id="tspan3773-0"
194 x="167.68533"
195 y="394.93799">Lorem ipsum</tspan></text>
196 <text
197 xml:space="preserve"
198 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"
199 x="167.68532"
200 y="447.46594"
201 id="text3775-9"
202 sodipodi:linespacing="125%"><tspan
203 sodipodi:role="line"
204 id="tspan3777-8"
205 x="167.68532"
206 y="447.46594"
207 style="font-size:48px;fill:#b3b3b3">bla bla bla bla bla bla bla ...</tspan></text>
208 <path
209 style="fill:none;stroke:#000000;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
210 d="m 13.131986,481.81114 729.330124,0"
211 id="path3769-2-3"
212 inkscape:connector-curvature="0" />
213 <path
214 sodipodi:type="arc"
215 style="fill:#8ea2ff;fill-opacity:1;stroke:#000000;stroke-width:0.69999999000000002;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
216 id="path3765-2"
217 sodipodi:cx="107.07617"
218 sodipodi:cy="337.52768"
219 sodipodi:rx="64.649765"
220 sodipodi:ry="61.619305"
221 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"
222 transform="translate(-26.263969,226.10582)" />
223 <text
224 xml:space="preserve"
225 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"
226 x="169.70564"
227 y="556.56238"
228 id="text3771-1"
229 sodipodi:linespacing="125%"><tspan
230 sodipodi:role="line"
231 id="tspan3773-1"
232 x="169.70564"
233 y="556.56238">Lorem ipsum</tspan></text>
234 <text
235 xml:space="preserve"
236 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"
237 x="169.70563"
238 y="609.09033"
239 id="text3775-8"
240 sodipodi:linespacing="125%"><tspan
241 sodipodi:role="line"
242 id="tspan3777-85"
243 x="169.70563"
244 y="609.09033"
245 style="font-size:48px;fill:#b3b3b3">bla bla bla bla bla bla bla ...</tspan></text>
246 <path
247 style="fill:none;stroke:#000000;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
248 d="m 15.152292,643.43555 729.330128,0"
249 id="path3769-2-1"
250 inkscape:connector-curvature="0" />
251 <path
252 sodipodi:type="arc"
253 style="fill:#8effff;fill-opacity:1;stroke:#000000;stroke-width:0.69999999;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
254 id="path3765-8"
255 sodipodi:cx="107.07617"
256 sodipodi:cy="337.52768"
257 sodipodi:rx="64.649765"
258 sodipodi:ry="61.619305"
259 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"
260 transform="translate(-24.243664,391.77084)" />
261 <text
262 xml:space="preserve"
263 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"
264 x="171.72594"
265 y="722.22742"
266 id="text3771-7"
267 sodipodi:linespacing="125%"><tspan
268 sodipodi:role="line"
269 id="tspan3773-6"
270 x="171.72594"
271 y="722.22742">Lorem ipsum</tspan></text>
272 <text
273 xml:space="preserve"
274 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"
275 x="171.72592"
276 y="774.75537"
277 id="text3775-5"
278 sodipodi:linespacing="125%"><tspan
279 sodipodi:role="line"
280 id="tspan3777-2"
281 x="171.72592"
282 y="774.75537"
283 style="font-size:48px;fill:#b3b3b3">bla bla bla bla bla bla bla ...</tspan></text>
284 <path
285 style="fill:none;stroke:#000000;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
286 d="m 17.172597,809.10057 729.330133,0"
287 id="path3769-2-13"
288 inkscape:connector-curvature="0" />
289 <path
290 sodipodi:type="arc"
291 style="fill:#e44738;fill-opacity:1;stroke:#000000;stroke-width:0.69999999000000002;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
292 id="path3765-9"
293 sodipodi:cx="107.07617"
294 sodipodi:cy="337.52768"
295 sodipodi:rx="64.649765"
296 sodipodi:ry="61.619305"
297 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"
298 transform="translate(-24.243664,557.43585)" />
299 <text
300 xml:space="preserve"
301 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"
302 x="171.72594"
303 y="887.89246"
304 id="text3771-2"
305 sodipodi:linespacing="125%"><tspan
306 sodipodi:role="line"
307 id="tspan3773-8"
308 x="171.72594"
309 y="887.89246">Lorem ipsum</tspan></text>
310 <text
311 xml:space="preserve"
312 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"
313 x="171.72592"
314 y="940.42041"
315 id="text3775-3"
316 sodipodi:linespacing="125%"><tspan
317 sodipodi:role="line"
318 id="tspan3777-7"
319 x="171.72592"
320 y="940.42041"
321 style="font-size:48px;fill:#b3b3b3">bla bla bla bla bla bla bla ...</tspan></text>
322 <path
323 style="fill:none;stroke:#000000;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
324 d="m 17.172597,974.76558 729.330123,0"
325 id="path3769-2-9"
326 inkscape:connector-curvature="0" />
327 <path
328 sodipodi:type="arc"
329 style="fill:none;stroke:#000000;stroke-width:8;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
330 id="path3929"
331 sodipodi:cx="590.93921"
332 sodipodi:cy="-119.06127"
333 sodipodi:rx="33.335033"
334 sodipodi:ry="33.335033"
335 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"
336 transform="matrix(0.85096826,0,0,0.85096826,175.43863,-68.81729)" />
337 <path
338 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"
339 d="m 692.92249,-145.20602 20.63059,24.06901 12.03451,-13.75372 -20.63059,-17.19215"
340 id="path3931"
341 inkscape:connector-curvature="0" />
342 </g>
343</svg>
0344
=== removed file 'qml/Dash/graphics/phone/screenshots/settings@12.png'
1Binary 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 differ345Binary 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
=== added file 'qml/Dash/graphics/phone/screenshots/ubuntu-weather-app.svg'
--- qml/Dash/graphics/phone/screenshots/ubuntu-weather-app.svg 1970-01-01 00:00:00 +0000
+++ qml/Dash/graphics/phone/screenshots/ubuntu-weather-app.svg 2015-05-18 22:06:13 +0000
@@ -0,0 +1,201 @@
1<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2<!-- Created with Inkscape (http://www.inkscape.org/) -->
3
4<svg
5 xmlns:dc="http://purl.org/dc/elements/1.1/"
6 xmlns:cc="http://creativecommons.org/ns#"
7 xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
8 xmlns:svg="http://www.w3.org/2000/svg"
9 xmlns="http://www.w3.org/2000/svg"
10 xmlns:xlink="http://www.w3.org/1999/xlink"
11 xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
12 xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
13 width="829"
14 height="480"
15 id="svg2740"
16 sodipodi:version="0.32"
17 inkscape:version="0.48.5 r10040"
18 version="1.0"
19 sodipodi:docname="ubuntu-weather-app.svg"
20 inkscape:output_extension="org.inkscape.output.svg.inkscape">
21 <defs
22 id="defs2742">
23 <linearGradient
24 id="linearGradient3824">
25 <stop
26 style="stop-color:#e6e6e6;stop-opacity:1;"
27 offset="0"
28 id="stop3826" />
29 <stop
30 style="stop-color:#23abff;stop-opacity:1;"
31 offset="1"
32 id="stop3828" />
33 </linearGradient>
34 <linearGradient
35 inkscape:collect="always"
36 xlink:href="#linearGradient3824"
37 id="linearGradient3830"
38 x1="348.55862"
39 y1="343.23914"
40 x2="348.55862"
41 y2="-17.422215"
42 gradientUnits="userSpaceOnUse" />
43 </defs>
44 <sodipodi:namedview
45 id="base"
46 pagecolor="#ffffff"
47 bordercolor="#666666"
48 borderopacity="1.0"
49 gridtolerance="10000"
50 guidetolerance="10"
51 objecttolerance="10"
52 inkscape:pageopacity="0.0"
53 inkscape:pageshadow="2"
54 inkscape:zoom="0.82625984"
55 inkscape:cx="331.28234"
56 inkscape:cy="125.54212"
57 inkscape:document-units="px"
58 inkscape:current-layer="layer1"
59 showgrid="false"
60 inkscape:window-width="1145"
61 inkscape:window-height="847"
62 inkscape:window-x="268"
63 inkscape:window-y="63"
64 inkscape:window-maximized="0" />
65 <metadata
66 id="metadata2745">
67 <rdf:RDF>
68 <cc:Work
69 rdf:about="">
70 <dc:format>image/svg+xml</dc:format>
71 <dc:type
72 rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
73 </cc:Work>
74 </rdf:RDF>
75 </metadata>
76 <g
77 inkscape:label="Layer 1"
78 inkscape:groupmode="layer"
79 id="layer1"
80 transform="translate(-321.13452,-104.68346)">
81 <rect
82 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"
83 id="rect2990"
84 width="832.66785"
85 height="480.47839"
86 x="-1.210273"
87 y="0.73188055"
88 transform="translate(321.13452,104.68346)" />
89 <path
90 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"
91 id="path11949"
92 inkscape:flatsided="false"
93 inkscape:randomized="-0.092"
94 inkscape:rounded="0.1"
95 sodipodi:arg1="0.79570711"
96 sodipodi:arg2="1.144773"
97 sodipodi:cx="275.15002"
98 sodipodi:cy="88.090233"
99 sodipodi:r1="57.019234"
100 sodipodi:r2="32.818508"
101 sodipodi:sides="9"
102 sodipodi:type="star"
103 style="fill:#f5ff12;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.2;marker:none;visibility:visible;display:inline;overflow:visible"
104 transform="matrix(2.527571,0,0,2.527571,85.214779,60.619097)" />
105 <path
106 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"
107 id="path11951"
108 sodipodi:cx="154.61601"
109 sodipodi:cy="77.283737"
110 sodipodi:rx="39.900909"
111 sodipodi:ry="37.407101"
112 sodipodi:type="arc"
113 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"
114 transform="matrix(2.4568175,0,0,2.1990879,404.91256,120.05076)" />
115 <path
116 transform="matrix(3.2663208,0,0,3.4016021,515.92101,-254.59331)"
117 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"
118 sodipodi:type="inkscape:offset"
119 inkscape:radius="0"
120 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 "
121 id="path11953"
122 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" />
123 <path
124 inkscape:connector-curvature="0"
125 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"
126 id="path11963"
127 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" />
128 <path
129 inkscape:connector-curvature="0"
130 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"
131 sodipodi:nodetypes="cccc"
132 id="path11965"
133 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" />
134 <path
135 inkscape:connector-curvature="0"
136 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"
137 sodipodi:nodetypes="cccc"
138 id="path11967"
139 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" />
140 <text
141 xml:space="preserve"
142 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"
143 x="68.985565"
144 y="92.712631"
145 id="text2992"
146 sodipodi:linespacing="125%"
147 transform="translate(321.13452,104.68346)"><tspan
148 sodipodi:role="line"
149 id="tspan2994"
150 x="68.985565"
151 y="92.712631" /></text>
152 <text
153 xml:space="preserve"
154 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"
155 x="-202.1156"
156 y="155.64684"
157 id="text2996"
158 sodipodi:linespacing="125%"
159 transform="translate(321.13452,104.68346)"><tspan
160 sodipodi:role="line"
161 id="tspan2998"
162 x="-202.1156"
163 y="155.64684" /></text>
164 <text
165 xml:space="preserve"
166 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"
167 x="342.91943"
168 y="155.03653"
169 id="text3000"
170 sodipodi:linespacing="125%"><tspan
171 sodipodi:role="line"
172 id="tspan3002"
173 x="342.91943"
174 y="155.03653"
175 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>
176 <text
177 xml:space="preserve"
178 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"
179 x="460.31592"
180 y="358.3624"
181 id="text3004"
182 sodipodi:linespacing="125%"><tspan
183 sodipodi:role="line"
184 id="tspan3006"
185 x="460.31592"
186 y="358.3624"
187 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>
188 <text
189 xml:space="preserve"
190 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"
191 x="460.19751"
192 y="412.14325"
193 id="text3004-0"
194 sodipodi:linespacing="125%"><tspan
195 sodipodi:role="line"
196 id="tspan3006-4"
197 x="460.19751"
198 y="412.14325"
199 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>
200 </g>
201</svg>
0202
=== added file 'qml/DeviceConfiguration.qml'
--- qml/DeviceConfiguration.qml 1970-01-01 00:00:00 +0000
+++ qml/DeviceConfiguration.qml 2015-05-18 22:06:13 +0000
@@ -0,0 +1,81 @@
1/*
2 * Copyright (C) 2015 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17import QtQuick 2.0
18
19StateGroup {
20 id: root
21
22 readonly property int useNativeOrientation: -1
23
24 property int primaryOrientation: useNativeOrientation
25
26 property int supportedOrientations: Qt.PortraitOrientation
27 | Qt.InvertedPortraitOrientation
28 | Qt.LandscapeOrientation
29 | Qt.InvertedLandscapeOrientation
30
31 // Supported values so far:
32 // "phone", "tablet" or "desktop"
33 property string category: "phone"
34
35
36 property alias name: root.state
37
38 states: [
39 State {
40 name: "mako"
41 PropertyChanges {
42 target: root
43 supportedOrientations: Qt.PortraitOrientation
44 | Qt.LandscapeOrientation
45 | Qt.InvertedLandscapeOrientation
46 }
47 },
48 State {
49 name: "krillin"
50 PropertyChanges {
51 target: root
52 supportedOrientations: Qt.PortraitOrientation
53 | Qt.LandscapeOrientation
54 | Qt.InvertedLandscapeOrientation
55 }
56 },
57 State {
58 name: "manta"
59 PropertyChanges {
60 target: root
61 category: "tablet"
62 }
63 },
64 State {
65 name: "flo"
66 PropertyChanges {
67 target: root
68 primaryOrientation: Qt.InvertedLandscapeOrientation
69 category: "tablet"
70 }
71 },
72 State {
73 name: "desktop"
74 PropertyChanges {
75 target: root
76 category: "desktop"
77 }
78 }
79 ]
80
81}
082
=== modified file 'qml/Greeter/Greeter.qml'
--- qml/Greeter/Greeter.qml 2015-03-18 10:17:28 +0000
+++ qml/Greeter/Greeter.qml 2015-05-18 22:06:13 +0000
@@ -52,6 +52,8 @@
52 property int failedLoginsDelayAttempts: 7 // number of failed logins52 property int failedLoginsDelayAttempts: 7 // number of failed logins
53 property real failedLoginsDelayMinutes: 5 // minutes of forced waiting53 property real failedLoginsDelayMinutes: 5 // minutes of forced waiting
5454
55 readonly property bool animating: loader.item ? loader.item.animating : false
56
55 signal tease()57 signal tease()
56 signal sessionStarted()58 signal sessionStarted()
57 signal emergencyCall()59 signal emergencyCall()
5860
=== modified file 'qml/Greeter/NarrowView.qml'
--- qml/Greeter/NarrowView.qml 2015-02-23 15:43:41 +0000
+++ qml/Greeter/NarrowView.qml 2015-05-18 22:06:13 +0000
@@ -33,6 +33,7 @@
33 property alias infographicModel: coverPage.infographicModel33 property alias infographicModel: coverPage.infographicModel
34 readonly property bool fullyShown: coverPage.showProgress === 1 || lockscreen.shown34 readonly property bool fullyShown: coverPage.showProgress === 1 || lockscreen.shown
35 readonly property bool required: coverPage.required || lockscreen.required35 readonly property bool required: coverPage.required || lockscreen.required
36 readonly property bool animating: coverPage.showAnimation.running || coverPage.hideAnimation.running
3637
37 signal selected(int index) // unused38 signal selected(int index) // unused
38 signal responded(string response)39 signal responded(string response)
3940
=== modified file 'qml/Greeter/WideView.qml'
--- qml/Greeter/WideView.qml 2015-02-23 15:43:41 +0000
+++ qml/Greeter/WideView.qml 2015-05-18 22:06:13 +0000
@@ -32,6 +32,7 @@
32 property alias infographicModel: coverPage.infographicModel32 property alias infographicModel: coverPage.infographicModel
33 readonly property bool fullyShown: coverPage.showProgress === 133 readonly property bool fullyShown: coverPage.showProgress === 1
34 readonly property bool required: coverPage.required34 readonly property bool required: coverPage.required
35 readonly property bool animating: coverPage.showAnimation.running || coverPage.hideAnimation.running
3536
36 // so that it can be replaced in tests with a mock object37 // so that it can be replaced in tests with a mock object
37 property var inputMethod: Qt.inputMethod38 property var inputMethod: Qt.inputMethod
3839
=== added file 'qml/OrientedShell.qml'
--- qml/OrientedShell.qml 1970-01-01 00:00:00 +0000
+++ qml/OrientedShell.qml 2015-05-18 22:06:13 +0000
@@ -0,0 +1,185 @@
1/*
2 * Copyright (C) 2015 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17import QtQuick 2.0
18import QtQuick.Window 2.0
19import Unity.Session 0.1
20import GSettings 1.0
21import "Components"
22import "Rotation"
23
24Rectangle {
25 id: root
26 color: "black"
27
28 implicitWidth: units.gu(40)
29 implicitHeight: units.gu(71)
30
31 // NB: native and primary orientations here don't map exactly to their QScreen counterparts
32 readonly property int nativeOrientation: width > height ? Qt.LandscapeOrientation : Qt.PortraitOrientation
33
34 readonly property int primaryOrientation:
35 deviceConfiguration.primaryOrientation == deviceConfiguration.useNativeOrientation
36 ? nativeOrientation : deviceConfiguration.primaryOrientation
37
38 DeviceConfiguration {
39 id: deviceConfiguration
40 name: applicationArguments.deviceName
41 }
42
43 // to be overwritten by tests
44 property var usageModeSettings: GSettings { schema.id: "com.canonical.Unity8" }
45 property int physicalOrientation: Screen.orientation
46 property bool orientationLocked: OrientationLock.enabled
47 property var orientationLock: OrientationLock
48
49 property int orientation
50 onPhysicalOrientationChanged: {
51 if (!orientationLocked) {
52 orientation = physicalOrientation;
53 }
54 }
55 onOrientationLockedChanged: {
56 if (orientationLocked) {
57 orientationLock.savedOrientation = physicalOrientation;
58 } else {
59 orientation = physicalOrientation;
60 }
61 }
62 Component.onCompleted: {
63 if (orientationLocked) {
64 orientation = orientationLock.savedOrientation;
65 }
66 }
67
68 readonly property int supportedOrientations: shell.supportedOrientations
69 & deviceConfiguration.supportedOrientations
70 property int acceptedOrientationAngle: {
71 if (orientation & supportedOrientations) {
72 return Screen.angleBetween(nativeOrientation, orientation);
73 } else if (shell.orientation & supportedOrientations) {
74 // stay where we are
75 return shell.orientationAngle;
76 } else if (angleToOrientation(shell.mainAppWindowOrientationAngle) & supportedOrientations) {
77 return shell.mainAppWindowOrientationAngle;
78 } else {
79 // rotate to some supported orientation as we can't stay where we currently are
80 // TODO: Choose the closest to the current one
81 if (supportedOrientations & Qt.PortraitOrientation) {
82 return Screen.angleBetween(nativeOrientation, Qt.PortraitOrientation);
83 } else if (supportedOrientations & Qt.LandcscapeOrientation) {
84 return Screen.angleBetween(nativeOrientation, Qt.LandscapeOrientation);
85 } else if (supportedOrientations & Qt.InvertedPortraitOrientation) {
86 return Screen.angleBetween(nativeOrientation, Qt.InvertedPortraitOrientation);
87 } else if (supportedOrientations & Qt.InvertedLandscapeOrientation) {
88 return Screen.angleBetween(nativeOrientation, Qt.InvertedLandscapeOrientation);
89 } else {
90 // if all fails, fallback to primary orientation
91 return Screen.angleBetween(nativeOrientation, primaryOrientation);
92 }
93 }
94 }
95
96 function angleToOrientation(angle) {
97 switch (angle) {
98 case 0:
99 return nativeOrientation;
100 break;
101 case 90:
102 return nativeOrientation === Qt.PortraitOrientation ? Qt.InvertedLandscapeOrientation
103 : Qt.PortraitOrientation;
104 break;
105 case 180:
106 return nativeOrientation === Qt.PortraitOrientation ? Qt.InvertedPortraitOrientation
107 : Qt.InvertedLandscapeOrientation;
108 break;
109 case 270:
110 return nativeOrientation === Qt.PortraitOrientation ? Qt.LandscapeOrientation
111 : Qt.InvertedPortraitOrientation;
112 break;
113 default:
114 console.warn("angleToOrientation: Invalid orientation angle: " + angle);
115 return primaryOrientation;
116 }
117 }
118
119 RotationStates {
120 id: rotationStates
121 objectName: "rotationStates"
122 orientedShell: root
123 shell: shell
124 shellCover: shellCover
125 windowScreenshot: windowScreenshot
126 }
127
128 Shell {
129 id: shell
130 objectName: "shell"
131 width: root.width
132 height: root.height
133 orientation: root.angleToOrientation(orientationAngle)
134 primaryOrientation: root.primaryOrientation
135 nativeOrientation: root.nativeOrientation
136 nativeWidth: root.width
137 nativeHeight: root.height
138
139 // TODO: Factor in the connected input devices (eg: physical keyboard, mouse, touchscreen),
140 // what's the output device (eg: big TV, desktop monitor, phone display), etc.
141 usageScenario: {
142 if (root.usageModeSettings.usageMode === "Windowed") {
143 return "desktop";
144 } else if (root.usageModeSettings.usageMode === "Staged"
145 && deviceConfiguration.category === "desktop") {
146 return "tablet";
147 } else {
148 return deviceConfiguration.category;
149 }
150 }
151
152 property real transformRotationAngle
153 property real transformOriginX
154 property real transformOriginY
155
156 transform: Rotation {
157 origin.x: shell.transformOriginX; origin.y: shell.transformOriginY; axis { x: 0; y: 0; z: 1 }
158 angle: shell.transformRotationAngle
159 }
160 }
161
162 Rectangle {
163 id: shellCover
164 color: "black"
165 anchors.fill: parent
166 visible: false
167 }
168
169 WindowScreenshot {
170 id: windowScreenshot
171 visible: false
172 width: root.width
173 height: root.height
174
175 property real transformRotationAngle
176 property real transformOriginX
177 property real transformOriginY
178
179 transform: Rotation {
180 origin.x: windowScreenshot.transformOriginX; origin.y: windowScreenshot.transformOriginY;
181 axis { x: 0; y: 0; z: 1 }
182 angle: windowScreenshot.transformRotationAngle
183 }
184 }
185}
0186
=== modified file 'qml/Panel/Panel.qml'
--- qml/Panel/Panel.qml 2015-04-02 15:08:05 +0000
+++ qml/Panel/Panel.qml 2015-05-18 22:06:13 +0000
@@ -27,6 +27,9 @@
27 property alias indicators: __indicators27 property alias indicators: __indicators
28 property alias callHint: __callHint28 property alias callHint: __callHint
29 property bool fullscreenMode: false29 property bool fullscreenMode: false
30 property real indicatorAreaShowProgress: 1.0
31
32 opacity: fullscreenMode && indicators.fullyClosed ? 0.0 : 1.0
3033
31 Rectangle {34 Rectangle {
32 id: darkenedArea35 id: darkenedArea
@@ -58,6 +61,12 @@
58 NumberAnimation { duration: UbuntuAnimation.FastDuration; easing: UbuntuAnimation.StandardEasing }61 NumberAnimation { duration: UbuntuAnimation.FastDuration; easing: UbuntuAnimation.StandardEasing }
59 }62 }
6063
64 transform: Translate {
65 y: indicators.state === "initial"
66 ? (1.0 - indicatorAreaShowProgress) * -d.indicatorHeight
67 : 0
68 }
69
61 BorderImage {70 BorderImage {
62 id: dropShadow71 id: dropShadow
63 anchors {72 anchors {
6473
=== added directory 'qml/Rotation'
=== added file 'qml/Rotation/HalfLoopRotationAnimation.qml'
--- qml/Rotation/HalfLoopRotationAnimation.qml 1970-01-01 00:00:00 +0000
+++ qml/Rotation/HalfLoopRotationAnimation.qml 2015-05-18 22:06:13 +0000
@@ -0,0 +1,46 @@
1/*
2 * Copyright (C) 2015 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17import QtQuick 2.3
18
19SequentialAnimation {
20 id: root
21
22 // set from outside
23 property int fromAngle
24 property int toAngle
25 property var info
26 property var shell
27
28 readonly property bool flipShellDimensions: toAngle == 90 || toAngle == 270
29
30 ScriptAction { script: {
31 info.transitioning = true;
32 shell.orientationAngle = root.toAngle;
33 shell.x = (orientedShell.width - shell.width) / 2
34 shell.y = (orientedShell.height - shell.height) / 2;
35 shell.transformOriginX = shell.width / 2;
36 shell.transformOriginY = shell.height / 2;
37 shell.updateFocusedAppOrientation();
38 } }
39 NumberAnimation {
40 target: shell
41 property: "transformRotationAngle"
42 from: root.fromAngle; to: root.toAngle
43 duration: rotationDuration; easing.type: rotationEasing
44 }
45 ScriptAction { script: { info.transitioning = false; } }
46}
047
=== added file 'qml/Rotation/ImmediateRotationAction.qml'
--- qml/Rotation/ImmediateRotationAction.qml 1970-01-01 00:00:00 +0000
+++ qml/Rotation/ImmediateRotationAction.qml 2015-05-18 22:06:13 +0000
@@ -0,0 +1,45 @@
1/*
2 * Copyright (C) 2015 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17import QtQuick 2.3
18
19ScriptAction {
20 property var info
21 property var shell
22
23 script: {
24 info.transitioning = true;
25 shell.orientationAngle = info.requestedOrientationAngle;
26 shell.transformRotationAngle = info.requestedOrientationAngle;
27
28 // Making bindings as orientedShell's dimensions might wiggle during startup.
29 if (info.requestedOrientationAngle === 90 || info.requestedOrientationAngle === 270) {
30 shell.width = Qt.binding(function() { return orientedShell.height; });
31 shell.height = Qt.binding(function() { return orientedShell.width; });
32 } else {
33 shell.width = Qt.binding(function() { return orientedShell.width; });
34 shell.height = Qt.binding(function() { return orientedShell.height; });
35 }
36
37 shell.x = Qt.binding(function() { return (orientedShell.width - shell.width) / 2; });
38 shell.y = Qt.binding(function() { return (orientedShell.height - shell.height) / 2; });
39 shell.transformOriginX = Qt.binding(function() { return shell.width / 2; });
40 shell.transformOriginY = Qt.binding(function() { return shell.height / 2; });
41
42 shell.updateFocusedAppOrientation();
43 info.transitioning = false;
44 }
45}
046
=== added file 'qml/Rotation/NinetyRotationAnimation.qml'
--- qml/Rotation/NinetyRotationAnimation.qml 1970-01-01 00:00:00 +0000
+++ qml/Rotation/NinetyRotationAnimation.qml 2015-05-18 22:06:13 +0000
@@ -0,0 +1,90 @@
1/*
2 * Copyright (C) 2015 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17import QtQuick 2.3
18
19SequentialAnimation {
20 id: root
21
22 property int fromAngle
23 property int toAngle
24 property var info
25 property var shell
26
27 readonly property real fromY: fromAngle === 0 || fromAngle === 90 ? 0 : orientedShell.height - orientedShell.width;
28 readonly property real toY: toAngle === 0 || toAngle === 90 ? 0 : orientedShell.height - orientedShell.width;
29 readonly property bool flipShellDimensions: toAngle == 90 || toAngle == 270
30
31 ScriptAction { script: {
32 info.transitioning = true;
33 windowScreenshot.take();
34 windowScreenshot.visible = true;
35 shell.orientationAngle = root.toAngle;
36 shell.x = 0;
37 shell.width = flipShellDimensions ? orientedShell.height : orientedShell.width;
38 shell.height = flipShellDimensions ? orientedShell.width : orientedShell.height;
39 shell.transformOriginX = orientedShell.width / 2;
40 shell.transformOriginY = orientedShell.width / 2;
41 shell.updateFocusedAppOrientation();
42 shellCover.visible = true;
43
44 windowScreenshot.transformOriginX = orientedShell.width / 2;
45 if (fromAngle == 180 || fromAngle == 270) {
46 windowScreenshot.transformOriginY = orientedShell.height - (orientedShell.width / 2);
47 } else {
48 windowScreenshot.transformOriginY = orientedShell.width / 2;
49 }
50 } }
51 ParallelAnimation {
52 NumberAnimation {
53 target: shellCover; property: "opacity"; from: 1; to: 0;
54 duration: rotationDuration; easing.type: rotationEasing
55 }
56 RotationAnimation {
57 target: shell; property: "transformRotationAngle";
58 from: root.fromAngle; to: root.toAngle
59 direction: RotationAnimation.Shortest
60 duration: rotationDuration; easing.type: rotationEasing
61 }
62 NumberAnimation {
63 target: shell; property: "y"
64 from: root.fromY; to: root.toY
65 duration: rotationDuration; easing.type: rotationEasing
66 }
67
68 NumberAnimation {
69 target: windowScreenshot; property: "opacity"; from: 1; to: 0;
70 duration: rotationDuration; easing.type: rotationEasing
71 }
72 RotationAnimation {
73 target: windowScreenshot; property: "transformRotationAngle";
74 from: 0; to: root.toAngle - root.fromAngle
75 direction: RotationAnimation.Shortest
76 duration: rotationDuration; easing.type: rotationEasing
77 }
78 NumberAnimation {
79 target: windowScreenshot; property: "y"
80 from: 0; to: root.toY - root.fromY
81 duration: rotationDuration; easing.type: rotationEasing
82 }
83 }
84 ScriptAction { script: {
85 windowScreenshot.visible = false;
86 windowScreenshot.discard();
87 shellCover.visible = false;
88 info.transitioning = false;
89 } }
90}
091
=== added file 'qml/Rotation/RotationStates.qml'
--- qml/Rotation/RotationStates.qml 1970-01-01 00:00:00 +0000
+++ qml/Rotation/RotationStates.qml 2015-05-18 22:06:13 +0000
@@ -0,0 +1,278 @@
1/*
2 * Copyright (C) 2015 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17import QtQuick 2.0
18import Ubuntu.Components 1.1
19import Powerd 0.1
20
21// Why the state machine is done that way:
22// We cannot use regular PropertyChanges{} inside the State elements as steps in the
23// transition animations must take place in a well defined order.
24// Which means that we also cannot jump to a new state in the middle of a transition
25// as that would make hell brake loose.
26StateGroup {
27 id: root
28
29 // to be set from the outside
30 property Item orientedShell
31 property Item shell
32 property Item shellCover
33 property Item windowScreenshot
34
35 property int rotationDuration: 450
36 property int rotationEasing: Easing.InOutCubic
37 // Those values are good for debugging/development
38 //property int rotationDuration: 3000
39 //property int rotationEasing: Easing.Linear
40
41 state: "0"
42 states: [
43 State { name: "0" },
44 State { name: "90" },
45 State { name: "180" },
46 State { name: "270" }
47 ]
48
49 property QtObject d: QtObject {
50 id: d
51
52 property bool startingUp: true
53 property var finishStartUpTimer: Timer {
54 interval: 500
55 onTriggered: d.startingUp = false
56 }
57 Component.onCompleted: {
58 finishStartUpTimer.start();
59 }
60
61 property bool transitioning: false
62 onTransitioningChanged: {
63 d.tryUpdateState();
64 }
65
66 readonly property int requestedOrientationAngle: root.orientedShell.acceptedOrientationAngle
67
68 // Avoiding a direct call to tryUpdateState() as the state change might trigger an immediate
69 // change to Shell.orientationAngle which, in its turn, causes a reevaluation of
70 // requestedOrientationAngle (ie., OrientedShell.acceptedOrientationAngle). A reentrant evaluation
71 // of a binding is detected by QML as a binding loop and QML will deny the reevalutation, which
72 // will leave us in a bogus state.
73 //
74 // To avoid this mess we update the state in the next event loop iteration, ensuring a clean
75 // call stack.
76 onRequestedOrientationAngleChanged: {
77 stateUpdateTimer.start();
78 }
79 property Timer stateUpdateTimer: Timer {
80 id: stateUpdateTimer
81 interval: 1
82 onTriggered: { d.tryUpdateState(); }
83 }
84
85 function tryUpdateState() {
86 if (d.transitioning || (!d.startingUp && !root.shell.orientationChangesEnabled)) {
87 return;
88 }
89
90 var requestedState = d.requestedOrientationAngle.toString();
91 if (requestedState !== root.state) {
92 d.resolveAnimationType();
93 root.state = requestedState;
94 }
95 }
96
97 property Connections shellConnections: Connections {
98 target: root.shell
99 onOrientationChangesEnabledChanged: {
100 d.tryUpdateState();
101 }
102 }
103
104 property var shellBeingResized: Binding {
105 target: root.shell
106 property: "beingResized"
107 value: d.transitioning
108 }
109
110 readonly property int fullAnimation: 0
111 readonly property int indicatorsBarAnimation: 1
112 readonly property int noAnimation: 2
113
114 property int animationType
115
116 // animationType update *must* take place *before* the state update.
117 // If animationType and state were updated through bindings, as with normal qml code,
118 // there would be no guarantee in the order of the binding updates, which could then
119 // cause the wrong transitions to be chosen for the state changes.
120 function resolveAnimationType() {
121 if (d.startingUp) {
122 // During start up, inital property values are still settling while we're still
123 // to render the very first frame
124 d.animationType = d.noAnimation;
125 } else if (Powerd.status === Powerd.Off) {
126 // There's no point in animating if the user can't see it (display is off).
127 d.animationType = d.noAnimation;
128 } else if (root.shell.showingGreeter) {
129 // A rotating greeter looks weird.
130 d.animationType = d.noAnimation;
131 } else {
132 if (!root.shell.mainApp) {
133 // shouldn't happen but, anyway
134 d.animationType = d.fullAnimation;
135 return;
136 }
137
138 if (root.shell.mainApp.rotatesWindowContents) {
139 // The application will animate its own GUI, so we don't have to do anything ourselves.
140 d.animationType = d.noAnimation;
141 } else if (root.shell.mainAppWindowOrientationAngle == d.requestedOrientationAngle) {
142 // The app window is already on its final orientation angle.
143 // So we just animate the indicators bar
144 // TODO: what if the app is fullscreen?
145 d.animationType = d.indicatorsBarAnimation;
146 } else {
147 d.animationType = d.fullAnimation;
148 }
149 }
150 }
151
152 // When an application switch takes place, d.requestedOrientationAngle and
153 // root.shell.mainAppWindowOrientationAngle get updated separately, at different moments.
154 // So, when one of those properties change, we shouldn't make a decision straight away
155 // as the other might be stale and about to be changed. So let's give it a bit of time for
156 // them to get properly updated.
157 // This approach is indeed a bit hacky.
158 property bool appWindowOrientationAngleNeedsUpdateUnstable:
159 root.shell.orientationAngle === d.requestedOrientationAngle
160 && root.shell.mainApp
161 && root.shell.mainAppWindowOrientationAngle !== root.shell.orientationAngle
162 && !d.transitioning
163 onAppWindowOrientationAngleNeedsUpdateUnstableChanged: {
164 stableTimer.restart();
165 }
166 property Timer stableTimer: Timer {
167 interval: 200
168 onTriggered: {
169 if (d.appWindowOrientationAngleNeedsUpdateUnstable) {
170 shell.updateFocusedAppOrientationAnimated();
171 }
172 }
173 }
174 }
175
176 transitions: [
177 Transition {
178 from: "90"; to: "0"
179 enabled: d.animationType == d.fullAnimation
180 NinetyRotationAnimation { fromAngle: 90; toAngle: 0
181 info: d; shell: root.shell }
182 },
183 Transition {
184 from: "0"; to: "90"
185 enabled: d.animationType == d.fullAnimation
186 NinetyRotationAnimation { fromAngle: 0; toAngle: 90
187 info: d; shell: root.shell }
188 },
189 Transition {
190 from: "0"; to: "270"
191 enabled: d.animationType == d.fullAnimation
192 NinetyRotationAnimation { fromAngle: 0; toAngle: 270
193 info: d; shell: root.shell }
194 },
195 Transition {
196 from: "270"; to: "0"
197 enabled: d.animationType == d.fullAnimation
198 NinetyRotationAnimation { fromAngle: 270; toAngle: 0
199 info: d; shell: root.shell }
200 },
201 Transition {
202 from: "90"; to: "180"
203 enabled: d.animationType == d.fullAnimation
204 NinetyRotationAnimation { fromAngle: 90; toAngle: 180
205 info: d; shell: root.shell }
206 },
207 Transition {
208 from: "180"; to: "90"
209 enabled: d.animationType == d.fullAnimation
210 NinetyRotationAnimation { fromAngle: 180; toAngle: 90
211 info: d; shell: root.shell }
212 },
213 Transition {
214 from: "180"; to: "270"
215 enabled: d.animationType == d.fullAnimation
216 NinetyRotationAnimation { fromAngle: 180; toAngle: 270
217 info: d; shell: root.shell }
218 },
219 Transition {
220 from: "270"; to: "180"
221 enabled: d.animationType == d.fullAnimation
222 NinetyRotationAnimation { fromAngle: 270; toAngle: 180
223 info: d; shell: root.shell }
224 },
225 Transition {
226 from: "0"; to: "180"
227 enabled: d.animationType == d.fullAnimation
228 HalfLoopRotationAnimation { fromAngle: 0; toAngle: 180
229 info: d; shell: root.shell }
230 },
231 Transition {
232 from: "180"; to: "0"
233 enabled: d.animationType == d.fullAnimation
234 HalfLoopRotationAnimation { fromAngle: 180; toAngle: 0
235 info: d; shell: root.shell }
236 },
237 Transition {
238 from: "90"; to: "270"
239 enabled: d.animationType == d.fullAnimation
240 HalfLoopRotationAnimation { fromAngle: 90; toAngle: 270
241 info: d; shell: root.shell }
242 },
243 Transition {
244 from: "270"; to: "90"
245 enabled: d.animationType == d.fullAnimation
246 HalfLoopRotationAnimation { fromAngle: 270; toAngle: 90
247 info: d; shell: root.shell }
248 },
249 Transition {
250 objectName: "immediateTransition"
251 enabled: d.animationType == d.noAnimation
252 ImmediateRotationAction { info: d; shell: root.shell }
253 },
254 Transition {
255 enabled: d.animationType == d.indicatorsBarAnimation
256 SequentialAnimation {
257 ScriptAction { script: {
258 d.transitioning = true;
259 } }
260 NumberAnimation {
261 duration: UbuntuAnimation.FastDuration; easing: UbuntuAnimation.StandardEasing
262 target: root.shell; property: "indicatorAreaShowProgress"
263 from: 1.0; to: 0.0
264 }
265 ImmediateRotationAction { info: d; shell: root.shell }
266 NumberAnimation {
267 duration: UbuntuAnimation.FastDuration; easing: UbuntuAnimation.StandardEasing
268 target: root.shell; property: "indicatorAreaShowProgress"
269 from: 0.0; to: 1.0
270 }
271 ScriptAction { script: {
272 d.transitioning = false;
273 }}
274 }
275 }
276 ]
277
278}
0279
=== modified file 'qml/Shell.qml'
--- qml/Shell.qml 2015-05-05 14:46:18 +0000
+++ qml/Shell.qml 2015-05-18 22:06:13 +0000
@@ -1,5 +1,5 @@
1/*1/*
2 * Copyright (C) 2013 Canonical, Ltd.2 * Copyright (C) 2013-2015 Canonical, Ltd.
3 *3 *
4 * This program is free software; you can redistribute it and/or modify4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by5 * it under the terms of the GNU General Public License as published by
@@ -45,39 +45,69 @@
45Item {45Item {
46 id: shell46 id: shell
4747
48 // to be set from outside
49 property int orientationAngle: 0
50 property int orientation
51 property int primaryOrientation
52 property int nativeOrientation
53 property real nativeWidth
54 property real nativeHeight
55 property alias indicatorAreaShowProgress: panel.indicatorAreaShowProgress
56 property bool beingResized
57 property string usageScenario: "phone" // supported values: "phone", "tablet" or "desktop"
58 function updateFocusedAppOrientation() {
59 applicationsDisplayLoader.item.updateFocusedAppOrientation();
60 }
61 function updateFocusedAppOrientationAnimated() {
62 applicationsDisplayLoader.item.updateFocusedAppOrientationAnimated();
63 }
64
65 // to be read from outside
66 readonly property int mainAppWindowOrientationAngle:
67 applicationsDisplayLoader.item ? applicationsDisplayLoader.item.mainAppWindowOrientationAngle : 0
68
69 readonly property bool orientationChangesEnabled: panel.indicators.fullyClosed
70 && (applicationsDisplayLoader.item && applicationsDisplayLoader.item.orientationChangesEnabled)
71 && !greeter.animating
72
73 readonly property bool showingGreeter: greeter.shown
74
75 property bool startingUp: true
76 Timer { id: finishStartUpTimer; interval: 500; onTriggered: startingUp = false }
77
78 property int supportedOrientations: {
79 if (startingUp) {
80 // Ensure we don't rotate during start up
81 return Qt.PrimaryOrientation;
82 } else if (greeter.shown) {
83 return Qt.PrimaryOrientation;
84 } else if (mainApp) {
85 return mainApp.supportedOrientations;
86 } else {
87 // we just don't care
88 return Qt.PortraitOrientation
89 | Qt.LandscapeOrientation
90 | Qt.InvertedPortraitOrientation
91 | Qt.InvertedLandscapeOrientation;
92 }
93 }
94
95 // For autopilot consumption
96 readonly property string focusedApplicationId: ApplicationManager.focusedApplicationId
97
98 // internal props from here onwards
99 readonly property var mainApp:
100 applicationsDisplayLoader.item ? applicationsDisplayLoader.item.mainApp : null
101
48 // Disable everything while greeter is waiting, so that the user can't swipe102 // Disable everything while greeter is waiting, so that the user can't swipe
49 // the greeter or launcher until we know whether the session is locked.103 // the greeter or launcher until we know whether the session is locked.
50 enabled: !greeter.waiting104 enabled: !greeter.waiting
51105
52 // this is only here to select the width / height of the window if not running fullscreen
53 property bool tablet: false
54 width: tablet ? units.gu(160) : applicationArguments.hasGeometry() ? applicationArguments.width() : units.gu(40)
55 height: tablet ? units.gu(100) : applicationArguments.hasGeometry() ? applicationArguments.height() : units.gu(71)
56
57 property real edgeSize: units.gu(2)106 property real edgeSize: units.gu(2)
58 property url defaultBackground: Qt.resolvedUrl(shell.width >= units.gu(60) ? "graphics/tablet_background.jpg" : "graphics/phone_background.jpg")107 property url defaultBackground: Qt.resolvedUrl(shell.width >= units.gu(60) ? "graphics/tablet_background.jpg" : "graphics/phone_background.jpg")
59 property url background: asImageTester.status == Image.Ready ? asImageTester.source108 property url background: asImageTester.status == Image.Ready ? asImageTester.source
60 : gsImageTester.status == Image.Ready ? gsImageTester.source : defaultBackground109 : gsImageTester.status == Image.Ready ? gsImageTester.source : defaultBackground
61110
62 property bool sideStageEnabled: shell.width >= units.gu(100)
63 readonly property string focusedApplicationId: ApplicationManager.focusedApplicationId
64
65 property int orientation
66 readonly property int deviceOrientationAngle: Screen.angleBetween(Screen.primaryOrientation, Screen.orientation)
67 onDeviceOrientationAngleChanged: {
68 if (!OrientationLock.enabled) {
69 orientation = Screen.orientation;
70 }
71 }
72 readonly property bool orientationLockEnabled: OrientationLock.enabled
73 onOrientationLockEnabledChanged: {
74 if (orientationLockEnabled) {
75 OrientationLock.savedOrientation = Screen.orientation;
76 } else {
77 orientation = Screen.orientation;
78 }
79 }
80
81 // This is _only_ used to expose the property to autopilot tests111 // This is _only_ used to expose the property to autopilot tests
82 readonly property string testShellMode: shellMode112 readonly property string testShellMode: shellMode
83113
@@ -85,7 +115,8 @@
85 if (ApplicationManager.findApplication(appId)) {115 if (ApplicationManager.findApplication(appId)) {
86 ApplicationManager.requestFocusApplication(appId);116 ApplicationManager.requestFocusApplication(appId);
87 } else {117 } else {
88 var execFlags = shell.sideStageEnabled ? ApplicationManager.NoFlag : ApplicationManager.ForceMainStage;118 var execFlags = shell.usageScenario === "phone" ? ApplicationManager.ForceMainStage
119 : ApplicationManager.NoFlag;
89 ApplicationManager.startApplication(appId, execFlags);120 ApplicationManager.startApplication(appId, execFlags);
90 }121 }
91 }122 }
@@ -123,11 +154,6 @@
123 sourceSize.width: 0154 sourceSize.width: 0
124 }155 }
125156
126 GSettings {
127 id: usageModeSettings
128 schema.id: "com.canonical.Unity8"
129 }
130
131 Binding {157 Binding {
132 target: LauncherModel158 target: LauncherModel
133 property: "applicationManager"159 property: "applicationManager"
@@ -139,9 +165,7 @@
139 if (ApplicationManager.count > 0) {165 if (ApplicationManager.count > 0) {
140 ApplicationManager.focusApplication(ApplicationManager.get(0).appId);166 ApplicationManager.focusApplication(ApplicationManager.get(0).appId);
141 }167 }
142 if (orientationLockEnabled) {168 finishStartUpTimer.start();
143 orientation = OrientationLock.savedOrientation;
144 }
145 }169 }
146170
147 VolumeControl {171 VolumeControl {
@@ -234,9 +258,19 @@
234 // theoretical attack where user enters lockedApp mode, then makes258 // theoretical attack where user enters lockedApp mode, then makes
235 // the screen larger (maybe connects to monitor) and tries to enter259 // the screen larger (maybe connects to monitor) and tries to enter
236 // tablet mode.260 // tablet mode.
237 property bool tabletMode: shell.sideStageEnabled && !greeter.hasLockedApp261
238 source: usageModeSettings.usageMode === "Windowed" ? "Stages/DesktopStage.qml"262 property string usageScenario: shell.usageScenario === "phone" || greeter.hasLockedApp
239 : tabletMode ? "Stages/TabletStage.qml" : "Stages/PhoneStage.qml"263 ? "phone"
264 : shell.usageScenario
265 source: {
266 if (applicationsDisplayLoader.usageScenario === "phone") {
267 return "Stages/PhoneStage.qml";
268 } else if (applicationsDisplayLoader.usageScenario === "tablet") {
269 return "Stages/TabletStage.qml";
270 } else {
271 return "Stages/DesktopStage.qml";
272 }
273 }
240274
241 property bool interactive: tutorial.spreadEnabled275 property bool interactive: tutorial.spreadEnabled
242 && !greeter.shown276 && !greeter.shown
@@ -279,7 +313,12 @@
279 }313 }
280 Binding {314 Binding {
281 target: applicationsDisplayLoader.item315 target: applicationsDisplayLoader.item
282 property: "orientation"316 property: "shellOrientationAngle"
317 value: shell.orientationAngle
318 }
319 Binding {
320 target: applicationsDisplayLoader.item
321 property: "shellOrientation"
283 value: shell.orientation322 value: shell.orientation
284 }323 }
285 Binding {324 Binding {
@@ -287,6 +326,31 @@
287 property: "background"326 property: "background"
288 value: shell.background327 value: shell.background
289 }328 }
329 Binding {
330 target: applicationsDisplayLoader.item
331 property: "shellPrimaryOrientation"
332 value: shell.primaryOrientation
333 }
334 Binding {
335 target: applicationsDisplayLoader.item
336 property: "nativeOrientation"
337 value: shell.nativeOrientation
338 }
339 Binding {
340 target: applicationsDisplayLoader.item
341 property: "nativeWidth"
342 value: shell.nativeWidth
343 }
344 Binding {
345 target: applicationsDisplayLoader.item
346 property: "nativeHeight"
347 value: shell.nativeHeight
348 }
349 Binding {
350 target: applicationsDisplayLoader.item
351 property: "beingResized"
352 value: shell.beingResized
353 }
290 }354 }
291355
292 Tutorial {356 Tutorial {
@@ -356,7 +420,7 @@
356 objectName: "greeter"420 objectName: "greeter"
357421
358 hides: [launcher, panel.indicators]422 hides: [launcher, panel.indicators]
359 tabletMode: shell.sideStageEnabled423 tabletMode: shell.usageScenario !== "phone"
360 launcherOffset: launcher.progress424 launcherOffset: launcher.progress
361 forcedUnlock: tutorial.running425 forcedUnlock: tutorial.running
362 background: shell.background426 background: shell.background
@@ -483,20 +547,18 @@
483 expandedPanelHeight: units.gu(7)547 expandedPanelHeight: units.gu(7)
484548
485 indicatorsModel: Indicators.IndicatorsModel {549 indicatorsModel: Indicators.IndicatorsModel {
486 // TODO: This should be sourced by device type (e.g. "desktop", "tablet", "phone"...)550 // tablet and phone both use the same profile
487 profile: indicatorProfile551 profile: shell.usageScenario === "desktop" ? "desktop" : "phone"
488 Component.onCompleted: load()552 Component.onCompleted: load();
489 }553 }
490 }554 }
555
491 callHint {556 callHint {
492 greeterShown: greeter.shown557 greeterShown: greeter.shown
493 }558 }
494559
495 property bool topmostApplicationIsFullscreen:560 property bool mainAppIsFullscreen: shell.mainApp && shell.mainApp.fullscreen
496 ApplicationManager.focusedApplicationId &&561 fullscreenMode: (mainAppIsFullscreen && !LightDM.Greeter.active && launcher.progress == 0)
497 ApplicationManager.findApplication(ApplicationManager.focusedApplicationId).fullscreen
498
499 fullscreenMode: (topmostApplicationIsFullscreen && !LightDM.Greeter.active && launcher.progress == 0)
500 || greeter.hasLockedApp562 || greeter.hasLockedApp
501 }563 }
502564
@@ -514,7 +576,7 @@
514 available: tutorial.launcherEnabled576 available: tutorial.launcherEnabled
515 && (!greeter.locked || AccountsService.enableLauncherWhileLocked)577 && (!greeter.locked || AccountsService.enableLauncherWhileLocked)
516 && !greeter.hasLockedApp578 && !greeter.hasLockedApp
517 inverted: usageModeSettings.usageMode === "Staged"579 inverted: shell.usageScenario !== "desktop"
518 shadeBackground: !tutorial.running580 shadeBackground: !tutorial.running
519581
520 onShowDashHome: showHome()582 onShowDashHome: showHome()
@@ -556,7 +618,7 @@
556 Rectangle {618 Rectangle {
557 id: modalNotificationBackground619 id: modalNotificationBackground
558620
559 visible: notifications.useModal && (notifications.state == "narrow")621 visible: notifications.useModal
560 color: "#000000"622 color: "#000000"
561 anchors.fill: parent623 anchors.fill: parent
562 opacity: 0.9624 opacity: 0.9
@@ -601,6 +663,7 @@
601663
602 Dialogs {664 Dialogs {
603 id: dialogs665 id: dialogs
666 objectName: "dialogs"
604 anchors.fill: parent667 anchors.fill: parent
605 z: overlay.z + 10668 z: overlay.z + 10
606 onPowerOffClicked: {669 onPowerOffClicked: {
607670
=== modified file 'qml/Stages/ApplicationWindow.qml'
--- qml/Stages/ApplicationWindow.qml 2015-02-26 22:35:53 +0000
+++ qml/Stages/ApplicationWindow.qml 2015-05-18 22:06:13 +0000
@@ -1,5 +1,5 @@
1/*1/*
2 * Copyright 2014 Canonical Ltd.2 * Copyright 2014-2015 Canonical Ltd.
3 *3 *
4 * This program is free software; you can redistribute it and/or modify4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published by5 * it under the terms of the GNU Lesser General Public License as published by
@@ -24,10 +24,11 @@
24 // to be read from outside24 // to be read from outside
25 readonly property bool fullscreen: application ? application.fullscreen : false25 readonly property bool fullscreen: application ? application.fullscreen : false
26 property alias interactive: sessionContainer.interactive26 property alias interactive: sessionContainer.interactive
27 property bool orientationChangesEnabled: d.supportsSurfaceResize ? d.surfaceOldEnoughToBeResized : true
2728
28 // to be set from outside29 // to be set from outside
29 property QtObject application30 property QtObject application
30 property int orientation31 property int surfaceOrientationAngle
3132
32 QtObject {33 QtObject {
33 id: d34 id: d
@@ -62,6 +63,15 @@
62 // Remove this when possible63 // Remove this when possible
63 property bool surfaceInitialized: false64 property bool surfaceInitialized: false
6465
66 property bool supportsSurfaceResize:
67 application &&
68 ((application.supportedOrientations & Qt.PortraitOrientation)
69 || (application.supportedOrientations & Qt.InvertedPortraitOrientation))
70 &&
71 ((application.supportedOrientations & Qt.LandscapeOrientation)
72 || (application.supportedOrientations & Qt.InvertedLandscapeOrientation))
73
74 property bool surfaceOldEnoughToBeResized: false
65 }75 }
6676
67 Timer {77 Timer {
@@ -70,6 +80,12 @@
70 onTriggered: { if (sessionContainer.surface) {d.surfaceInitialized = true;} }80 onTriggered: { if (sessionContainer.surface) {d.surfaceInitialized = true;} }
71 }81 }
7282
83 Timer {
84 id: surfaceIsOldTimer
85 interval: 1000
86 onTriggered: { if (stateGroup.state === "surface") { d.surfaceOldEnoughToBeResized = true; } }
87 }
88
73 Image {89 Image {
74 id: screenshotImage90 id: screenshotImage
75 objectName: "screenshotImage"91 objectName: "screenshotImage"
@@ -113,7 +129,8 @@
113 // A fake application might not even have a session property.129 // A fake application might not even have a session property.
114 session: application && application.session ? application.session : null130 session: application && application.session ? application.session : null
115 anchors.fill: parent131 anchors.fill: parent
116 orientation: root.orientation132
133 surfaceOrientationAngle: application && application.rotatesWindowContents ? root.surfaceOrientationAngle : 0
117134
118 onSurfaceChanged: {135 onSurfaceChanged: {
119 if (sessionContainer.surface) {136 if (sessionContainer.surface) {
@@ -179,15 +196,21 @@
179 UbuntuNumberAnimation { target: sessionContainer.surfaceContainer; property: "opacity";196 UbuntuNumberAnimation { target: sessionContainer.surfaceContainer; property: "opacity";
180 from: 0.0; to: 1.0197 from: 0.0; to: 1.0
181 duration: UbuntuAnimation.BriskDuration }198 duration: UbuntuAnimation.BriskDuration }
182 PropertyAction { target: splashLoader; property: "active"; value: false }199 ScriptAction { script: {
200 splashLoader.active = false;
201 surfaceIsOldTimer.start();
202 } }
183 }203 }
184 },204 },
185 Transition {205 Transition {
186 from: "surface"; to: "splashScreen"206 from: "surface"; to: "splashScreen"
187 SequentialAnimation {207 SequentialAnimation {
188 PropertyAction { target: splashLoader; property: "active"; value: true }208 ScriptAction { script: {
189 PropertyAction { target: sessionContainer.surfaceContainer209 surfaceIsOldTimer.stop();
190 property: "visible"; value: true }210 d.surfaceOldEnoughToBeResized = false;
211 splashLoader.active = true;
212 sessionContainer.surfaceContainer.visible = true;
213 } }
191 UbuntuNumberAnimation { target: splashLoader; property: "opacity";214 UbuntuNumberAnimation { target: splashLoader; property: "opacity";
192 from: 0.0; to: 1.0215 from: 0.0; to: 1.0
193 duration: UbuntuAnimation.BriskDuration }216 duration: UbuntuAnimation.BriskDuration }
@@ -198,14 +221,18 @@
198 Transition {221 Transition {
199 from: "surface"; to: "screenshot"222 from: "surface"; to: "screenshot"
200 SequentialAnimation {223 SequentialAnimation {
201 PropertyAction { target: screenshotImage224 ScriptAction { script: {
202 property: "visible"; value: true }225 surfaceIsOldTimer.stop();
226 d.surfaceOldEnoughToBeResized = false;
227 screenshotImage.visible = true;
228 } }
203 UbuntuNumberAnimation { target: screenshotImage; property: "opacity";229 UbuntuNumberAnimation { target: screenshotImage; property: "opacity";
204 from: 0.0; to: 1.0230 from: 0.0; to: 1.0
205 duration: UbuntuAnimation.BriskDuration }231 duration: UbuntuAnimation.BriskDuration }
206 PropertyAction { target: sessionContainer.surfaceContainer232 ScriptAction { script: {
207 property: "visible"; value: false }233 sessionContainer.surfaceContainer.visible = false;
208 ScriptAction { script: { if (sessionContainer.session) { sessionContainer.session.release(); } } }234 if (sessionContainer.session) { sessionContainer.session.release(); }
235 } }
209 }236 }
210 },237 },
211 Transition {238 Transition {
@@ -216,8 +243,11 @@
216 UbuntuNumberAnimation { target: screenshotImage; property: "opacity";243 UbuntuNumberAnimation { target: screenshotImage; property: "opacity";
217 from: 1.0; to: 0.0244 from: 1.0; to: 0.0
218 duration: UbuntuAnimation.BriskDuration }245 duration: UbuntuAnimation.BriskDuration }
219 PropertyAction { target: screenshotImage; property: "visible"; value: false }246 ScriptAction { script: {
220 PropertyAction { target: screenshotImage; property: "source"; value: "" }247 screenshotImage.visible = false;
248 screenshotImage.source = "";
249 surfaceIsOldTimer.start();
250 } }
221 }251 }
222 },252 },
223 Transition {253 Transition {
@@ -233,10 +263,12 @@
233 },263 },
234 Transition {264 Transition {
235 from: "surface"; to: "void"265 from: "surface"; to: "void"
236 SequentialAnimation {266 ScriptAction { script: {
237 PropertyAction { target: sessionContainer.surfaceContainer; property: "visible"; value: false }267 surfaceIsOldTimer.stop();
238 ScriptAction { script: { if (sessionContainer.session) { sessionContainer.session.release(); } } }268 d.surfaceOldEnoughToBeResized = false;
239 }269 sessionContainer.surfaceContainer.visible = false;
270 if (sessionContainer.session) { sessionContainer.session.release(); }
271 } }
240 },272 },
241 Transition {273 Transition {
242 from: "void"; to: "surface"274 from: "void"; to: "surface"
@@ -246,6 +278,9 @@
246 UbuntuNumberAnimation { target: sessionContainer.surfaceContainer; property: "opacity";278 UbuntuNumberAnimation { target: sessionContainer.surfaceContainer; property: "opacity";
247 from: 0.0; to: 1.0279 from: 0.0; to: 1.0
248 duration: UbuntuAnimation.BriskDuration }280 duration: UbuntuAnimation.BriskDuration }
281 ScriptAction { script: {
282 surfaceIsOldTimer.start();
283 } }
249 }284 }
250 }285 }
251 ]286 ]
252287
=== modified file 'qml/Stages/DesktopStage.qml'
--- qml/Stages/DesktopStage.qml 2015-03-13 19:18:35 +0000
+++ qml/Stages/DesktopStage.qml 2015-05-18 22:06:13 +0000
@@ -27,6 +27,29 @@
2727
28 anchors.fill: parent28 anchors.fill: parent
2929
30 // Controls to be set from outside
31 property int dragAreaWidth // just to comply with the interface shared between stages
32 property real maximizedAppTopMargin
33 property bool interactive
34 property bool spreadEnabled // just to comply with the interface shared between stages
35 property real inverseProgress: 0 // just to comply with the interface shared between stages
36 property int shellOrientationAngle: 0
37 property int shellOrientation
38 property int shellPrimaryOrientation
39 property int nativeOrientation
40 property bool beingResized: false
41
42 // functions to be called from outside
43 function updateFocusedAppOrientation() { /* TODO */ }
44 function updateFocusedAppOrientationAnimated() { /* TODO */}
45
46 // To be read from outside
47 readonly property var mainApp: ApplicationManager.focusedApplicationId
48 ? ApplicationManager.findApplication(ApplicationManager.focusedApplicationId)
49 : null
50 property int mainAppWindowOrientationAngle: 0
51 readonly property bool orientationChangesEnabled: false
52
30 property alias background: wallpaper.source53 property alias background: wallpaper.source
3154
32 property var windowStateStorage: WindowStateStorage55 property var windowStateStorage: WindowStateStorage
3356
=== added file 'qml/Stages/OrientationChangeAnimation.qml'
--- qml/Stages/OrientationChangeAnimation.qml 1970-01-01 00:00:00 +0000
+++ qml/Stages/OrientationChangeAnimation.qml 2015-05-18 22:06:13 +0000
@@ -0,0 +1,241 @@
1/*
2 * Copyright 2015 Canonical Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17import QtQuick 2.3
18
19QtObject {
20 id: root
21
22 // to be set from outside
23 property Item spreadDelegate
24 property Item background
25 property Item window
26 property Item screenshot
27
28 function start() {
29 if (window.orientationAngle === 0) {
30 if (spreadDelegate.shellOrientationAngle === 90) {
31 chosenAnimation = simple90Animation;
32 } else if (spreadDelegate.shellOrientationAngle === 180) {
33 chosenAnimation = halfLoopAnimation;
34 } else if (spreadDelegate.shellOrientationAngle === 270) {
35 chosenAnimation = moving90Animation;
36 } else {
37 chosenAnimation = null;
38 }
39 } else if (window.orientationAngle === 90) {
40 if (spreadDelegate.shellOrientationAngle === 0) {
41 chosenAnimation = simple90Animation;
42 } else if (spreadDelegate.shellOrientationAngle === 180) {
43 chosenAnimation = moving90Animation;
44 } else if (spreadDelegate.shellOrientationAngle === 270) {
45 chosenAnimation = halfLoopAnimation;
46 } else {
47 chosenAnimation = null;
48 }
49 } else if (window.orientationAngle === 180) {
50 if (spreadDelegate.shellOrientationAngle === 0) {
51 chosenAnimation = halfLoopAnimation;
52 } else if (spreadDelegate.shellOrientationAngle === 90) {
53 chosenAnimation = moving90Animation;
54 } else if (spreadDelegate.shellOrientationAngle === 270) {
55 chosenAnimation = simple90Animation;
56 } else {
57 chosenAnimation = null;
58 }
59 } else if (window.orientationAngle === 270) {
60 if (spreadDelegate.shellOrientationAngle === 0) {
61 chosenAnimation = moving90Animation;
62 } else if (spreadDelegate.shellOrientationAngle === 90) {
63 chosenAnimation = halfLoopAnimation;
64 } else if (spreadDelegate.shellOrientationAngle === 180) {
65 chosenAnimation = simple90Animation;
66 } else {
67 chosenAnimation = null;
68 }
69 }
70
71 if (chosenAnimation)
72 chosenAnimation.start();
73 }
74
75 // to be read from outside
76 property bool running: chosenAnimation ? chosenAnimation.running : false
77
78 property int duration: 450
79 property int easingType: Easing.InOutCubic
80
81 property int shortestDimension: spreadDelegate.width < spreadDelegate.height
82 ? spreadDelegate.width : spreadDelegate.height
83 property int longestDimension: spreadDelegate.width > spreadDelegate.height
84 ? spreadDelegate.width : spreadDelegate.height
85 property string longestAxis: spreadDelegate.width > spreadDelegate.height ? "x" : "y"
86
87 property QtObject chosenAnimation
88
89 function setup90Animation() {
90 background.visible = true;
91
92 screenshot.width = window.width;
93 screenshot.height = window.height;
94 screenshot.window.anchors.topMargin = window.window.anchors.topMargin;
95 screenshot.take();
96 screenshot.transformOriginX = root.shortestDimension / 2;
97 screenshot.transformOriginY = root.shortestDimension / 2;
98 screenshot.visible = true;
99
100 window.rotation = 0;
101 window.width = spreadDelegate.width;
102 window.height = spreadDelegate.height;
103 window.transformOriginX = root.shortestDimension / 2;
104 window.transformOriginY = root.shortestDimension / 2;
105 }
106
107 function tearDown90Animation() {
108 window.orientationAngle = spreadDelegate.shellOrientationAngle;
109 screenshot.discard();
110 screenshot.visible = false;
111 background.visible = false;
112 }
113
114 property QtObject simple90Animation: SequentialAnimation {
115 id: simple90Animation
116
117 ScriptAction { script: setup90Animation() }
118 ParallelAnimation {
119 RotationAnimation {
120 target: root.window
121 duration: root.duration
122 easing.type: root.easingType
123 from: window.orientationAngle - spreadDelegate.shellOrientationAngle
124 to: 0
125 property: "transformRotationAngle"
126 }
127 RotationAnimation {
128 target: root.screenshot
129 duration: root.duration
130 easing.type: root.easingType
131 from: window.orientationAngle - spreadDelegate.shellOrientationAngle
132 to: 0
133 property: "transformRotationAngle"
134 }
135 NumberAnimation {
136 target: root.screenshot
137 duration: root.duration
138 easing.type: root.easingType
139 property: "opacity"
140 from: 1.0
141 to: 0.0
142 }
143 NumberAnimation {
144 target: root.window
145 duration: root.duration
146 easing.type: root.easingType
147 property: "opacity"
148 from: 0.0
149 to: 1.0
150 }
151 }
152 ScriptAction { script: tearDown90Animation() }
153 }
154
155 property QtObject moving90Animation: SequentialAnimation {
156 id: moving90Animation
157
158 ScriptAction { script: setup90Animation() }
159 ParallelAnimation {
160 RotationAnimation {
161 target: root.window
162 duration: root.duration
163 easing.type: root.easingType
164 direction: RotationAnimation.Shortest
165 from: window.orientationAngle - spreadDelegate.shellOrientationAngle
166 to: 0
167 property: "transformRotationAngle"
168 }
169 RotationAnimation {
170 target: root.screenshot
171 duration: root.duration
172 easing.type: root.easingType
173 direction: RotationAnimation.Shortest
174 from: window.orientationAngle - spreadDelegate.shellOrientationAngle
175 to: 0
176 property: "transformRotationAngle"
177 }
178 NumberAnimation {
179 target: root.screenshot
180 duration: root.duration
181 easing.type: root.easingType
182 property: "opacity"
183 from: 1.0
184 to: 0.0
185 }
186 NumberAnimation {
187 target: root.window
188 duration: root.duration
189 easing.type: root.easingType
190 property: "opacity"
191 from: 0.0
192 to: 1.0
193 }
194 NumberAnimation {
195 target: root.window
196 duration: root.duration
197 easing.type: root.easingType
198 property: root.longestAxis
199 from: root.longestDimension - root.shortestDimension
200 to: 0
201 }
202 NumberAnimation {
203 target: root.screenshot
204 duration: root.duration
205 easing.type: root.easingType
206 property: root.longestAxis
207 from: root.longestDimension - root.shortestDimension
208 to: 0
209 }
210 }
211 ScriptAction { script: tearDown90Animation() }
212 }
213
214 property QtObject halfLoopAnimation: SequentialAnimation {
215 id: halfLoopAnimation
216
217 ScriptAction { script: {
218 background.visible = true;
219
220 window.rotation = 0;
221 window.width = spreadDelegate.width;
222 window.height = spreadDelegate.height;
223 window.transformOriginX = window.width / 2
224 window.transformOriginY = window.height / 2
225 } }
226 ParallelAnimation {
227 RotationAnimation {
228 target: root.window
229 duration: root.duration
230 easing.type: root.easingType
231 from: window.orientationAngle - spreadDelegate.shellOrientationAngle
232 to: 0
233 property: "transformRotationAngle"
234 }
235 }
236 ScriptAction { script: {
237 window.orientationAngle = spreadDelegate.shellOrientationAngle;
238 background.visible = false;
239 } }
240 }
241}
0242
=== modified file 'qml/Stages/PhoneStage.qml'
--- qml/Stages/PhoneStage.qml 2015-04-10 21:16:37 +0000
+++ qml/Stages/PhoneStage.qml 2015-05-18 22:06:13 +0000
@@ -1,5 +1,5 @@
1/*1/*
2 * Copyright (C) 2014 Canonical, Ltd.2 * Copyright (C) 2014-2015 Canonical, Ltd.
3 *3 *
4 * This program is free software; you can redistribute it and/or modify4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by5 * it under the terms of the GNU General Public License as published by
@@ -31,12 +31,64 @@
31 property bool interactive31 property bool interactive
32 property bool spreadEnabled: true // If false, animations and right edge will be disabled32 property bool spreadEnabled: true // If false, animations and right edge will be disabled
33 property real inverseProgress: 0 // This is the progress for left edge drags, in pixels.33 property real inverseProgress: 0 // This is the progress for left edge drags, in pixels.
34 property int orientation: Qt.PortraitOrientation
35 property QtObject applicationManager: ApplicationManager34 property QtObject applicationManager: ApplicationManager
36 property bool focusFirstApp: true // If false, focused app will appear on right edge like other apps35 property bool focusFirstApp: true // If false, focused app will appear on right edge like other apps
37 property bool altTabEnabled: true36 property bool altTabEnabled: true
38 property real startScale: 1.137 property real startScale: 1.1
39 property real endScale: 0.738 property real endScale: 0.7
39 property int shellOrientationAngle: 0
40 property int shellOrientation
41 property int shellPrimaryOrientation
42 property int nativeOrientation
43 property real nativeWidth
44 property real nativeHeight
45 property bool beingResized: false
46 onBeingResizedChanged: {
47 if (beingResized) {
48 // Brace yourselves for impact!
49 spreadView.selectedIndex = -1;
50 spreadView.phase = 0;
51 spreadView.contentX = -spreadView.shift;
52 }
53 }
54 function updateFocusedAppOrientation() {
55 if (spreadRepeater.count > 0) {
56 spreadRepeater.itemAt(0).matchShellOrientation();
57 }
58
59 for (var i = 1; i < spreadRepeater.count; ++i) {
60
61 var spreadDelegate = spreadRepeater.itemAt(i);
62
63 var delta = spreadDelegate.appWindowOrientationAngle - root.shellOrientationAngle;
64 if (delta < 0) { delta += 360; }
65 delta = delta % 360;
66
67 var supportedOrientations = spreadDelegate.application.supportedOrientations;
68 if (supportedOrientations === Qt.PrimaryOrientation) {
69 supportedOrientations = spreadDelegate.shellPrimaryOrientation;
70 }
71
72 if (delta === 180 && (supportedOrientations & spreadDelegate.shellOrientation)) {
73 spreadDelegate.matchShellOrientation();
74 }
75 }
76 }
77 function updateFocusedAppOrientationAnimated() {
78 if (spreadRepeater.count > 0) {
79 spreadRepeater.itemAt(0).animateToShellOrientation();
80 }
81 }
82
83 // To be read from outside
84 readonly property var mainApp: applicationManager.focusedApplicationId
85 ? applicationManager.findApplication(applicationManager.focusedApplicationId)
86 : null
87 property int mainAppWindowOrientationAngle: 0
88 readonly property bool orientationChangesEnabled: priv.focusedAppOrientationChangesEnabled
89 && !priv.focusedAppDelegateIsDislocated
90 && !(priv.focusedAppDelegate && priv.focusedAppDelegate.xBehavior.running)
91 && spreadView.phase === 0
4092
41 // How far left the stage has been dragged93 // How far left the stage has been dragged
42 readonly property real dragProgress: spreadRepeater.count > 0 ? -spreadRepeater.itemAt(0).xTranslate : 094 readonly property real dragProgress: spreadRepeater.count > 0 ? -spreadRepeater.itemAt(0).xTranslate : 0
@@ -54,12 +106,6 @@
54 spreadView.snapTo(priv.indexOf(appId));106 spreadView.snapTo(priv.indexOf(appId));
55 }107 }
56108
57 onWidthChanged: {
58 spreadView.selectedIndex = -1;
59 spreadView.phase = 0;
60 spreadView.contentX = -spreadView.shift;
61 }
62
63 onInverseProgressChanged: {109 onInverseProgressChanged: {
64 // This can't be a simple binding because that would be triggered after this handler110 // This can't be a simple binding because that would be triggered after this handler
65 // while we need it active before doing the anition left/right111 // while we need it active before doing the anition left/right
@@ -73,6 +119,20 @@
73 priv.oldInverseProgress = inverseProgress;119 priv.oldInverseProgress = inverseProgress;
74 }120 }
75121
122 // <FIXME-contentX> See rationale in the next comment with this tag
123 onWidthChanged: {
124 if (!root.beingResized) {
125 // we're being resized without a warning (ie, the corresponding property wasn't set
126 root.beingResized = true;
127 beingResizedTimer.start();
128 }
129 }
130 Timer {
131 id: beingResizedTimer
132 interval: 100
133 onTriggered: { root.beingResized = false; }
134 }
135
76 Connections {136 Connections {
77 target: applicationManager137 target: applicationManager
78138
@@ -115,10 +175,10 @@
115 QtObject {175 QtObject {
116 id: priv176 id: priv
117177
118 readonly property int firstSpreadIndex: root.focusFirstApp ? 1 : 0178 property string focusedAppId: root.applicationManager.focusedApplicationId
119 property string focusedAppId: applicationManager.focusedApplicationId179 property var focusedApplication: root.applicationManager.findApplication(focusedAppId)
120 property var focusedApplication: applicationManager.findApplication(focusedAppId)
121 property var focusedAppDelegate: null180 property var focusedAppDelegate: null
181 property bool focusedAppOrientationChangesEnabled: false
122182
123 property real oldInverseProgress: 0183 property real oldInverseProgress: 0
124 property bool animateX: false184 property bool animateX: false
@@ -131,15 +191,27 @@
131 }191 }
132 }192 }
133193
194 property bool focusedAppDelegateIsDislocated: focusedAppDelegate && focusedAppDelegate.x !== 0
195
134 function indexOf(appId) {196 function indexOf(appId) {
135 for (var i = 0; i < applicationManager.count; i++) {197 for (var i = 0; i < root.applicationManager.count; i++) {
136 if (applicationManager.get(i).appId == appId) {198 if (root.applicationManager.get(i).appId == appId) {
137 return i;199 return i;
138 }200 }
139 }201 }
140 return -1;202 return -1;
141 }203 }
142204
205 // Is more stable than "spreadView.shiftedContentX === 0" as it filters out noise caused by
206 // Flickable.contentX changing due to resizes.
207 property bool fullyShowingFocusedApp: true
208 }
209 Timer {
210 id: fullyShowingFocusedAppUpdateTimer
211 interval: 100
212 onTriggered: {
213 priv.fullyShowingFocusedApp = spreadView.shiftedContentX === 0;
214 }
143 }215 }
144216
145 Flickable {217 Flickable {
@@ -187,9 +259,25 @@
187 property int draggedDelegateCount: 0259 property int draggedDelegateCount: 0
188 property int closingIndex: -1260 property int closingIndex: -1
189261
190 property bool focusChanging: false262 // <FIXME-contentX> Workaround Flickable's behavior of bringing contentX back between valid boundaries
263 // when resized. The proper way to fix this is refactoring PhoneStage so that it doesn't
264 // rely on having Flickable.contentX keeping an out-of-bounds value when it's set programatically
265 // (as opposed to having contentX reaching an out-of-bounds value through dragging, which will trigger
266 // the Flickable.boundsBehavior upon release).
267 onContentXChanged: { forceItToRemainStillIfBeingResized(); }
268 onShiftChanged: { forceItToRemainStillIfBeingResized(); }
269 function forceItToRemainStillIfBeingResized() {
270 if (root.beingResized && contentX != -spreadView.shift) {
271 contentX = -spreadView.shift;
272 }
273 }
191274
192 onShiftedContentXChanged: {275 onShiftedContentXChanged: {
276 if (root.beingResized) {
277 // Flickabe.contentX wiggles during resizes. Don't react to it.
278 return;
279 }
280
193 switch (phase) {281 switch (phase) {
194 case 0:282 case 0:
195 if (shiftedContentX > width * positionMarker2) {283 if (shiftedContentX > width * positionMarker2) {
@@ -204,6 +292,7 @@
204 }292 }
205 break;293 break;
206 }294 }
295 fullyShowingFocusedAppUpdateTimer.restart();
207 }296 }
208297
209 function snap() {298 function snap() {
@@ -228,7 +317,7 @@
228 snapAnimation.start();317 snapAnimation.start();
229 return;318 return;
230 }319 }
231 if (applicationManager.count <= index) {320 if (root.applicationManager.count <= index) {
232 // In case we're trying to snap to some non existing app, lets snap back to the first one321 // In case we're trying to snap to some non existing app, lets snap back to the first one
233 index = 0;322 index = 0;
234 }323 }
@@ -265,7 +354,7 @@
265 ScriptAction {354 ScriptAction {
266 script: {355 script: {
267 if (spreadView.selectedIndex >= 0) {356 if (spreadView.selectedIndex >= 0) {
268 applicationManager.focusApplication(applicationManager.get(spreadView.selectedIndex).appId);357 root.applicationManager.focusApplication(root.applicationManager.get(spreadView.selectedIndex).appId);
269358
270 spreadView.selectedIndex = -1;359 spreadView.selectedIndex = -1;
271 spreadView.phase = 0;360 spreadView.phase = 0;
@@ -280,7 +369,7 @@
280 // This width controls how much the spread can be flicked left/right. It's composed of:369 // This width controls how much the spread can be flicked left/right. It's composed of:
281 // tileDistance * app count (with a minimum of 3 apps, in order to also allow moving 1 and 2 apps a bit)370 // tileDistance * app count (with a minimum of 3 apps, in order to also allow moving 1 and 2 apps a bit)
282 // + some constant value (still scales with the screen width) which looks good and somewhat fills the screen371 // + some constant value (still scales with the screen width) which looks good and somewhat fills the screen
283 width: Math.max(3, applicationManager.count) * spreadView.tileDistance + (spreadView.width - spreadView.tileDistance) * 1.5372 width: Math.max(3, root.applicationManager.count) * spreadView.tileDistance + (spreadView.width - spreadView.tileDistance) * 1.5
284 height: parent.height373 height: parent.height
285 Behavior on width {374 Behavior on width {
286 enabled: spreadView.closingIndex >= 0375 enabled: spreadView.closingIndex >= 0
@@ -303,7 +392,7 @@
303 Repeater {392 Repeater {
304 id: spreadRepeater393 id: spreadRepeater
305 objectName: "spreadRepeater"394 objectName: "spreadRepeater"
306 model: applicationManager395 model: root.applicationManager
307 delegate: TransformedSpreadDelegate {396 delegate: TransformedSpreadDelegate {
308 id: appDelegate397 id: appDelegate
309 objectName: "appDelegate" + index398 objectName: "appDelegate" + index
@@ -318,11 +407,10 @@
318 selected: spreadView.selectedIndex == index407 selected: spreadView.selectedIndex == index
319 otherSelected: spreadView.selectedIndex >= 0 && !selected408 otherSelected: spreadView.selectedIndex >= 0 && !selected
320 interactive: !spreadView.interactive && spreadView.phase === 0409 interactive: !spreadView.interactive && spreadView.phase === 0
321 && spreadView.shiftedContentX === 0 && root.interactive && isFocused410 && priv.fullyShowingFocusedApp && root.interactive && isFocused
322 swipeToCloseEnabled: spreadView.interactive && root.interactive && !snapAnimation.running411 swipeToCloseEnabled: spreadView.interactive && root.interactive && !snapAnimation.running
323 maximizedAppTopMargin: root.maximizedAppTopMargin412 maximizedAppTopMargin: root.maximizedAppTopMargin
324 dropShadow: spreadView.active ||413 dropShadow: spreadView.active || priv.focusedAppDelegateIsDislocated
325 (priv.focusedAppDelegate && priv.focusedAppDelegate.x !== 0)
326 focusFirstApp: root.focusFirstApp414 focusFirstApp: root.focusFirstApp
327415
328 readonly property bool isDash: model.appId == "unity8-dash"416 readonly property bool isDash: model.appId == "unity8-dash"
@@ -345,7 +433,7 @@
345 return spreadView.width + spreadIndex * spreadView.tileDistance;433 return spreadView.width + spreadIndex * spreadView.tileDistance;
346 }434 }
347435
348 application: applicationManager.get(index)436 application: root.applicationManager.get(index)
349 closeable: !isDash437 closeable: !isDash
350438
351 property real behavioredIndex: index439 property real behavioredIndex: index
@@ -361,18 +449,16 @@
361 }449 }
362 }450 }
363451
452 property var xBehavior: xBehavior
364 Behavior on x {453 Behavior on x {
454 id: xBehavior
365 enabled: root.spreadEnabled &&455 enabled: root.spreadEnabled &&
366 !spreadView.active &&456 !spreadView.active &&
367 !snapAnimation.running &&457 !snapAnimation.running &&
368 priv.animateX458 priv.animateX &&
459 !root.beingResized
369 UbuntuNumberAnimation {460 UbuntuNumberAnimation {
370 duration: UbuntuAnimation.BriskDuration461 duration: UbuntuAnimation.BriskDuration
371 onRunningChanged: {
372 if (!running && root.inverseProgress == 0) {
373 spreadView.focusChanging = false;
374 }
375 }
376 }462 }
377 }463 }
378464
@@ -412,22 +498,21 @@
412 }498 }
413499
414 // Hiding tiles when their progress is negative or reached the maximum500 // Hiding tiles when their progress is negative or reached the maximum
415 visible: (progress >= 0 && progress < 1.7) ||501 visible: (progress >= 0 && progress < 1.7)
416 (isDash && priv.focusedAppDelegate.x !== 0)502 || (isDash && priv.focusedAppDelegateIsDislocated)
417503
418 Binding {504
419 target: appDelegate505 shellOrientationAngle: root.shellOrientationAngle
420 property: "orientation"506 shellOrientation: root.shellOrientation
421 when: appDelegate.interactive507 shellPrimaryOrientation: root.shellPrimaryOrientation
422 value: root.orientation508 nativeOrientation: root.nativeOrientation
423 }
424509
425 onClicked: {510 onClicked: {
426 if (root.altTabEnabled && spreadView.phase == 2) {511 if (root.altTabEnabled && spreadView.phase == 2) {
427 if (applicationManager.focusedApplicationId == applicationManager.get(index).appId) {512 if (root.applicationManager.focusedApplicationId == root.applicationManager.get(index).appId) {
428 spreadView.snapTo(index);513 spreadView.snapTo(index);
429 } else {514 } else {
430 applicationManager.requestFocusApplication(applicationManager.get(index).appId);515 root.applicationManager.requestFocusApplication(root.applicationManager.get(index).appId);
431 }516 }
432 }517 }
433 }518 }
@@ -442,7 +527,20 @@
442527
443 onClosed: {528 onClosed: {
444 spreadView.closingIndex = index;529 spreadView.closingIndex = index;
445 applicationManager.stopApplication(applicationManager.get(index).appId);530 root.applicationManager.stopApplication(root.applicationManager.get(index).appId);
531 }
532
533 Binding {
534 target: root
535 when: index == 0
536 property: "mainAppWindowOrientationAngle"
537 value: appWindowOrientationAngle
538 }
539 Binding {
540 target: priv
541 when: index == 0
542 property: "focusedAppOrientationChangesEnabled"
543 value: orientationChangesEnabled
446 }544 }
447 }545 }
448 }546 }
449547
=== modified file 'qml/Stages/SessionContainer.qml'
--- qml/Stages/SessionContainer.qml 2015-01-28 12:59:21 +0000
+++ qml/Stages/SessionContainer.qml 2015-05-18 22:06:13 +0000
@@ -1,5 +1,5 @@
1/*1/*
2 * Copyright 2014 Canonical Ltd.2 * Copyright 2014-2015 Canonical Ltd.
3 *3 *
4 * This program is free software; you can redistribute it and/or modify4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published by5 * it under the terms of the GNU Lesser General Public License as published by
@@ -24,14 +24,13 @@
24 readonly property var childSessions: session ? session.childSessions : null24 readonly property var childSessions: session ? session.childSessions : null
25 readonly property alias surface: _surfaceContainer.surface25 readonly property alias surface: _surfaceContainer.surface
26 property alias interactive: _surfaceContainer.interactive26 property alias interactive: _surfaceContainer.interactive
27 property int orientation27 property alias surfaceOrientationAngle: _surfaceContainer.surfaceOrientationAngle
2828
29 readonly property alias surfaceContainer: _surfaceContainer29 readonly property alias surfaceContainer: _surfaceContainer
30 SurfaceContainer {30 SurfaceContainer {
31 id: _surfaceContainer31 id: _surfaceContainer
32 anchors.fill: parent32 anchors.fill: parent
33 surface: session ? session.surface : null33 surface: session ? session.surface : null
34 orientation: root.orientation
35 }34 }
3635
37 Repeater {36 Repeater {
@@ -72,11 +71,6 @@
72 target: item; when: item71 target: item; when: item
73 property: "height"; value: root.height72 property: "height"; value: root.height
74 }73 }
75
76 Binding {
77 target: item; when: item
78 property: "orientation"; value: root.orientation
79 }
80 }74 }
81 }75 }
8276
8377
=== modified file 'qml/Stages/SpreadDelegate.qml'
--- qml/Stages/SpreadDelegate.qml 2015-01-28 12:59:21 +0000
+++ qml/Stages/SpreadDelegate.qml 2015-05-18 22:06:13 +0000
@@ -1,5 +1,5 @@
1/*1/*
2 * Copyright 2014 Canonical Ltd.2 * Copyright 2014-2015 Canonical Ltd.
3 *3 *
4 * This program is free software; you can redistribute it and/or modify4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published by5 * it under the terms of the GNU Lesser General Public License as published by
@@ -18,6 +18,7 @@
18 */18 */
1919
20import QtQuick 2.020import QtQuick 2.0
21import QtQuick.Window 2.0
21import Ubuntu.Components 1.122import Ubuntu.Components 1.1
22import "../Components"23import "../Components"
2324
@@ -28,6 +29,9 @@
28 readonly property bool dragged: dragArea.moving29 readonly property bool dragged: dragArea.moving
29 signal clicked()30 signal clicked()
30 signal closed()31 signal closed()
32 readonly property alias appWindowOrientationAngle: appWindowWithShadow.orientationAngle
33 readonly property alias appWindowRotation: appWindowWithShadow.rotation
34 readonly property alias orientationChangesEnabled: appWindow.orientationChangesEnabled
3135
32 // to be set from outside36 // to be set from outside
33 property bool interactive: true37 property bool interactive: true
@@ -36,10 +40,54 @@
36 property alias swipeToCloseEnabled: dragArea.enabled40 property alias swipeToCloseEnabled: dragArea.enabled
37 property bool closeable41 property bool closeable
38 property alias application: appWindow.application42 property alias application: appWindow.application
39 property int orientation43 property int shellOrientationAngle
44 property int shellOrientation
45 property int shellPrimaryOrientation
46 property int nativeOrientation
47
48 function matchShellOrientation() {
49 if (!root.application)
50 return;
51 appWindowWithShadow.orientationAngle = root.shellOrientationAngle;
52 }
53
54 function animateToShellOrientation() {
55 if (!root.application)
56 return;
57
58 if (root.application.rotatesWindowContents) {
59 appWindowWithShadow.orientationAngle = root.shellOrientationAngle;
60 } else {
61 orientationChangeAnimation.start();
62 }
63 }
64
65 OrientationChangeAnimation {
66 id: orientationChangeAnimation
67 objectName: "orientationChangeAnimation"
68 spreadDelegate: root
69 background: background
70 window: appWindowWithShadow
71 screenshot: appWindowScreenshotWithShadow
72 }
73
74 QtObject {
75 id: priv
76 property bool startingUp: true
77 }
78
79 Component.onCompleted: { finishStartUpTimer.start(); }
80 Timer { id: finishStartUpTimer; interval: 400; onTriggered: priv.startingUp = false }
81
82 Rectangle {
83 id: background
84 color: "black"
85 anchors.fill: parent
86 visible: false
87 }
4088
41 Item {89 Item {
42 objectName: "appWindowWithShadow"90 objectName: "displacedAppWindowWithShadow"
4391
44 readonly property real limit: root.height / 492 readonly property real limit: root.height / 4
4593
@@ -52,27 +100,220 @@
52 return k * (1 - Math.pow((k - 1) / k, distance))100 return k * (1 - Math.pow((k - 1) / k, distance))
53 }101 }
54102
55 BorderImage {103 Item {
56 anchors {104 id: appWindowWithShadow
57 fill: appWindow105 objectName: "appWindowWithShadow"
58 margins: -units.gu(2)106
59 }107 property int orientationAngle
60 source: "graphics/dropshadow2gu.sci"108
61 opacity: root.dropShadow ? .3 : 0109 property real transformRotationAngle: 0
62 Behavior on opacity { UbuntuNumberAnimation {} }110 property real transformOriginX
63 }111 property real transformOriginY
64112
65 ApplicationWindow {113 property var window: appWindow
66 id: appWindow114
67 objectName: application ? "appWindow_" + application.appId : "appWindow_null"115 transform: Rotation {
68 focus: true116 origin.x: appWindowWithShadow.transformOriginX
69 anchors {117 origin.y: appWindowWithShadow.transformOriginY
70 fill: parent118 axis { x: 0; y: 0; z: 1 }
71 topMargin: appWindow.fullscreen ? 0 : maximizedAppTopMargin119 angle: appWindowWithShadow.transformRotationAngle
72 }120 }
73121
74 interactive: root.interactive122 state: {
75 orientation: root.orientation123 if (priv.startingUp) {
124 return "startingUp";
125 } else if (root.application && root.application.rotatesWindowContents) {
126 return "counterRotate";
127 } else if (orientationChangeAnimation.running) {
128 return "animatingRotation";
129 } else {
130 return "keepSceneRotation";
131 }
132 }
133
134 // Ensures the given angle is in the form (0,90,180,270)
135 function normalizeAngle(angle) {
136 while (angle < 0) {
137 angle += 360;
138 }
139 return angle % 360;
140 }
141
142 states: [
143 // Sets the initial orientationAngle of the window, when it first slides into view
144 // (with the splash screen likely being displayed). At that point we just try to
145 // match shell's current orientation. We need a bit of time in this state as the
146 // information we need to decide orientationAngle may take a few cycles to
147 // be set.
148 State {
149 name: "startingUp"
150 PropertyChanges {
151 target: appWindowWithShadow
152 restoreEntryValues: false
153 orientationAngle: {
154 if (!root.application || root.application.rotatesWindowContents) {
155 return 0;
156 }
157 var supportedOrientations = root.application.supportedOrientations;
158
159 if (supportedOrientations === Qt.PrimaryOrientation) {
160 supportedOrientations = root.shellPrimaryOrientation;
161 }
162
163 // If it doesn't support shell's current orientation
164 // then simply pick some arbitraty one that it does support
165 var chosenOrientation = 0;
166 if (supportedOrientations & root.shellOrientation) {
167 chosenOrientation = root.shellOrientation;
168 } else if (supportedOrientations & Qt.PortraitOrientation) {
169 chosenOrientation = Qt.PortraitOrientation;
170 } else if (supportedOrientations & Qt.LandscapeOrientation) {
171 chosenOrientation = Qt.LandscapeOrientation;
172 } else if (supportedOrientations & Qt.InvertedPortraitOrientation) {
173 chosenOrientation = Qt.InvertedPortraitOrientation;
174 } else if (supportedOrientations & Qt.InvertedLandscapeOrientation) {
175 chosenOrientation = Qt.InvertedLandscapeOrientation;
176 } else {
177 chosenOrientation = root.shellPrimaryOrientation;
178 }
179
180 return Screen.angleBetween(root.nativeOrientation, chosenOrientation);
181 }
182
183 rotation: normalizeAngle(appWindowWithShadow.orientationAngle - root.shellOrientationAngle)
184 width: {
185 if (rotation == 0 || rotation == 180) {
186 return root.width;
187 } else {
188 return root.height;
189 }
190 }
191 height: {
192 if (rotation == 0 || rotation == 180)
193 return root.height;
194 else
195 return root.width;
196 }
197 }
198 },
199 // In this state we stick to our currently set orientationAngle, which may change only due
200 // to calls made to matchShellOrientation() or animateToShellOrientation()
201 State {
202 id: keepSceneRotationState
203 name: "keepSceneRotation"
204
205 StateChangeScript { script: {
206 // break binding
207 appWindowWithShadow.orientationAngle = appWindowWithShadow.orientationAngle;
208 } }
209 PropertyChanges {
210 target: appWindowWithShadow
211 restoreEntryValues: false
212 rotation: normalizeAngle(appWindowWithShadow.orientationAngle - root.shellOrientationAngle)
213 width: {
214 if (rotation == 0 || rotation == 180) {
215 return root.width;
216 } else {
217 return root.height;
218 }
219 }
220 height: {
221 if (rotation == 0 || rotation == 180)
222 return root.height;
223 else
224 return root.width;
225 }
226 }
227 },
228 // In this state we counteract any shell rotation so that the window, in scene coordinates,
229 // remains unrotated.
230 State {
231 name: "counterRotate"
232 StateChangeScript { script: {
233 // break binding
234 appWindowWithShadow.orientationAngle = appWindowWithShadow.orientationAngle;
235 } }
236 PropertyChanges {
237 target: appWindowWithShadow
238 width: root.shellOrientationAngle == 0 || root.shellOrientationAngle == 180 ? root.width : root.height
239 height: root.shellOrientationAngle == 0 || root.shellOrientationAngle == 180 ? root.height : root.width
240 rotation: normalizeAngle(-root.shellOrientationAngle)
241 }
242 PropertyChanges {
243 target: appWindow
244 surfaceOrientationAngle: orientationAngle
245 }
246 },
247 State {
248 name: "animatingRotation"
249 }
250 ]
251
252 x: (parent.width - width) / 2
253 y: (parent.height - height) / 2
254
255 BorderImage {
256 anchors {
257 fill: appWindow
258 margins: -units.gu(2)
259 }
260 source: "graphics/dropshadow2gu.sci"
261 opacity: root.dropShadow ? .3 : 0
262 Behavior on opacity { UbuntuNumberAnimation {} }
263 }
264
265 ApplicationWindow {
266 id: appWindow
267 objectName: application ? "appWindow_" + application.appId : "appWindow_null"
268 focus: true
269 anchors {
270 fill: parent
271 topMargin: appWindow.fullscreen || application.rotatesWindowContents
272 ? 0 : maximizedAppTopMargin
273 }
274
275 interactive: root.interactive
276 }
277 }
278 }
279
280 Item {
281 // mimics appWindowWithShadow. Do the positioning of screenshots of non-fullscreen
282 // app windows
283 id: appWindowScreenshotWithShadow
284 visible: false
285
286 property real transformRotationAngle: 0
287 property real transformOriginX
288 property real transformOriginY
289
290 transform: Rotation {
291 origin.x: appWindowScreenshotWithShadow.transformOriginX
292 origin.y: appWindowScreenshotWithShadow.transformOriginY
293 axis { x: 0; y: 0; z: 1 }
294 angle: appWindowScreenshotWithShadow.transformRotationAngle
295 }
296
297 property var window: appWindowScreenshot
298
299 function take() {
300 // Format: "image://application/$APP_ID/$CURRENT_TIME_MS"
301 // eg: "image://application/calculator-app/123456"
302 var timeMs = new Date().getTime();
303 appWindowScreenshot.source = "image://application/" + root.application.appId + "/" + timeMs;
304 }
305 function discard() {
306 appWindowScreenshot.source = "";
307 }
308
309 Image {
310 id: appWindowScreenshot
311 source: ""
312
313 anchors.fill: parent
314
315 sourceSize.width: width
316 sourceSize.height: height
76 }317 }
77 }318 }
78319
79320
=== modified file 'qml/Stages/SurfaceContainer.qml'
--- qml/Stages/SurfaceContainer.qml 2015-03-12 18:55:52 +0000
+++ qml/Stages/SurfaceContainer.qml 2015-05-18 22:06:13 +0000
@@ -24,8 +24,8 @@
24 objectName: "surfaceContainer"24 objectName: "surfaceContainer"
25 property Item surface: null25 property Item surface: null
26 property bool hadSurface: false26 property bool hadSurface: false
27 property int orientation
28 property bool interactive27 property bool interactive
28 property int surfaceOrientationAngle: 0
2929
30 onSurfaceChanged: {30 onSurfaceChanged: {
31 if (surface) {31 if (surface) {
@@ -39,10 +39,10 @@
39 }39 }
40 }40 }
41 Binding { target: surface; property: "anchors.fill"; value: root }41 Binding { target: surface; property: "anchors.fill"; value: root }
42 Binding { target: surface; property: "orientation"; value: root.orientation }
43 Binding { target: surface; property: "z"; value: 1 }42 Binding { target: surface; property: "z"; value: 1 }
44 Binding { target: surface; property: "enabled"; value: root.interactive; when: surface }43 Binding { target: surface; property: "enabled"; value: root.interactive; when: surface }
45 Binding { target: surface; property: "antialiasing"; value: !root.interactive; when: surface }44 Binding { target: surface; property: "antialiasing"; value: !root.interactive; when: surface }
45 Binding { target: surface; property: "orientationAngle"; value: root.surfaceOrientationAngle; when: surface }
4646
47 InputWatcher {47 InputWatcher {
48 target: root.surface48 target: root.surface
4949
=== modified file 'qml/Stages/TabletStage.qml'
--- qml/Stages/TabletStage.qml 2015-04-10 21:16:37 +0000
+++ qml/Stages/TabletStage.qml 2015-05-18 22:06:13 +0000
@@ -1,5 +1,5 @@
1/*1/*
2 * Copyright (C) 2014 Canonical, Ltd.2 * Copyright (C) 2014-2015 Canonical, Ltd.
3 *3 *
4 * This program is free software; you can redistribute it and/or modify4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by5 * it under the terms of the GNU General Public License as published by
@@ -28,13 +28,79 @@
28 color: "#111111"28 color: "#111111"
2929
30 // Controls to be set from outside30 // Controls to be set from outside
31 property bool shown: false
32 property bool moving: false
33 property int dragAreaWidth31 property int dragAreaWidth
34 property real maximizedAppTopMargin32 property real maximizedAppTopMargin
35 property bool interactive33 property bool interactive
34 property alias beingResized: spreadView.beingResized
35
36 property bool spreadEnabled: true // If false, animations and right edge will be disabled
37
36 property real inverseProgress: 0 // This is the progress for left edge drags, in pixels.38 property real inverseProgress: 0 // This is the progress for left edge drags, in pixels.
37 property int orientation: Qt.PortraitOrientation39 property int shellOrientationAngle: 0
40 property int shellOrientation
41 property int shellPrimaryOrientation
42 property int nativeOrientation
43 property real nativeWidth
44 property real nativeHeight
45 function updateFocusedAppOrientation() {
46 var mainStageAppIndex = priv.indexOf(priv.mainStageAppId);
47 if (mainStageAppIndex >= 0 && mainStageAppIndex < spreadRepeater.count) {
48 spreadRepeater.itemAt(mainStageAppIndex).matchShellOrientation();
49 }
50
51 for (var i = 0; i < spreadRepeater.count; ++i) {
52
53 if (i === mainStageAppIndex) {
54 continue;
55 }
56
57 var spreadDelegate = spreadRepeater.itemAt(i);
58
59 var delta = spreadDelegate.appWindowOrientationAngle - root.shellOrientationAngle;
60 if (delta < 0) { delta += 360; }
61 delta = delta % 360;
62
63 var supportedOrientations = spreadDelegate.application.supportedOrientations;
64 if (supportedOrientations === Qt.PrimaryOrientation) {
65 supportedOrientations = spreadDelegate.shellPrimaryOrientation;
66 }
67
68 if (delta === 180 && (supportedOrientations & spreadDelegate.shellOrientation)) {
69 spreadDelegate.matchShellOrientation();
70 }
71 }
72 }
73 function updateFocusedAppOrientationAnimated() {
74 var mainStageAppIndex = priv.indexOf(priv.mainStageAppId);
75 if (mainStageAppIndex >= 0 && mainStageAppIndex < spreadRepeater.count) {
76 spreadRepeater.itemAt(mainStageAppIndex).animateToShellOrientation();
77 }
78
79 if (priv.sideStageAppId) {
80 var sideStageAppIndex = priv.indexOf(priv.sideStageAppId);
81 if (sideStageAppIndex >= 0 && sideStageAppIndex < spreadRepeater.count) {
82 spreadRepeater.itemAt(sideStageAppIndex).matchShellOrientation();
83 }
84 }
85 }
86
87 // To be read from outside
88 property var mainApp: null
89 property int mainAppWindowOrientationAngle: 0
90 readonly property bool orientationChangesEnabled: priv.mainAppOrientationChangesEnabled
91
92 onWidthChanged: {
93 spreadView.selectedIndex = -1;
94 spreadView.phase = 0;
95 spreadView.contentX = -spreadView.shift;
96 }
97
98 onShellOrientationChanged: {
99 if (shellOrientation == Qt.PortraitOrientation || shellOrientation == Qt.InvertedPortraitOrientation) {
100 ApplicationManager.focusApplication(priv.mainStageAppId);
101 priv.sideStageAppId = "";
102 }
103 }
38104
39 onInverseProgressChanged: {105 onInverseProgressChanged: {
40 // This can't be a simple binding because that would be triggered after this handler106 // This can't be a simple binding because that would be triggered after this handler
@@ -54,6 +120,13 @@
54120
55 property string focusedAppId: ApplicationManager.focusedApplicationId121 property string focusedAppId: ApplicationManager.focusedApplicationId
56 property string oldFocusedAppId: ""122 property string oldFocusedAppId: ""
123 property bool mainAppOrientationChangesEnabled: false
124
125 property real landscapeHeight: root.nativeOrientation == Qt.LandscapeOrientation ?
126 root.nativeHeight : root.nativeWidth
127
128 property bool shellIsLandscape: root.shellOrientation === Qt.LandscapeOrientation
129 || root.shellOrientation === Qt.InvertedLandscapeOrientation
57130
58 property string mainStageAppId131 property string mainStageAppId
59 property string sideStageAppId132 property string sideStageAppId
@@ -71,6 +144,7 @@
71 priv.sideStageAppId = focusedAppId;144 priv.sideStageAppId = focusedAppId;
72 } else {145 } else {
73 priv.mainStageAppId = focusedAppId;146 priv.mainStageAppId = focusedAppId;
147 root.mainApp = focusedApp;
74 }148 }
75 }149 }
76150
@@ -169,6 +243,7 @@
169243
170 Flickable {244 Flickable {
171 id: spreadView245 id: spreadView
246 objectName: "spreadView"
172 anchors.fill: parent247 anchors.fill: parent
173 interactive: (spreadDragArea.dragging || phase > 1) && draggedDelegateCount === 0248 interactive: (spreadDragArea.dragging || phase > 1) && draggedDelegateCount === 0
174 contentWidth: spreadRow.width - shift249 contentWidth: spreadRow.width - shift
@@ -217,7 +292,25 @@
217 property int draggedDelegateCount: 0292 property int draggedDelegateCount: 0
218 property int closingIndex: -1293 property int closingIndex: -1
219294
295 // FIXME: Workaround Flickable's not keepping its contentX still when resized
296 onContentXChanged: { forceItToRemainStillIfBeingResized(); }
297 onShiftChanged: { forceItToRemainStillIfBeingResized(); }
298 function forceItToRemainStillIfBeingResized() {
299 if (root.beingResized && contentX != -shift) {
300 contentX = -shift;
301 }
302 }
303
220 property bool animateX: true304 property bool animateX: true
305 property bool beingResized: false
306 onBeingResizedChanged: {
307 if (beingResized) {
308 // Brace yourselves for impact!
309 selectedIndex = -1;
310 phase = 0;
311 contentX = -shift;
312 }
313 }
221314
222 property bool sideStageDragging: sideStageDragHandle.dragging315 property bool sideStageDragging: sideStageDragHandle.dragging
223 property real sideStageDragProgress: sideStageDragHandle.progress316 property real sideStageDragProgress: sideStageDragHandle.progress
@@ -256,7 +349,6 @@
256 case "overlay":349 case "overlay":
257 return 1;350 return 1;
258 }351 }
259 print("Unhandled nextInStack case! This shouldn't happen any more when the Dash is an app!");
260 return -1;352 return -1;
261 }353 }
262 property int nextZInStack: indexToZIndex(nextInStack)354 property int nextZInStack: indexToZIndex(nextInStack)
@@ -292,6 +384,10 @@
292 }384 }
293385
294 onShiftedContentXChanged: {386 onShiftedContentXChanged: {
387 if (root.beingResized) {
388 // Flickabe.contentX wiggles during resizes. Don't react to it.
389 return;
390 }
295 if (spreadView.phase == 0 && spreadView.shiftedContentX > spreadView.width * spreadView.positionMarker2) {391 if (spreadView.phase == 0 && spreadView.shiftedContentX > spreadView.width * spreadView.positionMarker2) {
296 spreadView.phase = 1;392 spreadView.phase = 1;
297 } else if (spreadView.phase == 1 && spreadView.shiftedContentX > spreadView.width * spreadView.positionMarker4) {393 } else if (spreadView.phase == 1 && spreadView.shiftedContentX > spreadView.width * spreadView.positionMarker4) {
@@ -401,8 +497,8 @@
401 MouseArea {497 MouseArea {
402 id: spreadRow498 id: spreadRow
403 x: spreadView.contentX499 x: spreadView.contentX
500 width: spreadView.width + Math.max(spreadView.width, ApplicationManager.count * spreadView.tileDistance)
404 height: root.height501 height: root.height
405 width: spreadView.width + Math.max(spreadView.width, ApplicationManager.count * spreadView.tileDistance)
406502
407 onClicked: {503 onClicked: {
408 spreadView.snapTo(0);504 spreadView.snapTo(0);
@@ -411,8 +507,9 @@
411 Rectangle {507 Rectangle {
412 id: sideStageBackground508 id: sideStageBackground
413 color: "black"509 color: "black"
414 anchors.fill: parent510 width: spreadView.sideStageWidth * (1 - sideStageDragHandle.progress)
415 anchors.leftMargin: spreadView.width - (1 - sideStageDragHandle.progress) * spreadView.sideStageWidth511 height: priv.landscapeHeight
512 x: spreadView.width - width
416 z: spreadView.indexToZIndex(priv.indexOf(priv.sideStageAppId))513 z: spreadView.indexToZIndex(priv.indexOf(priv.sideStageAppId))
417 opacity: spreadView.phase == 0 ? 1 : 0514 opacity: spreadView.phase == 0 ? 1 : 0
418 Behavior on opacity { UbuntuNumberAnimation {} }515 Behavior on opacity { UbuntuNumberAnimation {} }
@@ -420,8 +517,10 @@
420517
421 Item {518 Item {
422 id: sideStageDragHandle519 id: sideStageDragHandle
423 anchors { top: parent.top; bottom: parent.bottom; left: parent.left; leftMargin: spreadView.width - spreadView.sideStageWidth - width }520 anchors.right: sideStageBackground.left
521 anchors.top: sideStageBackground.top
424 width: units.gu(2)522 width: units.gu(2)
523 height: priv.landscapeHeight
425 z: sideStageBackground.z524 z: sideStageBackground.z
426 opacity: spreadView.phase <= 0 && spreadView.sideStageVisible ? 1 : 0525 opacity: spreadView.phase <= 0 && spreadView.sideStageVisible ? 1 : 0
427 property real progress: 0526 property real progress: 0
@@ -440,7 +539,6 @@
440539
441 Image {540 Image {
442 anchors.centerIn: parent541 anchors.centerIn: parent
443 anchors.horizontalCenterOffset: parent.progress * spreadView.sideStageWidth - (width - parent.width) / 2
444 width: sideStageDragHandleMouseArea.pressed ? parent.width * 2 : parent.width542 width: sideStageDragHandleMouseArea.pressed ? parent.width * 2 : parent.width
445 height: parent.height543 height: parent.height
446 source: "graphics/sidestage_handle@20.png"544 source: "graphics/sidestage_handle@20.png"
@@ -453,16 +551,19 @@
453 enabled: spreadView.shiftedContentX == 0551 enabled: spreadView.shiftedContentX == 0
454 property int startX552 property int startX
455 property var gesturePoints: new Array()553 property var gesturePoints: new Array()
554 property real totalDiff
456555
457 onPressed: {556 onPressed: {
458 gesturePoints = [];557 gesturePoints = [];
459 startX = mouseX;558 startX = mouseX;
559 totalDiff = 0.0;
460 sideStageDragHandle.progress = 0;560 sideStageDragHandle.progress = 0;
461 sideStageDragHandle.dragging = true;561 sideStageDragHandle.dragging = true;
462 }562 }
463 onMouseXChanged: {563 onMouseXChanged: {
564 totalDiff += mouseX - startX;
464 if (priv.mainStageAppId) {565 if (priv.mainStageAppId) {
465 sideStageDragHandle.progress = Math.max(0, (-startX + mouseX) / spreadView.sideStageWidth);566 sideStageDragHandle.progress = Math.max(0, totalDiff / spreadView.sideStageWidth);
466 }567 }
467 gesturePoints.push(mouseX);568 gesturePoints.push(mouseX);
468 }569 }
@@ -491,12 +592,26 @@
491592
492 Repeater {593 Repeater {
493 id: spreadRepeater594 id: spreadRepeater
595 objectName: "spreadRepeater"
494 model: ApplicationManager596 model: ApplicationManager
495597
496 delegate: TransformedTabletSpreadDelegate {598 delegate: TransformedTabletSpreadDelegate {
497 id: spreadTile599 id: spreadTile
498 height: spreadView.height600 objectName: "spreadDelegate_" + model.appId
499 width: model.stage == ApplicationInfoInterface.MainStage ? spreadView.width : spreadView.sideStageWidth601 width: {
602 if (wantsMainStage) {
603 return spreadView.width;
604 } else {
605 return spreadView.sideStageWidth;
606 }
607 }
608 height: {
609 if (wantsMainStage) {
610 return spreadView.height;
611 } else {
612 return priv.landscapeHeight;
613 }
614 }
500 active: model.appId == priv.mainStageAppId || model.appId == priv.sideStageAppId615 active: model.appId == priv.mainStageAppId || model.appId == priv.sideStageAppId
501 zIndex: spreadView.indexToZIndex(index)616 zIndex: spreadView.indexToZIndex(index)
502 selected: spreadView.selectedIndex == index617 selected: spreadView.selectedIndex == index
@@ -509,6 +624,8 @@
509 application: ApplicationManager.get(index)624 application: ApplicationManager.get(index)
510 closeable: !isDash625 closeable: !isDash
511626
627 readonly property bool wantsMainStage: model.stage == ApplicationInfoInterface.MainStage
628
512 readonly property bool isDash: model.appId == "unity8-dash"629 readonly property bool isDash: model.appId == "unity8-dash"
513630
514 // FIXME: A regular binding doesn't update any more after closing an app.631 // FIXME: A regular binding doesn't update any more after closing an app.
@@ -560,12 +677,11 @@
560 return progress;677 return progress;
561 }678 }
562679
563 Binding {680 shellOrientationAngle: wantsMainStage ? root.shellOrientationAngle : 0
564 target: spreadTile681 shellOrientation: wantsMainStage ? root.shellOrientation : Qt.PortraitOrientation
565 property: "orientation"682 shellPrimaryOrientation: wantsMainStage ? root.shellPrimaryOrientation : Qt.PortraitOrientation
566 when: spreadTile.interactive683 nativeOrientation: wantsMainStage ? root.nativeOrientation : Qt.PortraitOrientation
567 value: root.orientation684
568 }
569685
570 onClicked: {686 onClicked: {
571 if (spreadView.phase == 2) {687 if (spreadView.phase == 2) {
@@ -586,6 +702,19 @@
586 ApplicationManager.stopApplication(ApplicationManager.get(index).appId);702 ApplicationManager.stopApplication(ApplicationManager.get(index).appId);
587 }703 }
588704
705 Binding {
706 target: root
707 when: model.appId == priv.mainStageAppId
708 property: "mainAppWindowOrientationAngle"
709 value: appWindowOrientationAngle
710 }
711 Binding {
712 target: priv
713 when: model.appId == priv.mainStageAppId
714 property: "mainAppOrientationChangesEnabled"
715 value: orientationChangesEnabled
716 }
717
589 EasingCurve {718 EasingCurve {
590 id: snappingCurve719 id: snappingCurve
591 type: EasingCurve.Linear720 type: EasingCurve.Linear
@@ -599,9 +728,11 @@
599728
600 DirectionalDragArea {729 DirectionalDragArea {
601 id: spreadDragArea730 id: spreadDragArea
731 objectName: "spreadDragArea"
602 anchors { top: parent.top; right: parent.right; bottom: parent.bottom }732 anchors { top: parent.top; right: parent.right; bottom: parent.bottom }
603 width: root.dragAreaWidth733 width: root.dragAreaWidth
604 direction: Direction.Leftwards734 direction: Direction.Leftwards
735 enabled: (spreadView.phase != 2 && root.spreadEnabled) || dragging
605736
606 property var gesturePoints: new Array()737 property var gesturePoints: new Array()
607738
608739
=== modified file 'qml/Stages/TransformedSpreadDelegate.qml'
--- qml/Stages/TransformedSpreadDelegate.qml 2015-01-06 14:46:52 +0000
+++ qml/Stages/TransformedSpreadDelegate.qml 2015-05-18 22:06:13 +0000
@@ -298,7 +298,6 @@
298298
299 return easingCurve.value;299 return easingCurve.value;
300 }300 }
301
302 }301 }
303302
304 transform: [303 transform: [
@@ -307,16 +306,61 @@
307 axis { x: 0; y: 1; z: 0 }306 axis { x: 0; y: 1; z: 0 }
308 angle: priv.angle307 angle: priv.angle
309 },308 },
309
310 // The next two transformations are to ensure that fullscreen and rotated
311 // windows all have the same size and position as an unrotated (0 degrees)
312 // non-fullscreen window when they're stacked on top of each other on the
313 // far left of the spread.
314 Translate {
315 y: !fullscreen && appWindowRotation === 180
316 ? priv.topMarginProgress * maximizedAppTopMargin
317 : 0
318 },
319 Scale {
320 origin {
321 x: appWindowRotation === 270 ? spreadView.width : 0
322 y: spreadView.height
323 }
324
325 xScale: {
326 switch (appWindowRotation) {
327 case 90:
328 case 270:
329 if (fullscreen) {
330 return 1;
331 } else {
332 return 1 + priv.topMarginProgress * maximizedAppTopMargin / spreadView.width;
333 }
334 break;
335 default:
336 return 1;
337 }
338 }
339
340 yScale: {
341 switch (appWindowRotation) {
342 case 0:
343 if (fullscreen) {
344 return 1 - priv.topMarginProgress * maximizedAppTopMargin / spreadView.height;
345 } else {
346 return 1;
347 }
348 break;
349 case 90:
350 case 270:
351 return 1 - priv.topMarginProgress * maximizedAppTopMargin / spreadView.height;
352 break;
353 default:
354 return 1;
355 }
356 }
357 },
358
310 Scale {359 Scale {
311 origin { x: 0; y: spreadView.height / 2 }360 origin { x: 0; y: spreadView.height / 2 }
312 xScale: priv.scale361 xScale: priv.scale
313 yScale: xScale362 yScale: xScale
314 },363 },
315 Scale {
316 origin { x: 0; y: (spreadView.height * priv.scale) + maximizedAppTopMargin * 3 }
317 xScale: 1
318 yScale: fullscreen ? 1 - priv.topMarginProgress * maximizedAppTopMargin / spreadView.height : 1
319 },
320 Translate {364 Translate {
321 x: priv.xTranslate365 x: priv.xTranslate
322 }366 }
323367
=== modified file 'qml/Stages/TransformedTabletSpreadDelegate.qml'
--- qml/Stages/TransformedTabletSpreadDelegate.qml 2015-02-02 16:23:34 +0000
+++ qml/Stages/TransformedTabletSpreadDelegate.qml 2015-05-18 22:06:13 +0000
@@ -50,7 +50,9 @@
50 property int dragOffset: 050 property int dragOffset: 0
5151
52 dropShadow: spreadView.active ||52 dropShadow: spreadView.active ||
53 (active && model.stage == ApplicationInfoInterface.MainStage && priv.xTranslate != 0)53 (active
54 && (model.stage == ApplicationInfoInterface.MainStage || !priv.shellIsLandscape)
55 && priv.xTranslate != 0)
5456
55 onSelectedChanged: {57 onSelectedChanged: {
56 if (selected) {58 if (selected) {
@@ -139,7 +141,8 @@
139 !snapAnimation.running &&141 !snapAnimation.running &&
140 model.appId !== "unity8-dash" &&142 model.appId !== "unity8-dash" &&
141 !spreadView.sideStageDragging &&143 !spreadView.sideStageDragging &&
142 spreadView.animateX144 spreadView.animateX &&
145 !spreadView.beingResized
143 UbuntuNumberAnimation {146 UbuntuNumberAnimation {
144 duration: UbuntuAnimation.FastDuration147 duration: UbuntuAnimation.FastDuration
145 }148 }
146149
=== modified file 'run.sh'
--- run.sh 2015-03-11 08:07:31 +0000
+++ run.sh 2015-05-18 22:06:13 +0000
@@ -44,7 +44,7 @@
44 export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD/builddir/plugins/LightDM/liblightdm44 export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD/builddir/plugins/LightDM/liblightdm
45fi45fi
4646
47QML_PHONE_SHELL_ARGS=""47QML_PHONE_SHELL_ARGS="-windowgeometry=40gux68gu -devicename=mako"
48if $MOUSE_TOUCH; then48if $MOUSE_TOUCH; then
49 QML_PHONE_SHELL_ARGS="$QML_PHONE_SHELL_ARGS -mousetouch"49 QML_PHONE_SHELL_ARGS="$QML_PHONE_SHELL_ARGS -mousetouch"
50fi50fi
5151
=== added file 'src/ApplicationArguments.cpp'
--- src/ApplicationArguments.cpp 1970-01-01 00:00:00 +0000
+++ src/ApplicationArguments.cpp 2015-05-18 22:06:13 +0000
@@ -0,0 +1,22 @@
1/*
2 * Copyright (C) 2015 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include "ApplicationArguments.h"
18
19ApplicationArguments::ApplicationArguments(QObject *parent)
20 : QObject(parent)
21{
22}
023
=== modified file 'src/ApplicationArguments.h'
--- src/ApplicationArguments.h 2015-04-15 15:20:24 +0000
+++ src/ApplicationArguments.h 2015-05-18 22:06:13 +0000
@@ -1,5 +1,5 @@
1/*1/*
2 * Copyright (C) 2013 Canonical, Ltd.2 * Copyright (C) 2013,2015 Canonical, Ltd.
3 *3 *
4 * This program is free software; you can redistribute it and/or modify4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by5 * it under the terms of the GNU General Public License as published by
@@ -13,7 +13,6 @@
13 * You should have received a copy of the GNU General Public License13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *15 *
16 * Authored by: Nick Dedekind <nick.dedekind@canonical.com>
17 */16 */
1817
1918
@@ -22,23 +21,20 @@
2221
23#include <QObject>22#include <QObject>
24#include <QSize>23#include <QSize>
25#include <QStringList>24#include <QString>
2625
27class ApplicationArguments : public QObject26class ApplicationArguments : public QObject
28{27{
29 Q_OBJECT28 Q_OBJECT
29 Q_PROPERTY(QString deviceName READ deviceName CONSTANT)
30public:30public:
31 // Not exposed to the app as setSize isn't invokable31 ApplicationArguments(QObject *parent = nullptr);
32 void setSize(const QSize &size) {
33 m_size = size;
34 }
3532
36 Q_INVOKABLE bool hasGeometry() const { return m_size.isValid(); }33 void setDeviceName(QString deviceName) { m_deviceName = deviceName; }
37 Q_INVOKABLE int width() const { return m_size.width(); }34 QString deviceName() const { return m_deviceName; }
38 Q_INVOKABLE int height() const { return m_size.height(); }
3935
40private:36private:
41 QSize m_size;37 QString m_deviceName;
42};38};
4339
44#endif // APPLICATION_ARGUMENTS_H40#endif // APPLICATION_ARGUMENTS_H
4541
=== modified file 'src/CMakeLists.txt'
--- src/CMakeLists.txt 2015-04-14 14:11:43 +0000
+++ src/CMakeLists.txt 2015-05-18 22:06:13 +0000
@@ -17,7 +17,7 @@
17)17)
1818
19add_executable(${SHELL_APP}19add_executable(${SHELL_APP}
20 ApplicationArguments.h20 ApplicationArguments.cpp
21 main.cpp21 main.cpp
22 MouseTouchAdaptor.cpp22 MouseTouchAdaptor.cpp
23 CachingNetworkManagerFactory.cpp23 CachingNetworkManagerFactory.cpp
@@ -26,13 +26,12 @@
26)26)
2727
28qt5_use_modules(${SHELL_APP} Gui Qml Quick Test)28qt5_use_modules(${SHELL_APP} Gui Qml Quick Test)
29pkg_check_modules(XCB REQUIRED xcb)29
3030pkg_check_modules(NEEDED_LIBS REQUIRED xcb libandroid-properties)
31if (NOT "${XCB_INCLUDE_DIRS}" STREQUAL "")31if (NOT "${NEEDED_LIBS_INCLUDE_DIRS}" STREQUAL "")
32 set_target_properties(${SHELL_APP} PROPERTIES INCLUDE_DIRECTORIES ${XCB_INCLUDE_DIRS})32 set_target_properties(${SHELL_APP} PROPERTIES INCLUDE_DIRECTORIES ${NEEDED_LIBS_INCLUDE_DIRS})
33
34 target_link_libraries(${SHELL_APP} ${XCB_LDFLAGS})
35endif()33endif()
34target_link_libraries(${SHELL_APP} ${NEEDED_LIBS_LDFLAGS})
3635
37target_link_libraries(${SHELL_APP} UbuntuGestures connectivity-qt1)36target_link_libraries(${SHELL_APP} UbuntuGestures connectivity-qt1)
3837
3938
=== modified file 'src/Dash/CMakeLists.txt'
--- src/Dash/CMakeLists.txt 2014-10-27 09:40:01 +0000
+++ src/Dash/CMakeLists.txt 2015-05-18 22:06:13 +0000
@@ -1,6 +1,6 @@
1set(DASH_SRCS1set(DASH_SRCS
2 main.cpp2 main.cpp
3 ../ApplicationArguments.h3 ../ApplicationArguments.cpp
4 ../MouseTouchAdaptor.cpp4 ../MouseTouchAdaptor.cpp
5 ../CachingNetworkManagerFactory.cpp5 ../CachingNetworkManagerFactory.cpp
6)6)
@@ -9,6 +9,12 @@
99
10qt5_use_modules(unity8-dash Gui Qml Quick Test)10qt5_use_modules(unity8-dash Gui Qml Quick Test)
1111
12pkg_check_modules(NEEDED_LIBS REQUIRED xcb libandroid-properties)
13if (NOT "${NEEDED_LIBS_INCLUDE_DIRS}" STREQUAL "")
14 set_target_properties(unity8-dash PROPERTIES INCLUDE_DIRECTORIES ${NEEDED_LIBS_INCLUDE_DIRS})
15endif()
16target_link_libraries(unity8-dash ${NEEDED_LIBS_LDFLAGS})
17
12# For it to find libUbuntuGestures.so, needed by Ubuntu.Gestures QML module.18# For it to find libUbuntuGestures.so, needed by Ubuntu.Gestures QML module.
13set_target_properties(unity8-dash PROPERTIES INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${SHELL_PRIVATE_LIBDIR}")19set_target_properties(unity8-dash PROPERTIES INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${SHELL_PRIVATE_LIBDIR}")
1420
1521
=== modified file 'src/Dash/main.cpp'
--- src/Dash/main.cpp 2015-04-15 15:20:24 +0000
+++ src/Dash/main.cpp 2015-05-18 22:06:13 +0000
@@ -61,12 +61,6 @@
61 parser.process(*application);61 parser.process(*application);
6262
63 ApplicationArguments qmlArgs;63 ApplicationArguments qmlArgs;
64 if (parser.isSet(windowGeometryOption) &&
65 parser.value(windowGeometryOption).split('x').size() == 2)
66 {
67 QStringList geom = parser.value(windowGeometryOption).split('x');
68 qmlArgs.setSize(QSize(geom.at(0).toInt(), geom.at(1).toInt()));
69 }
7064
71 if (getenv("QT_LOAD_TESTABILITY")) {65 if (getenv("QT_LOAD_TESTABILITY")) {
72 QLibrary testLib(QLatin1String("qttestability"));66 QLibrary testLib(QLatin1String("qttestability"));
@@ -88,6 +82,18 @@
8882
89 QQuickView* view = new QQuickView();83 QQuickView* view = new QQuickView();
90 view->setResizeMode(QQuickView::SizeRootObjectToView);84 view->setResizeMode(QQuickView::SizeRootObjectToView);
85
86 if (parser.isSet(windowGeometryOption) &&
87 parser.value(windowGeometryOption).split('x').size() == 2)
88 {
89 QStringList geom = parser.value(windowGeometryOption).split('x');
90 QSize windowSize(geom.at(0).toInt(), geom.at(1).toInt());
91 if (windowSize.isValid()) {
92 view->setWidth(windowSize.width());
93 view->setHeight(windowSize.height());
94 }
95 }
96
91 view->setTitle("Scopes");97 view->setTitle("Scopes");
92 view->rootContext()->setContextProperty("applicationArguments", &qmlArgs);98 view->rootContext()->setContextProperty("applicationArguments", &qmlArgs);
9399
94100
=== modified file 'src/UnityCommandLineParser.cpp'
--- src/UnityCommandLineParser.cpp 2015-04-14 14:11:43 +0000
+++ src/UnityCommandLineParser.cpp 2015-05-18 22:06:13 +0000
@@ -49,6 +49,10 @@
49 "DISCOURAGED: Please set QT_LOAD_TESTABILITY instead.\nLoad the testability driver");49 "DISCOURAGED: Please set QT_LOAD_TESTABILITY instead.\nLoad the testability driver");
50 parser.addOption(testabilityOption);50 parser.addOption(testabilityOption);
5151
52 QCommandLineOption devicenameOption(QStringList() << "devicename",
53 "Specify the device name instead of letting Unity 8 find it out", "devicename", "");
54 parser.addOption(devicenameOption);
55
52 QCommandLineOption modeOption("mode",56 QCommandLineOption modeOption("mode",
53 "Whether to run greeter and/or shell [full-greeter, full-shell, greeter, shell]",57 "Whether to run greeter and/or shell [full-greeter, full-shell, greeter, shell]",
54 "mode", "full-greeter");58 "mode", "full-greeter");
@@ -73,6 +77,7 @@
73 m_hasFrameless = parser.isSet(framelessOption);77 m_hasFrameless = parser.isSet(framelessOption);
74 m_hasMouseToTouch = parser.isSet(mousetouchOption);78 m_hasMouseToTouch = parser.isSet(mousetouchOption);
75 m_hasFullscreen = parser.isSet(fullscreenOption);79 m_hasFullscreen = parser.isSet(fullscreenOption);
80 m_deviceName = parser.value(devicenameOption);
76 resolveMode(parser, modeOption);81 resolveMode(parser, modeOption);
77}82}
7883
7984
=== modified file 'src/UnityCommandLineParser.h'
--- src/UnityCommandLineParser.h 2015-04-14 14:11:43 +0000
+++ src/UnityCommandLineParser.h 2015-05-18 22:06:13 +0000
@@ -30,6 +30,7 @@
30 bool hasFrameless() const { return m_hasFrameless; }30 bool hasFrameless() const { return m_hasFrameless; }
31 bool hasMouseToTouch() const { return m_hasMouseToTouch; }31 bool hasMouseToTouch() const { return m_hasMouseToTouch; }
32 bool hasFullscreen() const { return m_hasFullscreen; }32 bool hasFullscreen() const { return m_hasFullscreen; }
33 QString deviceName() const { return m_deviceName; }
33 QString mode() const { return m_mode; }34 QString mode() const { return m_mode; }
34private:35private:
3536
@@ -44,6 +45,7 @@
44 bool m_hasFrameless;45 bool m_hasFrameless;
45 bool m_hasMouseToTouch;46 bool m_hasMouseToTouch;
46 bool m_hasFullscreen;47 bool m_hasFullscreen;
48 QString m_deviceName;
47 QString m_mode;49 QString m_mode;
48};50};
4951
5052
=== modified file 'src/main.cpp'
--- src/main.cpp 2015-04-15 15:20:24 +0000
+++ src/main.cpp 2015-05-18 22:06:13 +0000
@@ -25,6 +25,9 @@
25#include <csignal>25#include <csignal>
26#include <libintl.h>26#include <libintl.h>
2727
28// libandroid-properties
29#include <hybris/properties/properties.h>
30
28// local31// local
29#include <paths.h>32#include <paths.h>
30#include "MouseTouchAdaptor.h"33#include "MouseTouchAdaptor.h"
@@ -50,13 +53,15 @@
5053
51 UnityCommandLineParser parser(*application);54 UnityCommandLineParser parser(*application);
5255
53 QString indicatorProfile = qgetenv("UNITY_INDICATOR_PROFILE");
54 if (indicatorProfile.isEmpty()) {
55 indicatorProfile = "phone";
56 }
57
58 ApplicationArguments qmlArgs;56 ApplicationArguments qmlArgs;
59 qmlArgs.setSize(parser.windowGeometry());57
58 if (!parser.deviceName().isEmpty()) {
59 qmlArgs.setDeviceName(parser.deviceName());
60 } else {
61 char buffer[200];
62 property_get("ro.product.device", buffer /* value */, "desktop" /* default_value*/);
63 qmlArgs.setDeviceName(QString(buffer));
64 }
6065
61 // The testability driver is only loaded by QApplication but not by QGuiApplication.66 // The testability driver is only loaded by QApplication but not by QGuiApplication.
62 // However, QApplication depends on QWidget which would add some unneeded overhead => Let's load the testability driver on our own.67 // However, QApplication depends on QWidget which would add some unneeded overhead => Let's load the testability driver on our own.
@@ -82,9 +87,14 @@
82 view->setResizeMode(QQuickView::SizeRootObjectToView);87 view->setResizeMode(QQuickView::SizeRootObjectToView);
83 view->setColor("black");88 view->setColor("black");
84 view->setTitle("Unity8 Shell");89 view->setTitle("Unity8 Shell");
90
91 if (parser.windowGeometry().isValid()) {
92 view->setWidth(parser.windowGeometry().width());
93 view->setHeight(parser.windowGeometry().height());
94 }
95
85 view->engine()->setBaseUrl(QUrl::fromLocalFile(::qmlDirectory()));96 view->engine()->setBaseUrl(QUrl::fromLocalFile(::qmlDirectory()));
86 view->rootContext()->setContextProperty("applicationArguments", &qmlArgs);97 view->rootContext()->setContextProperty("applicationArguments", &qmlArgs);
87 view->rootContext()->setContextProperty("indicatorProfile", indicatorProfile);
88 view->rootContext()->setContextProperty("shellMode", parser.mode());98 view->rootContext()->setContextProperty("shellMode", parser.mode());
89 if (parser.hasFrameless()) {99 if (parser.hasFrameless()) {
90 view->setFlags(Qt::FramelessWindowHint);100 view->setFlags(Qt::FramelessWindowHint);
@@ -99,7 +109,7 @@
99 mouseTouchAdaptor = MouseTouchAdaptor::instance();109 mouseTouchAdaptor = MouseTouchAdaptor::instance();
100 }110 }
101111
102 QUrl source(::qmlDirectory()+"Shell.qml");112 QUrl source(::qmlDirectory()+"OrientedShell.qml");
103 prependImportPaths(view->engine(), ::overrideImportPaths());113 prependImportPaths(view->engine(), ::overrideImportPaths());
104 if (!isMirServer) {114 if (!isMirServer) {
105 prependImportPaths(view->engine(), ::nonMirImportPaths());115 prependImportPaths(view->engine(), ::nonMirImportPaths());
106116
=== modified file 'tests/mocks/Unity/Application/ApplicationInfo.cpp'
--- tests/mocks/Unity/Application/ApplicationInfo.cpp 2014-08-28 23:16:07 +0000
+++ tests/mocks/Unity/Application/ApplicationInfo.cpp 2015-05-18 22:06:13 +0000
@@ -1,5 +1,5 @@
1/*1/*
2 * Copyright (C) 2013-2014 Canonical, Ltd.2 * Copyright (C) 2013-2015 Canonical, Ltd.
3 *3 *
4 * This program is free software; you can redistribute it and/or modify4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by5 * it under the terms of the GNU General Public License as published by
@@ -34,6 +34,11 @@
34 , m_focused(false)34 , m_focused(false)
35 , m_fullscreen(false)35 , m_fullscreen(false)
36 , m_session(0)36 , m_session(0)
37 , m_supportedOrientations(Qt::PortraitOrientation |
38 Qt::LandscapeOrientation |
39 Qt::InvertedPortraitOrientation |
40 Qt::InvertedLandscapeOrientation)
41 , m_rotatesWindowContents(false)
37 , m_manualSurfaceCreation(false)42 , m_manualSurfaceCreation(false)
38{43{
39}44}
@@ -45,6 +50,11 @@
45 , m_focused(false)50 , m_focused(false)
46 , m_fullscreen(false)51 , m_fullscreen(false)
47 , m_session(0)52 , m_session(0)
53 , m_supportedOrientations(Qt::PortraitOrientation |
54 Qt::LandscapeOrientation |
55 Qt::InvertedPortraitOrientation |
56 Qt::InvertedLandscapeOrientation)
57 , m_rotatesWindowContents(false)
48 , m_manualSurfaceCreation(false)58 , m_manualSurfaceCreation(false)
49{59{
50}60}
@@ -99,9 +109,17 @@
99109
100void ApplicationInfo::setScreenshotId(const QString &screenshotId)110void ApplicationInfo::setScreenshotId(const QString &screenshotId)
101{111{
102 QString screenshotFileName = QString("%1/Dash/graphics/phone/screenshots/%2@12.png")112 QString screenshotFileName;
103 .arg(qmlDirectory())113
104 .arg(screenshotId);114 if (screenshotId.endsWith(".svg")) {
115 screenshotFileName = QString("%1/Dash/graphics/phone/screenshots/%2")
116 .arg(qmlDirectory())
117 .arg(screenshotId);
118 } else {
119 screenshotFileName = QString("%1/Dash/graphics/phone/screenshots/%2@12.png")
120 .arg(qmlDirectory())
121 .arg(screenshotId);
122 }
105123
106 if (screenshotFileName != m_screenshotFileName) {124 if (screenshotFileName != m_screenshotFileName) {
107 m_screenshotFileName = screenshotFileName;125 m_screenshotFileName = screenshotFileName;
@@ -145,6 +163,9 @@
145163
146 if (!m_manualSurfaceCreation && m_state == ApplicationInfo::Running) {164 if (!m_manualSurfaceCreation && m_state == ApplicationInfo::Running) {
147 QTimer::singleShot(500, this, SLOT(createSession()));165 QTimer::singleShot(500, this, SLOT(createSession()));
166 } else if (m_state == ApplicationInfo::Stopped) {
167 delete m_session;
168 m_session = nullptr;
148 }169 }
149 }170 }
150}171}
@@ -172,3 +193,23 @@
172 Q_EMIT manualSurfaceCreationChanged(value);193 Q_EMIT manualSurfaceCreationChanged(value);
173 }194 }
174}195}
196
197Qt::ScreenOrientations ApplicationInfo::supportedOrientations() const
198{
199 return m_supportedOrientations;
200}
201
202void ApplicationInfo::setSupportedOrientations(Qt::ScreenOrientations orientations)
203{
204 m_supportedOrientations = orientations;
205}
206
207bool ApplicationInfo::rotatesWindowContents() const
208{
209 return m_rotatesWindowContents;
210}
211
212void ApplicationInfo::setRotatesWindowContents(bool value)
213{
214 m_rotatesWindowContents = value;
215}
175216
=== modified file 'tests/mocks/Unity/Application/ApplicationInfo.h'
--- tests/mocks/Unity/Application/ApplicationInfo.h 2014-09-15 19:05:32 +0000
+++ tests/mocks/Unity/Application/ApplicationInfo.h 2015-05-18 22:06:13 +0000
@@ -1,5 +1,5 @@
1/*1/*
2 * Copyright (C) 2013-2014 Canonical, Ltd.2 * Copyright (C) 2013-2015 Canonical, Ltd.
3 *3 *
4 * This program is free software; you can redistribute it and/or modify4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by5 * it under the terms of the GNU General Public License as published by
@@ -80,6 +80,12 @@
80 void setFullscreen(bool value);80 void setFullscreen(bool value);
81 bool fullscreen() const { return m_fullscreen; }81 bool fullscreen() const { return m_fullscreen; }
8282
83 Qt::ScreenOrientations supportedOrientations() const override;
84 void setSupportedOrientations(Qt::ScreenOrientations orientations);
85
86 bool rotatesWindowContents() const override;
87 void setRotatesWindowContents(bool value);
88
83 bool manualSurfaceCreation() const { return m_manualSurfaceCreation; }89 bool manualSurfaceCreation() const { return m_manualSurfaceCreation; }
84 void setManualSurfaceCreation(bool value);90 void setManualSurfaceCreation(bool value);
8591
@@ -108,6 +114,8 @@
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches