on xenial help sign in
Merge lp:~mterry/unity8/no-touch-no-lifecycle
c3bcab3Michał Sawicz
CMakeLists.txt+4−1
@@ -57,7 +57,7 @@ find_package(Qt5DBus 5.2 REQUIRED)
57find_package(Qt5Concurrent 5.2 REQUIRED)
57find_package(Qt5Concurrent 5.2 REQUIRED)
58find_package(Qt5Sql 5.2 REQUIRED)
58find_package(Qt5Sql 5.2 REQUIRED)
59
59
60−pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application>=8)
60+pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=9)
61
61
62# Standard install paths
62# Standard install paths
63include(GNUInstallDirs)
63include(GNUInstallDirs)
@@ -101,6 +101,9 @@ add_definitions(-DQT_NO_KEYWORDS)
101# Save a few container detach and conversions
101# Save a few container detach and conversions
102add_definitions(-DQT_STRICT_ITERATORS)
102add_definitions(-DQT_STRICT_ITERATORS)
103
103
104+# Use the fast string builder
105+add_definitions(-DQT_USE_QSTRINGBUILDER)
106+
104# Autopilot tests
107# Autopilot tests
105include(autopilot)
108include(autopilot)
106declare_autopilot_test(shell unity8.shell ${CMAKE_SOURCE_DIR}/tests/autopilot/)
109declare_autopilot_test(shell unity8.shell ${CMAKE_SOURCE_DIR}/tests/autopilot/)
data/CMakeLists.txt+3
@@ -11,5 +11,8 @@ install(FILES
11 DESTINATION ${CMAKE_INSTALL_DATADIR}/applications
11 DESTINATION ${CMAKE_INSTALL_DATADIR}/applications
12 )
12 )
13
13
14+add_custom_target(pkgversion ALL COMMAND dpkg-parsechangelog -l${CMAKE_SOURCE_DIR}/debian/changelog --show-field version > ${CMAKE_CURRENT_BINARY_DIR}/version)
15+
14install(FILES com.canonical.Unity8.gschema.xml DESTINATION ${CMAKE_INSTALL_DATADIR}/glib-2.0/schemas)
16install(FILES com.canonical.Unity8.gschema.xml DESTINATION ${CMAKE_INSTALL_DATADIR}/glib-2.0/schemas)
15install(FILES unity8-dash.url-dispatcher DESTINATION ${CMAKE_INSTALL_DATADIR}/url-dispatcher/urls)
17install(FILES unity8-dash.url-dispatcher DESTINATION ${CMAKE_INSTALL_DATADIR}/url-dispatcher/urls)
18+install(FILES ${CMAKE_CURRENT_BINARY_DIR}/version DESTINATION ${CMAKE_INSTALL_LOCALSTATEDIR}/lib/unity8)
data/unity8.conf+10
@@ -46,6 +46,16 @@ pre-start script
46 initctl set-env --global MIR_SERVER_PROMPT_FILE=1
46 initctl set-env --global MIR_SERVER_PROMPT_FILE=1
47
47
48 initctl emit --no-wait indicator-services-start
48 initctl emit --no-wait indicator-services-start
49+
50+ # Disable Qt's stuttering 'touch compression' to fix scrolling smoothness
51+ # issues (LP: #1486341). As a bonus, this eliminates most of the
52+ # lag seen in the indicator panel pull-down (LP: #1488327) and also
53+ # reduces lag seen in apps:
54+ initctl set-env --global QML_NO_TOUCH_COMPRESSION=1
55+
56+ # For twice the fun and half the latency, try this (Warning: not all
57+ # devices are fast enough to keep up smoothly yet)...
58+ # initctl set-env MIR_SERVER_NBUFFERS=2
49end script
59end script
50
60
51exec ${BINARY:-unity8} $ARGS
61exec ${BINARY:-unity8} $ARGS
debian/changelog+55
@@ -1,3 +1,58 @@
1+unity8 (8.11+15.10.20151021-0ubuntu1) wily; urgency=medium
2+
3+ [ Albert Astals Cid ]
4+ * Clazy fixes
5+ * Enable Efficient String Construction by default
6+
7+ [ CI Train Bot ]
8+ * New rebuild forced.
9+
10+ [ Daniel d'Andrada ]
11+ * Have unity8 drawing its own cursor (LP: #1488417)
12+ * Initial multi-monitor support
13+
14+ [ Daniel van Vugt ]
15+ * Disable Qt's stuttering 'touch compression' to fix scrolling
16+ smoothness (LP: #1486341, #1488327)
17+
18+ [ Lukáš Tinkl ]
19+ * Fix autopilot wizard test skipping the reporting page
20+ * Implement Unity.Platform plugin wrapping org.freedesktop.hostname1
21+ (LP: #1504318)
22+ * React to window title (aka surface name) changes (LP: #1497092)
23+ * Rotate the screenshots according to the actual orientation
24+
25+ [ Michał Sawicz ]
26+ * Fix application API dependency
27+ * Have unity8 drawing its own cursor (LP: #1488417)
28+ * Initial multi-monitor support
29+ * Rotate the screenshots according to the actual orientation
30+
31+ [ Nick Dedekind ]
32+ * Fixed leak in UnityMenuModelStackTest
33+ * Moved time translation to SDK (LP: #1372061)
34+
35+ -- Michał Sawicz <michal.sawicz@canonical.com> Wed, 21 Oct 2015 11:51:53 +0000
36+
37+unity8 (8.11+15.10.20151009-0ubuntu1) wily; urgency=medium
38+
39+ [ CI Train Bot ]
40+ * New rebuild forced.
41+
42+ [ Pawel Stolowski ]
43+ * Store unity8 package version in /var/lib/.../version file for fast
44+ retrieval from the shell plugin.
45+
46+ -- Pawel Stolowski <ci-train-bot@canonical.com> Fri, 09 Oct 2015 09:13:03 +0000
47+
48+unity8 (8.11+15.10.20151008-0ubuntu1) wily; urgency=medium
49+
50+ [ Lukáš Tinkl ]
51+ * Revert to using plaintext instead of HTML-like markup for the
52+ notifications (LP: #1504256)
53+
54+ -- Michał Sawicz <michal.sawicz@canonical.com> Thu, 08 Oct 2015 20:46:26 +0000
55+
1unity8 (8.11+15.10.20151002-0ubuntu1) wily; urgency=medium
56unity8 (8.11+15.10.20151002-0ubuntu1) wily; urgency=medium
2
57
3 [ CI Train Bot ]
58 [ CI Train Bot ]
debian/control+8−6
@@ -25,6 +25,7 @@ Build-Depends: cmake,
25 libpay2-dev,
25 libpay2-dev,
26 libpulse-dev,
26 libpulse-dev,
27 libqmenumodel-dev (>= 0.2.9),
27 libqmenumodel-dev (>= 0.2.9),
28+ libqt5svg5-dev,
28 libqt5xmlpatterns5-dev,
29 libqt5xmlpatterns5-dev,
29 libsystemsettings-dev,
30 libsystemsettings-dev,
30 libudev-dev,
31 libudev-dev,
@@ -49,7 +50,7 @@ Build-Depends: cmake,
49 qtdeclarative5-private-dev (>= 5.2.1),
50 qtdeclarative5-private-dev (>= 5.2.1),
50 qtdeclarative5-qtmultimedia-plugin,
51 qtdeclarative5-qtmultimedia-plugin,
51 qtdeclarative5-ubuntu-settings-components (>= 0.6),
52 qtdeclarative5-ubuntu-settings-components (>= 0.6),
52− qtdeclarative5-ubuntu-ui-toolkit-plugin (>= 1.1.1239) | qtdeclarative5-ubuntu-ui-toolkit-plugin-gles (>= 1.1.1239),
53+ qtdeclarative5-ubuntu-ui-toolkit-plugin (>= 1.3.1627) | qtdeclarative5-ubuntu-ui-toolkit-plugin-gles (>= 1.3.1627),
53 qtdeclarative5-ubuntu-web-plugin,
54 qtdeclarative5-ubuntu-web-plugin,
54 ttf-ubuntu-font-family,
55 ttf-ubuntu-font-family,
55Standards-Version: 3.9.4
56Standards-Version: 3.9.4
@@ -64,7 +65,7 @@ X-Ubuntu-Use-Langpack: yes
64Package: indicators-client
65Package: indicators-client
65Architecture: amd64 armhf i386
66Architecture: amd64 armhf i386
66Depends: qmenumodel-qml (>= 0.2.9),
67Depends: qmenumodel-qml (>= 0.2.9),
67− qtdeclarative5-ubuntu-ui-toolkit-plugin (>= 1.1.1239) | qtdeclarative5-ubuntu-ui-toolkit-plugin-gles (>= 1.1.1239),
68+ qtdeclarative5-ubuntu-ui-toolkit-plugin (>= 1.3.1627) | qtdeclarative5-ubuntu-ui-toolkit-plugin-gles (>= 1.3.1627),
68 unity8 (= ${binary:Version}),
69 unity8 (= ${binary:Version}),
69 ${misc:Depends},
70 ${misc:Depends},
70 ${shlibs:Depends},
71 ${shlibs:Depends},
@@ -87,7 +88,8 @@ Description: Development tool for Unity scopes
87Package: unity8
88Package: unity8
88Architecture: any
89Architecture: any
89Provides: indicator-renderer,
90Provides: indicator-renderer,
91+Depends: dmz-cursor-theme,
90−Depends: gsettings-desktop-schemas,
92+ gsettings-desktop-schemas,
91 libcap2-bin,
93 libcap2-bin,
92 libglib2.0-bin,
94 libglib2.0-bin,
93 qmenumodel-qml (>= 0.2.9),
95 qmenumodel-qml (>= 0.2.9),
@@ -122,10 +124,10 @@ Architecture: all
122Depends: qml-module-qtquick-layouts,
124Depends: qml-module-qtquick-layouts,
123 qtdeclarative5-ubuntu-settings-components (>= 0.6),
125 qtdeclarative5-ubuntu-settings-components (>= 0.6),
124 qtdeclarative5-ubuntu-thumbnailer0.1 | ubuntu-thumbnailer-impl,
126 qtdeclarative5-ubuntu-thumbnailer0.1 | ubuntu-thumbnailer-impl,
125− qtdeclarative5-ubuntu-ui-toolkit-plugin (>= 1.1.1239) | qtdeclarative5-ubuntu-ui-toolkit-plugin-gles (>= 1.1.1239),
127+ qtdeclarative5-ubuntu-ui-toolkit-plugin (>= 1.3.1627) | qtdeclarative5-ubuntu-ui-toolkit-plugin-gles (>= 1.3.1627),
126 qtdeclarative5-unity-notifications-plugin (>= 0.1.2) | unity-notifications-impl,
128 qtdeclarative5-unity-notifications-plugin (>= 0.1.2) | unity-notifications-impl,
127 ubuntu-thumbnailer-impl-0,
129 ubuntu-thumbnailer-impl-0,
128− unity-application-impl-8,
130+ unity-application-impl-9,
129 unity-notifications-impl-3,
131 unity-notifications-impl-3,
130 unity-plugin-scopes | unity-scopes-impl,
132 unity-plugin-scopes | unity-scopes-impl,
131 unity-scopes-impl-7,
133 unity-scopes-impl-7,
@@ -171,7 +173,7 @@ Pre-Depends: ${misc:Pre-Depends},
171Depends: ${misc:Depends},
173Depends: ${misc:Depends},
172 ${shlibs:Depends},
174 ${shlibs:Depends},
173Provides: unity-application-impl,
175Provides: unity-application-impl,
174− unity-application-impl-8,
176+ unity-application-impl-9,
175Replaces: unity8-autopilot (<< 8.02+15.04.20150422-0ubuntu1)
177Replaces: unity8-autopilot (<< 8.02+15.04.20150422-0ubuntu1)
176Description: Fake environment for running Unity 8 shell
178Description: Fake environment for running Unity 8 shell
177 Provides fake implementations of some QML modules used by Unity 8 shell
179 Provides fake implementations of some QML modules used by Unity 8 shell
debian/copyright+21
@@ -60,3 +60,24 @@ License: LGPL-2.1 with Digia Qt LGPL Exception 1.1 or GPL-3
60 packaging of this file. Please review the following information to
60 packaging of this file. Please review the following information to
61 ensure the GNU General Public License version 3.0 requirements will be
61 ensure the GNU General Public License version 3.0 requirements will be
62 met: http://www.gnu.org/copyleft/gpl.html.
62 met: http://www.gnu.org/copyleft/gpl.html.
63+
64+Files: plugins/Cursor/3rd_party/xcursor/xcursor.*
65+Copyright: 2002 Keith Packard
66+License: Keith Packard
67+ Permission to use, copy, modify, distribute, and sell this software and its
68+ documentation for any purpose is hereby granted without fee, provided that
69+ the above copyright notice appear in all copies and that both that
70+ copyright notice and this permission notice appear in supporting
71+ documentation, and that the name of Keith Packard not be used in
72+ advertising or publicity pertaining to distribution of the software without
73+ specific, written prior permission. Keith Packard makes no
74+ representations about the suitability of this software for any purpose. It
75+ is provided "as is" without express or implied warranty.
76+ .
77+ KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
78+ INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
79+ EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
80+ CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
81+ DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
82+ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
83+ PERFORMANCE OF THIS SOFTWARE.
debian/unity8-private.install+1
@@ -1,6 +1,7 @@
1usr/lib/*/libunity8-private.*
1usr/lib/*/libunity8-private.*
2usr/lib/*/unity8/libUbuntuGestures*
2usr/lib/*/unity8/libUbuntuGestures*
3usr/lib/*/unity8/qml/AccountsService
3usr/lib/*/unity8/qml/AccountsService
4+usr/lib/*/unity8/qml/Cursor
4usr/lib/*/unity8/qml/Dash
5usr/lib/*/unity8/qml/Dash
5usr/lib/*/unity8/qml/GlobalShortcut
6usr/lib/*/unity8/qml/GlobalShortcut
6usr/lib/*/unity8/qml/Greeter
7usr/lib/*/unity8/qml/Greeter
debian/unity8.install+2
@@ -1,3 +1,4 @@
1+var/lib/unity8/version
1data/unity8-dash.conf usr/share/upstart/sessions/
2data/unity8-dash.conf usr/share/upstart/sessions/
2data/unity8-filewatcher.conf usr/share/upstart/sessions/
3data/unity8-filewatcher.conf usr/share/upstart/sessions/
3data/unity8.conf usr/share/upstart/sessions/
4data/unity8.conf usr/share/upstart/sessions/
@@ -11,6 +12,7 @@ usr/share/unity8/Panel
11usr/share/unity8/Rotation
12usr/share/unity8/Rotation
12usr/share/unity8/DeviceConfiguration.qml
13usr/share/unity8/DeviceConfiguration.qml
13usr/share/unity8/OrientedShell.qml
14usr/share/unity8/OrientedShell.qml
15+usr/share/unity8/DisabledScreenNotice.qml
14usr/share/unity8/Shell.qml
16usr/share/unity8/Shell.qml
15usr/share/unity8/Stages
17usr/share/unity8/Stages
16usr/share/unity8/Tutorial
18usr/share/unity8/Tutorial
plugins/CMakeLists.txt+1
@@ -12,6 +12,7 @@ macro(add_unity8_plugin PLUGIN VERSION PATH)
12endmacro()
12endmacro()
13
13
14add_subdirectory(AccountsService)
14add_subdirectory(AccountsService)
15+add_subdirectory(Cursor)
15add_subdirectory(GlobalShortcut)
16add_subdirectory(GlobalShortcut)
16add_subdirectory(Greeter)
17add_subdirectory(Greeter)
17add_subdirectory(IntegratedLightDM)
18add_subdirectory(IntegratedLightDM)
plugins/Cursor/3rd_party/CMakeLists.txtnew file+1
@@ -0,0 +1 @@
1+add_subdirectory(xcursor)
plugins/Cursor/3rd_party/xcursor/CMakeLists.txtnew file+15
@@ -0,0 +1,15 @@
1+add_definitions(-D_DEFAULT_SOURCE=1)
2+
3+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC")
4+
5+set(
6+ XCURSOR_SOURCES
7+
8+ xcursor.c
9+)
10+
11+add_library(
12+ xcursorloader-static STATIC
13+
14+ ${XCURSOR_SOURCES}
15+)
plugins/Cursor/3rd_party/xcursor/xcursor.cnew file+968
@@ -0,0 +1,968 @@
1+/*
2+ * Copyright © 2002 Keith Packard
3+ *
4+ * Permission to use, copy, modify, distribute, and sell this software and its
5+ * documentation for any purpose is hereby granted without fee, provided that
6+ * the above copyright notice appear in all copies and that both that
7+ * copyright notice and this permission notice appear in supporting
8+ * documentation, and that the name of Keith Packard not be used in
9+ * advertising or publicity pertaining to distribution of the software without
10+ * specific, written prior permission. Keith Packard makes no
11+ * representations about the suitability of this software for any purpose. It
12+ * is provided "as is" without express or implied warranty.
13+ *
14+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
20+ * PERFORMANCE OF THIS SOFTWARE.
21+ */
22+
23+#include "xcursor.h"
24+#include <stdio.h>
25+#include <stdlib.h>
26+#include <string.h>
27+#include <dirent.h>
28+
29+/*
30+ * From libXcursor/include/X11/extensions/Xcursor.h
31+ */
32+
33+#define XcursorTrue 1
34+#define XcursorFalse 0
35+
36+/*
37+ * Cursor files start with a header. The header
38+ * contains a magic number, a version number and a
39+ * table of contents which has type and offset information
40+ * for the remaining tables in the file.
41+ *
42+ * File minor versions increment for compatible changes
43+ * File major versions increment for incompatible changes (never, we hope)
44+ *
45+ * Chunks of the same type are always upward compatible. Incompatible
46+ * changes are made with new chunk types; the old data can remain under
47+ * the old type. Upward compatible changes can add header data as the
48+ * header lengths are specified in the file.
49+ *
50+ * File:
51+ * FileHeader
52+ * LISTofChunk
53+ *
54+ * FileHeader:
55+ * CARD32 magic magic number
56+ * CARD32 header bytes in file header
57+ * CARD32 version file version
58+ * CARD32 ntoc number of toc entries
59+ * LISTofFileToc toc table of contents
60+ *
61+ * FileToc:
62+ * CARD32 type entry type
63+ * CARD32 subtype entry subtype (size for images)
64+ * CARD32 position absolute file position
65+ */
66+
67+#define XCURSOR_MAGIC 0x72756358 /* "Xcur" LSBFirst */
68+
69+/*
70+ * Current Xcursor version number. Will be substituted by configure
71+ * from the version in the libXcursor configure.ac file.
72+ */
73+
74+#define XCURSOR_LIB_MAJOR 1
75+#define XCURSOR_LIB_MINOR 1
76+#define XCURSOR_LIB_REVISION 13
77+#define XCURSOR_LIB_VERSION ((XCURSOR_LIB_MAJOR * 10000) + \
78+ (XCURSOR_LIB_MINOR * 100) + \
79+ (XCURSOR_LIB_REVISION))
80+
81+/*
82+ * This version number is stored in cursor files; changes to the
83+ * file format require updating this version number
84+ */
85+#define XCURSOR_FILE_MAJOR 1
86+#define XCURSOR_FILE_MINOR 0
87+#define XCURSOR_FILE_VERSION ((XCURSOR_FILE_MAJOR << 16) | (XCURSOR_FILE_MINOR))
88+#define XCURSOR_FILE_HEADER_LEN (4 * 4)
89+#define XCURSOR_FILE_TOC_LEN (3 * 4)
90+
91+typedef struct _XcursorFileToc {
92+ XcursorUInt type; /* chunk type */
93+ XcursorUInt subtype; /* subtype (size for images) */
94+ XcursorUInt position; /* absolute position in file */
95+} XcursorFileToc;
96+
97+typedef struct _XcursorFileHeader {
98+ XcursorUInt magic; /* magic number */
99+ XcursorUInt header; /* byte length of header */
100+ XcursorUInt version; /* file version number */
101+ XcursorUInt ntoc; /* number of toc entries */
102+ XcursorFileToc *tocs; /* table of contents */
103+} XcursorFileHeader;
104+
105+/*
106+ * The rest of the file is a list of chunks, each tagged by type
107+ * and version.
108+ *
109+ * Chunk:
110+ * ChunkHeader
111+ * <extra type-specific header fields>
112+ * <type-specific data>
113+ *
114+ * ChunkHeader:
115+ * CARD32 header bytes in chunk header + type header
116+ * CARD32 type chunk type
117+ * CARD32 subtype chunk subtype
118+ * CARD32 version chunk type version
119+ */
120+
121+#define XCURSOR_CHUNK_HEADER_LEN (4 * 4)
122+
123+typedef struct _XcursorChunkHeader {
124+ XcursorUInt header; /* bytes in chunk header */
125+ XcursorUInt type; /* chunk type */
126+ XcursorUInt subtype; /* chunk subtype (size for images) */
127+ XcursorUInt version; /* version of this type */
128+} XcursorChunkHeader;
129+
130+/*
131+ * Here's a list of the known chunk types
132+ */
133+
134+/*
135+ * Comments consist of a 4-byte length field followed by
136+ * UTF-8 encoded text
137+ *
138+ * Comment:
139+ * ChunkHeader header chunk header
140+ * CARD32 length bytes in text
141+ * LISTofCARD8 text UTF-8 encoded text
142+ */
143+
144+#define XCURSOR_COMMENT_TYPE 0xfffe0001
145+#define XCURSOR_COMMENT_VERSION 1
146+#define XCURSOR_COMMENT_HEADER_LEN (XCURSOR_CHUNK_HEADER_LEN + (1 *4))
147+#define XCURSOR_COMMENT_COPYRIGHT 1
148+#define XCURSOR_COMMENT_LICENSE 2
149+#define XCURSOR_COMMENT_OTHER 3
150+#define XCURSOR_COMMENT_MAX_LEN 0x100000
151+
152+typedef struct _XcursorComment {
153+ XcursorUInt version;
154+ XcursorUInt comment_type;
155+ char *comment;
156+} XcursorComment;
157+
158+/*
159+ * Each cursor image occupies a separate image chunk.
160+ * The length of the image header follows the chunk header
161+ * so that future versions can extend the header without
162+ * breaking older applications
163+ *
164+ * Image:
165+ * ChunkHeader header chunk header
166+ * CARD32 width actual width
167+ * CARD32 height actual height
168+ * CARD32 xhot hot spot x
169+ * CARD32 yhot hot spot y
170+ * CARD32 delay animation delay
171+ * LISTofCARD32 pixels ARGB pixels
172+ */
173+
174+#define XCURSOR_IMAGE_TYPE 0xfffd0002
175+#define XCURSOR_IMAGE_VERSION 1
176+#define XCURSOR_IMAGE_HEADER_LEN (XCURSOR_CHUNK_HEADER_LEN + (5*4))
177+#define XCURSOR_IMAGE_MAX_SIZE 0x7fff /* 32767x32767 max cursor size */
178+
179+typedef struct _XcursorFile XcursorFile;
180+
181+struct _XcursorFile {
182+ void *closure;
183+ int (*read) (XcursorFile *file, unsigned char *buf, int len);
184+ int (*write) (XcursorFile *file, unsigned char *buf, int len);
185+ int (*seek) (XcursorFile *file, long offset, int whence);
186+};
187+
188+typedef struct _XcursorComments {
189+ int ncomment; /* number of comments */
190+ XcursorComment **comments; /* array of XcursorComment pointers */
191+} XcursorComments;
192+
193+/*
194+ * From libXcursor/src/file.c
195+ */
196+
197+static XcursorImage *
198+XcursorImageCreate (int width, int height)
199+{
200+ XcursorImage *image;
201+
202+ image = malloc (sizeof (XcursorImage) +
203+ width * height * sizeof (XcursorPixel));
204+ if (!image)
205+ return NULL;
206+ image->version = XCURSOR_IMAGE_VERSION;
207+ image->pixels = (XcursorPixel *) (image + 1);
208+ image->size = width > height ? width : height;
209+ image->width = width;
210+ image->height = height;
211+ image->delay = 0;
212+ return image;
213+}
214+
215+static void
216+XcursorImageDestroy (XcursorImage *image)
217+{
218+ free (image);
219+}
220+
221+static XcursorImages *
222+XcursorImagesCreate (int size)
223+{
224+ XcursorImages *images;
225+
226+ images = malloc (sizeof (XcursorImages) +
227+ size * sizeof (XcursorImage *));
228+ if (!images)
229+ return NULL;
230+ images->nimage = 0;
231+ images->images = (XcursorImage **) (images + 1);
232+ images->name = NULL;
233+ return images;
234+}
235+
236+void
237+XcursorImagesDestroy (XcursorImages *images)
238+{
239+ int n;
240+
241+ if (!images)
242+ return;
243+
244+ for (n = 0; n < images->nimage; n++)
245+ XcursorImageDestroy (images->images[n]);
246+ if (images->name)
247+ free (images->name);
248+ free (images);
249+}
250+
251+static void
252+XcursorImagesSetName (XcursorImages *images, const char *name)
253+{
254+ char *new;
255+
256+ if (!images || !name)
257+ return;
258+
259+ new = malloc (strlen (name) + 1);
260+
261+ if (!new)
262+ return;
263+
264+ strcpy (new, name);
265+ if (images->name)
266+ free (images->name);
267+ images->name = new;
268+}
269+
270+static XcursorBool
271+_XcursorReadUInt (XcursorFile *file, XcursorUInt *u)
272+{
273+ unsigned char bytes[4];
274+
275+ if (!file || !u)
276+ return XcursorFalse;
277+
278+ if ((*file->read) (file, bytes, 4) != 4)
279+ return XcursorFalse;
280+ *u = ((bytes[0] << 0) |
281+ (bytes[1] << 8) |
282+ (bytes[2] << 16) |
283+ (bytes[3] << 24));
284+ return XcursorTrue;
285+}
286+
287+static void
288+_XcursorFileHeaderDestroy (XcursorFileHeader *fileHeader)
289+{
290+ free (fileHeader);
291+}
292+
293+static XcursorFileHeader *
294+_XcursorFileHeaderCreate (int ntoc)
295+{
296+ XcursorFileHeader *fileHeader;
297+
298+ if (ntoc > 0x10000)
299+ return NULL;
300+ fileHeader = malloc (sizeof (XcursorFileHeader) +
301+ ntoc * sizeof (XcursorFileToc));
302+ if (!fileHeader)
303+ return NULL;
304+ fileHeader->magic = XCURSOR_MAGIC;
305+ fileHeader->header = XCURSOR_FILE_HEADER_LEN;
306+ fileHeader->version = XCURSOR_FILE_VERSION;
307+ fileHeader->ntoc = ntoc;
308+ fileHeader->tocs = (XcursorFileToc *) (fileHeader + 1);
309+ return fileHeader;
310+}
311+
312+static XcursorFileHeader *
313+_XcursorReadFileHeader (XcursorFile *file)
314+{
315+ XcursorFileHeader head, *fileHeader;
316+ XcursorUInt skip;
317+ unsigned int n;
318+
319+ if (!file)
320+ return NULL;
321+
322+ if (!_XcursorReadUInt (file, &head.magic))
323+ return NULL;
324+ if (head.magic != XCURSOR_MAGIC)
325+ return NULL;
326+ if (!_XcursorReadUInt (file, &head.header))
327+ return NULL;
328+ if (!_XcursorReadUInt (file, &head.version))
329+ return NULL;
330+ if (!_XcursorReadUInt (file, &head.ntoc))
331+ return NULL;
332+ skip = head.header - XCURSOR_FILE_HEADER_LEN;
333+ if (skip)
334+ if ((*file->seek) (file, skip, SEEK_CUR) == EOF)
335+ return NULL;
336+ fileHeader = _XcursorFileHeaderCreate (head.ntoc);
337+ if (!fileHeader)
338+ return NULL;
339+ fileHeader->magic = head.magic;
340+ fileHeader->header = head.header;
341+ fileHeader->version = head.version;
342+ fileHeader->ntoc = head.ntoc;
343+ for (n = 0; n < fileHeader->ntoc; n++)
344+ {
345+ if (!_XcursorReadUInt (file, &fileHeader->tocs[n].type))
346+ break;
347+ if (!_XcursorReadUInt (file, &fileHeader->tocs[n].subtype))
348+ break;
349+ if (!_XcursorReadUInt (file, &fileHeader->tocs[n].position))
350+ break;
351+ }
352+ if (n != fileHeader->ntoc)
353+ {
354+ _XcursorFileHeaderDestroy (fileHeader);
355+ return NULL;
356+ }
357+ return fileHeader;
358+}
359+
360+static XcursorBool
361+_XcursorSeekToToc (XcursorFile *file,
362+ XcursorFileHeader *fileHeader,
363+ int toc)
364+{
365+ if (!file || !fileHeader || \
366+ (*file->seek) (file, fileHeader->tocs[toc].position, SEEK_SET) == EOF)
367+ return XcursorFalse;
368+ return XcursorTrue;
369+}
370+
371+static XcursorBool
372+_XcursorFileReadChunkHeader (XcursorFile *file,
373+ XcursorFileHeader *fileHeader,
374+ int toc,
375+ XcursorChunkHeader *chunkHeader)
376+{
377+ if (!file || !fileHeader || !chunkHeader)
378+ return XcursorFalse;
379+ if (!_XcursorSeekToToc (file, fileHeader, toc))
380+ return XcursorFalse;
381+ if (!_XcursorReadUInt (file, &chunkHeader->header))
382+ return XcursorFalse;
383+ if (!_XcursorReadUInt (file, &chunkHeader->type))
384+ return XcursorFalse;
385+ if (!_XcursorReadUInt (file, &chunkHeader->subtype))
386+ return XcursorFalse;
387+ if (!_XcursorReadUInt (file, &chunkHeader->version))
388+ return XcursorFalse;
389+ /* sanity check */
390+ if (chunkHeader->type != fileHeader->tocs[toc].type ||
391+ chunkHeader->subtype != fileHeader->tocs[toc].subtype)
392+ return XcursorFalse;
393+ return XcursorTrue;
394+}
395+
396+#define dist(a,b) ((a) > (b) ? (a) - (b) : (b) - (a))
397+
398+static XcursorDim
399+_XcursorFindBestSize (XcursorFileHeader *fileHeader,
400+ XcursorDim size,
401+ int *nsizesp)
402+{
403+ unsigned int n;
404+ int nsizes = 0;
405+ XcursorDim bestSize = 0;
406+ XcursorDim thisSize;
407+
408+ if (!fileHeader || !nsizesp)
409+ return 0;
410+
411+ for (n = 0; n < fileHeader->ntoc; n++)
412+ {
413+ if (fileHeader->tocs[n].type != XCURSOR_IMAGE_TYPE)
414+ continue;
415+ thisSize = fileHeader->tocs[n].subtype;
416+ if (!bestSize || dist (thisSize, size) < dist (bestSize, size))
417+ {
418+ bestSize = thisSize;
419+ nsizes = 1;
420+ }
421+ else if (thisSize == bestSize)
422+ nsizes++;
423+ }
424+ *nsizesp = nsizes;
425+ return bestSize;
426+}
427+
428+static int
429+_XcursorFindImageToc (XcursorFileHeader *fileHeader,
430+ XcursorDim size,
431+ int count)
432+{
433+ unsigned int toc;
434+ XcursorDim thisSize;
435+
436+ if (!fileHeader)
437+ return 0;
438+
439+ for (toc = 0; toc < fileHeader->ntoc; toc++)
440+ {
441+ if (fileHeader->tocs[toc].type != XCURSOR_IMAGE_TYPE)
442+ continue;
443+ thisSize = fileHeader->tocs[toc].subtype;
444+ if (thisSize != size)
445+ continue;
446+ if (!count)
447+ break;
448+ count--;
449+ }
450+ if (toc == fileHeader->ntoc)
451+ return -1;
452+ return toc;
453+}
454+
455+static XcursorImage *
456+_XcursorReadImage (XcursorFile *file,
457+ XcursorFileHeader *fileHeader,
458+ int toc)
459+{
460+ XcursorChunkHeader chunkHeader;
461+ XcursorImage head;
462+ XcursorImage *image;
463+ int n;
464+ XcursorPixel *p;
465+
466+ if (!file || !fileHeader)
467+ return NULL;
468+
469+ if (!_XcursorFileReadChunkHeader (file, fileHeader, toc, &chunkHeader))
470+ return NULL;
471+ if (!_XcursorReadUInt (file, &head.width))
472+ return NULL;
473+ if (!_XcursorReadUInt (file, &head.height))
474+ return NULL;
475+ if (!_XcursorReadUInt (file, &head.xhot))
476+ return NULL;
477+ if (!_XcursorReadUInt (file, &head.yhot))
478+ return NULL;
479+ if (!_XcursorReadUInt (file, &head.delay))
480+ return NULL;
481+ /* sanity check data */
482+ if (head.width >= 0x10000 || head.height > 0x10000)
483+ return NULL;
484+ if (head.width == 0 || head.height == 0)
485+ return NULL;
486+ if (head.xhot > head.width || head.yhot > head.height)
487+ return NULL;
488+
489+ /* Create the image and initialize it */
490+ image = XcursorImageCreate (head.width, head.height);
491+ if (image == NULL)
492+ return NULL;
493+ if (chunkHeader.version < image->version)
494+ image->version = chunkHeader.version;
495+ image->size = chunkHeader.subtype;
496+ image->xhot = head.xhot;
497+ image->yhot = head.yhot;
498+ image->delay = head.delay;
499+ n = image->width * image->height;
500+ p = image->pixels;
501+ while (n--)
502+ {
503+ if (!_XcursorReadUInt (file, p))
504+ {
505+ XcursorImageDestroy (image);
506+ return NULL;
507+ }
508+ p++;
509+ }
510+ return image;
511+}
512+
513+static XcursorImages *
514+XcursorXcFileLoadImages (XcursorFile *file, int size)
515+{
516+ XcursorFileHeader *fileHeader;
517+ XcursorDim bestSize;
518+ int nsize;
519+ XcursorImages *images;
520+ int n;
521+ int toc;
522+
523+ if (!file || size < 0)
524+ return NULL;
525+ fileHeader = _XcursorReadFileHeader (file);
526+ if (!fileHeader)
527+ return NULL;
528+ bestSize = _XcursorFindBestSize (fileHeader, (XcursorDim) size, &nsize);
529+ if (!bestSize)
530+ {
531+ _XcursorFileHeaderDestroy (fileHeader);
532+ return NULL;
533+ }
534+ images = XcursorImagesCreate (nsize);
535+ if (!images)
536+ {
537+ _XcursorFileHeaderDestroy (fileHeader);
538+ return NULL;
539+ }
540+ for (n = 0; n < nsize; n++)
541+ {
542+ toc = _XcursorFindImageToc (fileHeader, bestSize, n);
543+ if (toc < 0)
544+ break;
545+ images->images[images->nimage] = _XcursorReadImage (file, fileHeader,
546+ toc);
547+ if (!images->images[images->nimage])
548+ break;
549+ images->nimage++;
550+ }
551+ _XcursorFileHeaderDestroy (fileHeader);
552+ if (images->nimage != nsize)
553+ {
554+ XcursorImagesDestroy (images);
555+ images = NULL;
556+ }
557+ return images;
558+}
559+
560+static int
561+_XcursorStdioFileRead (XcursorFile *file, unsigned char *buf, int len)
562+{
563+ FILE *f = file->closure;
564+ return fread (buf, 1, len, f);
565+}
566+
567+static int
568+_XcursorStdioFileWrite (XcursorFile *file, unsigned char *buf, int len)
569+{
570+ FILE *f = file->closure;
571+ return fwrite (buf, 1, len, f);
572+}
573+
574+static int
575+_XcursorStdioFileSeek (XcursorFile *file, long offset, int whence)
576+{
577+ FILE *f = file->closure;
578+ return fseek (f, offset, whence);
579+}
580+
581+static void
582+_XcursorStdioFileInitialize (FILE *stdfile, XcursorFile *file)
583+{
584+ file->closure = stdfile;
585+ file->read = _XcursorStdioFileRead;
586+ file->write = _XcursorStdioFileWrite;
587+ file->seek = _XcursorStdioFileSeek;
588+}
589+
590+static XcursorImages *
591+XcursorFileLoadImages (FILE *file, int size)
592+{
593+ XcursorFile f;
594+
595+ if (!file)
596+ return NULL;
597+
598+ _XcursorStdioFileInitialize (file, &f);
599+ return XcursorXcFileLoadImages (&f, size);
600+}
601+
602+/*
603+ * From libXcursor/src/library.c
604+ */
605+
606+#ifndef ICONDIR
607+#define ICONDIR "/usr/X11R6/lib/X11/icons"
608+#endif
609+
610+#ifndef XCURSORPATH
611+#define XCURSORPATH "~/.icons:/usr/share/icons:/usr/share/pixmaps:~/.cursors:/usr/share/cursors/xorg-x11:"ICONDIR
612+#endif
613+
614+static const char *
615+XcursorLibraryPath (void)
616+{
617+ static const char *path;
618+
619+ if (!path)
620+ {
621+ path = getenv ("XCURSOR_PATH");
622+ if (!path)
623+ path = XCURSORPATH;
624+ }
625+ return path;
626+}
627+
628+static void
629+_XcursorAddPathElt (char *path, const char *elt, int len)
630+{
631+ int pathlen = strlen (path);
632+
633+ /* append / if the path doesn't currently have one */
634+ if (path[0] == '\0' || path[pathlen - 1] != '/')
635+ {
636+ strcat (path, "/");
637+ pathlen++;
638+ }
639+ if (len == -1)
640+ len = strlen (elt);
641+ /* strip leading slashes */
642+ while (len && elt[0] == '/')
643+ {
644+ elt++;
645+ len--;
646+ }
647+ strncpy (path + pathlen, elt, len);
648+ path[pathlen + len] = '\0';
649+}
650+
651+static char *
652+_XcursorBuildThemeDir (const char *dir, const char *theme)
653+{
654+ const char *colon;
655+ const char *tcolon;
656+ char *full;
657+ char *home;
658+ int dirlen;
659+ int homelen;
660+ int themelen;
661+ int len;
662+
663+ if (!dir || !theme)
664+ return NULL;
665+
666+ colon = strchr (dir, ':');
667+ if (!colon)
668+ colon = dir + strlen (dir);
669+
670+ dirlen = colon - dir;
671+
672+ tcolon = strchr (theme, ':');
673+ if (!tcolon)
674+ tcolon = theme + strlen (theme);
675+
676+ themelen = tcolon - theme;
677+
678+ home = NULL;
679+ homelen = 0;
680+ if (*dir == '~')
681+ {
682+ home = getenv ("HOME");
683+ if (!home)
684+ return NULL;
685+ homelen = strlen (home);
686+ dir++;
687+ dirlen--;
688+ }
689+
690+ /*
691+ * add space for any needed directory separators, one per component,
692+ * and one for the trailing null
693+ */
694+ len = 1 + homelen + 1 + dirlen + 1 + themelen + 1;
695+
696+ full = malloc (len);
697+ if (!full)
698+ return NULL;
699+ full[0] = '\0';
700+
701+ if (home)
702+ _XcursorAddPathElt (full, home, -1);
703+ _XcursorAddPathElt (full, dir, dirlen);
704+ _XcursorAddPathElt (full, theme, themelen);
705+ return full;
706+}
707+
708+static char *
709+_XcursorBuildFullname (const char *dir, const char *subdir, const char *file)
710+{
711+ char *full;
712+
713+ if (!dir || !subdir || !file)
714+ return NULL;
715+
716+ full = malloc (strlen (dir) + 1 + strlen (subdir) + 1 + strlen (file) + 1);
717+ if (!full)
718+ return NULL;
719+ full[0] = '\0';
720+ _XcursorAddPathElt (full, dir, -1);
721+ _XcursorAddPathElt (full, subdir, -1);
722+ _XcursorAddPathElt (full, file, -1);
723+ return full;
724+}
725+
726+static const char *
727+_XcursorNextPath (const char *path)
728+{
729+ char *colon = strchr (path, ':');
730+
731+ if (!colon)
732+ return NULL;
733+ return colon + 1;
734+}
735+
736+#define XcursorWhite(c) ((c) == ' ' || (c) == '\t' || (c) == '\n')
737+#define XcursorSep(c) ((c) == ';' || (c) == ',')
738+
739+static char *
740+_XcursorThemeInherits (const char *full)
741+{
742+ char line[8192];
743+ char *result = NULL;
744+ FILE *f;
745+
746+ if (!full)
747+ return NULL;
748+
749+ f = fopen (full, "r");
750+ if (f)
751+ {
752+ while (fgets (line, sizeof (line), f))
753+ {
754+ if (!strncmp (line, "Inherits", 8))
755+ {
756+ char *l = line + 8;
757+ char *r;
758+ while (*l == ' ') l++;
759+ if (*l != '=') continue;
760+ l++;
761+ while (*l == ' ') l++;
762+ result = malloc (strlen (l) + 1);
763+ if (result)
764+ {
765+ r = result;
766+ while (*l)
767+ {
768+ while (XcursorSep(*l) || XcursorWhite (*l)) l++;
769+ if (!*l)
770+ break;
771+ if (r != result)
772+ *r++ = ':';
773+ while (*l && !XcursorWhite(*l) &&
774+ !XcursorSep(*l))
775+ *r++ = *l++;
776+ }
777+ *r++ = '\0';
778+ }
779+ break;
780+ }
781+ }
782+ fclose (f);
783+ }
784+ return result;
785+}
786+
787+static FILE *
788+XcursorScanTheme (const char *theme, const char *name)
789+{
790+ FILE *f = NULL;
791+ char *full;
792+ char *dir;
793+ const char *path;
794+ char *inherits = NULL;
795+ const char *i;
796+
797+ if (!theme || !name)
798+ return NULL;
799+
800+ /*
801+ * Scan this theme
802+ */
803+ for (path = XcursorLibraryPath ();
804+ path && f == NULL;
805+ path = _XcursorNextPath (path))
806+ {
807+ dir = _XcursorBuildThemeDir (path, theme);
808+ if (dir)
809+ {
810+ full = _XcursorBuildFullname (dir, "cursors", name);
811+ if (full)
812+ {
813+ f = fopen (full, "r");
814+ free (full);
815+ }
816+ if (!f && !inherits)
817+ {
818+ full = _XcursorBuildFullname (dir, "", "index.theme");
819+ if (full)
820+ {
821+ inherits = _XcursorThemeInherits (full);
822+ free (full);
823+ }
824+ }
825+ free (dir);
826+ }
827+ }
828+ /*
829+ * Recurse to scan inherited themes
830+ */
831+ for (i = inherits; i && f == NULL; i = _XcursorNextPath (i))
832+ f = XcursorScanTheme (i, name);
833+ if (inherits != NULL)
834+ free (inherits);
835+ return f;
836+}
837+
838+XcursorImages *
839+XcursorLibraryLoadImages (const char *file, const char *theme, int size)
840+{
841+ FILE *f = NULL;
842+ XcursorImages *images = NULL;
843+
844+ if (!file)
845+ return NULL;
846+
847+ if (theme)
848+ f = XcursorScanTheme (theme, file);
849+ if (!f)
850+ f = XcursorScanTheme ("default", file);
851+ if (f)
852+ {
853+ images = XcursorFileLoadImages (f, size);
854+ if (images)
855+ XcursorImagesSetName (images, file);
856+ fclose (f);
857+ }
858+ return images;
859+}
860+
861+static void
862+load_all_cursors_from_dir(const char *path, int size,
863+ void (*load_callback)(XcursorImages *, void *),
864+ void *user_data)
865+{
866+ FILE *f;
867+ DIR *dir = opendir(path);
868+ struct dirent *ent;
869+ char *full;
870+ XcursorImages *images;
871+
872+ if (!dir)
873+ return;
874+
875+ for(ent = readdir(dir); ent; ent = readdir(dir)) {
876+#ifdef _DIRENT_HAVE_D_TYPE
877+ if (ent->d_type != DT_UNKNOWN &&
878+ (ent->d_type != DT_REG && ent->d_type != DT_LNK))
879+ continue;
880+#endif
881+
882+ full = _XcursorBuildFullname(path, "", ent->d_name);
883+ if (!full)
884+ continue;
885+
886+ f = fopen(full, "r");
887+ if (!f) {
888+ free(full);
889+ continue;
890+ }
891+
892+ images = XcursorFileLoadImages(f, size);
893+
894+ if (images) {
895+ XcursorImagesSetName(images, ent->d_name);
896+ load_callback(images, user_data);
897+ }
898+
899+ fclose (f);
900+ free(full);
901+ }
902+
903+ closedir(dir);
904+}
905+
906+/** Load all the cursor of a theme
907+ *
908+ * This function loads all the cursor images of a given theme and its
909+ * inherited themes. Each cursor is loaded into an XcursorImages object
910+ * which is passed to the caller's load callback. If a cursor appears
911+ * more than once across all the inherited themes, the load callback
912+ * will be called multiple times, with possibly different XcursorImages
913+ * object which have the same name. The user is expected to destroy the
914+ * XcursorImages objects passed to the callback with
915+ * XcursorImagesDestroy().
916+ *
917+ * \param theme The name of theme that should be loaded
918+ * \param size The desired size of the cursor images
919+ * \param load_callback A callback function that will be called
920+ * for each cursor loaded. The first parameter is the XcursorImages
921+ * object representing the loaded cursor and the second is a pointer
922+ * to data provided by the user.
923+ * \param user_data The data that should be passed to the load callback
924+ */
925+void
926+xcursor_load_theme(const char *theme, int size,
927+ void (*load_callback)(XcursorImages *, void *),
928+ void *user_data)
929+{
930+ char *full, *dir;
931+ char *inherits = NULL;
932+ const char *path, *i;
933+
934+ if (!theme)
935+ theme = "default";
936+
937+ for (path = XcursorLibraryPath();
938+ path;
939+ path = _XcursorNextPath(path)) {
940+ dir = _XcursorBuildThemeDir(path, theme);
941+ if (!dir)
942+ continue;
943+
944+ full = _XcursorBuildFullname(dir, "cursors", "");
945+
946+ if (full) {
947+ load_all_cursors_from_dir(full, size, load_callback,
948+ user_data);
949+ free(full);
950+ }
951+
952+ if (!inherits) {
953+ full = _XcursorBuildFullname(dir, "", "index.theme");
954+ if (full) {
955+ inherits = _XcursorThemeInherits(full);
956+ free(full);
957+ }
958+ }
959+
960+ free(dir);
961+ }
962+
963+ for (i = inherits; i; i = _XcursorNextPath(i))
964+ xcursor_load_theme(i, size, load_callback, user_data);
965+
966+ if (inherits)
967+ free(inherits);
968+}
plugins/Cursor/3rd_party/xcursor/xcursor.hnew file+65
@@ -0,0 +1,65 @@
1+/*
2+ * Copyright © 2002 Keith Packard
3+ *
4+ * Permission to use, copy, modify, distribute, and sell this software and its
5+ * documentation for any purpose is hereby granted without fee, provided that
6+ * the above copyright notice appear in all copies and that both that
7+ * copyright notice and this permission notice appear in supporting
8+ * documentation, and that the name of Keith Packard not be used in
9+ * advertising or publicity pertaining to distribution of the software without
10+ * specific, written prior permission. Keith Packard makes no
11+ * representations about the suitability of this software for any purpose. It
12+ * is provided "as is" without express or implied warranty.
13+ *
14+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
20+ * PERFORMANCE OF THIS SOFTWARE.
21+ */
22+
23+#ifndef XCURSOR_H
24+#define XCURSOR_H
25+
26+#include <stdint.h>
27+
28+
29+typedef int XcursorBool;
30+typedef uint32_t XcursorUInt;
31+
32+typedef XcursorUInt XcursorDim;
33+typedef XcursorUInt XcursorPixel;
34+
35+typedef struct _XcursorImage {
36+ XcursorUInt version; /* version of the image data */
37+ XcursorDim size; /* nominal size for matching */
38+ XcursorDim width; /* actual width */
39+ XcursorDim height; /* actual height */
40+ XcursorDim xhot; /* hot spot x (must be inside image) */
41+ XcursorDim yhot; /* hot spot y (must be inside image) */
42+ XcursorUInt delay; /* animation delay to next frame (ms) */
43+ XcursorPixel *pixels; /* pointer to pixels */
44+} XcursorImage;
45+
46+/*
47+ * Other data structures exposed by the library API
48+ */
49+typedef struct _XcursorImages {
50+ int nimage; /* number of images */
51+ XcursorImage **images; /* array of XcursorImage pointers */
52+ char *name; /* name used to load images */
53+} XcursorImages;
54+
55+XcursorImages *
56+XcursorLibraryLoadImages (const char *file, const char *theme, int size);
57+
58+void
59+XcursorImagesDestroy (XcursorImages *images);
60+
61+void
62+xcursor_load_theme(const char *theme, int size,
63+ void (*load_callback)(XcursorImages *, void *),
64+ void *user_data);
65+#endif
plugins/Cursor/CMakeLists.txtnew file+28
@@ -0,0 +1,28 @@
1+add_subdirectory(3rd_party)
2+
3+include_directories(
4+ ${CMAKE_CURRENT_SOURCE_DIR}
5+ ${CMAKE_CURRENT_SOURCE_DIR}/3rd_party/xcursor
6+ ${Qt5Gui_PRIVATE_INCLUDE_DIRS}
7+)
8+
9+set(QMLPLUGIN_SRC
10+ plugin.cpp
11+ MousePointer.cpp
12+ CursorImageProvider.cpp
13+ # We need to run moc on this header
14+ ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/MirMousePointerInterface.h
15+ )
16+
17+add_library(Cursor-qml SHARED
18+ ${QMLPLUGIN_SRC}
19+ )
20+
21+target_link_libraries(Cursor-qml
22+ xcursorloader-static
23+ ${QT5PLATFORM_SUPPORT_LDFLAGS}
24+)
25+
26+qt5_use_modules(Cursor-qml Qml Quick DBus Network Gui Sql Concurrent Svg)
27+
28+add_unity8_plugin(Cursor 1.0 Cursor TARGETS Cursor-qml)
plugins/Cursor/Cursor.qmlnew file+12
@@ -0,0 +1,12 @@
1+import QtQuick 2.4
2+import Cursor 1.0 // For MousePointer
3+
4+MousePointer {
5+ id: mousePointer
6+
7+ Image {
8+ x: -mousePointer.hotspotX
9+ y: -mousePointer.hotspotY
10+ source: "image://cursor/" + mousePointer.themeName + "/" + mousePointer.cursorName
11+ }
12+}
plugins/Cursor/CursorImageProvider.cppnew file+191
@@ -0,0 +1,191 @@
1+/*
2+ * Copyright (C) 2015 Canonical, Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it under
5+ * the terms of the GNU Lesser General Public License version 3, as published by
6+ * the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful, but WITHOUT
9+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11+ * Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#include "CursorImageProvider.h"
18+
19+#include <QDebug>
20+#include <QFile>
21+#include <QPainter>
22+#include <QSvgRenderer>
23+
24+CursorImageProvider *CursorImageProvider::m_instance = nullptr;
25+
26+/////
27+// BuiltInCursorImage
28+
29+BuiltInCursorImage::BuiltInCursorImage()
30+{
31+ const char *svgString =
32+ "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>"
33+ "<svg"
34+ " xmlns:dc=\"http://purl.org/dc/elements/1.1/\""
35+ " xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\""
36+ " xmlns:svg=\"http://www.w3.org/2000/svg\""
37+ " xmlns=\"http://www.w3.org/2000/svg\""
38+ " version=\"1.1\">"
39+ " <path"
40+ " 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\""
41+ " 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\" />"
42+ "</svg>";
43+
44+ qimage = QImage(20, 32, QImage::Format_ARGB32);
45+ QPainter imagePainter(&qimage);
46+
47+ QSvgRenderer *svgRenderer = new QSvgRenderer(QByteArray(svgString));
48+ svgRenderer->render(&imagePainter);
49+ delete svgRenderer;
50+}
51+
52+/////
53+// XCursorImage
54+
55+XCursorImage::XCursorImage(const QString &theme, const QString &file)
56+ : xcursorImages(nullptr)
57+{
58+ xcursorImages = XcursorLibraryLoadImages(QFile::encodeName(file), QFile::encodeName(theme), 32);
59+ if (!xcursorImages) {
60+ return;
61+ }
62+
63+ bool loaded = false;
64+ for (int i = 0; i < xcursorImages->nimage && !loaded; ++i) {
65+ XcursorImage *xcursorImage = xcursorImages->images[i];
66+ if (xcursorImage->size == 32) {
67+
68+ qimage = QImage((uchar*)xcursorImage->pixels,
69+ xcursorImage->width, xcursorImage->height, QImage::Format_ARGB32);
70+
71+ hotspot.setX(xcursorImage->xhot);
72+ hotspot.setY(xcursorImage->yhot);
73+
74+ loaded = true;
75+ }
76+ }
77+}
78+
79+XCursorImage::~XCursorImage()
80+{
81+ XcursorImagesDestroy(xcursorImages);
82+}
83+
84+/////
85+// CursorImageProvider
86+
87+CursorImageProvider::CursorImageProvider()
88+ : QQuickImageProvider(QQuickImageProvider::Image)
89+{
90+ if (m_instance) {
91+ qFatal("Cannot have multiple CursorImageProvider instances");
92+ }
93+ m_instance = this;
94+}
95+
96+CursorImageProvider::~CursorImageProvider()
97+{
98+ {
99+ QList< QMap<QString, CursorImage*> > cursorList = m_cursors.values();
100+
101+ for (int i = 0; i < cursorList.count(); ++i) {
102+ QList<CursorImage*> cursorImageList = cursorList[i].values();
103+ for (int j = 0; j < cursorImageList.count(); ++j) {
104+ delete cursorImageList[j];
105+ }
106+ }
107+ }
108+
109+ m_cursors.clear();
110+ m_instance = nullptr;
111+}
112+
113+QImage CursorImageProvider::requestImage(const QString &cursorThemeAndName, QSize *size, const QSize & /*requestedSize*/)
114+{
115+ CursorImage *cursorImage = fetchCursor(cursorThemeAndName);
116+ size->setWidth(cursorImage->qimage.width());
117+ size->setHeight(cursorImage->qimage.height());
118+
119+ return cursorImage->qimage;
120+}
121+
122+QPoint CursorImageProvider::hotspot(const QString &themeName, const QString &cursorName)
123+{
124+ CursorImage *cursorImage = fetchCursor(themeName, cursorName);
125+ if (cursorImage) {
126+ return cursorImage->hotspot;
127+ } else {
128+ return QPoint(0,0);
129+ }
130+}
131+
132+CursorImage *CursorImageProvider::fetchCursor(const QString &cursorThemeAndName)
133+{
134+ QString themeName;
135+ QString cursorName;
136+ {
137+ QStringList themeAndNameList = cursorThemeAndName.split("/");
138+ if (themeAndNameList.size() != 2) {
139+ return nullptr;
140+ }
141+ themeName = themeAndNameList[0];
142+ cursorName = themeAndNameList[1];
143+ }
144+
145+ return fetchCursor(themeName, cursorName);
146+}
147+
148+CursorImage *CursorImageProvider::fetchCursor(const QString &themeName, const QString &cursorName)
149+{
150+ CursorImage *cursorImage = fetchCursorHelper(themeName, cursorName);
151+
152+ // Try some fallbacks
153+ if (cursorImage->qimage.isNull()) {
154+ if (cursorName == "ibeam") {
155+ qDebug() << "CursorImageProvider: \"ibeam\" not found, falling back to \"xterm\"";
156+ cursorImage = fetchCursorHelper(themeName, "xterm");
157+ } else if (cursorName == "xterm") {
158+ qDebug() << "CursorImageProvider: \"xterm\" not found, falling back to \"ibeam\"";
159+ cursorImage = fetchCursorHelper(themeName, "ibeam");
160+ }
161+ }
162+
163+ // if it all fails, there must be at least a left_ptr
164+ if (cursorImage->qimage.isNull() && cursorName != "left_ptr") {
165+ qDebug() << "CursorImageProvider:" << cursorName
166+ << "not found (nor its fallbacks, if any). Going for \"left_ptr\" as a last resort.";
167+ cursorImage = fetchCursorHelper(themeName, "left_ptr");
168+ }
169+
170+ if (cursorImage->qimage.isNull()) {
171+ // finally, go for the built-in cursor
172+ qWarning() << "CursorImageProvider: couldn't find any cursors. Using the built-in one";
173+ if (!m_builtInCursorImage) {
174+ m_builtInCursorImage.reset(new BuiltInCursorImage);
175+ }
176+ cursorImage = m_builtInCursorImage.data();
177+ }
178+
179+ return cursorImage;
180+}
181+
182+CursorImage *CursorImageProvider::fetchCursorHelper(const QString &themeName, const QString &cursorName)
183+{
184+ QMap<QString, CursorImage*> &themeCursors = m_cursors[themeName];
185+
186+ if (!themeCursors.contains(cursorName)) {
187+ themeCursors[cursorName] = new XCursorImage(themeName, cursorName);
188+ }
189+
190+ return themeCursors[cursorName];
191+}
plugins/Cursor/CursorImageProvider.hnew file+76
@@ -0,0 +1,76 @@
1+/*
2+ * Copyright (C) 2015 Canonical, Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it under
5+ * the terms of the GNU Lesser General Public License version 3, as published by
6+ * the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful, but WITHOUT
9+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11+ * Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#ifndef CURSORIMAGEPROVIDER_H
18+#define CURSORIMAGEPROVIDER_H
19+
20+#include <QQuickImageProvider>
21+#include <QScopedPointer>
22+
23+// xcursor static lib
24+extern "C"
25+{
26+#include <xcursor.h>
27+}
28+
29+class CursorImage {
30+public:
31+ virtual ~CursorImage() {}
32+
33+ QImage qimage;
34+ QPoint hotspot;
35+};
36+
37+class XCursorImage : public CursorImage {
38+public:
39+ XCursorImage(const QString &theme, const QString &file);
40+ virtual ~XCursorImage();
41+
42+ XcursorImages *xcursorImages;
43+};
44+
45+class BuiltInCursorImage : public CursorImage {
46+public:
47+ BuiltInCursorImage();
48+};
49+
50+class CursorImageProvider : public QQuickImageProvider
51+{
52+public:
53+ CursorImageProvider();
54+ virtual ~CursorImageProvider();
55+
56+ static CursorImageProvider *instance() { return m_instance; }
57+
58+
59+ QImage requestImage(const QString &cursorName, QSize *size, const QSize &requestedSize) override;
60+
61+ QPoint hotspot(const QString &themeName, const QString &cursorName);
62+
63+private:
64+ CursorImage *fetchCursor(const QString &cursorThemeAndName);
65+ CursorImage *fetchCursor(const QString &themeName, const QString &cursorName);
66+ CursorImage *fetchCursorHelper(const QString &themeName, const QString &cursorName);
67+
68+ // themeName -> (cursorName -> cursorImage)
69+ QMap<QString, QMap<QString, CursorImage*> > m_cursors;
70+
71+ QScopedPointer<CursorImage> m_builtInCursorImage;
72+
73+ static CursorImageProvider *m_instance;
74+};
75+
76+#endif // CURSORIMAGEPROVIDER_H
plugins/Cursor/MousePointer.cppnew file+125
@@ -0,0 +1,125 @@
1+/*
2+ * Copyright (C) 2015 Canonical, Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it under
5+ * the terms of the GNU Lesser General Public License version 3, as published by
6+ * the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful, but WITHOUT
9+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11+ * Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#include "MousePointer.h"
18+#include "CursorImageProvider.h"
19+
20+// Unity API
21+#include <unity/shell/application/MirPlatformCursor.h>
22+
23+#include <QQuickWindow>
24+#include <QGuiApplication>
25+
26+#include <qpa/qwindowsysteminterface.h>
27+
28+MousePointer::MousePointer(QQuickItem *parent)
29+ : MirMousePointerInterface(parent)
30+ , m_cursorName("left_ptr")
31+ , m_themeName("default")
32+ , m_hotspotX(0)
33+ , m_hotspotY(0)
34+{
35+}
36+
37+void MousePointer::handleMouseEvent(ulong timestamp, QPointF movement, Qt::MouseButtons buttons,
38+ Qt::KeyboardModifiers modifiers)
39+{
40+ if (!parentItem()) {
41+ return;
42+ }
43+
44+ qreal newX = x() + movement.x();
45+ if (newX < 0) {
46+ newX = 0;
47+ } else if (newX > parentItem()->width()) {
48+ newX = parentItem()->width();
49+ }
50+ setX(newX);
51+
52+ qreal newY = y() + movement.y();
53+ if (newY < 0) {
54+ newY = 0;
55+ } else if (newY > parentItem()->height()) {
56+ newY = parentItem()->height();
57+ }
58+ setY(newY);
59+
60+ QPointF scenePosition = mapToItem(nullptr, QPointF(0, 0));
61+ QWindowSystemInterface::handleMouseEvent(window(), timestamp, scenePosition /*local*/, scenePosition /*global*/,
62+ buttons, modifiers);
63+}
64+
65+void MousePointer::itemChange(ItemChange change, const ItemChangeData &value)
66+{
67+ if (change == ItemSceneChange) {
68+ registerWindow(value.window);
69+ }
70+}
71+
72+void MousePointer::registerWindow(QWindow *window)
73+{
74+ if (m_registeredWindow && window != m_registeredWindow) {
75+ auto previousCursor = dynamic_cast<MirPlatformCursor*>(m_registeredWindow->screen()->handle()->cursor());
76+ if (previousCursor) {
77+ previousCursor->setMousePointer(nullptr);
78+ } else {
79+ qCritical("QPlatformCursor is not a MirPlatformCursor! Cursor module only works in a Mir server.");
80+ }
81+ }
82+
83+ m_registeredWindow = window;
84+
85+ if (m_registeredWindow) {
86+ auto cursor = dynamic_cast<MirPlatformCursor*>(window->screen()->handle()->cursor());
87+ if (cursor) {
88+ cursor->setMousePointer(this);
89+ } else {
90+ qCritical("QPlaformCursor is not a MirPlatformCursor! Cursor module only works in Mir.");
91+ }
92+ }
93+}
94+
95+void MousePointer::setCursorName(const QString &cursorName)
96+{
97+ if (cursorName != m_cursorName) {
98+ m_cursorName = cursorName;
99+ Q_EMIT cursorNameChanged(m_cursorName);
100+ updateHotspot();
101+ }
102+}
103+
104+void MousePointer::updateHotspot()
105+{
106+ QPoint newHotspot = CursorImageProvider::instance()->hotspot(m_themeName, m_cursorName);
107+
108+ if (m_hotspotX != newHotspot.x()) {
109+ m_hotspotX = newHotspot.x();
110+ Q_EMIT hotspotXChanged(m_hotspotX);
111+ }
112+
113+ if (m_hotspotY != newHotspot.y()) {
114+ m_hotspotY = newHotspot.y();
115+ Q_EMIT hotspotYChanged(m_hotspotY);
116+ }
117+}
118+
119+void MousePointer::setThemeName(const QString &themeName)
120+{
121+ if (m_themeName != themeName) {
122+ m_themeName = themeName;
123+ Q_EMIT themeNameChanged(m_themeName);
124+ }
125+}
plugins/Cursor/MousePointer.hnew file+59
@@ -0,0 +1,59 @@
1+/*
2+ * Copyright (C) 2015 Canonical, Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it under
5+ * the terms of the GNU Lesser General Public License version 3, as published by
6+ * the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful, but WITHOUT
9+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11+ * Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#ifndef MOUSEPOINTER_H
18+#define MOUSEPOINTER_H
19+
20+// Qt
21+#include <QPointer>
22+#include <QWindow>
23+
24+// Unity API
25+#include <unity/shell/application/MirMousePointerInterface.h>
26+
27+class MousePointer : public MirMousePointerInterface {
28+ Q_OBJECT
29+public:
30+ MousePointer(QQuickItem *parent = nullptr);
31+
32+ void setCursorName(const QString &qtCursorName) override;
33+ QString cursorName() const override { return m_cursorName; }
34+
35+ void setThemeName(const QString &themeName) override;
36+ QString themeName() const override { return m_themeName; }
37+
38+ qreal hotspotX() const override { return m_hotspotX; }
39+ qreal hotspotY() const override { return m_hotspotY; }
40+
41+public Q_SLOTS:
42+ void handleMouseEvent(ulong timestamp, QPointF movement, Qt::MouseButtons buttons,
43+ Qt::KeyboardModifiers modifiers) override;
44+
45+protected:
46+ void itemChange(ItemChange change, const ItemChangeData &value) override;
47+
48+private:
49+ void registerWindow(QWindow *window);
50+ void updateHotspot();
51+
52+ QPointer<QWindow> m_registeredWindow;
53+ QString m_cursorName;
54+ QString m_themeName;
55+ int m_hotspotX;
56+ int m_hotspotY;
57+};
58+
59+#endif // MOUSEPOINTER_H
plugins/Cursor/plugin.cppnew file+39
@@ -0,0 +1,39 @@
1+/*
2+ * Copyright (C) 2015 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+// Qt
18+#include <QtQml/qqml.h>
19+#include <QQmlContext>
20+
21+// self
22+#include "plugin.h"
23+
24+// local
25+#include "CursorImageProvider.h"
26+#include "MousePointer.h"
27+
28+void CursorPlugin::registerTypes(const char *uri)
29+{
30+ Q_ASSERT(uri == QLatin1String("Cursor"));
31+ qmlRegisterType<MousePointer>(uri, 1, 0, "MousePointer");
32+}
33+
34+void CursorPlugin::initializeEngine(QQmlEngine *engine, const char *uri)
35+{
36+ QQmlExtensionPlugin::initializeEngine(engine, uri);
37+
38+ engine->addImageProvider(QLatin1String("cursor"), new CursorImageProvider());
39+}
plugins/Cursor/plugin.hnew file+33
@@ -0,0 +1,33 @@
1+/*
2+ * Copyright (C) 2015 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#ifndef CURSOR_PLUGIN_H
18+#define CURSOR_PLUGIN_H
19+
20+#include <QtQml/QQmlEngine>
21+#include <QtQml/QQmlExtensionPlugin>
22+
23+class CursorPlugin : public QQmlExtensionPlugin
24+{
25+ Q_OBJECT
26+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
27+
28+public:
29+ void registerTypes(const char *uri) override;
30+ void initializeEngine(QQmlEngine *engine, const char *uri) override;
31+};
32+
33+#endif // CURSOR_PLUGIN_H
plugins/Cursor/qmldirnew file+3
@@ -0,0 +1,3 @@
1+module Cursor
2+plugin Cursor-qml
3+Cursor 1.0 Cursor.qml
plugins/IntegratedLightDM/UsersModel.cpp+7−6
@@ -43,16 +43,17 @@ MangleModel::MangleModel(QObject* parent)
43
43
44QVariant MangleModel::data(const QModelIndex &index, int role) const
44QVariant MangleModel::data(const QModelIndex &index, int role) const
45{
45{
46− QVariant data = QSortFilterProxyModel::data(index, role);
46+ QVariant variantData = QSortFilterProxyModel::data(index, role);
47
47
48 // If user's real name is empty, switch to unix name
48 // If user's real name is empty, switch to unix name
49− if (role == QLightDM::UsersModel::RealNameRole && data.toString().isEmpty()) {
49+ if (role == QLightDM::UsersModel::RealNameRole && variantData.toString().isEmpty()) {
50− data = QSortFilterProxyModel::data(index, QLightDM::UsersModel::NameRole);
50+ variantData = QSortFilterProxyModel::data(index, QLightDM::UsersModel::NameRole);
51− } else if (role == QLightDM::UsersModel::BackgroundPathRole && data.toString().startsWith('#')) {
51+ } else if (role == QLightDM::UsersModel::BackgroundPathRole && variantData.toString().startsWith('#')) {
52− data = "data:image/svg+xml,<svg><rect width='100%' height='100%' fill='" + data.toString() + "'/></svg>";
52+ const QString stringData = "data:image/svg+xml,<svg><rect width='100%' height='100%' fill='" + variantData.toString() + "'/></svg>";
53+ variantData = stringData;
53 }
54 }
54
55
55− return data;
56+ return variantData;
56}
57}
57
58
58// **** Now we continue with actual UsersModel class ****
59// **** Now we continue with actual UsersModel class ****
plugins/IntegratedLightDM/liblightdm/UsersModelPrivate.cpp+2−1
@@ -34,7 +34,8 @@ UsersModelPrivate::UsersModelPrivate(UsersModel* parent)
34 entries.reserve(users.count());
34 entries.reserve(users.count());
35 Q_FOREACH(const QString &user, users)
35 Q_FOREACH(const QString &user, users)
36 {
36 {
37− QString name = settings.value(user + "/name", user[0].toUpper() + user.mid(1)).toString();
37+ QVariant defaultValue = QString(user[0].toUpper() + user.mid(1));
38+ QString name = settings.value(user + "/name", defaultValue).toString();
38 entries.append({user, name, 0, 0, false, false, 0, 0});
39 entries.append({user, name, 0, 0, false, false, 0, 0});
39 }
40 }
40}
41}
plugins/ScreenGrabber/screengrabber.cpp+2−2
@@ -60,7 +60,7 @@ ScreenGrabber::ScreenGrabber(QObject *parent)
60 }
60 }
61}
61}
62
62
63−void ScreenGrabber::captureAndSave()
63+void ScreenGrabber::captureAndSave(int angle)
64{
64{
65 if (fileNamePrefix.isEmpty())
65 if (fileNamePrefix.isEmpty())
66 {
66 {
@@ -82,7 +82,7 @@ void ScreenGrabber::captureAndSave()
82 return;
82 return;
83 }
83 }
84
84
85− const QImage screenshot = main_window->grabWindow();
85+ const QImage screenshot = main_window->grabWindow().transformed(QTransform().rotate(angle));
86 const QString filename = makeFileName();
86 const QString filename = makeFileName();
87 qDebug() << "Saving screenshot to" << filename;
87 qDebug() << "Saving screenshot to" << filename;
88 auto saveOp = QtConcurrent::run(saveScreenshot, screenshot, filename, getFormat(), screenshotQuality);
88 auto saveOp = QtConcurrent::run(saveScreenshot, screenshot, filename, getFormat(), screenshotQuality);
plugins/ScreenGrabber/screengrabber.h+1−1
@@ -29,7 +29,7 @@ public:
29 ~ScreenGrabber() = default;
29 ~ScreenGrabber() = default;
30
30
31public Q_SLOTS:
31public Q_SLOTS:
32− void captureAndSave();
32+ void captureAndSave(int angle = 0);
33
33
34Q_SIGNALS:
34Q_SIGNALS:
35 void screenshotSaved(const QString &filename);
35 void screenshotSaved(const QString &filename);
plugins/Unity/CMakeLists.txt+1
@@ -4,3 +4,4 @@ add_subdirectory(Launcher)
4add_subdirectory(Session)
4add_subdirectory(Session)
5add_subdirectory(DashCommunicator)
5add_subdirectory(DashCommunicator)
6add_subdirectory(InputInfo)
6add_subdirectory(InputInfo)
7+add_subdirectory(Platform)
plugins/Unity/Launcher/desktopfilehandler.cpp+3−2
@@ -111,8 +111,9 @@ QString DesktopFileHandler::displayName() const
111 settings.beginGroup(QStringLiteral("Desktop Entry"));
111 settings.beginGroup(QStringLiteral("Desktop Entry"));
112
112
113 // First try to find Name[xx_YY] and Name[xx] in .desktop file
113 // First try to find Name[xx_YY] and Name[xx] in .desktop file
114− QString locale = QLocale().name();
114+ const QString locale = QLocale().name();
115− QString shortLocale = locale.split('_').first();
115+ const QStringList splitLocale = locale.split(QLatin1Char('_'));
116+ const QString shortLocale = splitLocale.first();
116
117
117 if (locale != shortLocale && settings.contains(QStringLiteral("Name[%1]").arg(locale))) {
118 if (locale != shortLocale && settings.contains(QStringLiteral("Name[%1]").arg(locale))) {
118 return settings.value(QStringLiteral("Name[%1]").arg(locale)).toString();
119 return settings.value(QStringLiteral("Name[%1]").arg(locale)).toString();
plugins/Unity/Platform/CMakeLists.txtnew file+9
@@ -0,0 +1,9 @@
1+set(platformplugin_SRCS
2+ platform.cpp
3+ plugin.cpp)
4+
5+add_library(Platform-qml SHARED ${platformplugin_SRCS})
6+
7+qt5_use_modules(Platform-qml DBus Qml)
8+
9+add_unity8_plugin(Unity.Platform 1.0 Unity/Platform TARGETS Platform-qml)
plugins/Unity/Platform/platform.cppnew file+43
@@ -0,0 +1,43 @@
1+/*
2+ * Copyright (C) 2015 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#include "platform.h"
18+
19+#include <QDBusConnection>
20+
21+Platform::Platform(QObject *parent)
22+ : QObject(parent)
23+ , m_iface("org.freedesktop.hostname1", "/org/freedesktop/hostname1", "org.freedesktop.hostname1",
24+ QDBusConnection::systemBus(), this)
25+{
26+ QMetaObject::invokeMethod(this, "init");
27+}
28+
29+void Platform::init()
30+{
31+ m_chassis = m_iface.property("Chassis").toString();
32+ m_isPC = (m_chassis == "desktop" || m_chassis == "laptop" || m_chassis == "server");
33+}
34+
35+QString Platform::chassis() const
36+{
37+ return m_chassis;
38+}
39+
40+bool Platform::isPC() const
41+{
42+ return m_isPC;
43+}
plugins/Unity/Platform/platform.hnew file+58
@@ -0,0 +1,58 @@
1+/*
2+ * Copyright (C) 2015 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#ifndef PLATFORM_H
18+#define PLATFORM_H
19+
20+#include <QDBusInterface>
21+
22+/**
23+ * @brief The Platform class
24+ *
25+ * Wrapper around platform detection support (org.freedesktop.hostname1)
26+ */
27+class Platform: public QObject
28+{
29+ Q_OBJECT
30+ /**
31+ * The chassis property
32+ *
33+ * Supported values include: "laptop", "computer", "handset" or "tablet"
34+ * For full list see: http://www.freedesktop.org/wiki/Software/systemd/hostnamed/
35+ */
36+ Q_PROPERTY(QString chassis READ chassis CONSTANT)
37+ /**
38+ * Whether the machine is an ordinary PC (desktop, laptop or server)
39+ */
40+ Q_PROPERTY(bool isPC READ isPC CONSTANT)
41+
42+public:
43+ Platform(QObject *parent = nullptr);
44+ ~Platform() = default;
45+
46+ QString chassis() const;
47+ bool isPC() const;
48+
49+private Q_SLOTS:
50+ void init();
51+
52+private:
53+ QDBusInterface m_iface;
54+ QString m_chassis;
55+ bool m_isPC;
56+};
57+
58+#endif // PLATFORM_H
plugins/Unity/Platform/plugin.cppnew file+27
@@ -0,0 +1,27 @@
1+/*
2+ * Copyright (C) 2015 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#include "plugin.h"
18+#include "platform.h"
19+
20+#include <QtQml>
21+
22+void GlobalShortcutPlugin::registerTypes(const char *uri)
23+{
24+ Q_ASSERT(uri == QLatin1String("Unity.Platform"));
25+
26+ qmlRegisterSingletonType<Platform>(uri, 1, 0, "Platform", [](QQmlEngine*, QJSEngine*) -> QObject* { return new Platform; });
27+}
plugins/Utils/relativetimeformatter.h → plugins/Unity/Platform/plugin.hrenamed+10−12
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright 2014 Canonical Ltd.
2+ * Copyright (C) 2015 Canonical, Ltd.
3 *
3 *
4 * This program is free software; you can redistribute it and/or modify
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
5 * it under the terms of the GNU General Public License as published by
@@ -12,23 +12,21 @@
12 *
12 *
13 * You should have received a copy of the GNU General Public License
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− *
16 */
15 */
17
16
18−#ifndef RELATIVETIMEFORMATTER_H
17+#ifndef PLATFORMPLUGIN_H
19−#define RELATIVETIMEFORMATTER_H
18+#define PLATFORMPLUGIN_H
20
19
21−#include "timeformatter.h"
20+#include <QQmlExtensionPlugin>
22
21
23−// TODO - move this to the sdk
22+class GlobalShortcutPlugin: public QQmlExtensionPlugin
24−// https://blueprints.launchpad.net/ubuntu-ui-toolkit/+spec/time-formatter
25−class RelativeTimeFormatter : public GDateTimeFormatter
26{
23{
27 Q_OBJECT
24 Q_OBJECT
28−public:
25+ Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
29− RelativeTimeFormatter(QObject *parent = 0);
30
26
31− QString format() const override;
27+public:
28+ void registerTypes(const char *uri) override;
32};
29};
33
30
34−#endif // RELATIVETIMEFORMATTER_H
31+
32+#endif // PLATFORMPLUGIN_H
plugins/Unity/Platform/qmldirnew file+2
@@ -0,0 +1,2 @@
1+module Unity.Platform
2+plugin Platform-qml
plugins/Unity/Session/dbusunitysessionservice.cpp+2−1
@@ -292,7 +292,8 @@ QString DBusUnitySessionService::RealName() const
292 if (p) {
292 if (p) {
293 const QString gecos = QString::fromLocal8Bit(p->pw_gecos);
293 const QString gecos = QString::fromLocal8Bit(p->pw_gecos);
294 if (!gecos.isEmpty()) {
294 if (!gecos.isEmpty()) {
295− return gecos.split(QLatin1Char(',')).first();
295+ const QStringList splitGecos = gecos.split(QLatin1Char(','));
296+ return splitGecos.first();
296 }
297 }
297 }
298 }
298
299
plugins/Utils/CMakeLists.txt−2
@@ -15,8 +15,6 @@ set(QMLPLUGIN_SRC
15 inputwatcher.cpp
15 inputwatcher.cpp
16 qlimitproxymodelqml.cpp
16 qlimitproxymodelqml.cpp
17 unitysortfilterproxymodelqml.cpp
17 unitysortfilterproxymodelqml.cpp
18− relativetimeformatter.cpp
19− timeformatter.cpp
20 Timer.cpp
18 Timer.cpp
21 unitymenumodelpaths.cpp
19 unitymenumodelpaths.cpp
22 windowkeysfilter.cpp
20 windowkeysfilter.cpp
plugins/Utils/plugin.cpp−5
@@ -29,8 +29,6 @@
29#include "inputwatcher.h"
29#include "inputwatcher.h"
30#include "qlimitproxymodelqml.h"
30#include "qlimitproxymodelqml.h"
31#include "unitysortfilterproxymodelqml.h"
31#include "unitysortfilterproxymodelqml.h"
32−#include "relativetimeformatter.h"
33−#include "timeformatter.h"
34#include "unitymenumodelpaths.h"
32#include "unitymenumodelpaths.h"
35#include "windowkeysfilter.h"
33#include "windowkeysfilter.h"
36#include "windowscreenshotprovider.h"
34#include "windowscreenshotprovider.h"
@@ -60,11 +58,8 @@ void UtilsPlugin::registerTypes(const char *uri)
60 qmlRegisterType<QLimitProxyModelQML>(uri, 0, 1, "LimitProxyModel");
58 qmlRegisterType<QLimitProxyModelQML>(uri, 0, 1, "LimitProxyModel");
61 qmlRegisterType<UnitySortFilterProxyModelQML>(uri, 0, 1, "UnitySortFilterProxyModel");
59 qmlRegisterType<UnitySortFilterProxyModelQML>(uri, 0, 1, "UnitySortFilterProxyModel");
62 qmlRegisterType<UnityMenuModelPaths>(uri, 0, 1, "UnityMenuModelPaths");
60 qmlRegisterType<UnityMenuModelPaths>(uri, 0, 1, "UnityMenuModelPaths");
63− qmlRegisterType<TimeFormatter>(uri, 0, 1, "TimeFormatter");
64 qmlRegisterType<WindowKeysFilter>(uri, 0, 1, "WindowKeysFilter");
61 qmlRegisterType<WindowKeysFilter>(uri, 0, 1, "WindowKeysFilter");
65− qmlRegisterType<GDateTimeFormatter>(uri, 0, 1, "GDateTimeFormatter");
66 qmlRegisterType<EasingCurve>(uri, 0, 1, "EasingCurve");
62 qmlRegisterType<EasingCurve>(uri, 0, 1, "EasingCurve");
67− qmlRegisterType<RelativeTimeFormatter>(uri, 0, 1, "RelativeTimeFormatter");
68 qmlRegisterSingletonType<WindowStateStorage>(uri, 0, 1, "WindowStateStorage", createWindowStateStorage);
63 qmlRegisterSingletonType<WindowStateStorage>(uri, 0, 1, "WindowStateStorage", createWindowStateStorage);
69 qmlRegisterType<InputWatcher>(uri, 0, 1, "InputWatcher");
64 qmlRegisterType<InputWatcher>(uri, 0, 1, "InputWatcher");
70 qmlRegisterSingletonType<Constants>(uri, 0, 1, "Constants", createConstants);
65 qmlRegisterSingletonType<Constants>(uri, 0, 1, "Constants", createConstants);
plugins/Utils/relativetimeformatter.cppdeleted−260
@@ -1,260 +0,0 @@
1−/*
2− * Copyright 2014 Canonical Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− *
16− */
17−
18−// Local
19−#include "relativetimeformatter.h"
20−
21−// Qt
22−#include <QDateTime>
23−
24−// Other
25−#include <glib.h>
26−#include <glib/gi18n.h>
27−#include <locale.h>
28−#include <langinfo.h>
29−#include <string.h>
30−
31−RelativeTimeFormatter::RelativeTimeFormatter(QObject *parent)
32− : GDateTimeFormatter(parent)
33−{
34−}
35−
36− /* Check the system locale setting to see if the format is 24-hour
37− time or 12-hour time */
38−gboolean
39−is_locale_12h(void)
40−{
41− int i;
42− static const char *formats_24h[] = {"%H", "%R", "%T", "%OH", "%k", nullptr};
43− const char* t_fmt = nl_langinfo(T_FMT);
44−
45− for (i=0; formats_24h[i]!=nullptr; i++)
46− if (strstr(t_fmt, formats_24h[i]) != nullptr)
47− return FALSE;
48−
49− return TRUE;
50−}
51−
52−typedef enum
53−{
54− DATE_PROXIMITY_YESTERDAY,
55− DATE_PROXIMITY_TODAY,
56− DATE_PROXIMITY_TOMORROW,
57− DATE_PROXIMITY_LAST_WEEK,
58− DATE_PROXIMITY_NEXT_WEEK,
59− DATE_PROXIMITY_FAR
60−} date_proximity_t;
61−
62−static date_proximity_t
63−getDateProximity(GDateTime* now, GDateTime* time)
64−{
65− date_proximity_t prox = DATE_PROXIMITY_FAR;
66− gint now_year, now_month, now_day;
67− gint time_year, time_month, time_day;
68−
69− // does it happen today?
70− g_date_time_get_ymd(now, &now_year, &now_month, &now_day);
71− g_date_time_get_ymd(time, &time_year, &time_month, &time_day);
72− if ((now_year == time_year) && (now_month == time_month) && (now_day == time_day)) {
73− return DATE_PROXIMITY_TODAY;
74− }
75−
76− // did it happen yesterday?
77− GDateTime* yesterday = g_date_time_add_days(now, -1);
78− gint tom_year, tom_month, tom_day;
79− g_date_time_get_ymd(yesterday, &tom_year, &tom_month, &tom_day);
80− g_date_time_unref(yesterday);
81− if ((tom_year == time_year) && (tom_month == time_month) && (tom_day == time_day)) {
82− return DATE_PROXIMITY_YESTERDAY;
83− }
84−
85− // does it happen tomorrow?
86− GDateTime* tomorrow = g_date_time_add_days(now, 1);
87− g_date_time_get_ymd(tomorrow, &tom_year, &tom_month, &tom_day);
88− g_date_time_unref(tomorrow);
89− if ((tom_year == time_year) && (tom_month == time_month) && (tom_day == time_day)) {
90− return DATE_PROXIMITY_TOMORROW;
91− }
92−
93− // does it happen this week?
94− if (g_date_time_compare(time, now) < 0) {
95− GDateTime* last_week = g_date_time_add_days(now, -6);
96− GDateTime* last_week_bound = g_date_time_new_local(g_date_time_get_year(last_week),
97− g_date_time_get_month(last_week),
98− g_date_time_get_day_of_month(last_week),
99− 0, 0, 0);
100− if (g_date_time_compare(time, last_week_bound) >= 0)
101− prox = DATE_PROXIMITY_LAST_WEEK;
102−
103− g_date_time_unref(last_week);
104− g_date_time_unref(last_week_bound);
105− } else {
106− GDateTime* next_week = g_date_time_add_days(now, 6);
107− GDateTime* next_week_bound = g_date_time_new_local(g_date_time_get_year(next_week),
108− g_date_time_get_month(next_week),
109− g_date_time_get_day_of_month(next_week),
110− 23, 59, 59.9);
111− if (g_date_time_compare(time, next_week_bound) <= 0)
112− prox = DATE_PROXIMITY_NEXT_WEEK;
113−
114− g_date_time_unref(next_week);
115− g_date_time_unref(next_week_bound);
116− }
117−
118− return prox;
119−}
120−
121−const char*
122−dgettext_datetime(const char *text)
123−{
124− return dgettext("unity8", text);
125−}
126−
127−/**
128− * _ a time yesterday should be shown as (e.g. “Yesterday 3:55 PM”)
129− * _ a time today should be shown as just the time (e.g. “3:55 PM”)
130− * _ a time tomorrow should be shown as(e.g. “Tomorrow 3:55 PM”)
131− * _ a time any other day this week should be shown as the short version of the
132− * day and time (e.g. “Wed 3:55 PM”)
133− * weekday (e.g. “Friday”)
134− * _ a time after this week should be shown as the short version of the day,
135− * date, and time (e.g. “Wed 21 Apr 3:55 PM”)
136− * _ in addition, when presenting the times of upcoming events, the time should
137− * be followed by the timezone if it is different from the one the computer
138− * is currently set to. For example, “Wed 3:55 PM UTC−5”.
139− *
140− * TODO - keep inline with indicator-datetime
141− */
142−char* generate_full_format_string_at_time (GDateTime* now,
143− GDateTime* then)
144−{
145− GString* ret = g_string_new (nullptr);
146−
147− if (then != nullptr) {
148− const date_proximity_t prox = getDateProximity(now, then);
149−
150− if (is_locale_12h()) {
151− switch (prox) {
152− case DATE_PROXIMITY_YESTERDAY:
153− /* Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
154− This format string is used for showing, on a 12-hour clock, times that happen yesterday.
155− (\u2003 is a unicode em space which is slightly wider than a normal space.)
156− en_US example: "Yesterday\u2003%l:%M %p" --> "Yesterday 1:00 PM" */
157− g_string_assign (ret, dgettext_datetime("Yesterday\u2003%l:%M %p"));
158− break;
159−
160− case DATE_PROXIMITY_TODAY:
161− /* Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
162− This format string is used for showing, on a 12-hour clock, times that happened today.
163− en_US example: "%l:%M %p" --> "1:00 PM" */
164− g_string_assign (ret, dgettext_datetime("%l:%M %p"));
165− break;
166−
167− case DATE_PROXIMITY_TOMORROW:
168− /* Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
169− This format string is used for showing, on a 12-hour clock, events/appointments that happen tomorrow.
170− (\u2003 is a unicode em space which is slightly wider than a normal space.)
171− en_US example: "Tomorrow\u2003%l:%M %p" --> "Tomorrow 1:00 PM" */
172− g_string_assign (ret, dgettext_datetime("Tomorrow\u2003%l:%M %p"));
173− break;
174−
175− case DATE_PROXIMITY_LAST_WEEK:
176− case DATE_PROXIMITY_NEXT_WEEK:
177− /* Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
178− This format string is used for showing, on a 12-hour clock, times that happened in the last week.
179− (\u2003 is a unicode em space which is slightly wider than a normal space.)
180− en_US example: "%a\u2003%l:%M %p" --> "Fri 1:00 PM" */
181− g_string_assign (ret, dgettext_datetime("%a\u2003%l:%M %p"));
182− break;
183−
184− case DATE_PROXIMITY_FAR:
185− /* Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
186− This format string is used for showing, on a 12-hour clock, times that happened before a week from now.
187− (\u2003 is a unicode em space which is slightly wider than a normal space.)
188− en_US example: "%a %b %d\u2003%l:%M %p" --> "Fri Oct 31 1:00 PM"
189− en_GB example: "%a %d %b\u2003%l:%M %p" --> "Fri 31 Oct 1:00 PM" */
190− g_string_assign (ret, dgettext_datetime("%a %d %b\u2003%l:%M %p"));
191− break;
192− }
193− } else {
194− switch (prox) {
195−
196− case DATE_PROXIMITY_YESTERDAY:
197− /* Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
198− This format string is used for showing, on a 24-hour clock, times that happen yesterday.
199− (\u2003 is a unicode em space which is slightly wider than a normal space.)
200− en_US example: "Yesterday\u2003%l:%M %p" --> "Yesterday 13:00" */
201− g_string_assign (ret, dgettext_datetime("Yesterday\u2003%H:%M"));
202− break;
203−
204− case DATE_PROXIMITY_TODAY:
205− /* Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
206− This format string is used for showing, on a 24-hour clock, times that happened today.
207− en_US example: "%H:%M" --> "13:00" */
208− g_string_assign (ret, dgettext_datetime("%H:%M"));
209− break;
210−
211− case DATE_PROXIMITY_TOMORROW:
212− /* Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
213− This format string is used for showing, on a 24-hour clock, events/appointments that happen tomorrow.
214− (\u2003 is a unicode em space which is slightly wider than a normal space.)
215− en_US example: "Tomorrow\u2003%l:%M %p" --> "Tomorrow 13:00" */
216− g_string_assign (ret, dgettext_datetime("Tomorrow\u2003%H:%M"));
217− break;
218−
219− case DATE_PROXIMITY_LAST_WEEK:
220− case DATE_PROXIMITY_NEXT_WEEK:
221− /* Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
222− This format string is used for showing, on a 24-hour clock, times that happened in the last week.
223− (\u2003 is a unicode em space which is slightly wider than a normal space.)
224− en_US example: "%a\u2003%H:%M" --> "Fri 13:00" */
225− g_string_assign (ret, dgettext_datetime("%a\u2003%H:%M"));
226− break;
227−
228− case DATE_PROXIMITY_FAR:
229− /* Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
230− This format string is used for showing, on a 24-hour clock, times that happened before a week from now.
231− (\u2003 is a unicode em space which is slightly wider than a normal space.)
232− en_US example: "%a %b %d\u2003%H:%M" --> "Fri Oct 31 13:00"
233− en_GB example: "%a %d %b\u2003%H:%M" --> "Fri 31 Oct 13:00" */
234− g_string_assign (ret, dgettext_datetime("%a %d %b\u2003%H:%M"));
235− break;
236− }
237− }
238− }
239−
240− return g_string_free (ret, FALSE);
241−}
242−
243−QString RelativeTimeFormatter::format() const
244−{
245− GDateTime* now = g_date_time_new_now_local();
246− if (!now) { return QString(); }
247−
248− GDateTime* then = g_date_time_new_from_unix_local(time());
249− if (!then) { return QString(); }
250−
251− char* time_format = generate_full_format_string_at_time(now, then);
252−
253− QString str(QString::fromUtf8(time_format));
254− g_free(time_format);
255−
256− g_date_time_unref(now);
257− g_date_time_unref(then);
258−
259− return str;
260−}
plugins/Utils/timeformatter.cppdeleted−206
@@ -1,206 +0,0 @@
1−/*
2− * Copyright 2013 Canonical Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− *
16− * Author: Lars Uebernickel <lars.uebernickel@canonical.com>
17− */
18−
19−#include "timeformatter.h"
20−
21−#include <gio/gio.h>
22−#include <QDateTime>
23−
24−struct TimeFormatterPrivate
25−{
26− TimeFormatter *formatter;
27−
28− QString format;
29− QString timeString;
30− qint64 time;
31−
32− GDBusConnection *system_bus;
33− guint subscription_id;
34− GCancellable *cancellable;
35−};
36−
37−static void
38−timedate1_properties_changed (GDBusConnection *connection,
39− const gchar *sender_name,
40− const gchar *object_path,
41− const gchar *interface_name,
42− const gchar *signal_name,
43− GVariant *parameters,
44− gpointer user_data)
45−{
46− Q_UNUSED(connection);
47− Q_UNUSED(sender_name);
48− Q_UNUSED(object_path);
49− Q_UNUSED(interface_name);
50− Q_UNUSED(signal_name);
51−
52− TimeFormatterPrivate *priv = (TimeFormatterPrivate *)user_data;
53− GVariant *changed;
54− GVariantIter *iter;
55− const gchar *name;
56−
57− if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(sa{sv}as)")))
58− return;
59−
60− g_variant_get (parameters, "(s@a{sv}as)", nullptr, &changed, &iter);
61−
62− if (g_variant_lookup (changed, "Timezone", "s", nullptr)) {
63− priv->formatter->update();
64− }
65− else {
66− while (g_variant_iter_next (iter, "&s", &name)) {
67− if (g_str_equal (name, "Timezone")) {
68− priv->formatter->update();
69− break;
70− }
71− }
72− }
73−
74− g_variant_unref (changed);
75− g_variant_iter_free (iter);
76−}
77−
78−static void
79−got_bus(GObject *object, GAsyncResult *result, gpointer user_data)
80−{
81− Q_UNUSED(object);
82−
83− TimeFormatterPrivate *priv = (TimeFormatterPrivate *)user_data;
84− GError *error = nullptr;
85−
86− priv->system_bus = g_bus_get_finish (result, &error);
87− if (priv->system_bus == nullptr) {
88− if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
89− qWarning("TimeFormatter: cannot connect to the system bus: %s", error->message);
90− g_error_free (error);
91− return;
92− }
93−
94− /* Listen to the PropertiesChanged on the org.freedesktop.timedate1
95− * interface from any sender. In practice, this signal will only be sent
96− * from timedated (we can trust other processes on the system bus to behave
97− * nicely). That way, we don't have to watch timedated's well-known name
98− * and keep the process alive.
99− */
100− priv->subscription_id = g_dbus_connection_signal_subscribe (priv->system_bus,
101− nullptr, /* sender */
102− "org.freedesktop.DBus.Properties",
103− "PropertiesChanged",
104− nullptr,
105− "org.freedesktop.timedate1",
106− G_DBUS_SIGNAL_FLAGS_NONE,
107− timedate1_properties_changed,
108− priv, nullptr);
109−}
110−
111−TimeFormatter::TimeFormatter(QObject *parent): QObject(parent)
112−{
113− priv = new TimeFormatterPrivate;
114− priv->formatter = this;
115− priv->time = 0;
116− priv->format = QStringLiteral("yyyy-MM-dd hh:mm");
117− priv->system_bus = nullptr;
118− priv->subscription_id = 0;
119− priv->cancellable = g_cancellable_new ();
120−
121− g_bus_get (G_BUS_TYPE_SYSTEM, priv->cancellable, got_bus, priv);
122−}
123−
124−TimeFormatter::TimeFormatter(const QString &initialFormat, QObject *parent): TimeFormatter(parent)
125−{
126− priv->format = initialFormat;
127−}
128−
129−TimeFormatter::~TimeFormatter()
130−{
131− if (priv->system_bus) {
132− g_dbus_connection_signal_unsubscribe (priv->system_bus, priv->subscription_id);
133− g_object_unref (priv->system_bus);
134− }
135−
136− g_cancellable_cancel (priv->cancellable);
137− g_object_unref (priv->cancellable);
138−}
139−
140−QString TimeFormatter::format() const
141−{
142− return priv->format;
143−}
144−
145−QString TimeFormatter::timeString() const
146−{
147− return priv->timeString;
148−}
149−
150−qint64 TimeFormatter::time() const
151−{
152− return priv->time;
153−}
154−
155−void TimeFormatter::setFormat(const QString &format)
156−{
157− if (priv->format != format) {
158− priv->format = format;
159− Q_EMIT formatChanged(priv->format);
160− update();
161− }
162−}
163−
164−void TimeFormatter::setTime(qint64 time)
165−{
166− if (priv->time != time) {
167− priv->time = time;
168− Q_EMIT timeChanged(priv->time);
169− update();
170− }
171−}
172−
173−void TimeFormatter::update()
174−{
175− priv->timeString = formatTime();
176− Q_EMIT timeStringChanged(priv->timeString);
177−}
178−
179−QString TimeFormatter::formatTime() const
180−{
181− return QDateTime::fromMSecsSinceEpoch(time() / 1000).toString(format());
182−}
183−
184−GDateTimeFormatter::GDateTimeFormatter(QObject* parent)
185−: TimeFormatter(QStringLiteral("%d-%m-%Y %I:%M%p"), parent)
186−{
187−}
188−
189−QString GDateTimeFormatter::formatTime() const
190−{
191− gchar* time_string;
192− GDateTime* datetime;
193− QByteArray formatBytes = format().toUtf8();
194−
195− datetime = g_date_time_new_from_unix_local(time());
196− if (!datetime) {
197− return QLatin1String("");
198− }
199−
200− time_string = g_date_time_format(datetime, formatBytes.constData());
201− QString formattedTime(QString::fromUtf8(time_string));
202−
203− g_free(time_string);
204− g_date_time_unref(datetime);
205− return formattedTime;
206−}
plugins/Utils/timeformatter.hdeleted−68
@@ -1,68 +0,0 @@
1−/*
2− * Copyright 2013 Canonical Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− *
16− * Author: Lars Uebernickel <lars.uebernickel@canonical.com>
17− */
18−
19−#ifndef TIME_FORMATTER_H
20−#define TIME_FORMATTER_H
21−
22−#include <QObject>
23−
24−// TODO - bug #1260728
25−class TimeFormatter : public QObject
26−{
27− Q_OBJECT
28− Q_PROPERTY(QString format READ format WRITE setFormat NOTIFY formatChanged)
29− Q_PROPERTY(QString timeString READ timeString NOTIFY timeStringChanged)
30− Q_PROPERTY(qint64 time READ time WRITE setTime NOTIFY timeChanged)
31−
32−public:
33− TimeFormatter(QObject *parent = 0);
34− virtual ~TimeFormatter();
35−
36− virtual QString format() const;
37− QString timeString() const;
38− qint64 time() const;
39−
40− void setFormat(const QString &format);
41− void setTime(qint64 time);
42−
43− void update();
44−
45−Q_SIGNALS:
46− void formatChanged(const QString &format);
47− void timeStringChanged(const QString &timeString);
48− void timeChanged(qint64 time);
49−
50−protected:
51− TimeFormatter(const QString &initialFormat, QObject *parent = 0);
52−
53− virtual QString formatTime() const;
54−
55−private:
56− struct TimeFormatterPrivate *priv;
57−};
58−
59−class GDateTimeFormatter : public TimeFormatter
60−{
61−public:
62− GDateTimeFormatter(QObject *parent = 0);
63−
64−protected:
65− QString formatTime() const override;
66−};
67−
68−#endif
plugins/Utils/timezoneFormatter.cpp+1−1
@@ -29,7 +29,7 @@ QString TimezoneFormatter::currentTimeInTimezone(const QVariant &tzId) const
29 if (tz.isValid()) {
29 if (tz.isValid()) {
30 const QDateTime now = QDateTime::currentDateTime().toTimeZone(tz);
30 const QDateTime now = QDateTime::currentDateTime().toTimeZone(tz);
31 // return locale-aware string in the form "day, hh:mm", e.g. "Mon 14:30" or "Mon 1:30 pm"
31 // return locale-aware string in the form "day, hh:mm", e.g. "Mon 14:30" or "Mon 1:30 pm"
32− return QStringLiteral("%1 %2").arg(now.toString("ddd")).arg(now.time().toString(Qt::DefaultLocaleShortDate));
32+ return QStringLiteral("%1 %2").arg(now.toString(QStringLiteral("ddd"))).arg(now.time().toString(Qt::DefaultLocaleShortDate));
33 }
33 }
34 return QString();
34 return QString();
35}
35}
plugins/Utils/windowstatestorage.cpp+61−22
@@ -47,26 +47,38 @@ WindowStateStorage::~WindowStateStorage()
47 m_db.close();
47 m_db.close();
48}
48}
49
49
50−void WindowStateStorage::saveGeometry(const QString &windowId, const QRect &rect)
50+void WindowStateStorage::saveState(const QString &windowId, WindowStateStorage::WindowState state)
51{
51{
52− QMutexLocker mutexLocker(&s_mutex);
52+ const QString queryString = QStringLiteral("INSERT OR REPLACE INTO state (windowId, state) values ('%1', '%2');")
53+ .arg(windowId)
54+ .arg((int)state);
55+
56+ saveValue(queryString);
57+}
58+
59+WindowStateStorage::WindowState WindowStateStorage::getState(const QString &windowId, WindowStateStorage::WindowState defaultValue) const
60+{
61+ const QString queryString = QStringLiteral("SELECT * FROM state WHERE windowId = '%1';")
62+ .arg(windowId);
53
63
64+ QSqlQuery query = getValue(queryString);
65+
66+ if (!query.first()) {
67+ return defaultValue;
68+ }
69+ return (WindowState)query.value("state").toInt();
70+}
71+
72+void WindowStateStorage::saveGeometry(const QString &windowId, const QRect &rect)
73+{
54− QString queryString = QStringLiteral("INSERT OR REPLACE INTO geometry (windowId, x, y, width, height) values ('%1', '%2', '%3', '%4', '%5');")
74+ const QString queryString = QStringLiteral("INSERT OR REPLACE INTO geometry (windowId, x, y, width, height) values ('%1', '%2', '%3', '%4', '%5');")
55 .arg(windowId)
75 .arg(windowId)
56 .arg(rect.x())
76 .arg(rect.x())
57 .arg(rect.y())
77 .arg(rect.y())
58 .arg(rect.width())
78 .arg(rect.width())
59 .arg(rect.height());
79 .arg(rect.height());
60
80
61− QFuture<void> future = QtConcurrent::run(executeAsyncQuery, queryString);
81+ saveValue(queryString);
62− m_asyncQueries.append(future);
63−
64− QFutureWatcher<void> *futureWatcher = new QFutureWatcher<void>();
65− futureWatcher->setFuture(future);
66− connect(futureWatcher, &QFutureWatcher<void>::finished,
67− this,
68− [=](){ m_asyncQueries.removeAll(futureWatcher->future());
69− futureWatcher->deleteLater(); });
70}
82}
71
83
72void WindowStateStorage::executeAsyncQuery(const QString &queryString)
84void WindowStateStorage::executeAsyncQuery(const QString &queryString)
@@ -82,20 +94,13 @@ void WindowStateStorage::executeAsyncQuery(const QString &queryString)
82 }
94 }
83}
95}
84
96
85−QRect WindowStateStorage::getGeometry(const QString &windowId, const QRect &defaultValue)
97+QRect WindowStateStorage::getGeometry(const QString &windowId, const QRect &defaultValue) const
86{
98{
87− QMutexLocker l(&s_mutex);
88 QString queryString = QStringLiteral("SELECT * FROM geometry WHERE windowId = '%1';")
99 QString queryString = QStringLiteral("SELECT * FROM geometry WHERE windowId = '%1';")
89 .arg(windowId);
100 .arg(windowId);
90− QSqlQuery query;
91
101
92− bool ok = query.exec(queryString);
102+ QSqlQuery query = getValue(queryString);
93− if (!ok) {
103+
94− qWarning() << "Error retrieving window state for" << windowId
95− << "Driver error:" << query.lastError().driverText()
96− << "Database error:" << query.lastError().databaseText();
97− return defaultValue;
98− }
99 if (!query.first()) {
104 if (!query.first()) {
100 return defaultValue;
105 return defaultValue;
101 }
106 }
@@ -114,4 +119,38 @@ void WindowStateStorage::initdb()
114 QSqlQuery query;
119 QSqlQuery query;
115 query.exec(QStringLiteral("CREATE TABLE geometry(windowId TEXT UNIQUE, x INTEGER, y INTEGER, width INTEGER, height INTEGER);"));
120 query.exec(QStringLiteral("CREATE TABLE geometry(windowId TEXT UNIQUE, x INTEGER, y INTEGER, width INTEGER, height INTEGER);"));
116 }
121 }
122+
123+ if (!m_db.tables().contains("state")) {
124+ QSqlQuery query;
125+ query.exec("CREATE TABLE state(windowId TEXT UNIQUE, state INTEGER);");
126+ }
127+}
128+
129+void WindowStateStorage::saveValue(const QString &queryString)
130+{
131+ QMutexLocker mutexLocker(&s_mutex);
132+
133+ QFuture<void> future = QtConcurrent::run(executeAsyncQuery, queryString);
134+ m_asyncQueries.append(future);
135+
136+ QFutureWatcher<void> *futureWatcher = new QFutureWatcher<void>();
137+ futureWatcher->setFuture(future);
138+ connect(futureWatcher, &QFutureWatcher<void>::finished,
139+ this,
140+ [=](){ m_asyncQueries.removeAll(futureWatcher->future());
141+ futureWatcher->deleteLater(); });
142+}
143+
144+QSqlQuery WindowStateStorage::getValue(const QString &queryString) const
145+{
146+ QMutexLocker l(&s_mutex);
147+ QSqlQuery query;
148+
149+ bool ok = query.exec(queryString);
150+ if (!ok) {
151+ qWarning() << "Error retrieving database query:" << queryString
152+ << "Driver error:" << query.lastError().driverText()
153+ << "Database error:" << query.lastError().databaseText();
154+ }
155+ return query;
117}
156}
plugins/Utils/windowstatestorage.h+13−1
@@ -22,16 +22,28 @@
22class WindowStateStorage: public QObject
22class WindowStateStorage: public QObject
23{
23{
24 Q_OBJECT
24 Q_OBJECT
25+ Q_ENUMS(WindowState)
25public:
26public:
27+ enum WindowState {
28+ WindowStateNormal,
29+ WindowStateMaximized
30+ };
31+
26 WindowStateStorage(QObject *parent = 0);
32 WindowStateStorage(QObject *parent = 0);
27 virtual ~WindowStateStorage();
33 virtual ~WindowStateStorage();
28
34
35+ Q_INVOKABLE void saveState(const QString &windowId, WindowState state);
36+ Q_INVOKABLE WindowState getState(const QString &windowId, WindowState defaultValue) const;
37+
29 Q_INVOKABLE void saveGeometry(const QString &windowId, const QRect &rect);
38 Q_INVOKABLE void saveGeometry(const QString &windowId, const QRect &rect);
30− Q_INVOKABLE QRect getGeometry(const QString &windowId, const QRect &defaultValue);
39+ Q_INVOKABLE QRect getGeometry(const QString &windowId, const QRect &defaultValue) const;
31
40
32private:
41private:
33 void initdb();
42 void initdb();
34
43
44+ void saveValue(const QString &queryString);
45+ QSqlQuery getValue(const QString &queryString) const;
46+
35 static void executeAsyncQuery(const QString &queryString);
47 static void executeAsyncQuery(const QString &queryString);
36 static QMutex s_mutex;
48 static QMutex s_mutex;
37
49
po/am.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=2; plural=n > 1;\n"
17"Plural-Forms: nplurals=2; plural=n > 1;\n"
18−"X-Launchpad-Export-Date: 2015-09-30 05:42+0000\n"
18+"X-Launchpad-Export-Date: 2015-10-16 05:57+0000\n"
19−"X-Generator: Launchpad (build 17768)\n"
19+"X-Generator: Launchpad (build 17812)\n"
20
20
21#: plugins/IntegratedLightDM/Greeter.cpp:112
21#: plugins/IntegratedLightDM/Greeter.cpp:112
22msgid "Password: "
22msgid "Password: "
po/ar.po+2−2
@@ -16,8 +16,8 @@ msgstr ""
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n % 100 >= "
17"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n % 100 >= "
18"3 && n % 100 <= 10 ? 3 : n % 100 >= 11 && n % 100 <= 99 ? 4 : 5;\n"
18"3 && n % 100 <= 10 ? 3 : n % 100 >= 11 && n % 100 <= 99 ? 4 : 5;\n"
19−"X-Launchpad-Export-Date: 2015-09-30 05:42+0000\n"
19+"X-Launchpad-Export-Date: 2015-10-16 05:57+0000\n"
20−"X-Generator: Launchpad (build 17768)\n"
20+"X-Generator: Launchpad (build 17812)\n"
21
21
22#: plugins/IntegratedLightDM/Greeter.cpp:112
22#: plugins/IntegratedLightDM/Greeter.cpp:112
23msgid "Password: "
23msgid "Password: "
po/ast.po+26−26
@@ -8,15 +8,15 @@ msgstr ""
8"Project-Id-Version: unity8\n"
8"Project-Id-Version: unity8\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10"POT-Creation-Date: 2015-09-16 00:49+0200\n"
10"POT-Creation-Date: 2015-09-16 00:49+0200\n"
11−"PO-Revision-Date: 2015-06-11 23:39+0000\n"
11+"PO-Revision-Date: 2015-10-06 12:07+0000\n"
12−"Last-Translator: enolp <enolp@softastur.org>\n"
12+"Last-Translator: Xuacu Saturio <xuacusk8@gmail.com>\n"
13"Language-Team: Asturian <ast@li.org>\n"
13"Language-Team: Asturian <ast@li.org>\n"
14"MIME-Version: 1.0\n"
14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2015-09-30 05:42+0000\n"
18+"X-Launchpad-Export-Date: 2015-10-16 05:57+0000\n"
19−"X-Generator: Launchpad (build 17768)\n"
19+"X-Generator: Launchpad (build 17812)\n"
20
20
21#: plugins/IntegratedLightDM/Greeter.cpp:112
21#: plugins/IntegratedLightDM/Greeter.cpp:112
22msgid "Password: "
22msgid "Password: "
@@ -29,7 +29,7 @@ msgstr "Anclar atayu"
29
29
30#: plugins/Unity/Launcher/launcheritem.cpp:52
30#: plugins/Unity/Launcher/launcheritem.cpp:52
31msgid "Quit"
31msgid "Quit"
32−msgstr ""
32+msgstr "Colar"
33
33
34#: plugins/Unity/Launcher/launcheritem.cpp:106
34#: plugins/Unity/Launcher/launcheritem.cpp:106
35msgid "Unpin shortcut"
35msgid "Unpin shortcut"
@@ -41,14 +41,14 @@ msgstr "Desanclar atayu"
41#. en_US example: "Yesterday\u2003%l:%M %p" --> "Yesterday 1:00 PM"
41#. en_US example: "Yesterday\u2003%l:%M %p" --> "Yesterday 1:00 PM"
42#: plugins/Utils/relativetimeformatter.cpp:157
42#: plugins/Utils/relativetimeformatter.cpp:157
43msgid "Yesterday %l:%M %p"
43msgid "Yesterday %l:%M %p"
44−msgstr ""
44+msgstr "Ayeri %l:%M %p"
45
45
46#. Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
46#. Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
47#. This format string is used for showing, on a 12-hour clock, times that happened today.
47#. This format string is used for showing, on a 12-hour clock, times that happened today.
48#. en_US example: "%l:%M %p" --> "1:00 PM"
48#. en_US example: "%l:%M %p" --> "1:00 PM"
49#: plugins/Utils/relativetimeformatter.cpp:164
49#: plugins/Utils/relativetimeformatter.cpp:164
50msgid "%l:%M %p"
50msgid "%l:%M %p"
51−msgstr ""
51+msgstr "%l:%M %p"
52
52
53#. Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
53#. Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
54#. This format string is used for showing, on a 12-hour clock, events/appointments that happen tomorrow.
54#. This format string is used for showing, on a 12-hour clock, events/appointments that happen tomorrow.
@@ -56,7 +56,7 @@ msgstr ""
56#. en_US example: "Tomorrow\u2003%l:%M %p" --> "Tomorrow 1:00 PM"
56#. en_US example: "Tomorrow\u2003%l:%M %p" --> "Tomorrow 1:00 PM"
57#: plugins/Utils/relativetimeformatter.cpp:172
57#: plugins/Utils/relativetimeformatter.cpp:172
58msgid "Tomorrow %l:%M %p"
58msgid "Tomorrow %l:%M %p"
59−msgstr ""
59+msgstr "Mañana %l:%M %p"
60
60
61#. Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
61#. Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
62#. This format string is used for showing, on a 12-hour clock, times that happened in the last week.
62#. This format string is used for showing, on a 12-hour clock, times that happened in the last week.
@@ -64,7 +64,7 @@ msgstr ""
64#. en_US example: "%a\u2003%l:%M %p" --> "Fri 1:00 PM"
64#. en_US example: "%a\u2003%l:%M %p" --> "Fri 1:00 PM"
65#: plugins/Utils/relativetimeformatter.cpp:181
65#: plugins/Utils/relativetimeformatter.cpp:181
66msgid "%a %l:%M %p"
66msgid "%a %l:%M %p"
67−msgstr ""
67+msgstr "%a %l:%M %p"
68
68
69#. Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
69#. Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
70#. This format string is used for showing, on a 12-hour clock, times that happened before a week from now.
70#. This format string is used for showing, on a 12-hour clock, times that happened before a week from now.
@@ -73,7 +73,7 @@ msgstr ""
73#. en_GB example: "%a %b %d\u2003%l:%M %p" --> "Fri 31 Oct 1:00 PM"
73#. en_GB example: "%a %b %d\u2003%l:%M %p" --> "Fri 31 Oct 1:00 PM"
74#: plugins/Utils/relativetimeformatter.cpp:190
74#: plugins/Utils/relativetimeformatter.cpp:190
75msgid "%a %d %b %l:%M %p"
75msgid "%a %d %b %l:%M %p"
76−msgstr ""
76+msgstr "%a %b %d %l:%M %p"
77
77
78#. Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
78#. Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
79#. This format string is used for showing, on a 24-hour clock, times that happen yesterday.
79#. This format string is used for showing, on a 24-hour clock, times that happen yesterday.
@@ -81,14 +81,14 @@ msgstr ""
81#. en_US example: "Yesterday\u2003%l:%M %p" --> "Yesterday 13:00"
81#. en_US example: "Yesterday\u2003%l:%M %p" --> "Yesterday 13:00"
82#: plugins/Utils/relativetimeformatter.cpp:201
82#: plugins/Utils/relativetimeformatter.cpp:201
83msgid "Yesterday %H:%M"
83msgid "Yesterday %H:%M"
84−msgstr ""
84+msgstr "Ayeri %H:%M"
85
85
86#. Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
86#. Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
87#. This format string is used for showing, on a 24-hour clock, times that happened today.
87#. This format string is used for showing, on a 24-hour clock, times that happened today.
88#. en_US example: "%H:%M" --> "13:00"
88#. en_US example: "%H:%M" --> "13:00"
89#: plugins/Utils/relativetimeformatter.cpp:208
89#: plugins/Utils/relativetimeformatter.cpp:208
90msgid "%H:%M"
90msgid "%H:%M"
91−msgstr ""
91+msgstr "%H:%M"
92
92
93#. Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
93#. Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
94#. This format string is used for showing, on a 24-hour clock, events/appointments that happen tomorrow.
94#. This format string is used for showing, on a 24-hour clock, events/appointments that happen tomorrow.
@@ -96,7 +96,7 @@ msgstr ""
96#. en_US example: "Tomorrow\u2003%l:%M %p" --> "Tomorrow 13:00"
96#. en_US example: "Tomorrow\u2003%l:%M %p" --> "Tomorrow 13:00"
97#: plugins/Utils/relativetimeformatter.cpp:216
97#: plugins/Utils/relativetimeformatter.cpp:216
98msgid "Tomorrow %H:%M"
98msgid "Tomorrow %H:%M"
99−msgstr ""
99+msgstr "Mañana %H:%M"
100
100
101#. Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
101#. Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
102#. This format string is used for showing, on a 24-hour clock, times that happened in the last week.
102#. This format string is used for showing, on a 24-hour clock, times that happened in the last week.
@@ -104,7 +104,7 @@ msgstr ""
104#. en_US example: "%a\u2003%H:%M" --> "Fri 13:00"
104#. en_US example: "%a\u2003%H:%M" --> "Fri 13:00"
105#: plugins/Utils/relativetimeformatter.cpp:225
105#: plugins/Utils/relativetimeformatter.cpp:225
106msgid "%a %H:%M"
106msgid "%a %H:%M"
107−msgstr ""
107+msgstr "%a %H:%M"
108
108
109#. Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
109#. Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
110#. This format string is used for showing, on a 24-hour clock, times that happened before a week from now.
110#. This format string is used for showing, on a 24-hour clock, times that happened before a week from now.
@@ -113,7 +113,7 @@ msgstr ""
113#. en_GB example: "%a %b %d\u2003%H:%M" --> "Fri 31 Oct 13:00"
113#. en_GB example: "%a %b %d\u2003%H:%M" --> "Fri 31 Oct 13:00"
114#: plugins/Utils/relativetimeformatter.cpp:234
114#: plugins/Utils/relativetimeformatter.cpp:234
115msgid "%a %d %b %H:%M"
115msgid "%a %d %b %H:%M"
116−msgstr ""
116+msgstr "%a %b %d %H:%M"
117
117
118#: qml/Components/DelayedLockscreen.qml:49
118#: qml/Components/DelayedLockscreen.qml:49
119msgid "Device Locked"
119msgid "Device Locked"
@@ -198,7 +198,7 @@ msgstr "Sí"
198#: qml/Components/Dialogs.qml:203
198#: qml/Components/Dialogs.qml:203
199msgctxt "Title: Power off/Restart dialog"
199msgctxt "Title: Power off/Restart dialog"
200msgid "Power"
200msgid "Power"
201−msgstr ""
201+msgstr "Apagáu"
202
202
203#: qml/Components/Dialogs.qml:204
203#: qml/Components/Dialogs.qml:204
204msgid ""
204msgid ""
@@ -378,7 +378,7 @@ msgstr "Sentímoslo, contraseña incorreuta"
378#: qml/Greeter/NarrowView.qml:121
378#: qml/Greeter/NarrowView.qml:121
379msgctxt "passphrase"
379msgctxt "passphrase"
380msgid "Please re-enter"
380msgid "Please re-enter"
381−msgstr ""
381+msgstr "Vuelve a escribila"
382
382
383#: qml/Greeter/NarrowView.qml:122
383#: qml/Greeter/NarrowView.qml:122
384msgid "Sorry, incorrect passcode"
384msgid "Sorry, incorrect passcode"
@@ -404,32 +404,32 @@ msgstr "Nun ta reproduciéndose nada"
404#, qt-format
404#, qt-format
405msgid "%1 hour"
405msgid "%1 hour"
406msgid_plural "%1 hours"
406msgid_plural "%1 hours"
407−msgstr[0] ""
407+msgstr[0] "%1 hora"
408−msgstr[1] ""
408+msgstr[1] "%1 hores"
409
409
410#: qml/Panel/Indicators/MenuItemFactory.qml:851
410#: qml/Panel/Indicators/MenuItemFactory.qml:851
411#, qt-format
411#, qt-format
412msgid "%1 minute"
412msgid "%1 minute"
413msgid_plural "%1 minutes"
413msgid_plural "%1 minutes"
414−msgstr[0] ""
414+msgstr[0] "%1 minutu"
415−msgstr[1] ""
415+msgstr[1] "%1 minutos"
416
416
417#: qml/Panel/Indicators/MenuItemFactory.qml:856
417#: qml/Panel/Indicators/MenuItemFactory.qml:856
418#, qt-format
418#, qt-format
419msgid "%1 second"
419msgid "%1 second"
420msgid_plural "%1 seconds"
420msgid_plural "%1 seconds"
421−msgstr[0] ""
421+msgstr[0] "%1 segundu"
422−msgstr[1] ""
422+msgstr[1] "%1 segundos"
423
423
424#: qml/Panel/Indicators/MenuItemFactory.qml:859
424#: qml/Panel/Indicators/MenuItemFactory.qml:859
425msgid "0 seconds"
425msgid "0 seconds"
426−msgstr ""
426+msgstr "0 segundos"
427
427
428#. Translators: String like "1 hour, 2 minutes, 3 seconds remaining"
428#. Translators: String like "1 hour, 2 minutes, 3 seconds remaining"
429#: qml/Panel/Indicators/MenuItemFactory.qml:861
429#: qml/Panel/Indicators/MenuItemFactory.qml:861
430#, qt-format
430#, qt-format
431msgid "%1 remaining"
431msgid "%1 remaining"
432−msgstr ""
432+msgstr "Queden %1"
433
433
434#: qml/Panel/Indicators/MenuItemFactory.qml:867
434#: qml/Panel/Indicators/MenuItemFactory.qml:867
435msgid "In queue…"
435msgid "In queue…"
@@ -462,7 +462,7 @@ msgstr "Responder"
462
462
463#: qml/Panel/Indicators/MessageMenuItemFactory.qml:204
463#: qml/Panel/Indicators/MessageMenuItemFactory.qml:204
464msgid "Call back"
464msgid "Call back"
465−msgstr ""
465+msgstr "Devolver llamada"
466
466
467#: qml/Panel/Indicators/ModemInfoItem.qml:105
467#: qml/Panel/Indicators/ModemInfoItem.qml:105
468msgid "Unlock SIM"
468msgid "Unlock SIM"
po/az.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2015-09-30 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2015-10-16 05:57+0000\n"
19−"X-Generator: Launchpad (build 17768)\n"
19+"X-Generator: Launchpad (build 17812)\n"
20
20
21#: plugins/IntegratedLightDM/Greeter.cpp:112
21#: plugins/IntegratedLightDM/Greeter.cpp:112
22msgid "Password: "
22msgid "Password: "
po/be.po+2−2
@@ -16,8 +16,8 @@ msgstr ""
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
17"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
18"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
18"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
19−"X-Launchpad-Export-Date: 2015-09-30 05:43+0000\n"
19+"X-Launchpad-Export-Date: 2015-10-16 05:57+0000\n"
20−"X-Generator: Launchpad (build 17768)\n"
20+"X-Generator: Launchpad (build 17812)\n"
21
21
22#: plugins/IntegratedLightDM/Greeter.cpp:112
22#: plugins/IntegratedLightDM/Greeter.cpp:112
23msgid "Password: "
23msgid "Password: "
po/bg.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2015-09-30 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2015-10-16 05:57+0000\n"
19−"X-Generator: Launchpad (build 17768)\n"
19+"X-Generator: Launchpad (build 17812)\n"
20
20
21#: plugins/IntegratedLightDM/Greeter.cpp:112
21#: plugins/IntegratedLightDM/Greeter.cpp:112
22msgid "Password: "
22msgid "Password: "
po/br.po+5−5
@@ -8,15 +8,15 @@ msgstr ""
8"Project-Id-Version: unity8\n"
8"Project-Id-Version: unity8\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10"POT-Creation-Date: 2015-09-16 00:49+0200\n"
10"POT-Creation-Date: 2015-09-16 00:49+0200\n"
11−"PO-Revision-Date: 2015-08-25 14:12+0000\n"
11+"PO-Revision-Date: 2015-10-05 06:47+0000\n"
12"Last-Translator: Fohanno Thierry <thierry.fohanno@ofis-bzh.org>\n"
12"Last-Translator: Fohanno Thierry <thierry.fohanno@ofis-bzh.org>\n"
13"Language-Team: Breton <br@li.org>\n"
13"Language-Team: Breton <br@li.org>\n"
14"MIME-Version: 1.0\n"
14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=2; plural=n > 1;\n"
17"Plural-Forms: nplurals=2; plural=n > 1;\n"
18−"X-Launchpad-Export-Date: 2015-09-30 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2015-10-16 05:57+0000\n"
19−"X-Generator: Launchpad (build 17768)\n"
19+"X-Generator: Launchpad (build 17812)\n"
20
20
21#: plugins/IntegratedLightDM/Greeter.cpp:112
21#: plugins/IntegratedLightDM/Greeter.cpp:112
22msgid "Password: "
22msgid "Password: "
@@ -29,7 +29,7 @@ msgstr "Spilhennañ ar verradenn"
29
29
30#: plugins/Unity/Launcher/launcheritem.cpp:52
30#: plugins/Unity/Launcher/launcheritem.cpp:52
31msgid "Quit"
31msgid "Quit"
32−msgstr ""
32+msgstr "Mont kuit"
33
33
34#: plugins/Unity/Launcher/launcheritem.cpp:106
34#: plugins/Unity/Launcher/launcheritem.cpp:106
35msgid "Unpin shortcut"
35msgid "Unpin shortcut"
@@ -465,7 +465,7 @@ msgstr "Respont"
465
465
466#: qml/Panel/Indicators/MessageMenuItemFactory.qml:204
466#: qml/Panel/Indicators/MessageMenuItemFactory.qml:204
467msgid "Call back"
467msgid "Call back"
468−msgstr ""
468+msgstr "Gervel en-dro"
469
469
470#: qml/Panel/Indicators/ModemInfoItem.qml:105
470#: qml/Panel/Indicators/ModemInfoItem.qml:105
471msgid "Unlock SIM"
471msgid "Unlock SIM"
po/bs.po+2−2
@@ -16,8 +16,8 @@ msgstr ""
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
17"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
18"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
18"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
19−"X-Launchpad-Export-Date: 2015-09-30 05:43+0000\n"
19+"X-Launchpad-Export-Date: 2015-10-16 05:57+0000\n"
20−"X-Generator: Launchpad (build 17768)\n"
20+"X-Generator: Launchpad (build 17812)\n"
21
21
22#: plugins/IntegratedLightDM/Greeter.cpp:112
22#: plugins/IntegratedLightDM/Greeter.cpp:112
23msgid "Password: "
23msgid "Password: "
po/ca.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2015-09-30 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2015-10-16 05:57+0000\n"
19−"X-Generator: Launchpad (build 17768)\n"
19+"X-Generator: Launchpad (build 17812)\n"
20
20
21#: plugins/IntegratedLightDM/Greeter.cpp:112
21#: plugins/IntegratedLightDM/Greeter.cpp:112
22msgid "Password: "
22msgid "Password: "
po/ca@valencia.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2015-09-30 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2015-10-16 05:58+0000\n"
19−"X-Generator: Launchpad (build 17768)\n"
19+"X-Generator: Launchpad (build 17812)\n"
20
20
21#: plugins/IntegratedLightDM/Greeter.cpp:112
21#: plugins/IntegratedLightDM/Greeter.cpp:112
22msgid "Password: "
22msgid "Password: "
po/ce.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2015-09-30 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2015-10-16 05:57+0000\n"
19−"X-Generator: Launchpad (build 17768)\n"
19+"X-Generator: Launchpad (build 17812)\n"
20
20
21#: plugins/IntegratedLightDM/Greeter.cpp:112
21#: plugins/IntegratedLightDM/Greeter.cpp:112
22msgid "Password: "
22msgid "Password: "
po/ckb.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2015-09-30 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2015-10-16 05:58+0000\n"
19−"X-Generator: Launchpad (build 17768)\n"
19+"X-Generator: Launchpad (build 17812)\n"
20
20
21#: plugins/IntegratedLightDM/Greeter.cpp:112
21#: plugins/IntegratedLightDM/Greeter.cpp:112
22msgid "Password: "
22msgid "Password: "
po/cs.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
17"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
18−"X-Launchpad-Export-Date: 2015-09-30 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2015-10-16 05:57+0000\n"
19−"X-Generator: Launchpad (build 17768)\n"
19+"X-Generator: Launchpad (build 17812)\n"
20"Language: cs\n"
20"Language: cs\n"
21
21
22#: plugins/IntegratedLightDM/Greeter.cpp:112
22#: plugins/IntegratedLightDM/Greeter.cpp:112
po/cy.po+2−2
@@ -16,8 +16,8 @@ msgstr ""
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=4; plural=n==1 ? 0 : n==2 ? 1 : (n != 8 && n != 11) ? "
17"Plural-Forms: nplurals=4; plural=n==1 ? 0 : n==2 ? 1 : (n != 8 && n != 11) ? "
18"2 : 3;\n"
18"2 : 3;\n"
19−"X-Launchpad-Export-Date: 2015-09-30 05:43+0000\n"
19+"X-Launchpad-Export-Date: 2015-10-16 05:58+0000\n"
20−"X-Generator: Launchpad (build 17768)\n"
20+"X-Generator: Launchpad (build 17812)\n"
21
21
22#: plugins/IntegratedLightDM/Greeter.cpp:112
22#: plugins/IntegratedLightDM/Greeter.cpp:112
23msgid "Password: "
23msgid "Password: "
po/da.po+2−2
@@ -16,8 +16,8 @@ msgstr ""
16"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Type: text/plain; charset=UTF-8\n"
17"Content-Transfer-Encoding: 8bit\n"
17"Content-Transfer-Encoding: 8bit\n"
18"Plural-Forms: nplurals=2; plural=n != 1;\n"
18"Plural-Forms: nplurals=2; plural=n != 1;\n"
19−"X-Launchpad-Export-Date: 2015-09-30 05:43+0000\n"
19+"X-Launchpad-Export-Date: 2015-10-16 05:57+0000\n"
20−"X-Generator: Launchpad (build 17768)\n"
20+"X-Generator: Launchpad (build 17812)\n"
21
21
22#: plugins/IntegratedLightDM/Greeter.cpp:112
22#: plugins/IntegratedLightDM/Greeter.cpp:112
23msgid "Password: "
23msgid "Password: "
po/de.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2015-09-30 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2015-10-16 05:57+0000\n"
19−"X-Generator: Launchpad (build 17768)\n"
19+"X-Generator: Launchpad (build 17812)\n"
20
20
21#: plugins/IntegratedLightDM/Greeter.cpp:112
21#: plugins/IntegratedLightDM/Greeter.cpp:112
22msgid "Password: "
22msgid "Password: "
po/el.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2015-09-30 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2015-10-16 05:57+0000\n"
19−"X-Generator: Launchpad (build 17768)\n"
19+"X-Generator: Launchpad (build 17812)\n"
20
20
21#: plugins/IntegratedLightDM/Greeter.cpp:112
21#: plugins/IntegratedLightDM/Greeter.cpp:112
22msgid "Password: "
22msgid "Password: "
po/en_AU.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2015-09-30 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2015-10-16 05:58+0000\n"
19−"X-Generator: Launchpad (build 17768)\n"
19+"X-Generator: Launchpad (build 17812)\n"
20
20
21#: plugins/IntegratedLightDM/Greeter.cpp:112
21#: plugins/IntegratedLightDM/Greeter.cpp:112
22msgid "Password: "
22msgid "Password: "
po/en_GB.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2015-09-30 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2015-10-16 05:58+0000\n"
19−"X-Generator: Launchpad (build 17768)\n"
19+"X-Generator: Launchpad (build 17812)\n"
20
20
21#: plugins/IntegratedLightDM/Greeter.cpp:112
21#: plugins/IntegratedLightDM/Greeter.cpp:112
22msgid "Password: "
22msgid "Password: "
po/eo.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2015-09-30 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2015-10-16 05:57+0000\n"
19−"X-Generator: Launchpad (build 17768)\n"
19+"X-Generator: Launchpad (build 17812)\n"
20
20
21#: plugins/IntegratedLightDM/Greeter.cpp:112
21#: plugins/IntegratedLightDM/Greeter.cpp:112
22msgid "Password: "
22msgid "Password: "
po/es.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2015-09-30 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2015-10-16 05:58+0000\n"
19−"X-Generator: Launchpad (build 17768)\n"
19+"X-Generator: Launchpad (build 17812)\n"
20
20
21#: plugins/IntegratedLightDM/Greeter.cpp:112
21#: plugins/IntegratedLightDM/Greeter.cpp:112
22msgid "Password: "
22msgid "Password: "
po/eu.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2015-09-30 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2015-10-16 05:57+0000\n"
19−"X-Generator: Launchpad (build 17768)\n"
19+"X-Generator: Launchpad (build 17812)\n"
20
20
21#: plugins/IntegratedLightDM/Greeter.cpp:112
21#: plugins/IntegratedLightDM/Greeter.cpp:112
22msgid "Password: "
22msgid "Password: "
po/fa.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=1; plural=0;\n"
17"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2015-09-30 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2015-10-16 05:57+0000\n"
19−"X-Generator: Launchpad (build 17768)\n"
19+"X-Generator: Launchpad (build 17812)\n"
20
20
21#: plugins/IntegratedLightDM/Greeter.cpp:112
21#: plugins/IntegratedLightDM/Greeter.cpp:112
22msgid "Password: "
22msgid "Password: "
po/fi.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2015-09-30 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2015-10-16 05:57+0000\n"
19−"X-Generator: Launchpad (build 17768)\n"
19+"X-Generator: Launchpad (build 17812)\n"
20
20
21#: plugins/IntegratedLightDM/Greeter.cpp:112
21#: plugins/IntegratedLightDM/Greeter.cpp:112
22msgid "Password: "
22msgid "Password: "
po/fo.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2015-09-30 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2015-10-16 05:57+0000\n"
19−"X-Generator: Launchpad (build 17768)\n"
19+"X-Generator: Launchpad (build 17812)\n"
20
20
21#: plugins/IntegratedLightDM/Greeter.cpp:112
21#: plugins/IntegratedLightDM/Greeter.cpp:112
22msgid "Password: "
22msgid "Password: "
po/fr.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=2; plural=n > 1;\n"
17"Plural-Forms: nplurals=2; plural=n > 1;\n"
18−"X-Launchpad-Export-Date: 2015-09-30 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2015-10-16 05:57+0000\n"
19−"X-Generator: Launchpad (build 17768)\n"
19+"X-Generator: Launchpad (build 17812)\n"
20
20
21#: plugins/IntegratedLightDM/Greeter.cpp:112
21#: plugins/IntegratedLightDM/Greeter.cpp:112
22msgid "Password: "
22msgid "Password: "
po/ga.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=3; plural=n==1 ? 0 : n==2 ? 1 : 2;\n"
17"Plural-Forms: nplurals=3; plural=n==1 ? 0 : n==2 ? 1 : 2;\n"
18−"X-Launchpad-Export-Date: 2015-09-30 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2015-10-16 05:57+0000\n"
19−"X-Generator: Launchpad (build 17768)\n"
19+"X-Generator: Launchpad (build 17812)\n"
20
20
21#: plugins/IntegratedLightDM/Greeter.cpp:112
21#: plugins/IntegratedLightDM/Greeter.cpp:112
22msgid "Password: "
22msgid "Password: "
po/gd.po+2−2
@@ -16,8 +16,8 @@ msgstr ""
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=4; plural=(n==1 || n==11) ? 0 : (n==2 || n==12) ? 1 : "
17"Plural-Forms: nplurals=4; plural=(n==1 || n==11) ? 0 : (n==2 || n==12) ? 1 : "
18"(n > 2 && n < 20) ? 2 : 3;\n"
18"(n > 2 && n < 20) ? 2 : 3;\n"
19−"X-Launchpad-Export-Date: 2015-09-30 05:43+0000\n"
19+"X-Launchpad-Export-Date: 2015-10-16 05:57+0000\n"
20−"X-Generator: Launchpad (build 17768)\n"
20+"X-Generator: Launchpad (build 17812)\n"
21"Language: gd\n"
21"Language: gd\n"
22
22
23#: plugins/IntegratedLightDM/Greeter.cpp:112
23#: plugins/IntegratedLightDM/Greeter.cpp:112
po/gl.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2015-09-30 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2015-10-16 05:57+0000\n"
19−"X-Generator: Launchpad (build 17768)\n"
19+"X-Generator: Launchpad (build 17812)\n"
20
20
21#: plugins/IntegratedLightDM/Greeter.cpp:112
21#: plugins/IntegratedLightDM/Greeter.cpp:112
22msgid "Password: "
22msgid "Password: "
po/gv.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=3; plural=n == 1 ? 0 : (n == 2 ? 1 : 2);\n"
17"Plural-Forms: nplurals=3; plural=n == 1 ? 0 : (n == 2 ? 1 : 2);\n"
18−"X-Launchpad-Export-Date: 2015-09-30 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2015-10-16 05:57+0000\n"
19−"X-Generator: Launchpad (build 17768)\n"
19+"X-Generator: Launchpad (build 17812)\n"
20
20
21#: plugins/IntegratedLightDM/Greeter.cpp:112
21#: plugins/IntegratedLightDM/Greeter.cpp:112
22msgid "Password: "
22msgid "Password: "
po/he.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2015-09-30 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2015-10-16 05:57+0000\n"
19−"X-Generator: Launchpad (build 17768)\n"
19+"X-Generator: Launchpad (build 17812)\n"
20
20
21#: plugins/IntegratedLightDM/Greeter.cpp:112
21#: plugins/IntegratedLightDM/Greeter.cpp:112
22msgid "Password: "
22msgid "Password: "
po/hi.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2015-09-30 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2015-10-16 05:57+0000\n"
19−"X-Generator: Launchpad (build 17768)\n"
19+"X-Generator: Launchpad (build 17812)\n"
20
20
21#: plugins/IntegratedLightDM/Greeter.cpp:112
21#: plugins/IntegratedLightDM/Greeter.cpp:112
22msgid "Password: "
22msgid "Password: "
po/hr.po+124−116
@@ -16,25 +16,25 @@ msgstr ""
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
17"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
18"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
18"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
19−"X-Launchpad-Export-Date: 2015-09-30 05:43+0000\n"
19+"X-Launchpad-Export-Date: 2015-10-16 05:57+0000\n"
20−"X-Generator: Launchpad (build 17768)\n"
20+"X-Generator: Launchpad (build 17812)\n"
21
21
22#: plugins/IntegratedLightDM/Greeter.cpp:112
22#: plugins/IntegratedLightDM/Greeter.cpp:112
23msgid "Password: "
23msgid "Password: "
24−msgstr ""
24+msgstr "Lozinka: "
25
25
26#: plugins/Unity/Launcher/launcheritem.cpp:47
26#: plugins/Unity/Launcher/launcheritem.cpp:47
27#: plugins/Unity/Launcher/launcheritem.cpp:106
27#: plugins/Unity/Launcher/launcheritem.cpp:106
28msgid "Pin shortcut"
28msgid "Pin shortcut"
29−msgstr ""
29+msgstr "Pričvrsti kraticu"
30
30
31#: plugins/Unity/Launcher/launcheritem.cpp:52
31#: plugins/Unity/Launcher/launcheritem.cpp:52
32msgid "Quit"
32msgid "Quit"
33−msgstr ""
33+msgstr "Zatvori"
34
34
35#: plugins/Unity/Launcher/launcheritem.cpp:106
35#: plugins/Unity/Launcher/launcheritem.cpp:106
36msgid "Unpin shortcut"
36msgid "Unpin shortcut"
37−msgstr ""
37+msgstr "Ukloni kraticu"
38
38
39#. Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
39#. Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
40#. This format string is used for showing, on a 12-hour clock, times that happen yesterday.
40#. This format string is used for showing, on a 12-hour clock, times that happen yesterday.
@@ -42,14 +42,14 @@ msgstr ""
42#. en_US example: "Yesterday\u2003%l:%M %p" --> "Yesterday 1:00 PM"
42#. en_US example: "Yesterday\u2003%l:%M %p" --> "Yesterday 1:00 PM"
43#: plugins/Utils/relativetimeformatter.cpp:157
43#: plugins/Utils/relativetimeformatter.cpp:157
44msgid "Yesterday %l:%M %p"
44msgid "Yesterday %l:%M %p"
45−msgstr ""
45+msgstr "Jučer %l:%M %p"
46
46
47#. Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
47#. Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
48#. This format string is used for showing, on a 12-hour clock, times that happened today.
48#. This format string is used for showing, on a 12-hour clock, times that happened today.
49#. en_US example: "%l:%M %p" --> "1:00 PM"
49#. en_US example: "%l:%M %p" --> "1:00 PM"
50#: plugins/Utils/relativetimeformatter.cpp:164
50#: plugins/Utils/relativetimeformatter.cpp:164
51msgid "%l:%M %p"
51msgid "%l:%M %p"
52−msgstr ""
52+msgstr "%l:%M %p"
53
53
54#. Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
54#. Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
55#. This format string is used for showing, on a 12-hour clock, events/appointments that happen tomorrow.
55#. This format string is used for showing, on a 12-hour clock, events/appointments that happen tomorrow.
@@ -57,7 +57,7 @@ msgstr ""
57#. en_US example: "Tomorrow\u2003%l:%M %p" --> "Tomorrow 1:00 PM"
57#. en_US example: "Tomorrow\u2003%l:%M %p" --> "Tomorrow 1:00 PM"
58#: plugins/Utils/relativetimeformatter.cpp:172
58#: plugins/Utils/relativetimeformatter.cpp:172
59msgid "Tomorrow %l:%M %p"
59msgid "Tomorrow %l:%M %p"
60−msgstr ""
60+msgstr "Sutra %l:%M %p"
61
61
62#. Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
62#. Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
63#. This format string is used for showing, on a 12-hour clock, times that happened in the last week.
63#. This format string is used for showing, on a 12-hour clock, times that happened in the last week.
@@ -65,7 +65,7 @@ msgstr ""
65#. en_US example: "%a\u2003%l:%M %p" --> "Fri 1:00 PM"
65#. en_US example: "%a\u2003%l:%M %p" --> "Fri 1:00 PM"
66#: plugins/Utils/relativetimeformatter.cpp:181
66#: plugins/Utils/relativetimeformatter.cpp:181
67msgid "%a %l:%M %p"
67msgid "%a %l:%M %p"
68−msgstr ""
68+msgstr "%a %l:%M %p"
69
69
70#. Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
70#. Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
71#. This format string is used for showing, on a 12-hour clock, times that happened before a week from now.
71#. This format string is used for showing, on a 12-hour clock, times that happened before a week from now.
@@ -74,7 +74,7 @@ msgstr ""
74#. en_GB example: "%a %b %d\u2003%l:%M %p" --> "Fri 31 Oct 1:00 PM"
74#. en_GB example: "%a %b %d\u2003%l:%M %p" --> "Fri 31 Oct 1:00 PM"
75#: plugins/Utils/relativetimeformatter.cpp:190
75#: plugins/Utils/relativetimeformatter.cpp:190
76msgid "%a %d %b %l:%M %p"
76msgid "%a %d %b %l:%M %p"
77−msgstr ""
77+msgstr "%a %d %b %l:%M %p"
78
78
79#. Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
79#. Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
80#. This format string is used for showing, on a 24-hour clock, times that happen yesterday.
80#. This format string is used for showing, on a 24-hour clock, times that happen yesterday.
@@ -82,14 +82,14 @@ msgstr ""
82#. en_US example: "Yesterday\u2003%l:%M %p" --> "Yesterday 13:00"
82#. en_US example: "Yesterday\u2003%l:%M %p" --> "Yesterday 13:00"
83#: plugins/Utils/relativetimeformatter.cpp:201
83#: plugins/Utils/relativetimeformatter.cpp:201
84msgid "Yesterday %H:%M"
84msgid "Yesterday %H:%M"
85−msgstr ""
85+msgstr "Jučer %H:%M"
86
86
87#. Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
87#. Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
88#. This format string is used for showing, on a 24-hour clock, times that happened today.
88#. This format string is used for showing, on a 24-hour clock, times that happened today.
89#. en_US example: "%H:%M" --> "13:00"
89#. en_US example: "%H:%M" --> "13:00"
90#: plugins/Utils/relativetimeformatter.cpp:208
90#: plugins/Utils/relativetimeformatter.cpp:208
91msgid "%H:%M"
91msgid "%H:%M"
92−msgstr ""
92+msgstr "%H:%M"
93
93
94#. Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
94#. Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
95#. This format string is used for showing, on a 24-hour clock, events/appointments that happen tomorrow.
95#. This format string is used for showing, on a 24-hour clock, events/appointments that happen tomorrow.
@@ -97,7 +97,7 @@ msgstr ""
97#. en_US example: "Tomorrow\u2003%l:%M %p" --> "Tomorrow 13:00"
97#. en_US example: "Tomorrow\u2003%l:%M %p" --> "Tomorrow 13:00"
98#: plugins/Utils/relativetimeformatter.cpp:216
98#: plugins/Utils/relativetimeformatter.cpp:216
99msgid "Tomorrow %H:%M"
99msgid "Tomorrow %H:%M"
100−msgstr ""
100+msgstr "Sutra %H:%M"
101
101
102#. Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
102#. Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
103#. This format string is used for showing, on a 24-hour clock, times that happened in the last week.
103#. This format string is used for showing, on a 24-hour clock, times that happened in the last week.
@@ -105,7 +105,7 @@ msgstr ""
105#. en_US example: "%a\u2003%H:%M" --> "Fri 13:00"
105#. en_US example: "%a\u2003%H:%M" --> "Fri 13:00"
106#: plugins/Utils/relativetimeformatter.cpp:225
106#: plugins/Utils/relativetimeformatter.cpp:225
107msgid "%a %H:%M"
107msgid "%a %H:%M"
108−msgstr ""
108+msgstr "%a %H:%M"
109
109
110#. Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
110#. Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
111#. This format string is used for showing, on a 24-hour clock, times that happened before a week from now.
111#. This format string is used for showing, on a 24-hour clock, times that happened before a week from now.
@@ -114,218 +114,221 @@ msgstr ""
114#. en_GB example: "%a %b %d\u2003%H:%M" --> "Fri 31 Oct 13:00"
114#. en_GB example: "%a %b %d\u2003%H:%M" --> "Fri 31 Oct 13:00"
115#: plugins/Utils/relativetimeformatter.cpp:234
115#: plugins/Utils/relativetimeformatter.cpp:234
116msgid "%a %d %b %H:%M"
116msgid "%a %d %b %H:%M"
117−msgstr ""
117+msgstr "%a %d %b %H:%M"
118
118
119#: qml/Components/DelayedLockscreen.qml:49
119#: qml/Components/DelayedLockscreen.qml:49
120msgid "Device Locked"
120msgid "Device Locked"
121−msgstr ""
121+msgstr "Uređaj zaključan"
122
122
123#: qml/Components/DelayedLockscreen.qml:64
123#: qml/Components/DelayedLockscreen.qml:64
124msgid "You have been locked out due to too many failed passphrase attempts."
124msgid "You have been locked out due to too many failed passphrase attempts."
125−msgstr ""
125+msgstr "Previše pogrešnih pokušaja otključavanja."
126
126
127#: qml/Components/DelayedLockscreen.qml:65
127#: qml/Components/DelayedLockscreen.qml:65
128msgid "You have been locked out due to too many failed passcode attempts."
128msgid "You have been locked out due to too many failed passcode attempts."
129−msgstr ""
129+msgstr "Previše pogrešnih pokušaja otključavanja."
130
130
131#: qml/Components/DelayedLockscreen.qml:74
131#: qml/Components/DelayedLockscreen.qml:74
132#, qt-format
132#, qt-format
133msgid "Please wait %1 minute and then try again…"
133msgid "Please wait %1 minute and then try again…"
134msgid_plural "Please wait %1 minutes and then try again…"
134msgid_plural "Please wait %1 minutes and then try again…"
135−msgstr[0] ""
135+msgstr[0] "Pričekajte %1 minutu a zatim ponovno pokušajte…"
136−msgstr[1] ""
136+msgstr[1] "Pričekajte %1 minute a zatim ponovno pokušajte…"
137+msgstr[2] "Pričekajte %1 minutua a zatim ponovno pokušajte…"
137
138
138#: qml/Components/Dialogs.qml:115
139#: qml/Components/Dialogs.qml:115
139msgctxt "Title: Lock/Log out dialog"
140msgctxt "Title: Lock/Log out dialog"
140msgid "Log out"
141msgid "Log out"
141−msgstr ""
142+msgstr "Odjava"
142
143
143#: qml/Components/Dialogs.qml:116
144#: qml/Components/Dialogs.qml:116
144msgid "Are you sure you want to log out?"
145msgid "Are you sure you want to log out?"
145−msgstr ""
146+msgstr "Sigurno se želite odjaviti?"
146
147
147#: qml/Components/Dialogs.qml:118
148#: qml/Components/Dialogs.qml:118
148msgctxt "Button: Lock the system"
149msgctxt "Button: Lock the system"
149msgid "Lock"
150msgid "Lock"
150−msgstr ""
151+msgstr "Zaključaj"
151
152
152#: qml/Components/Dialogs.qml:125
153#: qml/Components/Dialogs.qml:125
153msgctxt "Button: Log out from the system"
154msgctxt "Button: Log out from the system"
154msgid "Log Out"
155msgid "Log Out"
155−msgstr ""
156+msgstr "Odjava"
156
157
157#: qml/Components/Dialogs.qml:132 qml/Components/Dialogs.qml:165
158#: qml/Components/Dialogs.qml:132 qml/Components/Dialogs.qml:165
158#: qml/Components/Dialogs.qml:224
159#: qml/Components/Dialogs.qml:224
159msgid "Cancel"
160msgid "Cancel"
160−msgstr ""
161+msgstr "Odustani"
161
162
162#: qml/Components/Dialogs.qml:144
163#: qml/Components/Dialogs.qml:144
163msgctxt "Title: Reboot/Shut down dialog"
164msgctxt "Title: Reboot/Shut down dialog"
164msgid "Shut down"
165msgid "Shut down"
165−msgstr ""
166+msgstr "Isključi"
166
167
167#: qml/Components/Dialogs.qml:145
168#: qml/Components/Dialogs.qml:145
168msgid "Are you sure you want to shut down?"
169msgid "Are you sure you want to shut down?"
169−msgstr ""
170+msgstr "Sigurno želite isključiti?"
170
171
171#: qml/Components/Dialogs.qml:147
172#: qml/Components/Dialogs.qml:147
172msgctxt "Button: Reboot the system"
173msgctxt "Button: Reboot the system"
173msgid "Reboot"
174msgid "Reboot"
174−msgstr ""
175+msgstr "Ponovno pokreni"
175
176
176#: qml/Components/Dialogs.qml:156
177#: qml/Components/Dialogs.qml:156
177msgctxt "Button: Shut down the system"
178msgctxt "Button: Shut down the system"
178msgid "Shut down"
179msgid "Shut down"
179−msgstr ""
180+msgstr "Isključi"
180
181
181#: qml/Components/Dialogs.qml:178
182#: qml/Components/Dialogs.qml:178
182msgctxt "Title: Reboot dialog"
183msgctxt "Title: Reboot dialog"
183msgid "Reboot"
184msgid "Reboot"
184−msgstr ""
185+msgstr "Ponovno pokreni"
185
186
186#: qml/Components/Dialogs.qml:179
187#: qml/Components/Dialogs.qml:179
187msgid "Are you sure you want to reboot?"
188msgid "Are you sure you want to reboot?"
188−msgstr ""
189+msgstr "Sigurno želite ponovno pokrenuti?"
189
190
190#: qml/Components/Dialogs.qml:181
191#: qml/Components/Dialogs.qml:181
191msgid "No"
192msgid "No"
192−msgstr ""
193+msgstr "Ne"
193
194
194#: qml/Components/Dialogs.qml:188
195#: qml/Components/Dialogs.qml:188
195msgid "Yes"
196msgid "Yes"
196−msgstr ""
197+msgstr "Da"
197
198
198#: qml/Components/Dialogs.qml:203
199#: qml/Components/Dialogs.qml:203
199msgctxt "Title: Power off/Restart dialog"
200msgctxt "Title: Power off/Restart dialog"
200msgid "Power"
201msgid "Power"
201−msgstr ""
202+msgstr "Isključivanje"
202
203
203#: qml/Components/Dialogs.qml:204
204#: qml/Components/Dialogs.qml:204
204msgid ""
205msgid ""
205"Are you sure you would like\n"
206"Are you sure you would like\n"
206"to power off?"
207"to power off?"
207msgstr ""
208msgstr ""
209+"Sigurno želite\n"
210+"isključiti?"
208
211
209#: qml/Components/Dialogs.qml:206
212#: qml/Components/Dialogs.qml:206
210msgctxt "Button: Power off the system"
213msgctxt "Button: Power off the system"
211msgid "Power off"
214msgid "Power off"
212−msgstr ""
215+msgstr "Isključi"
213
216
214#: qml/Components/Dialogs.qml:215
217#: qml/Components/Dialogs.qml:215
215msgctxt "Button: Restart the system"
218msgctxt "Button: Restart the system"
216msgid "Restart"
219msgid "Restart"
217−msgstr ""
220+msgstr "Ponovo pokreni"
218
221
219#: qml/Components/Lockscreen.qml:245
222#: qml/Components/Lockscreen.qml:245
220msgid "Return to Call"
223msgid "Return to Call"
221−msgstr ""
224+msgstr "Vrati na poziv"
222
225
223#: qml/Components/Lockscreen.qml:245
226#: qml/Components/Lockscreen.qml:245
224msgid "Emergency Call"
227msgid "Emergency Call"
225−msgstr ""
228+msgstr "Hitni poziv"
226
229
227#: qml/Components/Lockscreen.qml:277
230#: qml/Components/Lockscreen.qml:277
228msgid "OK"
231msgid "OK"
229−msgstr ""
232+msgstr "U redu"
230
233
231#: qml/Dash/GenericScopeView.qml:569 qml/Dash/GenericScopeView.qml:727
234#: qml/Dash/GenericScopeView.qml:569 qml/Dash/GenericScopeView.qml:727
232msgid "See less"
235msgid "See less"
233−msgstr ""
236+msgstr "Prikaži manje"
234
237
235#: qml/Dash/GenericScopeView.qml:569
238#: qml/Dash/GenericScopeView.qml:569
236msgid "See all"
239msgid "See all"
237−msgstr ""
240+msgstr "Prikaži sve"
238
241
239#: qml/Dash/GenericScopeView.qml:631
242#: qml/Dash/GenericScopeView.qml:631
240msgctxt "Label: Hint for dash search line edit"
243msgctxt "Label: Hint for dash search line edit"
241msgid "Search"
244msgid "Search"
242−msgstr ""
245+msgstr "Pretraži"
243
246
244#: qml/Dash/PageHeader.qml:269
247#: qml/Dash/PageHeader.qml:269
245msgctxt "Button: Open the Ubuntu Store"
248msgctxt "Button: Open the Ubuntu Store"
246msgid "Store"
249msgid "Store"
247−msgstr ""
250+msgstr "Trgovina"
248
251
249#: qml/Dash/PageHeader.qml:276
252#: qml/Dash/PageHeader.qml:276
250msgctxt "Button: Start a search in the current dash scope"
253msgctxt "Button: Start a search in the current dash scope"
251msgid "Search"
254msgid "Search"
252−msgstr ""
255+msgstr "Pretraži"
253
256
254#: qml/Dash/PageHeader.qml:286
257#: qml/Dash/PageHeader.qml:286
255msgctxt "Button: Show the current dash scope settings"
258msgctxt "Button: Show the current dash scope settings"
256msgid "Settings"
259msgid "Settings"
257−msgstr ""
260+msgstr "Postavke"
258
261
259#: qml/Dash/PageHeader.qml:293
262#: qml/Dash/PageHeader.qml:293
260msgid "Remove from Favorites"
263msgid "Remove from Favorites"
261−msgstr ""
264+msgstr "Ukloni iz omiljenih"
262
265
263#: qml/Dash/PageHeader.qml:293
266#: qml/Dash/PageHeader.qml:293
264msgid "Add to Favorites"
267msgid "Add to Favorites"
265−msgstr ""
268+msgstr "Dodaj u omiljene"
266
269
267#: qml/Dash/Previews/PreviewActionCombo.qml:35
270#: qml/Dash/Previews/PreviewActionCombo.qml:35
268msgid "More..."
271msgid "More..."
269−msgstr ""
272+msgstr "Više..."
270
273
271#: qml/Dash/Previews/PreviewActionCombo.qml:35
274#: qml/Dash/Previews/PreviewActionCombo.qml:35
272msgid "Less..."
275msgid "Less..."
273−msgstr ""
276+msgstr "Manje..."
274
277
275#: qml/Dash/Previews/PreviewCommentInput.qml:68
278#: qml/Dash/Previews/PreviewCommentInput.qml:68
276#: qml/Dash/Previews/PreviewRatingInput.qml:174
279#: qml/Dash/Previews/PreviewRatingInput.qml:174
277#: qml/Panel/Indicators/MessageMenuItemFactory.qml:148
280#: qml/Panel/Indicators/MessageMenuItemFactory.qml:148
278#: qml/Panel/Indicators/MessageMenuItemFactory.qml:205
281#: qml/Panel/Indicators/MessageMenuItemFactory.qml:205
279msgid "Send"
282msgid "Send"
280−msgstr ""
283+msgstr "Pošalji"
281
284
282#: qml/Dash/Previews/PreviewRatingInput.qml:84
285#: qml/Dash/Previews/PreviewRatingInput.qml:84
283msgid "Rate this"
286msgid "Rate this"
284−msgstr ""
287+msgstr "Ocijeni ovo"
285
288
286#: qml/Dash/Previews/PreviewRatingInput.qml:129
289#: qml/Dash/Previews/PreviewRatingInput.qml:129
287msgid "Add a review"
290msgid "Add a review"
288−msgstr ""
291+msgstr "Dodaj recenziju"
289
292
290#: qml/Dash/PullToRefreshScopeStyle.qml:55
293#: qml/Dash/PullToRefreshScopeStyle.qml:55
291msgid "Pull to refresh…"
294msgid "Pull to refresh…"
292−msgstr ""
295+msgstr "Povuci za osvježavanje..."
293
296
294#: qml/Dash/PullToRefreshScopeStyle.qml:60
297#: qml/Dash/PullToRefreshScopeStyle.qml:60
295msgid "Release to refresh…"
298msgid "Release to refresh…"
296−msgstr ""
299+msgstr "Otpusti za osvježavanje..."
297
300
298#: qml/Dash/ScopeSettings/ScopeSettingBoolean.qml:43
301#: qml/Dash/ScopeSettings/ScopeSettingBoolean.qml:43
299msgid "Enable location data"
302msgid "Enable location data"
300−msgstr ""
303+msgstr "Omogući podatke lokacije"
301
304
302#: qml/Dash/ScopesList.qml:67
305#: qml/Dash/ScopesList.qml:67
303msgid "Manage"
306msgid "Manage"
304−msgstr ""
307+msgstr "Upravljaj"
305
308
306#: qml/Dash/ScopesList.qml:113
309#: qml/Dash/ScopesList.qml:113
307msgid "Home"
310msgid "Home"
308−msgstr ""
311+msgstr "Naslovnica"
309
312
310#: qml/Dash/ScopesList.qml:114
313#: qml/Dash/ScopesList.qml:114
311msgid "Also installed"
314msgid "Also installed"
312−msgstr ""
315+msgstr "Također instalirano"
313
316
314#: qml/Greeter/CoverPage.qml:107
317#: qml/Greeter/CoverPage.qml:107
315msgid "Unlock"
318msgid "Unlock"
316−msgstr ""
319+msgstr "Otključaj"
317
320
318#: qml/Greeter/LoginList.qml:236
321#: qml/Greeter/LoginList.qml:236
319msgid "Retry"
322msgid "Retry"
320−msgstr ""
323+msgstr "Pokušaj ponovno"
321
324
322#: qml/Greeter/LoginList.qml:237
325#: qml/Greeter/LoginList.qml:237
323msgid "Tap to unlock"
326msgid "Tap to unlock"
324−msgstr ""
327+msgstr "Dodirni za otključavanje"
325
328
326#: qml/Greeter/NarrowView.qml:54 qml/Wizard/Pages/passwd-confirm.qml:53
329#: qml/Greeter/NarrowView.qml:54 qml/Wizard/Pages/passwd-confirm.qml:53
327msgid "Sorry, incorrect passphrase."
330msgid "Sorry, incorrect passphrase."
328−msgstr ""
331+msgstr "Isprika, netočna lozinka."
329
332
330#: qml/Greeter/NarrowView.qml:55 qml/Wizard/Pages/passwd-confirm.qml:54
333#: qml/Greeter/NarrowView.qml:55 qml/Wizard/Pages/passwd-confirm.qml:54
331msgid "Sorry, incorrect passcode."
334msgid "Sorry, incorrect passcode."
@@ -333,13 +336,15 @@ msgstr ""
333
336
334#: qml/Greeter/NarrowView.qml:56
337#: qml/Greeter/NarrowView.qml:56
335msgid "This will be your last attempt."
338msgid "This will be your last attempt."
336−msgstr ""
339+msgstr "Ovo je vaš posljednji pokušaj."
337
340
338#: qml/Greeter/NarrowView.qml:58
341#: qml/Greeter/NarrowView.qml:58
339msgid ""
342msgid ""
340"If passphrase is entered incorrectly, your phone will conduct a factory "
343"If passphrase is entered incorrectly, your phone will conduct a factory "
341"reset and all personal data will be deleted."
344"reset and all personal data will be deleted."
342msgstr ""
345msgstr ""
346+"Ako netočno upišete lozinku, vaš telefon će pokrenuti vraćanje na tvorničke "
347+"postavke i svi osobni podaci će biti obrisani."
343
348
344#: qml/Greeter/NarrowView.qml:59
349#: qml/Greeter/NarrowView.qml:59
345msgid ""
350msgid ""
@@ -350,11 +355,11 @@ msgstr ""
350#: qml/Greeter/NarrowView.qml:116
355#: qml/Greeter/NarrowView.qml:116
351#, qt-format
356#, qt-format
352msgid "Enter %1"
357msgid "Enter %1"
353−msgstr ""
358+msgstr "Upišite %1"
354
359
355#: qml/Greeter/NarrowView.qml:117 qml/Wizard/Pages/passwd-set.qml:60
360#: qml/Greeter/NarrowView.qml:117 qml/Wizard/Pages/passwd-set.qml:60
356msgid "Enter passphrase"
361msgid "Enter passphrase"
357−msgstr ""
362+msgstr "Upišite lozinku"
358
363
359#: qml/Greeter/NarrowView.qml:118
364#: qml/Greeter/NarrowView.qml:118
360msgid "Enter passcode"
365msgid "Enter passcode"
@@ -363,149 +368,152 @@ msgstr ""
363#: qml/Greeter/NarrowView.qml:119
368#: qml/Greeter/NarrowView.qml:119
364#, qt-format
369#, qt-format
365msgid "Sorry, incorrect %1"
370msgid "Sorry, incorrect %1"
366−msgstr ""
371+msgstr "Isprika, netočna %1"
367
372
368#: qml/Greeter/NarrowView.qml:120
373#: qml/Greeter/NarrowView.qml:120
369msgid "Sorry, incorrect passphrase"
374msgid "Sorry, incorrect passphrase"
370−msgstr ""
375+msgstr "Isprika, netočna lozinka"
371
376
372#: qml/Greeter/NarrowView.qml:121
377#: qml/Greeter/NarrowView.qml:121
373msgctxt "passphrase"
378msgctxt "passphrase"
374msgid "Please re-enter"
379msgid "Please re-enter"
375−msgstr ""
380+msgstr "Ponovno upišite"
376
381
377#: qml/Greeter/NarrowView.qml:122
382#: qml/Greeter/NarrowView.qml:122
378msgid "Sorry, incorrect passcode"
383msgid "Sorry, incorrect passcode"
379−msgstr ""
384+msgstr "Isprika, netočna lozinka"
380
385
381#: qml/Notifications/NotificationMenuItemFactory.qml:128
386#: qml/Notifications/NotificationMenuItemFactory.qml:128
382msgid "Show password"
387msgid "Show password"
383−msgstr ""
388+msgstr "Prikaži lozinku"
384
389
385#: qml/Panel/ActiveCallHint.qml:79
390#: qml/Panel/ActiveCallHint.qml:79
386msgid "Tap to return to call..."
391msgid "Tap to return to call..."
387−msgstr ""
392+msgstr "Dodirni za povratak pozivu..."
388
393
389#: qml/Panel/ActiveCallHint.qml:92
394#: qml/Panel/ActiveCallHint.qml:92
390msgid "Conference"
395msgid "Conference"
391−msgstr ""
396+msgstr "Konferencija"
392
397
393#: qml/Panel/Indicators/MenuItemFactory.qml:718
398#: qml/Panel/Indicators/MenuItemFactory.qml:718
394msgid "Nothing is playing"
399msgid "Nothing is playing"
395−msgstr ""
400+msgstr "Ništa se ne reproducira"
396
401
397#: qml/Panel/Indicators/MenuItemFactory.qml:847
402#: qml/Panel/Indicators/MenuItemFactory.qml:847
398#, qt-format
403#, qt-format
399msgid "%1 hour"
404msgid "%1 hour"
400msgid_plural "%1 hours"
405msgid_plural "%1 hours"
401−msgstr[0] ""
406+msgstr[0] "%1 sat"
402−msgstr[1] ""
407+msgstr[1] "%1 sata"
408+msgstr[2] "%1 sati"
403
409
404#: qml/Panel/Indicators/MenuItemFactory.qml:851
410#: qml/Panel/Indicators/MenuItemFactory.qml:851
405#, qt-format
411#, qt-format
406msgid "%1 minute"
412msgid "%1 minute"
407msgid_plural "%1 minutes"
413msgid_plural "%1 minutes"
408−msgstr[0] ""
414+msgstr[0] "%1 minuta"
409−msgstr[1] ""
415+msgstr[1] "%1 minute"
416+msgstr[2] "%1 minuta"
410
417
411#: qml/Panel/Indicators/MenuItemFactory.qml:856
418#: qml/Panel/Indicators/MenuItemFactory.qml:856
412#, qt-format
419#, qt-format
413msgid "%1 second"
420msgid "%1 second"
414msgid_plural "%1 seconds"
421msgid_plural "%1 seconds"
415−msgstr[0] ""
422+msgstr[0] "%1 sekunda"
416−msgstr[1] ""
423+msgstr[1] "%1 sekunde"
424+msgstr[2] "%1 sekundi"
417
425
418#: qml/Panel/Indicators/MenuItemFactory.qml:859
426#: qml/Panel/Indicators/MenuItemFactory.qml:859
419msgid "0 seconds"
427msgid "0 seconds"
420−msgstr ""
428+msgstr "0 sekundi"
421
429
422#. Translators: String like "1 hour, 2 minutes, 3 seconds remaining"
430#. Translators: String like "1 hour, 2 minutes, 3 seconds remaining"
423#: qml/Panel/Indicators/MenuItemFactory.qml:861
431#: qml/Panel/Indicators/MenuItemFactory.qml:861
424#, qt-format
432#, qt-format
425msgid "%1 remaining"
433msgid "%1 remaining"
426−msgstr ""
434+msgstr "%1 preostalo"
427
435
428#: qml/Panel/Indicators/MenuItemFactory.qml:867
436#: qml/Panel/Indicators/MenuItemFactory.qml:867
429msgid "In queue…"
437msgid "In queue…"
430−msgstr ""
438+msgstr "Na čekanju..."
431
439
432#: qml/Panel/Indicators/MenuItemFactory.qml:871
440#: qml/Panel/Indicators/MenuItemFactory.qml:871
433msgid "Downloading"
441msgid "Downloading"
434−msgstr ""
442+msgstr "Preuzimanje"
435
443
436#: qml/Panel/Indicators/MenuItemFactory.qml:873
444#: qml/Panel/Indicators/MenuItemFactory.qml:873
437msgid "Paused, tap to resume"
445msgid "Paused, tap to resume"
438−msgstr ""
446+msgstr "Pauzirano, dodirni za nastavak"
439
447
440#: qml/Panel/Indicators/MenuItemFactory.qml:875
448#: qml/Panel/Indicators/MenuItemFactory.qml:875
441msgid "Canceled"
449msgid "Canceled"
442−msgstr ""
450+msgstr "Prekinuto"
443
451
444#: qml/Panel/Indicators/MenuItemFactory.qml:877
452#: qml/Panel/Indicators/MenuItemFactory.qml:877
445msgid "Finished"
453msgid "Finished"
446−msgstr ""
454+msgstr "Završeno"
447
455
448#: qml/Panel/Indicators/MenuItemFactory.qml:879
456#: qml/Panel/Indicators/MenuItemFactory.qml:879
449msgid "Failed, tap to retry"
457msgid "Failed, tap to retry"
450−msgstr ""
458+msgstr "Neuspjelo, dodirni za ponovni pokušaj"
451
459
452#: qml/Panel/Indicators/MessageMenuItemFactory.qml:149
460#: qml/Panel/Indicators/MessageMenuItemFactory.qml:149
453msgctxt "Label: Hint in message indicator line edit"
461msgctxt "Label: Hint in message indicator line edit"
454msgid "Reply"
462msgid "Reply"
455−msgstr ""
463+msgstr "Odgovori"
456
464
457#: qml/Panel/Indicators/MessageMenuItemFactory.qml:204
465#: qml/Panel/Indicators/MessageMenuItemFactory.qml:204
458msgid "Call back"
466msgid "Call back"
459−msgstr ""
467+msgstr "Uzvrati poziv"
460
468
461#: qml/Panel/Indicators/ModemInfoItem.qml:105
469#: qml/Panel/Indicators/ModemInfoItem.qml:105
462msgid "Unlock SIM"
470msgid "Unlock SIM"
463−msgstr ""
471+msgstr "Otključaj SIM"
464
472
465#: qml/Panel/Indicators/RoamingIndication.qml:27
473#: qml/Panel/Indicators/RoamingIndication.qml:27
466msgid "Roaming"
474msgid "Roaming"
467−msgstr ""
475+msgstr "Roaming"
468
476
469#: qml/Tutorial/TutorialBottomFinish.qml:24
477#: qml/Tutorial/TutorialBottomFinish.qml:24
470msgid "This action does different things for different apps"
478msgid "This action does different things for different apps"
471−msgstr ""
479+msgstr "Ova radnja izvršava različite stvari za različite aplikacije"
472
480
473#: qml/Tutorial/TutorialBottomFinish.qml:25
481#: qml/Tutorial/TutorialBottomFinish.qml:25
474msgid "Tap here to finish."
482msgid "Tap here to finish."
475−msgstr ""
483+msgstr "Dodirni za završetak."
476
484
477#: qml/Tutorial/TutorialBottom.qml:28
485#: qml/Tutorial/TutorialBottom.qml:28
478msgid "Open special menus"
486msgid "Open special menus"
479−msgstr ""
487+msgstr "Otvori posebne izbornike"
480
488
481#: qml/Tutorial/TutorialBottom.qml:29
489#: qml/Tutorial/TutorialBottom.qml:29
482msgid "Swipe up from the bottom edge."
490msgid "Swipe up from the bottom edge."
483−msgstr ""
491+msgstr "Povuci s donjeg ruba."
484
492
485#: qml/Tutorial/TutorialContent.qml:80 qml/Tutorial/TutorialLeftFinish.qml:25
493#: qml/Tutorial/TutorialContent.qml:80 qml/Tutorial/TutorialLeftFinish.qml:25
486#: qml/Tutorial/TutorialRight.qml:144
494#: qml/Tutorial/TutorialRight.qml:144
487msgid "Tap here to continue."
495msgid "Tap here to continue."
488−msgstr ""
496+msgstr "Dodirni ovdje za nastavak."
489
497
490#: qml/Tutorial/TutorialLeftFinish.qml:24
498#: qml/Tutorial/TutorialLeftFinish.qml:24
491msgid "These are the shortcuts to favorite apps"
499msgid "These are the shortcuts to favorite apps"
492−msgstr ""
500+msgstr "Ovo su prečaci do omiljenih aplikacija"
493
501
494#: qml/Tutorial/TutorialLeft.qml:26
502#: qml/Tutorial/TutorialLeft.qml:26
495msgid "Open the launcher"
503msgid "Open the launcher"
496−msgstr ""
504+msgstr "Otvori pokretač"
497
505
498#: qml/Tutorial/TutorialLeft.qml:27
506#: qml/Tutorial/TutorialLeft.qml:27
499msgid "Short swipe from the left edge."
507msgid "Short swipe from the left edge."
500−msgstr ""
508+msgstr "Povuci kratko s lijevog ruba"
501
509
502#: qml/Tutorial/TutorialPage.qml:178
510#: qml/Tutorial/TutorialPage.qml:178
503msgid "You almost got it!"
511msgid "You almost got it!"
504−msgstr ""
512+msgstr "Još malo i završili ste!"
505
513
506#: qml/Tutorial/TutorialPage.qml:195
514#: qml/Tutorial/TutorialPage.qml:195
507msgid "Try again."
515msgid "Try again."
508−msgstr ""
516+msgstr "Pokušaj ponovno."
509
517
510#: qml/Tutorial/TutorialRight.qml:31
518#: qml/Tutorial/TutorialRight.qml:31
511msgid "To view open apps"
519msgid "To view open apps"
@@ -522,63 +530,63 @@ msgstr ""
522#: qml/Wizard/Page.qml:89
530#: qml/Wizard/Page.qml:89
523msgctxt "Button: Go back one page in the Wizard"
531msgctxt "Button: Go back one page in the Wizard"
524msgid "Back"
532msgid "Back"
525−msgstr ""
533+msgstr "Natrag"
526
534
527#: qml/Wizard/Pages/here-terms.qml:27
535#: qml/Wizard/Pages/here-terms.qml:27
528msgid "Terms & Conditions"
536msgid "Terms & Conditions"
529−msgstr ""
537+msgstr "Uvjeti i odredbe"
530
538
531#: qml/Wizard/Pages/passwd-confirm.qml:49
539#: qml/Wizard/Pages/passwd-confirm.qml:49
532msgid "Confirm passphrase"
540msgid "Confirm passphrase"
533−msgstr ""
541+msgstr "Potvrdi lozinku"
534
542
535#: qml/Wizard/Pages/passwd-confirm.qml:50
543#: qml/Wizard/Pages/passwd-confirm.qml:50
536msgid "Confirm passcode"
544msgid "Confirm passcode"
537−msgstr ""
545+msgstr "Potvrdi lozinku"
538
546
539#: qml/Wizard/Pages/passwd-confirm.qml:53
547#: qml/Wizard/Pages/passwd-confirm.qml:53
540#: qml/Wizard/Pages/passwd-confirm.qml:54
548#: qml/Wizard/Pages/passwd-confirm.qml:54
541msgid "Please try again."
549msgid "Please try again."
542−msgstr ""
550+msgstr "Pokušajte ponovno."
543
551
544#: qml/Wizard/Pages/passwd-confirm.qml:82 qml/Wizard/Pages/passwd-set.qml:90
552#: qml/Wizard/Pages/passwd-confirm.qml:82 qml/Wizard/Pages/passwd-set.qml:90
545#: qml/Wizard/Pages/10-welcome.qml:88 qml/Wizard/Pages/30-passwd-type.qml:128
553#: qml/Wizard/Pages/10-welcome.qml:88 qml/Wizard/Pages/30-passwd-type.qml:128
546#: qml/Wizard/Pages/40-wifi.qml:215 qml/Wizard/Pages/50-location.qml:131
554#: qml/Wizard/Pages/40-wifi.qml:215 qml/Wizard/Pages/50-location.qml:131
547#: qml/Wizard/Pages/60-reporting.qml:50
555#: qml/Wizard/Pages/60-reporting.qml:50
548msgid "Continue"
556msgid "Continue"
549−msgstr ""
557+msgstr "Nastavi"
550
558
551#: qml/Wizard/Pages/passwd-set.qml:61
559#: qml/Wizard/Pages/passwd-set.qml:61
552msgid "Choose your passcode"
560msgid "Choose your passcode"
553−msgstr ""
561+msgstr "Odaberite vašu lozinku"
554
562
555#: qml/Wizard/Pages/passwd-set.qml:68
563#: qml/Wizard/Pages/passwd-set.qml:68
556msgid "Passphrase must be 4 characters long"
564msgid "Passphrase must be 4 characters long"
557−msgstr ""
565+msgstr "Lozinka mora biti dugačka 4 znamenke"
558
566
559#: qml/Wizard/Pages/10-welcome.qml:27
567#: qml/Wizard/Pages/10-welcome.qml:27
560msgid "Hi!"
568msgid "Hi!"
561−msgstr ""
569+msgstr "Bok!"
562
570
563#: qml/Wizard/Pages/10-welcome.qml:44
571#: qml/Wizard/Pages/10-welcome.qml:44
564msgid "Welcome to your Ubuntu phone."
572msgid "Welcome to your Ubuntu phone."
565−msgstr ""
573+msgstr "Dobrodošli u vaš Ubuntu telefon."
566
574
567#: qml/Wizard/Pages/10-welcome.qml:52
575#: qml/Wizard/Pages/10-welcome.qml:52
568msgid "Let’s get started."
576msgid "Let’s get started."
569−msgstr ""
577+msgstr "Započnimo."
570
578
571#: qml/Wizard/Pages/20-sim.qml:25
579#: qml/Wizard/Pages/20-sim.qml:25
572msgid "Add a SIM card and restart your device"
580msgid "Add a SIM card and restart your device"
573−msgstr ""
581+msgstr "Dodajte SIM karticu i ponovno pokrenite svoj uređaj"
574
582
575#: qml/Wizard/Pages/20-sim.qml:59
583#: qml/Wizard/Pages/20-sim.qml:59
576msgid "Without it, you won’t be able to make calls or use text messaging."
584msgid "Without it, you won’t be able to make calls or use text messaging."
577−msgstr ""
585+msgstr "Bez nje, nećete moći pozivati i slati tekstovne poruke."
578
586
579#: qml/Wizard/Pages/20-sim.qml:73 qml/Wizard/Pages/40-wifi.qml:215
587#: qml/Wizard/Pages/20-sim.qml:73 qml/Wizard/Pages/40-wifi.qml:215
580msgid "Skip"
588msgid "Skip"
581−msgstr ""
589+msgstr "Preskoči"
582
590
583#: qml/Wizard/Pages/30-passwd-type.qml:39
591#: qml/Wizard/Pages/30-passwd-type.qml:39
584msgid "Lock security"
592msgid "Lock security"
po/hu.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2015-09-30 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2015-10-16 05:57+0000\n"
19−"X-Generator: Launchpad (build 17768)\n"
19+"X-Generator: Launchpad (build 17812)\n"
20
20
21#: plugins/IntegratedLightDM/Greeter.cpp:112
21#: plugins/IntegratedLightDM/Greeter.cpp:112
22msgid "Password: "
22msgid "Password: "
po/hy.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=1; plural=0;\n"
17"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2015-09-30 05:42+0000\n"
18+"X-Launchpad-Export-Date: 2015-10-16 05:57+0000\n"
19−"X-Generator: Launchpad (build 17768)\n"
19+"X-Generator: Launchpad (build 17812)\n"
20
20
21#: plugins/IntegratedLightDM/Greeter.cpp:112
21#: plugins/IntegratedLightDM/Greeter.cpp:112
22msgid "Password: "
22msgid "Password: "
po/ia.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2015-09-30 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2015-10-16 05:57+0000\n"
19−"X-Generator: Launchpad (build 17768)\n"
19+"X-Generator: Launchpad (build 17812)\n"
20
20
21#: plugins/IntegratedLightDM/Greeter.cpp:112
21#: plugins/IntegratedLightDM/Greeter.cpp:112
22msgid "Password: "
22msgid "Password: "
po/id.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=1; plural=0;\n"
17"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2015-09-30 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2015-10-16 05:57+0000\n"
19−"X-Generator: Launchpad (build 17768)\n"
19+"X-Generator: Launchpad (build 17812)\n"
20
20
21#: plugins/IntegratedLightDM/Greeter.cpp:112
21#: plugins/IntegratedLightDM/Greeter.cpp:112
22msgid "Password: "
22msgid "Password: "
po/is.po+2−2
@@ -17,8 +17,8 @@ msgstr ""
17"Content-Type: text/plain; charset=UTF-8\n"
17"Content-Type: text/plain; charset=UTF-8\n"
18"Content-Transfer-Encoding: 8bit\n"
18"Content-Transfer-Encoding: 8bit\n"
19"Plural-Forms: nplurals=2; plural=n != 1;\n"
19"Plural-Forms: nplurals=2; plural=n != 1;\n"
20−"X-Launchpad-Export-Date: 2015-09-30 05:43+0000\n"
20+"X-Launchpad-Export-Date: 2015-10-16 05:57+0000\n"
21−"X-Generator: Launchpad (build 17768)\n"
21+"X-Generator: Launchpad (build 17812)\n"
22"Language: is\n"
22"Language: is\n"
23
23
24#: plugins/IntegratedLightDM/Greeter.cpp:112
24#: plugins/IntegratedLightDM/Greeter.cpp:112
po/it.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2015-09-30 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2015-10-16 05:57+0000\n"
19−"X-Generator: Launchpad (build 17768)\n"
19+"X-Generator: Launchpad (build 17812)\n"
20
20
21#: plugins/IntegratedLightDM/Greeter.cpp:112
21#: plugins/IntegratedLightDM/Greeter.cpp:112
22msgid "Password: "
22msgid "Password: "
po/ja.po+4−4
@@ -8,15 +8,15 @@ msgstr ""
8"Project-Id-Version: unity\n"
8"Project-Id-Version: unity\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10"POT-Creation-Date: 2015-09-16 00:49+0200\n"
10"POT-Creation-Date: 2015-09-16 00:49+0200\n"
11−"PO-Revision-Date: 2014-11-20 05:08+0000\n"
11+"PO-Revision-Date: 2015-10-05 10:05+0000\n"
12"Last-Translator: Kentaro Kazuhama <Unknown>\n"
12"Last-Translator: Kentaro Kazuhama <Unknown>\n"
13"Language-Team: Japanese <ja@li.org>\n"
13"Language-Team: Japanese <ja@li.org>\n"
14"MIME-Version: 1.0\n"
14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=1; plural=0;\n"
17"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2015-09-30 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2015-10-16 05:57+0000\n"
19−"X-Generator: Launchpad (build 17768)\n"
19+"X-Generator: Launchpad (build 17812)\n"
20
20
21#: plugins/IntegratedLightDM/Greeter.cpp:112
21#: plugins/IntegratedLightDM/Greeter.cpp:112
22msgid "Password: "
22msgid "Password: "
@@ -390,7 +390,7 @@ msgstr "グループ通話"
390
390
391#: qml/Panel/Indicators/MenuItemFactory.qml:718
391#: qml/Panel/Indicators/MenuItemFactory.qml:718
392msgid "Nothing is playing"
392msgid "Nothing is playing"
393−msgstr ""
393+msgstr "再生するものがありません"
394
394
395#: qml/Panel/Indicators/MenuItemFactory.qml:847
395#: qml/Panel/Indicators/MenuItemFactory.qml:847
396#, qt-format
396#, qt-format
po/km.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=1; plural=0;\n"
17"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2015-09-30 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2015-10-16 05:57+0000\n"
19−"X-Generator: Launchpad (build 17768)\n"
19+"X-Generator: Launchpad (build 17812)\n"
20
20
21#: plugins/IntegratedLightDM/Greeter.cpp:112
21#: plugins/IntegratedLightDM/Greeter.cpp:112
22msgid "Password: "
22msgid "Password: "
po/kn.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2015-09-30 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2015-10-16 05:57+0000\n"
19−"X-Generator: Launchpad (build 17768)\n"
19+"X-Generator: Launchpad (build 17812)\n"
20
20
21#: plugins/IntegratedLightDM/Greeter.cpp:112
21#: plugins/IntegratedLightDM/Greeter.cpp:112
22msgid "Password: "
22msgid "Password: "
po/ko.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=1; plural=0;\n"
17"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2015-09-30 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2015-10-16 05:57+0000\n"
19−"X-Generator: Launchpad (build 17768)\n"
19+"X-Generator: Launchpad (build 17812)\n"
20
20
21#: plugins/IntegratedLightDM/Greeter.cpp:112
21#: plugins/IntegratedLightDM/Greeter.cpp:112
22msgid "Password: "
22msgid "Password: "
po/ku.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2015-09-30 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2015-10-16 05:57+0000\n"
19−"X-Generator: Launchpad (build 17768)\n"
19+"X-Generator: Launchpad (build 17812)\n"
20
20
21#: plugins/IntegratedLightDM/Greeter.cpp:112
21#: plugins/IntegratedLightDM/Greeter.cpp:112
22msgid "Password: "
22msgid "Password: "
po/ky.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=1; plural=0;\n"
17"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2015-09-30 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2015-10-16 05:57+0000\n"
19−"X-Generator: Launchpad (build 17768)\n"
19+"X-Generator: Launchpad (build 17812)\n"
20
20
21#: plugins/IntegratedLightDM/Greeter.cpp:112
21#: plugins/IntegratedLightDM/Greeter.cpp:112
22msgid "Password: "
22msgid "Password: "
po/lo.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=1; plural=0;\n"
17"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2015-09-30 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2015-10-16 05:57+0000\n"
19−"X-Generator: Launchpad (build 17768)\n"
19+"X-Generator: Launchpad (build 17812)\n"
20
20
21#: plugins/IntegratedLightDM/Greeter.cpp:112
21#: plugins/IntegratedLightDM/Greeter.cpp:112
22msgid "Password: "
22msgid "Password: "
po/lt.po+2−2
@@ -16,8 +16,8 @@ msgstr ""
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
17"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
18"(n%100<10 || n%100>=20) ? 1 : 2;\n"
18"(n%100<10 || n%100>=20) ? 1 : 2;\n"
19−"X-Launchpad-Export-Date: 2015-09-30 05:43+0000\n"
19+"X-Launchpad-Export-Date: 2015-10-16 05:57+0000\n"
20−"X-Generator: Launchpad (build 17768)\n"
20+"X-Generator: Launchpad (build 17812)\n"
21
21
22#: plugins/IntegratedLightDM/Greeter.cpp:112
22#: plugins/IntegratedLightDM/Greeter.cpp:112
23msgid "Password: "
23msgid "Password: "
po/lv.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2;\n"
17"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2;\n"
18−"X-Launchpad-Export-Date: 2015-09-30 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2015-10-16 05:57+0000\n"
19−"X-Generator: Launchpad (build 17768)\n"
19+"X-Generator: Launchpad (build 17812)\n"
20
20
21#: plugins/IntegratedLightDM/Greeter.cpp:112
21#: plugins/IntegratedLightDM/Greeter.cpp:112
22msgid "Password: "
22msgid "Password: "
po/ml.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2015-09-30 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2015-10-16 05:57+0000\n"
19−"X-Generator: Launchpad (build 17768)\n"
19+"X-Generator: Launchpad (build 17812)\n"
20
20
21#: plugins/IntegratedLightDM/Greeter.cpp:112
21#: plugins/IntegratedLightDM/Greeter.cpp:112
22msgid "Password: "
22msgid "Password: "
po/mr.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2015-09-30 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2015-10-16 05:57+0000\n"
19−"X-Generator: Launchpad (build 17768)\n"
19+"X-Generator: Launchpad (build 17812)\n"
20
20
21#: plugins/IntegratedLightDM/Greeter.cpp:112
21#: plugins/IntegratedLightDM/Greeter.cpp:112
22msgid "Password: "
22msgid "Password: "
po/ms.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2015-09-30 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2015-10-16 05:57+0000\n"
19−"X-Generator: Launchpad (build 17768)\n"
19+"X-Generator: Launchpad (build 17812)\n"
20
20
21#: plugins/IntegratedLightDM/Greeter.cpp:112
21#: plugins/IntegratedLightDM/Greeter.cpp:112
22msgid "Password: "
22msgid "Password: "
po/my.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=1; plural=0;\n"
17"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2015-09-30 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2015-10-16 05:57+0000\n"
19−"X-Generator: Launchpad (build 17768)\n"
19+"X-Generator: Launchpad (build 17812)\n"
20
20
21#: plugins/IntegratedLightDM/Greeter.cpp:112
21#: plugins/IntegratedLightDM/Greeter.cpp:112
22msgid "Password: "
22msgid "Password: "
po/nb.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2015-09-30 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2015-10-16 05:57+0000\n"
19−"X-Generator: Launchpad (build 17768)\n"
19+"X-Generator: Launchpad (build 17812)\n"
20
20
21#: plugins/IntegratedLightDM/Greeter.cpp:112
21#: plugins/IntegratedLightDM/Greeter.cpp:112
22msgid "Password: "
22msgid "Password: "
po/nl.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2015-09-30 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2015-10-16 05:57+0000\n"
19−"X-Generator: Launchpad (build 17768)\n"
19+"X-Generator: Launchpad (build 17812)\n"
20
20
21#: plugins/IntegratedLightDM/Greeter.cpp:112
21#: plugins/IntegratedLightDM/Greeter.cpp:112
22msgid "Password: "
22msgid "Password: "
po/nn.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2015-09-30 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2015-10-16 05:57+0000\n"
19−"X-Generator: Launchpad (build 17768)\n"
19+"X-Generator: Launchpad (build 17812)\n"
20
20
21#: plugins/IntegratedLightDM/Greeter.cpp:112
21#: plugins/IntegratedLightDM/Greeter.cpp:112
22msgid "Password: "
22msgid "Password: "
po/oc.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=2; plural=n > 1;\n"
17"Plural-Forms: nplurals=2; plural=n > 1;\n"
18−"X-Launchpad-Export-Date: 2015-09-30 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2015-10-16 05:57+0000\n"
19−"X-Generator: Launchpad (build 17768)\n"
19+"X-Generator: Launchpad (build 17812)\n"
20
20
21#: plugins/IntegratedLightDM/Greeter.cpp:112
21#: plugins/IntegratedLightDM/Greeter.cpp:112
22msgid "Password: "
22msgid "Password: "
po/or.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=2; plural=n!=1;\n"
17"Plural-Forms: nplurals=2; plural=n!=1;\n"
18−"X-Launchpad-Export-Date: 2015-09-30 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2015-10-16 05:57+0000\n"
19−"X-Generator: Launchpad (build 17768)\n"
19+"X-Generator: Launchpad (build 17812)\n"
20
20
21#: plugins/IntegratedLightDM/Greeter.cpp:112
21#: plugins/IntegratedLightDM/Greeter.cpp:112
22msgid "Password: "
22msgid "Password: "
po/pa.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2015-09-30 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2015-10-16 05:57+0000\n"
19−"X-Generator: Launchpad (build 17768)\n"
19+"X-Generator: Launchpad (build 17812)\n"
20
20
21#: plugins/IntegratedLightDM/Greeter.cpp:112
21#: plugins/IntegratedLightDM/Greeter.cpp:112
22msgid "Password: "
22msgid "Password: "
po/pl.po+5−5
@@ -16,8 +16,8 @@ msgstr ""
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
17"Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
18"|| n%100>=20) ? 1 : 2;\n"
18"|| n%100>=20) ? 1 : 2;\n"
19−"X-Launchpad-Export-Date: 2015-09-30 05:43+0000\n"
19+"X-Launchpad-Export-Date: 2015-10-16 05:57+0000\n"
20−"X-Generator: Launchpad (build 17768)\n"
20+"X-Generator: Launchpad (build 17812)\n"
21
21
22#: plugins/IntegratedLightDM/Greeter.cpp:112
22#: plugins/IntegratedLightDM/Greeter.cpp:112
23msgid "Password: "
23msgid "Password: "
@@ -30,7 +30,7 @@ msgstr "Przypnij skrót"
30
30
31#: plugins/Unity/Launcher/launcheritem.cpp:52
31#: plugins/Unity/Launcher/launcheritem.cpp:52
32msgid "Quit"
32msgid "Quit"
33−msgstr ""
33+msgstr "Zakończ"
34
34
35#: plugins/Unity/Launcher/launcheritem.cpp:106
35#: plugins/Unity/Launcher/launcheritem.cpp:106
36msgid "Unpin shortcut"
36msgid "Unpin shortcut"
@@ -377,7 +377,7 @@ msgstr "Niestety, błędne hasło"
377#: qml/Greeter/NarrowView.qml:121
377#: qml/Greeter/NarrowView.qml:121
378msgctxt "passphrase"
378msgctxt "passphrase"
379msgid "Please re-enter"
379msgid "Please re-enter"
380−msgstr ""
380+msgstr "Wprowadź ponownie"
381
381
382#: qml/Greeter/NarrowView.qml:122
382#: qml/Greeter/NarrowView.qml:122
383msgid "Sorry, incorrect passcode"
383msgid "Sorry, incorrect passcode"
@@ -464,7 +464,7 @@ msgstr "Odpowiedz"
464
464
465#: qml/Panel/Indicators/MessageMenuItemFactory.qml:204
465#: qml/Panel/Indicators/MessageMenuItemFactory.qml:204
466msgid "Call back"
466msgid "Call back"
467−msgstr ""
467+msgstr "Oddzwoń"
468
468
469#: qml/Panel/Indicators/ModemInfoItem.qml:105
469#: qml/Panel/Indicators/ModemInfoItem.qml:105
470msgid "Unlock SIM"
470msgid "Unlock SIM"
po/pt.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2015-09-30 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2015-10-16 05:57+0000\n"
19−"X-Generator: Launchpad (build 17768)\n"
19+"X-Generator: Launchpad (build 17812)\n"
20
20
21#: plugins/IntegratedLightDM/Greeter.cpp:112
21#: plugins/IntegratedLightDM/Greeter.cpp:112
22msgid "Password: "
22msgid "Password: "
po/pt_BR.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=2; plural=n > 1;\n"
17"Plural-Forms: nplurals=2; plural=n > 1;\n"
18−"X-Launchpad-Export-Date: 2015-09-30 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2015-10-16 05:58+0000\n"
19−"X-Generator: Launchpad (build 17768)\n"
19+"X-Generator: Launchpad (build 17812)\n"
20
20
21#: plugins/IntegratedLightDM/Greeter.cpp:112
21#: plugins/IntegratedLightDM/Greeter.cpp:112
22msgid "Password: "
22msgid "Password: "
po/ro.po+2−2
@@ -16,8 +16,8 @@ msgstr ""
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=3; plural=(n == 1 ? 0: (((n % 100 > 19) || ((n % 100 "
17"Plural-Forms: nplurals=3; plural=(n == 1 ? 0: (((n % 100 > 19) || ((n % 100 "
18"== 0) && (n != 0))) ? 2: 1));\n"
18"== 0) && (n != 0))) ? 2: 1));\n"
19−"X-Launchpad-Export-Date: 2015-09-30 05:43+0000\n"
19+"X-Launchpad-Export-Date: 2015-10-16 05:57+0000\n"
20−"X-Generator: Launchpad (build 17768)\n"
20+"X-Generator: Launchpad (build 17812)\n"
21
21
22#: plugins/IntegratedLightDM/Greeter.cpp:112
22#: plugins/IntegratedLightDM/Greeter.cpp:112
23msgid "Password: "
23msgid "Password: "
po/ru.po+2−2
@@ -16,8 +16,8 @@ msgstr ""
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
17"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
18"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
18"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
19−"X-Launchpad-Export-Date: 2015-09-30 05:43+0000\n"
19+"X-Launchpad-Export-Date: 2015-10-16 05:57+0000\n"
20−"X-Generator: Launchpad (build 17768)\n"
20+"X-Generator: Launchpad (build 17812)\n"
21
21
22#: plugins/IntegratedLightDM/Greeter.cpp:112
22#: plugins/IntegratedLightDM/Greeter.cpp:112
23msgid "Password: "
23msgid "Password: "
po/shn.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=2; plural=(n == 1) ? 0 : 1;\n"
17"Plural-Forms: nplurals=2; plural=(n == 1) ? 0 : 1;\n"
18−"X-Launchpad-Export-Date: 2015-09-30 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2015-10-16 05:57+0000\n"
19−"X-Generator: Launchpad (build 17768)\n"
19+"X-Generator: Launchpad (build 17812)\n"
20
20
21#: plugins/IntegratedLightDM/Greeter.cpp:112
21#: plugins/IntegratedLightDM/Greeter.cpp:112
22msgid "Password: "
22msgid "Password: "
po/si.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2015-09-30 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2015-10-16 05:57+0000\n"
19−"X-Generator: Launchpad (build 17768)\n"
19+"X-Generator: Launchpad (build 17812)\n"
20
20
21#: plugins/IntegratedLightDM/Greeter.cpp:112
21#: plugins/IntegratedLightDM/Greeter.cpp:112
22msgid "Password: "
22msgid "Password: "
po/sk.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=3; plural=(n==1) ? 1 : (n>=2 && n<=4) ? 2 : 0;\n"
17"Plural-Forms: nplurals=3; plural=(n==1) ? 1 : (n>=2 && n<=4) ? 2 : 0;\n"
18−"X-Launchpad-Export-Date: 2015-09-30 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2015-10-16 05:57+0000\n"
19−"X-Generator: Launchpad (build 17768)\n"
19+"X-Generator: Launchpad (build 17812)\n"
20
20
21#: plugins/IntegratedLightDM/Greeter.cpp:112
21#: plugins/IntegratedLightDM/Greeter.cpp:112
22msgid "Password: "
22msgid "Password: "
po/sl.po+2−2
@@ -16,8 +16,8 @@ msgstr ""
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=4; plural=(n%100==1 ? 1 : n%100==2 ? 2 : n%100==3 || "
17"Plural-Forms: nplurals=4; plural=(n%100==1 ? 1 : n%100==2 ? 2 : n%100==3 || "
18"n%100==4 ? 3 : 0);\n"
18"n%100==4 ? 3 : 0);\n"
19−"X-Launchpad-Export-Date: 2015-09-30 05:43+0000\n"
19+"X-Launchpad-Export-Date: 2015-10-16 05:57+0000\n"
20−"X-Generator: Launchpad (build 17768)\n"
20+"X-Generator: Launchpad (build 17812)\n"
21
21
22#: plugins/IntegratedLightDM/Greeter.cpp:112
22#: plugins/IntegratedLightDM/Greeter.cpp:112
23msgid "Password: "
23msgid "Password: "
po/sq.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2015-09-30 05:42+0000\n"
18+"X-Launchpad-Export-Date: 2015-10-16 05:57+0000\n"
19−"X-Generator: Launchpad (build 17768)\n"
19+"X-Generator: Launchpad (build 17812)\n"
20
20
21#: plugins/IntegratedLightDM/Greeter.cpp:112
21#: plugins/IntegratedLightDM/Greeter.cpp:112
22msgid "Password: "
22msgid "Password: "
po/sr.po+2−2
@@ -17,8 +17,8 @@ msgstr ""
17"Content-Transfer-Encoding: 8bit\n"
17"Content-Transfer-Encoding: 8bit\n"
18"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
18"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
19"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
19"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
20−"X-Launchpad-Export-Date: 2015-09-30 05:43+0000\n"
20+"X-Launchpad-Export-Date: 2015-10-16 05:57+0000\n"
21−"X-Generator: Launchpad (build 17768)\n"
21+"X-Generator: Launchpad (build 17812)\n"
22"Language: sr\n"
22"Language: sr\n"
23
23
24#: plugins/IntegratedLightDM/Greeter.cpp:112
24#: plugins/IntegratedLightDM/Greeter.cpp:112
po/sv.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2015-09-30 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2015-10-16 05:58+0000\n"
19−"X-Generator: Launchpad (build 17768)\n"
19+"X-Generator: Launchpad (build 17812)\n"
20"Language: sv\n"
20"Language: sv\n"
21
21
22#: plugins/IntegratedLightDM/Greeter.cpp:112
22#: plugins/IntegratedLightDM/Greeter.cpp:112
po/sw.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2015-09-30 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2015-10-16 05:58+0000\n"
19−"X-Generator: Launchpad (build 17768)\n"
19+"X-Generator: Launchpad (build 17812)\n"
20
20
21#: plugins/IntegratedLightDM/Greeter.cpp:112
21#: plugins/IntegratedLightDM/Greeter.cpp:112
22msgid "Password: "
22msgid "Password: "
po/ta.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2015-09-30 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2015-10-16 05:58+0000\n"
19−"X-Generator: Launchpad (build 17768)\n"
19+"X-Generator: Launchpad (build 17812)\n"
20"Language: ta\n"
20"Language: ta\n"
21
21
22#: plugins/IntegratedLightDM/Greeter.cpp:112
22#: plugins/IntegratedLightDM/Greeter.cpp:112
po/te.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2015-09-30 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2015-10-16 05:58+0000\n"
19−"X-Generator: Launchpad (build 17768)\n"
19+"X-Generator: Launchpad (build 17812)\n"
20
20
21#: plugins/IntegratedLightDM/Greeter.cpp:112
21#: plugins/IntegratedLightDM/Greeter.cpp:112
22msgid "Password: "
22msgid "Password: "
po/th.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=1; plural=0;\n"
17"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2015-09-30 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2015-10-16 05:58+0000\n"
19−"X-Generator: Launchpad (build 17768)\n"
19+"X-Generator: Launchpad (build 17812)\n"
20
20
21#: plugins/IntegratedLightDM/Greeter.cpp:112
21#: plugins/IntegratedLightDM/Greeter.cpp:112
22msgid "Password: "
22msgid "Password: "
po/tr.po+4−4
@@ -15,8 +15,8 @@ msgstr ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2015-09-30 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2015-10-16 05:58+0000\n"
19−"X-Generator: Launchpad (build 17768)\n"
19+"X-Generator: Launchpad (build 17812)\n"
20
20
21#: plugins/IntegratedLightDM/Greeter.cpp:112
21#: plugins/IntegratedLightDM/Greeter.cpp:112
22msgid "Password: "
22msgid "Password: "
@@ -29,7 +29,7 @@ msgstr "Kısayolu iğnele"
29
29
30#: plugins/Unity/Launcher/launcheritem.cpp:52
30#: plugins/Unity/Launcher/launcheritem.cpp:52
31msgid "Quit"
31msgid "Quit"
32−msgstr ""
32+msgstr "Çıkış"
33
33
34#: plugins/Unity/Launcher/launcheritem.cpp:106
34#: plugins/Unity/Launcher/launcheritem.cpp:106
35msgid "Unpin shortcut"
35msgid "Unpin shortcut"
@@ -459,7 +459,7 @@ msgstr "Yanıtla"
459
459
460#: qml/Panel/Indicators/MessageMenuItemFactory.qml:204
460#: qml/Panel/Indicators/MessageMenuItemFactory.qml:204
461msgid "Call back"
461msgid "Call back"
462−msgstr ""
462+msgstr "Geri ara"
463
463
464#: qml/Panel/Indicators/ModemInfoItem.qml:105
464#: qml/Panel/Indicators/ModemInfoItem.qml:105
465msgid "Unlock SIM"
465msgid "Unlock SIM"
po/ug.po+9−9
@@ -9,14 +9,14 @@ msgstr ""
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10"POT-Creation-Date: 2015-09-16 00:49+0200\n"
10"POT-Creation-Date: 2015-09-16 00:49+0200\n"
11"PO-Revision-Date: 2015-10-02 03:54+0000\n"
11"PO-Revision-Date: 2015-10-02 03:54+0000\n"
12−"Last-Translator: eltikin <eltikinuyghur@hotmail.com>\n"
12+"Last-Translator: Eltikin <eltikinuyghur@hotmail.com>\n"
13"Language-Team: Uyghur Computer Science Association <UKIJ@yahoogroups.com>\n"
13"Language-Team: Uyghur Computer Science Association <UKIJ@yahoogroups.com>\n"
14"MIME-Version: 1.0\n"
14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=1; plural=0;\n"
17"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2015-10-03 05:40+0000\n"
18+"X-Launchpad-Export-Date: 2015-10-16 05:58+0000\n"
19−"X-Generator: Launchpad (build 17783)\n"
19+"X-Generator: Launchpad (build 17812)\n"
20
20
21#: plugins/IntegratedLightDM/Greeter.cpp:112
21#: plugins/IntegratedLightDM/Greeter.cpp:112
22msgid "Password: "
22msgid "Password: "
@@ -48,7 +48,7 @@ msgstr ""
48#. en_US example: "%l:%M %p" --> "1:00 PM"
48#. en_US example: "%l:%M %p" --> "1:00 PM"
49#: plugins/Utils/relativetimeformatter.cpp:164
49#: plugins/Utils/relativetimeformatter.cpp:164
50msgid "%l:%M %p"
50msgid "%l:%M %p"
51−msgstr ""
51+msgstr "%l:%M %p"
52
52
53#. Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
53#. Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
54#. This format string is used for showing, on a 12-hour clock, events/appointments that happen tomorrow.
54#. This format string is used for showing, on a 12-hour clock, events/appointments that happen tomorrow.
@@ -64,7 +64,7 @@ msgstr "ئەتە %l:%M %p"
64#. en_US example: "%a\u2003%l:%M %p" --> "Fri 1:00 PM"
64#. en_US example: "%a\u2003%l:%M %p" --> "Fri 1:00 PM"
65#: plugins/Utils/relativetimeformatter.cpp:181
65#: plugins/Utils/relativetimeformatter.cpp:181
66msgid "%a %l:%M %p"
66msgid "%a %l:%M %p"
67−msgstr ""
67+msgstr "%a %l:%M %p"
68
68
69#. Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
69#. Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
70#. This format string is used for showing, on a 12-hour clock, times that happened before a week from now.
70#. This format string is used for showing, on a 12-hour clock, times that happened before a week from now.
@@ -73,7 +73,7 @@ msgstr ""
73#. en_GB example: "%a %b %d\u2003%l:%M %p" --> "Fri 31 Oct 1:00 PM"
73#. en_GB example: "%a %b %d\u2003%l:%M %p" --> "Fri 31 Oct 1:00 PM"
74#: plugins/Utils/relativetimeformatter.cpp:190
74#: plugins/Utils/relativetimeformatter.cpp:190
75msgid "%a %d %b %l:%M %p"
75msgid "%a %d %b %l:%M %p"
76−msgstr ""
76+msgstr "%a %d %b %l:%M %p"
77
77
78#. Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
78#. Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
79#. This format string is used for showing, on a 24-hour clock, times that happen yesterday.
79#. This format string is used for showing, on a 24-hour clock, times that happen yesterday.
@@ -88,7 +88,7 @@ msgstr ""
88#. en_US example: "%H:%M" --> "13:00"
88#. en_US example: "%H:%M" --> "13:00"
89#: plugins/Utils/relativetimeformatter.cpp:208
89#: plugins/Utils/relativetimeformatter.cpp:208
90msgid "%H:%M"
90msgid "%H:%M"
91−msgstr ""
91+msgstr "%H:%M"
92
92
93#. Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
93#. Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
94#. This format string is used for showing, on a 24-hour clock, events/appointments that happen tomorrow.
94#. This format string is used for showing, on a 24-hour clock, events/appointments that happen tomorrow.
@@ -104,7 +104,7 @@ msgstr "ئەتە %H:%M"
104#. en_US example: "%a\u2003%H:%M" --> "Fri 13:00"
104#. en_US example: "%a\u2003%H:%M" --> "Fri 13:00"
105#: plugins/Utils/relativetimeformatter.cpp:225
105#: plugins/Utils/relativetimeformatter.cpp:225
106msgid "%a %H:%M"
106msgid "%a %H:%M"
107−msgstr ""
107+msgstr "%a %H:%M"
108
108
109#. Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
109#. Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
110#. This format string is used for showing, on a 24-hour clock, times that happened before a week from now.
110#. This format string is used for showing, on a 24-hour clock, times that happened before a week from now.
@@ -113,7 +113,7 @@ msgstr ""
113#. en_GB example: "%a %b %d\u2003%H:%M" --> "Fri 31 Oct 13:00"
113#. en_GB example: "%a %b %d\u2003%H:%M" --> "Fri 31 Oct 13:00"
114#: plugins/Utils/relativetimeformatter.cpp:234
114#: plugins/Utils/relativetimeformatter.cpp:234
115msgid "%a %d %b %H:%M"
115msgid "%a %d %b %H:%M"
116−msgstr ""
116+msgstr "%a %d %b %H:%M"
117
117
118#: qml/Components/DelayedLockscreen.qml:49
118#: qml/Components/DelayedLockscreen.qml:49
119msgid "Device Locked"
119msgid "Device Locked"
po/uk.po+2−2
@@ -16,8 +16,8 @@ msgstr ""
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
17"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
18"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
18"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
19−"X-Launchpad-Export-Date: 2015-09-30 05:43+0000\n"
19+"X-Launchpad-Export-Date: 2015-10-16 05:58+0000\n"
20−"X-Generator: Launchpad (build 17768)\n"
20+"X-Generator: Launchpad (build 17812)\n"
21
21
22#: plugins/IntegratedLightDM/Greeter.cpp:112
22#: plugins/IntegratedLightDM/Greeter.cpp:112
23msgid "Password: "
23msgid "Password: "
po/ur.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2015-09-30 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2015-10-16 05:58+0000\n"
19−"X-Generator: Launchpad (build 17768)\n"
19+"X-Generator: Launchpad (build 17812)\n"
20
20
21#: plugins/IntegratedLightDM/Greeter.cpp:112
21#: plugins/IntegratedLightDM/Greeter.cpp:112
22msgid "Password: "
22msgid "Password: "
po/uz.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=1; plural=0;\n"
17"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2015-09-30 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2015-10-16 05:58+0000\n"
19−"X-Generator: Launchpad (build 17768)\n"
19+"X-Generator: Launchpad (build 17812)\n"
20
20
21#: plugins/IntegratedLightDM/Greeter.cpp:112
21#: plugins/IntegratedLightDM/Greeter.cpp:112
22msgid "Password: "
22msgid "Password: "
po/vi.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=1; plural=0;\n"
17"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2015-09-30 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2015-10-16 05:58+0000\n"
19−"X-Generator: Launchpad (build 17768)\n"
19+"X-Generator: Launchpad (build 17812)\n"
20
20
21#: plugins/IntegratedLightDM/Greeter.cpp:112
21#: plugins/IntegratedLightDM/Greeter.cpp:112
22msgid "Password: "
22msgid "Password: "
po/xh.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2015-09-30 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2015-10-16 05:58+0000\n"
19−"X-Generator: Launchpad (build 17768)\n"
19+"X-Generator: Launchpad (build 17812)\n"
20
20
21#: plugins/IntegratedLightDM/Greeter.cpp:112
21#: plugins/IntegratedLightDM/Greeter.cpp:112
22msgid "Password: "
22msgid "Password: "
po/zh_CN.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=1; plural=0;\n"
17"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2015-09-30 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2015-10-16 05:58+0000\n"
19−"X-Generator: Launchpad (build 17768)\n"
19+"X-Generator: Launchpad (build 17812)\n"
20
20
21#: plugins/IntegratedLightDM/Greeter.cpp:112
21#: plugins/IntegratedLightDM/Greeter.cpp:112
22msgid "Password: "
22msgid "Password: "
po/zh_HK.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=1; plural=0;\n"
17"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2015-09-30 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2015-10-16 05:58+0000\n"
19−"X-Generator: Launchpad (build 17768)\n"
19+"X-Generator: Launchpad (build 17812)\n"
20
20
21#: plugins/IntegratedLightDM/Greeter.cpp:112
21#: plugins/IntegratedLightDM/Greeter.cpp:112
22msgid "Password: "
22msgid "Password: "
po/zh_TW.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=1; plural=0;\n"
17"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2015-09-30 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2015-10-16 05:58+0000\n"
19−"X-Generator: Launchpad (build 17768)\n"
19+"X-Generator: Launchpad (build 17812)\n"
20"Language: zh_TW\n"
20"Language: zh_TW\n"
21
21
22#: plugins/IntegratedLightDM/Greeter.cpp:112
22#: plugins/IntegratedLightDM/Greeter.cpp:112
qml/Components/Dialogs.qml+3−2
@@ -20,6 +20,7 @@ import Unity.Application 0.1
20import Unity.Session 0.1
20import Unity.Session 0.1
21import Ubuntu.Components 1.1
21import Ubuntu.Components 1.1
22import GlobalShortcut 1.0
22import GlobalShortcut 1.0
23+import Unity.Platform 1.0
23import "../Greeter"
24import "../Greeter"
24
25
25Item {
26Item {
@@ -46,13 +47,13 @@ Item {
46
47
47 GlobalShortcut { // reboot/shutdown dialog
48 GlobalShortcut { // reboot/shutdown dialog
48 shortcut: Qt.Key_PowerDown
49 shortcut: Qt.Key_PowerDown
49− active: root.usageScenario === "desktop"
50+ active: Platform.isPC
50 onTriggered: root.unitySessionService.RequestShutdown()
51 onTriggered: root.unitySessionService.RequestShutdown()
51 }
52 }
52
53
53 GlobalShortcut { // reboot/shutdown dialog
54 GlobalShortcut { // reboot/shutdown dialog
54 shortcut: Qt.Key_PowerOff
55 shortcut: Qt.Key_PowerOff
55− active: root.usageScenario === "desktop"
56+ active: Platform.isPC
56 onTriggered: root.unitySessionService.RequestShutdown()
57 onTriggered: root.unitySessionService.RequestShutdown()
57 }
58 }
58
59
qml/Components/Orientations.qmlnew file+29
@@ -0,0 +1,29 @@
1+/*
2+ * Copyright 2015 Canonical Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.4
18+
19+QtObject {
20+ // Just because "native" is a reserved keyword :(
21+ property int native_: Qt.PortraitOrientation
22+
23+ property int primary: Qt.PortraitOrientation
24+
25+ property int landscape: Qt.LandscapeOrientation
26+ property int invertedLandscape: Qt.InvertedLandscapeOrientation
27+ property int portrait: Qt.PortraitOrientation
28+ property int invertedPortrait: Qt.InvertedPortraitOrientation
29+}
qml/Components/ScreenGrabber.qml+4−1
@@ -26,6 +26,9 @@ Rectangle {
26 anchors.fill: parent
26 anchors.fill: parent
27 opacity: 0.0
27 opacity: 0.0
28
28
29+ // to be set from outside
30+ property int rotationAngle: 0
31+
29 ScreenGrabber {
32 ScreenGrabber {
30 id: screenGrabber
33 id: screenGrabber
31 objectName: "screenGrabber"
34 objectName: "screenGrabber"
@@ -67,7 +70,7 @@ Rectangle {
67 to: 0.0
70 to: 0.0
68 onStopped: {
71 onStopped: {
69 if (visible) {
72 if (visible) {
70− screenGrabber.captureAndSave();
73+ screenGrabber.captureAndSave(root.rotationAngle);
71 visible = false;
74 visible = false;
72 }
75 }
73 }
76 }
qml/Components/WallpaperResolver.qmlnew file+63
@@ -0,0 +1,63 @@
1+/*
2+ * Copyright (C) 2015 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.4
18+import AccountsService 0.1
19+import GSettings 1.0
20+import Ubuntu.Components 1.3
21+
22+/*
23+ Defines the background URL based on several factors, such as:
24+ - default, fallback, background
25+ - Background set in AccountSettings, if any
26+ - Background set in GSettings, if any
27+ */
28+QtObject {
29+ // Users should set their UI width here.
30+ property real width
31+
32+ property url defaultBackground: Qt.resolvedUrl(width >= units.gu(60) ? "../graphics/tablet_background.jpg"
33+ : "../graphics/phone_background.jpg")
34+
35+ // That's the property users of this component are going to consume.
36+ readonly property url background: asImageTester.status == Image.Ready ? asImageTester.source
37+ : gsImageTester.status == Image.Ready ? gsImageTester.source : defaultBackground
38+
39+ // This is a dummy image to detect if the custom AS set wallpaper loads successfully.
40+ property var _asImageTester: Image {
41+ id: asImageTester
42+ source: AccountsService.backgroundFile != undefined && AccountsService.backgroundFile.length > 0 ? AccountsService.backgroundFile : ""
43+ height: 0
44+ width: 0
45+ sourceSize.height: 0
46+ sourceSize.width: 0
47+ }
48+
49+ // This is a dummy image to detect if the custom GSettings set wallpaper loads successfully.
50+ property var _gsImageTester: Image {
51+ id: gsImageTester
52+ source: backgroundSettings.pictureUri && backgroundSettings.pictureUri.length > 0 ? backgroundSettings.pictureUri : ""
53+ height: 0
54+ width: 0
55+ sourceSize.height: 0
56+ sourceSize.width: 0
57+ }
58+
59+ property var _gsettings: GSettings {
60+ id: backgroundSettings
61+ schema.id: "org.gnome.desktop.background"
62+ }
63+}
qml/Components/WindowControlButtons.qml+3
@@ -28,6 +28,7 @@ Row {
28 signal maximize()
28 signal maximize()
29
29
30 Rectangle {
30 Rectangle {
31+ objectName: "closeWindowButton"
31 height: parent.height; width: height; radius: height / 2
32 height: parent.height; width: height; radius: height / 2
32 gradient: Gradient {
33 gradient: Gradient {
33 GradientStop { color: "#F49073"; position: 0 }
34 GradientStop { color: "#F49073"; position: 0 }
@@ -38,6 +39,7 @@ Row {
38 MouseArea { anchors.fill: parent; onClicked: root.close() }
39 MouseArea { anchors.fill: parent; onClicked: root.close() }
39 }
40 }
40 Rectangle {
41 Rectangle {
42+ objectName: "minimizeWindowButton"
41 height: parent.height; width: height; radius: height / 2
43 height: parent.height; width: height; radius: height / 2
42 gradient: Gradient {
44 gradient: Gradient {
43 GradientStop { color: "#92918C"; position: 0 }
45 GradientStop { color: "#92918C"; position: 0 }
@@ -48,6 +50,7 @@ Row {
48 MouseArea { anchors.fill: parent; onClicked: root.minimize() }
50 MouseArea { anchors.fill: parent; onClicked: root.minimize() }
49 }
51 }
50 Rectangle {
52 Rectangle {
53+ objectName: "maximizeWindowButton"
51 height: parent.height; width: height; radius: height / 2
54 height: parent.height; width: height; radius: height / 2
52 gradient: Gradient {
55 gradient: Gradient {
53 GradientStop { color: "#92918C"; position: 0 }
56 GradientStop { color: "#92918C"; position: 0 }
qml/DeviceConfiguration.qml+84−63
@@ -16,78 +16,99 @@
16
16
17import QtQuick 2.0
17import QtQuick 2.0
18
18
19−StateGroup {
19+QtObject {
20 id: root
20 id: root
21
21
22 readonly property int useNativeOrientation: -1
22 readonly property int useNativeOrientation: -1
23
23
24− property int primaryOrientation: useNativeOrientation
24+ // The only writable property in the API
25+ // all other properties are set according to the device name
26+ property alias name: priv.state
25
27
26− property int supportedOrientations: Qt.PortraitOrientation
28+ readonly property alias primaryOrientation: priv.primaryOrientation
27− | Qt.InvertedPortraitOrientation
29+ readonly property alias supportedOrientations: priv.supportedOrientations
28− | Qt.LandscapeOrientation
30+ readonly property alias landscapeOrientation: priv.landscapeOrientation
29− | Qt.InvertedLandscapeOrientation
31+ readonly property alias invertedLandscapeOrientation: priv.invertedLandscapeOrientation
32+ readonly property alias portraitOrientation: priv.portraitOrientation
33+ readonly property alias invertedPortraitOrientation: priv.invertedPortraitOrientation
30
34
31− // Supported values so far:
32− // "phone", "tablet" or "desktop"
33− property string category: "phone"
35+ readonly property alias category: priv.category
34
36
35− property int ignoredMice: 0
37+ readonly property alias ignoredMice: priv.ignoredMice
36
38
39+ readonly property var priv: StateGroup {
40+ id: priv
37
41
38− property alias name: root.state
42+ property int primaryOrientation: root.useNativeOrientation
39
43
40− states: [
44+ property int supportedOrientations: Qt.PortraitOrientation
41− State {
45+ | Qt.InvertedPortraitOrientation
42− name: "mako"
43− PropertyChanges {
44− target: root
45− supportedOrientations: Qt.PortraitOrientation
46− | Qt.LandscapeOrientation
46+ | Qt.LandscapeOrientation
47− | Qt.InvertedLandscapeOrientation
47+ | Qt.InvertedLandscapeOrientation
48− }
48+
49− },
50− State {
51− name: "krillin"
52− PropertyChanges {
53− target: root
54− supportedOrientations: Qt.PortraitOrientation
55− | Qt.LandscapeOrientation
49+ property int landscapeOrientation: Qt.LandscapeOrientation
56− | Qt.InvertedLandscapeOrientation
50+ property int invertedLandscapeOrientation: Qt.InvertedLandscapeOrientation
57− }
58− },
59− State {
60− name: "arale"
61− PropertyChanges {
62− target: root
63− supportedOrientations: Qt.PortraitOrientation
51+ property int portraitOrientation: Qt.PortraitOrientation
64− | Qt.LandscapeOrientation
52+ property int invertedPortraitOrientation: Qt.InvertedPortraitOrientation
65− | Qt.InvertedLandscapeOrientation
53+
66− ignoredMice: 1
54+ // Supported values so far:
67− }
68− },
69− State {
70− name: "manta"
71− PropertyChanges {
72− target: root
73− category: "tablet"
74− }
75− },
76− State {
77− name: "flo"
78− PropertyChanges {
79− target: root
80− primaryOrientation: Qt.InvertedLandscapeOrientation
81− category: "tablet"
82− }
83− },
84− State {
85− name: "desktop"
55+ // "phone", "tablet" or "desktop"
86− PropertyChanges {
56+ property string category: "phone"
87− target: root
88− category: "desktop"
89− }
90− }
91− ]
92
57
58+ property int ignoredMice: 0
59+
60+ states: [
61+ State {
62+ name: "mako"
63+ PropertyChanges {
64+ target: priv
65+ supportedOrientations: Qt.PortraitOrientation
66+ | Qt.LandscapeOrientation
67+ | Qt.InvertedLandscapeOrientation
68+ }
69+ },
70+ State {
71+ name: "krillin"
72+ PropertyChanges {
73+ target: priv
74+ supportedOrientations: Qt.PortraitOrientation
75+ | Qt.LandscapeOrientation
76+ | Qt.InvertedLandscapeOrientation
77+ }
78+ },
79+ State {
80+ name: "arale"
81+ PropertyChanges {
82+ target: priv
83+ supportedOrientations: Qt.PortraitOrientation
84+ | Qt.LandscapeOrientation
85+ | Qt.InvertedLandscapeOrientation
86+ ignoredMice: 1
87+ }
88+ },
89+ State {
90+ name: "manta"
91+ PropertyChanges {
92+ target: priv
93+ category: "tablet"
94+ }
95+ },
96+ State {
97+ name: "flo"
98+ PropertyChanges {
99+ target: priv
100+ landscapeOrientation: Qt.InvertedLandscapeOrientation
101+ primaryOrientation: Qt.InvertedLandscapeOrientation
102+ category: "tablet"
103+ }
104+ },
105+ State {
106+ name: "desktop"
107+ PropertyChanges {
108+ target: priv
109+ category: "desktop"
110+ }
111+ }
112+ ]
113+ }
93}
114}
qml/DisabledScreenNotice.qmlnew file+49
@@ -0,0 +1,49 @@
1+/*
2+ * Copyright (C) 2015 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.4
18+import Ubuntu.Components 1.3
19+import "Components"
20+
21+Image {
22+ id: root
23+
24+ WallpaperResolver {
25+ width: root.width
26+ id: wallpaperResolver
27+ }
28+
29+ source: wallpaperResolver.background
30+
31+ UbuntuShape {
32+ anchors.fill: text
33+ anchors.margins: -units.gu(2)
34+ backgroundColor: "black"
35+ opacity: 0.4
36+ }
37+
38+ Label {
39+ id: text
40+ anchors.centerIn: parent
41+ width: parent.width / 2
42+ text: i18n.tr("Your device is now connected to an external display.")
43+ color: "white"
44+ horizontalAlignment: Text.AlignHCenter
45+ verticalAlignment: Text.AlignVCenter
46+ fontSize: "x-large"
47+ wrapMode: Text.Wrap
48+ }
49+}
qml/Greeter/Greeter.qml+1−1
@@ -251,7 +251,7 @@ Showable {
251
251
252 // event eater
252 // event eater
253 // Nothing should leak to items behind the greeter
253 // Nothing should leak to items behind the greeter
254− MouseArea { anchors.fill: parent }
254+ MouseArea { anchors.fill: parent; hoverEnabled: true }
255
255
256 Loader {
256 Loader {
257 id: loader
257 id: loader
qml/Launcher/Launcher.qml+1
@@ -188,6 +188,7 @@ Item {
188 bottom: parent.bottom
188 bottom: parent.bottom
189 }
189 }
190 enabled: root.shadeBackground && root.state == "visible"
190 enabled: root.shadeBackground && root.state == "visible"
191+ visible: enabled // otherwise it will get in the way of cursor selection for some reason
191 onPressed: {
192 onPressed: {
192 root.state = ""
193 root.state = ""
193 }
194 }
qml/Notifications/Notification.qml+4−2
@@ -50,6 +50,7 @@ Item {
50 readonly property real contentSpacing: units.gu(2)
50 readonly property real contentSpacing: units.gu(2)
51 readonly property bool canBeClosed: type === Notification.Ephemeral
51 readonly property bool canBeClosed: type === Notification.Ephemeral
52 property bool hasMouse
52 property bool hasMouse
53+ property url background: ""
53
54
54 objectName: "background"
55 objectName: "background"
55 implicitHeight: type !== Notification.PlaceHolder ? (fullscreen ? maxHeight : outterColumn.height - shapedBack.anchors.topMargin + contentSpacing * 2) : 0
56 implicitHeight: type !== Notification.PlaceHolder ? (fullscreen ? maxHeight : outterColumn.height - shapedBack.anchors.topMargin + contentSpacing * 2) : 0
@@ -283,7 +284,7 @@ Item {
283 fontSize: "medium"
284 fontSize: "medium"
284 color: darkOnBright ? sdFontColor : Theme.palette.selected.backgroundText
285 color: darkOnBright ? sdFontColor : Theme.palette.selected.backgroundText
285 elide: Text.ElideRight
286 elide: Text.ElideRight
286− textFormat: Text.StyledText
287+ textFormat: Text.PlainText
287 }
288 }
288
289
289 Label {
290 Label {
@@ -300,7 +301,7 @@ Item {
300 wrapMode: Text.WordWrap
301 wrapMode: Text.WordWrap
301 maximumLineCount: type == Notification.SnapDecision ? 12 : 2
302 maximumLineCount: type == Notification.SnapDecision ? 12 : 2
302 elide: Text.ElideRight
303 elide: Text.ElideRight
303− textFormat: Text.StyledText
304+ textFormat: Text.PlainText
304 }
305 }
305 }
306 }
306
307
@@ -401,6 +402,7 @@ Item {
401 menuData: model
402 menuData: model
402 menuIndex: index
403 menuIndex: index
403 maxHeight: notification.maxHeight
404 maxHeight: notification.maxHeight
405+ background: notification.background
404
406
405 onLoaded: {
407 onLoaded: {
406 notification.fullscreen = Qt.binding(function() { return fullscreen; });
408 notification.fullscreen = Qt.binding(function() { return fullscreen; });
qml/Notifications/NotificationMenuItemFactory.qml+2−1
@@ -30,6 +30,7 @@ Loader {
30 property int menuIndex : -1
30 property int menuIndex : -1
31 property int maxHeight
31 property int maxHeight
32 readonly property bool fullscreen: menuData.type === "com.canonical.snapdecision.pinlock"
32 readonly property bool fullscreen: menuData.type === "com.canonical.snapdecision.pinlock"
33+ property url background: ""
33
34
34 signal accepted()
35 signal accepted()
35
36
@@ -149,7 +150,7 @@ Loader {
149 infoText: notification.summary
150 infoText: notification.summary
150 errorText: errorAction.valid ? errorAction.state : ""
151 errorText: errorAction.valid ? errorAction.state : ""
151 retryText: notification.body
152 retryText: notification.body
152− background: shell.background
153+ background: menuFactory.background
153 darkenBackground: 0.4
154 darkenBackground: 0.4
154
155
155 onEntered: {
156 onEntered: {
qml/Notifications/Notifications.qml+2
@@ -29,6 +29,7 @@ ListView {
29 property real margin
29 property real margin
30 property bool useModal: snapDecisionProxyModel.count > 0
30 property bool useModal: snapDecisionProxyModel.count > 0
31 property bool hasMouse
31 property bool hasMouse
32+ property url background: ""
32
33
33 UnitySortFilterProxyModel {
34 UnitySortFilterProxyModel {
34 id: snapDecisionProxyModel
35 id: snapDecisionProxyModel
@@ -60,6 +61,7 @@ ListView {
60 maxHeight: notificationList.height
61 maxHeight: notificationList.height
61 margins: notificationList.margin
62 margins: notificationList.margin
62 hasMouse: notificationList.hasMouse
63 hasMouse: notificationList.hasMouse
64+ background: notificationList.background
63
65
64 // make sure there's no opacity-difference between the several
66 // make sure there's no opacity-difference between the several
65 // elements in a notification
67 // elements in a notification
qml/OrientedShell.qml+41−22
@@ -32,20 +32,31 @@ Rectangle {
32 implicitWidth: units.gu(40)
32 implicitWidth: units.gu(40)
33 implicitHeight: units.gu(71)
33 implicitHeight: units.gu(71)
34
34
35− // NB: native and primary orientations here don't map exactly to their QScreen counterparts
36− readonly property int nativeOrientation: width > height ? Qt.LandscapeOrientation : Qt.PortraitOrientation
37−
38− readonly property int primaryOrientation:
39− deviceConfiguration.primaryOrientation == deviceConfiguration.useNativeOrientation
40− ? nativeOrientation : deviceConfiguration.primaryOrientation
41−
42 DeviceConfiguration {
35 DeviceConfiguration {
43 id: deviceConfiguration
36 id: deviceConfiguration
44 name: applicationArguments.deviceName
37 name: applicationArguments.deviceName
45 }
38 }
46
39
40+ property alias orientations: d.orientations
41+
42+ Item {
43+ id: d
44+
45+ property Orientations orientations: Orientations {
46+ id: orientations
47+ // NB: native and primary orientations here don't map exactly to their QScreen counterparts
48+ native_: root.width > root.height ? Qt.LandscapeOrientation : Qt.PortraitOrientation
49+
50+ primary: deviceConfiguration.primaryOrientation == deviceConfiguration.useNativeOrientation
51+ ? native_ : deviceConfiguration.primaryOrientation
47
52
53+ landscape: deviceConfiguration.landscapeOrientation
54+ invertedLandscape: deviceConfiguration.invertedLandscapeOrientation
55+ portrait: deviceConfiguration.portraitOrientation
56+ invertedPortrait: deviceConfiguration.invertedPortraitOrientation
57+ }
58+ }
48− // to be overwritten by tests
59+ // to be overwritten by tests
49 property var unity8Settings: Unity8Settings {}
60 property var unity8Settings: Unity8Settings {}
50 property var oskSettings: GSettings { schema.id: "com.canonical.keyboard.maliit" }
61 property var oskSettings: GSettings { schema.id: "com.canonical.keyboard.maliit" }
51
62
@@ -76,6 +87,12 @@ Rectangle {
76 oskSettings.disableHeight = shell.usageScenario == "desktop"
87 oskSettings.disableHeight = shell.usageScenario == "desktop"
77 }
88 }
78
89
90+ // we must rotate to a supported orientation regardless of shell's preference
91+ property bool orientationChangesEnabled:
92+ (orientation & supportedOrientations) === 0 ? true
93+ : shell.orientationChangesEnabled
94+
95+
79 Binding {
96 Binding {
80 target: oskSettings
97 target: oskSettings
81 property: "stayHidden"
98 property: "stayHidden"
@@ -89,10 +106,13 @@ Rectangle {
89 }
106 }
90
107
91 readonly property int supportedOrientations: shell.supportedOrientations
108 readonly property int supportedOrientations: shell.supportedOrientations
92− & deviceConfiguration.supportedOrientations
109+ & (deviceConfiguration.supportedOrientations == deviceConfiguration.useNativeOrientation
110+ ? nativeOrientation
111+ : deviceConfiguration.supportedOrientations)
112+
93 property int acceptedOrientationAngle: {
113 property int acceptedOrientationAngle: {
94 if (orientation & supportedOrientations) {
114 if (orientation & supportedOrientations) {
95− return Screen.angleBetween(nativeOrientation, orientation);
115+ return Screen.angleBetween(orientations.native_, orientation);
96 } else if (shell.orientation & supportedOrientations) {
116 } else if (shell.orientation & supportedOrientations) {
97 // stay where we are
117 // stay where we are
98 return shell.orientationAngle;
118 return shell.orientationAngle;
@@ -102,16 +122,16 @@ Rectangle {
102 // rotate to some supported orientation as we can't stay where we currently are
122 // rotate to some supported orientation as we can't stay where we currently are
103 // TODO: Choose the closest to the current one
123 // TODO: Choose the closest to the current one
104 if (supportedOrientations & Qt.PortraitOrientation) {
124 if (supportedOrientations & Qt.PortraitOrientation) {
105− return Screen.angleBetween(nativeOrientation, Qt.PortraitOrientation);
125+ return Screen.angleBetween(orientations.native_, Qt.PortraitOrientation);
106 } else if (supportedOrientations & Qt.LandscapeOrientation) {
126 } else if (supportedOrientations & Qt.LandscapeOrientation) {
107− return Screen.angleBetween(nativeOrientation, Qt.LandscapeOrientation);
127+ return Screen.angleBetween(orientations.native_, Qt.LandscapeOrientation);
108 } else if (supportedOrientations & Qt.InvertedPortraitOrientation) {
128 } else if (supportedOrientations & Qt.InvertedPortraitOrientation) {
109− return Screen.angleBetween(nativeOrientation, Qt.InvertedPortraitOrientation);
129+ return Screen.angleBetween(orientations.native_, Qt.InvertedPortraitOrientation);
110 } else if (supportedOrientations & Qt.InvertedLandscapeOrientation) {
130 } else if (supportedOrientations & Qt.InvertedLandscapeOrientation) {
111− return Screen.angleBetween(nativeOrientation, Qt.InvertedLandscapeOrientation);
131+ return Screen.angleBetween(orientations.native_, Qt.InvertedLandscapeOrientation);
112 } else {
132 } else {
113 // if all fails, fallback to primary orientation
133 // if all fails, fallback to primary orientation
114− return Screen.angleBetween(nativeOrientation, primaryOrientation);
134+ return Screen.angleBetween(orientations.native_, orientations.primary);
115 }
135 }
116 }
136 }
117 }
137 }
@@ -119,19 +139,19 @@ Rectangle {
119 function angleToOrientation(angle) {
139 function angleToOrientation(angle) {
120 switch (angle) {
140 switch (angle) {
121 case 0:
141 case 0:
122− return nativeOrientation;
142+ return orientations.native_;
123 case 90:
143 case 90:
124− return nativeOrientation === Qt.PortraitOrientation ? Qt.InvertedLandscapeOrientation
144+ return orientations.native_ === Qt.PortraitOrientation ? Qt.InvertedLandscapeOrientation
125 : Qt.PortraitOrientation;
145 : Qt.PortraitOrientation;
126 case 180:
146 case 180:
127− return nativeOrientation === Qt.PortraitOrientation ? Qt.InvertedPortraitOrientation
147+ return orientations.native_ === Qt.PortraitOrientation ? Qt.InvertedPortraitOrientation
128 : Qt.InvertedLandscapeOrientation;
148 : Qt.InvertedLandscapeOrientation;
129 case 270:
149 case 270:
130− return nativeOrientation === Qt.PortraitOrientation ? Qt.LandscapeOrientation
150+ return orientations.native_ === Qt.PortraitOrientation ? Qt.LandscapeOrientation
131 : Qt.InvertedPortraitOrientation;
151 : Qt.InvertedPortraitOrientation;
132 default:
152 default:
133 console.warn("angleToOrientation: Invalid orientation angle: " + angle);
153 console.warn("angleToOrientation: Invalid orientation angle: " + angle);
134− return primaryOrientation;
154+ return orientations.primary;
135 }
155 }
136 }
156 }
137
157
@@ -150,8 +170,7 @@ Rectangle {
150 width: root.width
170 width: root.width
151 height: root.height
171 height: root.height
152 orientation: root.angleToOrientation(orientationAngle)
172 orientation: root.angleToOrientation(orientationAngle)
153− primaryOrientation: root.primaryOrientation
173+ orientations: root.orientations
154− nativeOrientation: root.nativeOrientation
155 nativeWidth: root.width
174 nativeWidth: root.width
156 nativeHeight: root.height
175 nativeHeight: root.height
157 mode: applicationArguments.mode
176 mode: applicationArguments.mode
qml/Panel/Indicators/MenuItemFactory.qml+19−15
@@ -20,7 +20,7 @@ import Ubuntu.Settings.Components 0.1
20import QMenuModel 0.1
20import QMenuModel 0.1
21import Utils 0.1 as Utils
21import Utils 0.1 as Utils
22import Ubuntu.Components.ListItems 0.1 as ListItems
22import Ubuntu.Components.ListItems 0.1 as ListItems
23−import Ubuntu.Components 1.2
23+import Ubuntu.Components 1.3
24import Unity.Session 0.1
24import Unity.Session 0.1
25
25
26Item {
26Item {
@@ -350,20 +350,23 @@ Item {
350 id: alarmMenu;
350 id: alarmMenu;
351
351
352 Menus.EventMenu {
352 Menus.EventMenu {
353+ id: alarmItem
353 objectName: "alarmMenu"
354 objectName: "alarmMenu"
354 property QtObject menuData: null
355 property QtObject menuData: null
355 property var menuModel: menuFactory.menuModel
356 property var menuModel: menuFactory.menuModel
356 property int menuIndex: -1
357 property int menuIndex: -1
357 property var extendedData: menuData && menuData.ext || undefined
358 property var extendedData: menuData && menuData.ext || undefined
358− // TODO - bug #1260728
359+
359− property var timeFormatter: Utils.GDateTimeFormatter {
360+ property date serverTime: new Date(getExtendedProperty(extendedData, "xCanonicalTime", 0) * 1000)
360− time: getExtendedProperty(extendedData, "xCanonicalTime", 0)
361+ LiveTimer {
362+ frequency: LiveTimer.Relative
363+ relativeTime: alarmItem.serverTime
361− format: getExtendedProperty(extendedData, "xCanonicalTimeFormat", "")
364+ onTrigger: alarmItem.serverTime = new Date(getExtendedProperty(extendedData, "xCanonicalTime", 0) * 1000)
362 }
365 }
363
366
364 text: menuData && menuData.label || ""
367 text: menuData && menuData.label || ""
365 iconSource: menuData && menuData.icon || "image://theme/alarm-clock"
368 iconSource: menuData && menuData.icon || "image://theme/alarm-clock"
366− time: timeFormatter.timeString
369+ time: i18n.relativeDateTime(serverTime)
367 enabled: menuData && menuData.sensitive || false
370 enabled: menuData && menuData.sensitive || false
368 highlightWhenPressed: false
371 highlightWhenPressed: false
369
372
@@ -379,8 +382,7 @@ Item {
379
382
380 function loadAttributes() {
383 function loadAttributes() {
381 if (!menuModel || menuIndex == -1) return;
384 if (!menuModel || menuIndex == -1) return;
382− menuModel.loadExtendedAttributes(menuIndex, {'x-canonical-time': 'int64',
385+ menuModel.loadExtendedAttributes(menuIndex, {'x-canonical-time': 'int64'});
383− 'x-canonical-time-format': 'string'});
384 }
386 }
385 }
387 }
386 }
388 }
@@ -389,20 +391,23 @@ Item {
389 id: appointmentMenu;
391 id: appointmentMenu;
390
392
391 Menus.EventMenu {
393 Menus.EventMenu {
394+ id: appointmentItem
392 objectName: "appointmentMenu"
395 objectName: "appointmentMenu"
393 property QtObject menuData: null
396 property QtObject menuData: null
394 property var menuModel: menuFactory.menuModel
397 property var menuModel: menuFactory.menuModel
395 property int menuIndex: -1
398 property int menuIndex: -1
396 property var extendedData: menuData && menuData.ext || undefined
399 property var extendedData: menuData && menuData.ext || undefined
397− // TODO - bug #1260728
400+
398− property var timeFormatter: Utils.GDateTimeFormatter {
401+ property date serverTime: new Date(getExtendedProperty(extendedData, "xCanonicalTime", 0) * 1000)
399− time: getExtendedProperty(extendedData, "xCanonicalTime", 0)
402+ LiveTimer {
403+ frequency: LiveTimer.Relative
404+ relativeTime: appointmentItem.serverTime
400− format: getExtendedProperty(extendedData, "xCanonicalTimeFormat", "")
405+ onTrigger: appointmentItem.serverTime = new Date(getExtendedProperty(extendedData, "xCanonicalTime", 0) * 1000)
401 }
406 }
402
407
403 text: menuData && menuData.label || ""
408 text: menuData && menuData.label || ""
404 iconSource: menuData && menuData.icon || "image://theme/calendar"
409 iconSource: menuData && menuData.icon || "image://theme/calendar"
405− time: timeFormatter.timeString
410+ time: i18n.relativeDateTime(serverTime)
406 eventColor: getExtendedProperty(extendedData, "xCanonicalColor", Qt.rgba(0.0, 0.0, 0.0, 0.0))
411 eventColor: getExtendedProperty(extendedData, "xCanonicalColor", Qt.rgba(0.0, 0.0, 0.0, 0.0))
407 enabled: menuData && menuData.sensitive || false
412 enabled: menuData && menuData.sensitive || false
408 highlightWhenPressed: false
413 highlightWhenPressed: false
@@ -420,8 +425,7 @@ Item {
420 function loadAttributes() {
425 function loadAttributes() {
421 if (!menuModel || menuIndex == -1) return;
426 if (!menuModel || menuIndex == -1) return;
422 menuModel.loadExtendedAttributes(menuIndex, {'x-canonical-color': 'string',
427 menuModel.loadExtendedAttributes(menuIndex, {'x-canonical-color': 'string',
423− 'x-canonical-time': 'int64',
428+ 'x-canonical-time': 'int64'});
424− 'x-canonical-time-format': 'string'});
425 }
429 }
426 }
430 }
427 }
431 }
qml/Panel/Indicators/MessageMenuItemFactory.qml+35−26
@@ -19,7 +19,7 @@
19 */
19 */
20
20
21import QtQuick 2.0
21import QtQuick 2.0
22−import Ubuntu.Components 0.1
22+import Ubuntu.Components 1.3
23import Ubuntu.Settings.Menus 0.1 as Menus
23import Ubuntu.Settings.Menus 0.1 as Menus
24import QMenuModel 0.1 as QMenuModel
24import QMenuModel 0.1 as QMenuModel
25import Utils 0.1 as Utils
25import Utils 0.1 as Utils
@@ -35,12 +35,17 @@ Loader {
35 signal menuSelected
35 signal menuSelected
36 signal menuDeselected
36 signal menuDeselected
37
37
38+ QtObject {
39+ id: priv
38− property var extendedData: menuData && menuData.ext || undefined
40+ property var extendedData: menuData && menuData.ext || undefined
39− property var actionsDescription: getExtendedProperty(extendedData, "xCanonicalMessageActions", undefined)
41+ property var actionsDescription: getExtendedProperty(extendedData, "xCanonicalMessageActions", undefined)
40−
41− // TODO - bug #1260728
42− property var timeFormatter: Utils.RelativeTimeFormatter {
43− time: getExtendedProperty(extendedData, "xCanonicalTime", 0) / 1000000
42+ property date time: new Date(getExtendedProperty(extendedData, "xCanonicalTime", 0) / 1000)
43+ property string timeString: i18n.relativeDateTime(time)
44+ }
45+ LiveTimer {
46+ frequency: LiveTimer.Relative
47+ relativeTime: priv.time
48+ onTrigger: priv.timeString = Qt.binding(function() { return i18n.relativeDateTime(priv.time); })
44 }
49 }
45
50
46 onMenuModelChanged: {
51 onMenuModelChanged: {
@@ -50,7 +55,7 @@ Loader {
50 loadAttributes();
55 loadAttributes();
51 }
56 }
52
57
53− sourceComponent: loadMessage(actionsDescription)
58+ sourceComponent: loadMessage(priv.actionsDescription)
54
59
55 function loadMessage(actions)
60 function loadMessage(actions)
56 {
61 {
@@ -100,11 +105,11 @@ Loader {
100 objectName: "simpleTextMessage"
105 objectName: "simpleTextMessage"
101 // text
106 // text
102 title: menuData && menuData.label || ""
107 title: menuData && menuData.label || ""
103− time: timeFormatter.timeString
108+ time: priv.timeString
104− body: getExtendedProperty(extendedData, "xCanonicalText", "")
109+ body: getExtendedProperty(priv.extendedData, "xCanonicalText", "")
105 // icons
110 // icons
106− avatar: getExtendedProperty(extendedData, "icon", "image://theme/contact")
111+ avatar: getExtendedProperty(priv.extendedData, "icon", "image://theme/contact")
107− icon: getExtendedProperty(extendedData, "xCanonicalAppIcon", "image://theme/message")
112+ icon: getExtendedProperty(priv.extendedData, "xCanonicalAppIcon", "image://theme/message")
108 // actions
113 // actions
109 enabled: menuData && menuData.sensitive || false
114 enabled: menuData && menuData.sensitive || false
110 removable: !selected
115 removable: !selected
@@ -133,7 +138,9 @@ Loader {
133 Menus.TextMessageMenu {
138 Menus.TextMessageMenu {
134 id: message
139 id: message
135 objectName: "textMessage"
140 objectName: "textMessage"
136− property var replyActionDescription: actionsDescription && actionsDescription.length > 0 ? actionsDescription[0] : undefined
141+ property var replyActionDescription: priv.actionsDescription && priv.actionsDescription.length > 0 ?
142+ priv.actionsDescription[0] :
143+ undefined
137
144
138 property var replyAction: QMenuModel.UnityMenuAction {
145 property var replyAction: QMenuModel.UnityMenuAction {
139 model: menuModel
146 model: menuModel
@@ -143,13 +150,13 @@ Loader {
143
150
144 // text
151 // text
145 title: menuData && menuData.label || ""
152 title: menuData && menuData.label || ""
146− time: timeFormatter.timeString
153+ time: priv.timeString
147− body: getExtendedProperty(extendedData, "xCanonicalText", "")
154+ body: getExtendedProperty(priv.extendedData, "xCanonicalText", "")
148− replyButtonText: getExtendedProperty(replyActionDescription, "label", i18n.tr("Send"))
155+ replyButtonText: getExtendedProperty(replyActionDescription, "label", i18n.ctr("Button: Send a reply message", "Send"))
149 replyHintText: i18n.ctr("Label: Hint in message indicator line edit", "Reply")
156 replyHintText: i18n.ctr("Label: Hint in message indicator line edit", "Reply")
150 // icons
157 // icons
151− avatar: getExtendedProperty(extendedData, "icon", "image://theme/contact")
158+ avatar: getExtendedProperty(priv.extendedData, "icon", "image://theme/contact")
152− icon: getExtendedProperty(extendedData, "xCanonicalAppIcon", "image://theme/message")
159+ icon: getExtendedProperty(priv.extendedData, "xCanonicalAppIcon", "image://theme/message")
153 // actions
160 // actions
154 replyEnabled: replyAction.valid && replyAction.enabled
161 replyEnabled: replyAction.valid && replyAction.enabled
155 enabled: menuData && menuData.sensitive || false
162 enabled: menuData && menuData.sensitive || false
@@ -183,8 +190,10 @@ Loader {
183 Menus.SnapDecisionMenu {
190 Menus.SnapDecisionMenu {
184 id: message
191 id: message
185 objectName: "snapDecision"
192 objectName: "snapDecision"
186− property var activateActionDescription: actionsDescription && actionsDescription.length > 0 ? actionsDescription[0] : undefined
193+ property var activateActionDescription: priv.actionsDescription && priv.actionsDescription.length > 0 ?
194+ priv.actionsDescription[0] : undefined
187− property var replyActionDescription: actionsDescription && actionsDescription.length > 1 ? actionsDescription[1] : undefined
195+ property var replyActionDescription: priv.actionsDescription && priv.actionsDescription.length > 1 ?
196+ priv.actionsDescription[1] : undefined
188
197
189 property var activateAction: QMenuModel.UnityMenuAction {
198 property var activateAction: QMenuModel.UnityMenuAction {
190 model: menuModel
199 model: menuModel
@@ -199,13 +208,13 @@ Loader {
199
208
200 // text
209 // text
201 title: menuData && menuData.label || ""
210 title: menuData && menuData.label || ""
202− time: timeFormatter.timeString
211+ time: priv.timeString
203− body: getExtendedProperty(extendedData, "xCanonicalText", "")
212+ body: getExtendedProperty(priv.extendedData, "xCanonicalText", "")
204− actionButtonText: getExtendedProperty(activateActionDescription, "label", i18n.tr("Call back"))
213+ actionButtonText: getExtendedProperty(activateActionDescription, "label", i18n.ctr("Button: Call back on phone", "Call back"))
205− replyButtonText: getExtendedProperty(replyActionDescription, "label", i18n.tr("Send"))
214+ replyButtonText: getExtendedProperty(replyActionDescription, "label", i18n.ctr("Button: Send a reply message", "Send"))
206 // icons
215 // icons
207− avatar: getExtendedProperty(extendedData, "icon", "image://theme/contact")
216+ avatar: getExtendedProperty(priv.extendedData, "icon", "image://theme/contact")
208− icon: getExtendedProperty(extendedData, "xCanonicalAppIcon", "image://theme/missed-call")
217+ icon: getExtendedProperty(priv.extendedData, "xCanonicalAppIcon", "image://theme/missed-call")
209 // actions
218 // actions
210 actionEnabled: activateAction.valid && activateAction.enabled
219 actionEnabled: activateAction.valid && activateAction.enabled
211 replyEnabled: replyAction.valid && replyAction.enabled
220 replyEnabled: replyAction.valid && replyAction.enabled
qml/Panel/Panel.qml+6−3
@@ -28,6 +28,7 @@ Item {
28 property alias callHint: __callHint
28 property alias callHint: __callHint
29 property bool fullscreenMode: false
29 property bool fullscreenMode: false
30 property real indicatorAreaShowProgress: 1.0
30 property real indicatorAreaShowProgress: 1.0
31+ property bool locked: false
31
32
32 opacity: fullscreenMode && indicators.fullyClosed ? 0.0 : 1.0
33 opacity: fullscreenMode && indicators.fullyClosed ? 0.0 : 1.0
33
34
@@ -48,6 +49,7 @@ Item {
48 MouseArea {
49 MouseArea {
49 anchors.fill: parent
50 anchors.fill: parent
50 onClicked: if (indicators.fullyOpened) indicators.hide();
51 onClicked: if (indicators.fullyOpened) indicators.hide();
52+ hoverEnabled: true // should also eat hover events, otherwise they will pass through
51 }
53 }
52 }
54 }
53
55
@@ -135,7 +137,7 @@ Item {
135 }
137 }
136
138
137 shown: false
139 shown: false
138− width: root.width - (PanelState.buttonsVisible ? windowControlButtons.width : 0)
140+ width: root.width - (windowControlButtons.visible ? windowControlButtons.width : 0)
139 minimizedPanelHeight: units.gu(3)
141 minimizedPanelHeight: units.gu(3)
140 expandedPanelHeight: units.gu(7)
142 expandedPanelHeight: units.gu(7)
141 openedHeight: root.height - indicatorOrangeLine.height
143 openedHeight: root.height - indicatorOrangeLine.height
@@ -163,13 +165,14 @@ Item {
163
165
164 WindowControlButtons {
166 WindowControlButtons {
165 id: windowControlButtons
167 id: windowControlButtons
168+ objectName: "panelWindowControlButtons"
166 anchors {
169 anchors {
167 left: parent.left
170 left: parent.left
168 top: parent.top
171 top: parent.top
169 margins: units.gu(0.7)
172 margins: units.gu(0.7)
170 }
173 }
171 height: indicators.minimizedPanelHeight - anchors.margins * 2
174 height: indicators.minimizedPanelHeight - anchors.margins * 2
172− visible: PanelState.buttonsVisible
175+ visible: PanelState.buttonsVisible && !root.locked
173 onClose: PanelState.close()
176 onClose: PanelState.close()
174 onMinimize: PanelState.minimize()
177 onMinimize: PanelState.minimize()
175 onMaximize: PanelState.maximize()
178 onMaximize: PanelState.maximize()
@@ -188,7 +191,7 @@ Item {
188 id: __callHint
191 id: __callHint
189 anchors {
192 anchors {
190 top: parent.top
193 top: parent.top
191− left: PanelState.buttonsVisible ? windowControlButtons.right : parent.left
194+ left: windowControlButtons.visible ? windowControlButtons.right : parent.left
192 }
195 }
193 height: indicators.minimizedPanelHeight
196 height: indicators.minimizedPanelHeight
194 visible: active && indicators.state == "initial"
197 visible: active && indicators.state == "initial"
qml/Rotation/RotationStates.qml+2−2
@@ -83,7 +83,7 @@ StateGroup {
83 }
83 }
84
84
85 function tryUpdateState() {
85 function tryUpdateState() {
86− if (d.transitioning || (!d.startingUp && !root.shell.orientationChangesEnabled)) {
86+ if (d.transitioning || (!d.startingUp && !root.orientedShell.orientationChangesEnabled)) {
87 return;
87 return;
88 }
88 }
89
89
@@ -95,7 +95,7 @@ StateGroup {
95 }
95 }
96
96
97 property Connections shellConnections: Connections {
97 property Connections shellConnections: Connections {
98− target: root.shell
98+ target: root.orientedShell
99 onOrientationChangesEnabledChanged: {
99 onOrientationChangesEnabledChanged: {
100 d.tryUpdateState();
100 d.tryUpdateState();
101 }
101 }
qml/Shell.qml+30−50
@@ -17,7 +17,6 @@
17import QtQuick 2.0
17import QtQuick 2.0
18import QtQuick.Window 2.0
18import QtQuick.Window 2.0
19import AccountsService 0.1
19import AccountsService 0.1
20−import GSettings 1.0
21import Unity.Application 0.1
20import Unity.Application 0.1
22import Ubuntu.Components 0.1
21import Ubuntu.Components 0.1
23import Ubuntu.Components.Popups 1.0
22import Ubuntu.Components.Popups 1.0
@@ -41,6 +40,7 @@ import Unity.Notifications 1.0 as NotificationBackend
41import Unity.Session 0.1
40import Unity.Session 0.1
42import Unity.DashCommunicator 0.1
41import Unity.DashCommunicator 0.1
43import Unity.Indicators 0.1 as Indicators
42import Unity.Indicators 0.1 as Indicators
43+import Cursor 1.0
44
44
45
45
46Item {
46Item {
@@ -49,21 +49,21 @@ Item {
49 // to be set from outside
49 // to be set from outside
50 property int orientationAngle: 0
50 property int orientationAngle: 0
51 property int orientation
51 property int orientation
52− property int primaryOrientation
52+ property Orientations orientations
53− property int nativeOrientation
54 property real nativeWidth
53 property real nativeWidth
55 property real nativeHeight
54 property real nativeHeight
56 property alias indicatorAreaShowProgress: panel.indicatorAreaShowProgress
55 property alias indicatorAreaShowProgress: panel.indicatorAreaShowProgress
57 property bool beingResized
56 property bool beingResized
58 property string usageScenario: "phone" // supported values: "phone", "tablet" or "desktop"
57 property string usageScenario: "phone" // supported values: "phone", "tablet" or "desktop"
59 property string mode: "full-greeter"
58 property string mode: "full-greeter"
59+ property bool cursorVisible: false
60 function updateFocusedAppOrientation() {
60 function updateFocusedAppOrientation() {
61 applicationsDisplayLoader.item.updateFocusedAppOrientation();
61 applicationsDisplayLoader.item.updateFocusedAppOrientation();
62 }
62 }
63 function updateFocusedAppOrientationAnimated() {
63 function updateFocusedAppOrientationAnimated() {
64 applicationsDisplayLoader.item.updateFocusedAppOrientationAnimated();
64 applicationsDisplayLoader.item.updateFocusedAppOrientationAnimated();
65 }
65 }
66− property bool hasMouse
66+ property bool hasMouse: false
67
67
68 // to be read from outside
68 // to be read from outside
69 readonly property int mainAppWindowOrientationAngle:
69 readonly property int mainAppWindowOrientationAngle:
@@ -107,9 +107,11 @@ Item {
107 enabled: greeter && !greeter.waiting
107 enabled: greeter && !greeter.waiting
108
108
109 property real edgeSize: units.gu(2)
109 property real edgeSize: units.gu(2)
110− property url defaultBackground: Qt.resolvedUrl(shell.width >= units.gu(60) ? "graphics/tablet_background.jpg" : "graphics/phone_background.jpg")
110+
111− property url background: asImageTester.status == Image.Ready ? asImageTester.source
111+ WallpaperResolver {
112− : gsImageTester.status == Image.Ready ? gsImageTester.source : defaultBackground
112+ id: wallpaperResolver
113+ width: shell.width
114+ }
113
115
114 readonly property alias greeter: greeterLoader.item
116 readonly property alias greeter: greeterLoader.item
115
117
@@ -130,31 +132,6 @@ Item {
130 shell.activateApplication(app);
132 shell.activateApplication(app);
131 }
133 }
132
134
133− // This is a dummy image to detect if the custom AS set wallpaper loads successfully.
134− Image {
135− id: asImageTester
136− source: AccountsService.backgroundFile != undefined && AccountsService.backgroundFile.length > 0 ? AccountsService.backgroundFile : ""
137− height: 0
138− width: 0
139− sourceSize.height: 0
140− sourceSize.width: 0
141− }
142−
143− GSettings {
144− id: backgroundSettings
145− schema.id: "org.gnome.desktop.background"
146− }
147−
148− // This is a dummy image to detect if the custom GSettings set wallpaper loads successfully.
149− Image {
150− id: gsImageTester
151− source: backgroundSettings.pictureUri && backgroundSettings.pictureUri.length > 0 ? backgroundSettings.pictureUri : ""
152− height: 0
153− width: 0
154− sourceSize.height: 0
155− sourceSize.width: 0
156− }
157−
158 Binding {
135 Binding {
159 target: LauncherModel
136 target: LauncherModel
160 property: "applicationManager"
137 property: "applicationManager"
@@ -190,11 +167,6 @@ Item {
190 onScreenshotTriggered: screenGrabber.capture();
167 onScreenshotTriggered: screenGrabber.capture();
191 }
168 }
192
169
193− ScreenGrabber {
194− id: screenGrabber
195− z: dialogs.z + 10
196− }
197−
198 GlobalShortcut {
170 GlobalShortcut {
199 // dummy shortcut to force creation of GlobalShortcutRegistry before WindowKeyFilter
171 // dummy shortcut to force creation of GlobalShortcutRegistry before WindowKeyFilter
200 }
172 }
@@ -326,18 +298,13 @@ Item {
326 }
298 }
327 Binding {
299 Binding {
328 target: applicationsDisplayLoader.item
300 target: applicationsDisplayLoader.item
329− property: "background"
301+ property: "orientations"
330− value: shell.background
302+ value: shell.orientations
331− }
332− Binding {
333− target: applicationsDisplayLoader.item
334− property: "shellPrimaryOrientation"
335− value: shell.primaryOrientation
336 }
303 }
337 Binding {
304 Binding {
338 target: applicationsDisplayLoader.item
305 target: applicationsDisplayLoader.item
339− property: "nativeOrientation"
306+ property: "background"
340− value: shell.nativeOrientation
307+ value: wallpaperResolver.background
341 }
308 }
342 Binding {
309 Binding {
343 target: applicationsDisplayLoader.item
310 target: applicationsDisplayLoader.item
@@ -432,7 +399,7 @@ Item {
432 tabletMode: shell.usageScenario != "phone"
399 tabletMode: shell.usageScenario != "phone"
433 launcherOffset: launcher.progress
400 launcherOffset: launcher.progress
434 forcedUnlock: tutorial.running
401 forcedUnlock: tutorial.running
435− background: shell.background
402+ background: wallpaperResolver.background
436
403
437 // avoid overlapping with Launcher's edge drag area
404 // avoid overlapping with Launcher's edge drag area
438 // FIXME: Fix TouchRegistry & friends and remove this workaround
405 // FIXME: Fix TouchRegistry & friends and remove this workaround
@@ -564,6 +531,7 @@ Item {
564
531
565 fullscreenMode: (topmostApplicationIsFullscreen && !lightDM.greeter.active && launcher.progress == 0)
532 fullscreenMode: (topmostApplicationIsFullscreen && !lightDM.greeter.active && launcher.progress == 0)
566 || greeter.hasLockedApp
533 || greeter.hasLockedApp
534+ locked: greeter && greeter.active
567 }
535 }
568
536
569 Launcher {
537 Launcher {
@@ -607,7 +575,7 @@ Item {
607 id: wizard
575 id: wizard
608 objectName: "wizard"
576 objectName: "wizard"
609 anchors.fill: parent
577 anchors.fill: parent
610− background: shell.background
578+ background: wallpaperResolver.background
611
579
612 function unlockWhenDoneWithWizard() {
580 function unlockWhenDoneWithWizard() {
613 if (!active) {
581 if (!active) {
@@ -638,6 +606,7 @@ Item {
638 model: NotificationBackend.Model
606 model: NotificationBackend.Model
639 margin: units.gu(1)
607 margin: units.gu(1)
640 hasMouse: shell.hasMouse
608 hasMouse: shell.hasMouse
609+ background: wallpaperResolver.background
641
610
642 y: topmostIsFullscreen ? 0 : panel.panelHeight
611 y: topmostIsFullscreen ? 0 : panel.panelHeight
643 height: parent.height - (topmostIsFullscreen ? 0 : panel.panelHeight)
612 height: parent.height - (topmostIsFullscreen ? 0 : panel.panelHeight)
@@ -684,9 +653,21 @@ Item {
684 onShowHome: showHome()
653 onShowHome: showHome()
685 }
654 }
686
655
656+ ScreenGrabber {
657+ id: screenGrabber
658+ rotationAngle: -shell.orientationAngle
659+ z: dialogs.z + 10
660+ }
661+
662+ Cursor {
663+ id: cursor
664+ visible: shell.hasMouse
665+ z: screenGrabber.z + 1
666+ }
667+
687 Rectangle {
668 Rectangle {
688 id: shutdownFadeOutRectangle
669 id: shutdownFadeOutRectangle
689− z: screenGrabber.z + 10
670+ z: cursor.z + 1
690 enabled: false
671 enabled: false
691 visible: false
672 visible: false
692 color: "black"
673 color: "black"
@@ -703,5 +684,4 @@ Item {
703 }
684 }
704 }
685 }
705 }
686 }
706−
707}
687}
qml/Stages/AbstractStage.qmlnew file+63
@@ -0,0 +1,63 @@
1+/*
2+ * Copyright (C) 2015 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.4
18+import Ubuntu.Components 1.3
19+import GSettings 1.0
20+
21+Rectangle {
22+ id: root
23+
24+ color: "#111111"
25+
26+ // Controls to be set from outside
27+ property bool altTabPressed
28+ property url background
29+ property bool beingResized
30+ property int dragAreaWidth
31+ property bool interactive
32+ property real inverseProgress // This is the progress for left edge drags, in pixels.
33+ property bool keepDashRunning: true
34+ property real maximizedAppTopMargin
35+ property real nativeHeight
36+ property real nativeWidth
37+ property QtObject orientations
38+ property int shellOrientation
39+ property int shellOrientationAngle
40+ property bool spreadEnabled: true // If false, animations and right edge will be disabled
41+ property bool suspended
42+
43+ // To be read from outside
44+ property var mainApp: null
45+ property int mainAppWindowOrientationAngle
46+ property bool orientationChangesEnabled
47+
48+ // Shared code for use in stage implementations
49+ GSettings {
50+ id: lifecycleExceptions
51+ schema.id: "com.canonical.qtmir"
52+ }
53+
54+ function isExemptFromLifecycle(appId) {
55+ var shortAppId = appId.split('_')[0];
56+ for (var i = 0; i < lifecycleExceptions.lifecycleExemptAppids.length; i++) {
57+ if (shortAppId === lifecycleExceptions.lifecycleExemptAppids[i]) {
58+ return true;
59+ }
60+ }
61+ return false;
62+ }
63+}
qml/Stages/ApplicationWindow.qml+2
@@ -27,6 +27,8 @@ FocusScope {
27 readonly property bool fullscreen: application ? application.fullscreen : false
27 readonly property bool fullscreen: application ? application.fullscreen : false
28 property alias interactive: sessionContainer.interactive
28 property alias interactive: sessionContainer.interactive
29 property bool orientationChangesEnabled: d.supportsSurfaceResize ? d.surfaceOldEnoughToBeResized : true
29 property bool orientationChangesEnabled: d.supportsSurfaceResize ? d.surfaceOldEnoughToBeResized : true
30+ readonly property string title: sessionContainer.surface && sessionContainer.surface.name !== "" ?
31+ sessionContainer.surface.name : d.name
30
32
31 // to be set from outside
33 // to be set from outside
32 property QtObject application
34 property QtObject application
qml/Stages/DecoratedWindow.qml+7−4
@@ -31,9 +31,10 @@ FocusScope {
31 property bool highlightShown: false
31 property bool highlightShown: false
32 property real shadowOpacity: 1
32 property real shadowOpacity: 1
33
33
34− signal close();
34+ signal close()
35− signal maximize();
35+ signal maximize()
36− signal minimize();
36+ signal minimize()
37+ signal decorationPressed()
37
38
38 BorderImage {
39 BorderImage {
39 anchors {
40 anchors {
@@ -61,13 +62,15 @@ FocusScope {
61
62
62 WindowDecoration {
63 WindowDecoration {
63 id: decoration
64 id: decoration
65+ target: root.parent
64 objectName: application ? "appWindowDecoration_" + application.appId : "appWindowDecoration_null"
66 objectName: application ? "appWindowDecoration_" + application.appId : "appWindowDecoration_null"
65 anchors { left: parent.left; top: parent.top; right: parent.right }
67 anchors { left: parent.left; top: parent.top; right: parent.right }
66 height: units.gu(3)
68 height: units.gu(3)
67− title: model.name
69+ title: window.title !== "" ? window.title : model.name
68 onClose: root.close();
70 onClose: root.close();
69 onMaximize: root.maximize();
71 onMaximize: root.maximize();
70 onMinimize: root.minimize();
72 onMinimize: root.minimize();
73+ onPressed: root.decorationPressed();
71 visible: decorationShown
74 visible: decorationShown
72 }
75 }
73
76
qml/Stages/DesktopStage.qml+21−32
@@ -22,39 +22,21 @@ import Ubuntu.Components 1.1
22import Unity.Application 0.1
22import Unity.Application 0.1
23import "../Components"
23import "../Components"
24import "../Components/PanelState"
24import "../Components/PanelState"
25+import "../Components"
25import Utils 0.1
26import Utils 0.1
26import Ubuntu.Gestures 0.1
27import Ubuntu.Gestures 0.1
27
28
28−Rectangle {
29+AbstractStage {
29 id: root
30 id: root
30 anchors.fill: parent
31 anchors.fill: parent
31
32
32− // Controls to be set from outside
33− property int dragAreaWidth // just to comply with the interface shared between stages
34− property real maximizedAppTopMargin
35− property bool interactive
36− property bool spreadEnabled // just to comply with the interface shared between stages
37− property real inverseProgress: 0 // just to comply with the interface shared between stages
38− property int shellOrientationAngle: 0
39− property int shellOrientation
40− property int shellPrimaryOrientation
41− property int nativeOrientation
42− property bool beingResized: false
43− property bool keepDashRunning: true
44− property bool suspended: false
45− property alias background: wallpaper.source
46− property alias altTabPressed: spread.altTabPressed
47−
48 // functions to be called from outside
33 // functions to be called from outside
49 function updateFocusedAppOrientation() { /* TODO */ }
34 function updateFocusedAppOrientation() { /* TODO */ }
50 function updateFocusedAppOrientationAnimated() { /* TODO */}
35 function updateFocusedAppOrientationAnimated() { /* TODO */}
51
36
52− // To be read from outside
53− readonly property var mainApp: ApplicationManager.focusedApplicationId
37+ mainApp: ApplicationManager.focusedApplicationId
54 ? ApplicationManager.findApplication(ApplicationManager.focusedApplicationId)
38 ? ApplicationManager.findApplication(ApplicationManager.focusedApplicationId)
55 : null
39 : null
56− property int mainAppWindowOrientationAngle: 0
57− readonly property bool orientationChangesEnabled: false
58
40
59 Connections {
41 Connections {
60 target: ApplicationManager
42 target: ApplicationManager
@@ -127,6 +109,7 @@ Rectangle {
127 property: "buttonsVisible"
109 property: "buttonsVisible"
128 value: priv.focusedAppDelegate !== null && priv.focusedAppDelegate.state === "maximized"
110 value: priv.focusedAppDelegate !== null && priv.focusedAppDelegate.state === "maximized"
129 }
111 }
112+ Component.onDestruction: PanelState.buttonsVisible = false;
130
113
131 FocusScope {
114 FocusScope {
132 id: appContainer
115 id: appContainer
@@ -137,6 +120,7 @@ Rectangle {
137 CrossFadeImage {
120 CrossFadeImage {
138 id: wallpaper
121 id: wallpaper
139 anchors.fill: parent
122 anchors.fill: parent
123+ source: root.background
140 sourceSize { height: root.height; width: root.width }
124 sourceSize { height: root.height; width: root.width }
141 fillMode: Image.PreserveAspectCrop
125 fillMode: Image.PreserveAspectCrop
142 }
126 }
@@ -155,11 +139,9 @@ Rectangle {
155 height: units.gu(50)
139 height: units.gu(50)
156 focus: model.appId === priv.focusedAppId
140 focus: model.appId === priv.focusedAppId
157
141
158− readonly property int minWidth: units.gu(10)
159− readonly property int minHeight: units.gu(10)
160−
161 property bool maximized: false
142 property bool maximized: false
162 property bool minimized: false
143 property bool minimized: false
144+ property bool animationsEnabled: true
163
145
164 property bool visuallyMaximized: false
146 property bool visuallyMaximized: false
165 property bool visuallyMinimized: false
147 property bool visuallyMinimized: false
@@ -213,15 +195,18 @@ Rectangle {
213 value: ApplicationInfoInterface.RequestedRunning // Always running for now
195 value: ApplicationInfoInterface.RequestedRunning // Always running for now
214 }
196 }
215
197
216− function maximize() {
198+ function maximize(animated) {
199+ animationsEnabled = (animated === undefined) || animated;
217 minimized = false;
200 minimized = false;
218 maximized = true;
201 maximized = true;
219 }
202 }
220− function minimize() {
203+ function minimize(animated) {
204+ animationsEnabled = (animated === undefined) || animated;
221 maximized = false;
205 maximized = false;
222 minimized = true;
206 minimized = true;
223 }
207 }
224− function unmaximize() {
208+ function unmaximize(animated) {
209+ animationsEnabled = (animated === undefined) || animated;
225 minimized = false;
210 minimized = false;
226 maximized = false;
211 maximized = false;
227 }
212 }
@@ -242,11 +227,13 @@ Rectangle {
242 transitions: [
227 transitions: [
243 Transition {
228 Transition {
244 to: "normal"
229 to: "normal"
230+ enabled: appDelegate.animationsEnabled
245 PropertyAction { target: appDelegate; properties: "visuallyMinimized,visuallyMaximized"; value: false }
231 PropertyAction { target: appDelegate; properties: "visuallyMinimized,visuallyMaximized"; value: false }
246 PropertyAnimation { target: appDelegate; properties: "x,y,opacity,width,height,scale," }
232 PropertyAnimation { target: appDelegate; properties: "x,y,opacity,width,height,scale," }
247 },
233 },
248 Transition {
234 Transition {
249 to: "maximized"
235 to: "maximized"
236+ enabled: appDelegate.animationsEnabled
250 SequentialAnimation {
237 SequentialAnimation {
251 PropertyAction { target: appDelegate; property: "visuallyMinimized"; value: false }
238 PropertyAction { target: appDelegate; property: "visuallyMinimized"; value: false }
252 PropertyAnimation { target: appDelegate; properties: "x,y,opacity,width,height,scale" }
239 PropertyAnimation { target: appDelegate; properties: "x,y,opacity,width,height,scale" }
@@ -255,6 +242,7 @@ Rectangle {
255 },
242 },
256 Transition {
243 Transition {
257 to: "minimized"
244 to: "minimized"
245+ enabled: appDelegate.animationsEnabled
258 SequentialAnimation {
246 SequentialAnimation {
259 PropertyAction { target: appDelegate; property: "visuallyMaximized"; value: false }
247 PropertyAction { target: appDelegate; property: "visuallyMaximized"; value: false }
260 PropertyAnimation { target: appDelegate; properties: "x,y,opacity,width,height,scale" }
248 PropertyAnimation { target: appDelegate; properties: "x,y,opacity,width,height,scale" }
@@ -283,12 +271,11 @@ Rectangle {
283 when: index == spread.highlightedIndex && blurLayer.ready
271 when: index == spread.highlightedIndex && blurLayer.ready
284 }
272 }
285
273
286− WindowMoveResizeArea {
274+ WindowResizeArea {
287− id: windowMoveResizeArea
288 target: appDelegate
275 target: appDelegate
289− minWidth: appDelegate.minWidth
276+ minWidth: units.gu(10)
290− minHeight: appDelegate.minHeight
277+ minHeight: units.gu(10)
291− resizeHandleWidth: units.gu(2)
278+ borderThickness: units.gu(2)
292 windowId: model.appId // FIXME: Change this to point to windowId once we have such a thing
279 windowId: model.appId // FIXME: Change this to point to windowId once we have such a thing
293
280
294 onPressed: { ApplicationManager.focusApplication(model.appId) }
281 onPressed: { ApplicationManager.focusApplication(model.appId) }
@@ -308,6 +295,7 @@ Rectangle {
308 onClose: ApplicationManager.stopApplication(model.appId)
295 onClose: ApplicationManager.stopApplication(model.appId)
309 onMaximize: appDelegate.maximize()
296 onMaximize: appDelegate.maximize()
310 onMinimize: appDelegate.minimize()
297 onMinimize: appDelegate.minimize()
298+ onDecorationPressed: { ApplicationManager.focusApplication(model.appId) }
311 }
299 }
312 }
300 }
313 }
301 }
@@ -340,5 +328,6 @@ Rectangle {
340 anchors.fill: parent
328 anchors.fill: parent
341 workspace: appContainer
329 workspace: appContainer
342 focus: state == "altTab"
330 focus: state == "altTab"
331+ altTabPressed: root.altTabPressed
343 }
332 }
344}
333}
qml/Stages/PhoneStage.qml+21−34
@@ -23,29 +23,15 @@ import Utils 0.1
23import Powerd 0.1
23import Powerd 0.1
24import "../Components"
24import "../Components"
25
25
26−Rectangle {
26+AbstractStage {
27 id: root
27 id: root
28
28
29− // Controls to be set from outside
30− property int dragAreaWidth
31− property real maximizedAppTopMargin
32− property bool interactive
33− property bool spreadEnabled: true // If false, animations and right edge will be disabled
34− property real inverseProgress: 0 // This is the progress for left edge drags, in pixels.
35 property QtObject applicationManager: ApplicationManager
29 property QtObject applicationManager: ApplicationManager
36 property bool focusFirstApp: true // If false, focused app will appear on right edge like other apps
30 property bool focusFirstApp: true // If false, focused app will appear on right edge like other apps
37 property bool altTabEnabled: true
31 property bool altTabEnabled: true
38 property real startScale: 1.1
32 property real startScale: 1.1
39 property real endScale: 0.7
33 property real endScale: 0.7
40− property bool keepDashRunning: true
34+
41− property bool suspended: false
42− property int shellOrientationAngle: 0
43− property int shellOrientation
44− property int shellPrimaryOrientation
45− property int nativeOrientation
46− property real nativeWidth
47− property real nativeHeight
48− property bool beingResized: false
49 onBeingResizedChanged: {
35 onBeingResizedChanged: {
50 if (beingResized) {
36 if (beingResized) {
51 // Brace yourselves for impact!
37 // Brace yourselves for impact!
@@ -57,6 +43,8 @@ Rectangle {
57 priv.reset();
43 priv.reset();
58 }
44 }
59 }
45 }
46+
47+ // Functions to be called from outside
60 function updateFocusedAppOrientation() {
48 function updateFocusedAppOrientation() {
61 if (spreadRepeater.count > 0) {
49 if (spreadRepeater.count > 0) {
62 spreadRepeater.itemAt(0).matchShellOrientation();
50 spreadRepeater.itemAt(0).matchShellOrientation();
@@ -72,7 +60,7 @@ Rectangle {
72
60
73 var supportedOrientations = spreadDelegate.application.supportedOrientations;
61 var supportedOrientations = spreadDelegate.application.supportedOrientations;
74 if (supportedOrientations === Qt.PrimaryOrientation) {
62 if (supportedOrientations === Qt.PrimaryOrientation) {
75− supportedOrientations = spreadDelegate.shellPrimaryOrientation;
63+ supportedOrientations = root.orientations.primary;
76 }
64 }
77
65
78 if (delta === 180 && (supportedOrientations & spreadDelegate.shellOrientation)) {
66 if (delta === 180 && (supportedOrientations & spreadDelegate.shellOrientation)) {
@@ -86,16 +74,14 @@ Rectangle {
86 }
74 }
87 }
75 }
88
76
89− // To be read from outside
90− readonly property var mainApp: applicationManager.focusedApplicationId
77+ mainApp: applicationManager.focusedApplicationId
91 ? applicationManager.findApplication(applicationManager.focusedApplicationId)
78 ? applicationManager.findApplication(applicationManager.focusedApplicationId)
92 : null
79 : null
93
80
94− property int mainAppWindowOrientationAngle: 0
95− readonly property bool orientationChangesEnabled: priv.focusedAppOrientationChangesEnabled
81+ orientationChangesEnabled: priv.focusedAppOrientationChangesEnabled
96− && !priv.focusedAppDelegateIsDislocated
82+ && !priv.focusedAppDelegateIsDislocated
97− && !(priv.focusedAppDelegate && priv.focusedAppDelegate.xBehavior.running)
83+ && !(priv.focusedAppDelegate && priv.focusedAppDelegate.xBehavior.running)
98− && spreadView.phase === 0
84+ && spreadView.phase === 0
99
85
100 // How far left the stage has been dragged
86 // How far left the stage has been dragged
101 readonly property real dragProgress: spreadRepeater.count > 0 ? -spreadRepeater.itemAt(0).xTranslate : 0
87 readonly property real dragProgress: spreadRepeater.count > 0 ? -spreadRepeater.itemAt(0).xTranslate : 0
@@ -107,8 +93,6 @@ Rectangle {
107
93
108 signal opened()
94 signal opened()
109
95
110− color: "#111111"
111−
112 function select(appId) {
96 function select(appId) {
113 spreadView.snapTo(priv.indexOf(appId));
97 spreadView.snapTo(priv.indexOf(appId));
114 }
98 }
@@ -439,16 +423,21 @@ Rectangle {
439 dropShadow: spreadView.active || priv.focusedAppDelegateIsDislocated
423 dropShadow: spreadView.active || priv.focusedAppDelegateIsDislocated
440 focusFirstApp: root.focusFirstApp
424 focusFirstApp: root.focusFirstApp
441
425
426+ readonly property bool isDash: model.appId == "unity8-dash"
427+
428+ readonly property bool canSuspend: model.isTouchApp
429+ && !isExemptFromLifecycle(model.appId)
430+
442 Binding {
431 Binding {
443 target: appDelegate.application
432 target: appDelegate.application
444 property: "requestedState"
433 property: "requestedState"
434+ value: !canSuspend
435+ || (isDash && root.keepDashRunning)
445− value: (isDash && root.keepDashRunning) || (!root.suspended && appDelegate.focus)
436+ || (!root.suspended && appDelegate.focus)
446− ? ApplicationInfoInterface.RequestedRunning
437+ ? ApplicationInfoInterface.RequestedRunning
447− : ApplicationInfoInterface.RequestedSuspended
438+ : ApplicationInfoInterface.RequestedSuspended
448 }
439 }
449
440
450− readonly property bool isDash: model.appId == "unity8-dash"
451−
452 z: isDash && !spreadView.active ? -1 : behavioredIndex
441 z: isDash && !spreadView.active ? -1 : behavioredIndex
453
442
454 x: {
443 x: {
@@ -542,11 +531,9 @@ Rectangle {
542 visible: Powerd.status == Powerd.On &&
531 visible: Powerd.status == Powerd.On &&
543 (!occluded || (isDash && priv.focusedAppDelegateIsDislocated))
532 (!occluded || (isDash && priv.focusedAppDelegateIsDislocated))
544
533
545−
546 shellOrientationAngle: root.shellOrientationAngle
534 shellOrientationAngle: root.shellOrientationAngle
547 shellOrientation: root.shellOrientation
535 shellOrientation: root.shellOrientation
548− shellPrimaryOrientation: root.shellPrimaryOrientation
536+ orientations: root.orientations
549− nativeOrientation: root.nativeOrientation
550
537
551 onClicked: {
538 onClicked: {
552 if (root.altTabEnabled && spreadView.phase == 2) {
539 if (root.altTabEnabled && spreadView.phase == 2) {
qml/Stages/ShimStage.qml+1−1
@@ -17,7 +17,7 @@
17import QtQuick 2.3
17import QtQuick 2.3
18import Ubuntu.Components 0.1
18import Ubuntu.Components 0.1
19
19
20−Rectangle {
20+AbstractStage {
21 id: shimStage
21 id: shimStage
22
22
23 anchors.fill: parent
23 anchors.fill: parent
qml/Stages/SpreadDelegate.qml+8−9
@@ -42,8 +42,7 @@ FocusScope {
42 property alias application: appWindow.application
42 property alias application: appWindow.application
43 property int shellOrientationAngle
43 property int shellOrientationAngle
44 property int shellOrientation
44 property int shellOrientation
45− property int shellPrimaryOrientation
45+ property QtObject orientations
46− property int nativeOrientation
47
46
48 function matchShellOrientation() {
47 function matchShellOrientation() {
49 if (!root.application)
48 if (!root.application)
@@ -157,7 +156,7 @@ FocusScope {
157 var supportedOrientations = root.application.supportedOrientations;
156 var supportedOrientations = root.application.supportedOrientations;
158
157
159 if (supportedOrientations === Qt.PrimaryOrientation) {
158 if (supportedOrientations === Qt.PrimaryOrientation) {
160− supportedOrientations = root.shellPrimaryOrientation;
159+ supportedOrientations = root.orientations.primary;
161 }
160 }
162
161
163 // If it doesn't support shell's current orientation
162 // If it doesn't support shell's current orientation
@@ -166,18 +165,18 @@ FocusScope {
166 if (supportedOrientations & root.shellOrientation) {
165 if (supportedOrientations & root.shellOrientation) {
167 chosenOrientation = root.shellOrientation;
166 chosenOrientation = root.shellOrientation;
168 } else if (supportedOrientations & Qt.PortraitOrientation) {
167 } else if (supportedOrientations & Qt.PortraitOrientation) {
169− chosenOrientation = Qt.PortraitOrientation;
168+ chosenOrientation = root.orientations.portrait;
170 } else if (supportedOrientations & Qt.LandscapeOrientation) {
169 } else if (supportedOrientations & Qt.LandscapeOrientation) {
171− chosenOrientation = Qt.LandscapeOrientation;
170+ chosenOrientation = root.orientations.landscape;
172 } else if (supportedOrientations & Qt.InvertedPortraitOrientation) {
171 } else if (supportedOrientations & Qt.InvertedPortraitOrientation) {
173− chosenOrientation = Qt.InvertedPortraitOrientation;
172+ chosenOrientation = root.orientations.invertedPortrait;
174 } else if (supportedOrientations & Qt.InvertedLandscapeOrientation) {
173 } else if (supportedOrientations & Qt.InvertedLandscapeOrientation) {
175− chosenOrientation = Qt.InvertedLandscapeOrientation;
174+ chosenOrientation = root.orientations.invertedLandscape;
176 } else {
175 } else {
177− chosenOrientation = root.shellPrimaryOrientation;
176+ chosenOrientation = root.orientations.primary;
178 }
177 }
179
178
180− return Screen.angleBetween(root.nativeOrientation, chosenOrientation);
179+ return Screen.angleBetween(root.orientations.native_, chosenOrientation);
181 }
180 }
182
181
183 rotation: normalizeAngle(appWindowWithShadow.orientationAngle - root.shellOrientationAngle)
182 rotation: normalizeAngle(appWindowWithShadow.orientationAngle - root.shellOrientationAngle)
qml/Stages/SurfaceContainer.qml+1
@@ -28,6 +28,7 @@ FocusScope {
28 property bool hadSurface: false
28 property bool hadSurface: false
29 property bool interactive
29 property bool interactive
30 property int surfaceOrientationAngle: 0
30 property int surfaceOrientationAngle: 0
31+ property string name: surface ? surface.name : ""
31 property bool resizeSurface: true
32 property bool resizeSurface: true
32
33
33 onSurfaceChanged: {
34 onSurfaceChanged: {
qml/Stages/TabletStage.qml+24−36
@@ -21,29 +21,12 @@ import Unity.Application 0.1
21import Utils 0.1
21import Utils 0.1
22import "../Components"
22import "../Components"
23
23
24−Rectangle {
24+AbstractStage {
25 id: root
25 id: root
26 objectName: "stages"
26 objectName: "stages"
27 anchors.fill: parent
27 anchors.fill: parent
28− color: "#111111"
28+
29−
30− // Controls to be set from outside
29+ // Functions to be called from outside
31− property int dragAreaWidth
32− property real maximizedAppTopMargin
33− property bool interactive
34− property alias beingResized: spreadView.beingResized
35−
36− property bool spreadEnabled: true // If false, animations and right edge will be disabled
37−
38− property real inverseProgress: 0 // This is the progress for left edge drags, in pixels.
39− property bool keepDashRunning: true
40− property bool suspended: false
41− property int shellOrientationAngle: 0
42− property int shellOrientation
43− property int shellPrimaryOrientation
44− property int nativeOrientation
45− property real nativeWidth
46− property real nativeHeight
47 function updateFocusedAppOrientation() {
30 function updateFocusedAppOrientation() {
48 var mainStageAppIndex = priv.indexOf(priv.mainStageAppId);
31 var mainStageAppIndex = priv.indexOf(priv.mainStageAppId);
49 if (mainStageAppIndex >= 0 && mainStageAppIndex < spreadRepeater.count) {
32 if (mainStageAppIndex >= 0 && mainStageAppIndex < spreadRepeater.count) {
@@ -64,7 +47,7 @@ Rectangle {
64
47
65 var supportedOrientations = spreadDelegate.application.supportedOrientations;
48 var supportedOrientations = spreadDelegate.application.supportedOrientations;
66 if (supportedOrientations === Qt.PrimaryOrientation) {
49 if (supportedOrientations === Qt.PrimaryOrientation) {
67− supportedOrientations = spreadDelegate.shellPrimaryOrientation;
50+ supportedOrientations = spreadDelegate.orientations.primary;
68 }
51 }
69
52
70 if (delta === 180 && (supportedOrientations & spreadDelegate.shellOrientation)) {
53 if (delta === 180 && (supportedOrientations & spreadDelegate.shellOrientation)) {
@@ -86,10 +69,7 @@ Rectangle {
86 }
69 }
87 }
70 }
88
71
89− // To be read from outside
90− property var mainApp: null
91− property int mainAppWindowOrientationAngle: 0
92− readonly property bool orientationChangesEnabled: priv.mainAppOrientationChangesEnabled
72+ orientationChangesEnabled: priv.mainAppOrientationChangesEnabled
93
73
94 onWidthChanged: {
74 onWidthChanged: {
95 spreadView.selectedIndex = -1;
75 spreadView.selectedIndex = -1;
@@ -130,7 +110,7 @@ Rectangle {
130 property string oldFocusedAppId: ""
110 property string oldFocusedAppId: ""
131 property bool mainAppOrientationChangesEnabled: false
111 property bool mainAppOrientationChangesEnabled: false
132
112
133− property real landscapeHeight: root.nativeOrientation == Qt.LandscapeOrientation ?
113+ property real landscapeHeight: root.orientations.native_ == Qt.LandscapeOrientation ?
134 root.nativeHeight : root.nativeWidth
114 root.nativeHeight : root.nativeWidth
135
115
136 property bool shellIsLandscape: root.shellOrientation === Qt.LandscapeOrientation
116 property bool shellIsLandscape: root.shellOrientation === Qt.LandscapeOrientation
@@ -302,7 +282,7 @@ Rectangle {
302 }
282 }
303
283
304 property bool animateX: true
284 property bool animateX: true
305− property bool beingResized: false
285+ property bool beingResized: root.beingResized
306 onBeingResizedChanged: {
286 onBeingResizedChanged: {
307 if (beingResized) {
287 if (beingResized) {
308 // Brace yourselves for impact!
288 // Brace yourselves for impact!
@@ -629,15 +609,18 @@ Rectangle {
629
609
630 readonly property bool isDash: model.appId == "unity8-dash"
610 readonly property bool isDash: model.appId == "unity8-dash"
631
611
612+ readonly property bool canSuspend: model.isTouchApp
613+ && !isExemptFromLifecycle(model.appId)
614+
632 Binding {
615 Binding {
633 target: spreadTile.application
616 target: spreadTile.application
634 property: "requestedState"
617 property: "requestedState"
618+ value: !canSuspend
635− value: (spreadTile.isDash && root.keepDashRunning)
619+ || (isDash && root.keepDashRunning)
636− ||
637− (!root.suspended && (model.appId == priv.mainStageAppId
620+ || (!root.suspended && (model.appId == priv.mainStageAppId
638− || model.appId == priv.sideStageAppId))
621+ || model.appId == priv.sideStageAppId))
639− ? ApplicationInfoInterface.RequestedRunning
622+ ? ApplicationInfoInterface.RequestedRunning
640− : ApplicationInfoInterface.RequestedSuspended
623+ : ApplicationInfoInterface.RequestedSuspended
641 }
624 }
642
625
643 // FIXME: A regular binding doesn't update any more after closing an app.
626 // FIXME: A regular binding doesn't update any more after closing an app.
@@ -699,9 +682,14 @@ Rectangle {
699
682
700 shellOrientationAngle: wantsMainStage ? root.shellOrientationAngle : 0
683 shellOrientationAngle: wantsMainStage ? root.shellOrientationAngle : 0
701 shellOrientation: wantsMainStage ? root.shellOrientation : Qt.PortraitOrientation
684 shellOrientation: wantsMainStage ? root.shellOrientation : Qt.PortraitOrientation
685+ orientations: Orientations {
702− shellPrimaryOrientation: wantsMainStage ? root.shellPrimaryOrientation : Qt.PortraitOrientation
686+ primary: spreadTile.wantsMainStage ? root.orientations.primary : Qt.PortraitOrientation
703− nativeOrientation: wantsMainStage ? root.nativeOrientation : Qt.PortraitOrientation
687+ native_: spreadTile.wantsMainStage ? root.orientations.native_ : Qt.PortraitOrientation
704−
688+ portrait: root.orientations.portrait
689+ invertedPortrait: root.orientations.invertedPortrait
690+ landscape: root.orientations.landscape
691+ invertedLandscape: root.orientations.invertedLandscape
692+ }
705
693
706 onClicked: {
694 onClicked: {
707 if (spreadView.phase == 2) {
695 if (spreadView.phase == 2) {
qml/Stages/WindowDecoration.qml+32−4
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright (C) 2014 Canonical, Ltd.
2+ * Copyright (C) 2014-2015 Canonical, Ltd.
3 *
3 *
4 * This program is free software; you can redistribute it and/or modify
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
5 * it under the terms of the GNU General Public License as published by
@@ -12,25 +12,53 @@
12 *
12 *
13 * You should have received a copy of the GNU General Public License
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− *
16− * Authors: Michael Zanetti <michael.zanetti@canonical.com>
17 */
15 */
18
16
19import QtQuick 2.3
17import QtQuick 2.3
18+import Unity.Application 0.1 // For Mir singleton
20import Ubuntu.Components 1.1
19import Ubuntu.Components 1.1
21import "../Components"
20import "../Components"
22
21
23−Item {
22+MouseArea {
24 id: root
23 id: root
25 clip: true
24 clip: true
26
25
26+ property Item target
27 property alias title: titleLabel.text
27 property alias title: titleLabel.text
28 property bool active: false
28 property bool active: false
29+ hoverEnabled: true
29
30
30 signal close()
31 signal close()
31 signal minimize()
32 signal minimize()
32 signal maximize()
33 signal maximize()
33
34
35+ QtObject {
36+ id: priv
37+ property real distanceX
38+ property real distanceY
39+ property bool dragging
40+ }
41+
42+ onPressedChanged: {
43+ if (pressed) {
44+ var pos = mapToItem(root.target, mouseX, mouseY);
45+ priv.distanceX = pos.x;
46+ priv.distanceY = pos.y;
47+ priv.dragging = true;
48+ Mir.cursorName = "grabbing";
49+ } else {
50+ priv.dragging = false;
51+ Mir.cursorName = "";
52+ }
53+ }
54+ onPositionChanged: {
55+ if (priv.dragging) {
56+ var pos = mapToItem(root.target.parent, mouseX, mouseY);
57+ root.target.x = pos.x - priv.distanceX;
58+ root.target.y = pos.y - priv.distanceY;
59+ }
60+ }
61+
34 Rectangle {
62 Rectangle {
35 anchors.fill: parent
63 anchors.fill: parent
36 anchors.bottomMargin: -radius
64 anchors.bottomMargin: -radius
qml/Stages/WindowMoveResizeArea.qmldeleted−109
@@ -1,109 +0,0 @@
1−/*
2− * Copyright (C) 2014-2015 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− *
16− * Authors: Michael Zanetti <michael.zanetti@canonical.com>
17− */
18−
19−import QtQuick 2.3
20−import Ubuntu.Components 1.1
21−import Utils 0.1
22−
23−MouseArea {
24− id: root
25− anchors.fill: target
26− anchors.margins: -resizeHandleWidth
27−
28− property var windowStateStorage: WindowStateStorage
29−
30− // The target item managed by this. Must be a parent or a sibling
31− // The area will anchor to it and manage move and resize events
32− property Item target: null
33− property string windowId: ""
34− property int resizeHandleWidth: 0
35− property int minWidth: 0
36− property int minHeight: 0
37−
38− QtObject {
39− id: priv
40− readonly property int windowWidth: root.width - root.resizeHandleWidth * 2
41− readonly property int windowHeight: root.height - resizeHandleWidth * 2
42−
43− property var startPoint
44−
45− property bool resizeTop: false
46− property bool resizeBottom: false
47− property bool resizeLeft: false
48− property bool resizeRight: false
49−
50− }
51−
52− Component.onCompleted: {
53− var windowState = windowStateStorage.getGeometry(root.windowId, Qt.rect(target.x, target.y, target.width, target.height))
54− if (windowState !== undefined) {
55− target.x = windowState.x
56− target.y = windowState.y
57− target.width = windowState.width
58− target.height = windowState.height
59− }
60− }
61−
62− onPressed: {
63− priv.startPoint = Qt.point(mouse.x, mouse.y);
64− priv.resizeTop = mouseY < root.resizeHandleWidth;
65− priv.resizeBottom = mouseY > (root.height - root.resizeHandleWidth);
66− priv.resizeLeft = mouseX < root.resizeHandleWidth;
67− priv.resizeRight = mouseX > (root.width - root.resizeHandleWidth);
68− }
69−
70− onPositionChanged: {
71− var currentPoint = Qt.point(mouse.x, mouse.y);
72− var mouseDiff = Qt.point(currentPoint.x - priv.startPoint.x, currentPoint.y - priv.startPoint.y);
73− var moveDiff = Qt.point(0, 0);
74− var sizeDiff = Qt.point(0, 0);
75− var maxSizeDiff = Qt.point(root.minWidth - root.target.width, root.minHeight - root.target.height)
76−
77− if (priv.resizeTop || priv.resizeBottom || priv.resizeLeft || priv.resizeRight) {
78− if (priv.resizeTop) {
79− sizeDiff.y = Math.max(maxSizeDiff.y, -currentPoint.y + priv.startPoint.y)
80− moveDiff.y = -sizeDiff.y
81− }
82− if (priv.resizeBottom) {
83− sizeDiff.y = Math.max(maxSizeDiff.y, currentPoint.y - priv.startPoint.y)
84− priv.startPoint.y += sizeDiff.y
85− }
86− if (priv.resizeLeft) {
87− sizeDiff.x = Math.max(maxSizeDiff.x, -currentPoint.x + priv.startPoint.x)
88− moveDiff.x = -sizeDiff.x
89− }
90− if (priv.resizeRight) {
91− sizeDiff.x = Math.max(maxSizeDiff.x, currentPoint.x - priv.startPoint.x)
92− priv.startPoint.x += sizeDiff.x
93− }
94−
95− target.x += moveDiff.x;
96− target.y += moveDiff.y;
97− target.width += sizeDiff.x;
98− target.height += sizeDiff.y;
99− } else {
100− target.x += mouseDiff.x;
101− target.y += mouseDiff.y;
102− }
103−
104− }
105−
106− Component.onDestruction: {
107− windowStateStorage.saveGeometry(root.windowId, Qt.rect(target.x, target.y, target.width, target.height))
108− }
109−}
qml/Stages/WindowResizeArea.qmlnew file+213
@@ -0,0 +1,213 @@
1+/*
2+ * Copyright (C) 2014-2015 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.3
18+import Ubuntu.Components 1.1
19+import Utils 0.1
20+import Unity.Application 0.1 // for Mir.cursorName
21+
22+MouseArea {
23+ id: root
24+ anchors.fill: target
25+ anchors.margins: -borderThickness
26+
27+ hoverEnabled: true
28+
29+ property var windowStateStorage: WindowStateStorage
30+
31+ // The target item managed by this. Must be a parent or a sibling
32+ // The area will anchor to it and manage move and resize events
33+ property Item target: null
34+ property string windowId: ""
35+ property int borderThickness: 0
36+ property int minWidth: 0
37+ property int minHeight: 0
38+
39+ QtObject {
40+ id: priv
41+
42+ property int normalX: 0
43+ property int normalY: 0
44+ property int normalWidth: 0
45+ property int normalHeight: 0
46+
47+ function updateNormalGeometry() {
48+ if (root.target.state == "normal") {
49+ normalX = root.target.x
50+ normalY = root.target.y
51+ normalWidth = root.target.width
52+ normalHeight = root.target.height
53+ }
54+ }
55+ }
56+
57+ Connections {
58+ target: root.target
59+ onXChanged: priv.updateNormalGeometry();
60+ onYChanged: priv.updateNormalGeometry();
61+ onWidthChanged: priv.updateNormalGeometry();
62+ onHeightChanged: priv.updateNormalGeometry();
63+ }
64+
65+ Component.onCompleted: {
66+ var windowGeometry = windowStateStorage.getGeometry(root.windowId, Qt.rect(target.x, target.y, target.width, target.height))
67+ if (windowGeometry !== undefined) {
68+ target.x = windowGeometry.x
69+ target.y = windowGeometry.y
70+ target.width = windowGeometry.width
71+ target.height = windowGeometry.height
72+ }
73+ var windowState = windowStateStorage.getState(root.windowId, WindowStateStorage.WindowStateNormal)
74+ if (windowState === WindowStateStorage.WindowStateMaximized) {
75+ target.maximize(false)
76+ }
77+ }
78+
79+ Component.onDestruction: {
80+ windowStateStorage.saveState(root.windowId, target.state == "maximized" ? WindowStateStorage.WindowStateMaximized : WindowStateStorage.WindowStateNormal)
81+ windowStateStorage.saveGeometry(root.windowId, Qt.rect(priv.normalX, priv.normalY, priv.normalWidth, priv.normalHeight))
82+ }
83+
84+ QtObject {
85+ id: d
86+ property bool leftBorder: false
87+ property bool rightBorder: false
88+ property bool topBorder: false
89+ property bool bottomBorder: false
90+
91+ property bool dragging: false
92+ property real startMousePosX
93+ property real startMousePosY
94+ property real startX
95+ property real startY
96+ property real startWidth
97+ property real startHeight
98+
99+ property string cursorName: {
100+ if (root.containsMouse || root.pressed) {
101+ if (leftBorder && !topBorder && !bottomBorder) {
102+ return "left_side";
103+ } else if (rightBorder && !topBorder && !bottomBorder) {
104+ return "right_side";
105+ } else if (topBorder && !leftBorder && !rightBorder) {
106+ return "top_side";
107+ } else if (bottomBorder && !leftBorder && !rightBorder) {
108+ return "bottom_side";
109+ } else if (leftBorder && topBorder) {
110+ return "top_left_corner";
111+ } else if (leftBorder && bottomBorder) {
112+ return "bottom_left_corner";
113+ } else if (rightBorder && topBorder) {
114+ return "top_right_corner";
115+ } else if (rightBorder && bottomBorder) {
116+ return "bottom_right_corner";
117+ } else {
118+ return "";
119+ }
120+ } else {
121+ return "";
122+ }
123+ }
124+ onCursorNameChanged: {
125+ Mir.cursorName = cursorName;
126+ }
127+
128+ function updateBorders() {
129+ leftBorder = mouseX <= borderThickness;
130+ rightBorder = mouseX >= width - borderThickness;
131+ topBorder = mouseY <= borderThickness;
132+ bottomBorder = mouseY >= height - borderThickness;
133+ }
134+ }
135+
136+ onPressedChanged: {
137+ var pos = mapToItem(target.parent, mouseX, mouseY);
138+
139+ if (pressed) {
140+ d.updateBorders();
141+ var pos = mapToItem(root.target.parent, mouseX, mouseY);
142+ d.startMousePosX = pos.x;
143+ d.startMousePosY = pos.y;
144+ d.startX = target.x;
145+ d.startY = target.y;
146+ d.startWidth = target.width;
147+ d.startHeight = target.height;
148+ d.dragging = true;
149+ } else {
150+ d.dragging = false;
151+ if (containsMouse) {
152+ d.updateBorders();
153+ }
154+ }
155+ }
156+
157+ onEntered: {
158+ if (!pressed) {
159+ d.updateBorders();
160+ }
161+ }
162+
163+ onPositionChanged: {
164+ if (!pressed) {
165+ d.updateBorders();
166+ }
167+
168+ if (!d.dragging) {
169+ return;
170+ }
171+
172+ var pos = mapToItem(target.parent, mouse.x, mouse.y);
173+
174+ var deltaX = pos.x - d.startMousePosX;
175+ var deltaY = pos.y - d.startMousePosY;
176+
177+ if (d.leftBorder) {
178+ var newTargetX = d.startX + deltaX;
179+ if (target.x + target.width > newTargetX + minWidth) {
180+ target.width = target.x + target.width - newTargetX;
181+ target.x = newTargetX;
182+ } else {
183+ target.x = target.x + target.width - minWidth;
184+ target.width = minWidth;
185+ }
186+
187+ } else if (d.rightBorder) {
188+ if (d.startWidth + deltaX >= minWidth) {
189+ target.width = d.startWidth + deltaX;
190+ } else {
191+ target.width = minWidth;
192+ }
193+ }
194+
195+ if (d.topBorder) {
196+ var newTargetY = d.startY + deltaY;
197+ if (target.y + target.height > newTargetY + minHeight) {
198+ target.height = target.y + target.height - newTargetY;
199+ target.y = newTargetY;
200+ } else {
201+ target.y = target.y + target.height - minHeight;
202+ target.height = minHeight;
203+ }
204+
205+ } else if (d.bottomBorder) {
206+ if (d.startHeight + deltaY >= minHeight) {
207+ target.height = d.startHeight + deltaY;
208+ } else {
209+ target.height = minHeight;
210+ }
211+ }
212+ }
213+}
qml/graphics/applicationIcons/libreoffice@18.pngnew file

Binary file not shown.

src/ApplicationArguments.h+10−2
@@ -26,17 +26,25 @@
26class ApplicationArguments : public QObject
26class ApplicationArguments : public QObject
27{
27{
28 Q_OBJECT
28 Q_OBJECT
29− Q_PROPERTY(QString deviceName READ deviceName CONSTANT)
29+ Q_PROPERTY(QString deviceName READ deviceName NOTIFY deviceNameChanged)
30 Q_PROPERTY(QString mode READ mode CONSTANT)
30 Q_PROPERTY(QString mode READ mode CONSTANT)
31public:
31public:
32 ApplicationArguments(QObject *parent = nullptr);
32 ApplicationArguments(QObject *parent = nullptr);
33
33
34− void setDeviceName(const QString &deviceName) { m_deviceName = deviceName; }
34+ void setDeviceName(const QString &deviceName) {
35+ if (deviceName != m_deviceName) {
36+ m_deviceName = deviceName;
37+ Q_EMIT deviceNameChanged(m_deviceName);
38+ }
39+ }
35 QString deviceName() const { return m_deviceName; }
40 QString deviceName() const { return m_deviceName; }
36
41
37 void setMode(const QString &mode) { m_mode = mode; }
42 void setMode(const QString &mode) { m_mode = mode; }
38 QString mode() const { return m_mode; }
43 QString mode() const { return m_mode; }
39
44
45+Q_SIGNALS:
46+ void deviceNameChanged(const QString&);
47+
40private:
48private:
41 QString m_deviceName;
49 QString m_deviceName;
42 QString m_mode;
50 QString m_mode;
src/CMakeLists.txt+3
@@ -21,6 +21,9 @@ add_executable(${SHELL_APP}
21 main.cpp
21 main.cpp
22 MouseTouchAdaptor.cpp
22 MouseTouchAdaptor.cpp
23 CachingNetworkManagerFactory.cpp
23 CachingNetworkManagerFactory.cpp
24+ SecondaryWindow.cpp
25+ ShellApplication.cpp
26+ ShellView.cpp
24 UnityCommandLineParser.cpp
27 UnityCommandLineParser.cpp
25 ${QML_FILES} # This is to make qml and image files appear in the IDE's project tree
28 ${QML_FILES} # This is to make qml and image files appear in the IDE's project tree
26)
29)
src/SecondaryWindow.cppnew file+31
@@ -0,0 +1,31 @@
1+/*
2+ * Copyright (C) 2015 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#include "SecondaryWindow.h"
18+
19+// local
20+#include <paths.h>
21+
22+SecondaryWindow::SecondaryWindow(QQmlEngine *engine)
23+ : QQuickView(engine, nullptr)
24+{
25+ setResizeMode(QQuickView::SizeRootObjectToView);
26+ setColor("black");
27+ setTitle(QStringLiteral("Unity8 Shell - Secondary Screen"));
28+
29+ QUrl source(::qmlDirectory() + "/DisabledScreenNotice.qml");
30+ setSource(source);
31+}
src/SecondaryWindow.hnew file+30
@@ -0,0 +1,30 @@
1+/*
2+ * Copyright (C) 2015 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#ifndef UNITY_SECONDARY_WINDOW_H
18+#define UNITY_SECONDARY_WINDOW_H
19+
20+#include <QQuickView>
21+
22+class SecondaryWindow : public QQuickView
23+{
24+ Q_OBJECT
25+
26+public:
27+ SecondaryWindow(QQmlEngine *engine);
28+};
29+
30+#endif // UNITY_SECONDARY_WINDOW_H
src/ShellApplication.cppnew file+197
@@ -0,0 +1,197 @@
1+/*
2+ * Copyright (C) 2015 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#include "ShellApplication.h"
18+
19+// Qt
20+#include <QLibrary>
21+#include <QScreen>
22+
23+#include <libintl.h>
24+
25+// libandroid-properties
26+#include <hybris/properties/properties.h>
27+
28+// local
29+#include <paths.h>
30+#include "CachingNetworkManagerFactory.h"
31+#include "MouseTouchAdaptor.h"
32+#include "UnityCommandLineParser.h"
33+
34+ShellApplication::ShellApplication(int & argc, char ** argv, bool isMirServer)
35+ : QGuiApplication(argc, argv)
36+ , m_shellView(nullptr)
37+ , m_secondaryWindow(nullptr)
38+ , m_mouseTouchAdaptor(nullptr)
39+ , m_qmlEngine(nullptr)
40+{
41+
42+ setApplicationName(QStringLiteral("unity8"));
43+
44+ connect(this, &QGuiApplication::screenAdded, this, &ShellApplication::onScreenAdded);
45+
46+ setupQmlEngine(isMirServer);
47+
48+ UnityCommandLineParser parser(*this);
49+
50+ if (!parser.deviceName().isEmpty()) {
51+ m_deviceName = parser.deviceName();
52+ } else {
53+ char buffer[200];
54+ property_get("ro.product.device", buffer /* value */, "desktop" /* default_value*/);
55+ m_deviceName = QString(buffer);
56+ }
57+ m_qmlArgs.setDeviceName(m_deviceName);
58+
59+ m_qmlArgs.setMode(parser.mode());
60+
61+ // The testability driver is only loaded by QApplication but not by QGuiApplication.
62+ // However, QApplication depends on QWidget which would add some unneeded overhead => Let's load the testability driver on our own.
63+ if (parser.hasTestability() || getenv("QT_LOAD_TESTABILITY")) {
64+ QLibrary testLib(QStringLiteral("qttestability"));
65+ if (testLib.load()) {
66+ typedef void (*TasInitialize)(void);
67+ TasInitialize initFunction = (TasInitialize)testLib.resolve("qt_testability_init");
68+ if (initFunction) {
69+ initFunction();
70+ } else {
71+ qCritical("Library qttestability resolve failed!");
72+ }
73+ } else {
74+ qCritical("Library qttestability load failed!");
75+ }
76+ }
77+
78+ bindtextdomain("unity8", translationDirectory().toUtf8().data());
79+ textdomain("unity8");
80+
81+ m_shellView = new ShellView(m_qmlEngine, &m_qmlArgs);
82+
83+ if (parser.windowGeometry().isValid()) {
84+ m_shellView->setWidth(parser.windowGeometry().width());
85+ m_shellView->setHeight(parser.windowGeometry().height());
86+ }
87+
88+ if (parser.hasFrameless()) {
89+ m_shellView->setFlags(Qt::FramelessWindowHint);
90+ }
91+
92+ // You will need this if you want to interact with touch-only components using a mouse
93+ // Needed only when manually testing on a desktop.
94+ if (parser.hasMouseToTouch()) {
95+ m_mouseTouchAdaptor = MouseTouchAdaptor::instance();
96+ }
97+
98+
99+ // Some hard-coded policy for now.
100+ // NB: We don't support more than two screens at the moment
101+ //
102+ // TODO: Support an arbitrary number of screens and different policies
103+ // (eg cloned desktop, several desktops, etc)
104+ if (isMirServer && screens().count() == 2) {
105+ m_shellView->setScreen(screens().at(1));
106+ m_qmlArgs.setDeviceName("desktop");
107+
108+ m_secondaryWindow = new SecondaryWindow(m_qmlEngine);
109+ m_secondaryWindow->setScreen(screens().at(0));
110+ // QWindow::showFullScreen() also calls QWindow::requestActivate() and we don't want that!
111+ m_secondaryWindow->setWindowState(Qt::WindowFullScreen);
112+ m_secondaryWindow->setVisible(true);
113+ }
114+
115+ if (isMirServer || parser.hasFullscreen()) {
116+ m_shellView->showFullScreen();
117+ } else {
118+ m_shellView->show();
119+ }
120+}
121+
122+ShellApplication::~ShellApplication()
123+{
124+ destroyResources();
125+}
126+
127+void ShellApplication::destroyResources()
128+{
129+ // Deletion order is important. Don't use QScopedPointers and the like
130+ // Otherwise the process will hang on shutdown (bug somewhere I guess).
131+ delete m_shellView;
132+ m_shellView = nullptr;
133+
134+ delete m_secondaryWindow;
135+ m_secondaryWindow = nullptr;
136+
137+ delete m_mouseTouchAdaptor;
138+ m_mouseTouchAdaptor = nullptr;
139+
140+ delete m_qmlEngine;
141+ m_qmlEngine = nullptr;
142+}
143+
144+void ShellApplication::setupQmlEngine(bool isMirServer)
145+{
146+ m_qmlEngine = new QQmlEngine(this);
147+
148+ m_qmlEngine->setBaseUrl(QUrl::fromLocalFile(::qmlDirectory()));
149+
150+ prependImportPaths(m_qmlEngine, ::overrideImportPaths());
151+ if (!isMirServer) {
152+ prependImportPaths(m_qmlEngine, ::nonMirImportPaths());
153+ }
154+ appendImportPaths(m_qmlEngine, ::fallbackImportPaths());
155+
156+ m_qmlEngine->setNetworkAccessManagerFactory(new CachingNetworkManagerFactory);
157+
158+ QObject::connect(m_qmlEngine, &QQmlEngine::quit, this, &QGuiApplication::quit);
159+}
160+
161+void ShellApplication::onScreenAdded(QScreen * /*screen*/)
162+{
163+ // TODO: Support an arbitrary number of screens and different policies
164+ // (eg cloned desktop, several desktops, etc)
165+ if (screens().count() == 2) {
166+ m_shellView->setScreen(screens().at(1));
167+ m_qmlArgs.setDeviceName("desktop");
168+ // Changing the QScreen where a QWindow is drawn makes it also lose focus (besides having
169+ // its backing QPlatformWindow recreated). So lets refocus it.
170+ m_shellView->requestActivate();
171+
172+ m_secondaryWindow = new SecondaryWindow(m_qmlEngine);
173+ m_secondaryWindow->setScreen(screens().at(0));
174+
175+ // QWindow::showFullScreen() also calls QWindow::requestActivate() and we don't want that!
176+ m_secondaryWindow->setWindowState(Qt::WindowFullScreen);
177+ m_secondaryWindow->setVisible(true);
178+ }
179+}
180+
181+void ShellApplication::onScreenAboutToBeRemoved(QScreen *screen)
182+{
183+ // TODO: Support an arbitrary number of screens and different policies
184+ // (eg cloned desktop, several desktops, etc)
185+ if (screen == m_shellView->screen()) {
186+ Q_ASSERT(screens().count() > 1);
187+ Q_ASSERT(screens().at(0) != screen);
188+ Q_ASSERT(m_secondaryWindow);
189+ delete m_secondaryWindow;
190+ m_secondaryWindow = nullptr;
191+ m_shellView->setScreen(screens().first());
192+ m_qmlArgs.setDeviceName(m_deviceName);
193+ // Changing the QScreen where a QWindow is drawn makes it also lose focus (besides having
194+ // its backing QPlatformWindow recreated). So lets refocus it.
195+ m_shellView->requestActivate();
196+ }
197+}
src/ShellApplication.hnew file+55
@@ -0,0 +1,55 @@
1+/*
2+ * Copyright (C) 2015 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#ifndef SHELLAPPLICATION_H
18+#define SHELLAPPLICATION_H
19+
20+#include <QGuiApplication>
21+#include <QQmlEngine>
22+#include <QQuickView>
23+#include <QScopedPointer>
24+
25+#include "ApplicationArguments.h"
26+#include "MouseTouchAdaptor.h"
27+#include "SecondaryWindow.h"
28+#include "ShellView.h"
29+
30+class ShellApplication : public QGuiApplication
31+{
32+ Q_OBJECT
33+public:
34+ ShellApplication(int & argc, char ** argv, bool isMirServer);
35+ virtual ~ShellApplication();
36+
37+ void destroyResources();
38+public Q_SLOTS:
39+ // called by qtmir
40+ void onScreenAboutToBeRemoved(QScreen *screen);
41+
42+private Q_SLOTS:
43+ void onScreenAdded(QScreen*);
44+
45+private:
46+ void setupQmlEngine(bool isMirServer);
47+ QString m_deviceName;
48+ ApplicationArguments m_qmlArgs;
49+ ShellView *m_shellView;
50+ SecondaryWindow *m_secondaryWindow;
51+ MouseTouchAdaptor *m_mouseTouchAdaptor;
52+ QQmlEngine *m_qmlEngine;
53+};
54+
55+#endif // SHELLAPPLICATION_H
src/ShellView.cppnew file+59
@@ -0,0 +1,59 @@
1+/*
2+ * Copyright (C) 2015 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#include "ShellView.h"
18+
19+// Qt
20+#include <QQmlContext>
21+#include <QQuickItem>
22+
23+// local
24+#include <paths.h>
25+
26+ShellView::ShellView(QQmlEngine *engine, QObject *qmlArgs)
27+ : QQuickView(engine, nullptr)
28+{
29+ setResizeMode(QQuickView::SizeRootObjectToView);
30+ setColor("black");
31+ setTitle(QStringLiteral("Unity8"));
32+
33+ rootContext()->setContextProperty(QStringLiteral("applicationArguments"), qmlArgs);
34+
35+ QUrl source(::qmlDirectory() + "/OrientedShell.qml");
36+ setSource(source);
37+
38+ connect(this, &QWindow::widthChanged, this, &ShellView::onWidthChanged);
39+ connect(this, &QWindow::heightChanged, this, &ShellView::onHeightChanged);
40+}
41+
42+void ShellView::onWidthChanged(int w)
43+{
44+ // For good measure in case SizeRootObjectToView doesn't fulfill its promise.
45+ //
46+ // There's at least one situation that's know to leave the root object with an outdated size.
47+ // (really looks like Qt bug)
48+ // Happens when starting unity8 with an external monitor already connected.
49+ // The QResizeEvent we get still has the size of the first screen and since the resize move is triggered
50+ // from the resize event handler, the root item doesn't get resized.
51+ // TODO: Confirm the Qt bug and submit a patch upstream
52+ rootObject()->setWidth(w);
53+}
54+
55+void ShellView::onHeightChanged(int h)
56+{
57+ // See comment in ShellView::onWidthChanged()
58+ rootObject()->setHeight(h);
59+}
src/ShellView.hnew file+34
@@ -0,0 +1,34 @@
1+/*
2+ * Copyright (C) 2015 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#ifndef UNITY_SHELL_VIEW_H
18+#define UNITY_SHELL_VIEW_H
19+
20+#include <QQuickView>
21+
22+class ShellView : public QQuickView
23+{
24+ Q_OBJECT
25+
26+public:
27+ ShellView(QQmlEngine *engine, QObject *qmlArgs);
28+
29+private Q_SLOTS:
30+ void onWidthChanged(int);
31+ void onHeightChanged(int);
32+};
33+
34+#endif // UNITY_SHELL_VIEW_H
src/main.cpp+4−101
@@ -14,26 +14,8 @@
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
15 */
16
16
17−// Qt
18−#include <QCommandLineParser>
19−#include <QtQuick/QQuickView>
20−#include <QtGui/QGuiApplication>
21−#include <QtQml/QQmlEngine>
22−#include <QtQml/QQmlContext>
23−#include <QLibrary>
24−#include <QDebug>
25−#include <csignal>
26−#include <libintl.h>
27−
28−// libandroid-properties
29−#include <hybris/properties/properties.h>
30−
31// local
17// local
32−#include <paths.h>
18+#include "ShellApplication.h"
33−#include "MouseTouchAdaptor.h"
34−#include "ApplicationArguments.h"
35−#include "CachingNetworkManagerFactory.h"
36−#include "UnityCommandLineParser.h"
37
19
38int main(int argc, const char *argv[])
20int main(int argc, const char *argv[])
39{
21{
@@ -43,91 +25,12 @@ int main(int argc, const char *argv[])
43 isMirServer = true;
25 isMirServer = true;
44 }
26 }
45
27
46− QGuiApplication::setApplicationName(QStringLiteral("unity8"));
28+ ShellApplication *application = new ShellApplication(argc, (char**)argv, isMirServer);
47− QGuiApplication *application;
48−
49− application = new QGuiApplication(argc, (char**)argv);
50−
51− UnityCommandLineParser parser(*application);
52−
53− ApplicationArguments qmlArgs;
54−
55− if (!parser.deviceName().isEmpty()) {
56− qmlArgs.setDeviceName(parser.deviceName());
57− } else {
58− char buffer[200];
59− property_get("ro.product.device", buffer /* value */, "desktop" /* default_value*/);
60− qmlArgs.setDeviceName(QString(buffer));
61− }
62−
63− qmlArgs.setMode(parser.mode());
64−
65− // The testability driver is only loaded by QApplication but not by QGuiApplication.
66− // However, QApplication depends on QWidget which would add some unneeded overhead => Let's load the testability driver on our own.
67− if (parser.hasTestability() || getenv("QT_LOAD_TESTABILITY")) {
68− QLibrary testLib(QStringLiteral("qttestability"));
69− if (testLib.load()) {
70− typedef void (*TasInitialize)(void);
71− TasInitialize initFunction = (TasInitialize)testLib.resolve("qt_testability_init");
72− if (initFunction) {
73− initFunction();
74− } else {
75− qCritical("Library qttestability resolve failed!");
76− }
77− } else {
78− qCritical("Library qttestability load failed!");
79− }
80− }
81−
82− bindtextdomain("unity8", translationDirectory().toUtf8().data());
83− textdomain("unity8");
84−
85− QQuickView* view = new QQuickView();
86− view->setResizeMode(QQuickView::SizeRootObjectToView);
87− view->setColor("black");
88− view->setTitle(QStringLiteral("Unity8 Shell"));
89−
90− if (parser.windowGeometry().isValid()) {
91− view->setWidth(parser.windowGeometry().width());
92− view->setHeight(parser.windowGeometry().height());
93− }
94−
95− view->engine()->setBaseUrl(QUrl::fromLocalFile(::qmlDirectory()));
96− view->rootContext()->setContextProperty(QStringLiteral("applicationArguments"), &qmlArgs);
97− if (parser.hasFrameless()) {
98− view->setFlags(Qt::FramelessWindowHint);
99− }
100−
101− // You will need this if you want to interact with touch-only components using a mouse
102− // Needed only when manually testing on a desktop.
103− MouseTouchAdaptor *mouseTouchAdaptor = 0;
104− if (parser.hasMouseToTouch()) {
105− mouseTouchAdaptor = MouseTouchAdaptor::instance();
106− }
107−
108− QUrl source(::qmlDirectory() + "/OrientedShell.qml");
109− prependImportPaths(view->engine(), ::overrideImportPaths());
110− if (!isMirServer) {
111− prependImportPaths(view->engine(), ::nonMirImportPaths());
112− }
113− appendImportPaths(view->engine(), ::fallbackImportPaths());
114−
115− CachingNetworkManagerFactory *managerFactory = new CachingNetworkManagerFactory();
116− view->engine()->setNetworkAccessManagerFactory(managerFactory);
117−
118− view->setSource(source);
119− QObject::connect(view->engine(), &QQmlEngine::quit, application, &QGuiApplication::quit);
120−
121− if (isMirServer || parser.hasFullscreen()) {
122− view->showFullScreen();
123− } else {
124− view->show();
125− }
126
29
127 int result = application->exec();
30 int result = application->exec();
128
31
129− delete view;
32+ application->destroyResources();
130− delete mouseTouchAdaptor;
33+
131 delete application;
34 delete application;
132
35
133 return result;
36 return result;
tests/autopilot/unity8/fixture_setup.py+1−1
@@ -133,7 +133,7 @@ class LaunchUnityWithFakeSensors(fixtures.Fixture):
133 args = [binary_arg] + env_args
133 args = [binary_arg] + env_args
134 self.unity_proxy = process_helpers.restart_unity_with_testability(
134 self.unity_proxy = process_helpers.restart_unity_with_testability(
135 *args)
135 *args)
136− self.main_win = self.unity_proxy.select_single(shell.QQuickView)
136+ self.main_win = self.unity_proxy.select_single(shell.ShellView)
137
137
138 def _create_sensors(self):
138 def _create_sensors(self):
139 # Wait for unity to start running.
139 # Wait for unity to start running.
tests/autopilot/unity8/greeter/tests/__init__.py+1−1
@@ -24,5 +24,5 @@ from unity8.shell.tests import UnityTestCase
24class GreeterTestCase(UnityTestCase):
24class GreeterTestCase(UnityTestCase):
25 def get_shell(self, unity_proxy):
25 def get_shell(self, unity_proxy):
26 main_window = (
26 main_window = (
27− unity_proxy.select_single(shell.QQuickView))
27+ unity_proxy.select_single(shell.ShellView))
28 return main_window.select_single('Shell')
28 return main_window.select_single('Shell')
tests/autopilot/unity8/launcher.py+1−1
@@ -42,7 +42,7 @@ class Launcher(ubuntuuitoolkit.UbuntuUIToolkitCustomProxyObjectBase):
42 logger.debug('The launcher is already opened.')
42 logger.debug('The launcher is already opened.')
43
43
44 def _swipe_to_show_launcher(self):
44 def _swipe_to_show_launcher(self):
45− view = self.get_root_instance().select_single('QQuickView')
45+ view = self.get_root_instance().select_single('ShellView')
46 start_y = stop_y = view.y + view.height // 2
46 start_y = stop_y = view.y + view.height // 2
47
47
48 start_x = view.x + 1
48 start_x = view.x + 1
tests/autopilot/unity8/settings_wizard/__init__.py+7−2
@@ -375,12 +375,17 @@ class WifiConnectPage(UbuntuUIToolkitCustomProxyObjectBase):
375 wizard = get_wizard(self)
375 wizard = get_wizard(self)
376 next_page = wizard.get_current_page()
376 next_page = wizard.get_current_page()
377 locationPageEnabled = True
377 locationPageEnabled = True
378+ reportingPageEnabled = True
378 if next_page.objectName == 'locationPage':
379 if next_page.objectName == 'locationPage':
379 next_page = wizard.get_location_page()
380 next_page = wizard.get_location_page()
380 else:
381 else:
381 locationPageEnabled = False
382 locationPageEnabled = False
383+ if next_page.objectName == 'reportingPage':
382− next_page = wizard.get_reporting_page()
384+ next_page = wizard.get_reporting_page()
385+ else:
386+ reportingPageEnabled = False
387+ next_page = wizard.get_finished_page()
383− return locationPageEnabled, next_page
388+ return locationPageEnabled, reportingPageEnabled, next_page
384
389
385 def _get_notification(self, unity):
390 def _get_notification(self, unity):
386 logger.info('Waiting longer for notification object')
391 logger.info('Waiting longer for notification object')
tests/autopilot/unity8/settings_wizard/tests/test_settings_wizard.py+10−5
@@ -80,14 +80,19 @@ class SkipThroughSettingsWizardTestCase(tests.UnityTestCase):
80 password_page = next_page
80 password_page = next_page
81 wifi_connect_page = self._test_password_page(password_page)
81 wifi_connect_page = self._test_password_page(password_page)
82
82
83+ reporting_page = None
83− locationPageEnabled, next_page = self._test_wifi_connect_page(
84+ locationPageEnabled, reportingPageEnabled, next_page = self._test_wifi_connect_page(wifi_connect_page)
84− wifi_connect_page)
85 if locationPageEnabled:
85 if locationPageEnabled:
86 location_page = next_page
86 location_page = next_page
87+ if reportingPageEnabled:
87− reporting_page = self._test_location_page(location_page)
88+ reporting_page = self._test_location_page(location_page)
89+ else:
90+ finish_page = next_page
91+
92+ if reporting_page is not None:
93+ finish_page = self._test_reporting_page(reporting_page)
88 else:
94 else:
89− reporting_page = next_page
95+ finish_page = next_page
90− finish_page = self._test_reporting_page(reporting_page)
91
96
92 finish_page.finish()
97 finish_page.finish()
93 self.assertFalse(
98 self.assertFalse(
tests/autopilot/unity8/shell/__init__.py+1−1
@@ -93,7 +93,7 @@ def _get_urgency(urgency):
93 return _urgency_enums.get(urgency.upper())
93 return _urgency_enums.get(urgency.upper())
94
94
95
95
96−class QQuickView(ubuntuuitoolkit.UbuntuUIToolkitCustomProxyObjectBase):
96+class ShellView(ubuntuuitoolkit.UbuntuUIToolkitCustomProxyObjectBase):
97 """An helper class that makes it easy to interact with the shell"""
97 """An helper class that makes it easy to interact with the shell"""
98
98
99 def get_greeter(self):
99 def get_greeter(self):
tests/autopilot/unity8/shell/tests/__init__.py+1−1
@@ -297,7 +297,7 @@ class UnityTestCase(AutopilotTestCase):
297
297
298 @property
298 @property
299 def main_window(self):
299 def main_window(self):
300− return self._proxy.select_single(shell.QQuickView)
300+ return self._proxy.select_single(shell.ShellView)
301
301
302
302
303class DashBaseTestCase(AutopilotTestCase):
303class DashBaseTestCase(AutopilotTestCase):
tests/mocks/CMakeLists.txt+1
@@ -29,6 +29,7 @@ macro(add_unity8_mock PLUGIN VERSION PATH)
29endmacro()
29endmacro()
30
30
31add_subdirectory(AccountsService)
31add_subdirectory(AccountsService)
32+add_subdirectory(Cursor)
32add_subdirectory(GSettings.1.0)
33add_subdirectory(GSettings.1.0)
33add_subdirectory(indicator-service)
34add_subdirectory(indicator-service)
34add_subdirectory(libusermetrics)
35add_subdirectory(libusermetrics)
tests/mocks/Cursor/CMakeLists.txtnew file+1
@@ -0,0 +1 @@
1+add_unity8_mock(Cursor 1.0 Cursor PREFIX mocks)
tests/mocks/Cursor/Cursor.qmlnew file+20
@@ -0,0 +1,20 @@
1+/*
2+ * Copyright (C) 2015 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.4
18+
19+Item {
20+}
tests/mocks/Cursor/qmldirnew file+2
@@ -0,0 +1,2 @@
1+module Cursor
2+Cursor 1.0 Cursor.qml
tests/mocks/GSettings.1.0/fake_gsettings.cpp+31
@@ -75,6 +75,19 @@ void GSettingsControllerQml::setLockedOutTime(qint64 timestamp)
75 }
75 }
76}
76}
77
77
78+QStringList GSettingsControllerQml::lifecycleExemptAppids() const
79+{
80+ return m_lifecycleExemptAppids;
81+}
82+
83+void GSettingsControllerQml::setLifecycleExemptAppids(const QStringList &appIds)
84+{
85+ if (m_lifecycleExemptAppids != appIds) {
86+ m_lifecycleExemptAppids = appIds;
87+ Q_EMIT lifecycleExemptAppidsChanged(m_lifecycleExemptAppids);
88+ }
89+}
90+
78GSettingsSchemaQml::GSettingsSchemaQml(QObject *parent): QObject(parent) {
91GSettingsSchemaQml::GSettingsSchemaQml(QObject *parent): QObject(parent) {
79}
92}
80
93
@@ -114,6 +127,8 @@ GSettingsQml::GSettingsQml(QObject *parent)
114 this, &GSettingsQml::usageModeChanged);
127 this, &GSettingsQml::usageModeChanged);
115 connect(GSettingsControllerQml::instance(), &GSettingsControllerQml::lockedOutTimeChanged,
128 connect(GSettingsControllerQml::instance(), &GSettingsControllerQml::lockedOutTimeChanged,
116 this, &GSettingsQml::lockedOutTimeChanged);
129 this, &GSettingsQml::lockedOutTimeChanged);
130+ connect(GSettingsControllerQml::instance(), &GSettingsControllerQml::lifecycleExemptAppidsChanged,
131+ this, &GSettingsQml::lifecycleExemptAppidsChanged);
117}
132}
118
133
119GSettingsSchemaQml * GSettingsQml::schema() const {
134GSettingsSchemaQml * GSettingsQml::schema() const {
@@ -167,3 +182,19 @@ void GSettingsQml::setLockedOutTime(qint64 timestamp)
167 GSettingsControllerQml::instance()->setLockedOutTime(timestamp);
182 GSettingsControllerQml::instance()->setLockedOutTime(timestamp);
168 }
183 }
169}
184}
185+
186+QStringList GSettingsQml::lifecycleExemptAppids() const
187+{
188+ if (m_schema->id() == "com.canonical.qtmir") {
189+ return GSettingsControllerQml::instance()->lifecycleExemptAppids();
190+ } else {
191+ return QStringList();
192+ }
193+}
194+
195+void GSettingsQml::setLifecycleExemptAppids(const QStringList &appIds)
196+{
197+ if (m_schema->id() == "com.canonical.qtmir") {
198+ GSettingsControllerQml::instance()->setLifecycleExemptAppids(appIds);
199+ }
200+}
tests/mocks/GSettings.1.0/fake_gsettings.h+10
@@ -19,6 +19,7 @@
19
19
20#include <QList>
20#include <QList>
21#include <QObject>
21#include <QObject>
22+#include <QStringList>
22
23
23class GSettingsSchemaQml: public QObject
24class GSettingsSchemaQml: public QObject
24{
25{
@@ -48,6 +49,7 @@ class GSettingsQml: public QObject
48 Q_PROPERTY(QString pictureUri READ pictureUri WRITE setPictureUri NOTIFY pictureUriChanged)
49 Q_PROPERTY(QString pictureUri READ pictureUri WRITE setPictureUri NOTIFY pictureUriChanged)
49 Q_PROPERTY(QString usageMode READ usageMode WRITE setUsageMode NOTIFY usageModeChanged)
50 Q_PROPERTY(QString usageMode READ usageMode WRITE setUsageMode NOTIFY usageModeChanged)
50 Q_PROPERTY(qint64 lockedOutTime READ lockedOutTime WRITE setLockedOutTime NOTIFY lockedOutTimeChanged)
51 Q_PROPERTY(qint64 lockedOutTime READ lockedOutTime WRITE setLockedOutTime NOTIFY lockedOutTimeChanged)
52+ Q_PROPERTY(QStringList lifecycleExemptAppids READ lifecycleExemptAppids WRITE setLifecycleExemptAppids NOTIFY lifecycleExemptAppidsChanged)
51
53
52public:
54public:
53 GSettingsQml(QObject *parent = nullptr);
55 GSettingsQml(QObject *parent = nullptr);
@@ -56,16 +58,19 @@ public:
56 QString pictureUri() const;
58 QString pictureUri() const;
57 QString usageMode() const;
59 QString usageMode() const;
58 qint64 lockedOutTime() const;
60 qint64 lockedOutTime() const;
61+ QStringList lifecycleExemptAppids() const;
59
62
60 void setPictureUri(const QString &str);
63 void setPictureUri(const QString &str);
61 void setUsageMode(const QString &usageMode);
64 void setUsageMode(const QString &usageMode);
62 void setLockedOutTime(qint64 timestamp);
65 void setLockedOutTime(qint64 timestamp);
66+ void setLifecycleExemptAppids(const QStringList &appIds);
63
67
64Q_SIGNALS:
68Q_SIGNALS:
65 void schemaChanged();
69 void schemaChanged();
66 void pictureUriChanged(const QString&);
70 void pictureUriChanged(const QString&);
67 void usageModeChanged(const QString&);
71 void usageModeChanged(const QString&);
68 void lockedOutTimeChanged(qint64);
72 void lockedOutTimeChanged(qint64);
73+ void lifecycleExemptAppidsChanged(const QStringList &);
69
74
70private:
75private:
71 GSettingsSchemaQml* m_schema;
76 GSettingsSchemaQml* m_schema;
@@ -90,10 +95,14 @@ public:
90 qint64 lockedOutTime() const;
95 qint64 lockedOutTime() const;
91 Q_INVOKABLE void setLockedOutTime(qint64 timestamp);
96 Q_INVOKABLE void setLockedOutTime(qint64 timestamp);
92
97
98+ QStringList lifecycleExemptAppids() const;
99+ Q_INVOKABLE void setLifecycleExemptAppids(const QStringList &appIds);
100+
93Q_SIGNALS:
101Q_SIGNALS:
94 void pictureUriChanged(const QString&);
102 void pictureUriChanged(const QString&);
95 void usageModeChanged(const QString&);
103 void usageModeChanged(const QString&);
96 void lockedOutTimeChanged(qint64 timestamp);
104 void lockedOutTimeChanged(qint64 timestamp);
105+ void lifecycleExemptAppidsChanged(const QStringList&);
97
106
98private:
107private:
99 GSettingsControllerQml();
108 GSettingsControllerQml();
@@ -101,6 +110,7 @@ private:
101 QString m_pictureUri;
110 QString m_pictureUri;
102 QString m_usageMode;
111 QString m_usageMode;
103 qint64 m_lockedOutTime;
112 qint64 m_lockedOutTime;
113+ QStringList m_lifecycleExemptAppids;
104
114
105 static GSettingsControllerQml* s_controllerInstance;
115 static GSettingsControllerQml* s_controllerInstance;
106 QList<GSettingsQml *> m_registeredGSettings;
116 QList<GSettingsQml *> m_registeredGSettings;
tests/mocks/Unity/Application/ApplicationInfo.cpp+12
@@ -41,6 +41,7 @@ ApplicationInfo::ApplicationInfo(const QString &appId, QObject *parent)
41 Qt::InvertedLandscapeOrientation)
41 Qt::InvertedLandscapeOrientation)
42 , m_rotatesWindowContents(false)
42 , m_rotatesWindowContents(false)
43 , m_requestedState(RequestedRunning)
43 , m_requestedState(RequestedRunning)
44+ , m_isTouchApp(true)
44 , m_manualSurfaceCreation(false)
45 , m_manualSurfaceCreation(false)
45{
46{
46}
47}
@@ -58,6 +59,7 @@ ApplicationInfo::ApplicationInfo(QObject *parent)
58 Qt::InvertedLandscapeOrientation)
59 Qt::InvertedLandscapeOrientation)
59 , m_rotatesWindowContents(false)
60 , m_rotatesWindowContents(false)
60 , m_requestedState(RequestedRunning)
61 , m_requestedState(RequestedRunning)
62+ , m_isTouchApp(true)
61 , m_manualSurfaceCreation(false)
63 , m_manualSurfaceCreation(false)
62{
64{
63}
65}
@@ -245,6 +247,16 @@ void ApplicationInfo::setRequestedState(RequestedState value)
245 }
247 }
246}
248}
247
249
250+bool ApplicationInfo::isTouchApp() const
251+{
252+ return m_isTouchApp;
253+}
254+
255+void ApplicationInfo::setIsTouchApp(bool isTouchApp)
256+{
257+ m_isTouchApp = isTouchApp;
258+}
259+
248void ApplicationInfo::onSessionSurfaceChanged(MirSurface* surface)
260void ApplicationInfo::onSessionSurfaceChanged(MirSurface* surface)
249{
261{
250 if (surface != nullptr && m_state == Starting) {
262 if (surface != nullptr && m_state == Starting) {
tests/mocks/Unity/Application/ApplicationInfo.h+4
@@ -89,6 +89,9 @@ public:
89 bool manualSurfaceCreation() const { return m_manualSurfaceCreation; }
89 bool manualSurfaceCreation() const { return m_manualSurfaceCreation; }
90 void setManualSurfaceCreation(bool value);
90 void setManualSurfaceCreation(bool value);
91
91
92+ bool isTouchApp() const override;
93+ void setIsTouchApp(bool isTouchApp); // only in mock
94+
92public:
95public:
93 void setSession(Session* session);
96 void setSession(Session* session);
94 Session* session() const { return m_session; }
97 Session* session() const { return m_session; }
@@ -121,6 +124,7 @@ private:
121 Qt::ScreenOrientations m_supportedOrientations;
124 Qt::ScreenOrientations m_supportedOrientations;
122 bool m_rotatesWindowContents;
125 bool m_rotatesWindowContents;
123 RequestedState m_requestedState;
126 RequestedState m_requestedState;
127+ bool m_isTouchApp;
124
128
125 bool m_manualSurfaceCreation;
129 bool m_manualSurfaceCreation;
126};
130};
tests/mocks/Unity/Application/ApplicationManager.cpp+9
@@ -105,6 +105,8 @@ QVariant ApplicationManager::data(const QModelIndex& index, int role) const {
105 return app->state();
105 return app->state();
106 case RoleFocused:
106 case RoleFocused:
107 return app->focused();
107 return app->focused();
108+ case RoleIsTouchApp:
109+ return app->isTouchApp();
108 case RoleSession:
110 case RoleSession:
109 return QVariant::fromValue(app->session());
111 return QVariant::fromValue(app->session());
110 case RoleFullscreen:
112 case RoleFullscreen:
@@ -458,6 +460,13 @@ void ApplicationManager::buildListOfAvailableApplications()
458 application->setName("YouTube");
460 application->setName("YouTube");
459 application->setIconId("youtube");
461 application->setIconId("youtube");
460 m_availableApplications.append(application);
462 m_availableApplications.append(application);
463+
464+ application = new ApplicationInfo(this);
465+ application->setAppId("libreoffice");
466+ application->setName("LibreOffice");
467+ application->setIconId("libreoffice");
468+ application->setIsTouchApp(false);
469+ m_availableApplications.append(application);
461}
470}
462
471
463
472
tests/mocks/Unity/Application/ApplicationManager.h+1−1
@@ -43,7 +43,7 @@ class ApplicationManager : public ApplicationManagerInterface {
43 static ApplicationManager *singleton();
43 static ApplicationManager *singleton();
44
44
45 enum MoreRoles {
45 enum MoreRoles {
46− RoleSession = RoleFocused+1,
46+ RoleSession = RoleIsTouchApp+1,
47 RoleFullscreen,
47 RoleFullscreen,
48 };
48 };
49 enum Flag {
49 enum Flag {
tests/mocks/Unity/Launcher/MockQuickListModel.cpp+1−1
@@ -32,7 +32,7 @@ QVariant MockQuickListModel::data(const QModelIndex &index, int role) const
32 switch (role)
32 switch (role)
33 {
33 {
34 case RoleLabel:
34 case RoleLabel:
35− return QLatin1String("test menu entry ") + QString::number(index.row());
35+ return QString(QLatin1String("test menu entry ") + QString::number(index.row()));
36 case RoleIcon:
36 case RoleIcon:
37 return QLatin1String("copy.png");
37 return QLatin1String("copy.png");
38 case RoleClickable:
38 case RoleClickable:
tests/mocks/Unity/fake_resultsmodel.cpp+1−1
@@ -78,7 +78,7 @@ ResultsModel::data(const QModelIndex& index, int role) const
78 case RoleTitle:
78 case RoleTitle:
79 return QString("Title.%1.%2").arg(m_categoryId).arg(index.row());
79 return QString("Title.%1.%2").arg(m_categoryId).arg(index.row());
80 case RoleArt:
80 case RoleArt:
81− return qmlDirectory() + "/graphics/applicationIcons/dash.png";
81+ return QString(qmlDirectory() + "/graphics/applicationIcons/dash.png");
82 case RoleSubtitle:
82 case RoleSubtitle:
83 return QString("Subtitle.%1.%2").arg(m_categoryId).arg(index.row());
83 return QString("Subtitle.%1.%2").arg(m_categoryId).arg(index.row());
84 case RoleMascot:
84 case RoleMascot:
tests/mocks/Unity/fake_scopesoverview.cpp+1−1
@@ -308,7 +308,7 @@ QVariant ScopesOverviewResultsModel::data(const QModelIndex& index, int role) co
308 case RoleSubtitle:
308 case RoleSubtitle:
309 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();
309 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();
310 case RoleArt:
310 case RoleArt:
311− return qmlDirectory() + "/graphics/applicationIcons/dash.png";
311+ return QString(qmlDirectory() + "/graphics/applicationIcons/dash.png");
312 case RoleMascot:
312 case RoleMascot:
313 case RoleEmblem:
313 case RoleEmblem:
314 case RoleSummary:
314 case RoleSummary:
tests/mocks/Utils/CMakeLists.txt−2
@@ -13,8 +13,6 @@ set(QMLPLUGIN_SRC
13 ${CMAKE_SOURCE_DIR}/plugins/Utils/activefocuslogger.cpp
13 ${CMAKE_SOURCE_DIR}/plugins/Utils/activefocuslogger.cpp
14 ${CMAKE_SOURCE_DIR}/plugins/Utils/qlimitproxymodelqml.cpp
14 ${CMAKE_SOURCE_DIR}/plugins/Utils/qlimitproxymodelqml.cpp
15 ${CMAKE_SOURCE_DIR}/plugins/Utils/unitysortfilterproxymodelqml.cpp
15 ${CMAKE_SOURCE_DIR}/plugins/Utils/unitysortfilterproxymodelqml.cpp
16− ${CMAKE_SOURCE_DIR}/plugins/Utils/relativetimeformatter.cpp
17− ${CMAKE_SOURCE_DIR}/plugins/Utils/timeformatter.cpp
18 ${CMAKE_SOURCE_DIR}/plugins/Utils/unitymenumodelpaths.cpp
16 ${CMAKE_SOURCE_DIR}/plugins/Utils/unitymenumodelpaths.cpp
19 ${CMAKE_SOURCE_DIR}/plugins/Utils/windowkeysfilter.cpp
17 ${CMAKE_SOURCE_DIR}/plugins/Utils/windowkeysfilter.cpp
20 ${CMAKE_SOURCE_DIR}/plugins/Utils/windowscreenshotprovider.cpp
18 ${CMAKE_SOURCE_DIR}/plugins/Utils/windowscreenshotprovider.cpp
tests/mocks/Utils/Utils.qmltypes+31−28
@@ -4,9 +4,18 @@ import QtQuick.tooling 1.1
4// It is used for QML tooling purposes only.
4// It is used for QML tooling purposes only.
5//
5//
6// This file was auto-generated by:
6// This file was auto-generated by:
7−// 'qmlplugindump -notrelocatable Utils 0.1 plugins'
7+// 'qmlplugindump -notrelocatable Utils 0.1 tests/mocks'
8
8
9Module {
9Module {
10+ Component {
11+ name: "Constants"
12+ prototype: "QObject"
13+ exports: ["Utils/Constants 0.1"]
14+ isCreatable: false
15+ isSingleton: true
16+ exportMetaObjectRevisions: [0]
17+ Property { name: "indicatorValueTimeout"; type: "int"; isReadonly: true }
18+ }
10 Component {
19 Component {
11 name: "EasingCurve"
20 name: "EasingCurve"
12 prototype: "QObject"
21 prototype: "QObject"
@@ -17,6 +26,22 @@ Module {
17 Property { name: "progress"; type: "double" }
26 Property { name: "progress"; type: "double" }
18 Property { name: "value"; type: "double"; isReadonly: true }
27 Property { name: "value"; type: "double"; isReadonly: true }
19 }
28 }
29+ Component {
30+ name: "InputWatcher"
31+ prototype: "QObject"
32+ exports: ["Utils/InputWatcher 0.1"]
33+ exportMetaObjectRevisions: [0]
34+ Property { name: "target"; type: "QObject"; isPointer: true }
35+ Property { name: "targetPressed"; type: "bool"; isReadonly: true }
36+ Signal {
37+ name: "targetChanged"
38+ Parameter { name: "value"; type: "QObject"; isPointer: true }
39+ }
40+ Signal {
41+ name: "targetPressedChanged"
42+ Parameter { name: "value"; type: "bool" }
43+ }
44+ }
20 Component {
45 Component {
21 name: "QAbstractProxyModel"
46 name: "QAbstractProxyModel"
22 prototype: "QAbstractItemModel"
47 prototype: "QAbstractItemModel"
@@ -59,33 +84,6 @@ Module {
59 Method { name: "clear" }
84 Method { name: "clear" }
60 Method { name: "invalidate" }
85 Method { name: "invalidate" }
61 }
86 }
62− Component {
63− name: "RelativeTimeFormatter"
64− prototype: "TimeFormatter"
65− exports: ["Utils/RelativeTimeFormatter 0.1"]
66− exportMetaObjectRevisions: [0]
67− }
68− Component {
69− name: "TimeFormatter"
70− prototype: "QObject"
71− exports: ["Utils/GDateTimeFormatter 0.1", "Utils/TimeFormatter 0.1"]
72− exportMetaObjectRevisions: [0, 0]
73− Property { name: "format"; type: "string" }
74− Property { name: "timeString"; type: "string"; isReadonly: true }
75− Property { name: "time"; type: "qlonglong" }
76− Signal {
77− name: "formatChanged"
78− Parameter { name: "format"; type: "string" }
79− }
80− Signal {
81− name: "timeStringChanged"
82− Parameter { name: "timeString"; type: "string" }
83− }
84− Signal {
85− name: "timeChanged"
86− Parameter { name: "time"; type: "qlonglong" }
87− }
88− }
89 Component {
87 Component {
90 name: "UnityMenuModelPaths"
88 name: "UnityMenuModelPaths"
91 prototype: "QObject"
89 prototype: "QObject"
@@ -160,6 +158,11 @@ Module {
160 isCreatable: false
158 isCreatable: false
161 isSingleton: true
159 isSingleton: true
162 exportMetaObjectRevisions: [0]
160 exportMetaObjectRevisions: [0]
161+ Property { name: "geometry"; type: "QVariantMap" }
162+ Signal {
163+ name: "geometryChanged"
164+ Parameter { name: "geometry"; type: "QVariantMap" }
165+ }
163 Method {
166 Method {
164 name: "saveGeometry"
167 name: "saveGeometry"
165 Parameter { name: "windowId"; type: "string" }
168 Parameter { name: "windowId"; type: "string" }
tests/mocks/Utils/plugin.cpp−13
@@ -23,14 +23,6 @@
23
23
24// local
24// local
25#include "plugin.h"
25#include "plugin.h"
26−#include "inputwatcher.h"
27−#include "qlimitproxymodelqml.h"
28−#include "unitysortfilterproxymodelqml.h"
29−#include "relativetimeformatter.h"
30−#include "timeformatter.h"
31−#include "unitymenumodelpaths.h"
32−#include "windowkeysfilter.h"
33−#include "easingcurve.h"
34#include "windowstatestorage.h"
26#include "windowstatestorage.h"
35#include "constants.h"
27#include "constants.h"
36
28
@@ -39,8 +31,6 @@
39#include <inputwatcher.h>
31#include <inputwatcher.h>
40#include <qlimitproxymodelqml.h>
32#include <qlimitproxymodelqml.h>
41#include <unitysortfilterproxymodelqml.h>
33#include <unitysortfilterproxymodelqml.h>
42−#include <relativetimeformatter.h>
43−#include <timeformatter.h>
44#include <unitymenumodelpaths.h>
34#include <unitymenumodelpaths.h>
45#include <windowkeysfilter.h>
35#include <windowkeysfilter.h>
46#include <windowscreenshotprovider.h>
36#include <windowscreenshotprovider.h>
@@ -67,11 +57,8 @@ void FakeUtilsPlugin::registerTypes(const char *uri)
67 qmlRegisterType<QLimitProxyModelQML>(uri, 0, 1, "LimitProxyModel");
57 qmlRegisterType<QLimitProxyModelQML>(uri, 0, 1, "LimitProxyModel");
68 qmlRegisterType<UnitySortFilterProxyModelQML>(uri, 0, 1, "UnitySortFilterProxyModel");
58 qmlRegisterType<UnitySortFilterProxyModelQML>(uri, 0, 1, "UnitySortFilterProxyModel");
69 qmlRegisterType<UnityMenuModelPaths>(uri, 0, 1, "UnityMenuModelPaths");
59 qmlRegisterType<UnityMenuModelPaths>(uri, 0, 1, "UnityMenuModelPaths");
70− qmlRegisterType<TimeFormatter>(uri, 0, 1, "TimeFormatter");
71 qmlRegisterType<WindowKeysFilter>(uri, 0, 1, "WindowKeysFilter");
60 qmlRegisterType<WindowKeysFilter>(uri, 0, 1, "WindowKeysFilter");
72− qmlRegisterType<GDateTimeFormatter>(uri, 0, 1, "GDateTimeFormatter");
73 qmlRegisterType<EasingCurve>(uri, 0, 1, "EasingCurve");
61 qmlRegisterType<EasingCurve>(uri, 0, 1, "EasingCurve");
74− qmlRegisterType<RelativeTimeFormatter>(uri, 0, 1, "RelativeTimeFormatter");
75 qmlRegisterSingletonType<WindowStateStorage>(uri, 0, 1, "WindowStateStorage", createWindowStateStorage);
62 qmlRegisterSingletonType<WindowStateStorage>(uri, 0, 1, "WindowStateStorage", createWindowStateStorage);
76 qmlRegisterType<InputWatcher>(uri, 0, 1, "InputWatcher");
63 qmlRegisterType<InputWatcher>(uri, 0, 1, "InputWatcher");
77 qmlRegisterSingletonType<Constants>(uri, 0, 1, "Constants", createConstants);
64 qmlRegisterSingletonType<Constants>(uri, 0, 1, "Constants", createConstants);
tests/mocks/Utils/windowstatestorage.cpp+17
@@ -44,3 +44,20 @@ QRect WindowStateStorage::getGeometry(const QString &windowId, const QRect &defa
44 if (!m_geometry.contains(windowId)) return defaultValue;
44 if (!m_geometry.contains(windowId)) return defaultValue;
45 return m_geometry.value(windowId).toRect();
45 return m_geometry.value(windowId).toRect();
46}
46}
47+
48+void WindowStateStorage::clear()
49+{
50+ m_state.clear();
51+ m_geometry.clear();
52+}
53+
54+void WindowStateStorage::saveState(const QString &windowId, WindowState state)
55+{
56+ m_state[windowId] = state;
57+}
58+
59+WindowStateStorage::WindowState WindowStateStorage::getState(const QString &windowId, WindowStateStorage::WindowState defaultValue)
60+{
61+ if (!m_state.contains(windowId)) return defaultValue;
62+ return m_state.value(windowId);
63+}
tests/mocks/Utils/windowstatestorage.h+12
@@ -22,12 +22,23 @@ class WindowStateStorage: public QObject
22{
22{
23 Q_OBJECT
23 Q_OBJECT
24 Q_PROPERTY(QVariantMap geometry READ geometry WRITE setGeometry NOTIFY geometryChanged)
24 Q_PROPERTY(QVariantMap geometry READ geometry WRITE setGeometry NOTIFY geometryChanged)
25+ Q_ENUMS(WindowState)
25public:
26public:
27+ enum WindowState {
28+ WindowStateNormal,
29+ WindowStateMaximized
30+ };
26 WindowStateStorage(QObject *parent = 0);
31 WindowStateStorage(QObject *parent = 0);
27
32
33+ Q_INVOKABLE void saveState(const QString &windowId, WindowState state);
34+ Q_INVOKABLE WindowState getState(const QString &windowId, WindowState defaultValue);
35+
28 Q_INVOKABLE void saveGeometry(const QString &windowId, const QRect &rect);
36 Q_INVOKABLE void saveGeometry(const QString &windowId, const QRect &rect);
29 Q_INVOKABLE QRect getGeometry(const QString &windowId, const QRect &defaultValue);
37 Q_INVOKABLE QRect getGeometry(const QString &windowId, const QRect &defaultValue);
30
38
39+ // Only in the mock, to easily restore a fresh state
40+ Q_INVOKABLE void clear();
41+
31Q_SIGNALS:
42Q_SIGNALS:
32 void geometryChanged(const QVariantMap& geometry);
43 void geometryChanged(const QVariantMap& geometry);
33
44
@@ -35,5 +46,6 @@ private:
35 void setGeometry(const QVariantMap& geometry);
46 void setGeometry(const QVariantMap& geometry);
36 QVariantMap geometry() const;
47 QVariantMap geometry() const;
37
48
49+ QHash<QString, WindowState> m_state;
38 QVariantMap m_geometry;
50 QVariantMap m_geometry;
39};
51};
tests/plugins/ScreenGrabber/ScreenGrabberTest.cpp+11
@@ -55,6 +55,17 @@ private Q_SLOTS:
55 QVERIFY(!args.first().toString().isEmpty());
55 QVERIFY(!args.first().toString().isEmpty());
56 }
56 }
57
57
58+ void testRotatedScreenshot()
59+ {
60+ QSignalSpy grabberSpy(m_grabber, &ScreenGrabber::screenshotSaved);
61+ m_grabber->captureAndSave(90); // rotate by 90°
62+ const QVariantList args = grabberSpy.takeFirst();
63+ const QString filename = args.first().toString();
64+ QVERIFY(!filename.isEmpty());
65+ QImage img(filename);
66+ QVERIFY(img.height() > img.width()); // verify that the image got rotated by 90° (height > width)
67+ }
68+
58private:
69private:
59 QQuickView *m_view;
70 QQuickView *m_view;
60 ScreenGrabber *m_grabber = nullptr;
71 ScreenGrabber *m_grabber = nullptr;
tests/plugins/ScreenGrabber/grabber.qml+1−1
@@ -20,7 +20,7 @@ import ScreenGrabber 0.1
20Rectangle {
20Rectangle {
21 property var grabber: screenGrabber
21 property var grabber: screenGrabber
22
22
23− width: 100
23+ width: 101 // width intentionally bigger than height to test rotation
24 height: 100
24 height: 100
25 color: "green"
25 color: "green"
26
26
tests/plugins/Unity/Indicators/UnityMenuModelStackTest.cpp+2−9
@@ -43,6 +43,8 @@ private Q_SLOTS:
43 {
43 {
44 delete m_model;
44 delete m_model;
45 m_model = nullptr;
45 m_model = nullptr;
46+ // send deleteLaters to avoid leaks.
47+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
46 }
48 }
47
49
48 void testHeadOnSetHead()
50 void testHeadOnSetHead()
@@ -146,19 +148,10 @@ private Q_SLOTS:
146
148
147 m_model->removeRow(removeIndex);
149 m_model->removeRow(removeIndex);
148
150
149− waitFor([&stack, resultCount]() { return stack.count() == resultCount; }, 1000);
150 QCOMPARE(stack.count(), resultCount);
151 QCOMPARE(stack.count(), resultCount);
151 }
152 }
152
153
153private:
154private:
154− bool waitFor(std::function<bool()> functor, int ms) {
155−
156− QElapsedTimer timer;
157− timer.start();
158− while(!functor() && timer.elapsed() < ms) { QTest::qWait(10); }
159− return functor();
160− }
161−
162 QVariant recuseAddMenu(int subMenuCount, int depth_remaining)
155 QVariant recuseAddMenu(int subMenuCount, int depth_remaining)
163 {
156 {
164 QVariantList rows;
157 QVariantList rows;
tests/plugins/Unity/Launcher/launchermodeltest.cpp+1
@@ -57,6 +57,7 @@ public:
57 QColor splashColorFooter() const override { return QColor(0,0,0,0); }
57 QColor splashColorFooter() const override { return QColor(0,0,0,0); }
58 Qt::ScreenOrientations supportedOrientations() const override { return Qt::PortraitOrientation; }
58 Qt::ScreenOrientations supportedOrientations() const override { return Qt::PortraitOrientation; }
59 bool rotatesWindowContents() const override { return false; }
59 bool rotatesWindowContents() const override { return false; }
60+ bool isTouchApp() const override { return true; }
60
61
61 // Methods used for mocking (not in the interface)
62 // Methods used for mocking (not in the interface)
62 void setFocused(bool focused) { m_focused = focused; Q_EMIT focusedChanged(focused); }
63 void setFocused(bool focused) { m_focused = focused; Q_EMIT focusedChanged(focused); }
tests/plugins/Utils/CMakeLists.txt−1
@@ -7,7 +7,6 @@ include_directories(
7foreach(util_test
7foreach(util_test
8 QLimitProxyModel
8 QLimitProxyModel
9 UnitySortFilterProxyModel
9 UnitySortFilterProxyModel
10− TimeFormatter
11 HomeKeyWatcher
10 HomeKeyWatcher
12)
11)
13 add_executable(${util_test}TestExec ${util_test}Test.cpp ModelTest.cpp)
12 add_executable(${util_test}TestExec ${util_test}Test.cpp ModelTest.cpp)
tests/plugins/Utils/TimeFormatterTest.cppdeleted−155
@@ -1,155 +0,0 @@
1−/*
2− * Copyright 2013 Canonical Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU Lesser General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU Lesser General Public License for more details.
12− *
13− * You should have received a copy of the GNU Lesser General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− *
16− * Author: Lars Uebernickel <lars.uebernickel@canonical.com>
17− */
18−
19−#include "timeformatter.h"
20−#include "relativetimeformatter.h"
21−
22−#include <locale.h>
23−
24−#include <QtTest>
25−#include <QDebug>
26−
27−class TimeFormatterTest : public QObject
28−{
29− Q_OBJECT
30−private:
31− void addTestData(QList<int> daysToAdd = QList<int>()) {
32− QTest::addColumn<QDateTime>("time");
33−
34− Q_FOREACH(int dayToAdd, daysToAdd) {
35− QDateTime time = QDateTime::currentDateTime().addDays(dayToAdd);
36− QDateTime am(time); am.setTime(QTime(1, 1, 1));
37− QDateTime midday(time); midday.setTime(QTime(12, 0, 0));
38− QDateTime pm(time); pm.setTime(QTime(17, 59, 59));
39−
40− QTest::newRow(QString("%1day-am").arg(dayToAdd).toLatin1()) << am;
41− QTest::newRow(QString("%1day-midday").arg(dayToAdd).toLatin1()) << midday;
42− QTest::newRow(QString("%1day-pm").arg(dayToAdd).toLatin1()) << pm;
43− }
44−
45− }
46−
47−private Q_SLOTS:
48− void testTimeFormatter_Format_data() { addTestData(QList<int>() << 0); }
49− void testTimeFormatter_Format()
50− {
51− QFETCH(QDateTime, time);
52− const QString format = "hh:mm dd.MM.yy";
53−
54− TimeFormatter formatter;
55− formatter.setTime(time.toMSecsSinceEpoch() * 1000);
56− formatter.setFormat(format);
57−
58− QCOMPARE(formatter.timeString(), time.toString(format));
59− }
60−
61− void tesGDatetTimeFormatter_Format_data() { addTestData(QList<int>() << 0); }
62− void tesGDatetTimeFormatter_Format()
63− {
64− QFETCH(QDateTime, time);
65− const QString format = "%d-%m-%Y %I:%M%p";
66−
67− GDateTimeFormatter formatter;
68− formatter.setTime(time.toMSecsSinceEpoch() / 1000); // strftime in seconds since epoc
69− formatter.setFormat(format);
70−
71− QCOMPARE(formatter.timeString(), time.toString("dd-MM-yyyy hh:mmAP"));
72− }
73−
74− void tesRelativeTimeFormatter_FarBack_data() { addTestData(QList<int>() << -200 << -20 << -7); }
75− void tesRelativeTimeFormatter_FarBack()
76− {
77− QFETCH(QDateTime, time);
78−
79− RelativeTimeFormatter formatter;
80− formatter.setTime(time.toMSecsSinceEpoch() / 1000); // strftime in seconds since epoc
81−
82− QCOMPARE(formatter.timeString(), time.toString("ddd dd MMM\u2003HH:mm"));
83− }
84−
85− void tesRelativeTimeFormatter_WeekBack_data() { addTestData(QList<int>() << -6 << -2); }
86− void tesRelativeTimeFormatter_WeekBack()
87− {
88− QFETCH(QDateTime, time);
89−
90− RelativeTimeFormatter formatter;
91− formatter.setTime(time.toMSecsSinceEpoch() / 1000); // strftime in seconds since epoc
92−
93− QCOMPARE(formatter.timeString(), time.toString("ddd\u2003HH:mm"));
94− }
95−
96− void tesRelativeTimeFormatter_Yesterday_data() { addTestData(QList<int>() << -1); }
97− void tesRelativeTimeFormatter_Yesterday()
98− {
99− QFETCH(QDateTime, time);
100−
101− RelativeTimeFormatter formatter;
102− formatter.setTime(time.toMSecsSinceEpoch() / 1000); // strftime in seconds since epoc
103−
104− QCOMPARE(formatter.timeString(), QString("Yesterday\u2003%1").arg(time.toString("HH:mm")));
105− }
106−
107− void tesRelativeTimeFormatter_Today_data() { addTestData(QList<int>() << 0); }
108− void tesRelativeTimeFormatter_Today()
109− {
110− QFETCH(QDateTime, time);
111−
112− RelativeTimeFormatter formatter;
113− formatter.setTime(time.toMSecsSinceEpoch() / 1000); // strftime in seconds since epoc
114−
115− QCOMPARE(formatter.timeString(), time.toString("HH:mm"));
116− }
117−
118− void tesRelativeTimeFormatter_Tomorrow_data() { addTestData(QList<int>() << 1); }
119− void tesRelativeTimeFormatter_Tomorrow()
120− {
121− QFETCH(QDateTime, time);
122−
123− RelativeTimeFormatter formatter;
124− formatter.setTime(time.toMSecsSinceEpoch() / 1000); // strftime in seconds since epoc
125−
126− QCOMPARE(formatter.timeString(), QString("Tomorrow\u2003%1").arg(time.toString("HH:mm")));
127− }
128−
129−
130− void tesRelativeTimeFormatter_WeekForward_data() { addTestData(QList<int>() << 2 << 6); }
131− void tesRelativeTimeFormatter_WeekForward()
132− {
133− QFETCH(QDateTime, time);
134−
135− RelativeTimeFormatter formatter;
136− formatter.setTime(time.toMSecsSinceEpoch() / 1000); // strftime in seconds since epoc
137−
138− QCOMPARE(formatter.timeString(), time.toString("ddd\u2003HH:mm"));
139− }
140−
141− void tesRelativeTimeFormatter_FarForward_data() { addTestData(QList<int>() << 7 << 20 << 200); }
142− void tesRelativeTimeFormatter_FarForward()
143− {
144− QFETCH(QDateTime, time);
145−
146− RelativeTimeFormatter formatter;
147− formatter.setTime(time.toMSecsSinceEpoch() / 1000); // strftime in seconds since epoc
148−
149− QCOMPARE(formatter.timeString(), time.toString("ddd dd MMM\u2003HH:mm"));
150− }
151−};
152−
153−QTEST_GUILESS_MAIN(TimeFormatterTest)
154−
155−#include "TimeFormatterTest.moc"
tests/plugins/Wizard/tst_pagelist.cpp+5−5
@@ -88,13 +88,13 @@ void PageListTest::testIterate()
88
88
89 PageList pageList;
89 PageList pageList;
90 QCOMPARE(pageList.index(), -1);
90 QCOMPARE(pageList.index(), -1);
91− QCOMPARE(pageList.next(), root.path() + "/a/" + PAGES_PATH + "/1.qml");
91+ QCOMPARE(pageList.next(), QString(root.path() + "/a/" + PAGES_PATH + "/1.qml"));
92 QCOMPARE(pageList.prev(), QString());
92 QCOMPARE(pageList.prev(), QString());
93− QCOMPARE(pageList.next(), root.path() + "/a/" + PAGES_PATH + "/2.qml");
93+ QCOMPARE(pageList.next(), QString(root.path() + "/a/" + PAGES_PATH + "/2.qml"));
94− QCOMPARE(pageList.prev(), root.path() + "/a/" + PAGES_PATH + "/1.qml");
94+ QCOMPARE(pageList.prev(), QString(root.path() + "/a/" + PAGES_PATH + "/1.qml"));
95 QCOMPARE(pageList.index(), 0);
95 QCOMPARE(pageList.index(), 0);
96− QCOMPARE(pageList.next(), root.path() + "/a/" + PAGES_PATH + "/2.qml");
96+ QCOMPARE(pageList.next(), QString(root.path() + "/a/" + PAGES_PATH + "/2.qml"));
97− QCOMPARE(pageList.next(), root.path() + "/a/" + PAGES_PATH + "/3.qml");
97+ QCOMPARE(pageList.next(), QString(root.path() + "/a/" + PAGES_PATH + "/3.qml"));
98 QCOMPARE(pageList.index(), 2);
98 QCOMPARE(pageList.index(), 2);
99 QCOMPARE(pageList.next(), QString());
99 QCOMPARE(pageList.next(), QString());
100 QCOMPARE(pageList.index(), 2);
100 QCOMPARE(pageList.index(), 2);
tests/qmltests/CMakeLists.txt+3−1
@@ -2,6 +2,7 @@
2add_subdirectory(Components)
2add_subdirectory(Components)
3
3
4add_unity8_qmltest(. OrientedShell LIGHTDM)
4add_unity8_qmltest(. OrientedShell LIGHTDM)
5+add_unity8_qmltest(. DisabledScreenNotice)
5add_unity8_qmltest(. Shell LIGHTDM)
6add_unity8_qmltest(. Shell LIGHTDM)
6add_unity8_qmltest(. ShellWithPin LIGHTDM)
7add_unity8_qmltest(. ShellWithPin LIGHTDM)
7add_unity8_qmltest(Components Background)
8add_unity8_qmltest(Components Background)
@@ -15,6 +16,7 @@ add_unity8_qmltest(Components Rating)
15add_unity8_qmltest(Components ResponsiveGridView)
16add_unity8_qmltest(Components ResponsiveGridView)
16add_unity8_qmltest(Components ResponsiveVerticalJournal)
17add_unity8_qmltest(Components ResponsiveVerticalJournal)
17add_unity8_qmltest(Components Showable)
18add_unity8_qmltest(Components Showable)
19+add_unity8_qmltest(Components WallpaperResolver)
18add_unity8_qmltest(Components ZoomableImage)
20add_unity8_qmltest(Components ZoomableImage)
19add_unity8_qmltest(Dash Dash)
21add_unity8_qmltest(Dash Dash)
20add_unity8_qmltest(Dash DashContent)
22add_unity8_qmltest(Dash DashContent)
@@ -78,7 +80,7 @@ add_unity8_qmltest(Stages SpreadDelegate)
78add_unity8_qmltest(Stages SurfaceContainer)
80add_unity8_qmltest(Stages SurfaceContainer)
79add_unity8_qmltest(Stages SessionContainer)
81add_unity8_qmltest(Stages SessionContainer)
80add_unity8_qmltest(Stages TabletStage)
82add_unity8_qmltest(Stages TabletStage)
81−add_unity8_qmltest(Stages WindowMoveResizeArea)
83+add_unity8_qmltest(Stages WindowResizeArea)
82add_unity8_qmltest(Stages Splash)
84add_unity8_qmltest(Stages Splash)
83add_unity8_qmltest(Tutorial Tutorial LIGHTDM)
85add_unity8_qmltest(Tutorial Tutorial LIGHTDM)
84add_unity8_qmltest(Wizard Wizard ENVIRONMENT "OXIDE_NO_SANDBOX=1")
86add_unity8_qmltest(Wizard Wizard ENVIRONMENT "OXIDE_NO_SANDBOX=1")
tests/qmltests/Components/tst_WallpaperResolver.qmlnew file+89
@@ -0,0 +1,89 @@
1+/*
2+ * Copyright (C) 2015 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.4
18+import QtTest 1.0
19+import Ubuntu.Components 1.3
20+import Unity.Test 0.1
21+import AccountsService 0.1
22+import GSettings 1.0
23+
24+import "../../../qml/Components"
25+
26+
27+Image {
28+ width: units.gu(70)
29+ height: units.gu(70)
30+
31+ source: wallpaperResolver.background
32+
33+ WallpaperResolver {
34+ id: wallpaperResolver
35+ width: units.gu(70)
36+ }
37+
38+ UnityTestCase {
39+ id: testCase
40+ name: "WallpaperResolver"
41+ when: windowShown
42+
43+ function test_background_data() {
44+ return [
45+ {tag: "color",
46+ accounts: Qt.resolvedUrl("data:image/svg+xml,<svg><rect width='100%' height='100%' fill='#dd4814'/></svg>"),
47+ gsettings: "",
48+ output: Qt.resolvedUrl("data:image/svg+xml,<svg><rect width='100%' height='100%' fill='#dd4814'/></svg>")},
49+
50+ {tag: "empty", accounts: "", gsettings: "", output: "defaultBackground"},
51+
52+ {tag: "as-specified",
53+ accounts: Qt.resolvedUrl("../../data/unity/backgrounds/blue.png"),
54+ gsettings: "",
55+ output: Qt.resolvedUrl("../../data/unity/backgrounds/blue.png")},
56+
57+ {tag: "gs-specified",
58+ accounts: "",
59+ gsettings: Qt.resolvedUrl("../../data/unity/backgrounds/red.png"),
60+ output: Qt.resolvedUrl("../../data/unity/backgrounds/red.png")},
61+
62+ {tag: "both-specified",
63+ accounts: Qt.resolvedUrl("../../data/unity/backgrounds/blue.png"),
64+ gsettings: Qt.resolvedUrl("../../data/unity/backgrounds/red.png"),
65+ output: Qt.resolvedUrl("../../data/unity/backgrounds/blue.png")},
66+
67+ {tag: "invalid-as",
68+ accounts: Qt.resolvedUrl("../../data/unity/backgrounds/nope.png"),
69+ gsettings: Qt.resolvedUrl("../../data/unity/backgrounds/red.png"),
70+ output: Qt.resolvedUrl("../../data/unity/backgrounds/red.png")},
71+
72+ {tag: "invalid-both",
73+ accounts: Qt.resolvedUrl("../../data/unity/backgrounds/nope.png"),
74+ gsettings: Qt.resolvedUrl("../../data/unity/backgrounds/stillnope.png"),
75+ output: "defaultBackground"},
76+ ]
77+ }
78+ function test_background(data) {
79+ AccountsService.backgroundFile = data.accounts;
80+ GSettingsController.setPictureUri(data.gsettings);
81+
82+ if (data.output === "defaultBackground") {
83+ tryCompare(wallpaperResolver, "background", wallpaperResolver.defaultBackground);
84+ } else {
85+ tryCompare(wallpaperResolver, "background", data.output);
86+ }
87+ }
88+ }
89+}
tests/qmltests/Panel/Indicators/tst_MenuItemFactory.qml+6−16
@@ -50,10 +50,6 @@ Item {
50 }
50 }
51 }
51 }
52
52
53− Utils.GDateTimeFormatter {
54− id: timeFormatter
55− }
56−
57 UT.UnityTestCase {
53 UT.UnityTestCase {
58 name: "MenuItemFactory"
54 name: "MenuItemFactory"
59 when: windowShown
55 when: windowShown
@@ -374,9 +370,9 @@ Item {
374 function test_create_alarmMenu_data() {
370 function test_create_alarmMenu_data() {
375 return [
371 return [
376 {label: "testLabel1", enabled: true, icon: "file:///testIcon1", color: Qt.rgba(0, 0, 0, 0),
372 {label: "testLabel1", enabled: true, icon: "file:///testIcon1", color: Qt.rgba(0, 0, 0, 0),
377− time: new Date(2014, 04, 14), timeFormat: "%a %d %b %l:%M %p"},
373+ time: new Date(2014, 04, 14)},
378 {label: "testLabel2", enabled: false, icon: "file:///testIcon2", color: Qt.rgba(1, 0, 0, 0),
374 {label: "testLabel2", enabled: false, icon: "file:///testIcon2", color: Qt.rgba(1, 0, 0, 0),
379− time: new Date(2015, 11, 31), timeFormat: "%A" },
375+ time: new Date(2015, 11, 31) },
380 ];
376 ];
381 }
377 }
382
378
@@ -386,11 +382,8 @@ Item {
386 menuData.sensitive = data.enabled;
382 menuData.sensitive = data.enabled;
387 menuData.icon = data.icon;
383 menuData.icon = data.icon;
388 menuData.ext = {
384 menuData.ext = {
389− 'xCanonicalTime': data.time.getTime() / 1000,
385+ 'xCanonicalTime': data.time.getTime() / 1000 // expected in seconds
390− 'xCanonicalTimeFormat': data.timeFormat
391 };
386 };
392− timeFormatter.format = data.timeFormat;
393− timeFormatter.time = data.time.getTime() / 1000;
394
387
395 loader.data = menuData;
388 loader.data = menuData;
396 loader.sourceComponent = factory.load(menuData);
389 loader.sourceComponent = factory.load(menuData);
@@ -399,7 +392,7 @@ Item {
399
392
400 compare(loader.item.text, data.label, "Label does not match data");
393 compare(loader.item.text, data.label, "Label does not match data");
401 compare(loader.item.iconSource, data.icon, "Icon does not match data");
394 compare(loader.item.iconSource, data.icon, "Icon does not match data");
402− compare(loader.item.time, timeFormatter.timeString, "Time does not match data");
395+ compare(loader.item.time, i18n.relativeDateTime(data.time), "Time does not match data");
403 compare(loader.item.enabled, data.enabled, "Enabled does not match data");
396 compare(loader.item.enabled, data.enabled, "Enabled does not match data");
404 }
397 }
405
398
@@ -419,11 +412,8 @@ Item {
419 menuData.icon = data.icon;
412 menuData.icon = data.icon;
420 menuData.ext = {
413 menuData.ext = {
421 'xCanonicalColor': data.colour,
414 'xCanonicalColor': data.colour,
422− 'xCanonicalTime': data.time.getTime() / 1000,
415+ 'xCanonicalTime': data.time.getTime() / 1000 // expected in seconds
423− 'xCanonicalTimeFormat': data.timeFormat
424 };
416 };
425− timeFormatter.format = data.timeFormat;
426− timeFormatter.time = data.time.getTime() / 1000;
427
417
428 loader.data = menuData;
418 loader.data = menuData;
429 loader.sourceComponent = factory.load(menuData);
419 loader.sourceComponent = factory.load(menuData);
@@ -432,7 +422,7 @@ Item {
432
422
433 compare(loader.item.text, data.label, "Label does not match data");
423 compare(loader.item.text, data.label, "Label does not match data");
434 compare(loader.item.iconSource, data.icon, "Icon does not match data");
424 compare(loader.item.iconSource, data.icon, "Icon does not match data");
435− compare(loader.item.time, timeFormatter.timeString, "Time does not match data");
425+ compare(loader.item.time, i18n.relativeDateTime(data.time), "Time does not match data");
436 compare(loader.item.eventColor, data.color, "Colour does not match data");
426 compare(loader.item.eventColor, data.color, "Colour does not match data");
437 compare(loader.item.enabled, data.enabled, "Enabled does not match data");
427 compare(loader.item.enabled, data.enabled, "Enabled does not match data");
438 }
428 }
tests/qmltests/Panel/Indicators/tst_MessageMenuItemFactory.qml+6−13
@@ -32,10 +32,6 @@ Item {
32 menuIndex: 0
32 menuIndex: 0
33 }
33 }
34
34
35− Utils.RelativeTimeFormatter {
36− id: timeFormatter
37− }
38−
39 UT.UnityTestCase {
35 UT.UnityTestCase {
40 name: "MessageMenuItemFactory"
36 name: "MessageMenuItemFactory"
41 when: windowShown
37 when: windowShown
@@ -82,17 +78,16 @@ Item {
82 menuData.label = data.title;
78 menuData.label = data.title;
83 menuData.sensitive = data.enabled;
79 menuData.sensitive = data.enabled;
84 menuData.ext = {
80 menuData.ext = {
85− 'xCanonicalTime': data.time.getTime()*1000,
81+ 'xCanonicalTime': data.time.getTime()*1000, // expected in microseconds
86 'xCanonicalText': data.body,
82 'xCanonicalText': data.body,
87 'icon': data.avatar,
83 'icon': data.avatar,
88 'xCanonicalAppIcon': data.icon,
84 'xCanonicalAppIcon': data.icon,
89 };
85 };
90 factory.menuData = menuData;
86 factory.menuData = menuData;
91− timeFormatter.time = data.time.getTime()/1000;
92
87
93 tryCompare(factory.item, "objectName", "simpleTextMessage");
88 tryCompare(factory.item, "objectName", "simpleTextMessage");
94 compare(factory.item.title, data.title, "Title does not match data");
89 compare(factory.item.title, data.title, "Title does not match data");
95− compare(factory.item.time, timeFormatter.timeString, "Time does not match data");
90+ compare(factory.item.time, i18n.relativeDateTime(data.time), "Time does not match data");
96 compare(factory.item.body, data.body, "Message does not match data");
91 compare(factory.item.body, data.body, "Message does not match data");
97 compare(factory.item.avatar, data.avatar, "Avatar does not match data");
92 compare(factory.item.avatar, data.avatar, "Avatar does not match data");
98 compare(factory.item.icon, data.icon, "App icon does not match data");
93 compare(factory.item.icon, data.icon, "App icon does not match data");
@@ -111,7 +106,7 @@ Item {
111 menuData.label = data.title;
106 menuData.label = data.title;
112 menuData.sensitive = data.enabled;
107 menuData.sensitive = data.enabled;
113 menuData.ext = {
108 menuData.ext = {
114− 'xCanonicalTime': data.time.getTime()*1000,
109+ 'xCanonicalTime': data.time.getTime()*1000, // expected in microseconds
115 'xCanonicalText': data.body,
110 'xCanonicalText': data.body,
116 'icon': data.avatar,
111 'icon': data.avatar,
117 'xCanonicalAppIcon': data.icon,
112 'xCanonicalAppIcon': data.icon,
@@ -123,11 +118,10 @@ Item {
123 ]
118 ]
124 };
119 };
125 factory.menuData = menuData;
120 factory.menuData = menuData;
126− timeFormatter.time = data.time.getTime()/1000;
127
121
128 tryCompare(factory.item, "objectName", "textMessage");
122 tryCompare(factory.item, "objectName", "textMessage");
129 compare(factory.item.title, data.title, "Title does not match data");
123 compare(factory.item.title, data.title, "Title does not match data");
130− compare(factory.item.time, timeFormatter.timeString, "Time does not match data");
124+ compare(factory.item.time, i18n.relativeDateTime(data.time), "Time does not match data");
131 compare(factory.item.body, data.body, "Message does not match data");
125 compare(factory.item.body, data.body, "Message does not match data");
132 compare(factory.item.avatar, data.avatar, "Avatar does not match data");
126 compare(factory.item.avatar, data.avatar, "Avatar does not match data");
133 compare(factory.item.icon, data.icon, "App icon does not match data");
127 compare(factory.item.icon, data.icon, "App icon does not match data");
@@ -147,7 +141,7 @@ Item {
147 menuData.label = data.title;
141 menuData.label = data.title;
148 menuData.sensitive = data.enabled;
142 menuData.sensitive = data.enabled;
149 menuData.ext = {
143 menuData.ext = {
150− 'xCanonicalTime': data.time.getTime()*1000,
144+ 'xCanonicalTime': data.time.getTime()*1000, // expected in microseconds
151 'xCanonicalText': data.body,
145 'xCanonicalText': data.body,
152 'icon': data.avatar,
146 'icon': data.avatar,
153 'xCanonicalAppIcon': data.icon,
147 'xCanonicalAppIcon': data.icon,
@@ -162,11 +156,10 @@ Item {
162 ]
156 ]
163 };
157 };
164 factory.menuData = menuData;
158 factory.menuData = menuData;
165− timeFormatter.time = data.time.getTime()/1000;
166
159
167 tryCompare(factory.item, "objectName", "snapDecision");
160 tryCompare(factory.item, "objectName", "snapDecision");
168 compare(factory.item.title, data.title, "Title does not match data");
161 compare(factory.item.title, data.title, "Title does not match data");
169− compare(factory.item.time, timeFormatter.timeString, "Time does not match data");
162+ compare(factory.item.time, i18n.relativeDateTime(data.time), "Time does not match data");
170 compare(factory.item.body, data.body, "Message does not match data");
163 compare(factory.item.body, data.body, "Message does not match data");
171 compare(factory.item.avatar, data.avatar, "Avatar does not match data");
164 compare(factory.item.avatar, data.avatar, "Avatar does not match data");
172 compare(factory.item.icon, data.icon, "App icon does not match data");
165 compare(factory.item.icon, data.icon, "App icon does not match data");
tests/qmltests/Stages/tst_PhoneStage.qml−2
@@ -34,8 +34,6 @@ Item {
34 maximizedAppTopMargin: units.gu(3) + units.dp(2)
34 maximizedAppTopMargin: units.gu(3) + units.dp(2)
35 interactive: true
35 interactive: true
36 shellOrientation: Qt.PortraitOrientation
36 shellOrientation: Qt.PortraitOrientation
37− shellPrimaryOrientation: Qt.PortraitOrientation
38− nativeOrientation: Qt.PortraitOrientation
39 }
37 }
40
38
41 Binding {
39 Binding {
tests/qmltests/Stages/tst_SpreadDelegate.qml+6−2
@@ -18,6 +18,7 @@ import QtQuick 2.0
18import QtTest 1.0
18import QtTest 1.0
19import Unity.Test 0.1 as UT
19import Unity.Test 0.1 as UT
20import ".."
20import ".."
21+import "../../../qml/Components"
21import "../../../qml/Stages"
22import "../../../qml/Stages"
22import Ubuntu.Components 0.1
23import Ubuntu.Components 0.1
23import Ubuntu.Components.ListItems 1.0 as ListItem
24import Ubuntu.Components.ListItems 1.0 as ListItem
@@ -73,8 +74,11 @@ Rectangle {
73 return Qt.LandscapeOrientation;
74 return Qt.LandscapeOrientation;
74 }
75 }
75 }
76 }
76− shellPrimaryOrientation: Qt.PortraitOrientation
77+
77− nativeOrientation: Qt.PortraitOrientation
78+ orientations: Orientations {
79+ // the default values will do
80+ }
81+
78 maximizedAppTopMargin: units.gu(3)
82 maximizedAppTopMargin: units.gu(3)
79 Component.onDestruction: {
83 Component.onDestruction: {
80 spreadDelegateLoader.itemDestroyed = true;
84 spreadDelegateLoader.itemDestroyed = true;
tests/qmltests/Stages/tst_TabletStage.qml+2−2
@@ -22,6 +22,7 @@ import Unity.Application 0.1
22import Unity.Test 0.1
22import Unity.Test 0.1
23
23
24import "../../../qml/Stages"
24import "../../../qml/Stages"
25+import "../../../qml/Components"
25
26
26Rectangle {
27Rectangle {
27 id: root
28 id: root
@@ -50,10 +51,9 @@ Rectangle {
50 maximizedAppTopMargin: units.gu(3) + units.dp(2)
51 maximizedAppTopMargin: units.gu(3) + units.dp(2)
51 interactive: true
52 interactive: true
52 shellOrientation: Qt.LandscapeOrientation
53 shellOrientation: Qt.LandscapeOrientation
53− shellPrimaryOrientation: Qt.LandscapeOrientation
54− nativeOrientation: Qt.LandscapeOrientation
55 nativeWidth: width
54 nativeWidth: width
56 nativeHeight: height
55 nativeHeight: height
56+ orientations: Orientations{} // Defaults are fine for testing
57 focus: true
57 focus: true
58 }
58 }
59 }
59 }
tests/qmltests/Stages/tst_WindowMoveResizeArea.qml → tests/qmltests/Stages/tst_WindowResizeArea.qmlrenamed+53−63
@@ -17,7 +17,7 @@
17import QtQuick 2.1
17import QtQuick 2.1
18import QtQuick.Layouts 1.1
18import QtQuick.Layouts 1.1
19import QtTest 1.0
19import QtTest 1.0
20−import Unity.Test 0.1 as UT
20+import Unity.Test 0.1
21import ".."
21import ".."
22import "../../../qml/Stages"
22import "../../../qml/Stages"
23import Ubuntu.Components 0.1
23import Ubuntu.Components 0.1
@@ -36,34 +36,41 @@ Item {
36
36
37 Item {
37 Item {
38 id: fakeWindow
38 id: fakeWindow
39− property alias minWidth: moveResizeArea.minWidth
39+ property alias minWidth: windowResizeArea.minWidth
40− property alias minHeight: moveResizeArea.minHeight
40+ property alias minHeight: windowResizeArea.minHeight
41 x: units.gu(20)
41 x: units.gu(20)
42 y: units.gu(20)
42 y: units.gu(20)
43 height: units.gu(20)
43 height: units.gu(20)
44 width: units.gu(20)
44 width: units.gu(20)
45 property int windowHeight: height
45 property int windowHeight: height
46 property int windowWidth: width
46 property int windowWidth: width
47− onWindowHeightChanged: height = windowHeight
47+ state: "normal"
48− onWindowWidthChanged: width = windowWidth
49
48
50− WindowMoveResizeArea {
49+ function maximize() {
51− id: moveResizeArea
50+ state = "maximized"
51+ }
52+
53+ WindowResizeArea {
54+ id: windowResizeArea
52 target: fakeWindow
55 target: fakeWindow
53− resizeHandleWidth: units.gu(0.5)
56+ borderThickness: units.gu(2)
54 minWidth: units.gu(15)
57 minWidth: units.gu(15)
55 minHeight: units.gu(10)
58 minHeight: units.gu(10)
56 windowId: "test-window-id"
59 windowId: "test-window-id"
57 }
60 }
58
61
59 Rectangle {
62 Rectangle {
60− anchors.fill: moveResizeArea
63+ anchors.fill: windowResizeArea
61 color: "red"
64 color: "red"
62 }
65 }
63
66
64 Rectangle {
67 Rectangle {
65 anchors.fill: fakeWindow
68 anchors.fill: fakeWindow
66 color: "blue"
69 color: "blue"
70+ MouseArea {
71+ anchors.fill: parent
72+ hoverEnabled: true
73+ }
67 }
74 }
68 }
75 }
69 }
76 }
@@ -73,8 +80,13 @@ Item {
73 sourceComponent: fakeWindowComponent
80 sourceComponent: fakeWindowComponent
74 }
81 }
75
82
83+ MouseTouchEmulationCheckbox {
84+ checked: false
85+ color: "black"
86+ }
87+
76− UT.UnityTestCase {
88+ UnityTestCase {
77− name: "WindowMoveResizeArea"
89+ name: "WindowResizeArea"
78 when: windowShown
90 when: windowShown
79
91
80 function init() {
92 function init() {
@@ -84,34 +96,6 @@ Item {
84 fakeWindow.height = units.gu(20)
96 fakeWindow.height = units.gu(20)
85 }
97 }
86
98
87− function test_dragWindow_data() {
88− return [
89− { tag: "up", dx: 0, dy: units.gu(-10) },
90− { tag: "down", dx: 0, dy: units.gu(10) },
91− { tag: "left", dx: units.gu(-10), dy: 0 },
92− { tag: "right", dx: units.gu(10), dy: 0 },
93− { tag: "right/down", dx: units.gu(10), dy: units.gu(10) },
94− { tag: "left/down", dx: units.gu(-10), dy: units.gu(10) }
95− ]
96− }
97−
98− function test_dragWindow(data) {
99− var initialWindowX = fakeWindow.x;
100− var initialWindowY = fakeWindow.y;
101− var initialWindowWidth = fakeWindow.width
102− var initialWindowHeight = fakeWindow.height
103−
104− var startDragX = initialWindowX + fakeWindow.width / 2;
105− var startDragY = initialWindowY + fakeWindow.height / 2;
106− mouseFlick(root, startDragX, startDragY, startDragX + data.dx, startDragY + data.dy, true, true, units.gu(.5), 10)
107−
108− tryCompare(fakeWindow, "x", initialWindowX + data.dx)
109− tryCompare(fakeWindow, "y", initialWindowX + data.dy)
110−
111− compare(fakeWindow.height, initialWindowHeight);
112− compare(fakeWindow.width, initialWindowWidth);
113− }
114−
115 function test_resizeWindowRightBottom_data() {
99 function test_resizeWindowRightBottom_data() {
116 return [
100 return [
117 { tag: "width", dx: units.gu(10), dy: 0 },
101 { tag: "width", dx: units.gu(10), dy: 0 },
@@ -166,30 +150,6 @@ Item {
166 compare(fakeWindow.y, Math.min(initialWindowY + data.dy, initialWindowY + maxMoveY));
150 compare(fakeWindow.y, Math.min(initialWindowY + data.dy, initialWindowY + maxMoveY));
167 }
151 }
168
152
169− function test_saveRestorePosition() {
170− var initialWindowX = fakeWindow.x;
171− var initialWindowY = fakeWindow.y;
172− var initialWindowWidth = fakeWindow.width;
173− var initialWindowHeight = fakeWindow.height;
174−
175− var moveDelta = units.gu(5);
176− var startDragX = initialWindowX + fakeWindow.width / 2;
177− var startDragY = initialWindowY + fakeWindow.height / 2;
178− mouseFlick(root, startDragX, startDragY, startDragX + moveDelta, startDragY + moveDelta, true, true, units.gu(.5), 10)
179−
180− tryCompare(fakeWindow, "x", initialWindowX + moveDelta)
181− tryCompare(fakeWindow, "y", initialWindowX + moveDelta)
182−
183− // This will destroy the window and recreate it
184− windowLoader.active = false;
185− waitForRendering(root);
186− windowLoader.active = true;
187−
188− // Make sure it's again where we left it before destroying
189− tryCompare(fakeWindow, "x", initialWindowX + moveDelta)
190− tryCompare(fakeWindow, "y", initialWindowX + moveDelta)
191− }
192−
193 function test_saveRestoreSize() {
153 function test_saveRestoreSize() {
194 var initialWindowX = fakeWindow.x;
154 var initialWindowX = fakeWindow.x;
195 var initialWindowY = fakeWindow.y;
155 var initialWindowY = fakeWindow.y;
@@ -238,5 +198,35 @@ Item {
238 tryCompare(fakeWindow, "width", initialWindowWidth);
198 tryCompare(fakeWindow, "width", initialWindowWidth);
239 tryCompare(fakeWindow, "height", initialWindowHeight);
199 tryCompare(fakeWindow, "height", initialWindowHeight);
240 }
200 }
201+
202+ function test_saveRestoreMaximized() {
203+ var initialWindowX = fakeWindow.x;
204+ var initialWindowY = fakeWindow.y;
205+
206+ var moveDelta = units.gu(5);
207+
208+ fakeWindow.x = initialWindowX + moveDelta
209+ fakeWindow.y = initialWindowY + moveDelta
210+
211+ // Now change the state to maximized. The window should not keep updating the stored values
212+ fakeWindow.state = "maximized"
213+ fakeWindow.x = 31415 // 0 is too risky to pass the test even when broken
214+ fakeWindow.y = 31415
215+
216+ // This will destroy the window and recreate it
217+ windowLoader.active = false;
218+ waitForRendering(root);
219+ windowLoader.active = true;
220+
221+ // Make sure it's again where we left it in normal state before destroying
222+ tryCompare(fakeWindow, "x", initialWindowX + moveDelta)
223+ tryCompare(fakeWindow, "y", initialWindowX + moveDelta)
224+
225+ // Make sure maximize() has been called after restoring
226+ tryCompare(fakeWindow, "state", "maximized")
227+
228+ // clean up
229+ fakeWindow.state = "normal"
230+ }
241 }
231 }
242}
232}
tests/qmltests/tst_DisabledScreenNotice.qmlnew file+37
@@ -0,0 +1,37 @@
1+/*
2+ * Copyright (C) 2015 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.4
18+import QtTest 1.0
19+import Unity.Test 0.1
20+import "../../qml"
21+
22+
23+Item {
24+ id: root
25+ width: units.gu(70)
26+ height: units.gu(70)
27+
28+ DisabledScreenNotice {
29+ anchors.fill: parent
30+ }
31+
32+ UnityTestCase {
33+ id: testCase
34+ name: "DisabledScreenNotice"
35+ when: windowShown
36+ }
37+}
tests/qmltests/tst_OrientedShell.qml+56−2
@@ -110,6 +110,22 @@ Rectangle {
110 physicalOrientation180: Qt.LandscapeOrientation
110 physicalOrientation180: Qt.LandscapeOrientation
111 primaryOrientationAngle: 90
111 primaryOrientationAngle: 90
112 }
112 }
113+ },
114+ State {
115+ name: "desktop"
116+ PropertyChanges {
117+ target: orientedShellLoader
118+ width: units.gu(100)
119+ height: units.gu(56)
120+ }
121+ PropertyChanges {
122+ target: root
123+ physicalOrientation270: Qt.InvertedPortraitOrientation
124+ physicalOrientation0: Qt.LandscapeOrientation
125+ physicalOrientation90: Qt.PortraitOrientation
126+ physicalOrientation180: Qt.InvertedLandscapeOrientation
127+ primaryOrientationAngle: 0
128+ }
113 }
129 }
114 ]
130 ]
115
131
@@ -250,7 +266,7 @@ Rectangle {
250 anchors { left: parent.left; right: parent.right }
266 anchors { left: parent.left; right: parent.right }
251 activeFocusOnPress: false
267 activeFocusOnPress: false
252 text: "Device Name"
268 text: "Device Name"
253− model: ["mako", "manta", "flo"]
269+ model: ["mako", "manta", "flo", "desktop"]
254 onSelectedIndexChanged: {
270 onSelectedIndexChanged: {
255 testCase.tearDown();
271 testCase.tearDown();
256 applicationArguments.deviceName = model[selectedIndex];
272 applicationArguments.deviceName = model[selectedIndex];
@@ -264,6 +280,10 @@ Rectangle {
264 text: "Usage Mode"
280 text: "Usage Mode"
265 model: ["Staged", "Windowed", "Automatic"]
281 model: ["Staged", "Windowed", "Automatic"]
266 }
282 }
283+ MouseTouchEmulationCheckbox {
284+ checked: true
285+ color: "white"
286+ }
267 Button {
287 Button {
268 text: "Switch fullscreen"
288 text: "Switch fullscreen"
269 activeFocusOnPress: false
289 activeFocusOnPress: false
@@ -306,12 +326,14 @@ Rectangle {
306 Row {
326 Row {
307 Button {
327 Button {
308 text: "Add mouse"
328 text: "Add mouse"
329+ activeFocusOnPress: false
309 onClicked: {
330 onClicked: {
310 UnityInputInfo.inputInfo.addMockMouse()
331 UnityInputInfo.inputInfo.addMockMouse()
311 }
332 }
312 }
333 }
313 Button {
334 Button {
314 text: "Remove mouse"
335 text: "Remove mouse"
336+ activeFocusOnPress: false
315 onClicked: {
337 onClicked: {
316 UnityInputInfo.inputInfo.removeMockMouse()
338 UnityInputInfo.inputInfo.removeMockMouse()
317 }
339 }
@@ -320,17 +342,37 @@ Rectangle {
320 Row {
342 Row {
321 Button {
343 Button {
322 text: "Add kbd"
344 text: "Add kbd"
345+ activeFocusOnPress: false
323 onClicked: {
346 onClicked: {
324 UnityInputInfo.inputInfo.addMockKeyboard()
347 UnityInputInfo.inputInfo.addMockKeyboard()
325 }
348 }
326 }
349 }
327 Button {
350 Button {
351+ activeFocusOnPress: false
328 text: "Remove kbd"
352 text: "Remove kbd"
329 onClicked: {
353 onClicked: {
330 UnityInputInfo.inputInfo.removeMockKeyboard()
354 UnityInputInfo.inputInfo.removeMockKeyboard()
331 }
355 }
332 }
356 }
333 }
357 }
358+
359+ // Simulates what happens when the shell is moved to an external monitor and back
360+ Button {
361+ id: moveToFromMonitorButton
362+ text: applicationArguments.deviceName === "desktop" ? "Move to " + prevDevName + " screen" : "Move to desktop screen"
363+ activeFocusOnPress: false
364+ property string prevDevName: "mako"
365+ onClicked: {
366+ usageModeSelector.selectedIndex = 2; // "Automatic"
367+
368+ if (applicationArguments.deviceName === "desktop") {
369+ applicationArguments.deviceName = prevDevName;
370+ } else {
371+ prevDevName = applicationArguments.deviceName;
372+ applicationArguments.deviceName = "desktop"
373+ }
374+ }
375+ }
334 }
376 }
335 }
377 }
336
378
@@ -798,7 +840,7 @@ Rectangle {
798 // shell should remain in its primery orientation as the app in the main stage
840 // shell should remain in its primery orientation as the app in the main stage
799 // is the one that dictates its orientation. In this case it's unity8-dash
841 // is the one that dictates its orientation. In this case it's unity8-dash
800 // which supports only primary orientation
842 // which supports only primary orientation
801− compare(shell.orientation, orientedShell.primaryOrientation);
843+ compare(shell.orientation, orientedShell.orientations.primary);
802 }
844 }
803
845
804 function test_sideStageAppsRemainPortraitInSpread_data() {
846 function test_sideStageAppsRemainPortraitInSpread_data() {
@@ -1050,6 +1092,18 @@ Rectangle {
1050 compare(signalSpy.count, 0);
1092 compare(signalSpy.count, 0);
1051 }
1093 }
1052
1094
1095+ function test_moveToExternalMonitor() {
1096+ loadShell("flo");
1097+
1098+ compare(orientedShell.orientation, Qt.InvertedLandscapeOrientation);
1099+ compare(shell.transformRotationAngle, 90);
1100+
1101+ moveToFromMonitorButton.clicked();
1102+
1103+ tryCompare(orientedShell, "orientation", Qt.LandscapeOrientation);
1104+ tryCompare(shell, "transformRotationAngle" , 0);
1105+ }
1106+
1053 // angle - rotation angle in degrees clockwise, relative to the primary orientation.
1107 // angle - rotation angle in degrees clockwise, relative to the primary orientation.
1054 function rotateTo(angle) {
1108 function rotateTo(angle) {
1055 switch (angle) {
1109 switch (angle) {
tests/qmltests/tst_Shell.qml+112−26
@@ -29,8 +29,11 @@ import Unity.Notifications 1.0
29import Unity.Test 0.1
29import Unity.Test 0.1
30import Powerd 0.1
30import Powerd 0.1
31import Wizard 0.1 as Wizard
31import Wizard 0.1 as Wizard
32+import Utils 0.1
32
33
33import "../../qml"
34import "../../qml"
35+import "../../qml/Components"
36+import "../../qml/Components/PanelState"
34import "Stages"
37import "Stages"
35
38
36Rectangle {
39Rectangle {
@@ -97,8 +100,7 @@ Rectangle {
97 id: __shell
100 id: __shell
98 usageScenario: usageScenarioSelector.model[usageScenarioSelector.selectedIndex]
101 usageScenario: usageScenarioSelector.model[usageScenarioSelector.selectedIndex]
99 orientation: Qt.PortraitOrientation
102 orientation: Qt.PortraitOrientation
100− primaryOrientation: Qt.PortraitOrientation
103+ orientations: Orientations{} // Defaults are fine for testing
101− nativeOrientation: Qt.PortraitOrientation
102 Component.onDestruction: {
104 Component.onDestruction: {
103 shellLoader.itemDestroyed = true;
105 shellLoader.itemDestroyed = true;
104 }
106 }
@@ -302,6 +304,7 @@ Rectangle {
302 mouseEmulation.checked = true;
304 mouseEmulation.checked = true;
303 tryCompare(shell, "enabled", true); // make sure greeter didn't leave us in disabled state
305 tryCompare(shell, "enabled", true); // make sure greeter didn't leave us in disabled state
304 tearDown();
306 tearDown();
307+ WindowStateStorage.clear();
305 }
308 }
306
309
307 function loadShell(formFactor) {
310 function loadShell(formFactor) {
@@ -377,6 +380,8 @@ Rectangle {
377 LightDM.Greeter.authenticate(""); // reset greeter
380 LightDM.Greeter.authenticate(""); // reset greeter
378
381
379 sessionSpy.clear();
382 sessionSpy.clear();
383+
384+ GSettingsController.setLifecycleExemptAppids([]);
380 }
385 }
381
386
382 function killApps() {
387 function killApps() {
@@ -1240,30 +1245,6 @@ Rectangle {
1240 tryCompare(launcherPanel, "x", -launcherPanel.width);
1245 tryCompare(launcherPanel, "x", -launcherPanel.width);
1241 }
1246 }
1242
1247
1243− function test_background_data() {
1244− return [
1245− {tag: "color", accounts: Qt.resolvedUrl("data:image/svg+xml,<svg><rect width='100%' height='100%' fill='#dd4814'/></svg>"), gsettings: "", output: Qt.resolvedUrl("data:image/svg+xml,<svg><rect width='100%' height='100%' fill='#dd4814'/></svg>")},
1246− {tag: "empty", accounts: "", gsettings: "", output: "defaultBackground"},
1247− {tag: "as-specified", accounts: Qt.resolvedUrl("../data/unity/backgrounds/blue.png"), gsettings: "", output: Qt.resolvedUrl("../data/unity/backgrounds/blue.png")},
1248− {tag: "gs-specified", accounts: "", gsettings: Qt.resolvedUrl("../data/unity/backgrounds/red.png"), output: Qt.resolvedUrl("../data/unity/backgrounds/red.png")},
1249− {tag: "both-specified", accounts: Qt.resolvedUrl("../data/unity/backgrounds/blue.png"), gsettings: Qt.resolvedUrl("../data/unity/backgrounds/red.png"), output: Qt.resolvedUrl("../data/unity/backgrounds/blue.png")},
1250− {tag: "invalid-as", accounts: Qt.resolvedUrl("../data/unity/backgrounds/nope.png"), gsettings: Qt.resolvedUrl("../data/unity/backgrounds/red.png"), output: Qt.resolvedUrl("../data/unity/backgrounds/red.png")},
1251− {tag: "invalid-both", accounts: Qt.resolvedUrl("../data/unity/backgrounds/nope.png"), gsettings: Qt.resolvedUrl("../data/unity/backgrounds/stillnope.png"), output: "defaultBackground"},
1252− ]
1253− }
1254− function test_background(data) {
1255− loadShell("phone");
1256− swipeAwayGreeter();
1257− AccountsService.backgroundFile = data.accounts;
1258− GSettingsController.setPictureUri(data.gsettings);
1259−
1260− if (data.output === "defaultBackground") {
1261− tryCompare(shell, "background", shell.defaultBackground);
1262− } else {
1263− tryCompare(shell, "background", data.output);
1264− }
1265− }
1266−
1267 function test_tabletLogin_data() {
1248 function test_tabletLogin_data() {
1268 return [
1249 return [
1269 {tag: "auth error", user: "auth-error", loggedIn: false, password: ""},
1250 {tag: "auth error", user: "auth-error", loggedIn: false, password: ""},
@@ -1731,5 +1712,110 @@ Rectangle {
1731
1712
1732 keyRelease(Qt.Key_Control);
1713 keyRelease(Qt.Key_Control);
1733 }
1714 }
1715+
1716+ // regression test for http://pad.lv/1443319
1717+ function test_closeMaximizedAndRestart() {
1718+ loadDesktopShellWithApps();
1719+
1720+ var appRepeater = findChild(shell, "appRepeater")
1721+ var appId = ApplicationManager.get(0).appId;
1722+ var appDelegate = appRepeater.itemAt(0);
1723+ var maximizeButton = findChild(appDelegate, "maximizeWindowButton");
1724+
1725+ wait(5000)
1726+ tryCompare(appDelegate, "state", "normal");
1727+ tryCompare(PanelState, "buttonsVisible", false)
1728+
1729+ wait(5000)
1730+ mouseClick(maximizeButton, maximizeButton.width / 2, maximizeButton.height / 2);
1731+ tryCompare(appDelegate, "state", "maximized");
1732+ tryCompare(PanelState, "buttonsVisible", true)
1733+
1734+ ApplicationManager.stopApplication(appId);
1735+ tryCompare(PanelState, "buttonsVisible", false)
1736+
1737+ ApplicationManager.startApplication(appId);
1738+ tryCompare(PanelState, "buttonsVisible", true)
1739+ }
1740+
1741+ // bug http://pad.lv/1431566
1742+ function test_switchToStagedHidesPanelButtons() {
1743+ loadDesktopShellWithApps();
1744+ var appRepeater = findChild(shell, "appRepeater")
1745+ var appId = ApplicationManager.get(0).appId;
1746+ var appDelegate = appRepeater.itemAt(0);
1747+ var panelButtons = findChild(shell, "panelWindowControlButtons")
1748+
1749+ tryCompare(appDelegate, "state", "normal");
1750+ tryCompare(panelButtons, "visible", false);
1751+
1752+ appDelegate.maximize(false);
1753+ tryCompare(panelButtons, "visible", true);
1754+
1755+ shell.usageScenario = "phone";
1756+ waitForRendering(shell);
1757+ tryCompare(panelButtons, "visible", false);
1758+
1759+ shell.usageScenario = "desktop";
1760+ waitForRendering(shell);
1761+ tryCompare(panelButtons, "visible", true);
1762+ }
1763+
1764+ function test_lockingGreeterHidesPanelButtons() {
1765+ loadDesktopShellWithApps();
1766+ var appRepeater = findChild(shell, "appRepeater")
1767+ var appId = ApplicationManager.get(0).appId;
1768+ var appDelegate = appRepeater.itemAt(0);
1769+ var panelButtons = findChild(shell, "panelWindowControlButtons")
1770+
1771+ tryCompare(appDelegate, "state", "normal");
1772+ tryCompare(panelButtons, "visible", false);
1773+
1774+ appDelegate.maximize(false);
1775+ tryCompare(panelButtons, "visible", true);
1776+
1777+ LightDM.Greeter.showGreeter();
1778+ waitForRendering(shell);
1779+ tryCompare(panelButtons, "visible", false);
1780+
1781+ LightDM.Greeter.hideGreeter();
1782+ waitForRendering(shell);
1783+ tryCompare(panelButtons, "visible", true);
1784+ }
1785+
1786+ function test_lifecyclePolicy_data() {
1787+ return [
1788+ {tag: "phone", formFactor: "phone", usageScenario: "phone", suspendsApps: true},
1789+ {tag: "tablet", formFactor: "tablet", usageScenario: "tablet", suspendsApps: true},
1790+ {tag: "desktop", formFactor: "tablet", usageScenario: "desktop", suspendsApps: false}
1791+ ]
1792+ }
1793+
1794+ function test_lifecyclePolicy(data) {
1795+ loadShell(data.formFactor);
1796+ shell.usageScenario = data.usageScenario;
1797+
1798+ GSettingsController.setLifecycleExemptAppids(["webbrowser-app"]);
1799+
1800+ var app1 = ApplicationManager.startApplication("camera-app");
1801+ waitUntilAppWindowIsFullyLoaded(app1);
1802+ var app2 = ApplicationManager.startApplication("webbrowser-app");
1803+ waitUntilAppWindowIsFullyLoaded(app2);
1804+ var app3 = ApplicationManager.startApplication("libreoffice");
1805+ waitUntilAppWindowIsFullyLoaded(app3);
1806+ var app4 = ApplicationManager.startApplication("dialer-app");
1807+ waitUntilAppWindowIsFullyLoaded(app4);
1808+
1809+ compare(app1.requestedState, data.suspendsApps ?
1810+ ApplicationInfoInterface.RequestedSuspended :
1811+ ApplicationInfoInterface.RequestedRunning);
1812+
1813+ compare(app2.requestedState, ApplicationInfoInterface.RequestedRunning);
1814+
1815+ compare(app3.isTouchApp, false); // sanity check our mock, which sets this for us
1816+ compare(app3.requestedState, ApplicationInfoInterface.RequestedRunning);
1817+
1818+ compare(app4.requestedState, ApplicationInfoInterface.RequestedRunning);
1819+ }
1734 }
1820 }
1735}
1821}