Merge lp:~saviq/unity8/add-cursor-copyright into lp:unity8
- add-cursor-copyright
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Albert Astals Cid |
Approved revision: | 2008 |
Merged at revision: | 2019 |
Proposed branch: | lp:~saviq/unity8/add-cursor-copyright |
Merge into: | lp:unity8 |
Diff against target: |
5811 lines (+3041/-1212) 103 files modified
CMakeLists.txt (+4/-1) data/unity8.conf (+10/-0) debian/changelog (+36/-0) debian/control (+9/-7) debian/copyright (+21/-0) debian/unity8-private.install (+1/-0) debian/unity8.install (+1/-0) plugins/CMakeLists.txt (+1/-0) plugins/Cursor/3rd_party/CMakeLists.txt (+1/-0) plugins/Cursor/3rd_party/xcursor/CMakeLists.txt (+15/-0) plugins/Cursor/3rd_party/xcursor/xcursor.c (+968/-0) plugins/Cursor/3rd_party/xcursor/xcursor.h (+65/-0) plugins/Cursor/CMakeLists.txt (+28/-0) plugins/Cursor/Cursor.qml (+28/-0) plugins/Cursor/CursorImageProvider.cpp (+191/-0) plugins/Cursor/CursorImageProvider.h (+76/-0) plugins/Cursor/MousePointer.cpp (+125/-0) plugins/Cursor/MousePointer.h (+59/-0) plugins/Cursor/plugin.cpp (+39/-0) plugins/Cursor/plugin.h (+33/-0) plugins/Cursor/qmldir (+3/-0) plugins/IntegratedLightDM/UsersModel.cpp (+7/-6) plugins/IntegratedLightDM/liblightdm/UsersModelPrivate.cpp (+2/-1) plugins/ScreenGrabber/screengrabber.cpp (+2/-2) plugins/ScreenGrabber/screengrabber.h (+1/-1) plugins/Unity/CMakeLists.txt (+1/-0) plugins/Unity/Launcher/desktopfilehandler.cpp (+3/-2) plugins/Unity/Platform/CMakeLists.txt (+9/-0) plugins/Unity/Platform/platform.cpp (+43/-0) plugins/Unity/Platform/platform.h (+58/-0) plugins/Unity/Platform/plugin.cpp (+27/-0) plugins/Unity/Platform/plugin.h (+32/-0) plugins/Unity/Platform/qmldir (+2/-0) plugins/Unity/Session/dbusunitysessionservice.cpp (+2/-1) plugins/Utils/CMakeLists.txt (+0/-2) plugins/Utils/plugin.cpp (+0/-5) plugins/Utils/relativetimeformatter.cpp (+0/-260) plugins/Utils/relativetimeformatter.h (+0/-34) plugins/Utils/timeformatter.cpp (+0/-206) plugins/Utils/timeformatter.h (+0/-68) plugins/Utils/timezoneFormatter.cpp (+1/-1) qml/Components/Dialogs.qml (+3/-2) qml/Components/ScreenGrabber.qml (+4/-1) qml/Components/WallpaperResolver.qml (+63/-0) qml/DeviceConfiguration.qml (+1/-0) qml/DisabledScreenNotice.qml (+49/-0) qml/Greeter/Greeter.qml (+1/-1) qml/Launcher/Launcher.qml (+1/-0) qml/Notifications/Notification.qml (+2/-0) qml/Notifications/NotificationMenuItemFactory.qml (+2/-1) qml/Notifications/Notifications.qml (+2/-0) qml/OrientedShell.qml (+10/-1) qml/Panel/Indicators/MenuItemFactory.qml (+19/-15) qml/Panel/Indicators/MessageMenuItemFactory.qml (+35/-26) qml/Panel/Panel.qml (+1/-0) qml/Rotation/RotationStates.qml (+2/-2) qml/Shell.qml (+24/-40) qml/Stages/ApplicationWindow.qml (+2/-0) qml/Stages/DecoratedWindow.qml (+7/-4) qml/Stages/DesktopStage.qml (+5/-8) qml/Stages/SurfaceContainer.qml (+1/-0) qml/Stages/WindowDecoration.qml (+32/-4) qml/Stages/WindowResizeArea.qml (+135/-62) src/ApplicationArguments.h (+10/-2) src/CMakeLists.txt (+3/-0) src/SecondaryWindow.cpp (+31/-0) src/SecondaryWindow.h (+30/-0) src/ShellApplication.cpp (+197/-0) src/ShellApplication.h (+55/-0) src/ShellView.cpp (+59/-0) src/ShellView.h (+34/-0) src/main.cpp (+4/-101) tests/autopilot/unity8/fixture_setup.py (+1/-1) tests/autopilot/unity8/greeter/tests/__init__.py (+1/-1) tests/autopilot/unity8/launcher.py (+1/-1) tests/autopilot/unity8/settings_wizard/__init__.py (+7/-2) tests/autopilot/unity8/settings_wizard/tests/test_settings_wizard.py (+10/-5) tests/autopilot/unity8/shell/__init__.py (+1/-1) tests/autopilot/unity8/shell/tests/__init__.py (+1/-1) tests/mocks/CMakeLists.txt (+1/-0) tests/mocks/Cursor/CMakeLists.txt (+1/-0) tests/mocks/Cursor/Cursor.qml (+20/-0) tests/mocks/Cursor/qmldir (+2/-0) tests/mocks/Unity/Launcher/MockQuickListModel.cpp (+1/-1) tests/mocks/Unity/fake_resultsmodel.cpp (+1/-1) tests/mocks/Unity/fake_scopesoverview.cpp (+1/-1) tests/mocks/Utils/CMakeLists.txt (+0/-2) tests/mocks/Utils/Utils.qmltypes (+31/-28) tests/mocks/Utils/plugin.cpp (+0/-13) tests/plugins/ScreenGrabber/ScreenGrabberTest.cpp (+11/-0) tests/plugins/ScreenGrabber/grabber.qml (+1/-1) tests/plugins/Unity/Indicators/UnityMenuModelStackTest.cpp (+2/-9) tests/plugins/Utils/CMakeLists.txt (+0/-1) tests/plugins/Utils/TimeFormatterTest.cpp (+0/-155) tests/plugins/Wizard/tst_pagelist.cpp (+5/-5) tests/qmltests/CMakeLists.txt (+3/-1) tests/qmltests/Components/tst_WallpaperResolver.qml (+89/-0) tests/qmltests/Panel/Indicators/tst_MenuItemFactory.qml (+6/-16) tests/qmltests/Panel/Indicators/tst_MessageMenuItemFactory.qml (+6/-13) tests/qmltests/Stages/tst_WindowResizeArea.qml (+18/-61) tests/qmltests/tst_DisabledScreenNotice.qml (+37/-0) tests/qmltests/tst_OrientedShell.qml (+55/-1) tests/qmltests/tst_Shell.qml (+0/-24) |
To merge this branch: | bzr merge lp:~saviq/unity8/add-cursor-copyright |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
PS Jenkins bot (community) | continuous-integration | Needs Fixing | |
Albert Astals Cid (community) | Approve | ||
Review via email: mp+275692@code.launchpad.net |
Commit message
Add missing copyright to Cursor.qml
Description of the change
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2008
http://
Executed test runs:
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Preview Diff
1 | === modified file 'CMakeLists.txt' |
2 | --- CMakeLists.txt 2015-09-30 16:49:52 +0000 |
3 | +++ CMakeLists.txt 2015-10-26 12:04:03 +0000 |
4 | @@ -57,7 +57,7 @@ |
5 | find_package(Qt5Concurrent 5.2 REQUIRED) |
6 | find_package(Qt5Sql 5.2 REQUIRED) |
7 | |
8 | -pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application>=8) |
9 | +pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=9) |
10 | |
11 | # Standard install paths |
12 | include(GNUInstallDirs) |
13 | @@ -101,6 +101,9 @@ |
14 | # Save a few container detach and conversions |
15 | add_definitions(-DQT_STRICT_ITERATORS) |
16 | |
17 | +# Use the fast string builder |
18 | +add_definitions(-DQT_USE_QSTRINGBUILDER) |
19 | + |
20 | # Autopilot tests |
21 | include(autopilot) |
22 | declare_autopilot_test(shell unity8.shell ${CMAKE_SOURCE_DIR}/tests/autopilot/) |
23 | |
24 | === modified file 'data/unity8.conf' |
25 | --- data/unity8.conf 2015-09-01 12:41:57 +0000 |
26 | +++ data/unity8.conf 2015-10-26 12:04:03 +0000 |
27 | @@ -46,6 +46,16 @@ |
28 | initctl set-env --global MIR_SERVER_PROMPT_FILE=1 |
29 | |
30 | initctl emit --no-wait indicator-services-start |
31 | + |
32 | + # Disable Qt's stuttering 'touch compression' to fix scrolling smoothness |
33 | + # issues (LP: #1486341). As a bonus, this eliminates most of the |
34 | + # lag seen in the indicator panel pull-down (LP: #1488327) and also |
35 | + # reduces lag seen in apps: |
36 | + initctl set-env --global QML_NO_TOUCH_COMPRESSION=1 |
37 | + |
38 | + # For twice the fun and half the latency, try this (Warning: not all |
39 | + # devices are fast enough to keep up smoothly yet)... |
40 | + # initctl set-env MIR_SERVER_NBUFFERS=2 |
41 | end script |
42 | |
43 | exec ${BINARY:-unity8} $ARGS |
44 | |
45 | === modified file 'debian/changelog' |
46 | --- debian/changelog 2015-10-09 09:13:03 +0000 |
47 | +++ debian/changelog 2015-10-26 12:04:03 +0000 |
48 | @@ -1,3 +1,39 @@ |
49 | +unity8 (8.11+15.10.20151021-0ubuntu1) wily; urgency=medium |
50 | + |
51 | + [ Albert Astals Cid ] |
52 | + * Clazy fixes |
53 | + * Enable Efficient String Construction by default |
54 | + |
55 | + [ CI Train Bot ] |
56 | + * New rebuild forced. |
57 | + |
58 | + [ Daniel d'Andrada ] |
59 | + * Have unity8 drawing its own cursor (LP: #1488417) |
60 | + * Initial multi-monitor support |
61 | + |
62 | + [ Daniel van Vugt ] |
63 | + * Disable Qt's stuttering 'touch compression' to fix scrolling |
64 | + smoothness (LP: #1486341, #1488327) |
65 | + |
66 | + [ Lukáš Tinkl ] |
67 | + * Fix autopilot wizard test skipping the reporting page |
68 | + * Implement Unity.Platform plugin wrapping org.freedesktop.hostname1 |
69 | + (LP: #1504318) |
70 | + * React to window title (aka surface name) changes (LP: #1497092) |
71 | + * Rotate the screenshots according to the actual orientation |
72 | + |
73 | + [ Michał Sawicz ] |
74 | + * Fix application API dependency |
75 | + * Have unity8 drawing its own cursor (LP: #1488417) |
76 | + * Initial multi-monitor support |
77 | + * Rotate the screenshots according to the actual orientation |
78 | + |
79 | + [ Nick Dedekind ] |
80 | + * Fixed leak in UnityMenuModelStackTest |
81 | + * Moved time translation to SDK (LP: #1372061) |
82 | + |
83 | + -- Michał Sawicz <michal.sawicz@canonical.com> Wed, 21 Oct 2015 11:51:53 +0000 |
84 | + |
85 | unity8 (8.11+15.10.20151009-0ubuntu1) wily; urgency=medium |
86 | |
87 | [ CI Train Bot ] |
88 | |
89 | === modified file 'debian/control' |
90 | --- debian/control 2015-09-23 18:15:40 +0000 |
91 | +++ debian/control 2015-10-26 12:04:03 +0000 |
92 | @@ -25,10 +25,11 @@ |
93 | libpay2-dev, |
94 | libpulse-dev, |
95 | libqmenumodel-dev (>= 0.2.9), |
96 | + libqt5svg5-dev, |
97 | libqt5xmlpatterns5-dev, |
98 | libsystemsettings-dev, |
99 | libudev-dev, |
100 | - libunity-api-dev (>= 7.100), |
101 | + libunity-api-dev (>= 7.101), |
102 | libusermetricsoutput1-dev, |
103 | libxcb1-dev, |
104 | pkg-config, |
105 | @@ -49,7 +50,7 @@ |
106 | qtdeclarative5-private-dev (>= 5.2.1), |
107 | qtdeclarative5-qtmultimedia-plugin, |
108 | qtdeclarative5-ubuntu-settings-components (>= 0.6), |
109 | - qtdeclarative5-ubuntu-ui-toolkit-plugin (>= 1.1.1239) | qtdeclarative5-ubuntu-ui-toolkit-plugin-gles (>= 1.1.1239), |
110 | + qtdeclarative5-ubuntu-ui-toolkit-plugin (>= 1.3.1627) | qtdeclarative5-ubuntu-ui-toolkit-plugin-gles (>= 1.3.1627), |
111 | qtdeclarative5-ubuntu-web-plugin, |
112 | ttf-ubuntu-font-family, |
113 | Standards-Version: 3.9.4 |
114 | @@ -64,7 +65,7 @@ |
115 | Package: indicators-client |
116 | Architecture: amd64 armhf i386 |
117 | Depends: qmenumodel-qml (>= 0.2.9), |
118 | - qtdeclarative5-ubuntu-ui-toolkit-plugin (>= 1.1.1239) | qtdeclarative5-ubuntu-ui-toolkit-plugin-gles (>= 1.1.1239), |
119 | + qtdeclarative5-ubuntu-ui-toolkit-plugin (>= 1.3.1627) | qtdeclarative5-ubuntu-ui-toolkit-plugin-gles (>= 1.3.1627), |
120 | unity8 (= ${binary:Version}), |
121 | ${misc:Depends}, |
122 | ${shlibs:Depends}, |
123 | @@ -87,7 +88,8 @@ |
124 | Package: unity8 |
125 | Architecture: any |
126 | Provides: indicator-renderer, |
127 | -Depends: gsettings-desktop-schemas, |
128 | +Depends: dmz-cursor-theme, |
129 | + gsettings-desktop-schemas, |
130 | libcap2-bin, |
131 | libglib2.0-bin, |
132 | qmenumodel-qml (>= 0.2.9), |
133 | @@ -122,10 +124,10 @@ |
134 | Depends: qml-module-qtquick-layouts, |
135 | qtdeclarative5-ubuntu-settings-components (>= 0.6), |
136 | qtdeclarative5-ubuntu-thumbnailer0.1 | ubuntu-thumbnailer-impl, |
137 | - qtdeclarative5-ubuntu-ui-toolkit-plugin (>= 1.1.1239) | qtdeclarative5-ubuntu-ui-toolkit-plugin-gles (>= 1.1.1239), |
138 | + qtdeclarative5-ubuntu-ui-toolkit-plugin (>= 1.3.1627) | qtdeclarative5-ubuntu-ui-toolkit-plugin-gles (>= 1.3.1627), |
139 | qtdeclarative5-unity-notifications-plugin (>= 0.1.2) | unity-notifications-impl, |
140 | ubuntu-thumbnailer-impl-0, |
141 | - unity-application-impl-8, |
142 | + unity-application-impl-9, |
143 | unity-notifications-impl-3, |
144 | unity-plugin-scopes | unity-scopes-impl, |
145 | unity-scopes-impl-7, |
146 | @@ -171,7 +173,7 @@ |
147 | Depends: ${misc:Depends}, |
148 | ${shlibs:Depends}, |
149 | Provides: unity-application-impl, |
150 | - unity-application-impl-8, |
151 | + unity-application-impl-9, |
152 | Replaces: unity8-autopilot (<< 8.02+15.04.20150422-0ubuntu1) |
153 | Description: Fake environment for running Unity 8 shell |
154 | Provides fake implementations of some QML modules used by Unity 8 shell |
155 | |
156 | === modified file 'debian/copyright' |
157 | --- debian/copyright 2014-06-11 15:36:51 +0000 |
158 | +++ debian/copyright 2015-10-26 12:04:03 +0000 |
159 | @@ -60,3 +60,24 @@ |
160 | packaging of this file. Please review the following information to |
161 | ensure the GNU General Public License version 3.0 requirements will be |
162 | met: http://www.gnu.org/copyleft/gpl.html. |
163 | + |
164 | +Files: plugins/Cursor/3rd_party/xcursor/xcursor.* |
165 | +Copyright: 2002 Keith Packard |
166 | +License: Keith Packard |
167 | + Permission to use, copy, modify, distribute, and sell this software and its |
168 | + documentation for any purpose is hereby granted without fee, provided that |
169 | + the above copyright notice appear in all copies and that both that |
170 | + copyright notice and this permission notice appear in supporting |
171 | + documentation, and that the name of Keith Packard not be used in |
172 | + advertising or publicity pertaining to distribution of the software without |
173 | + specific, written prior permission. Keith Packard makes no |
174 | + representations about the suitability of this software for any purpose. It |
175 | + is provided "as is" without express or implied warranty. |
176 | + . |
177 | + KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, |
178 | + INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO |
179 | + EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR |
180 | + CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, |
181 | + DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER |
182 | + TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR |
183 | + PERFORMANCE OF THIS SOFTWARE. |
184 | |
185 | === modified file 'debian/unity8-private.install' |
186 | --- debian/unity8-private.install 2015-09-02 09:30:32 +0000 |
187 | +++ debian/unity8-private.install 2015-10-26 12:04:03 +0000 |
188 | @@ -1,6 +1,7 @@ |
189 | usr/lib/*/libunity8-private.* |
190 | usr/lib/*/unity8/libUbuntuGestures* |
191 | usr/lib/*/unity8/qml/AccountsService |
192 | +usr/lib/*/unity8/qml/Cursor |
193 | usr/lib/*/unity8/qml/Dash |
194 | usr/lib/*/unity8/qml/GlobalShortcut |
195 | usr/lib/*/unity8/qml/Greeter |
196 | |
197 | === modified file 'debian/unity8.install' |
198 | --- debian/unity8.install 2015-10-01 13:10:32 +0000 |
199 | +++ debian/unity8.install 2015-10-26 12:04:03 +0000 |
200 | @@ -12,6 +12,7 @@ |
201 | usr/share/unity8/Rotation |
202 | usr/share/unity8/DeviceConfiguration.qml |
203 | usr/share/unity8/OrientedShell.qml |
204 | +usr/share/unity8/DisabledScreenNotice.qml |
205 | usr/share/unity8/Shell.qml |
206 | usr/share/unity8/Stages |
207 | usr/share/unity8/Tutorial |
208 | |
209 | === modified file 'plugins/CMakeLists.txt' |
210 | --- plugins/CMakeLists.txt 2015-09-02 09:30:32 +0000 |
211 | +++ plugins/CMakeLists.txt 2015-10-26 12:04:03 +0000 |
212 | @@ -12,6 +12,7 @@ |
213 | endmacro() |
214 | |
215 | add_subdirectory(AccountsService) |
216 | +add_subdirectory(Cursor) |
217 | add_subdirectory(GlobalShortcut) |
218 | add_subdirectory(Greeter) |
219 | add_subdirectory(IntegratedLightDM) |
220 | |
221 | === added directory 'plugins/Cursor' |
222 | === added directory 'plugins/Cursor/3rd_party' |
223 | === added file 'plugins/Cursor/3rd_party/CMakeLists.txt' |
224 | --- plugins/Cursor/3rd_party/CMakeLists.txt 1970-01-01 00:00:00 +0000 |
225 | +++ plugins/Cursor/3rd_party/CMakeLists.txt 2015-10-26 12:04:03 +0000 |
226 | @@ -0,0 +1,1 @@ |
227 | +add_subdirectory(xcursor) |
228 | |
229 | === added directory 'plugins/Cursor/3rd_party/xcursor' |
230 | === added file 'plugins/Cursor/3rd_party/xcursor/CMakeLists.txt' |
231 | --- plugins/Cursor/3rd_party/xcursor/CMakeLists.txt 1970-01-01 00:00:00 +0000 |
232 | +++ plugins/Cursor/3rd_party/xcursor/CMakeLists.txt 2015-10-26 12:04:03 +0000 |
233 | @@ -0,0 +1,15 @@ |
234 | +add_definitions(-D_DEFAULT_SOURCE=1) |
235 | + |
236 | +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC") |
237 | + |
238 | +set( |
239 | + XCURSOR_SOURCES |
240 | + |
241 | + xcursor.c |
242 | +) |
243 | + |
244 | +add_library( |
245 | + xcursorloader-static STATIC |
246 | + |
247 | + ${XCURSOR_SOURCES} |
248 | +) |
249 | |
250 | === added file 'plugins/Cursor/3rd_party/xcursor/xcursor.c' |
251 | --- plugins/Cursor/3rd_party/xcursor/xcursor.c 1970-01-01 00:00:00 +0000 |
252 | +++ plugins/Cursor/3rd_party/xcursor/xcursor.c 2015-10-26 12:04:03 +0000 |
253 | @@ -0,0 +1,968 @@ |
254 | +/* |
255 | + * Copyright © 2002 Keith Packard |
256 | + * |
257 | + * Permission to use, copy, modify, distribute, and sell this software and its |
258 | + * documentation for any purpose is hereby granted without fee, provided that |
259 | + * the above copyright notice appear in all copies and that both that |
260 | + * copyright notice and this permission notice appear in supporting |
261 | + * documentation, and that the name of Keith Packard not be used in |
262 | + * advertising or publicity pertaining to distribution of the software without |
263 | + * specific, written prior permission. Keith Packard makes no |
264 | + * representations about the suitability of this software for any purpose. It |
265 | + * is provided "as is" without express or implied warranty. |
266 | + * |
267 | + * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, |
268 | + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO |
269 | + * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR |
270 | + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, |
271 | + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER |
272 | + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR |
273 | + * PERFORMANCE OF THIS SOFTWARE. |
274 | + */ |
275 | + |
276 | +#include "xcursor.h" |
277 | +#include <stdio.h> |
278 | +#include <stdlib.h> |
279 | +#include <string.h> |
280 | +#include <dirent.h> |
281 | + |
282 | +/* |
283 | + * From libXcursor/include/X11/extensions/Xcursor.h |
284 | + */ |
285 | + |
286 | +#define XcursorTrue 1 |
287 | +#define XcursorFalse 0 |
288 | + |
289 | +/* |
290 | + * Cursor files start with a header. The header |
291 | + * contains a magic number, a version number and a |
292 | + * table of contents which has type and offset information |
293 | + * for the remaining tables in the file. |
294 | + * |
295 | + * File minor versions increment for compatible changes |
296 | + * File major versions increment for incompatible changes (never, we hope) |
297 | + * |
298 | + * Chunks of the same type are always upward compatible. Incompatible |
299 | + * changes are made with new chunk types; the old data can remain under |
300 | + * the old type. Upward compatible changes can add header data as the |
301 | + * header lengths are specified in the file. |
302 | + * |
303 | + * File: |
304 | + * FileHeader |
305 | + * LISTofChunk |
306 | + * |
307 | + * FileHeader: |
308 | + * CARD32 magic magic number |
309 | + * CARD32 header bytes in file header |
310 | + * CARD32 version file version |
311 | + * CARD32 ntoc number of toc entries |
312 | + * LISTofFileToc toc table of contents |
313 | + * |
314 | + * FileToc: |
315 | + * CARD32 type entry type |
316 | + * CARD32 subtype entry subtype (size for images) |
317 | + * CARD32 position absolute file position |
318 | + */ |
319 | + |
320 | +#define XCURSOR_MAGIC 0x72756358 /* "Xcur" LSBFirst */ |
321 | + |
322 | +/* |
323 | + * Current Xcursor version number. Will be substituted by configure |
324 | + * from the version in the libXcursor configure.ac file. |
325 | + */ |
326 | + |
327 | +#define XCURSOR_LIB_MAJOR 1 |
328 | +#define XCURSOR_LIB_MINOR 1 |
329 | +#define XCURSOR_LIB_REVISION 13 |
330 | +#define XCURSOR_LIB_VERSION ((XCURSOR_LIB_MAJOR * 10000) + \ |
331 | + (XCURSOR_LIB_MINOR * 100) + \ |
332 | + (XCURSOR_LIB_REVISION)) |
333 | + |
334 | +/* |
335 | + * This version number is stored in cursor files; changes to the |
336 | + * file format require updating this version number |
337 | + */ |
338 | +#define XCURSOR_FILE_MAJOR 1 |
339 | +#define XCURSOR_FILE_MINOR 0 |
340 | +#define XCURSOR_FILE_VERSION ((XCURSOR_FILE_MAJOR << 16) | (XCURSOR_FILE_MINOR)) |
341 | +#define XCURSOR_FILE_HEADER_LEN (4 * 4) |
342 | +#define XCURSOR_FILE_TOC_LEN (3 * 4) |
343 | + |
344 | +typedef struct _XcursorFileToc { |
345 | + XcursorUInt type; /* chunk type */ |
346 | + XcursorUInt subtype; /* subtype (size for images) */ |
347 | + XcursorUInt position; /* absolute position in file */ |
348 | +} XcursorFileToc; |
349 | + |
350 | +typedef struct _XcursorFileHeader { |
351 | + XcursorUInt magic; /* magic number */ |
352 | + XcursorUInt header; /* byte length of header */ |
353 | + XcursorUInt version; /* file version number */ |
354 | + XcursorUInt ntoc; /* number of toc entries */ |
355 | + XcursorFileToc *tocs; /* table of contents */ |
356 | +} XcursorFileHeader; |
357 | + |
358 | +/* |
359 | + * The rest of the file is a list of chunks, each tagged by type |
360 | + * and version. |
361 | + * |
362 | + * Chunk: |
363 | + * ChunkHeader |
364 | + * <extra type-specific header fields> |
365 | + * <type-specific data> |
366 | + * |
367 | + * ChunkHeader: |
368 | + * CARD32 header bytes in chunk header + type header |
369 | + * CARD32 type chunk type |
370 | + * CARD32 subtype chunk subtype |
371 | + * CARD32 version chunk type version |
372 | + */ |
373 | + |
374 | +#define XCURSOR_CHUNK_HEADER_LEN (4 * 4) |
375 | + |
376 | +typedef struct _XcursorChunkHeader { |
377 | + XcursorUInt header; /* bytes in chunk header */ |
378 | + XcursorUInt type; /* chunk type */ |
379 | + XcursorUInt subtype; /* chunk subtype (size for images) */ |
380 | + XcursorUInt version; /* version of this type */ |
381 | +} XcursorChunkHeader; |
382 | + |
383 | +/* |
384 | + * Here's a list of the known chunk types |
385 | + */ |
386 | + |
387 | +/* |
388 | + * Comments consist of a 4-byte length field followed by |
389 | + * UTF-8 encoded text |
390 | + * |
391 | + * Comment: |
392 | + * ChunkHeader header chunk header |
393 | + * CARD32 length bytes in text |
394 | + * LISTofCARD8 text UTF-8 encoded text |
395 | + */ |
396 | + |
397 | +#define XCURSOR_COMMENT_TYPE 0xfffe0001 |
398 | +#define XCURSOR_COMMENT_VERSION 1 |
399 | +#define XCURSOR_COMMENT_HEADER_LEN (XCURSOR_CHUNK_HEADER_LEN + (1 *4)) |
400 | +#define XCURSOR_COMMENT_COPYRIGHT 1 |
401 | +#define XCURSOR_COMMENT_LICENSE 2 |
402 | +#define XCURSOR_COMMENT_OTHER 3 |
403 | +#define XCURSOR_COMMENT_MAX_LEN 0x100000 |
404 | + |
405 | +typedef struct _XcursorComment { |
406 | + XcursorUInt version; |
407 | + XcursorUInt comment_type; |
408 | + char *comment; |
409 | +} XcursorComment; |
410 | + |
411 | +/* |
412 | + * Each cursor image occupies a separate image chunk. |
413 | + * The length of the image header follows the chunk header |
414 | + * so that future versions can extend the header without |
415 | + * breaking older applications |
416 | + * |
417 | + * Image: |
418 | + * ChunkHeader header chunk header |
419 | + * CARD32 width actual width |
420 | + * CARD32 height actual height |
421 | + * CARD32 xhot hot spot x |
422 | + * CARD32 yhot hot spot y |
423 | + * CARD32 delay animation delay |
424 | + * LISTofCARD32 pixels ARGB pixels |
425 | + */ |
426 | + |
427 | +#define XCURSOR_IMAGE_TYPE 0xfffd0002 |
428 | +#define XCURSOR_IMAGE_VERSION 1 |
429 | +#define XCURSOR_IMAGE_HEADER_LEN (XCURSOR_CHUNK_HEADER_LEN + (5*4)) |
430 | +#define XCURSOR_IMAGE_MAX_SIZE 0x7fff /* 32767x32767 max cursor size */ |
431 | + |
432 | +typedef struct _XcursorFile XcursorFile; |
433 | + |
434 | +struct _XcursorFile { |
435 | + void *closure; |
436 | + int (*read) (XcursorFile *file, unsigned char *buf, int len); |
437 | + int (*write) (XcursorFile *file, unsigned char *buf, int len); |
438 | + int (*seek) (XcursorFile *file, long offset, int whence); |
439 | +}; |
440 | + |
441 | +typedef struct _XcursorComments { |
442 | + int ncomment; /* number of comments */ |
443 | + XcursorComment **comments; /* array of XcursorComment pointers */ |
444 | +} XcursorComments; |
445 | + |
446 | +/* |
447 | + * From libXcursor/src/file.c |
448 | + */ |
449 | + |
450 | +static XcursorImage * |
451 | +XcursorImageCreate (int width, int height) |
452 | +{ |
453 | + XcursorImage *image; |
454 | + |
455 | + image = malloc (sizeof (XcursorImage) + |
456 | + width * height * sizeof (XcursorPixel)); |
457 | + if (!image) |
458 | + return NULL; |
459 | + image->version = XCURSOR_IMAGE_VERSION; |
460 | + image->pixels = (XcursorPixel *) (image + 1); |
461 | + image->size = width > height ? width : height; |
462 | + image->width = width; |
463 | + image->height = height; |
464 | + image->delay = 0; |
465 | + return image; |
466 | +} |
467 | + |
468 | +static void |
469 | +XcursorImageDestroy (XcursorImage *image) |
470 | +{ |
471 | + free (image); |
472 | +} |
473 | + |
474 | +static XcursorImages * |
475 | +XcursorImagesCreate (int size) |
476 | +{ |
477 | + XcursorImages *images; |
478 | + |
479 | + images = malloc (sizeof (XcursorImages) + |
480 | + size * sizeof (XcursorImage *)); |
481 | + if (!images) |
482 | + return NULL; |
483 | + images->nimage = 0; |
484 | + images->images = (XcursorImage **) (images + 1); |
485 | + images->name = NULL; |
486 | + return images; |
487 | +} |
488 | + |
489 | +void |
490 | +XcursorImagesDestroy (XcursorImages *images) |
491 | +{ |
492 | + int n; |
493 | + |
494 | + if (!images) |
495 | + return; |
496 | + |
497 | + for (n = 0; n < images->nimage; n++) |
498 | + XcursorImageDestroy (images->images[n]); |
499 | + if (images->name) |
500 | + free (images->name); |
501 | + free (images); |
502 | +} |
503 | + |
504 | +static void |
505 | +XcursorImagesSetName (XcursorImages *images, const char *name) |
506 | +{ |
507 | + char *new; |
508 | + |
509 | + if (!images || !name) |
510 | + return; |
511 | + |
512 | + new = malloc (strlen (name) + 1); |
513 | + |
514 | + if (!new) |
515 | + return; |
516 | + |
517 | + strcpy (new, name); |
518 | + if (images->name) |
519 | + free (images->name); |
520 | + images->name = new; |
521 | +} |
522 | + |
523 | +static XcursorBool |
524 | +_XcursorReadUInt (XcursorFile *file, XcursorUInt *u) |
525 | +{ |
526 | + unsigned char bytes[4]; |
527 | + |
528 | + if (!file || !u) |
529 | + return XcursorFalse; |
530 | + |
531 | + if ((*file->read) (file, bytes, 4) != 4) |
532 | + return XcursorFalse; |
533 | + *u = ((bytes[0] << 0) | |
534 | + (bytes[1] << 8) | |
535 | + (bytes[2] << 16) | |
536 | + (bytes[3] << 24)); |
537 | + return XcursorTrue; |
538 | +} |
539 | + |
540 | +static void |
541 | +_XcursorFileHeaderDestroy (XcursorFileHeader *fileHeader) |
542 | +{ |
543 | + free (fileHeader); |
544 | +} |
545 | + |
546 | +static XcursorFileHeader * |
547 | +_XcursorFileHeaderCreate (int ntoc) |
548 | +{ |
549 | + XcursorFileHeader *fileHeader; |
550 | + |
551 | + if (ntoc > 0x10000) |
552 | + return NULL; |
553 | + fileHeader = malloc (sizeof (XcursorFileHeader) + |
554 | + ntoc * sizeof (XcursorFileToc)); |
555 | + if (!fileHeader) |
556 | + return NULL; |
557 | + fileHeader->magic = XCURSOR_MAGIC; |
558 | + fileHeader->header = XCURSOR_FILE_HEADER_LEN; |
559 | + fileHeader->version = XCURSOR_FILE_VERSION; |
560 | + fileHeader->ntoc = ntoc; |
561 | + fileHeader->tocs = (XcursorFileToc *) (fileHeader + 1); |
562 | + return fileHeader; |
563 | +} |
564 | + |
565 | +static XcursorFileHeader * |
566 | +_XcursorReadFileHeader (XcursorFile *file) |
567 | +{ |
568 | + XcursorFileHeader head, *fileHeader; |
569 | + XcursorUInt skip; |
570 | + unsigned int n; |
571 | + |
572 | + if (!file) |
573 | + return NULL; |
574 | + |
575 | + if (!_XcursorReadUInt (file, &head.magic)) |
576 | + return NULL; |
577 | + if (head.magic != XCURSOR_MAGIC) |
578 | + return NULL; |
579 | + if (!_XcursorReadUInt (file, &head.header)) |
580 | + return NULL; |
581 | + if (!_XcursorReadUInt (file, &head.version)) |
582 | + return NULL; |
583 | + if (!_XcursorReadUInt (file, &head.ntoc)) |
584 | + return NULL; |
585 | + skip = head.header - XCURSOR_FILE_HEADER_LEN; |
586 | + if (skip) |
587 | + if ((*file->seek) (file, skip, SEEK_CUR) == EOF) |
588 | + return NULL; |
589 | + fileHeader = _XcursorFileHeaderCreate (head.ntoc); |
590 | + if (!fileHeader) |
591 | + return NULL; |
592 | + fileHeader->magic = head.magic; |
593 | + fileHeader->header = head.header; |
594 | + fileHeader->version = head.version; |
595 | + fileHeader->ntoc = head.ntoc; |
596 | + for (n = 0; n < fileHeader->ntoc; n++) |
597 | + { |
598 | + if (!_XcursorReadUInt (file, &fileHeader->tocs[n].type)) |
599 | + break; |
600 | + if (!_XcursorReadUInt (file, &fileHeader->tocs[n].subtype)) |
601 | + break; |
602 | + if (!_XcursorReadUInt (file, &fileHeader->tocs[n].position)) |
603 | + break; |
604 | + } |
605 | + if (n != fileHeader->ntoc) |
606 | + { |
607 | + _XcursorFileHeaderDestroy (fileHeader); |
608 | + return NULL; |
609 | + } |
610 | + return fileHeader; |
611 | +} |
612 | + |
613 | +static XcursorBool |
614 | +_XcursorSeekToToc (XcursorFile *file, |
615 | + XcursorFileHeader *fileHeader, |
616 | + int toc) |
617 | +{ |
618 | + if (!file || !fileHeader || \ |
619 | + (*file->seek) (file, fileHeader->tocs[toc].position, SEEK_SET) == EOF) |
620 | + return XcursorFalse; |
621 | + return XcursorTrue; |
622 | +} |
623 | + |
624 | +static XcursorBool |
625 | +_XcursorFileReadChunkHeader (XcursorFile *file, |
626 | + XcursorFileHeader *fileHeader, |
627 | + int toc, |
628 | + XcursorChunkHeader *chunkHeader) |
629 | +{ |
630 | + if (!file || !fileHeader || !chunkHeader) |
631 | + return XcursorFalse; |
632 | + if (!_XcursorSeekToToc (file, fileHeader, toc)) |
633 | + return XcursorFalse; |
634 | + if (!_XcursorReadUInt (file, &chunkHeader->header)) |
635 | + return XcursorFalse; |
636 | + if (!_XcursorReadUInt (file, &chunkHeader->type)) |
637 | + return XcursorFalse; |
638 | + if (!_XcursorReadUInt (file, &chunkHeader->subtype)) |
639 | + return XcursorFalse; |
640 | + if (!_XcursorReadUInt (file, &chunkHeader->version)) |
641 | + return XcursorFalse; |
642 | + /* sanity check */ |
643 | + if (chunkHeader->type != fileHeader->tocs[toc].type || |
644 | + chunkHeader->subtype != fileHeader->tocs[toc].subtype) |
645 | + return XcursorFalse; |
646 | + return XcursorTrue; |
647 | +} |
648 | + |
649 | +#define dist(a,b) ((a) > (b) ? (a) - (b) : (b) - (a)) |
650 | + |
651 | +static XcursorDim |
652 | +_XcursorFindBestSize (XcursorFileHeader *fileHeader, |
653 | + XcursorDim size, |
654 | + int *nsizesp) |
655 | +{ |
656 | + unsigned int n; |
657 | + int nsizes = 0; |
658 | + XcursorDim bestSize = 0; |
659 | + XcursorDim thisSize; |
660 | + |
661 | + if (!fileHeader || !nsizesp) |
662 | + return 0; |
663 | + |
664 | + for (n = 0; n < fileHeader->ntoc; n++) |
665 | + { |
666 | + if (fileHeader->tocs[n].type != XCURSOR_IMAGE_TYPE) |
667 | + continue; |
668 | + thisSize = fileHeader->tocs[n].subtype; |
669 | + if (!bestSize || dist (thisSize, size) < dist (bestSize, size)) |
670 | + { |
671 | + bestSize = thisSize; |
672 | + nsizes = 1; |
673 | + } |
674 | + else if (thisSize == bestSize) |
675 | + nsizes++; |
676 | + } |
677 | + *nsizesp = nsizes; |
678 | + return bestSize; |
679 | +} |
680 | + |
681 | +static int |
682 | +_XcursorFindImageToc (XcursorFileHeader *fileHeader, |
683 | + XcursorDim size, |
684 | + int count) |
685 | +{ |
686 | + unsigned int toc; |
687 | + XcursorDim thisSize; |
688 | + |
689 | + if (!fileHeader) |
690 | + return 0; |
691 | + |
692 | + for (toc = 0; toc < fileHeader->ntoc; toc++) |
693 | + { |
694 | + if (fileHeader->tocs[toc].type != XCURSOR_IMAGE_TYPE) |
695 | + continue; |
696 | + thisSize = fileHeader->tocs[toc].subtype; |
697 | + if (thisSize != size) |
698 | + continue; |
699 | + if (!count) |
700 | + break; |
701 | + count--; |
702 | + } |
703 | + if (toc == fileHeader->ntoc) |
704 | + return -1; |
705 | + return toc; |
706 | +} |
707 | + |
708 | +static XcursorImage * |
709 | +_XcursorReadImage (XcursorFile *file, |
710 | + XcursorFileHeader *fileHeader, |
711 | + int toc) |
712 | +{ |
713 | + XcursorChunkHeader chunkHeader; |
714 | + XcursorImage head; |
715 | + XcursorImage *image; |
716 | + int n; |
717 | + XcursorPixel *p; |
718 | + |
719 | + if (!file || !fileHeader) |
720 | + return NULL; |
721 | + |
722 | + if (!_XcursorFileReadChunkHeader (file, fileHeader, toc, &chunkHeader)) |
723 | + return NULL; |
724 | + if (!_XcursorReadUInt (file, &head.width)) |
725 | + return NULL; |
726 | + if (!_XcursorReadUInt (file, &head.height)) |
727 | + return NULL; |
728 | + if (!_XcursorReadUInt (file, &head.xhot)) |
729 | + return NULL; |
730 | + if (!_XcursorReadUInt (file, &head.yhot)) |
731 | + return NULL; |
732 | + if (!_XcursorReadUInt (file, &head.delay)) |
733 | + return NULL; |
734 | + /* sanity check data */ |
735 | + if (head.width >= 0x10000 || head.height > 0x10000) |
736 | + return NULL; |
737 | + if (head.width == 0 || head.height == 0) |
738 | + return NULL; |
739 | + if (head.xhot > head.width || head.yhot > head.height) |
740 | + return NULL; |
741 | + |
742 | + /* Create the image and initialize it */ |
743 | + image = XcursorImageCreate (head.width, head.height); |
744 | + if (image == NULL) |
745 | + return NULL; |
746 | + if (chunkHeader.version < image->version) |
747 | + image->version = chunkHeader.version; |
748 | + image->size = chunkHeader.subtype; |
749 | + image->xhot = head.xhot; |
750 | + image->yhot = head.yhot; |
751 | + image->delay = head.delay; |
752 | + n = image->width * image->height; |
753 | + p = image->pixels; |
754 | + while (n--) |
755 | + { |
756 | + if (!_XcursorReadUInt (file, p)) |
757 | + { |
758 | + XcursorImageDestroy (image); |
759 | + return NULL; |
760 | + } |
761 | + p++; |
762 | + } |
763 | + return image; |
764 | +} |
765 | + |
766 | +static XcursorImages * |
767 | +XcursorXcFileLoadImages (XcursorFile *file, int size) |
768 | +{ |
769 | + XcursorFileHeader *fileHeader; |
770 | + XcursorDim bestSize; |
771 | + int nsize; |
772 | + XcursorImages *images; |
773 | + int n; |
774 | + int toc; |
775 | + |
776 | + if (!file || size < 0) |
777 | + return NULL; |
778 | + fileHeader = _XcursorReadFileHeader (file); |
779 | + if (!fileHeader) |
780 | + return NULL; |
781 | + bestSize = _XcursorFindBestSize (fileHeader, (XcursorDim) size, &nsize); |
782 | + if (!bestSize) |
783 | + { |
784 | + _XcursorFileHeaderDestroy (fileHeader); |
785 | + return NULL; |
786 | + } |
787 | + images = XcursorImagesCreate (nsize); |
788 | + if (!images) |
789 | + { |
790 | + _XcursorFileHeaderDestroy (fileHeader); |
791 | + return NULL; |
792 | + } |
793 | + for (n = 0; n < nsize; n++) |
794 | + { |
795 | + toc = _XcursorFindImageToc (fileHeader, bestSize, n); |
796 | + if (toc < 0) |
797 | + break; |
798 | + images->images[images->nimage] = _XcursorReadImage (file, fileHeader, |
799 | + toc); |
800 | + if (!images->images[images->nimage]) |
801 | + break; |
802 | + images->nimage++; |
803 | + } |
804 | + _XcursorFileHeaderDestroy (fileHeader); |
805 | + if (images->nimage != nsize) |
806 | + { |
807 | + XcursorImagesDestroy (images); |
808 | + images = NULL; |
809 | + } |
810 | + return images; |
811 | +} |
812 | + |
813 | +static int |
814 | +_XcursorStdioFileRead (XcursorFile *file, unsigned char *buf, int len) |
815 | +{ |
816 | + FILE *f = file->closure; |
817 | + return fread (buf, 1, len, f); |
818 | +} |
819 | + |
820 | +static int |
821 | +_XcursorStdioFileWrite (XcursorFile *file, unsigned char *buf, int len) |
822 | +{ |
823 | + FILE *f = file->closure; |
824 | + return fwrite (buf, 1, len, f); |
825 | +} |
826 | + |
827 | +static int |
828 | +_XcursorStdioFileSeek (XcursorFile *file, long offset, int whence) |
829 | +{ |
830 | + FILE *f = file->closure; |
831 | + return fseek (f, offset, whence); |
832 | +} |
833 | + |
834 | +static void |
835 | +_XcursorStdioFileInitialize (FILE *stdfile, XcursorFile *file) |
836 | +{ |
837 | + file->closure = stdfile; |
838 | + file->read = _XcursorStdioFileRead; |
839 | + file->write = _XcursorStdioFileWrite; |
840 | + file->seek = _XcursorStdioFileSeek; |
841 | +} |
842 | + |
843 | +static XcursorImages * |
844 | +XcursorFileLoadImages (FILE *file, int size) |
845 | +{ |
846 | + XcursorFile f; |
847 | + |
848 | + if (!file) |
849 | + return NULL; |
850 | + |
851 | + _XcursorStdioFileInitialize (file, &f); |
852 | + return XcursorXcFileLoadImages (&f, size); |
853 | +} |
854 | + |
855 | +/* |
856 | + * From libXcursor/src/library.c |
857 | + */ |
858 | + |
859 | +#ifndef ICONDIR |
860 | +#define ICONDIR "/usr/X11R6/lib/X11/icons" |
861 | +#endif |
862 | + |
863 | +#ifndef XCURSORPATH |
864 | +#define XCURSORPATH "~/.icons:/usr/share/icons:/usr/share/pixmaps:~/.cursors:/usr/share/cursors/xorg-x11:"ICONDIR |
865 | +#endif |
866 | + |
867 | +static const char * |
868 | +XcursorLibraryPath (void) |
869 | +{ |
870 | + static const char *path; |
871 | + |
872 | + if (!path) |
873 | + { |
874 | + path = getenv ("XCURSOR_PATH"); |
875 | + if (!path) |
876 | + path = XCURSORPATH; |
877 | + } |
878 | + return path; |
879 | +} |
880 | + |
881 | +static void |
882 | +_XcursorAddPathElt (char *path, const char *elt, int len) |
883 | +{ |
884 | + int pathlen = strlen (path); |
885 | + |
886 | + /* append / if the path doesn't currently have one */ |
887 | + if (path[0] == '\0' || path[pathlen - 1] != '/') |
888 | + { |
889 | + strcat (path, "/"); |
890 | + pathlen++; |
891 | + } |
892 | + if (len == -1) |
893 | + len = strlen (elt); |
894 | + /* strip leading slashes */ |
895 | + while (len && elt[0] == '/') |
896 | + { |
897 | + elt++; |
898 | + len--; |
899 | + } |
900 | + strncpy (path + pathlen, elt, len); |
901 | + path[pathlen + len] = '\0'; |
902 | +} |
903 | + |
904 | +static char * |
905 | +_XcursorBuildThemeDir (const char *dir, const char *theme) |
906 | +{ |
907 | + const char *colon; |
908 | + const char *tcolon; |
909 | + char *full; |
910 | + char *home; |
911 | + int dirlen; |
912 | + int homelen; |
913 | + int themelen; |
914 | + int len; |
915 | + |
916 | + if (!dir || !theme) |
917 | + return NULL; |
918 | + |
919 | + colon = strchr (dir, ':'); |
920 | + if (!colon) |
921 | + colon = dir + strlen (dir); |
922 | + |
923 | + dirlen = colon - dir; |
924 | + |
925 | + tcolon = strchr (theme, ':'); |
926 | + if (!tcolon) |
927 | + tcolon = theme + strlen (theme); |
928 | + |
929 | + themelen = tcolon - theme; |
930 | + |
931 | + home = NULL; |
932 | + homelen = 0; |
933 | + if (*dir == '~') |
934 | + { |
935 | + home = getenv ("HOME"); |
936 | + if (!home) |
937 | + return NULL; |
938 | + homelen = strlen (home); |
939 | + dir++; |
940 | + dirlen--; |
941 | + } |
942 | + |
943 | + /* |
944 | + * add space for any needed directory separators, one per component, |
945 | + * and one for the trailing null |
946 | + */ |
947 | + len = 1 + homelen + 1 + dirlen + 1 + themelen + 1; |
948 | + |
949 | + full = malloc (len); |
950 | + if (!full) |
951 | + return NULL; |
952 | + full[0] = '\0'; |
953 | + |
954 | + if (home) |
955 | + _XcursorAddPathElt (full, home, -1); |
956 | + _XcursorAddPathElt (full, dir, dirlen); |
957 | + _XcursorAddPathElt (full, theme, themelen); |
958 | + return full; |
959 | +} |
960 | + |
961 | +static char * |
962 | +_XcursorBuildFullname (const char *dir, const char *subdir, const char *file) |
963 | +{ |
964 | + char *full; |
965 | + |
966 | + if (!dir || !subdir || !file) |
967 | + return NULL; |
968 | + |
969 | + full = malloc (strlen (dir) + 1 + strlen (subdir) + 1 + strlen (file) + 1); |
970 | + if (!full) |
971 | + return NULL; |
972 | + full[0] = '\0'; |
973 | + _XcursorAddPathElt (full, dir, -1); |
974 | + _XcursorAddPathElt (full, subdir, -1); |
975 | + _XcursorAddPathElt (full, file, -1); |
976 | + return full; |
977 | +} |
978 | + |
979 | +static const char * |
980 | +_XcursorNextPath (const char *path) |
981 | +{ |
982 | + char *colon = strchr (path, ':'); |
983 | + |
984 | + if (!colon) |
985 | + return NULL; |
986 | + return colon + 1; |
987 | +} |
988 | + |
989 | +#define XcursorWhite(c) ((c) == ' ' || (c) == '\t' || (c) == '\n') |
990 | +#define XcursorSep(c) ((c) == ';' || (c) == ',') |
991 | + |
992 | +static char * |
993 | +_XcursorThemeInherits (const char *full) |
994 | +{ |
995 | + char line[8192]; |
996 | + char *result = NULL; |
997 | + FILE *f; |
998 | + |
999 | + if (!full) |
1000 | + return NULL; |
1001 | + |
1002 | + f = fopen (full, "r"); |
1003 | + if (f) |
1004 | + { |
1005 | + while (fgets (line, sizeof (line), f)) |
1006 | + { |
1007 | + if (!strncmp (line, "Inherits", 8)) |
1008 | + { |
1009 | + char *l = line + 8; |
1010 | + char *r; |
1011 | + while (*l == ' ') l++; |
1012 | + if (*l != '=') continue; |
1013 | + l++; |
1014 | + while (*l == ' ') l++; |
1015 | + result = malloc (strlen (l) + 1); |
1016 | + if (result) |
1017 | + { |
1018 | + r = result; |
1019 | + while (*l) |
1020 | + { |
1021 | + while (XcursorSep(*l) || XcursorWhite (*l)) l++; |
1022 | + if (!*l) |
1023 | + break; |
1024 | + if (r != result) |
1025 | + *r++ = ':'; |
1026 | + while (*l && !XcursorWhite(*l) && |
1027 | + !XcursorSep(*l)) |
1028 | + *r++ = *l++; |
1029 | + } |
1030 | + *r++ = '\0'; |
1031 | + } |
1032 | + break; |
1033 | + } |
1034 | + } |
1035 | + fclose (f); |
1036 | + } |
1037 | + return result; |
1038 | +} |
1039 | + |
1040 | +static FILE * |
1041 | +XcursorScanTheme (const char *theme, const char *name) |
1042 | +{ |
1043 | + FILE *f = NULL; |
1044 | + char *full; |
1045 | + char *dir; |
1046 | + const char *path; |
1047 | + char *inherits = NULL; |
1048 | + const char *i; |
1049 | + |
1050 | + if (!theme || !name) |
1051 | + return NULL; |
1052 | + |
1053 | + /* |
1054 | + * Scan this theme |
1055 | + */ |
1056 | + for (path = XcursorLibraryPath (); |
1057 | + path && f == NULL; |
1058 | + path = _XcursorNextPath (path)) |
1059 | + { |
1060 | + dir = _XcursorBuildThemeDir (path, theme); |
1061 | + if (dir) |
1062 | + { |
1063 | + full = _XcursorBuildFullname (dir, "cursors", name); |
1064 | + if (full) |
1065 | + { |
1066 | + f = fopen (full, "r"); |
1067 | + free (full); |
1068 | + } |
1069 | + if (!f && !inherits) |
1070 | + { |
1071 | + full = _XcursorBuildFullname (dir, "", "index.theme"); |
1072 | + if (full) |
1073 | + { |
1074 | + inherits = _XcursorThemeInherits (full); |
1075 | + free (full); |
1076 | + } |
1077 | + } |
1078 | + free (dir); |
1079 | + } |
1080 | + } |
1081 | + /* |
1082 | + * Recurse to scan inherited themes |
1083 | + */ |
1084 | + for (i = inherits; i && f == NULL; i = _XcursorNextPath (i)) |
1085 | + f = XcursorScanTheme (i, name); |
1086 | + if (inherits != NULL) |
1087 | + free (inherits); |
1088 | + return f; |
1089 | +} |
1090 | + |
1091 | +XcursorImages * |
1092 | +XcursorLibraryLoadImages (const char *file, const char *theme, int size) |
1093 | +{ |
1094 | + FILE *f = NULL; |
1095 | + XcursorImages *images = NULL; |
1096 | + |
1097 | + if (!file) |
1098 | + return NULL; |
1099 | + |
1100 | + if (theme) |
1101 | + f = XcursorScanTheme (theme, file); |
1102 | + if (!f) |
1103 | + f = XcursorScanTheme ("default", file); |
1104 | + if (f) |
1105 | + { |
1106 | + images = XcursorFileLoadImages (f, size); |
1107 | + if (images) |
1108 | + XcursorImagesSetName (images, file); |
1109 | + fclose (f); |
1110 | + } |
1111 | + return images; |
1112 | +} |
1113 | + |
1114 | +static void |
1115 | +load_all_cursors_from_dir(const char *path, int size, |
1116 | + void (*load_callback)(XcursorImages *, void *), |
1117 | + void *user_data) |
1118 | +{ |
1119 | + FILE *f; |
1120 | + DIR *dir = opendir(path); |
1121 | + struct dirent *ent; |
1122 | + char *full; |
1123 | + XcursorImages *images; |
1124 | + |
1125 | + if (!dir) |
1126 | + return; |
1127 | + |
1128 | + for(ent = readdir(dir); ent; ent = readdir(dir)) { |
1129 | +#ifdef _DIRENT_HAVE_D_TYPE |
1130 | + if (ent->d_type != DT_UNKNOWN && |
1131 | + (ent->d_type != DT_REG && ent->d_type != DT_LNK)) |
1132 | + continue; |
1133 | +#endif |
1134 | + |
1135 | + full = _XcursorBuildFullname(path, "", ent->d_name); |
1136 | + if (!full) |
1137 | + continue; |
1138 | + |
1139 | + f = fopen(full, "r"); |
1140 | + if (!f) { |
1141 | + free(full); |
1142 | + continue; |
1143 | + } |
1144 | + |
1145 | + images = XcursorFileLoadImages(f, size); |
1146 | + |
1147 | + if (images) { |
1148 | + XcursorImagesSetName(images, ent->d_name); |
1149 | + load_callback(images, user_data); |
1150 | + } |
1151 | + |
1152 | + fclose (f); |
1153 | + free(full); |
1154 | + } |
1155 | + |
1156 | + closedir(dir); |
1157 | +} |
1158 | + |
1159 | +/** Load all the cursor of a theme |
1160 | + * |
1161 | + * This function loads all the cursor images of a given theme and its |
1162 | + * inherited themes. Each cursor is loaded into an XcursorImages object |
1163 | + * which is passed to the caller's load callback. If a cursor appears |
1164 | + * more than once across all the inherited themes, the load callback |
1165 | + * will be called multiple times, with possibly different XcursorImages |
1166 | + * object which have the same name. The user is expected to destroy the |
1167 | + * XcursorImages objects passed to the callback with |
1168 | + * XcursorImagesDestroy(). |
1169 | + * |
1170 | + * \param theme The name of theme that should be loaded |
1171 | + * \param size The desired size of the cursor images |
1172 | + * \param load_callback A callback function that will be called |
1173 | + * for each cursor loaded. The first parameter is the XcursorImages |
1174 | + * object representing the loaded cursor and the second is a pointer |
1175 | + * to data provided by the user. |
1176 | + * \param user_data The data that should be passed to the load callback |
1177 | + */ |
1178 | +void |
1179 | +xcursor_load_theme(const char *theme, int size, |
1180 | + void (*load_callback)(XcursorImages *, void *), |
1181 | + void *user_data) |
1182 | +{ |
1183 | + char *full, *dir; |
1184 | + char *inherits = NULL; |
1185 | + const char *path, *i; |
1186 | + |
1187 | + if (!theme) |
1188 | + theme = "default"; |
1189 | + |
1190 | + for (path = XcursorLibraryPath(); |
1191 | + path; |
1192 | + path = _XcursorNextPath(path)) { |
1193 | + dir = _XcursorBuildThemeDir(path, theme); |
1194 | + if (!dir) |
1195 | + continue; |
1196 | + |
1197 | + full = _XcursorBuildFullname(dir, "cursors", ""); |
1198 | + |
1199 | + if (full) { |
1200 | + load_all_cursors_from_dir(full, size, load_callback, |
1201 | + user_data); |
1202 | + free(full); |
1203 | + } |
1204 | + |
1205 | + if (!inherits) { |
1206 | + full = _XcursorBuildFullname(dir, "", "index.theme"); |
1207 | + if (full) { |
1208 | + inherits = _XcursorThemeInherits(full); |
1209 | + free(full); |
1210 | + } |
1211 | + } |
1212 | + |
1213 | + free(dir); |
1214 | + } |
1215 | + |
1216 | + for (i = inherits; i; i = _XcursorNextPath(i)) |
1217 | + xcursor_load_theme(i, size, load_callback, user_data); |
1218 | + |
1219 | + if (inherits) |
1220 | + free(inherits); |
1221 | +} |
1222 | |
1223 | === added file 'plugins/Cursor/3rd_party/xcursor/xcursor.h' |
1224 | --- plugins/Cursor/3rd_party/xcursor/xcursor.h 1970-01-01 00:00:00 +0000 |
1225 | +++ plugins/Cursor/3rd_party/xcursor/xcursor.h 2015-10-26 12:04:03 +0000 |
1226 | @@ -0,0 +1,65 @@ |
1227 | +/* |
1228 | + * Copyright © 2002 Keith Packard |
1229 | + * |
1230 | + * Permission to use, copy, modify, distribute, and sell this software and its |
1231 | + * documentation for any purpose is hereby granted without fee, provided that |
1232 | + * the above copyright notice appear in all copies and that both that |
1233 | + * copyright notice and this permission notice appear in supporting |
1234 | + * documentation, and that the name of Keith Packard not be used in |
1235 | + * advertising or publicity pertaining to distribution of the software without |
1236 | + * specific, written prior permission. Keith Packard makes no |
1237 | + * representations about the suitability of this software for any purpose. It |
1238 | + * is provided "as is" without express or implied warranty. |
1239 | + * |
1240 | + * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, |
1241 | + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO |
1242 | + * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR |
1243 | + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, |
1244 | + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER |
1245 | + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR |
1246 | + * PERFORMANCE OF THIS SOFTWARE. |
1247 | + */ |
1248 | + |
1249 | +#ifndef XCURSOR_H |
1250 | +#define XCURSOR_H |
1251 | + |
1252 | +#include <stdint.h> |
1253 | + |
1254 | + |
1255 | +typedef int XcursorBool; |
1256 | +typedef uint32_t XcursorUInt; |
1257 | + |
1258 | +typedef XcursorUInt XcursorDim; |
1259 | +typedef XcursorUInt XcursorPixel; |
1260 | + |
1261 | +typedef struct _XcursorImage { |
1262 | + XcursorUInt version; /* version of the image data */ |
1263 | + XcursorDim size; /* nominal size for matching */ |
1264 | + XcursorDim width; /* actual width */ |
1265 | + XcursorDim height; /* actual height */ |
1266 | + XcursorDim xhot; /* hot spot x (must be inside image) */ |
1267 | + XcursorDim yhot; /* hot spot y (must be inside image) */ |
1268 | + XcursorUInt delay; /* animation delay to next frame (ms) */ |
1269 | + XcursorPixel *pixels; /* pointer to pixels */ |
1270 | +} XcursorImage; |
1271 | + |
1272 | +/* |
1273 | + * Other data structures exposed by the library API |
1274 | + */ |
1275 | +typedef struct _XcursorImages { |
1276 | + int nimage; /* number of images */ |
1277 | + XcursorImage **images; /* array of XcursorImage pointers */ |
1278 | + char *name; /* name used to load images */ |
1279 | +} XcursorImages; |
1280 | + |
1281 | +XcursorImages * |
1282 | +XcursorLibraryLoadImages (const char *file, const char *theme, int size); |
1283 | + |
1284 | +void |
1285 | +XcursorImagesDestroy (XcursorImages *images); |
1286 | + |
1287 | +void |
1288 | +xcursor_load_theme(const char *theme, int size, |
1289 | + void (*load_callback)(XcursorImages *, void *), |
1290 | + void *user_data); |
1291 | +#endif |
1292 | |
1293 | === added file 'plugins/Cursor/CMakeLists.txt' |
1294 | --- plugins/Cursor/CMakeLists.txt 1970-01-01 00:00:00 +0000 |
1295 | +++ plugins/Cursor/CMakeLists.txt 2015-10-26 12:04:03 +0000 |
1296 | @@ -0,0 +1,28 @@ |
1297 | +add_subdirectory(3rd_party) |
1298 | + |
1299 | +include_directories( |
1300 | + ${CMAKE_CURRENT_SOURCE_DIR} |
1301 | + ${CMAKE_CURRENT_SOURCE_DIR}/3rd_party/xcursor |
1302 | + ${Qt5Gui_PRIVATE_INCLUDE_DIRS} |
1303 | +) |
1304 | + |
1305 | +set(QMLPLUGIN_SRC |
1306 | + plugin.cpp |
1307 | + MousePointer.cpp |
1308 | + CursorImageProvider.cpp |
1309 | + # We need to run moc on this header |
1310 | + ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/MirMousePointerInterface.h |
1311 | + ) |
1312 | + |
1313 | +add_library(Cursor-qml SHARED |
1314 | + ${QMLPLUGIN_SRC} |
1315 | + ) |
1316 | + |
1317 | +target_link_libraries(Cursor-qml |
1318 | + xcursorloader-static |
1319 | + ${QT5PLATFORM_SUPPORT_LDFLAGS} |
1320 | +) |
1321 | + |
1322 | +qt5_use_modules(Cursor-qml Qml Quick DBus Network Gui Sql Concurrent Svg) |
1323 | + |
1324 | +add_unity8_plugin(Cursor 1.0 Cursor TARGETS Cursor-qml) |
1325 | |
1326 | === added file 'plugins/Cursor/Cursor.qml' |
1327 | --- plugins/Cursor/Cursor.qml 1970-01-01 00:00:00 +0000 |
1328 | +++ plugins/Cursor/Cursor.qml 2015-10-26 12:04:03 +0000 |
1329 | @@ -0,0 +1,28 @@ |
1330 | +/* |
1331 | + * Copyright (C) 2015 Canonical, Ltd. |
1332 | + * |
1333 | + * This program is free software; you can redistribute it and/or modify |
1334 | + * it under the terms of the GNU General Public License as published by |
1335 | + * the Free Software Foundation; version 3. |
1336 | + * |
1337 | + * This program is distributed in the hope that it will be useful, |
1338 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1339 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1340 | + * GNU General Public License for more details. |
1341 | + * |
1342 | + * You should have received a copy of the GNU General Public License |
1343 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1344 | + */ |
1345 | + |
1346 | +import QtQuick 2.4 |
1347 | +import Cursor 1.0 // For MousePointer |
1348 | + |
1349 | +MousePointer { |
1350 | + id: mousePointer |
1351 | + |
1352 | + Image { |
1353 | + x: -mousePointer.hotspotX |
1354 | + y: -mousePointer.hotspotY |
1355 | + source: "image://cursor/" + mousePointer.themeName + "/" + mousePointer.cursorName |
1356 | + } |
1357 | +} |
1358 | |
1359 | === added file 'plugins/Cursor/CursorImageProvider.cpp' |
1360 | --- plugins/Cursor/CursorImageProvider.cpp 1970-01-01 00:00:00 +0000 |
1361 | +++ plugins/Cursor/CursorImageProvider.cpp 2015-10-26 12:04:03 +0000 |
1362 | @@ -0,0 +1,191 @@ |
1363 | +/* |
1364 | + * Copyright (C) 2015 Canonical, Ltd. |
1365 | + * |
1366 | + * This program is free software: you can redistribute it and/or modify it under |
1367 | + * the terms of the GNU Lesser General Public License version 3, as published by |
1368 | + * the Free Software Foundation. |
1369 | + * |
1370 | + * This program is distributed in the hope that it will be useful, but WITHOUT |
1371 | + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
1372 | + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
1373 | + * Lesser General Public License for more details. |
1374 | + * |
1375 | + * You should have received a copy of the GNU Lesser General Public License |
1376 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1377 | + */ |
1378 | + |
1379 | +#include "CursorImageProvider.h" |
1380 | + |
1381 | +#include <QDebug> |
1382 | +#include <QFile> |
1383 | +#include <QPainter> |
1384 | +#include <QSvgRenderer> |
1385 | + |
1386 | +CursorImageProvider *CursorImageProvider::m_instance = nullptr; |
1387 | + |
1388 | +///// |
1389 | +// BuiltInCursorImage |
1390 | + |
1391 | +BuiltInCursorImage::BuiltInCursorImage() |
1392 | +{ |
1393 | + const char *svgString = |
1394 | + "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>" |
1395 | + "<svg" |
1396 | + " xmlns:dc=\"http://purl.org/dc/elements/1.1/\"" |
1397 | + " xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"" |
1398 | + " xmlns:svg=\"http://www.w3.org/2000/svg\"" |
1399 | + " xmlns=\"http://www.w3.org/2000/svg\"" |
1400 | + " version=\"1.1\">" |
1401 | + " <path" |
1402 | + " style=\"fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:40;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1\"" |
1403 | + " d=\"M 20.504,50.94931 460.42533,518.14486 266.47603,515.61948 366.48114,719.16522 274.05218,770.68296 172.53185,559.56112 20.504,716.13476 Z\" />" |
1404 | + "</svg>"; |
1405 | + |
1406 | + qimage = QImage(20, 32, QImage::Format_ARGB32); |
1407 | + QPainter imagePainter(&qimage); |
1408 | + |
1409 | + QSvgRenderer *svgRenderer = new QSvgRenderer(QByteArray(svgString)); |
1410 | + svgRenderer->render(&imagePainter); |
1411 | + delete svgRenderer; |
1412 | +} |
1413 | + |
1414 | +///// |
1415 | +// XCursorImage |
1416 | + |
1417 | +XCursorImage::XCursorImage(const QString &theme, const QString &file) |
1418 | + : xcursorImages(nullptr) |
1419 | +{ |
1420 | + xcursorImages = XcursorLibraryLoadImages(QFile::encodeName(file), QFile::encodeName(theme), 32); |
1421 | + if (!xcursorImages) { |
1422 | + return; |
1423 | + } |
1424 | + |
1425 | + bool loaded = false; |
1426 | + for (int i = 0; i < xcursorImages->nimage && !loaded; ++i) { |
1427 | + XcursorImage *xcursorImage = xcursorImages->images[i]; |
1428 | + if (xcursorImage->size == 32) { |
1429 | + |
1430 | + qimage = QImage((uchar*)xcursorImage->pixels, |
1431 | + xcursorImage->width, xcursorImage->height, QImage::Format_ARGB32); |
1432 | + |
1433 | + hotspot.setX(xcursorImage->xhot); |
1434 | + hotspot.setY(xcursorImage->yhot); |
1435 | + |
1436 | + loaded = true; |
1437 | + } |
1438 | + } |
1439 | +} |
1440 | + |
1441 | +XCursorImage::~XCursorImage() |
1442 | +{ |
1443 | + XcursorImagesDestroy(xcursorImages); |
1444 | +} |
1445 | + |
1446 | +///// |
1447 | +// CursorImageProvider |
1448 | + |
1449 | +CursorImageProvider::CursorImageProvider() |
1450 | + : QQuickImageProvider(QQuickImageProvider::Image) |
1451 | +{ |
1452 | + if (m_instance) { |
1453 | + qFatal("Cannot have multiple CursorImageProvider instances"); |
1454 | + } |
1455 | + m_instance = this; |
1456 | +} |
1457 | + |
1458 | +CursorImageProvider::~CursorImageProvider() |
1459 | +{ |
1460 | + { |
1461 | + QList< QMap<QString, CursorImage*> > cursorList = m_cursors.values(); |
1462 | + |
1463 | + for (int i = 0; i < cursorList.count(); ++i) { |
1464 | + QList<CursorImage*> cursorImageList = cursorList[i].values(); |
1465 | + for (int j = 0; j < cursorImageList.count(); ++j) { |
1466 | + delete cursorImageList[j]; |
1467 | + } |
1468 | + } |
1469 | + } |
1470 | + |
1471 | + m_cursors.clear(); |
1472 | + m_instance = nullptr; |
1473 | +} |
1474 | + |
1475 | +QImage CursorImageProvider::requestImage(const QString &cursorThemeAndName, QSize *size, const QSize & /*requestedSize*/) |
1476 | +{ |
1477 | + CursorImage *cursorImage = fetchCursor(cursorThemeAndName); |
1478 | + size->setWidth(cursorImage->qimage.width()); |
1479 | + size->setHeight(cursorImage->qimage.height()); |
1480 | + |
1481 | + return cursorImage->qimage; |
1482 | +} |
1483 | + |
1484 | +QPoint CursorImageProvider::hotspot(const QString &themeName, const QString &cursorName) |
1485 | +{ |
1486 | + CursorImage *cursorImage = fetchCursor(themeName, cursorName); |
1487 | + if (cursorImage) { |
1488 | + return cursorImage->hotspot; |
1489 | + } else { |
1490 | + return QPoint(0,0); |
1491 | + } |
1492 | +} |
1493 | + |
1494 | +CursorImage *CursorImageProvider::fetchCursor(const QString &cursorThemeAndName) |
1495 | +{ |
1496 | + QString themeName; |
1497 | + QString cursorName; |
1498 | + { |
1499 | + QStringList themeAndNameList = cursorThemeAndName.split("/"); |
1500 | + if (themeAndNameList.size() != 2) { |
1501 | + return nullptr; |
1502 | + } |
1503 | + themeName = themeAndNameList[0]; |
1504 | + cursorName = themeAndNameList[1]; |
1505 | + } |
1506 | + |
1507 | + return fetchCursor(themeName, cursorName); |
1508 | +} |
1509 | + |
1510 | +CursorImage *CursorImageProvider::fetchCursor(const QString &themeName, const QString &cursorName) |
1511 | +{ |
1512 | + CursorImage *cursorImage = fetchCursorHelper(themeName, cursorName); |
1513 | + |
1514 | + // Try some fallbacks |
1515 | + if (cursorImage->qimage.isNull()) { |
1516 | + if (cursorName == "ibeam") { |
1517 | + qDebug() << "CursorImageProvider: \"ibeam\" not found, falling back to \"xterm\""; |
1518 | + cursorImage = fetchCursorHelper(themeName, "xterm"); |
1519 | + } else if (cursorName == "xterm") { |
1520 | + qDebug() << "CursorImageProvider: \"xterm\" not found, falling back to \"ibeam\""; |
1521 | + cursorImage = fetchCursorHelper(themeName, "ibeam"); |
1522 | + } |
1523 | + } |
1524 | + |
1525 | + // if it all fails, there must be at least a left_ptr |
1526 | + if (cursorImage->qimage.isNull() && cursorName != "left_ptr") { |
1527 | + qDebug() << "CursorImageProvider:" << cursorName |
1528 | + << "not found (nor its fallbacks, if any). Going for \"left_ptr\" as a last resort."; |
1529 | + cursorImage = fetchCursorHelper(themeName, "left_ptr"); |
1530 | + } |
1531 | + |
1532 | + if (cursorImage->qimage.isNull()) { |
1533 | + // finally, go for the built-in cursor |
1534 | + qWarning() << "CursorImageProvider: couldn't find any cursors. Using the built-in one"; |
1535 | + if (!m_builtInCursorImage) { |
1536 | + m_builtInCursorImage.reset(new BuiltInCursorImage); |
1537 | + } |
1538 | + cursorImage = m_builtInCursorImage.data(); |
1539 | + } |
1540 | + |
1541 | + return cursorImage; |
1542 | +} |
1543 | + |
1544 | +CursorImage *CursorImageProvider::fetchCursorHelper(const QString &themeName, const QString &cursorName) |
1545 | +{ |
1546 | + QMap<QString, CursorImage*> &themeCursors = m_cursors[themeName]; |
1547 | + |
1548 | + if (!themeCursors.contains(cursorName)) { |
1549 | + themeCursors[cursorName] = new XCursorImage(themeName, cursorName); |
1550 | + } |
1551 | + |
1552 | + return themeCursors[cursorName]; |
1553 | +} |
1554 | |
1555 | === added file 'plugins/Cursor/CursorImageProvider.h' |
1556 | --- plugins/Cursor/CursorImageProvider.h 1970-01-01 00:00:00 +0000 |
1557 | +++ plugins/Cursor/CursorImageProvider.h 2015-10-26 12:04:03 +0000 |
1558 | @@ -0,0 +1,76 @@ |
1559 | +/* |
1560 | + * Copyright (C) 2015 Canonical, Ltd. |
1561 | + * |
1562 | + * This program is free software: you can redistribute it and/or modify it under |
1563 | + * the terms of the GNU Lesser General Public License version 3, as published by |
1564 | + * the Free Software Foundation. |
1565 | + * |
1566 | + * This program is distributed in the hope that it will be useful, but WITHOUT |
1567 | + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
1568 | + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
1569 | + * Lesser General Public License for more details. |
1570 | + * |
1571 | + * You should have received a copy of the GNU Lesser General Public License |
1572 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1573 | + */ |
1574 | + |
1575 | +#ifndef CURSORIMAGEPROVIDER_H |
1576 | +#define CURSORIMAGEPROVIDER_H |
1577 | + |
1578 | +#include <QQuickImageProvider> |
1579 | +#include <QScopedPointer> |
1580 | + |
1581 | +// xcursor static lib |
1582 | +extern "C" |
1583 | +{ |
1584 | +#include <xcursor.h> |
1585 | +} |
1586 | + |
1587 | +class CursorImage { |
1588 | +public: |
1589 | + virtual ~CursorImage() {} |
1590 | + |
1591 | + QImage qimage; |
1592 | + QPoint hotspot; |
1593 | +}; |
1594 | + |
1595 | +class XCursorImage : public CursorImage { |
1596 | +public: |
1597 | + XCursorImage(const QString &theme, const QString &file); |
1598 | + virtual ~XCursorImage(); |
1599 | + |
1600 | + XcursorImages *xcursorImages; |
1601 | +}; |
1602 | + |
1603 | +class BuiltInCursorImage : public CursorImage { |
1604 | +public: |
1605 | + BuiltInCursorImage(); |
1606 | +}; |
1607 | + |
1608 | +class CursorImageProvider : public QQuickImageProvider |
1609 | +{ |
1610 | +public: |
1611 | + CursorImageProvider(); |
1612 | + virtual ~CursorImageProvider(); |
1613 | + |
1614 | + static CursorImageProvider *instance() { return m_instance; } |
1615 | + |
1616 | + |
1617 | + QImage requestImage(const QString &cursorName, QSize *size, const QSize &requestedSize) override; |
1618 | + |
1619 | + QPoint hotspot(const QString &themeName, const QString &cursorName); |
1620 | + |
1621 | +private: |
1622 | + CursorImage *fetchCursor(const QString &cursorThemeAndName); |
1623 | + CursorImage *fetchCursor(const QString &themeName, const QString &cursorName); |
1624 | + CursorImage *fetchCursorHelper(const QString &themeName, const QString &cursorName); |
1625 | + |
1626 | + // themeName -> (cursorName -> cursorImage) |
1627 | + QMap<QString, QMap<QString, CursorImage*> > m_cursors; |
1628 | + |
1629 | + QScopedPointer<CursorImage> m_builtInCursorImage; |
1630 | + |
1631 | + static CursorImageProvider *m_instance; |
1632 | +}; |
1633 | + |
1634 | +#endif // CURSORIMAGEPROVIDER_H |
1635 | |
1636 | === added file 'plugins/Cursor/MousePointer.cpp' |
1637 | --- plugins/Cursor/MousePointer.cpp 1970-01-01 00:00:00 +0000 |
1638 | +++ plugins/Cursor/MousePointer.cpp 2015-10-26 12:04:03 +0000 |
1639 | @@ -0,0 +1,125 @@ |
1640 | +/* |
1641 | + * Copyright (C) 2015 Canonical, Ltd. |
1642 | + * |
1643 | + * This program is free software: you can redistribute it and/or modify it under |
1644 | + * the terms of the GNU Lesser General Public License version 3, as published by |
1645 | + * the Free Software Foundation. |
1646 | + * |
1647 | + * This program is distributed in the hope that it will be useful, but WITHOUT |
1648 | + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
1649 | + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
1650 | + * Lesser General Public License for more details. |
1651 | + * |
1652 | + * You should have received a copy of the GNU Lesser General Public License |
1653 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1654 | + */ |
1655 | + |
1656 | +#include "MousePointer.h" |
1657 | +#include "CursorImageProvider.h" |
1658 | + |
1659 | +// Unity API |
1660 | +#include <unity/shell/application/MirPlatformCursor.h> |
1661 | + |
1662 | +#include <QQuickWindow> |
1663 | +#include <QGuiApplication> |
1664 | + |
1665 | +#include <qpa/qwindowsysteminterface.h> |
1666 | + |
1667 | +MousePointer::MousePointer(QQuickItem *parent) |
1668 | + : MirMousePointerInterface(parent) |
1669 | + , m_cursorName("left_ptr") |
1670 | + , m_themeName("default") |
1671 | + , m_hotspotX(0) |
1672 | + , m_hotspotY(0) |
1673 | +{ |
1674 | +} |
1675 | + |
1676 | +void MousePointer::handleMouseEvent(ulong timestamp, QPointF movement, Qt::MouseButtons buttons, |
1677 | + Qt::KeyboardModifiers modifiers) |
1678 | +{ |
1679 | + if (!parentItem()) { |
1680 | + return; |
1681 | + } |
1682 | + |
1683 | + qreal newX = x() + movement.x(); |
1684 | + if (newX < 0) { |
1685 | + newX = 0; |
1686 | + } else if (newX > parentItem()->width()) { |
1687 | + newX = parentItem()->width(); |
1688 | + } |
1689 | + setX(newX); |
1690 | + |
1691 | + qreal newY = y() + movement.y(); |
1692 | + if (newY < 0) { |
1693 | + newY = 0; |
1694 | + } else if (newY > parentItem()->height()) { |
1695 | + newY = parentItem()->height(); |
1696 | + } |
1697 | + setY(newY); |
1698 | + |
1699 | + QPointF scenePosition = mapToItem(nullptr, QPointF(0, 0)); |
1700 | + QWindowSystemInterface::handleMouseEvent(window(), timestamp, scenePosition /*local*/, scenePosition /*global*/, |
1701 | + buttons, modifiers); |
1702 | +} |
1703 | + |
1704 | +void MousePointer::itemChange(ItemChange change, const ItemChangeData &value) |
1705 | +{ |
1706 | + if (change == ItemSceneChange) { |
1707 | + registerWindow(value.window); |
1708 | + } |
1709 | +} |
1710 | + |
1711 | +void MousePointer::registerWindow(QWindow *window) |
1712 | +{ |
1713 | + if (m_registeredWindow && window != m_registeredWindow) { |
1714 | + auto previousCursor = dynamic_cast<MirPlatformCursor*>(m_registeredWindow->screen()->handle()->cursor()); |
1715 | + if (previousCursor) { |
1716 | + previousCursor->setMousePointer(nullptr); |
1717 | + } else { |
1718 | + qCritical("QPlatformCursor is not a MirPlatformCursor! Cursor module only works in a Mir server."); |
1719 | + } |
1720 | + } |
1721 | + |
1722 | + m_registeredWindow = window; |
1723 | + |
1724 | + if (m_registeredWindow) { |
1725 | + auto cursor = dynamic_cast<MirPlatformCursor*>(window->screen()->handle()->cursor()); |
1726 | + if (cursor) { |
1727 | + cursor->setMousePointer(this); |
1728 | + } else { |
1729 | + qCritical("QPlaformCursor is not a MirPlatformCursor! Cursor module only works in Mir."); |
1730 | + } |
1731 | + } |
1732 | +} |
1733 | + |
1734 | +void MousePointer::setCursorName(const QString &cursorName) |
1735 | +{ |
1736 | + if (cursorName != m_cursorName) { |
1737 | + m_cursorName = cursorName; |
1738 | + Q_EMIT cursorNameChanged(m_cursorName); |
1739 | + updateHotspot(); |
1740 | + } |
1741 | +} |
1742 | + |
1743 | +void MousePointer::updateHotspot() |
1744 | +{ |
1745 | + QPoint newHotspot = CursorImageProvider::instance()->hotspot(m_themeName, m_cursorName); |
1746 | + |
1747 | + if (m_hotspotX != newHotspot.x()) { |
1748 | + m_hotspotX = newHotspot.x(); |
1749 | + Q_EMIT hotspotXChanged(m_hotspotX); |
1750 | + } |
1751 | + |
1752 | + if (m_hotspotY != newHotspot.y()) { |
1753 | + m_hotspotY = newHotspot.y(); |
1754 | + Q_EMIT hotspotYChanged(m_hotspotY); |
1755 | + } |
1756 | +} |
1757 | + |
1758 | +void MousePointer::setThemeName(const QString &themeName) |
1759 | +{ |
1760 | + if (m_themeName != themeName) { |
1761 | + m_themeName = themeName; |
1762 | + Q_EMIT themeNameChanged(m_themeName); |
1763 | + } |
1764 | +} |
1765 | |
1766 | === added file 'plugins/Cursor/MousePointer.h' |
1767 | --- plugins/Cursor/MousePointer.h 1970-01-01 00:00:00 +0000 |
1768 | +++ plugins/Cursor/MousePointer.h 2015-10-26 12:04:03 +0000 |
1769 | @@ -0,0 +1,59 @@ |
1770 | +/* |
1771 | + * Copyright (C) 2015 Canonical, Ltd. |
1772 | + * |
1773 | + * This program is free software: you can redistribute it and/or modify it under |
1774 | + * the terms of the GNU Lesser General Public License version 3, as published by |
1775 | + * the Free Software Foundation. |
1776 | + * |
1777 | + * This program is distributed in the hope that it will be useful, but WITHOUT |
1778 | + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
1779 | + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
1780 | + * Lesser General Public License for more details. |
1781 | + * |
1782 | + * You should have received a copy of the GNU Lesser General Public License |
1783 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1784 | + */ |
1785 | + |
1786 | +#ifndef MOUSEPOINTER_H |
1787 | +#define MOUSEPOINTER_H |
1788 | + |
1789 | +// Qt |
1790 | +#include <QPointer> |
1791 | +#include <QWindow> |
1792 | + |
1793 | +// Unity API |
1794 | +#include <unity/shell/application/MirMousePointerInterface.h> |
1795 | + |
1796 | +class MousePointer : public MirMousePointerInterface { |
1797 | + Q_OBJECT |
1798 | +public: |
1799 | + MousePointer(QQuickItem *parent = nullptr); |
1800 | + |
1801 | + void setCursorName(const QString &qtCursorName) override; |
1802 | + QString cursorName() const override { return m_cursorName; } |
1803 | + |
1804 | + void setThemeName(const QString &themeName) override; |
1805 | + QString themeName() const override { return m_themeName; } |
1806 | + |
1807 | + qreal hotspotX() const override { return m_hotspotX; } |
1808 | + qreal hotspotY() const override { return m_hotspotY; } |
1809 | + |
1810 | +public Q_SLOTS: |
1811 | + void handleMouseEvent(ulong timestamp, QPointF movement, Qt::MouseButtons buttons, |
1812 | + Qt::KeyboardModifiers modifiers) override; |
1813 | + |
1814 | +protected: |
1815 | + void itemChange(ItemChange change, const ItemChangeData &value) override; |
1816 | + |
1817 | +private: |
1818 | + void registerWindow(QWindow *window); |
1819 | + void updateHotspot(); |
1820 | + |
1821 | + QPointer<QWindow> m_registeredWindow; |
1822 | + QString m_cursorName; |
1823 | + QString m_themeName; |
1824 | + int m_hotspotX; |
1825 | + int m_hotspotY; |
1826 | +}; |
1827 | + |
1828 | +#endif // MOUSEPOINTER_H |
1829 | |
1830 | === added file 'plugins/Cursor/plugin.cpp' |
1831 | --- plugins/Cursor/plugin.cpp 1970-01-01 00:00:00 +0000 |
1832 | +++ plugins/Cursor/plugin.cpp 2015-10-26 12:04:03 +0000 |
1833 | @@ -0,0 +1,39 @@ |
1834 | +/* |
1835 | + * Copyright (C) 2015 Canonical, Ltd. |
1836 | + * |
1837 | + * This program is free software; you can redistribute it and/or modify |
1838 | + * it under the terms of the GNU General Public License as published by |
1839 | + * the Free Software Foundation; version 3. |
1840 | + * |
1841 | + * This program is distributed in the hope that it will be useful, |
1842 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1843 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1844 | + * GNU General Public License for more details. |
1845 | + * |
1846 | + * You should have received a copy of the GNU General Public License |
1847 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1848 | + */ |
1849 | + |
1850 | +// Qt |
1851 | +#include <QtQml/qqml.h> |
1852 | +#include <QQmlContext> |
1853 | + |
1854 | +// self |
1855 | +#include "plugin.h" |
1856 | + |
1857 | +// local |
1858 | +#include "CursorImageProvider.h" |
1859 | +#include "MousePointer.h" |
1860 | + |
1861 | +void CursorPlugin::registerTypes(const char *uri) |
1862 | +{ |
1863 | + Q_ASSERT(uri == QLatin1String("Cursor")); |
1864 | + qmlRegisterType<MousePointer>(uri, 1, 0, "MousePointer"); |
1865 | +} |
1866 | + |
1867 | +void CursorPlugin::initializeEngine(QQmlEngine *engine, const char *uri) |
1868 | +{ |
1869 | + QQmlExtensionPlugin::initializeEngine(engine, uri); |
1870 | + |
1871 | + engine->addImageProvider(QLatin1String("cursor"), new CursorImageProvider()); |
1872 | +} |
1873 | |
1874 | === added file 'plugins/Cursor/plugin.h' |
1875 | --- plugins/Cursor/plugin.h 1970-01-01 00:00:00 +0000 |
1876 | +++ plugins/Cursor/plugin.h 2015-10-26 12:04:03 +0000 |
1877 | @@ -0,0 +1,33 @@ |
1878 | +/* |
1879 | + * Copyright (C) 2015 Canonical, Ltd. |
1880 | + * |
1881 | + * This program is free software; you can redistribute it and/or modify |
1882 | + * it under the terms of the GNU General Public License as published by |
1883 | + * the Free Software Foundation; version 3. |
1884 | + * |
1885 | + * This program is distributed in the hope that it will be useful, |
1886 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1887 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1888 | + * GNU General Public License for more details. |
1889 | + * |
1890 | + * You should have received a copy of the GNU General Public License |
1891 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1892 | + */ |
1893 | + |
1894 | +#ifndef CURSOR_PLUGIN_H |
1895 | +#define CURSOR_PLUGIN_H |
1896 | + |
1897 | +#include <QtQml/QQmlEngine> |
1898 | +#include <QtQml/QQmlExtensionPlugin> |
1899 | + |
1900 | +class CursorPlugin : public QQmlExtensionPlugin |
1901 | +{ |
1902 | + Q_OBJECT |
1903 | + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") |
1904 | + |
1905 | +public: |
1906 | + void registerTypes(const char *uri) override; |
1907 | + void initializeEngine(QQmlEngine *engine, const char *uri) override; |
1908 | +}; |
1909 | + |
1910 | +#endif // CURSOR_PLUGIN_H |
1911 | |
1912 | === added file 'plugins/Cursor/qmldir' |
1913 | --- plugins/Cursor/qmldir 1970-01-01 00:00:00 +0000 |
1914 | +++ plugins/Cursor/qmldir 2015-10-26 12:04:03 +0000 |
1915 | @@ -0,0 +1,3 @@ |
1916 | +module Cursor |
1917 | +plugin Cursor-qml |
1918 | +Cursor 1.0 Cursor.qml |
1919 | |
1920 | === modified file 'plugins/IntegratedLightDM/UsersModel.cpp' |
1921 | --- plugins/IntegratedLightDM/UsersModel.cpp 2015-04-30 09:31:51 +0000 |
1922 | +++ plugins/IntegratedLightDM/UsersModel.cpp 2015-10-26 12:04:03 +0000 |
1923 | @@ -43,16 +43,17 @@ |
1924 | |
1925 | QVariant MangleModel::data(const QModelIndex &index, int role) const |
1926 | { |
1927 | - QVariant data = QSortFilterProxyModel::data(index, role); |
1928 | + QVariant variantData = QSortFilterProxyModel::data(index, role); |
1929 | |
1930 | // If user's real name is empty, switch to unix name |
1931 | - if (role == QLightDM::UsersModel::RealNameRole && data.toString().isEmpty()) { |
1932 | - data = QSortFilterProxyModel::data(index, QLightDM::UsersModel::NameRole); |
1933 | - } else if (role == QLightDM::UsersModel::BackgroundPathRole && data.toString().startsWith('#')) { |
1934 | - data = "data:image/svg+xml,<svg><rect width='100%' height='100%' fill='" + data.toString() + "'/></svg>"; |
1935 | + if (role == QLightDM::UsersModel::RealNameRole && variantData.toString().isEmpty()) { |
1936 | + variantData = QSortFilterProxyModel::data(index, QLightDM::UsersModel::NameRole); |
1937 | + } else if (role == QLightDM::UsersModel::BackgroundPathRole && variantData.toString().startsWith('#')) { |
1938 | + const QString stringData = "data:image/svg+xml,<svg><rect width='100%' height='100%' fill='" + variantData.toString() + "'/></svg>"; |
1939 | + variantData = stringData; |
1940 | } |
1941 | |
1942 | - return data; |
1943 | + return variantData; |
1944 | } |
1945 | |
1946 | // **** Now we continue with actual UsersModel class **** |
1947 | |
1948 | === modified file 'plugins/IntegratedLightDM/liblightdm/UsersModelPrivate.cpp' |
1949 | --- plugins/IntegratedLightDM/liblightdm/UsersModelPrivate.cpp 2015-09-14 09:11:08 +0000 |
1950 | +++ plugins/IntegratedLightDM/liblightdm/UsersModelPrivate.cpp 2015-10-26 12:04:03 +0000 |
1951 | @@ -34,7 +34,8 @@ |
1952 | entries.reserve(users.count()); |
1953 | Q_FOREACH(const QString &user, users) |
1954 | { |
1955 | - QString name = settings.value(user + "/name", user[0].toUpper() + user.mid(1)).toString(); |
1956 | + QVariant defaultValue = QString(user[0].toUpper() + user.mid(1)); |
1957 | + QString name = settings.value(user + "/name", defaultValue).toString(); |
1958 | entries.append({user, name, 0, 0, false, false, 0, 0}); |
1959 | } |
1960 | } |
1961 | |
1962 | === modified file 'plugins/ScreenGrabber/screengrabber.cpp' |
1963 | --- plugins/ScreenGrabber/screengrabber.cpp 2015-09-23 15:14:01 +0000 |
1964 | +++ plugins/ScreenGrabber/screengrabber.cpp 2015-10-26 12:04:03 +0000 |
1965 | @@ -60,7 +60,7 @@ |
1966 | } |
1967 | } |
1968 | |
1969 | -void ScreenGrabber::captureAndSave() |
1970 | +void ScreenGrabber::captureAndSave(int angle) |
1971 | { |
1972 | if (fileNamePrefix.isEmpty()) |
1973 | { |
1974 | @@ -82,7 +82,7 @@ |
1975 | return; |
1976 | } |
1977 | |
1978 | - const QImage screenshot = main_window->grabWindow(); |
1979 | + const QImage screenshot = main_window->grabWindow().transformed(QTransform().rotate(angle)); |
1980 | const QString filename = makeFileName(); |
1981 | qDebug() << "Saving screenshot to" << filename; |
1982 | auto saveOp = QtConcurrent::run(saveScreenshot, screenshot, filename, getFormat(), screenshotQuality); |
1983 | |
1984 | === modified file 'plugins/ScreenGrabber/screengrabber.h' |
1985 | --- plugins/ScreenGrabber/screengrabber.h 2015-07-17 19:59:31 +0000 |
1986 | +++ plugins/ScreenGrabber/screengrabber.h 2015-10-26 12:04:03 +0000 |
1987 | @@ -29,7 +29,7 @@ |
1988 | ~ScreenGrabber() = default; |
1989 | |
1990 | public Q_SLOTS: |
1991 | - void captureAndSave(); |
1992 | + void captureAndSave(int angle = 0); |
1993 | |
1994 | Q_SIGNALS: |
1995 | void screenshotSaved(const QString &filename); |
1996 | |
1997 | === modified file 'plugins/Unity/CMakeLists.txt' |
1998 | --- plugins/Unity/CMakeLists.txt 2015-05-05 11:19:15 +0000 |
1999 | +++ plugins/Unity/CMakeLists.txt 2015-10-26 12:04:03 +0000 |
2000 | @@ -4,3 +4,4 @@ |
2001 | add_subdirectory(Session) |
2002 | add_subdirectory(DashCommunicator) |
2003 | add_subdirectory(InputInfo) |
2004 | +add_subdirectory(Platform) |
2005 | |
2006 | === modified file 'plugins/Unity/Launcher/desktopfilehandler.cpp' |
2007 | --- plugins/Unity/Launcher/desktopfilehandler.cpp 2015-09-14 09:41:55 +0000 |
2008 | +++ plugins/Unity/Launcher/desktopfilehandler.cpp 2015-10-26 12:04:03 +0000 |
2009 | @@ -111,8 +111,9 @@ |
2010 | settings.beginGroup(QStringLiteral("Desktop Entry")); |
2011 | |
2012 | // First try to find Name[xx_YY] and Name[xx] in .desktop file |
2013 | - QString locale = QLocale().name(); |
2014 | - QString shortLocale = locale.split('_').first(); |
2015 | + const QString locale = QLocale().name(); |
2016 | + const QStringList splitLocale = locale.split(QLatin1Char('_')); |
2017 | + const QString shortLocale = splitLocale.first(); |
2018 | |
2019 | if (locale != shortLocale && settings.contains(QStringLiteral("Name[%1]").arg(locale))) { |
2020 | return settings.value(QStringLiteral("Name[%1]").arg(locale)).toString(); |
2021 | |
2022 | === added directory 'plugins/Unity/Platform' |
2023 | === added file 'plugins/Unity/Platform/CMakeLists.txt' |
2024 | --- plugins/Unity/Platform/CMakeLists.txt 1970-01-01 00:00:00 +0000 |
2025 | +++ plugins/Unity/Platform/CMakeLists.txt 2015-10-26 12:04:03 +0000 |
2026 | @@ -0,0 +1,9 @@ |
2027 | +set(platformplugin_SRCS |
2028 | + platform.cpp |
2029 | + plugin.cpp) |
2030 | + |
2031 | +add_library(Platform-qml SHARED ${platformplugin_SRCS}) |
2032 | + |
2033 | +qt5_use_modules(Platform-qml DBus Qml) |
2034 | + |
2035 | +add_unity8_plugin(Unity.Platform 1.0 Unity/Platform TARGETS Platform-qml) |
2036 | |
2037 | === added file 'plugins/Unity/Platform/platform.cpp' |
2038 | --- plugins/Unity/Platform/platform.cpp 1970-01-01 00:00:00 +0000 |
2039 | +++ plugins/Unity/Platform/platform.cpp 2015-10-26 12:04:03 +0000 |
2040 | @@ -0,0 +1,43 @@ |
2041 | +/* |
2042 | + * Copyright (C) 2015 Canonical, Ltd. |
2043 | + * |
2044 | + * This program is free software; you can redistribute it and/or modify |
2045 | + * it under the terms of the GNU General Public License as published by |
2046 | + * the Free Software Foundation; version 3. |
2047 | + * |
2048 | + * This program is distributed in the hope that it will be useful, |
2049 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2050 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2051 | + * GNU General Public License for more details. |
2052 | + * |
2053 | + * You should have received a copy of the GNU General Public License |
2054 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2055 | + */ |
2056 | + |
2057 | +#include "platform.h" |
2058 | + |
2059 | +#include <QDBusConnection> |
2060 | + |
2061 | +Platform::Platform(QObject *parent) |
2062 | + : QObject(parent) |
2063 | + , m_iface("org.freedesktop.hostname1", "/org/freedesktop/hostname1", "org.freedesktop.hostname1", |
2064 | + QDBusConnection::systemBus(), this) |
2065 | +{ |
2066 | + QMetaObject::invokeMethod(this, "init"); |
2067 | +} |
2068 | + |
2069 | +void Platform::init() |
2070 | +{ |
2071 | + m_chassis = m_iface.property("Chassis").toString(); |
2072 | + m_isPC = (m_chassis == "desktop" || m_chassis == "laptop" || m_chassis == "server"); |
2073 | +} |
2074 | + |
2075 | +QString Platform::chassis() const |
2076 | +{ |
2077 | + return m_chassis; |
2078 | +} |
2079 | + |
2080 | +bool Platform::isPC() const |
2081 | +{ |
2082 | + return m_isPC; |
2083 | +} |
2084 | |
2085 | === added file 'plugins/Unity/Platform/platform.h' |
2086 | --- plugins/Unity/Platform/platform.h 1970-01-01 00:00:00 +0000 |
2087 | +++ plugins/Unity/Platform/platform.h 2015-10-26 12:04:03 +0000 |
2088 | @@ -0,0 +1,58 @@ |
2089 | +/* |
2090 | + * Copyright (C) 2015 Canonical, Ltd. |
2091 | + * |
2092 | + * This program is free software; you can redistribute it and/or modify |
2093 | + * it under the terms of the GNU General Public License as published by |
2094 | + * the Free Software Foundation; version 3. |
2095 | + * |
2096 | + * This program is distributed in the hope that it will be useful, |
2097 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2098 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2099 | + * GNU General Public License for more details. |
2100 | + * |
2101 | + * You should have received a copy of the GNU General Public License |
2102 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2103 | + */ |
2104 | + |
2105 | +#ifndef PLATFORM_H |
2106 | +#define PLATFORM_H |
2107 | + |
2108 | +#include <QDBusInterface> |
2109 | + |
2110 | +/** |
2111 | + * @brief The Platform class |
2112 | + * |
2113 | + * Wrapper around platform detection support (org.freedesktop.hostname1) |
2114 | + */ |
2115 | +class Platform: public QObject |
2116 | +{ |
2117 | + Q_OBJECT |
2118 | + /** |
2119 | + * The chassis property |
2120 | + * |
2121 | + * Supported values include: "laptop", "computer", "handset" or "tablet" |
2122 | + * For full list see: http://www.freedesktop.org/wiki/Software/systemd/hostnamed/ |
2123 | + */ |
2124 | + Q_PROPERTY(QString chassis READ chassis CONSTANT) |
2125 | + /** |
2126 | + * Whether the machine is an ordinary PC (desktop, laptop or server) |
2127 | + */ |
2128 | + Q_PROPERTY(bool isPC READ isPC CONSTANT) |
2129 | + |
2130 | +public: |
2131 | + Platform(QObject *parent = nullptr); |
2132 | + ~Platform() = default; |
2133 | + |
2134 | + QString chassis() const; |
2135 | + bool isPC() const; |
2136 | + |
2137 | +private Q_SLOTS: |
2138 | + void init(); |
2139 | + |
2140 | +private: |
2141 | + QDBusInterface m_iface; |
2142 | + QString m_chassis; |
2143 | + bool m_isPC; |
2144 | +}; |
2145 | + |
2146 | +#endif // PLATFORM_H |
2147 | |
2148 | === added file 'plugins/Unity/Platform/plugin.cpp' |
2149 | --- plugins/Unity/Platform/plugin.cpp 1970-01-01 00:00:00 +0000 |
2150 | +++ plugins/Unity/Platform/plugin.cpp 2015-10-26 12:04:03 +0000 |
2151 | @@ -0,0 +1,27 @@ |
2152 | +/* |
2153 | + * Copyright (C) 2015 Canonical, Ltd. |
2154 | + * |
2155 | + * This program is free software; you can redistribute it and/or modify |
2156 | + * it under the terms of the GNU General Public License as published by |
2157 | + * the Free Software Foundation; version 3. |
2158 | + * |
2159 | + * This program is distributed in the hope that it will be useful, |
2160 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2161 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2162 | + * GNU General Public License for more details. |
2163 | + * |
2164 | + * You should have received a copy of the GNU General Public License |
2165 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2166 | + */ |
2167 | + |
2168 | +#include "plugin.h" |
2169 | +#include "platform.h" |
2170 | + |
2171 | +#include <QtQml> |
2172 | + |
2173 | +void GlobalShortcutPlugin::registerTypes(const char *uri) |
2174 | +{ |
2175 | + Q_ASSERT(uri == QLatin1String("Unity.Platform")); |
2176 | + |
2177 | + qmlRegisterSingletonType<Platform>(uri, 1, 0, "Platform", [](QQmlEngine*, QJSEngine*) -> QObject* { return new Platform; }); |
2178 | +} |
2179 | |
2180 | === added file 'plugins/Unity/Platform/plugin.h' |
2181 | --- plugins/Unity/Platform/plugin.h 1970-01-01 00:00:00 +0000 |
2182 | +++ plugins/Unity/Platform/plugin.h 2015-10-26 12:04:03 +0000 |
2183 | @@ -0,0 +1,32 @@ |
2184 | +/* |
2185 | + * Copyright (C) 2015 Canonical, Ltd. |
2186 | + * |
2187 | + * This program is free software; you can redistribute it and/or modify |
2188 | + * it under the terms of the GNU General Public License as published by |
2189 | + * the Free Software Foundation; version 3. |
2190 | + * |
2191 | + * This program is distributed in the hope that it will be useful, |
2192 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2193 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2194 | + * GNU General Public License for more details. |
2195 | + * |
2196 | + * You should have received a copy of the GNU General Public License |
2197 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2198 | + */ |
2199 | + |
2200 | +#ifndef PLATFORMPLUGIN_H |
2201 | +#define PLATFORMPLUGIN_H |
2202 | + |
2203 | +#include <QQmlExtensionPlugin> |
2204 | + |
2205 | +class GlobalShortcutPlugin: public QQmlExtensionPlugin |
2206 | +{ |
2207 | + Q_OBJECT |
2208 | + Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid) |
2209 | + |
2210 | +public: |
2211 | + void registerTypes(const char *uri) override; |
2212 | +}; |
2213 | + |
2214 | + |
2215 | +#endif // PLATFORMPLUGIN_H |
2216 | |
2217 | === added file 'plugins/Unity/Platform/qmldir' |
2218 | --- plugins/Unity/Platform/qmldir 1970-01-01 00:00:00 +0000 |
2219 | +++ plugins/Unity/Platform/qmldir 2015-10-26 12:04:03 +0000 |
2220 | @@ -0,0 +1,2 @@ |
2221 | +module Unity.Platform |
2222 | +plugin Platform-qml |
2223 | |
2224 | === modified file 'plugins/Unity/Session/dbusunitysessionservice.cpp' |
2225 | --- plugins/Unity/Session/dbusunitysessionservice.cpp 2015-09-14 09:11:08 +0000 |
2226 | +++ plugins/Unity/Session/dbusunitysessionservice.cpp 2015-10-26 12:04:03 +0000 |
2227 | @@ -292,7 +292,8 @@ |
2228 | if (p) { |
2229 | const QString gecos = QString::fromLocal8Bit(p->pw_gecos); |
2230 | if (!gecos.isEmpty()) { |
2231 | - return gecos.split(QLatin1Char(',')).first(); |
2232 | + const QStringList splitGecos = gecos.split(QLatin1Char(',')); |
2233 | + return splitGecos.first(); |
2234 | } |
2235 | } |
2236 | |
2237 | |
2238 | === modified file 'plugins/Utils/CMakeLists.txt' |
2239 | --- plugins/Utils/CMakeLists.txt 2015-09-25 12:13:13 +0000 |
2240 | +++ plugins/Utils/CMakeLists.txt 2015-10-26 12:04:03 +0000 |
2241 | @@ -15,8 +15,6 @@ |
2242 | inputwatcher.cpp |
2243 | qlimitproxymodelqml.cpp |
2244 | unitysortfilterproxymodelqml.cpp |
2245 | - relativetimeformatter.cpp |
2246 | - timeformatter.cpp |
2247 | Timer.cpp |
2248 | unitymenumodelpaths.cpp |
2249 | windowkeysfilter.cpp |
2250 | |
2251 | === modified file 'plugins/Utils/plugin.cpp' |
2252 | --- plugins/Utils/plugin.cpp 2015-09-25 12:13:13 +0000 |
2253 | +++ plugins/Utils/plugin.cpp 2015-10-26 12:04:03 +0000 |
2254 | @@ -29,8 +29,6 @@ |
2255 | #include "inputwatcher.h" |
2256 | #include "qlimitproxymodelqml.h" |
2257 | #include "unitysortfilterproxymodelqml.h" |
2258 | -#include "relativetimeformatter.h" |
2259 | -#include "timeformatter.h" |
2260 | #include "unitymenumodelpaths.h" |
2261 | #include "windowkeysfilter.h" |
2262 | #include "windowscreenshotprovider.h" |
2263 | @@ -60,11 +58,8 @@ |
2264 | qmlRegisterType<QLimitProxyModelQML>(uri, 0, 1, "LimitProxyModel"); |
2265 | qmlRegisterType<UnitySortFilterProxyModelQML>(uri, 0, 1, "UnitySortFilterProxyModel"); |
2266 | qmlRegisterType<UnityMenuModelPaths>(uri, 0, 1, "UnityMenuModelPaths"); |
2267 | - qmlRegisterType<TimeFormatter>(uri, 0, 1, "TimeFormatter"); |
2268 | qmlRegisterType<WindowKeysFilter>(uri, 0, 1, "WindowKeysFilter"); |
2269 | - qmlRegisterType<GDateTimeFormatter>(uri, 0, 1, "GDateTimeFormatter"); |
2270 | qmlRegisterType<EasingCurve>(uri, 0, 1, "EasingCurve"); |
2271 | - qmlRegisterType<RelativeTimeFormatter>(uri, 0, 1, "RelativeTimeFormatter"); |
2272 | qmlRegisterSingletonType<WindowStateStorage>(uri, 0, 1, "WindowStateStorage", createWindowStateStorage); |
2273 | qmlRegisterType<InputWatcher>(uri, 0, 1, "InputWatcher"); |
2274 | qmlRegisterSingletonType<Constants>(uri, 0, 1, "Constants", createConstants); |
2275 | |
2276 | === removed file 'plugins/Utils/relativetimeformatter.cpp' |
2277 | --- plugins/Utils/relativetimeformatter.cpp 2015-09-21 13:17:30 +0000 |
2278 | +++ plugins/Utils/relativetimeformatter.cpp 1970-01-01 00:00:00 +0000 |
2279 | @@ -1,260 +0,0 @@ |
2280 | -/* |
2281 | - * Copyright 2014 Canonical Ltd. |
2282 | - * |
2283 | - * This program is free software; you can redistribute it and/or modify |
2284 | - * it under the terms of the GNU General Public License as published by |
2285 | - * the Free Software Foundation; version 3. |
2286 | - * |
2287 | - * This program is distributed in the hope that it will be useful, |
2288 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2289 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2290 | - * GNU General Public License for more details. |
2291 | - * |
2292 | - * You should have received a copy of the GNU General Public License |
2293 | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2294 | - * |
2295 | - */ |
2296 | - |
2297 | -// Local |
2298 | -#include "relativetimeformatter.h" |
2299 | - |
2300 | -// Qt |
2301 | -#include <QDateTime> |
2302 | - |
2303 | -// Other |
2304 | -#include <glib.h> |
2305 | -#include <glib/gi18n.h> |
2306 | -#include <locale.h> |
2307 | -#include <langinfo.h> |
2308 | -#include <string.h> |
2309 | - |
2310 | -RelativeTimeFormatter::RelativeTimeFormatter(QObject *parent) |
2311 | - : GDateTimeFormatter(parent) |
2312 | -{ |
2313 | -} |
2314 | - |
2315 | - /* Check the system locale setting to see if the format is 24-hour |
2316 | - time or 12-hour time */ |
2317 | -gboolean |
2318 | -is_locale_12h(void) |
2319 | -{ |
2320 | - int i; |
2321 | - static const char *formats_24h[] = {"%H", "%R", "%T", "%OH", "%k", nullptr}; |
2322 | - const char* t_fmt = nl_langinfo(T_FMT); |
2323 | - |
2324 | - for (i=0; formats_24h[i]!=nullptr; i++) |
2325 | - if (strstr(t_fmt, formats_24h[i]) != nullptr) |
2326 | - return FALSE; |
2327 | - |
2328 | - return TRUE; |
2329 | -} |
2330 | - |
2331 | -typedef enum |
2332 | -{ |
2333 | - DATE_PROXIMITY_YESTERDAY, |
2334 | - DATE_PROXIMITY_TODAY, |
2335 | - DATE_PROXIMITY_TOMORROW, |
2336 | - DATE_PROXIMITY_LAST_WEEK, |
2337 | - DATE_PROXIMITY_NEXT_WEEK, |
2338 | - DATE_PROXIMITY_FAR |
2339 | -} date_proximity_t; |
2340 | - |
2341 | -static date_proximity_t |
2342 | -getDateProximity(GDateTime* now, GDateTime* time) |
2343 | -{ |
2344 | - date_proximity_t prox = DATE_PROXIMITY_FAR; |
2345 | - gint now_year, now_month, now_day; |
2346 | - gint time_year, time_month, time_day; |
2347 | - |
2348 | - // does it happen today? |
2349 | - g_date_time_get_ymd(now, &now_year, &now_month, &now_day); |
2350 | - g_date_time_get_ymd(time, &time_year, &time_month, &time_day); |
2351 | - if ((now_year == time_year) && (now_month == time_month) && (now_day == time_day)) { |
2352 | - return DATE_PROXIMITY_TODAY; |
2353 | - } |
2354 | - |
2355 | - // did it happen yesterday? |
2356 | - GDateTime* yesterday = g_date_time_add_days(now, -1); |
2357 | - gint tom_year, tom_month, tom_day; |
2358 | - g_date_time_get_ymd(yesterday, &tom_year, &tom_month, &tom_day); |
2359 | - g_date_time_unref(yesterday); |
2360 | - if ((tom_year == time_year) && (tom_month == time_month) && (tom_day == time_day)) { |
2361 | - return DATE_PROXIMITY_YESTERDAY; |
2362 | - } |
2363 | - |
2364 | - // does it happen tomorrow? |
2365 | - GDateTime* tomorrow = g_date_time_add_days(now, 1); |
2366 | - g_date_time_get_ymd(tomorrow, &tom_year, &tom_month, &tom_day); |
2367 | - g_date_time_unref(tomorrow); |
2368 | - if ((tom_year == time_year) && (tom_month == time_month) && (tom_day == time_day)) { |
2369 | - return DATE_PROXIMITY_TOMORROW; |
2370 | - } |
2371 | - |
2372 | - // does it happen this week? |
2373 | - if (g_date_time_compare(time, now) < 0) { |
2374 | - GDateTime* last_week = g_date_time_add_days(now, -6); |
2375 | - GDateTime* last_week_bound = g_date_time_new_local(g_date_time_get_year(last_week), |
2376 | - g_date_time_get_month(last_week), |
2377 | - g_date_time_get_day_of_month(last_week), |
2378 | - 0, 0, 0); |
2379 | - if (g_date_time_compare(time, last_week_bound) >= 0) |
2380 | - prox = DATE_PROXIMITY_LAST_WEEK; |
2381 | - |
2382 | - g_date_time_unref(last_week); |
2383 | - g_date_time_unref(last_week_bound); |
2384 | - } else { |
2385 | - GDateTime* next_week = g_date_time_add_days(now, 6); |
2386 | - GDateTime* next_week_bound = g_date_time_new_local(g_date_time_get_year(next_week), |
2387 | - g_date_time_get_month(next_week), |
2388 | - g_date_time_get_day_of_month(next_week), |
2389 | - 23, 59, 59.9); |
2390 | - if (g_date_time_compare(time, next_week_bound) <= 0) |
2391 | - prox = DATE_PROXIMITY_NEXT_WEEK; |
2392 | - |
2393 | - g_date_time_unref(next_week); |
2394 | - g_date_time_unref(next_week_bound); |
2395 | - } |
2396 | - |
2397 | - return prox; |
2398 | -} |
2399 | - |
2400 | -const char* |
2401 | -dgettext_datetime(const char *text) |
2402 | -{ |
2403 | - return dgettext("unity8", text); |
2404 | -} |
2405 | - |
2406 | -/** |
2407 | - * _ a time yesterday should be shown as (e.g. “Yesterday 3:55 PM”) |
2408 | - * _ a time today should be shown as just the time (e.g. “3:55 PM”) |
2409 | - * _ a time tomorrow should be shown as(e.g. “Tomorrow 3:55 PM”) |
2410 | - * _ a time any other day this week should be shown as the short version of the |
2411 | - * day and time (e.g. “Wed 3:55 PM”) |
2412 | - * weekday (e.g. “Friday”) |
2413 | - * _ a time after this week should be shown as the short version of the day, |
2414 | - * date, and time (e.g. “Wed 21 Apr 3:55 PM”) |
2415 | - * _ in addition, when presenting the times of upcoming events, the time should |
2416 | - * be followed by the timezone if it is different from the one the computer |
2417 | - * is currently set to. For example, “Wed 3:55 PM UTC−5”. |
2418 | - * |
2419 | - * TODO - keep inline with indicator-datetime |
2420 | - */ |
2421 | -char* generate_full_format_string_at_time (GDateTime* now, |
2422 | - GDateTime* then) |
2423 | -{ |
2424 | - GString* ret = g_string_new (nullptr); |
2425 | - |
2426 | - if (then != nullptr) { |
2427 | - const date_proximity_t prox = getDateProximity(now, then); |
2428 | - |
2429 | - if (is_locale_12h()) { |
2430 | - switch (prox) { |
2431 | - case DATE_PROXIMITY_YESTERDAY: |
2432 | - /* Translators, please edit/rearrange these strftime(3) tokens to suit your locale! |
2433 | - This format string is used for showing, on a 12-hour clock, times that happen yesterday. |
2434 | - (\u2003 is a unicode em space which is slightly wider than a normal space.) |
2435 | - en_US example: "Yesterday\u2003%l:%M %p" --> "Yesterday 1:00 PM" */ |
2436 | - g_string_assign (ret, dgettext_datetime("Yesterday\u2003%l:%M %p")); |
2437 | - break; |
2438 | - |
2439 | - case DATE_PROXIMITY_TODAY: |
2440 | - /* Translators, please edit/rearrange these strftime(3) tokens to suit your locale! |
2441 | - This format string is used for showing, on a 12-hour clock, times that happened today. |
2442 | - en_US example: "%l:%M %p" --> "1:00 PM" */ |
2443 | - g_string_assign (ret, dgettext_datetime("%l:%M %p")); |
2444 | - break; |
2445 | - |
2446 | - case DATE_PROXIMITY_TOMORROW: |
2447 | - /* Translators, please edit/rearrange these strftime(3) tokens to suit your locale! |
2448 | - This format string is used for showing, on a 12-hour clock, events/appointments that happen tomorrow. |
2449 | - (\u2003 is a unicode em space which is slightly wider than a normal space.) |
2450 | - en_US example: "Tomorrow\u2003%l:%M %p" --> "Tomorrow 1:00 PM" */ |
2451 | - g_string_assign (ret, dgettext_datetime("Tomorrow\u2003%l:%M %p")); |
2452 | - break; |
2453 | - |
2454 | - case DATE_PROXIMITY_LAST_WEEK: |
2455 | - case DATE_PROXIMITY_NEXT_WEEK: |
2456 | - /* Translators, please edit/rearrange these strftime(3) tokens to suit your locale! |
2457 | - This format string is used for showing, on a 12-hour clock, times that happened in the last week. |
2458 | - (\u2003 is a unicode em space which is slightly wider than a normal space.) |
2459 | - en_US example: "%a\u2003%l:%M %p" --> "Fri 1:00 PM" */ |
2460 | - g_string_assign (ret, dgettext_datetime("%a\u2003%l:%M %p")); |
2461 | - break; |
2462 | - |
2463 | - case DATE_PROXIMITY_FAR: |
2464 | - /* Translators, please edit/rearrange these strftime(3) tokens to suit your locale! |
2465 | - This format string is used for showing, on a 12-hour clock, times that happened before a week from now. |
2466 | - (\u2003 is a unicode em space which is slightly wider than a normal space.) |
2467 | - en_US example: "%a %b %d\u2003%l:%M %p" --> "Fri Oct 31 1:00 PM" |
2468 | - en_GB example: "%a %d %b\u2003%l:%M %p" --> "Fri 31 Oct 1:00 PM" */ |
2469 | - g_string_assign (ret, dgettext_datetime("%a %d %b\u2003%l:%M %p")); |
2470 | - break; |
2471 | - } |
2472 | - } else { |
2473 | - switch (prox) { |
2474 | - |
2475 | - case DATE_PROXIMITY_YESTERDAY: |
2476 | - /* Translators, please edit/rearrange these strftime(3) tokens to suit your locale! |
2477 | - This format string is used for showing, on a 24-hour clock, times that happen yesterday. |
2478 | - (\u2003 is a unicode em space which is slightly wider than a normal space.) |
2479 | - en_US example: "Yesterday\u2003%l:%M %p" --> "Yesterday 13:00" */ |
2480 | - g_string_assign (ret, dgettext_datetime("Yesterday\u2003%H:%M")); |
2481 | - break; |
2482 | - |
2483 | - case DATE_PROXIMITY_TODAY: |
2484 | - /* Translators, please edit/rearrange these strftime(3) tokens to suit your locale! |
2485 | - This format string is used for showing, on a 24-hour clock, times that happened today. |
2486 | - en_US example: "%H:%M" --> "13:00" */ |
2487 | - g_string_assign (ret, dgettext_datetime("%H:%M")); |
2488 | - break; |
2489 | - |
2490 | - case DATE_PROXIMITY_TOMORROW: |
2491 | - /* Translators, please edit/rearrange these strftime(3) tokens to suit your locale! |
2492 | - This format string is used for showing, on a 24-hour clock, events/appointments that happen tomorrow. |
2493 | - (\u2003 is a unicode em space which is slightly wider than a normal space.) |
2494 | - en_US example: "Tomorrow\u2003%l:%M %p" --> "Tomorrow 13:00" */ |
2495 | - g_string_assign (ret, dgettext_datetime("Tomorrow\u2003%H:%M")); |
2496 | - break; |
2497 | - |
2498 | - case DATE_PROXIMITY_LAST_WEEK: |
2499 | - case DATE_PROXIMITY_NEXT_WEEK: |
2500 | - /* Translators, please edit/rearrange these strftime(3) tokens to suit your locale! |
2501 | - This format string is used for showing, on a 24-hour clock, times that happened in the last week. |
2502 | - (\u2003 is a unicode em space which is slightly wider than a normal space.) |
2503 | - en_US example: "%a\u2003%H:%M" --> "Fri 13:00" */ |
2504 | - g_string_assign (ret, dgettext_datetime("%a\u2003%H:%M")); |
2505 | - break; |
2506 | - |
2507 | - case DATE_PROXIMITY_FAR: |
2508 | - /* Translators, please edit/rearrange these strftime(3) tokens to suit your locale! |
2509 | - This format string is used for showing, on a 24-hour clock, times that happened before a week from now. |
2510 | - (\u2003 is a unicode em space which is slightly wider than a normal space.) |
2511 | - en_US example: "%a %b %d\u2003%H:%M" --> "Fri Oct 31 13:00" |
2512 | - en_GB example: "%a %d %b\u2003%H:%M" --> "Fri 31 Oct 13:00" */ |
2513 | - g_string_assign (ret, dgettext_datetime("%a %d %b\u2003%H:%M")); |
2514 | - break; |
2515 | - } |
2516 | - } |
2517 | - } |
2518 | - |
2519 | - return g_string_free (ret, FALSE); |
2520 | -} |
2521 | - |
2522 | -QString RelativeTimeFormatter::format() const |
2523 | -{ |
2524 | - GDateTime* now = g_date_time_new_now_local(); |
2525 | - if (!now) { return QString(); } |
2526 | - |
2527 | - GDateTime* then = g_date_time_new_from_unix_local(time()); |
2528 | - if (!then) { return QString(); } |
2529 | - |
2530 | - char* time_format = generate_full_format_string_at_time(now, then); |
2531 | - |
2532 | - QString str(QString::fromUtf8(time_format)); |
2533 | - g_free(time_format); |
2534 | - |
2535 | - g_date_time_unref(now); |
2536 | - g_date_time_unref(then); |
2537 | - |
2538 | - return str; |
2539 | -} |
2540 | |
2541 | === removed file 'plugins/Utils/relativetimeformatter.h' |
2542 | --- plugins/Utils/relativetimeformatter.h 2014-09-19 14:46:53 +0000 |
2543 | +++ plugins/Utils/relativetimeformatter.h 1970-01-01 00:00:00 +0000 |
2544 | @@ -1,34 +0,0 @@ |
2545 | -/* |
2546 | - * Copyright 2014 Canonical Ltd. |
2547 | - * |
2548 | - * This program is free software; you can redistribute it and/or modify |
2549 | - * it under the terms of the GNU General Public License as published by |
2550 | - * the Free Software Foundation; version 3. |
2551 | - * |
2552 | - * This program is distributed in the hope that it will be useful, |
2553 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2554 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2555 | - * GNU General Public License for more details. |
2556 | - * |
2557 | - * You should have received a copy of the GNU General Public License |
2558 | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2559 | - * |
2560 | - */ |
2561 | - |
2562 | -#ifndef RELATIVETIMEFORMATTER_H |
2563 | -#define RELATIVETIMEFORMATTER_H |
2564 | - |
2565 | -#include "timeformatter.h" |
2566 | - |
2567 | -// TODO - move this to the sdk |
2568 | -// https://blueprints.launchpad.net/ubuntu-ui-toolkit/+spec/time-formatter |
2569 | -class RelativeTimeFormatter : public GDateTimeFormatter |
2570 | -{ |
2571 | - Q_OBJECT |
2572 | -public: |
2573 | - RelativeTimeFormatter(QObject *parent = 0); |
2574 | - |
2575 | - QString format() const override; |
2576 | -}; |
2577 | - |
2578 | -#endif // RELATIVETIMEFORMATTER_H |
2579 | |
2580 | === removed file 'plugins/Utils/timeformatter.cpp' |
2581 | --- plugins/Utils/timeformatter.cpp 2015-09-24 14:02:25 +0000 |
2582 | +++ plugins/Utils/timeformatter.cpp 1970-01-01 00:00:00 +0000 |
2583 | @@ -1,206 +0,0 @@ |
2584 | -/* |
2585 | - * Copyright 2013 Canonical Ltd. |
2586 | - * |
2587 | - * This program is free software; you can redistribute it and/or modify |
2588 | - * it under the terms of the GNU General Public License as published by |
2589 | - * the Free Software Foundation; version 3. |
2590 | - * |
2591 | - * This program is distributed in the hope that it will be useful, |
2592 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2593 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2594 | - * GNU General Public License for more details. |
2595 | - * |
2596 | - * You should have received a copy of the GNU General Public License |
2597 | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2598 | - * |
2599 | - * Author: Lars Uebernickel <lars.uebernickel@canonical.com> |
2600 | - */ |
2601 | - |
2602 | -#include "timeformatter.h" |
2603 | - |
2604 | -#include <gio/gio.h> |
2605 | -#include <QDateTime> |
2606 | - |
2607 | -struct TimeFormatterPrivate |
2608 | -{ |
2609 | - TimeFormatter *formatter; |
2610 | - |
2611 | - QString format; |
2612 | - QString timeString; |
2613 | - qint64 time; |
2614 | - |
2615 | - GDBusConnection *system_bus; |
2616 | - guint subscription_id; |
2617 | - GCancellable *cancellable; |
2618 | -}; |
2619 | - |
2620 | -static void |
2621 | -timedate1_properties_changed (GDBusConnection *connection, |
2622 | - const gchar *sender_name, |
2623 | - const gchar *object_path, |
2624 | - const gchar *interface_name, |
2625 | - const gchar *signal_name, |
2626 | - GVariant *parameters, |
2627 | - gpointer user_data) |
2628 | -{ |
2629 | - Q_UNUSED(connection); |
2630 | - Q_UNUSED(sender_name); |
2631 | - Q_UNUSED(object_path); |
2632 | - Q_UNUSED(interface_name); |
2633 | - Q_UNUSED(signal_name); |
2634 | - |
2635 | - TimeFormatterPrivate *priv = (TimeFormatterPrivate *)user_data; |
2636 | - GVariant *changed; |
2637 | - GVariantIter *iter; |
2638 | - const gchar *name; |
2639 | - |
2640 | - if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(sa{sv}as)"))) |
2641 | - return; |
2642 | - |
2643 | - g_variant_get (parameters, "(s@a{sv}as)", nullptr, &changed, &iter); |
2644 | - |
2645 | - if (g_variant_lookup (changed, "Timezone", "s", nullptr)) { |
2646 | - priv->formatter->update(); |
2647 | - } |
2648 | - else { |
2649 | - while (g_variant_iter_next (iter, "&s", &name)) { |
2650 | - if (g_str_equal (name, "Timezone")) { |
2651 | - priv->formatter->update(); |
2652 | - break; |
2653 | - } |
2654 | - } |
2655 | - } |
2656 | - |
2657 | - g_variant_unref (changed); |
2658 | - g_variant_iter_free (iter); |
2659 | -} |
2660 | - |
2661 | -static void |
2662 | -got_bus(GObject *object, GAsyncResult *result, gpointer user_data) |
2663 | -{ |
2664 | - Q_UNUSED(object); |
2665 | - |
2666 | - TimeFormatterPrivate *priv = (TimeFormatterPrivate *)user_data; |
2667 | - GError *error = nullptr; |
2668 | - |
2669 | - priv->system_bus = g_bus_get_finish (result, &error); |
2670 | - if (priv->system_bus == nullptr) { |
2671 | - if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) |
2672 | - qWarning("TimeFormatter: cannot connect to the system bus: %s", error->message); |
2673 | - g_error_free (error); |
2674 | - return; |
2675 | - } |
2676 | - |
2677 | - /* Listen to the PropertiesChanged on the org.freedesktop.timedate1 |
2678 | - * interface from any sender. In practice, this signal will only be sent |
2679 | - * from timedated (we can trust other processes on the system bus to behave |
2680 | - * nicely). That way, we don't have to watch timedated's well-known name |
2681 | - * and keep the process alive. |
2682 | - */ |
2683 | - priv->subscription_id = g_dbus_connection_signal_subscribe (priv->system_bus, |
2684 | - nullptr, /* sender */ |
2685 | - "org.freedesktop.DBus.Properties", |
2686 | - "PropertiesChanged", |
2687 | - nullptr, |
2688 | - "org.freedesktop.timedate1", |
2689 | - G_DBUS_SIGNAL_FLAGS_NONE, |
2690 | - timedate1_properties_changed, |
2691 | - priv, nullptr); |
2692 | -} |
2693 | - |
2694 | -TimeFormatter::TimeFormatter(QObject *parent): QObject(parent) |
2695 | -{ |
2696 | - priv = new TimeFormatterPrivate; |
2697 | - priv->formatter = this; |
2698 | - priv->time = 0; |
2699 | - priv->format = QStringLiteral("yyyy-MM-dd hh:mm"); |
2700 | - priv->system_bus = nullptr; |
2701 | - priv->subscription_id = 0; |
2702 | - priv->cancellable = g_cancellable_new (); |
2703 | - |
2704 | - g_bus_get (G_BUS_TYPE_SYSTEM, priv->cancellable, got_bus, priv); |
2705 | -} |
2706 | - |
2707 | -TimeFormatter::TimeFormatter(const QString &initialFormat, QObject *parent): TimeFormatter(parent) |
2708 | -{ |
2709 | - priv->format = initialFormat; |
2710 | -} |
2711 | - |
2712 | -TimeFormatter::~TimeFormatter() |
2713 | -{ |
2714 | - if (priv->system_bus) { |
2715 | - g_dbus_connection_signal_unsubscribe (priv->system_bus, priv->subscription_id); |
2716 | - g_object_unref (priv->system_bus); |
2717 | - } |
2718 | - |
2719 | - g_cancellable_cancel (priv->cancellable); |
2720 | - g_object_unref (priv->cancellable); |
2721 | -} |
2722 | - |
2723 | -QString TimeFormatter::format() const |
2724 | -{ |
2725 | - return priv->format; |
2726 | -} |
2727 | - |
2728 | -QString TimeFormatter::timeString() const |
2729 | -{ |
2730 | - return priv->timeString; |
2731 | -} |
2732 | - |
2733 | -qint64 TimeFormatter::time() const |
2734 | -{ |
2735 | - return priv->time; |
2736 | -} |
2737 | - |
2738 | -void TimeFormatter::setFormat(const QString &format) |
2739 | -{ |
2740 | - if (priv->format != format) { |
2741 | - priv->format = format; |
2742 | - Q_EMIT formatChanged(priv->format); |
2743 | - update(); |
2744 | - } |
2745 | -} |
2746 | - |
2747 | -void TimeFormatter::setTime(qint64 time) |
2748 | -{ |
2749 | - if (priv->time != time) { |
2750 | - priv->time = time; |
2751 | - Q_EMIT timeChanged(priv->time); |
2752 | - update(); |
2753 | - } |
2754 | -} |
2755 | - |
2756 | -void TimeFormatter::update() |
2757 | -{ |
2758 | - priv->timeString = formatTime(); |
2759 | - Q_EMIT timeStringChanged(priv->timeString); |
2760 | -} |
2761 | - |
2762 | -QString TimeFormatter::formatTime() const |
2763 | -{ |
2764 | - return QDateTime::fromMSecsSinceEpoch(time() / 1000).toString(format()); |
2765 | -} |
2766 | - |
2767 | -GDateTimeFormatter::GDateTimeFormatter(QObject* parent) |
2768 | -: TimeFormatter(QStringLiteral("%d-%m-%Y %I:%M%p"), parent) |
2769 | -{ |
2770 | -} |
2771 | - |
2772 | -QString GDateTimeFormatter::formatTime() const |
2773 | -{ |
2774 | - gchar* time_string; |
2775 | - GDateTime* datetime; |
2776 | - QByteArray formatBytes = format().toUtf8(); |
2777 | - |
2778 | - datetime = g_date_time_new_from_unix_local(time()); |
2779 | - if (!datetime) { |
2780 | - return QLatin1String(""); |
2781 | - } |
2782 | - |
2783 | - time_string = g_date_time_format(datetime, formatBytes.constData()); |
2784 | - QString formattedTime(QString::fromUtf8(time_string)); |
2785 | - |
2786 | - g_free(time_string); |
2787 | - g_date_time_unref(datetime); |
2788 | - return formattedTime; |
2789 | -} |
2790 | |
2791 | === removed file 'plugins/Utils/timeformatter.h' |
2792 | --- plugins/Utils/timeformatter.h 2015-09-17 13:42:15 +0000 |
2793 | +++ plugins/Utils/timeformatter.h 1970-01-01 00:00:00 +0000 |
2794 | @@ -1,68 +0,0 @@ |
2795 | -/* |
2796 | - * Copyright 2013 Canonical Ltd. |
2797 | - * |
2798 | - * This program is free software; you can redistribute it and/or modify |
2799 | - * it under the terms of the GNU General Public License as published by |
2800 | - * the Free Software Foundation; version 3. |
2801 | - * |
2802 | - * This program is distributed in the hope that it will be useful, |
2803 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2804 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2805 | - * GNU General Public License for more details. |
2806 | - * |
2807 | - * You should have received a copy of the GNU General Public License |
2808 | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2809 | - * |
2810 | - * Author: Lars Uebernickel <lars.uebernickel@canonical.com> |
2811 | - */ |
2812 | - |
2813 | -#ifndef TIME_FORMATTER_H |
2814 | -#define TIME_FORMATTER_H |
2815 | - |
2816 | -#include <QObject> |
2817 | - |
2818 | -// TODO - bug #1260728 |
2819 | -class TimeFormatter : public QObject |
2820 | -{ |
2821 | - Q_OBJECT |
2822 | - Q_PROPERTY(QString format READ format WRITE setFormat NOTIFY formatChanged) |
2823 | - Q_PROPERTY(QString timeString READ timeString NOTIFY timeStringChanged) |
2824 | - Q_PROPERTY(qint64 time READ time WRITE setTime NOTIFY timeChanged) |
2825 | - |
2826 | -public: |
2827 | - TimeFormatter(QObject *parent = 0); |
2828 | - virtual ~TimeFormatter(); |
2829 | - |
2830 | - virtual QString format() const; |
2831 | - QString timeString() const; |
2832 | - qint64 time() const; |
2833 | - |
2834 | - void setFormat(const QString &format); |
2835 | - void setTime(qint64 time); |
2836 | - |
2837 | - void update(); |
2838 | - |
2839 | -Q_SIGNALS: |
2840 | - void formatChanged(const QString &format); |
2841 | - void timeStringChanged(const QString &timeString); |
2842 | - void timeChanged(qint64 time); |
2843 | - |
2844 | -protected: |
2845 | - TimeFormatter(const QString &initialFormat, QObject *parent = 0); |
2846 | - |
2847 | - virtual QString formatTime() const; |
2848 | - |
2849 | -private: |
2850 | - struct TimeFormatterPrivate *priv; |
2851 | -}; |
2852 | - |
2853 | -class GDateTimeFormatter : public TimeFormatter |
2854 | -{ |
2855 | -public: |
2856 | - GDateTimeFormatter(QObject *parent = 0); |
2857 | - |
2858 | -protected: |
2859 | - QString formatTime() const override; |
2860 | -}; |
2861 | - |
2862 | -#endif |
2863 | |
2864 | === modified file 'plugins/Utils/timezoneFormatter.cpp' |
2865 | --- plugins/Utils/timezoneFormatter.cpp 2015-09-17 13:42:15 +0000 |
2866 | +++ plugins/Utils/timezoneFormatter.cpp 2015-10-26 12:04:03 +0000 |
2867 | @@ -29,7 +29,7 @@ |
2868 | if (tz.isValid()) { |
2869 | const QDateTime now = QDateTime::currentDateTime().toTimeZone(tz); |
2870 | // return locale-aware string in the form "day, hh:mm", e.g. "Mon 14:30" or "Mon 1:30 pm" |
2871 | - return QStringLiteral("%1 %2").arg(now.toString("ddd")).arg(now.time().toString(Qt::DefaultLocaleShortDate)); |
2872 | + return QStringLiteral("%1 %2").arg(now.toString(QStringLiteral("ddd"))).arg(now.time().toString(Qt::DefaultLocaleShortDate)); |
2873 | } |
2874 | return QString(); |
2875 | } |
2876 | |
2877 | === modified file 'qml/Components/Dialogs.qml' |
2878 | --- qml/Components/Dialogs.qml 2015-09-02 09:30:32 +0000 |
2879 | +++ qml/Components/Dialogs.qml 2015-10-26 12:04:03 +0000 |
2880 | @@ -20,6 +20,7 @@ |
2881 | import Unity.Session 0.1 |
2882 | import Ubuntu.Components 1.1 |
2883 | import GlobalShortcut 1.0 |
2884 | +import Unity.Platform 1.0 |
2885 | import "../Greeter" |
2886 | |
2887 | Item { |
2888 | @@ -46,13 +47,13 @@ |
2889 | |
2890 | GlobalShortcut { // reboot/shutdown dialog |
2891 | shortcut: Qt.Key_PowerDown |
2892 | - active: root.usageScenario === "desktop" |
2893 | + active: Platform.isPC |
2894 | onTriggered: root.unitySessionService.RequestShutdown() |
2895 | } |
2896 | |
2897 | GlobalShortcut { // reboot/shutdown dialog |
2898 | shortcut: Qt.Key_PowerOff |
2899 | - active: root.usageScenario === "desktop" |
2900 | + active: Platform.isPC |
2901 | onTriggered: root.unitySessionService.RequestShutdown() |
2902 | } |
2903 | |
2904 | |
2905 | === modified file 'qml/Components/ScreenGrabber.qml' |
2906 | --- qml/Components/ScreenGrabber.qml 2015-08-24 15:39:53 +0000 |
2907 | +++ qml/Components/ScreenGrabber.qml 2015-10-26 12:04:03 +0000 |
2908 | @@ -26,6 +26,9 @@ |
2909 | anchors.fill: parent |
2910 | opacity: 0.0 |
2911 | |
2912 | + // to be set from outside |
2913 | + property int rotationAngle: 0 |
2914 | + |
2915 | ScreenGrabber { |
2916 | id: screenGrabber |
2917 | objectName: "screenGrabber" |
2918 | @@ -67,7 +70,7 @@ |
2919 | to: 0.0 |
2920 | onStopped: { |
2921 | if (visible) { |
2922 | - screenGrabber.captureAndSave(); |
2923 | + screenGrabber.captureAndSave(root.rotationAngle); |
2924 | visible = false; |
2925 | } |
2926 | } |
2927 | |
2928 | === added file 'qml/Components/WallpaperResolver.qml' |
2929 | --- qml/Components/WallpaperResolver.qml 1970-01-01 00:00:00 +0000 |
2930 | +++ qml/Components/WallpaperResolver.qml 2015-10-26 12:04:03 +0000 |
2931 | @@ -0,0 +1,63 @@ |
2932 | +/* |
2933 | + * Copyright (C) 2015 Canonical, Ltd. |
2934 | + * |
2935 | + * This program is free software; you can redistribute it and/or modify |
2936 | + * it under the terms of the GNU General Public License as published by |
2937 | + * the Free Software Foundation; version 3. |
2938 | + * |
2939 | + * This program is distributed in the hope that it will be useful, |
2940 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2941 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2942 | + * GNU General Public License for more details. |
2943 | + * |
2944 | + * You should have received a copy of the GNU General Public License |
2945 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2946 | + */ |
2947 | + |
2948 | +import QtQuick 2.4 |
2949 | +import AccountsService 0.1 |
2950 | +import GSettings 1.0 |
2951 | +import Ubuntu.Components 1.3 |
2952 | + |
2953 | +/* |
2954 | + Defines the background URL based on several factors, such as: |
2955 | + - default, fallback, background |
2956 | + - Background set in AccountSettings, if any |
2957 | + - Background set in GSettings, if any |
2958 | + */ |
2959 | +QtObject { |
2960 | + // Users should set their UI width here. |
2961 | + property real width |
2962 | + |
2963 | + property url defaultBackground: Qt.resolvedUrl(width >= units.gu(60) ? "../graphics/tablet_background.jpg" |
2964 | + : "../graphics/phone_background.jpg") |
2965 | + |
2966 | + // That's the property users of this component are going to consume. |
2967 | + readonly property url background: asImageTester.status == Image.Ready ? asImageTester.source |
2968 | + : gsImageTester.status == Image.Ready ? gsImageTester.source : defaultBackground |
2969 | + |
2970 | + // This is a dummy image to detect if the custom AS set wallpaper loads successfully. |
2971 | + property var _asImageTester: Image { |
2972 | + id: asImageTester |
2973 | + source: AccountsService.backgroundFile != undefined && AccountsService.backgroundFile.length > 0 ? AccountsService.backgroundFile : "" |
2974 | + height: 0 |
2975 | + width: 0 |
2976 | + sourceSize.height: 0 |
2977 | + sourceSize.width: 0 |
2978 | + } |
2979 | + |
2980 | + // This is a dummy image to detect if the custom GSettings set wallpaper loads successfully. |
2981 | + property var _gsImageTester: Image { |
2982 | + id: gsImageTester |
2983 | + source: backgroundSettings.pictureUri && backgroundSettings.pictureUri.length > 0 ? backgroundSettings.pictureUri : "" |
2984 | + height: 0 |
2985 | + width: 0 |
2986 | + sourceSize.height: 0 |
2987 | + sourceSize.width: 0 |
2988 | + } |
2989 | + |
2990 | + property var _gsettings: GSettings { |
2991 | + id: backgroundSettings |
2992 | + schema.id: "org.gnome.desktop.background" |
2993 | + } |
2994 | +} |
2995 | |
2996 | === modified file 'qml/DeviceConfiguration.qml' |
2997 | --- qml/DeviceConfiguration.qml 2015-07-01 17:52:34 +0000 |
2998 | +++ qml/DeviceConfiguration.qml 2015-10-26 12:04:03 +0000 |
2999 | @@ -86,6 +86,7 @@ |
3000 | PropertyChanges { |
3001 | target: root |
3002 | category: "desktop" |
3003 | + supportedOrientations: root.useNativeOrientation |
3004 | } |
3005 | } |
3006 | ] |
3007 | |
3008 | === added file 'qml/DisabledScreenNotice.qml' |
3009 | --- qml/DisabledScreenNotice.qml 1970-01-01 00:00:00 +0000 |
3010 | +++ qml/DisabledScreenNotice.qml 2015-10-26 12:04:03 +0000 |
3011 | @@ -0,0 +1,49 @@ |
3012 | +/* |
3013 | + * Copyright (C) 2015 Canonical, Ltd. |
3014 | + * |
3015 | + * This program is free software; you can redistribute it and/or modify |
3016 | + * it under the terms of the GNU General Public License as published by |
3017 | + * the Free Software Foundation; version 3. |
3018 | + * |
3019 | + * This program is distributed in the hope that it will be useful, |
3020 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
3021 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
3022 | + * GNU General Public License for more details. |
3023 | + * |
3024 | + * You should have received a copy of the GNU General Public License |
3025 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
3026 | + */ |
3027 | + |
3028 | +import QtQuick 2.4 |
3029 | +import Ubuntu.Components 1.3 |
3030 | +import "Components" |
3031 | + |
3032 | +Image { |
3033 | + id: root |
3034 | + |
3035 | + WallpaperResolver { |
3036 | + width: root.width |
3037 | + id: wallpaperResolver |
3038 | + } |
3039 | + |
3040 | + source: wallpaperResolver.background |
3041 | + |
3042 | + UbuntuShape { |
3043 | + anchors.fill: text |
3044 | + anchors.margins: -units.gu(2) |
3045 | + backgroundColor: "black" |
3046 | + opacity: 0.4 |
3047 | + } |
3048 | + |
3049 | + Label { |
3050 | + id: text |
3051 | + anchors.centerIn: parent |
3052 | + width: parent.width / 2 |
3053 | + text: i18n.tr("Your device is now connected to an external display.") |
3054 | + color: "white" |
3055 | + horizontalAlignment: Text.AlignHCenter |
3056 | + verticalAlignment: Text.AlignVCenter |
3057 | + fontSize: "x-large" |
3058 | + wrapMode: Text.Wrap |
3059 | + } |
3060 | +} |
3061 | |
3062 | === modified file 'qml/Greeter/Greeter.qml' |
3063 | --- qml/Greeter/Greeter.qml 2015-09-02 13:06:56 +0000 |
3064 | +++ qml/Greeter/Greeter.qml 2015-10-26 12:04:03 +0000 |
3065 | @@ -251,7 +251,7 @@ |
3066 | |
3067 | // event eater |
3068 | // Nothing should leak to items behind the greeter |
3069 | - MouseArea { anchors.fill: parent } |
3070 | + MouseArea { anchors.fill: parent; hoverEnabled: true } |
3071 | |
3072 | Loader { |
3073 | id: loader |
3074 | |
3075 | === modified file 'qml/Launcher/Launcher.qml' |
3076 | --- qml/Launcher/Launcher.qml 2015-09-02 14:18:40 +0000 |
3077 | +++ qml/Launcher/Launcher.qml 2015-10-26 12:04:03 +0000 |
3078 | @@ -188,6 +188,7 @@ |
3079 | bottom: parent.bottom |
3080 | } |
3081 | enabled: root.shadeBackground && root.state == "visible" |
3082 | + visible: enabled // otherwise it will get in the way of cursor selection for some reason |
3083 | onPressed: { |
3084 | root.state = "" |
3085 | } |
3086 | |
3087 | === modified file 'qml/Notifications/Notification.qml' |
3088 | --- qml/Notifications/Notification.qml 2015-10-08 19:30:59 +0000 |
3089 | +++ qml/Notifications/Notification.qml 2015-10-26 12:04:03 +0000 |
3090 | @@ -50,6 +50,7 @@ |
3091 | readonly property real contentSpacing: units.gu(2) |
3092 | readonly property bool canBeClosed: type === Notification.Ephemeral |
3093 | property bool hasMouse |
3094 | + property url background: "" |
3095 | |
3096 | objectName: "background" |
3097 | implicitHeight: type !== Notification.PlaceHolder ? (fullscreen ? maxHeight : outterColumn.height - shapedBack.anchors.topMargin + contentSpacing * 2) : 0 |
3098 | @@ -401,6 +402,7 @@ |
3099 | menuData: model |
3100 | menuIndex: index |
3101 | maxHeight: notification.maxHeight |
3102 | + background: notification.background |
3103 | |
3104 | onLoaded: { |
3105 | notification.fullscreen = Qt.binding(function() { return fullscreen; }); |
3106 | |
3107 | === modified file 'qml/Notifications/NotificationMenuItemFactory.qml' |
3108 | --- qml/Notifications/NotificationMenuItemFactory.qml 2014-11-17 13:46:56 +0000 |
3109 | +++ qml/Notifications/NotificationMenuItemFactory.qml 2015-10-26 12:04:03 +0000 |
3110 | @@ -30,6 +30,7 @@ |
3111 | property int menuIndex : -1 |
3112 | property int maxHeight |
3113 | readonly property bool fullscreen: menuData.type === "com.canonical.snapdecision.pinlock" |
3114 | + property url background: "" |
3115 | |
3116 | signal accepted() |
3117 | |
3118 | @@ -149,7 +150,7 @@ |
3119 | infoText: notification.summary |
3120 | errorText: errorAction.valid ? errorAction.state : "" |
3121 | retryText: notification.body |
3122 | - background: shell.background |
3123 | + background: menuFactory.background |
3124 | darkenBackground: 0.4 |
3125 | |
3126 | onEntered: { |
3127 | |
3128 | === modified file 'qml/Notifications/Notifications.qml' |
3129 | --- qml/Notifications/Notifications.qml 2015-09-22 14:23:44 +0000 |
3130 | +++ qml/Notifications/Notifications.qml 2015-10-26 12:04:03 +0000 |
3131 | @@ -29,6 +29,7 @@ |
3132 | property real margin |
3133 | property bool useModal: snapDecisionProxyModel.count > 0 |
3134 | property bool hasMouse |
3135 | + property url background: "" |
3136 | |
3137 | UnitySortFilterProxyModel { |
3138 | id: snapDecisionProxyModel |
3139 | @@ -60,6 +61,7 @@ |
3140 | maxHeight: notificationList.height |
3141 | margins: notificationList.margin |
3142 | hasMouse: notificationList.hasMouse |
3143 | + background: notificationList.background |
3144 | |
3145 | // make sure there's no opacity-difference between the several |
3146 | // elements in a notification |
3147 | |
3148 | === modified file 'qml/OrientedShell.qml' |
3149 | --- qml/OrientedShell.qml 2015-09-22 14:23:44 +0000 |
3150 | +++ qml/OrientedShell.qml 2015-10-26 12:04:03 +0000 |
3151 | @@ -76,6 +76,12 @@ |
3152 | oskSettings.disableHeight = shell.usageScenario == "desktop" |
3153 | } |
3154 | |
3155 | + // we must rotate to a supported orientation regardless of shell's preference |
3156 | + property bool orientationChangesEnabled: |
3157 | + (orientation & supportedOrientations) === 0 ? true |
3158 | + : shell.orientationChangesEnabled |
3159 | + |
3160 | + |
3161 | Binding { |
3162 | target: oskSettings |
3163 | property: "stayHidden" |
3164 | @@ -89,7 +95,10 @@ |
3165 | } |
3166 | |
3167 | readonly property int supportedOrientations: shell.supportedOrientations |
3168 | - & deviceConfiguration.supportedOrientations |
3169 | + & (deviceConfiguration.supportedOrientations == deviceConfiguration.useNativeOrientation |
3170 | + ? nativeOrientation |
3171 | + : deviceConfiguration.supportedOrientations) |
3172 | + |
3173 | property int acceptedOrientationAngle: { |
3174 | if (orientation & supportedOrientations) { |
3175 | return Screen.angleBetween(nativeOrientation, orientation); |
3176 | |
3177 | === modified file 'qml/Panel/Indicators/MenuItemFactory.qml' |
3178 | --- qml/Panel/Indicators/MenuItemFactory.qml 2015-09-17 18:02:22 +0000 |
3179 | +++ qml/Panel/Indicators/MenuItemFactory.qml 2015-10-26 12:04:03 +0000 |
3180 | @@ -20,7 +20,7 @@ |
3181 | import QMenuModel 0.1 |
3182 | import Utils 0.1 as Utils |
3183 | import Ubuntu.Components.ListItems 0.1 as ListItems |
3184 | -import Ubuntu.Components 1.2 |
3185 | +import Ubuntu.Components 1.3 |
3186 | import Unity.Session 0.1 |
3187 | |
3188 | Item { |
3189 | @@ -350,20 +350,23 @@ |
3190 | id: alarmMenu; |
3191 | |
3192 | Menus.EventMenu { |
3193 | + id: alarmItem |
3194 | objectName: "alarmMenu" |
3195 | property QtObject menuData: null |
3196 | property var menuModel: menuFactory.menuModel |
3197 | property int menuIndex: -1 |
3198 | property var extendedData: menuData && menuData.ext || undefined |
3199 | - // TODO - bug #1260728 |
3200 | - property var timeFormatter: Utils.GDateTimeFormatter { |
3201 | - time: getExtendedProperty(extendedData, "xCanonicalTime", 0) |
3202 | - format: getExtendedProperty(extendedData, "xCanonicalTimeFormat", "") |
3203 | + |
3204 | + property date serverTime: new Date(getExtendedProperty(extendedData, "xCanonicalTime", 0) * 1000) |
3205 | + LiveTimer { |
3206 | + frequency: LiveTimer.Relative |
3207 | + relativeTime: alarmItem.serverTime |
3208 | + onTrigger: alarmItem.serverTime = new Date(getExtendedProperty(extendedData, "xCanonicalTime", 0) * 1000) |
3209 | } |
3210 | |
3211 | text: menuData && menuData.label || "" |
3212 | iconSource: menuData && menuData.icon || "image://theme/alarm-clock" |
3213 | - time: timeFormatter.timeString |
3214 | + time: i18n.relativeDateTime(serverTime) |
3215 | enabled: menuData && menuData.sensitive || false |
3216 | highlightWhenPressed: false |
3217 | |
3218 | @@ -379,8 +382,7 @@ |
3219 | |
3220 | function loadAttributes() { |
3221 | if (!menuModel || menuIndex == -1) return; |
3222 | - menuModel.loadExtendedAttributes(menuIndex, {'x-canonical-time': 'int64', |
3223 | - 'x-canonical-time-format': 'string'}); |
3224 | + menuModel.loadExtendedAttributes(menuIndex, {'x-canonical-time': 'int64'}); |
3225 | } |
3226 | } |
3227 | } |
3228 | @@ -389,20 +391,23 @@ |
3229 | id: appointmentMenu; |
3230 | |
3231 | Menus.EventMenu { |
3232 | + id: appointmentItem |
3233 | objectName: "appointmentMenu" |
3234 | property QtObject menuData: null |
3235 | property var menuModel: menuFactory.menuModel |
3236 | property int menuIndex: -1 |
3237 | property var extendedData: menuData && menuData.ext || undefined |
3238 | - // TODO - bug #1260728 |
3239 | - property var timeFormatter: Utils.GDateTimeFormatter { |
3240 | - time: getExtendedProperty(extendedData, "xCanonicalTime", 0) |
3241 | - format: getExtendedProperty(extendedData, "xCanonicalTimeFormat", "") |
3242 | + |
3243 | + property date serverTime: new Date(getExtendedProperty(extendedData, "xCanonicalTime", 0) * 1000) |
3244 | + LiveTimer { |
3245 | + frequency: LiveTimer.Relative |
3246 | + relativeTime: appointmentItem.serverTime |
3247 | + onTrigger: appointmentItem.serverTime = new Date(getExtendedProperty(extendedData, "xCanonicalTime", 0) * 1000) |
3248 | } |
3249 | |
3250 | text: menuData && menuData.label || "" |
3251 | iconSource: menuData && menuData.icon || "image://theme/calendar" |
3252 | - time: timeFormatter.timeString |
3253 | + time: i18n.relativeDateTime(serverTime) |
3254 | eventColor: getExtendedProperty(extendedData, "xCanonicalColor", Qt.rgba(0.0, 0.0, 0.0, 0.0)) |
3255 | enabled: menuData && menuData.sensitive || false |
3256 | highlightWhenPressed: false |
3257 | @@ -420,8 +425,7 @@ |
3258 | function loadAttributes() { |
3259 | if (!menuModel || menuIndex == -1) return; |
3260 | menuModel.loadExtendedAttributes(menuIndex, {'x-canonical-color': 'string', |
3261 | - 'x-canonical-time': 'int64', |
3262 | - 'x-canonical-time-format': 'string'}); |
3263 | + 'x-canonical-time': 'int64'}); |
3264 | } |
3265 | } |
3266 | } |
3267 | |
3268 | === modified file 'qml/Panel/Indicators/MessageMenuItemFactory.qml' |
3269 | --- qml/Panel/Indicators/MessageMenuItemFactory.qml 2015-09-15 22:50:16 +0000 |
3270 | +++ qml/Panel/Indicators/MessageMenuItemFactory.qml 2015-10-26 12:04:03 +0000 |
3271 | @@ -19,7 +19,7 @@ |
3272 | */ |
3273 | |
3274 | import QtQuick 2.0 |
3275 | -import Ubuntu.Components 0.1 |
3276 | +import Ubuntu.Components 1.3 |
3277 | import Ubuntu.Settings.Menus 0.1 as Menus |
3278 | import QMenuModel 0.1 as QMenuModel |
3279 | import Utils 0.1 as Utils |
3280 | @@ -35,12 +35,17 @@ |
3281 | signal menuSelected |
3282 | signal menuDeselected |
3283 | |
3284 | - property var extendedData: menuData && menuData.ext || undefined |
3285 | - property var actionsDescription: getExtendedProperty(extendedData, "xCanonicalMessageActions", undefined) |
3286 | - |
3287 | - // TODO - bug #1260728 |
3288 | - property var timeFormatter: Utils.RelativeTimeFormatter { |
3289 | - time: getExtendedProperty(extendedData, "xCanonicalTime", 0) / 1000000 |
3290 | + QtObject { |
3291 | + id: priv |
3292 | + property var extendedData: menuData && menuData.ext || undefined |
3293 | + property var actionsDescription: getExtendedProperty(extendedData, "xCanonicalMessageActions", undefined) |
3294 | + property date time: new Date(getExtendedProperty(extendedData, "xCanonicalTime", 0) / 1000) |
3295 | + property string timeString: i18n.relativeDateTime(time) |
3296 | + } |
3297 | + LiveTimer { |
3298 | + frequency: LiveTimer.Relative |
3299 | + relativeTime: priv.time |
3300 | + onTrigger: priv.timeString = Qt.binding(function() { return i18n.relativeDateTime(priv.time); }) |
3301 | } |
3302 | |
3303 | onMenuModelChanged: { |
3304 | @@ -50,7 +55,7 @@ |
3305 | loadAttributes(); |
3306 | } |
3307 | |
3308 | - sourceComponent: loadMessage(actionsDescription) |
3309 | + sourceComponent: loadMessage(priv.actionsDescription) |
3310 | |
3311 | function loadMessage(actions) |
3312 | { |
3313 | @@ -100,11 +105,11 @@ |
3314 | objectName: "simpleTextMessage" |
3315 | // text |
3316 | title: menuData && menuData.label || "" |
3317 | - time: timeFormatter.timeString |
3318 | - body: getExtendedProperty(extendedData, "xCanonicalText", "") |
3319 | + time: priv.timeString |
3320 | + body: getExtendedProperty(priv.extendedData, "xCanonicalText", "") |
3321 | // icons |
3322 | - avatar: getExtendedProperty(extendedData, "icon", "image://theme/contact") |
3323 | - icon: getExtendedProperty(extendedData, "xCanonicalAppIcon", "image://theme/message") |
3324 | + avatar: getExtendedProperty(priv.extendedData, "icon", "image://theme/contact") |
3325 | + icon: getExtendedProperty(priv.extendedData, "xCanonicalAppIcon", "image://theme/message") |
3326 | // actions |
3327 | enabled: menuData && menuData.sensitive || false |
3328 | removable: !selected |
3329 | @@ -133,7 +138,9 @@ |
3330 | Menus.TextMessageMenu { |
3331 | id: message |
3332 | objectName: "textMessage" |
3333 | - property var replyActionDescription: actionsDescription && actionsDescription.length > 0 ? actionsDescription[0] : undefined |
3334 | + property var replyActionDescription: priv.actionsDescription && priv.actionsDescription.length > 0 ? |
3335 | + priv.actionsDescription[0] : |
3336 | + undefined |
3337 | |
3338 | property var replyAction: QMenuModel.UnityMenuAction { |
3339 | model: menuModel |
3340 | @@ -143,13 +150,13 @@ |
3341 | |
3342 | // text |
3343 | title: menuData && menuData.label || "" |
3344 | - time: timeFormatter.timeString |
3345 | - body: getExtendedProperty(extendedData, "xCanonicalText", "") |
3346 | - replyButtonText: getExtendedProperty(replyActionDescription, "label", i18n.tr("Send")) |
3347 | + time: priv.timeString |
3348 | + body: getExtendedProperty(priv.extendedData, "xCanonicalText", "") |
3349 | + replyButtonText: getExtendedProperty(replyActionDescription, "label", i18n.ctr("Button: Send a reply message", "Send")) |
3350 | replyHintText: i18n.ctr("Label: Hint in message indicator line edit", "Reply") |
3351 | // icons |
3352 | - avatar: getExtendedProperty(extendedData, "icon", "image://theme/contact") |
3353 | - icon: getExtendedProperty(extendedData, "xCanonicalAppIcon", "image://theme/message") |
3354 | + avatar: getExtendedProperty(priv.extendedData, "icon", "image://theme/contact") |
3355 | + icon: getExtendedProperty(priv.extendedData, "xCanonicalAppIcon", "image://theme/message") |
3356 | // actions |
3357 | replyEnabled: replyAction.valid && replyAction.enabled |
3358 | enabled: menuData && menuData.sensitive || false |
3359 | @@ -183,8 +190,10 @@ |
3360 | Menus.SnapDecisionMenu { |
3361 | id: message |
3362 | objectName: "snapDecision" |
3363 | - property var activateActionDescription: actionsDescription && actionsDescription.length > 0 ? actionsDescription[0] : undefined |
3364 | - property var replyActionDescription: actionsDescription && actionsDescription.length > 1 ? actionsDescription[1] : undefined |
3365 | + property var activateActionDescription: priv.actionsDescription && priv.actionsDescription.length > 0 ? |
3366 | + priv.actionsDescription[0] : undefined |
3367 | + property var replyActionDescription: priv.actionsDescription && priv.actionsDescription.length > 1 ? |
3368 | + priv.actionsDescription[1] : undefined |
3369 | |
3370 | property var activateAction: QMenuModel.UnityMenuAction { |
3371 | model: menuModel |
3372 | @@ -199,13 +208,13 @@ |
3373 | |
3374 | // text |
3375 | title: menuData && menuData.label || "" |
3376 | - time: timeFormatter.timeString |
3377 | - body: getExtendedProperty(extendedData, "xCanonicalText", "") |
3378 | - actionButtonText: getExtendedProperty(activateActionDescription, "label", i18n.tr("Call back")) |
3379 | - replyButtonText: getExtendedProperty(replyActionDescription, "label", i18n.tr("Send")) |
3380 | + time: priv.timeString |
3381 | + body: getExtendedProperty(priv.extendedData, "xCanonicalText", "") |
3382 | + actionButtonText: getExtendedProperty(activateActionDescription, "label", i18n.ctr("Button: Call back on phone", "Call back")) |
3383 | + replyButtonText: getExtendedProperty(replyActionDescription, "label", i18n.ctr("Button: Send a reply message", "Send")) |
3384 | // icons |
3385 | - avatar: getExtendedProperty(extendedData, "icon", "image://theme/contact") |
3386 | - icon: getExtendedProperty(extendedData, "xCanonicalAppIcon", "image://theme/missed-call") |
3387 | + avatar: getExtendedProperty(priv.extendedData, "icon", "image://theme/contact") |
3388 | + icon: getExtendedProperty(priv.extendedData, "xCanonicalAppIcon", "image://theme/missed-call") |
3389 | // actions |
3390 | actionEnabled: activateAction.valid && activateAction.enabled |
3391 | replyEnabled: replyAction.valid && replyAction.enabled |
3392 | |
3393 | === modified file 'qml/Panel/Panel.qml' |
3394 | --- qml/Panel/Panel.qml 2015-06-29 03:58:22 +0000 |
3395 | +++ qml/Panel/Panel.qml 2015-10-26 12:04:03 +0000 |
3396 | @@ -48,6 +48,7 @@ |
3397 | MouseArea { |
3398 | anchors.fill: parent |
3399 | onClicked: if (indicators.fullyOpened) indicators.hide(); |
3400 | + hoverEnabled: true // should also eat hover events, otherwise they will pass through |
3401 | } |
3402 | } |
3403 | |
3404 | |
3405 | === modified file 'qml/Rotation/RotationStates.qml' |
3406 | --- qml/Rotation/RotationStates.qml 2015-05-11 14:36:03 +0000 |
3407 | +++ qml/Rotation/RotationStates.qml 2015-10-26 12:04:03 +0000 |
3408 | @@ -83,7 +83,7 @@ |
3409 | } |
3410 | |
3411 | function tryUpdateState() { |
3412 | - if (d.transitioning || (!d.startingUp && !root.shell.orientationChangesEnabled)) { |
3413 | + if (d.transitioning || (!d.startingUp && !root.orientedShell.orientationChangesEnabled)) { |
3414 | return; |
3415 | } |
3416 | |
3417 | @@ -95,7 +95,7 @@ |
3418 | } |
3419 | |
3420 | property Connections shellConnections: Connections { |
3421 | - target: root.shell |
3422 | + target: root.orientedShell |
3423 | onOrientationChangesEnabledChanged: { |
3424 | d.tryUpdateState(); |
3425 | } |
3426 | |
3427 | === modified file 'qml/Shell.qml' |
3428 | --- qml/Shell.qml 2015-09-22 14:23:44 +0000 |
3429 | +++ qml/Shell.qml 2015-10-26 12:04:03 +0000 |
3430 | @@ -17,7 +17,6 @@ |
3431 | import QtQuick 2.0 |
3432 | import QtQuick.Window 2.0 |
3433 | import AccountsService 0.1 |
3434 | -import GSettings 1.0 |
3435 | import Unity.Application 0.1 |
3436 | import Ubuntu.Components 0.1 |
3437 | import Ubuntu.Components.Popups 1.0 |
3438 | @@ -41,6 +40,7 @@ |
3439 | import Unity.Session 0.1 |
3440 | import Unity.DashCommunicator 0.1 |
3441 | import Unity.Indicators 0.1 as Indicators |
3442 | +import Cursor 1.0 |
3443 | |
3444 | |
3445 | Item { |
3446 | @@ -63,7 +63,7 @@ |
3447 | function updateFocusedAppOrientationAnimated() { |
3448 | applicationsDisplayLoader.item.updateFocusedAppOrientationAnimated(); |
3449 | } |
3450 | - property bool hasMouse |
3451 | + property bool hasMouse: false |
3452 | |
3453 | // to be read from outside |
3454 | readonly property int mainAppWindowOrientationAngle: |
3455 | @@ -107,9 +107,11 @@ |
3456 | enabled: greeter && !greeter.waiting |
3457 | |
3458 | property real edgeSize: units.gu(2) |
3459 | - property url defaultBackground: Qt.resolvedUrl(shell.width >= units.gu(60) ? "graphics/tablet_background.jpg" : "graphics/phone_background.jpg") |
3460 | - property url background: asImageTester.status == Image.Ready ? asImageTester.source |
3461 | - : gsImageTester.status == Image.Ready ? gsImageTester.source : defaultBackground |
3462 | + |
3463 | + WallpaperResolver { |
3464 | + id: wallpaperResolver |
3465 | + width: shell.width |
3466 | + } |
3467 | |
3468 | readonly property alias greeter: greeterLoader.item |
3469 | |
3470 | @@ -130,31 +132,6 @@ |
3471 | shell.activateApplication(app); |
3472 | } |
3473 | |
3474 | - // This is a dummy image to detect if the custom AS set wallpaper loads successfully. |
3475 | - Image { |
3476 | - id: asImageTester |
3477 | - source: AccountsService.backgroundFile != undefined && AccountsService.backgroundFile.length > 0 ? AccountsService.backgroundFile : "" |
3478 | - height: 0 |
3479 | - width: 0 |
3480 | - sourceSize.height: 0 |
3481 | - sourceSize.width: 0 |
3482 | - } |
3483 | - |
3484 | - GSettings { |
3485 | - id: backgroundSettings |
3486 | - schema.id: "org.gnome.desktop.background" |
3487 | - } |
3488 | - |
3489 | - // This is a dummy image to detect if the custom GSettings set wallpaper loads successfully. |
3490 | - Image { |
3491 | - id: gsImageTester |
3492 | - source: backgroundSettings.pictureUri && backgroundSettings.pictureUri.length > 0 ? backgroundSettings.pictureUri : "" |
3493 | - height: 0 |
3494 | - width: 0 |
3495 | - sourceSize.height: 0 |
3496 | - sourceSize.width: 0 |
3497 | - } |
3498 | - |
3499 | Binding { |
3500 | target: LauncherModel |
3501 | property: "applicationManager" |
3502 | @@ -190,11 +167,6 @@ |
3503 | onScreenshotTriggered: screenGrabber.capture(); |
3504 | } |
3505 | |
3506 | - ScreenGrabber { |
3507 | - id: screenGrabber |
3508 | - z: dialogs.z + 10 |
3509 | - } |
3510 | - |
3511 | GlobalShortcut { |
3512 | // dummy shortcut to force creation of GlobalShortcutRegistry before WindowKeyFilter |
3513 | } |
3514 | @@ -327,7 +299,7 @@ |
3515 | Binding { |
3516 | target: applicationsDisplayLoader.item |
3517 | property: "background" |
3518 | - value: shell.background |
3519 | + value: wallpaperResolver.background |
3520 | } |
3521 | Binding { |
3522 | target: applicationsDisplayLoader.item |
3523 | @@ -432,7 +404,7 @@ |
3524 | tabletMode: shell.usageScenario != "phone" |
3525 | launcherOffset: launcher.progress |
3526 | forcedUnlock: tutorial.running |
3527 | - background: shell.background |
3528 | + background: wallpaperResolver.background |
3529 | |
3530 | // avoid overlapping with Launcher's edge drag area |
3531 | // FIXME: Fix TouchRegistry & friends and remove this workaround |
3532 | @@ -607,7 +579,7 @@ |
3533 | id: wizard |
3534 | objectName: "wizard" |
3535 | anchors.fill: parent |
3536 | - background: shell.background |
3537 | + background: wallpaperResolver.background |
3538 | |
3539 | function unlockWhenDoneWithWizard() { |
3540 | if (!active) { |
3541 | @@ -638,6 +610,7 @@ |
3542 | model: NotificationBackend.Model |
3543 | margin: units.gu(1) |
3544 | hasMouse: shell.hasMouse |
3545 | + background: wallpaperResolver.background |
3546 | |
3547 | y: topmostIsFullscreen ? 0 : panel.panelHeight |
3548 | height: parent.height - (topmostIsFullscreen ? 0 : panel.panelHeight) |
3549 | @@ -684,9 +657,21 @@ |
3550 | onShowHome: showHome() |
3551 | } |
3552 | |
3553 | + ScreenGrabber { |
3554 | + id: screenGrabber |
3555 | + rotationAngle: -shell.orientationAngle |
3556 | + z: dialogs.z + 10 |
3557 | + } |
3558 | + |
3559 | + Cursor { |
3560 | + id: cursor |
3561 | + visible: shell.hasMouse |
3562 | + z: screenGrabber.z + 1 |
3563 | + } |
3564 | + |
3565 | Rectangle { |
3566 | id: shutdownFadeOutRectangle |
3567 | - z: screenGrabber.z + 10 |
3568 | + z: cursor.z + 1 |
3569 | enabled: false |
3570 | visible: false |
3571 | color: "black" |
3572 | @@ -703,5 +688,4 @@ |
3573 | } |
3574 | } |
3575 | } |
3576 | - |
3577 | } |
3578 | |
3579 | === modified file 'qml/Stages/ApplicationWindow.qml' |
3580 | --- qml/Stages/ApplicationWindow.qml 2015-09-17 12:25:29 +0000 |
3581 | +++ qml/Stages/ApplicationWindow.qml 2015-10-26 12:04:03 +0000 |
3582 | @@ -27,6 +27,8 @@ |
3583 | readonly property bool fullscreen: application ? application.fullscreen : false |
3584 | property alias interactive: sessionContainer.interactive |
3585 | property bool orientationChangesEnabled: d.supportsSurfaceResize ? d.surfaceOldEnoughToBeResized : true |
3586 | + readonly property string title: sessionContainer.surface && sessionContainer.surface.name !== "" ? |
3587 | + sessionContainer.surface.name : d.name |
3588 | |
3589 | // to be set from outside |
3590 | property QtObject application |
3591 | |
3592 | === modified file 'qml/Stages/DecoratedWindow.qml' |
3593 | --- qml/Stages/DecoratedWindow.qml 2015-09-08 10:32:28 +0000 |
3594 | +++ qml/Stages/DecoratedWindow.qml 2015-10-26 12:04:03 +0000 |
3595 | @@ -31,9 +31,10 @@ |
3596 | property bool highlightShown: false |
3597 | property real shadowOpacity: 1 |
3598 | |
3599 | - signal close(); |
3600 | - signal maximize(); |
3601 | - signal minimize(); |
3602 | + signal close() |
3603 | + signal maximize() |
3604 | + signal minimize() |
3605 | + signal decorationPressed() |
3606 | |
3607 | BorderImage { |
3608 | anchors { |
3609 | @@ -61,13 +62,15 @@ |
3610 | |
3611 | WindowDecoration { |
3612 | id: decoration |
3613 | + target: root.parent |
3614 | objectName: application ? "appWindowDecoration_" + application.appId : "appWindowDecoration_null" |
3615 | anchors { left: parent.left; top: parent.top; right: parent.right } |
3616 | height: units.gu(3) |
3617 | - title: model.name |
3618 | + title: window.title !== "" ? window.title : model.name |
3619 | onClose: root.close(); |
3620 | onMaximize: root.maximize(); |
3621 | onMinimize: root.minimize(); |
3622 | + onPressed: root.decorationPressed(); |
3623 | visible: decorationShown |
3624 | } |
3625 | |
3626 | |
3627 | === modified file 'qml/Stages/DesktopStage.qml' |
3628 | --- qml/Stages/DesktopStage.qml 2015-09-18 15:28:07 +0000 |
3629 | +++ qml/Stages/DesktopStage.qml 2015-10-26 12:04:03 +0000 |
3630 | @@ -138,9 +138,6 @@ |
3631 | height: units.gu(50) |
3632 | focus: model.appId === priv.focusedAppId |
3633 | |
3634 | - readonly property int minWidth: units.gu(10) |
3635 | - readonly property int minHeight: units.gu(10) |
3636 | - |
3637 | property bool maximized: false |
3638 | property bool minimized: false |
3639 | |
3640 | @@ -215,12 +212,11 @@ |
3641 | when: index == spread.highlightedIndex && blurLayer.ready |
3642 | } |
3643 | |
3644 | - WindowMoveResizeArea { |
3645 | - id: windowMoveResizeArea |
3646 | + WindowResizeArea { |
3647 | target: appDelegate |
3648 | - minWidth: appDelegate.minWidth |
3649 | - minHeight: appDelegate.minHeight |
3650 | - resizeHandleWidth: units.gu(2) |
3651 | + minWidth: units.gu(10) |
3652 | + minHeight: units.gu(10) |
3653 | + borderThickness: units.gu(2) |
3654 | windowId: model.appId // FIXME: Change this to point to windowId once we have such a thing |
3655 | |
3656 | onPressed: { ApplicationManager.focusApplication(model.appId) } |
3657 | @@ -240,6 +236,7 @@ |
3658 | onClose: ApplicationManager.stopApplication(model.appId) |
3659 | onMaximize: appDelegate.maximize() |
3660 | onMinimize: appDelegate.minimize() |
3661 | + onDecorationPressed: { ApplicationManager.focusApplication(model.appId) } |
3662 | } |
3663 | } |
3664 | } |
3665 | |
3666 | === modified file 'qml/Stages/SurfaceContainer.qml' |
3667 | --- qml/Stages/SurfaceContainer.qml 2015-09-09 13:44:12 +0000 |
3668 | +++ qml/Stages/SurfaceContainer.qml 2015-10-26 12:04:03 +0000 |
3669 | @@ -28,6 +28,7 @@ |
3670 | property bool hadSurface: false |
3671 | property bool interactive |
3672 | property int surfaceOrientationAngle: 0 |
3673 | + property string name: surface ? surface.name : "" |
3674 | property bool resizeSurface: true |
3675 | |
3676 | onSurfaceChanged: { |
3677 | |
3678 | === modified file 'qml/Stages/WindowDecoration.qml' |
3679 | --- qml/Stages/WindowDecoration.qml 2015-03-13 19:18:35 +0000 |
3680 | +++ qml/Stages/WindowDecoration.qml 2015-10-26 12:04:03 +0000 |
3681 | @@ -1,5 +1,5 @@ |
3682 | /* |
3683 | - * Copyright (C) 2014 Canonical, Ltd. |
3684 | + * Copyright (C) 2014-2015 Canonical, Ltd. |
3685 | * |
3686 | * This program is free software; you can redistribute it and/or modify |
3687 | * it under the terms of the GNU General Public License as published by |
3688 | @@ -12,25 +12,53 @@ |
3689 | * |
3690 | * You should have received a copy of the GNU General Public License |
3691 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
3692 | - * |
3693 | - * Authors: Michael Zanetti <michael.zanetti@canonical.com> |
3694 | */ |
3695 | |
3696 | import QtQuick 2.3 |
3697 | +import Unity.Application 0.1 // For Mir singleton |
3698 | import Ubuntu.Components 1.1 |
3699 | import "../Components" |
3700 | |
3701 | -Item { |
3702 | +MouseArea { |
3703 | id: root |
3704 | clip: true |
3705 | |
3706 | + property Item target |
3707 | property alias title: titleLabel.text |
3708 | property bool active: false |
3709 | + hoverEnabled: true |
3710 | |
3711 | signal close() |
3712 | signal minimize() |
3713 | signal maximize() |
3714 | |
3715 | + QtObject { |
3716 | + id: priv |
3717 | + property real distanceX |
3718 | + property real distanceY |
3719 | + property bool dragging |
3720 | + } |
3721 | + |
3722 | + onPressedChanged: { |
3723 | + if (pressed) { |
3724 | + var pos = mapToItem(root.target, mouseX, mouseY); |
3725 | + priv.distanceX = pos.x; |
3726 | + priv.distanceY = pos.y; |
3727 | + priv.dragging = true; |
3728 | + Mir.cursorName = "grabbing"; |
3729 | + } else { |
3730 | + priv.dragging = false; |
3731 | + Mir.cursorName = ""; |
3732 | + } |
3733 | + } |
3734 | + onPositionChanged: { |
3735 | + if (priv.dragging) { |
3736 | + var pos = mapToItem(root.target.parent, mouseX, mouseY); |
3737 | + root.target.x = pos.x - priv.distanceX; |
3738 | + root.target.y = pos.y - priv.distanceY; |
3739 | + } |
3740 | + } |
3741 | + |
3742 | Rectangle { |
3743 | anchors.fill: parent |
3744 | anchors.bottomMargin: -radius |
3745 | |
3746 | === renamed file 'qml/Stages/WindowMoveResizeArea.qml' => 'qml/Stages/WindowResizeArea.qml' |
3747 | --- qml/Stages/WindowMoveResizeArea.qml 2015-09-08 10:32:28 +0000 |
3748 | +++ qml/Stages/WindowResizeArea.qml 2015-10-26 12:04:03 +0000 |
3749 | @@ -12,18 +12,19 @@ |
3750 | * |
3751 | * You should have received a copy of the GNU General Public License |
3752 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
3753 | - * |
3754 | - * Authors: Michael Zanetti <michael.zanetti@canonical.com> |
3755 | */ |
3756 | |
3757 | import QtQuick 2.3 |
3758 | import Ubuntu.Components 1.1 |
3759 | import Utils 0.1 |
3760 | +import Unity.Application 0.1 // for Mir.cursorName |
3761 | |
3762 | MouseArea { |
3763 | id: root |
3764 | anchors.fill: target |
3765 | - anchors.margins: -resizeHandleWidth |
3766 | + anchors.margins: -borderThickness |
3767 | + |
3768 | + hoverEnabled: true |
3769 | |
3770 | property var windowStateStorage: WindowStateStorage |
3771 | |
3772 | @@ -31,24 +32,10 @@ |
3773 | // The area will anchor to it and manage move and resize events |
3774 | property Item target: null |
3775 | property string windowId: "" |
3776 | - property int resizeHandleWidth: 0 |
3777 | + property int borderThickness: 0 |
3778 | property int minWidth: 0 |
3779 | property int minHeight: 0 |
3780 | |
3781 | - QtObject { |
3782 | - id: priv |
3783 | - readonly property int windowWidth: root.width - root.resizeHandleWidth * 2 |
3784 | - readonly property int windowHeight: root.height - resizeHandleWidth * 2 |
3785 | - |
3786 | - property var startPoint |
3787 | - |
3788 | - property bool resizeTop: false |
3789 | - property bool resizeBottom: false |
3790 | - property bool resizeLeft: false |
3791 | - property bool resizeRight: false |
3792 | - |
3793 | - } |
3794 | - |
3795 | Component.onCompleted: { |
3796 | var windowState = windowStateStorage.getGeometry(root.windowId, Qt.rect(target.x, target.y, target.width, target.height)) |
3797 | if (windowState !== undefined) { |
3798 | @@ -59,51 +46,137 @@ |
3799 | } |
3800 | } |
3801 | |
3802 | - onPressed: { |
3803 | - priv.startPoint = Qt.point(mouse.x, mouse.y); |
3804 | - priv.resizeTop = mouseY < root.resizeHandleWidth; |
3805 | - priv.resizeBottom = mouseY > (root.height - root.resizeHandleWidth); |
3806 | - priv.resizeLeft = mouseX < root.resizeHandleWidth; |
3807 | - priv.resizeRight = mouseX > (root.width - root.resizeHandleWidth); |
3808 | - } |
3809 | - |
3810 | - onPositionChanged: { |
3811 | - var currentPoint = Qt.point(mouse.x, mouse.y); |
3812 | - var mouseDiff = Qt.point(currentPoint.x - priv.startPoint.x, currentPoint.y - priv.startPoint.y); |
3813 | - var moveDiff = Qt.point(0, 0); |
3814 | - var sizeDiff = Qt.point(0, 0); |
3815 | - var maxSizeDiff = Qt.point(root.minWidth - root.target.width, root.minHeight - root.target.height) |
3816 | - |
3817 | - if (priv.resizeTop || priv.resizeBottom || priv.resizeLeft || priv.resizeRight) { |
3818 | - if (priv.resizeTop) { |
3819 | - sizeDiff.y = Math.max(maxSizeDiff.y, -currentPoint.y + priv.startPoint.y) |
3820 | - moveDiff.y = -sizeDiff.y |
3821 | - } |
3822 | - if (priv.resizeBottom) { |
3823 | - sizeDiff.y = Math.max(maxSizeDiff.y, currentPoint.y - priv.startPoint.y) |
3824 | - priv.startPoint.y += sizeDiff.y |
3825 | - } |
3826 | - if (priv.resizeLeft) { |
3827 | - sizeDiff.x = Math.max(maxSizeDiff.x, -currentPoint.x + priv.startPoint.x) |
3828 | - moveDiff.x = -sizeDiff.x |
3829 | - } |
3830 | - if (priv.resizeRight) { |
3831 | - sizeDiff.x = Math.max(maxSizeDiff.x, currentPoint.x - priv.startPoint.x) |
3832 | - priv.startPoint.x += sizeDiff.x |
3833 | - } |
3834 | - |
3835 | - target.x += moveDiff.x; |
3836 | - target.y += moveDiff.y; |
3837 | - target.width += sizeDiff.x; |
3838 | - target.height += sizeDiff.y; |
3839 | - } else { |
3840 | - target.x += mouseDiff.x; |
3841 | - target.y += mouseDiff.y; |
3842 | - } |
3843 | - |
3844 | - } |
3845 | - |
3846 | Component.onDestruction: { |
3847 | windowStateStorage.saveGeometry(root.windowId, Qt.rect(target.x, target.y, target.width, target.height)) |
3848 | } |
3849 | + |
3850 | + QtObject { |
3851 | + id: d |
3852 | + property bool leftBorder: false |
3853 | + property bool rightBorder: false |
3854 | + property bool topBorder: false |
3855 | + property bool bottomBorder: false |
3856 | + |
3857 | + property bool dragging: false |
3858 | + property real startMousePosX |
3859 | + property real startMousePosY |
3860 | + property real startX |
3861 | + property real startY |
3862 | + property real startWidth |
3863 | + property real startHeight |
3864 | + |
3865 | + property string cursorName: { |
3866 | + if (root.containsMouse || root.pressed) { |
3867 | + if (leftBorder && !topBorder && !bottomBorder) { |
3868 | + return "left_side"; |
3869 | + } else if (rightBorder && !topBorder && !bottomBorder) { |
3870 | + return "right_side"; |
3871 | + } else if (topBorder && !leftBorder && !rightBorder) { |
3872 | + return "top_side"; |
3873 | + } else if (bottomBorder && !leftBorder && !rightBorder) { |
3874 | + return "bottom_side"; |
3875 | + } else if (leftBorder && topBorder) { |
3876 | + return "top_left_corner"; |
3877 | + } else if (leftBorder && bottomBorder) { |
3878 | + return "bottom_left_corner"; |
3879 | + } else if (rightBorder && topBorder) { |
3880 | + return "top_right_corner"; |
3881 | + } else if (rightBorder && bottomBorder) { |
3882 | + return "bottom_right_corner"; |
3883 | + } else { |
3884 | + return ""; |
3885 | + } |
3886 | + } else { |
3887 | + return ""; |
3888 | + } |
3889 | + } |
3890 | + onCursorNameChanged: { |
3891 | + Mir.cursorName = cursorName; |
3892 | + } |
3893 | + |
3894 | + function updateBorders() { |
3895 | + leftBorder = mouseX <= borderThickness; |
3896 | + rightBorder = mouseX >= width - borderThickness; |
3897 | + topBorder = mouseY <= borderThickness; |
3898 | + bottomBorder = mouseY >= height - borderThickness; |
3899 | + } |
3900 | + } |
3901 | + |
3902 | + onPressedChanged: { |
3903 | + var pos = mapToItem(target.parent, mouseX, mouseY); |
3904 | + |
3905 | + if (pressed) { |
3906 | + d.updateBorders(); |
3907 | + var pos = mapToItem(root.target.parent, mouseX, mouseY); |
3908 | + d.startMousePosX = pos.x; |
3909 | + d.startMousePosY = pos.y; |
3910 | + d.startX = target.x; |
3911 | + d.startY = target.y; |
3912 | + d.startWidth = target.width; |
3913 | + d.startHeight = target.height; |
3914 | + d.dragging = true; |
3915 | + } else { |
3916 | + d.dragging = false; |
3917 | + if (containsMouse) { |
3918 | + d.updateBorders(); |
3919 | + } |
3920 | + } |
3921 | + } |
3922 | + |
3923 | + onEntered: { |
3924 | + if (!pressed) { |
3925 | + d.updateBorders(); |
3926 | + } |
3927 | + } |
3928 | + |
3929 | + onPositionChanged: { |
3930 | + if (!pressed) { |
3931 | + d.updateBorders(); |
3932 | + } |
3933 | + |
3934 | + if (!d.dragging) { |
3935 | + return; |
3936 | + } |
3937 | + |
3938 | + var pos = mapToItem(target.parent, mouse.x, mouse.y); |
3939 | + |
3940 | + var deltaX = pos.x - d.startMousePosX; |
3941 | + var deltaY = pos.y - d.startMousePosY; |
3942 | + |
3943 | + if (d.leftBorder) { |
3944 | + var newTargetX = d.startX + deltaX; |
3945 | + if (target.x + target.width > newTargetX + minWidth) { |
3946 | + target.width = target.x + target.width - newTargetX; |
3947 | + target.x = newTargetX; |
3948 | + } else { |
3949 | + target.x = target.x + target.width - minWidth; |
3950 | + target.width = minWidth; |
3951 | + } |
3952 | + |
3953 | + } else if (d.rightBorder) { |
3954 | + if (d.startWidth + deltaX >= minWidth) { |
3955 | + target.width = d.startWidth + deltaX; |
3956 | + } else { |
3957 | + target.width = minWidth; |
3958 | + } |
3959 | + } |
3960 | + |
3961 | + if (d.topBorder) { |
3962 | + var newTargetY = d.startY + deltaY; |
3963 | + if (target.y + target.height > newTargetY + minHeight) { |
3964 | + target.height = target.y + target.height - newTargetY; |
3965 | + target.y = newTargetY; |
3966 | + } else { |
3967 | + target.y = target.y + target.height - minHeight; |
3968 | + target.height = minHeight; |
3969 | + } |
3970 | + |
3971 | + } else if (d.bottomBorder) { |
3972 | + if (d.startHeight + deltaY >= minHeight) { |
3973 | + target.height = d.startHeight + deltaY; |
3974 | + } else { |
3975 | + target.height = minHeight; |
3976 | + } |
3977 | + } |
3978 | + } |
3979 | } |
3980 | |
3981 | === modified file 'src/ApplicationArguments.h' |
3982 | --- src/ApplicationArguments.h 2015-09-14 09:11:08 +0000 |
3983 | +++ src/ApplicationArguments.h 2015-10-26 12:04:03 +0000 |
3984 | @@ -26,17 +26,25 @@ |
3985 | class ApplicationArguments : public QObject |
3986 | { |
3987 | Q_OBJECT |
3988 | - Q_PROPERTY(QString deviceName READ deviceName CONSTANT) |
3989 | + Q_PROPERTY(QString deviceName READ deviceName NOTIFY deviceNameChanged) |
3990 | Q_PROPERTY(QString mode READ mode CONSTANT) |
3991 | public: |
3992 | ApplicationArguments(QObject *parent = nullptr); |
3993 | |
3994 | - void setDeviceName(const QString &deviceName) { m_deviceName = deviceName; } |
3995 | + void setDeviceName(const QString &deviceName) { |
3996 | + if (deviceName != m_deviceName) { |
3997 | + m_deviceName = deviceName; |
3998 | + Q_EMIT deviceNameChanged(m_deviceName); |
3999 | + } |
4000 | + } |
4001 | QString deviceName() const { return m_deviceName; } |
4002 | |
4003 | void setMode(const QString &mode) { m_mode = mode; } |
4004 | QString mode() const { return m_mode; } |
4005 | |
4006 | +Q_SIGNALS: |
4007 | + void deviceNameChanged(const QString&); |
4008 | + |
4009 | private: |
4010 | QString m_deviceName; |
4011 | QString m_mode; |
4012 | |
4013 | === modified file 'src/CMakeLists.txt' |
4014 | --- src/CMakeLists.txt 2015-06-24 11:41:09 +0000 |
4015 | +++ src/CMakeLists.txt 2015-10-26 12:04:03 +0000 |
4016 | @@ -21,6 +21,9 @@ |
4017 | main.cpp |
4018 | MouseTouchAdaptor.cpp |
4019 | CachingNetworkManagerFactory.cpp |
4020 | + SecondaryWindow.cpp |
4021 | + ShellApplication.cpp |
4022 | + ShellView.cpp |
4023 | UnityCommandLineParser.cpp |
4024 | ${QML_FILES} # This is to make qml and image files appear in the IDE's project tree |
4025 | ) |
4026 | |
4027 | === added file 'src/SecondaryWindow.cpp' |
4028 | --- src/SecondaryWindow.cpp 1970-01-01 00:00:00 +0000 |
4029 | +++ src/SecondaryWindow.cpp 2015-10-26 12:04:03 +0000 |
4030 | @@ -0,0 +1,31 @@ |
4031 | +/* |
4032 | + * Copyright (C) 2015 Canonical, Ltd. |
4033 | + * |
4034 | + * This program is free software; you can redistribute it and/or modify |
4035 | + * it under the terms of the GNU General Public License as published by |
4036 | + * the Free Software Foundation; version 3. |
4037 | + * |
4038 | + * This program is distributed in the hope that it will be useful, |
4039 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
4040 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
4041 | + * GNU General Public License for more details. |
4042 | + * |
4043 | + * You should have received a copy of the GNU General Public License |
4044 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
4045 | + */ |
4046 | + |
4047 | +#include "SecondaryWindow.h" |
4048 | + |
4049 | +// local |
4050 | +#include <paths.h> |
4051 | + |
4052 | +SecondaryWindow::SecondaryWindow(QQmlEngine *engine) |
4053 | + : QQuickView(engine, nullptr) |
4054 | +{ |
4055 | + setResizeMode(QQuickView::SizeRootObjectToView); |
4056 | + setColor("black"); |
4057 | + setTitle(QStringLiteral("Unity8 Shell - Secondary Screen")); |
4058 | + |
4059 | + QUrl source(::qmlDirectory() + "/DisabledScreenNotice.qml"); |
4060 | + setSource(source); |
4061 | +} |
4062 | |
4063 | === added file 'src/SecondaryWindow.h' |
4064 | --- src/SecondaryWindow.h 1970-01-01 00:00:00 +0000 |
4065 | +++ src/SecondaryWindow.h 2015-10-26 12:04:03 +0000 |
4066 | @@ -0,0 +1,30 @@ |
4067 | +/* |
4068 | + * Copyright (C) 2015 Canonical, Ltd. |
4069 | + * |
4070 | + * This program is free software; you can redistribute it and/or modify |
4071 | + * it under the terms of the GNU General Public License as published by |
4072 | + * the Free Software Foundation; version 3. |
4073 | + * |
4074 | + * This program is distributed in the hope that it will be useful, |
4075 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
4076 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
4077 | + * GNU General Public License for more details. |
4078 | + * |
4079 | + * You should have received a copy of the GNU General Public License |
4080 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
4081 | + */ |
4082 | + |
4083 | +#ifndef UNITY_SECONDARY_WINDOW_H |
4084 | +#define UNITY_SECONDARY_WINDOW_H |
4085 | + |
4086 | +#include <QQuickView> |
4087 | + |
4088 | +class SecondaryWindow : public QQuickView |
4089 | +{ |
4090 | + Q_OBJECT |
4091 | + |
4092 | +public: |
4093 | + SecondaryWindow(QQmlEngine *engine); |
4094 | +}; |
4095 | + |
4096 | +#endif // UNITY_SECONDARY_WINDOW_H |
4097 | |
4098 | === added file 'src/ShellApplication.cpp' |
4099 | --- src/ShellApplication.cpp 1970-01-01 00:00:00 +0000 |
4100 | +++ src/ShellApplication.cpp 2015-10-26 12:04:03 +0000 |
4101 | @@ -0,0 +1,197 @@ |
4102 | +/* |
4103 | + * Copyright (C) 2015 Canonical, Ltd. |
4104 | + * |
4105 | + * This program is free software; you can redistribute it and/or modify |
4106 | + * it under the terms of the GNU General Public License as published by |
4107 | + * the Free Software Foundation; version 3. |
4108 | + * |
4109 | + * This program is distributed in the hope that it will be useful, |
4110 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
4111 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
4112 | + * GNU General Public License for more details. |
4113 | + * |
4114 | + * You should have received a copy of the GNU General Public License |
4115 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
4116 | + */ |
4117 | + |
4118 | +#include "ShellApplication.h" |
4119 | + |
4120 | +// Qt |
4121 | +#include <QLibrary> |
4122 | +#include <QScreen> |
4123 | + |
4124 | +#include <libintl.h> |
4125 | + |
4126 | +// libandroid-properties |
4127 | +#include <hybris/properties/properties.h> |
4128 | + |
4129 | +// local |
4130 | +#include <paths.h> |
4131 | +#include "CachingNetworkManagerFactory.h" |
4132 | +#include "MouseTouchAdaptor.h" |
4133 | +#include "UnityCommandLineParser.h" |
4134 | + |
4135 | +ShellApplication::ShellApplication(int & argc, char ** argv, bool isMirServer) |
4136 | + : QGuiApplication(argc, argv) |
4137 | + , m_shellView(nullptr) |
4138 | + , m_secondaryWindow(nullptr) |
4139 | + , m_mouseTouchAdaptor(nullptr) |
4140 | + , m_qmlEngine(nullptr) |
4141 | +{ |
4142 | + |
4143 | + setApplicationName(QStringLiteral("unity8")); |
4144 | + |
4145 | + connect(this, &QGuiApplication::screenAdded, this, &ShellApplication::onScreenAdded); |
4146 | + |
4147 | + setupQmlEngine(isMirServer); |
4148 | + |
4149 | + UnityCommandLineParser parser(*this); |
4150 | + |
4151 | + if (!parser.deviceName().isEmpty()) { |
4152 | + m_deviceName = parser.deviceName(); |
4153 | + } else { |
4154 | + char buffer[200]; |
4155 | + property_get("ro.product.device", buffer /* value */, "desktop" /* default_value*/); |
4156 | + m_deviceName = QString(buffer); |
4157 | + } |
4158 | + m_qmlArgs.setDeviceName(m_deviceName); |
4159 | + |
4160 | + m_qmlArgs.setMode(parser.mode()); |
4161 | + |
4162 | + // The testability driver is only loaded by QApplication but not by QGuiApplication. |
4163 | + // However, QApplication depends on QWidget which would add some unneeded overhead => Let's load the testability driver on our own. |
4164 | + if (parser.hasTestability() || getenv("QT_LOAD_TESTABILITY")) { |
4165 | + QLibrary testLib(QStringLiteral("qttestability")); |
4166 | + if (testLib.load()) { |
4167 | + typedef void (*TasInitialize)(void); |
4168 | + TasInitialize initFunction = (TasInitialize)testLib.resolve("qt_testability_init"); |
4169 | + if (initFunction) { |
4170 | + initFunction(); |
4171 | + } else { |
4172 | + qCritical("Library qttestability resolve failed!"); |
4173 | + } |
4174 | + } else { |
4175 | + qCritical("Library qttestability load failed!"); |
4176 | + } |
4177 | + } |
4178 | + |
4179 | + bindtextdomain("unity8", translationDirectory().toUtf8().data()); |
4180 | + textdomain("unity8"); |
4181 | + |
4182 | + m_shellView = new ShellView(m_qmlEngine, &m_qmlArgs); |
4183 | + |
4184 | + if (parser.windowGeometry().isValid()) { |
4185 | + m_shellView->setWidth(parser.windowGeometry().width()); |
4186 | + m_shellView->setHeight(parser.windowGeometry().height()); |
4187 | + } |
4188 | + |
4189 | + if (parser.hasFrameless()) { |
4190 | + m_shellView->setFlags(Qt::FramelessWindowHint); |
4191 | + } |
4192 | + |
4193 | + // You will need this if you want to interact with touch-only components using a mouse |
4194 | + // Needed only when manually testing on a desktop. |
4195 | + if (parser.hasMouseToTouch()) { |
4196 | + m_mouseTouchAdaptor = MouseTouchAdaptor::instance(); |
4197 | + } |
4198 | + |
4199 | + |
4200 | + // Some hard-coded policy for now. |
4201 | + // NB: We don't support more than two screens at the moment |
4202 | + // |
4203 | + // TODO: Support an arbitrary number of screens and different policies |
4204 | + // (eg cloned desktop, several desktops, etc) |
4205 | + if (isMirServer && screens().count() == 2) { |
4206 | + m_shellView->setScreen(screens().at(1)); |
4207 | + m_qmlArgs.setDeviceName("desktop"); |
4208 | + |
4209 | + m_secondaryWindow = new SecondaryWindow(m_qmlEngine); |
4210 | + m_secondaryWindow->setScreen(screens().at(0)); |
4211 | + // QWindow::showFullScreen() also calls QWindow::requestActivate() and we don't want that! |
4212 | + m_secondaryWindow->setWindowState(Qt::WindowFullScreen); |
4213 | + m_secondaryWindow->setVisible(true); |
4214 | + } |
4215 | + |
4216 | + if (isMirServer || parser.hasFullscreen()) { |
4217 | + m_shellView->showFullScreen(); |
4218 | + } else { |
4219 | + m_shellView->show(); |
4220 | + } |
4221 | +} |
4222 | + |
4223 | +ShellApplication::~ShellApplication() |
4224 | +{ |
4225 | + destroyResources(); |
4226 | +} |
4227 | + |
4228 | +void ShellApplication::destroyResources() |
4229 | +{ |
4230 | + // Deletion order is important. Don't use QScopedPointers and the like |
4231 | + // Otherwise the process will hang on shutdown (bug somewhere I guess). |
4232 | + delete m_shellView; |
4233 | + m_shellView = nullptr; |
4234 | + |
4235 | + delete m_secondaryWindow; |
4236 | + m_secondaryWindow = nullptr; |
4237 | + |
4238 | + delete m_mouseTouchAdaptor; |
4239 | + m_mouseTouchAdaptor = nullptr; |
4240 | + |
4241 | + delete m_qmlEngine; |
4242 | + m_qmlEngine = nullptr; |
4243 | +} |
4244 | + |
4245 | +void ShellApplication::setupQmlEngine(bool isMirServer) |
4246 | +{ |
4247 | + m_qmlEngine = new QQmlEngine(this); |
4248 | + |
4249 | + m_qmlEngine->setBaseUrl(QUrl::fromLocalFile(::qmlDirectory())); |
4250 | + |
4251 | + prependImportPaths(m_qmlEngine, ::overrideImportPaths()); |
4252 | + if (!isMirServer) { |
4253 | + prependImportPaths(m_qmlEngine, ::nonMirImportPaths()); |
4254 | + } |
4255 | + appendImportPaths(m_qmlEngine, ::fallbackImportPaths()); |
4256 | + |
4257 | + m_qmlEngine->setNetworkAccessManagerFactory(new CachingNetworkManagerFactory); |
4258 | + |
4259 | + QObject::connect(m_qmlEngine, &QQmlEngine::quit, this, &QGuiApplication::quit); |
4260 | +} |
4261 | + |
4262 | +void ShellApplication::onScreenAdded(QScreen * /*screen*/) |
4263 | +{ |
4264 | + // TODO: Support an arbitrary number of screens and different policies |
4265 | + // (eg cloned desktop, several desktops, etc) |
4266 | + if (screens().count() == 2) { |
4267 | + m_shellView->setScreen(screens().at(1)); |
4268 | + m_qmlArgs.setDeviceName("desktop"); |
4269 | + // Changing the QScreen where a QWindow is drawn makes it also lose focus (besides having |
4270 | + // its backing QPlatformWindow recreated). So lets refocus it. |
4271 | + m_shellView->requestActivate(); |
4272 | + |
4273 | + m_secondaryWindow = new SecondaryWindow(m_qmlEngine); |
4274 | + m_secondaryWindow->setScreen(screens().at(0)); |
4275 | + |
4276 | + // QWindow::showFullScreen() also calls QWindow::requestActivate() and we don't want that! |
4277 | + m_secondaryWindow->setWindowState(Qt::WindowFullScreen); |
4278 | + m_secondaryWindow->setVisible(true); |
4279 | + } |
4280 | +} |
4281 | + |
4282 | +void ShellApplication::onScreenAboutToBeRemoved(QScreen *screen) |
4283 | +{ |
4284 | + // TODO: Support an arbitrary number of screens and different policies |
4285 | + // (eg cloned desktop, several desktops, etc) |
4286 | + if (screen == m_shellView->screen()) { |
4287 | + Q_ASSERT(screens().count() > 1); |
4288 | + Q_ASSERT(screens().at(0) != screen); |
4289 | + Q_ASSERT(m_secondaryWindow); |
4290 | + delete m_secondaryWindow; |
4291 | + m_secondaryWindow = nullptr; |
4292 | + m_shellView->setScreen(screens().first()); |
4293 | + m_qmlArgs.setDeviceName(m_deviceName); |
4294 | + // Changing the QScreen where a QWindow is drawn makes it also lose focus (besides having |
4295 | + // its backing QPlatformWindow recreated). So lets refocus it. |
4296 | + m_shellView->requestActivate(); |
4297 | + } |
4298 | +} |
4299 | |
4300 | === added file 'src/ShellApplication.h' |
4301 | --- src/ShellApplication.h 1970-01-01 00:00:00 +0000 |
4302 | +++ src/ShellApplication.h 2015-10-26 12:04:03 +0000 |
4303 | @@ -0,0 +1,55 @@ |
4304 | +/* |
4305 | + * Copyright (C) 2015 Canonical, Ltd. |
4306 | + * |
4307 | + * This program is free software; you can redistribute it and/or modify |
4308 | + * it under the terms of the GNU General Public License as published by |
4309 | + * the Free Software Foundation; version 3. |
4310 | + * |
4311 | + * This program is distributed in the hope that it will be useful, |
4312 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
4313 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
4314 | + * GNU General Public License for more details. |
4315 | + * |
4316 | + * You should have received a copy of the GNU General Public License |
4317 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
4318 | + */ |
4319 | + |
4320 | +#ifndef SHELLAPPLICATION_H |
4321 | +#define SHELLAPPLICATION_H |
4322 | + |
4323 | +#include <QGuiApplication> |
4324 | +#include <QQmlEngine> |
4325 | +#include <QQuickView> |
4326 | +#include <QScopedPointer> |
4327 | + |
4328 | +#include "ApplicationArguments.h" |
4329 | +#include "MouseTouchAdaptor.h" |
4330 | +#include "SecondaryWindow.h" |
4331 | +#include "ShellView.h" |
4332 | + |
4333 | +class ShellApplication : public QGuiApplication |
4334 | +{ |
4335 | + Q_OBJECT |
4336 | +public: |
4337 | + ShellApplication(int & argc, char ** argv, bool isMirServer); |
4338 | + virtual ~ShellApplication(); |
4339 | + |
4340 | + void destroyResources(); |
4341 | +public Q_SLOTS: |
4342 | + // called by qtmir |
4343 | + void onScreenAboutToBeRemoved(QScreen *screen); |
4344 | + |
4345 | +private Q_SLOTS: |
4346 | + void onScreenAdded(QScreen*); |
4347 | + |
4348 | +private: |
4349 | + void setupQmlEngine(bool isMirServer); |
4350 | + QString m_deviceName; |
4351 | + ApplicationArguments m_qmlArgs; |
4352 | + ShellView *m_shellView; |
4353 | + SecondaryWindow *m_secondaryWindow; |
4354 | + MouseTouchAdaptor *m_mouseTouchAdaptor; |
4355 | + QQmlEngine *m_qmlEngine; |
4356 | +}; |
4357 | + |
4358 | +#endif // SHELLAPPLICATION_H |
4359 | |
4360 | === added file 'src/ShellView.cpp' |
4361 | --- src/ShellView.cpp 1970-01-01 00:00:00 +0000 |
4362 | +++ src/ShellView.cpp 2015-10-26 12:04:03 +0000 |
4363 | @@ -0,0 +1,59 @@ |
4364 | +/* |
4365 | + * Copyright (C) 2015 Canonical, Ltd. |
4366 | + * |
4367 | + * This program is free software; you can redistribute it and/or modify |
4368 | + * it under the terms of the GNU General Public License as published by |
4369 | + * the Free Software Foundation; version 3. |
4370 | + * |
4371 | + * This program is distributed in the hope that it will be useful, |
4372 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
4373 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
4374 | + * GNU General Public License for more details. |
4375 | + * |
4376 | + * You should have received a copy of the GNU General Public License |
4377 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
4378 | + */ |
4379 | + |
4380 | +#include "ShellView.h" |
4381 | + |
4382 | +// Qt |
4383 | +#include <QQmlContext> |
4384 | +#include <QQuickItem> |
4385 | + |
4386 | +// local |
4387 | +#include <paths.h> |
4388 | + |
4389 | +ShellView::ShellView(QQmlEngine *engine, QObject *qmlArgs) |
4390 | + : QQuickView(engine, nullptr) |
4391 | +{ |
4392 | + setResizeMode(QQuickView::SizeRootObjectToView); |
4393 | + setColor("black"); |
4394 | + setTitle(QStringLiteral("Unity8")); |
4395 | + |
4396 | + rootContext()->setContextProperty(QStringLiteral("applicationArguments"), qmlArgs); |
4397 | + |
4398 | + QUrl source(::qmlDirectory() + "/OrientedShell.qml"); |
4399 | + setSource(source); |
4400 | + |
4401 | + connect(this, &QWindow::widthChanged, this, &ShellView::onWidthChanged); |
4402 | + connect(this, &QWindow::heightChanged, this, &ShellView::onHeightChanged); |
4403 | +} |
4404 | + |
4405 | +void ShellView::onWidthChanged(int w) |
4406 | +{ |
4407 | + // For good measure in case SizeRootObjectToView doesn't fulfill its promise. |
4408 | + // |
4409 | + // There's at least one situation that's know to leave the root object with an outdated size. |
4410 | + // (really looks like Qt bug) |
4411 | + // Happens when starting unity8 with an external monitor already connected. |
4412 | + // The QResizeEvent we get still has the size of the first screen and since the resize move is triggered |
4413 | + // from the resize event handler, the root item doesn't get resized. |
4414 | + // TODO: Confirm the Qt bug and submit a patch upstream |
4415 | + rootObject()->setWidth(w); |
4416 | +} |
4417 | + |
4418 | +void ShellView::onHeightChanged(int h) |
4419 | +{ |
4420 | + // See comment in ShellView::onWidthChanged() |
4421 | + rootObject()->setHeight(h); |
4422 | +} |
4423 | |
4424 | === added file 'src/ShellView.h' |
4425 | --- src/ShellView.h 1970-01-01 00:00:00 +0000 |
4426 | +++ src/ShellView.h 2015-10-26 12:04:03 +0000 |
4427 | @@ -0,0 +1,34 @@ |
4428 | +/* |
4429 | + * Copyright (C) 2015 Canonical, Ltd. |
4430 | + * |
4431 | + * This program is free software; you can redistribute it and/or modify |
4432 | + * it under the terms of the GNU General Public License as published by |
4433 | + * the Free Software Foundation; version 3. |
4434 | + * |
4435 | + * This program is distributed in the hope that it will be useful, |
4436 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
4437 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
4438 | + * GNU General Public License for more details. |
4439 | + * |
4440 | + * You should have received a copy of the GNU General Public License |
4441 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
4442 | + */ |
4443 | + |
4444 | +#ifndef UNITY_SHELL_VIEW_H |
4445 | +#define UNITY_SHELL_VIEW_H |
4446 | + |
4447 | +#include <QQuickView> |
4448 | + |
4449 | +class ShellView : public QQuickView |
4450 | +{ |
4451 | + Q_OBJECT |
4452 | + |
4453 | +public: |
4454 | + ShellView(QQmlEngine *engine, QObject *qmlArgs); |
4455 | + |
4456 | +private Q_SLOTS: |
4457 | + void onWidthChanged(int); |
4458 | + void onHeightChanged(int); |
4459 | +}; |
4460 | + |
4461 | +#endif // UNITY_SHELL_VIEW_H |
4462 | |
4463 | === modified file 'src/main.cpp' |
4464 | --- src/main.cpp 2015-09-23 15:14:01 +0000 |
4465 | +++ src/main.cpp 2015-10-26 12:04:03 +0000 |
4466 | @@ -14,26 +14,8 @@ |
4467 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
4468 | */ |
4469 | |
4470 | -// Qt |
4471 | -#include <QCommandLineParser> |
4472 | -#include <QtQuick/QQuickView> |
4473 | -#include <QtGui/QGuiApplication> |
4474 | -#include <QtQml/QQmlEngine> |
4475 | -#include <QtQml/QQmlContext> |
4476 | -#include <QLibrary> |
4477 | -#include <QDebug> |
4478 | -#include <csignal> |
4479 | -#include <libintl.h> |
4480 | - |
4481 | -// libandroid-properties |
4482 | -#include <hybris/properties/properties.h> |
4483 | - |
4484 | // local |
4485 | -#include <paths.h> |
4486 | -#include "MouseTouchAdaptor.h" |
4487 | -#include "ApplicationArguments.h" |
4488 | -#include "CachingNetworkManagerFactory.h" |
4489 | -#include "UnityCommandLineParser.h" |
4490 | +#include "ShellApplication.h" |
4491 | |
4492 | int main(int argc, const char *argv[]) |
4493 | { |
4494 | @@ -43,91 +25,12 @@ |
4495 | isMirServer = true; |
4496 | } |
4497 | |
4498 | - QGuiApplication::setApplicationName(QStringLiteral("unity8")); |
4499 | - QGuiApplication *application; |
4500 | - |
4501 | - application = new QGuiApplication(argc, (char**)argv); |
4502 | - |
4503 | - UnityCommandLineParser parser(*application); |
4504 | - |
4505 | - ApplicationArguments qmlArgs; |
4506 | - |
4507 | - if (!parser.deviceName().isEmpty()) { |
4508 | - qmlArgs.setDeviceName(parser.deviceName()); |
4509 | - } else { |
4510 | - char buffer[200]; |
4511 | - property_get("ro.product.device", buffer /* value */, "desktop" /* default_value*/); |
4512 | - qmlArgs.setDeviceName(QString(buffer)); |
4513 | - } |
4514 | - |
4515 | - qmlArgs.setMode(parser.mode()); |
4516 | - |
4517 | - // The testability driver is only loaded by QApplication but not by QGuiApplication. |
4518 | - // However, QApplication depends on QWidget which would add some unneeded overhead => Let's load the testability driver on our own. |
4519 | - if (parser.hasTestability() || getenv("QT_LOAD_TESTABILITY")) { |
4520 | - QLibrary testLib(QStringLiteral("qttestability")); |
4521 | - if (testLib.load()) { |
4522 | - typedef void (*TasInitialize)(void); |
4523 | - TasInitialize initFunction = (TasInitialize)testLib.resolve("qt_testability_init"); |
4524 | - if (initFunction) { |
4525 | - initFunction(); |
4526 | - } else { |
4527 | - qCritical("Library qttestability resolve failed!"); |
4528 | - } |
4529 | - } else { |
4530 | - qCritical("Library qttestability load failed!"); |
4531 | - } |
4532 | - } |
4533 | - |
4534 | - bindtextdomain("unity8", translationDirectory().toUtf8().data()); |
4535 | - textdomain("unity8"); |
4536 | - |
4537 | - QQuickView* view = new QQuickView(); |
4538 | - view->setResizeMode(QQuickView::SizeRootObjectToView); |
4539 | - view->setColor("black"); |
4540 | - view->setTitle(QStringLiteral("Unity8 Shell")); |
4541 | - |
4542 | - if (parser.windowGeometry().isValid()) { |
4543 | - view->setWidth(parser.windowGeometry().width()); |
4544 | - view->setHeight(parser.windowGeometry().height()); |
4545 | - } |
4546 | - |
4547 | - view->engine()->setBaseUrl(QUrl::fromLocalFile(::qmlDirectory())); |
4548 | - view->rootContext()->setContextProperty(QStringLiteral("applicationArguments"), &qmlArgs); |
4549 | - if (parser.hasFrameless()) { |
4550 | - view->setFlags(Qt::FramelessWindowHint); |
4551 | - } |
4552 | - |
4553 | - // You will need this if you want to interact with touch-only components using a mouse |
4554 | - // Needed only when manually testing on a desktop. |
4555 | - MouseTouchAdaptor *mouseTouchAdaptor = 0; |
4556 | - if (parser.hasMouseToTouch()) { |
4557 | - mouseTouchAdaptor = MouseTouchAdaptor::instance(); |
4558 | - } |
4559 | - |
4560 | - QUrl source(::qmlDirectory() + "/OrientedShell.qml"); |
4561 | - prependImportPaths(view->engine(), ::overrideImportPaths()); |
4562 | - if (!isMirServer) { |
4563 | - prependImportPaths(view->engine(), ::nonMirImportPaths()); |
4564 | - } |
4565 | - appendImportPaths(view->engine(), ::fallbackImportPaths()); |
4566 | - |
4567 | - CachingNetworkManagerFactory *managerFactory = new CachingNetworkManagerFactory(); |
4568 | - view->engine()->setNetworkAccessManagerFactory(managerFactory); |
4569 | - |
4570 | - view->setSource(source); |
4571 | - QObject::connect(view->engine(), &QQmlEngine::quit, application, &QGuiApplication::quit); |
4572 | - |
4573 | - if (isMirServer || parser.hasFullscreen()) { |
4574 | - view->showFullScreen(); |
4575 | - } else { |
4576 | - view->show(); |
4577 | - } |
4578 | + ShellApplication *application = new ShellApplication(argc, (char**)argv, isMirServer); |
4579 | |
4580 | int result = application->exec(); |
4581 | |
4582 | - delete view; |
4583 | - delete mouseTouchAdaptor; |
4584 | + application->destroyResources(); |
4585 | + |
4586 | delete application; |
4587 | |
4588 | return result; |
4589 | |
4590 | === modified file 'tests/autopilot/unity8/fixture_setup.py' |
4591 | --- tests/autopilot/unity8/fixture_setup.py 2015-09-21 12:50:10 +0000 |
4592 | +++ tests/autopilot/unity8/fixture_setup.py 2015-10-26 12:04:03 +0000 |
4593 | @@ -133,7 +133,7 @@ |
4594 | args = [binary_arg] + env_args |
4595 | self.unity_proxy = process_helpers.restart_unity_with_testability( |
4596 | *args) |
4597 | - self.main_win = self.unity_proxy.select_single(shell.QQuickView) |
4598 | + self.main_win = self.unity_proxy.select_single(shell.ShellView) |
4599 | |
4600 | def _create_sensors(self): |
4601 | # Wait for unity to start running. |
4602 | |
4603 | === modified file 'tests/autopilot/unity8/greeter/tests/__init__.py' |
4604 | --- tests/autopilot/unity8/greeter/tests/__init__.py 2015-04-29 19:21:18 +0000 |
4605 | +++ tests/autopilot/unity8/greeter/tests/__init__.py 2015-10-26 12:04:03 +0000 |
4606 | @@ -24,5 +24,5 @@ |
4607 | class GreeterTestCase(UnityTestCase): |
4608 | def get_shell(self, unity_proxy): |
4609 | main_window = ( |
4610 | - unity_proxy.select_single(shell.QQuickView)) |
4611 | + unity_proxy.select_single(shell.ShellView)) |
4612 | return main_window.select_single('Shell') |
4613 | |
4614 | === modified file 'tests/autopilot/unity8/launcher.py' |
4615 | --- tests/autopilot/unity8/launcher.py 2015-04-29 19:21:18 +0000 |
4616 | +++ tests/autopilot/unity8/launcher.py 2015-10-26 12:04:03 +0000 |
4617 | @@ -42,7 +42,7 @@ |
4618 | logger.debug('The launcher is already opened.') |
4619 | |
4620 | def _swipe_to_show_launcher(self): |
4621 | - view = self.get_root_instance().select_single('QQuickView') |
4622 | + view = self.get_root_instance().select_single('ShellView') |
4623 | start_y = stop_y = view.y + view.height // 2 |
4624 | |
4625 | start_x = view.x + 1 |
4626 | |
4627 | === modified file 'tests/autopilot/unity8/settings_wizard/__init__.py' |
4628 | --- tests/autopilot/unity8/settings_wizard/__init__.py 2015-05-21 16:52:05 +0000 |
4629 | +++ tests/autopilot/unity8/settings_wizard/__init__.py 2015-10-26 12:04:03 +0000 |
4630 | @@ -375,12 +375,17 @@ |
4631 | wizard = get_wizard(self) |
4632 | next_page = wizard.get_current_page() |
4633 | locationPageEnabled = True |
4634 | + reportingPageEnabled = True |
4635 | if next_page.objectName == 'locationPage': |
4636 | next_page = wizard.get_location_page() |
4637 | else: |
4638 | locationPageEnabled = False |
4639 | - next_page = wizard.get_reporting_page() |
4640 | - return locationPageEnabled, next_page |
4641 | + if next_page.objectName == 'reportingPage': |
4642 | + next_page = wizard.get_reporting_page() |
4643 | + else: |
4644 | + reportingPageEnabled = False |
4645 | + next_page = wizard.get_finished_page() |
4646 | + return locationPageEnabled, reportingPageEnabled, next_page |
4647 | |
4648 | def _get_notification(self, unity): |
4649 | logger.info('Waiting longer for notification object') |
4650 | |
4651 | === modified file 'tests/autopilot/unity8/settings_wizard/tests/test_settings_wizard.py' |
4652 | --- tests/autopilot/unity8/settings_wizard/tests/test_settings_wizard.py 2015-05-21 16:37:36 +0000 |
4653 | +++ tests/autopilot/unity8/settings_wizard/tests/test_settings_wizard.py 2015-10-26 12:04:03 +0000 |
4654 | @@ -80,14 +80,19 @@ |
4655 | password_page = next_page |
4656 | wifi_connect_page = self._test_password_page(password_page) |
4657 | |
4658 | - locationPageEnabled, next_page = self._test_wifi_connect_page( |
4659 | - wifi_connect_page) |
4660 | + reporting_page = None |
4661 | + locationPageEnabled, reportingPageEnabled, next_page = self._test_wifi_connect_page(wifi_connect_page) |
4662 | if locationPageEnabled: |
4663 | location_page = next_page |
4664 | - reporting_page = self._test_location_page(location_page) |
4665 | + if reportingPageEnabled: |
4666 | + reporting_page = self._test_location_page(location_page) |
4667 | + else: |
4668 | + finish_page = next_page |
4669 | + |
4670 | + if reporting_page is not None: |
4671 | + finish_page = self._test_reporting_page(reporting_page) |
4672 | else: |
4673 | - reporting_page = next_page |
4674 | - finish_page = self._test_reporting_page(reporting_page) |
4675 | + finish_page = next_page |
4676 | |
4677 | finish_page.finish() |
4678 | self.assertFalse( |
4679 | |
4680 | === modified file 'tests/autopilot/unity8/shell/__init__.py' |
4681 | --- tests/autopilot/unity8/shell/__init__.py 2015-06-22 15:47:34 +0000 |
4682 | +++ tests/autopilot/unity8/shell/__init__.py 2015-10-26 12:04:03 +0000 |
4683 | @@ -93,7 +93,7 @@ |
4684 | return _urgency_enums.get(urgency.upper()) |
4685 | |
4686 | |
4687 | -class QQuickView(ubuntuuitoolkit.UbuntuUIToolkitCustomProxyObjectBase): |
4688 | +class ShellView(ubuntuuitoolkit.UbuntuUIToolkitCustomProxyObjectBase): |
4689 | """An helper class that makes it easy to interact with the shell""" |
4690 | |
4691 | def get_greeter(self): |
4692 | |
4693 | === modified file 'tests/autopilot/unity8/shell/tests/__init__.py' |
4694 | --- tests/autopilot/unity8/shell/tests/__init__.py 2015-09-21 12:50:10 +0000 |
4695 | +++ tests/autopilot/unity8/shell/tests/__init__.py 2015-10-26 12:04:03 +0000 |
4696 | @@ -297,7 +297,7 @@ |
4697 | |
4698 | @property |
4699 | def main_window(self): |
4700 | - return self._proxy.select_single(shell.QQuickView) |
4701 | + return self._proxy.select_single(shell.ShellView) |
4702 | |
4703 | |
4704 | class DashBaseTestCase(AutopilotTestCase): |
4705 | |
4706 | === modified file 'tests/mocks/CMakeLists.txt' |
4707 | --- tests/mocks/CMakeLists.txt 2015-08-06 22:45:56 +0000 |
4708 | +++ tests/mocks/CMakeLists.txt 2015-10-26 12:04:03 +0000 |
4709 | @@ -29,6 +29,7 @@ |
4710 | endmacro() |
4711 | |
4712 | add_subdirectory(AccountsService) |
4713 | +add_subdirectory(Cursor) |
4714 | add_subdirectory(GSettings.1.0) |
4715 | add_subdirectory(indicator-service) |
4716 | add_subdirectory(libusermetrics) |
4717 | |
4718 | === added directory 'tests/mocks/Cursor' |
4719 | === added file 'tests/mocks/Cursor/CMakeLists.txt' |
4720 | --- tests/mocks/Cursor/CMakeLists.txt 1970-01-01 00:00:00 +0000 |
4721 | +++ tests/mocks/Cursor/CMakeLists.txt 2015-10-26 12:04:03 +0000 |
4722 | @@ -0,0 +1,1 @@ |
4723 | +add_unity8_mock(Cursor 1.0 Cursor PREFIX mocks) |
4724 | |
4725 | === added file 'tests/mocks/Cursor/Cursor.qml' |
4726 | --- tests/mocks/Cursor/Cursor.qml 1970-01-01 00:00:00 +0000 |
4727 | +++ tests/mocks/Cursor/Cursor.qml 2015-10-26 12:04:03 +0000 |
4728 | @@ -0,0 +1,20 @@ |
4729 | +/* |
4730 | + * Copyright (C) 2015 Canonical, Ltd. |
4731 | + * |
4732 | + * This program is free software; you can redistribute it and/or modify |
4733 | + * it under the terms of the GNU General Public License as published by |
4734 | + * the Free Software Foundation; version 3. |
4735 | + * |
4736 | + * This program is distributed in the hope that it will be useful, |
4737 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
4738 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
4739 | + * GNU General Public License for more details. |
4740 | + * |
4741 | + * You should have received a copy of the GNU General Public License |
4742 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
4743 | + */ |
4744 | + |
4745 | +import QtQuick 2.4 |
4746 | + |
4747 | +Item { |
4748 | +} |
4749 | |
4750 | === added file 'tests/mocks/Cursor/qmldir' |
4751 | --- tests/mocks/Cursor/qmldir 1970-01-01 00:00:00 +0000 |
4752 | +++ tests/mocks/Cursor/qmldir 2015-10-26 12:04:03 +0000 |
4753 | @@ -0,0 +1,2 @@ |
4754 | +module Cursor |
4755 | +Cursor 1.0 Cursor.qml |
4756 | |
4757 | === modified file 'tests/mocks/Unity/Launcher/MockQuickListModel.cpp' |
4758 | --- tests/mocks/Unity/Launcher/MockQuickListModel.cpp 2013-08-19 15:10:58 +0000 |
4759 | +++ tests/mocks/Unity/Launcher/MockQuickListModel.cpp 2015-10-26 12:04:03 +0000 |
4760 | @@ -32,7 +32,7 @@ |
4761 | switch (role) |
4762 | { |
4763 | case RoleLabel: |
4764 | - return QLatin1String("test menu entry ") + QString::number(index.row()); |
4765 | + return QString(QLatin1String("test menu entry ") + QString::number(index.row())); |
4766 | case RoleIcon: |
4767 | return QLatin1String("copy.png"); |
4768 | case RoleClickable: |
4769 | |
4770 | === modified file 'tests/mocks/Unity/fake_resultsmodel.cpp' |
4771 | --- tests/mocks/Unity/fake_resultsmodel.cpp 2015-09-22 10:44:21 +0000 |
4772 | +++ tests/mocks/Unity/fake_resultsmodel.cpp 2015-10-26 12:04:03 +0000 |
4773 | @@ -78,7 +78,7 @@ |
4774 | case RoleTitle: |
4775 | return QString("Title.%1.%2").arg(m_categoryId).arg(index.row()); |
4776 | case RoleArt: |
4777 | - return qmlDirectory() + "/graphics/applicationIcons/dash.png"; |
4778 | + return QString(qmlDirectory() + "/graphics/applicationIcons/dash.png"); |
4779 | case RoleSubtitle: |
4780 | return QString("Subtitle.%1.%2").arg(m_categoryId).arg(index.row()); |
4781 | case RoleMascot: |
4782 | |
4783 | === modified file 'tests/mocks/Unity/fake_scopesoverview.cpp' |
4784 | --- tests/mocks/Unity/fake_scopesoverview.cpp 2015-09-22 10:44:21 +0000 |
4785 | +++ tests/mocks/Unity/fake_scopesoverview.cpp 2015-10-26 12:04:03 +0000 |
4786 | @@ -308,7 +308,7 @@ |
4787 | case RoleSubtitle: |
4788 | return scope && scope->name() == "Videos this is long ab cd ef gh ij kl" ? "tube, movies, cinema, pictures, art, moving images, magic in a box" : QString(); |
4789 | case RoleArt: |
4790 | - return qmlDirectory() + "/graphics/applicationIcons/dash.png"; |
4791 | + return QString(qmlDirectory() + "/graphics/applicationIcons/dash.png"); |
4792 | case RoleMascot: |
4793 | case RoleEmblem: |
4794 | case RoleSummary: |
4795 | |
4796 | === modified file 'tests/mocks/Utils/CMakeLists.txt' |
4797 | --- tests/mocks/Utils/CMakeLists.txt 2015-09-17 12:25:29 +0000 |
4798 | +++ tests/mocks/Utils/CMakeLists.txt 2015-10-26 12:04:03 +0000 |
4799 | @@ -13,8 +13,6 @@ |
4800 | ${CMAKE_SOURCE_DIR}/plugins/Utils/activefocuslogger.cpp |
4801 | ${CMAKE_SOURCE_DIR}/plugins/Utils/qlimitproxymodelqml.cpp |
4802 | ${CMAKE_SOURCE_DIR}/plugins/Utils/unitysortfilterproxymodelqml.cpp |
4803 | - ${CMAKE_SOURCE_DIR}/plugins/Utils/relativetimeformatter.cpp |
4804 | - ${CMAKE_SOURCE_DIR}/plugins/Utils/timeformatter.cpp |
4805 | ${CMAKE_SOURCE_DIR}/plugins/Utils/unitymenumodelpaths.cpp |
4806 | ${CMAKE_SOURCE_DIR}/plugins/Utils/windowkeysfilter.cpp |
4807 | ${CMAKE_SOURCE_DIR}/plugins/Utils/windowscreenshotprovider.cpp |
4808 | |
4809 | === modified file 'tests/mocks/Utils/Utils.qmltypes' |
4810 | --- tests/mocks/Utils/Utils.qmltypes 2015-03-04 13:04:58 +0000 |
4811 | +++ tests/mocks/Utils/Utils.qmltypes 2015-10-26 12:04:03 +0000 |
4812 | @@ -4,10 +4,19 @@ |
4813 | // It is used for QML tooling purposes only. |
4814 | // |
4815 | // This file was auto-generated by: |
4816 | -// 'qmlplugindump -notrelocatable Utils 0.1 plugins' |
4817 | +// 'qmlplugindump -notrelocatable Utils 0.1 tests/mocks' |
4818 | |
4819 | Module { |
4820 | Component { |
4821 | + name: "Constants" |
4822 | + prototype: "QObject" |
4823 | + exports: ["Utils/Constants 0.1"] |
4824 | + isCreatable: false |
4825 | + isSingleton: true |
4826 | + exportMetaObjectRevisions: [0] |
4827 | + Property { name: "indicatorValueTimeout"; type: "int"; isReadonly: true } |
4828 | + } |
4829 | + Component { |
4830 | name: "EasingCurve" |
4831 | prototype: "QObject" |
4832 | exports: ["Utils/EasingCurve 0.1"] |
4833 | @@ -18,6 +27,22 @@ |
4834 | Property { name: "value"; type: "double"; isReadonly: true } |
4835 | } |
4836 | Component { |
4837 | + name: "InputWatcher" |
4838 | + prototype: "QObject" |
4839 | + exports: ["Utils/InputWatcher 0.1"] |
4840 | + exportMetaObjectRevisions: [0] |
4841 | + Property { name: "target"; type: "QObject"; isPointer: true } |
4842 | + Property { name: "targetPressed"; type: "bool"; isReadonly: true } |
4843 | + Signal { |
4844 | + name: "targetChanged" |
4845 | + Parameter { name: "value"; type: "QObject"; isPointer: true } |
4846 | + } |
4847 | + Signal { |
4848 | + name: "targetPressedChanged" |
4849 | + Parameter { name: "value"; type: "bool" } |
4850 | + } |
4851 | + } |
4852 | + Component { |
4853 | name: "QAbstractProxyModel" |
4854 | prototype: "QAbstractItemModel" |
4855 | Property { name: "sourceModel"; type: "QAbstractItemModel"; isPointer: true } |
4856 | @@ -60,33 +85,6 @@ |
4857 | Method { name: "invalidate" } |
4858 | } |
4859 | Component { |
4860 | - name: "RelativeTimeFormatter" |
4861 | - prototype: "TimeFormatter" |
4862 | - exports: ["Utils/RelativeTimeFormatter 0.1"] |
4863 | - exportMetaObjectRevisions: [0] |
4864 | - } |
4865 | - Component { |
4866 | - name: "TimeFormatter" |
4867 | - prototype: "QObject" |
4868 | - exports: ["Utils/GDateTimeFormatter 0.1", "Utils/TimeFormatter 0.1"] |
4869 | - exportMetaObjectRevisions: [0, 0] |
4870 | - Property { name: "format"; type: "string" } |
4871 | - Property { name: "timeString"; type: "string"; isReadonly: true } |
4872 | - Property { name: "time"; type: "qlonglong" } |
4873 | - Signal { |
4874 | - name: "formatChanged" |
4875 | - Parameter { name: "format"; type: "string" } |
4876 | - } |
4877 | - Signal { |
4878 | - name: "timeStringChanged" |
4879 | - Parameter { name: "timeString"; type: "string" } |
4880 | - } |
4881 | - Signal { |
4882 | - name: "timeChanged" |
4883 | - Parameter { name: "time"; type: "qlonglong" } |
4884 | - } |
4885 | - } |
4886 | - Component { |
4887 | name: "UnityMenuModelPaths" |
4888 | prototype: "QObject" |
4889 | exports: ["Utils/UnityMenuModelPaths 0.1"] |
4890 | @@ -160,6 +158,11 @@ |
4891 | isCreatable: false |
4892 | isSingleton: true |
4893 | exportMetaObjectRevisions: [0] |
4894 | + Property { name: "geometry"; type: "QVariantMap" } |
4895 | + Signal { |
4896 | + name: "geometryChanged" |
4897 | + Parameter { name: "geometry"; type: "QVariantMap" } |
4898 | + } |
4899 | Method { |
4900 | name: "saveGeometry" |
4901 | Parameter { name: "windowId"; type: "string" } |
4902 | |
4903 | === modified file 'tests/mocks/Utils/plugin.cpp' |
4904 | --- tests/mocks/Utils/plugin.cpp 2015-09-17 12:25:29 +0000 |
4905 | +++ tests/mocks/Utils/plugin.cpp 2015-10-26 12:04:03 +0000 |
4906 | @@ -23,14 +23,6 @@ |
4907 | |
4908 | // local |
4909 | #include "plugin.h" |
4910 | -#include "inputwatcher.h" |
4911 | -#include "qlimitproxymodelqml.h" |
4912 | -#include "unitysortfilterproxymodelqml.h" |
4913 | -#include "relativetimeformatter.h" |
4914 | -#include "timeformatter.h" |
4915 | -#include "unitymenumodelpaths.h" |
4916 | -#include "windowkeysfilter.h" |
4917 | -#include "easingcurve.h" |
4918 | #include "windowstatestorage.h" |
4919 | #include "constants.h" |
4920 | |
4921 | @@ -39,8 +31,6 @@ |
4922 | #include <inputwatcher.h> |
4923 | #include <qlimitproxymodelqml.h> |
4924 | #include <unitysortfilterproxymodelqml.h> |
4925 | -#include <relativetimeformatter.h> |
4926 | -#include <timeformatter.h> |
4927 | #include <unitymenumodelpaths.h> |
4928 | #include <windowkeysfilter.h> |
4929 | #include <windowscreenshotprovider.h> |
4930 | @@ -67,11 +57,8 @@ |
4931 | qmlRegisterType<QLimitProxyModelQML>(uri, 0, 1, "LimitProxyModel"); |
4932 | qmlRegisterType<UnitySortFilterProxyModelQML>(uri, 0, 1, "UnitySortFilterProxyModel"); |
4933 | qmlRegisterType<UnityMenuModelPaths>(uri, 0, 1, "UnityMenuModelPaths"); |
4934 | - qmlRegisterType<TimeFormatter>(uri, 0, 1, "TimeFormatter"); |
4935 | qmlRegisterType<WindowKeysFilter>(uri, 0, 1, "WindowKeysFilter"); |
4936 | - qmlRegisterType<GDateTimeFormatter>(uri, 0, 1, "GDateTimeFormatter"); |
4937 | qmlRegisterType<EasingCurve>(uri, 0, 1, "EasingCurve"); |
4938 | - qmlRegisterType<RelativeTimeFormatter>(uri, 0, 1, "RelativeTimeFormatter"); |
4939 | qmlRegisterSingletonType<WindowStateStorage>(uri, 0, 1, "WindowStateStorage", createWindowStateStorage); |
4940 | qmlRegisterType<InputWatcher>(uri, 0, 1, "InputWatcher"); |
4941 | qmlRegisterSingletonType<Constants>(uri, 0, 1, "Constants", createConstants); |
4942 | |
4943 | === modified file 'tests/plugins/ScreenGrabber/ScreenGrabberTest.cpp' |
4944 | --- tests/plugins/ScreenGrabber/ScreenGrabberTest.cpp 2015-07-20 15:06:46 +0000 |
4945 | +++ tests/plugins/ScreenGrabber/ScreenGrabberTest.cpp 2015-10-26 12:04:03 +0000 |
4946 | @@ -55,6 +55,17 @@ |
4947 | QVERIFY(!args.first().toString().isEmpty()); |
4948 | } |
4949 | |
4950 | + void testRotatedScreenshot() |
4951 | + { |
4952 | + QSignalSpy grabberSpy(m_grabber, &ScreenGrabber::screenshotSaved); |
4953 | + m_grabber->captureAndSave(90); // rotate by 90° |
4954 | + const QVariantList args = grabberSpy.takeFirst(); |
4955 | + const QString filename = args.first().toString(); |
4956 | + QVERIFY(!filename.isEmpty()); |
4957 | + QImage img(filename); |
4958 | + QVERIFY(img.height() > img.width()); // verify that the image got rotated by 90° (height > width) |
4959 | + } |
4960 | + |
4961 | private: |
4962 | QQuickView *m_view; |
4963 | ScreenGrabber *m_grabber = nullptr; |
4964 | |
4965 | === modified file 'tests/plugins/ScreenGrabber/grabber.qml' |
4966 | --- tests/plugins/ScreenGrabber/grabber.qml 2015-07-17 19:59:31 +0000 |
4967 | +++ tests/plugins/ScreenGrabber/grabber.qml 2015-10-26 12:04:03 +0000 |
4968 | @@ -20,7 +20,7 @@ |
4969 | Rectangle { |
4970 | property var grabber: screenGrabber |
4971 | |
4972 | - width: 100 |
4973 | + width: 101 // width intentionally bigger than height to test rotation |
4974 | height: 100 |
4975 | color: "green" |
4976 | |
4977 | |
4978 | === modified file 'tests/plugins/Unity/Indicators/UnityMenuModelStackTest.cpp' |
4979 | --- tests/plugins/Unity/Indicators/UnityMenuModelStackTest.cpp 2015-08-19 13:56:21 +0000 |
4980 | +++ tests/plugins/Unity/Indicators/UnityMenuModelStackTest.cpp 2015-10-26 12:04:03 +0000 |
4981 | @@ -43,6 +43,8 @@ |
4982 | { |
4983 | delete m_model; |
4984 | m_model = nullptr; |
4985 | + // send deleteLaters to avoid leaks. |
4986 | + QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); |
4987 | } |
4988 | |
4989 | void testHeadOnSetHead() |
4990 | @@ -146,19 +148,10 @@ |
4991 | |
4992 | m_model->removeRow(removeIndex); |
4993 | |
4994 | - waitFor([&stack, resultCount]() { return stack.count() == resultCount; }, 1000); |
4995 | QCOMPARE(stack.count(), resultCount); |
4996 | } |
4997 | |
4998 | private: |
4999 | - bool waitFor(std::function<bool()> functor, int ms) { |
5000 | - |
* Did you perform an exploratory manual test run of the code change and any related functionality?
No, it's just copyright addition
* Did CI run pass? If not, please explain why.
Doesn't matter since it's just copyright addition
* Did you make sure that the branch does not contain spurious tags?
Yes