Merge lp:~unity-team/qtmir/silo0 into lp:qtmir

Proposed by Gerry Boland
Status: Work in progress
Proposed branch: lp:~unity-team/qtmir/silo0
Merge into: lp:qtmir
Diff against target: 10000 lines (+6274/-1380) (has conflicts)
103 files modified
3rd_party/CMakeLists.txt (+1/-0)
3rd_party/xcursor/CMakeLists.txt (+15/-0)
3rd_party/xcursor/README (+1/-0)
3rd_party/xcursor/xcursor.c (+968/-0)
3rd_party/xcursor/xcursor.h (+65/-0)
CMakeLists.txt (+2/-1)
README (+10/-1)
debian/changelog (+12/-1)
debian/copyright (+21/-0)
demos/qml-demo-shell/ResizeArea.qml (+119/-0)
demos/qml-demo-shell/TitleBar.qml (+72/-0)
demos/qml-demo-shell/Window.qml (+166/-39)
demos/qml-demo-shell/WindowBufferSized.qml (+178/-0)
demos/qml-demo-shell/qml-demo-shell.qml (+172/-72)
src/common/debughelpers.cpp (+11/-0)
src/common/debughelpers.h (+1/-0)
src/modules/Unity/Application/CMakeLists.txt (+10/-2)
src/modules/Unity/Application/Cursor.qml (+12/-0)
src/modules/Unity/Application/cursorimageprovider.cpp (+146/-0)
src/modules/Unity/Application/cursorimageprovider.h (+68/-0)
src/modules/Unity/Application/mirbuffersgtexture.cpp (+5/-6)
src/modules/Unity/Application/mirbuffersgtexture.h (+2/-2)
src/modules/Unity/Application/mirsingleton.cpp (+33/-0)
src/modules/Unity/Application/mirsingleton.h (+45/-0)
src/modules/Unity/Application/mirsurface.cpp (+631/-0)
src/modules/Unity/Application/mirsurface.h (+152/-0)
src/modules/Unity/Application/mirsurfaceinterface.h (+90/-0)
src/modules/Unity/Application/mirsurfaceitem.cpp (+353/-421)
src/modules/Unity/Application/mirsurfaceitem.h (+61/-70)
src/modules/Unity/Application/mirsurfaceiteminterface.h (+0/-116)
src/modules/Unity/Application/mirsurfaceitemmodel.h (+0/-32)
src/modules/Unity/Application/mirsurfacemanager.cpp (+27/-29)
src/modules/Unity/Application/mirsurfacemanager.h (+13/-10)
src/modules/Unity/Application/mousepointer.cpp (+146/-0)
src/modules/Unity/Application/mousepointer.h (+70/-0)
src/modules/Unity/Application/plugin.cpp (+15/-4)
src/modules/Unity/Application/qmldir (+1/-0)
src/modules/Unity/Application/session.cpp (+7/-12)
src/modules/Unity/Application/session.h (+3/-3)
src/modules/Unity/Application/session_interface.h (+6/-6)
src/modules/Unity/CMakeLists.txt (+1/-0)
src/modules/Unity/Screens/CMakeLists.txt (+18/-0)
src/modules/Unity/Screens/plugin.cpp (+41/-0)
src/modules/Unity/Screens/qmldir (+2/-0)
src/modules/Unity/Screens/screens.cpp (+71/-0)
src/modules/Unity/Screens/screens.h (+54/-0)
src/platforms/mirserver/CMakeLists.txt (+7/-3)
src/platforms/mirserver/cursor.cpp (+121/-0)
src/platforms/mirserver/cursor.h (+56/-0)
src/platforms/mirserver/display.cpp.THIS (+1/-1)
src/platforms/mirserver/logging.h (+1/-0)
src/platforms/mirserver/miropenglcontext.cpp (+23/-8)
src/platforms/mirserver/mirserver.cpp (+40/-4)
src/platforms/mirserver/mirserver.h (+8/-3)
src/platforms/mirserver/mirserverintegration.cpp (+47/-40)
src/platforms/mirserver/mirserverintegration.h (+4/-7)
src/platforms/mirserver/mousepointerinterface.h (+57/-0)
src/platforms/mirserver/offscreensurface.cpp (+61/-0)
src/platforms/mirserver/offscreensurface.h (+43/-0)
src/platforms/mirserver/qmirserver.cpp (+13/-1)
src/platforms/mirserver/qmirserver.h (+3/-0)
src/platforms/mirserver/qmirserver_p.h (+2/-0)
src/platforms/mirserver/qtcompositor.cpp (+9/-34)
src/platforms/mirserver/qtcompositor.h (+13/-5)
src/platforms/mirserver/qteventfeeder.cpp (+118/-87)
src/platforms/mirserver/qteventfeeder.h (+13/-9)
src/platforms/mirserver/screen.cpp (+104/-7)
src/platforms/mirserver/screen.h (+42/-6)
src/platforms/mirserver/screencontroller.cpp (+299/-0)
src/platforms/mirserver/screencontroller.h (+101/-0)
src/platforms/mirserver/screenwindow.cpp (+33/-79)
src/platforms/mirserver/screenwindow.h (+10/-24)
src/platforms/mirserver/sessionlistener.h (+3/-1)
src/platforms/mirserver/surfaceobserver.cpp (+6/-0)
src/platforms/mirserver/surfaceobserver.h (+3/-1)
src/platforms/mirserver/tileddisplayconfigurationpolicy.cpp (+44/-0)
src/platforms/mirserver/tileddisplayconfigurationpolicy.h (+35/-0)
tests/common/fake_displayconfigurationoutput.h (+73/-0)
tests/common/gmock_fixes.h (+124/-0)
tests/common/mock_display.h (+53/-0)
tests/common/mock_display_buffer.h (+43/-0)
tests/common/mock_display_configuration.h (+35/-0)
tests/common/mock_main_loop.h (+53/-0)
tests/mirserver/CMakeLists.txt (+1/-0)
tests/mirserver/QtEventFeeder/mock_qtwindowsystem.h (+17/-10)
tests/mirserver/QtEventFeeder/qteventfeeder_test.cpp (+29/-16)
tests/mirserver/Screen/CMakeLists.txt (+1/-0)
tests/mirserver/Screen/screen_test.cpp (+40/-24)
tests/mirserver/ScreenController/CMakeLists.txt (+28/-0)
tests/mirserver/ScreenController/screencontroller_test.cpp (+194/-0)
tests/mirserver/ScreenController/stub_display.h (+91/-0)
tests/mirserver/ScreenController/stub_screen.h (+31/-0)
tests/mirserver/ScreenController/testable_screencontroller.h (+38/-0)
tests/modules/ApplicationManager/CMakeLists.txt (+1/-1)
tests/modules/ApplicationManager/application_manager_test.cpp (+22/-22)
tests/modules/MirSurfaceItem/CMakeLists.txt (+2/-0)
tests/modules/MirSurfaceItem/mirsurfaceitem_test.cpp (+32/-65)
tests/modules/SessionManager/CMakeLists.txt (+1/-1)
tests/modules/SessionManager/session_test.cpp (+4/-4)
tests/modules/common/fake_mirsurface.h (+141/-38)
tests/modules/common/mock_mirsurfaceitem.h (+0/-49)
tests/modules/common/mock_session.h (+2/-2)
tests/modules/common/qtmir_test.h (+1/-1)
Text conflict in debian/changelog
Text conflict in src/modules/Unity/Application/mirsurfaceitem.cpp
To merge this branch: bzr merge lp:~unity-team/qtmir/silo0
Reviewer Review Type Date Requested Status
Mir development team Pending
Review via email: mp+264172@code.launchpad.net

Commit message

DO NOT MERGE

To post a comment you must log in.
lp:~unity-team/qtmir/silo0 updated
346. By Andreas Pokorny

Release in step with Mir 0.14.0
Approved by: Gerry Boland

347. By CI Train Bot Account

Releasing 0.4.5+15.10.20150722-0ubuntu1

348. By Gerry Boland

Remove explicit gcc4.9 dependency Fixes: #1452338
Approved by: PS Jenkins bot, Daniel d'Andrada

349. By CI Train Bot Account

Releasing 0.4.5+15.10.20150728-0ubuntu1

350. By Daniel d'Andrada <dandrader@panzer>

Remove focus-based app lifecycle. Let shell control it.

API changes:
- ApplicationManager: removed suspended and forceDashActive
- Added Application.requestedState

Also refactored and clearly defined Application and Session states and state transitions.
- Let Application define its own state based on events provided by ApplicationManager. Previously that responsibility was split between those classes.
- Session now defines its own state based on events and requests fed by Application, SessionManager and SurfaceManager.
Approved by: Gerry Boland

351. By Gerry Boland

We depend on Qt 5.4, remove compatibility code for older versions
Approved by: PS Jenkins bot, Daniel d'Andrada

352. By Lukáš Tinkl

Extend the key table to cover full xkb range of keycodes.

Fixes many missing symbols, mainly various multimedia keys.
Also fix missing mapping to back/forward extra mouse buttons.
Approved by: Gerry Boland, Daniel d'Andrada

353. By Gerry Boland

CMake should require mir 0.14
Approved by: Daniel d'Andrada

354. By Gerry Boland

No change rebuild using GCC 5.
Approved by: Gerry Boland

355. By Alan Griffiths

Start restructuring code to use the Mir WindowManager interface for window management. (Instead of completely replacing the Shell.)
Approved by: Gerry Boland, PS Jenkins bot

356. By Daniel van Vugt

ensure the argv passed to mir is a null terminated list (not a nullptr)
Approved by: Gerry Boland, PS Jenkins bot

357. By Gerry Boland

Ubuntu Touch has no shared graphics cache implemented, QPA should not say it does
Approved by: PS Jenkins bot, Daniel d'Andrada

358. By CI Train Bot Account

Releasing 0.4.5+15.10.20150804.1-0ubuntu1

359. By Gerry Boland

Merge mirSurface branch, fixing conflicts

360. By Gerry Boland

Merge mousePointer

361. By Gerry Boland

Add changelog entry for last vivid release

362. By Gerry Boland

Merge trunk

363. By Gerry Boland

Merge multimonitor

364. By Gerry Boland

Fix all the namespace issues

365. By Gerry Boland

Oops, infinite loop due to merge error

366. By Gerry Boland

Fix up mouse pointer

367. By Gerry Boland

Add hack to resize surface to suit all displaus

368. By Gerry Boland

Workaround a crash fix

369. By Daniel d'Andrada

QtEventFeeder: log the pointer events it gets from Mir

Unmerged revisions

369. By Daniel d'Andrada

QtEventFeeder: log the pointer events it gets from Mir

368. By Gerry Boland

Workaround a crash fix

367. By Gerry Boland

Add hack to resize surface to suit all displaus

366. By Gerry Boland

Fix up mouse pointer

365. By Gerry Boland

Oops, infinite loop due to merge error

364. By Gerry Boland

Fix all the namespace issues

363. By Gerry Boland

Merge multimonitor

362. By Gerry Boland

Merge trunk

361. By Gerry Boland

Add changelog entry for last vivid release

360. By Gerry Boland

Merge mousePointer

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added directory '3rd_party'
2=== added file '3rd_party/CMakeLists.txt'
3--- 3rd_party/CMakeLists.txt 1970-01-01 00:00:00 +0000
4+++ 3rd_party/CMakeLists.txt 2015-08-27 14:51:37 +0000
5@@ -0,0 +1,1 @@
6+add_subdirectory(xcursor)
7
8=== added directory '3rd_party/xcursor'
9=== added file '3rd_party/xcursor/CMakeLists.txt'
10--- 3rd_party/xcursor/CMakeLists.txt 1970-01-01 00:00:00 +0000
11+++ 3rd_party/xcursor/CMakeLists.txt 2015-08-27 14:51:37 +0000
12@@ -0,0 +1,15 @@
13+add_definitions(-D_DEFAULT_SOURCE=1)
14+
15+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC")
16+
17+set(
18+ XCURSOR_SOURCES
19+
20+ xcursor.c
21+)
22+
23+add_library(
24+ xcursorloader-static STATIC
25+
26+ ${XCURSOR_SOURCES}
27+)
28
29=== added file '3rd_party/xcursor/README'
30--- 3rd_party/xcursor/README 1970-01-01 00:00:00 +0000
31+++ 3rd_party/xcursor/README 2015-08-27 14:51:37 +0000
32@@ -0,0 +1,1 @@
33+TODO: This should go away once we start using the cursor feature from Mir instead of drawing the cursor ourselves as an item in the QML scene
34
35=== added file '3rd_party/xcursor/xcursor.c'
36--- 3rd_party/xcursor/xcursor.c 1970-01-01 00:00:00 +0000
37+++ 3rd_party/xcursor/xcursor.c 2015-08-27 14:51:37 +0000
38@@ -0,0 +1,968 @@
39+/*
40+ * Copyright © 2002 Keith Packard
41+ *
42+ * Permission to use, copy, modify, distribute, and sell this software and its
43+ * documentation for any purpose is hereby granted without fee, provided that
44+ * the above copyright notice appear in all copies and that both that
45+ * copyright notice and this permission notice appear in supporting
46+ * documentation, and that the name of Keith Packard not be used in
47+ * advertising or publicity pertaining to distribution of the software without
48+ * specific, written prior permission. Keith Packard makes no
49+ * representations about the suitability of this software for any purpose. It
50+ * is provided "as is" without express or implied warranty.
51+ *
52+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
53+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
54+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
55+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
56+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
57+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
58+ * PERFORMANCE OF THIS SOFTWARE.
59+ */
60+
61+#include "xcursor.h"
62+#include <stdio.h>
63+#include <stdlib.h>
64+#include <string.h>
65+#include <dirent.h>
66+
67+/*
68+ * From libXcursor/include/X11/extensions/Xcursor.h
69+ */
70+
71+#define XcursorTrue 1
72+#define XcursorFalse 0
73+
74+/*
75+ * Cursor files start with a header. The header
76+ * contains a magic number, a version number and a
77+ * table of contents which has type and offset information
78+ * for the remaining tables in the file.
79+ *
80+ * File minor versions increment for compatible changes
81+ * File major versions increment for incompatible changes (never, we hope)
82+ *
83+ * Chunks of the same type are always upward compatible. Incompatible
84+ * changes are made with new chunk types; the old data can remain under
85+ * the old type. Upward compatible changes can add header data as the
86+ * header lengths are specified in the file.
87+ *
88+ * File:
89+ * FileHeader
90+ * LISTofChunk
91+ *
92+ * FileHeader:
93+ * CARD32 magic magic number
94+ * CARD32 header bytes in file header
95+ * CARD32 version file version
96+ * CARD32 ntoc number of toc entries
97+ * LISTofFileToc toc table of contents
98+ *
99+ * FileToc:
100+ * CARD32 type entry type
101+ * CARD32 subtype entry subtype (size for images)
102+ * CARD32 position absolute file position
103+ */
104+
105+#define XCURSOR_MAGIC 0x72756358 /* "Xcur" LSBFirst */
106+
107+/*
108+ * Current Xcursor version number. Will be substituted by configure
109+ * from the version in the libXcursor configure.ac file.
110+ */
111+
112+#define XCURSOR_LIB_MAJOR 1
113+#define XCURSOR_LIB_MINOR 1
114+#define XCURSOR_LIB_REVISION 13
115+#define XCURSOR_LIB_VERSION ((XCURSOR_LIB_MAJOR * 10000) + \
116+ (XCURSOR_LIB_MINOR * 100) + \
117+ (XCURSOR_LIB_REVISION))
118+
119+/*
120+ * This version number is stored in cursor files; changes to the
121+ * file format require updating this version number
122+ */
123+#define XCURSOR_FILE_MAJOR 1
124+#define XCURSOR_FILE_MINOR 0
125+#define XCURSOR_FILE_VERSION ((XCURSOR_FILE_MAJOR << 16) | (XCURSOR_FILE_MINOR))
126+#define XCURSOR_FILE_HEADER_LEN (4 * 4)
127+#define XCURSOR_FILE_TOC_LEN (3 * 4)
128+
129+typedef struct _XcursorFileToc {
130+ XcursorUInt type; /* chunk type */
131+ XcursorUInt subtype; /* subtype (size for images) */
132+ XcursorUInt position; /* absolute position in file */
133+} XcursorFileToc;
134+
135+typedef struct _XcursorFileHeader {
136+ XcursorUInt magic; /* magic number */
137+ XcursorUInt header; /* byte length of header */
138+ XcursorUInt version; /* file version number */
139+ XcursorUInt ntoc; /* number of toc entries */
140+ XcursorFileToc *tocs; /* table of contents */
141+} XcursorFileHeader;
142+
143+/*
144+ * The rest of the file is a list of chunks, each tagged by type
145+ * and version.
146+ *
147+ * Chunk:
148+ * ChunkHeader
149+ * <extra type-specific header fields>
150+ * <type-specific data>
151+ *
152+ * ChunkHeader:
153+ * CARD32 header bytes in chunk header + type header
154+ * CARD32 type chunk type
155+ * CARD32 subtype chunk subtype
156+ * CARD32 version chunk type version
157+ */
158+
159+#define XCURSOR_CHUNK_HEADER_LEN (4 * 4)
160+
161+typedef struct _XcursorChunkHeader {
162+ XcursorUInt header; /* bytes in chunk header */
163+ XcursorUInt type; /* chunk type */
164+ XcursorUInt subtype; /* chunk subtype (size for images) */
165+ XcursorUInt version; /* version of this type */
166+} XcursorChunkHeader;
167+
168+/*
169+ * Here's a list of the known chunk types
170+ */
171+
172+/*
173+ * Comments consist of a 4-byte length field followed by
174+ * UTF-8 encoded text
175+ *
176+ * Comment:
177+ * ChunkHeader header chunk header
178+ * CARD32 length bytes in text
179+ * LISTofCARD8 text UTF-8 encoded text
180+ */
181+
182+#define XCURSOR_COMMENT_TYPE 0xfffe0001
183+#define XCURSOR_COMMENT_VERSION 1
184+#define XCURSOR_COMMENT_HEADER_LEN (XCURSOR_CHUNK_HEADER_LEN + (1 *4))
185+#define XCURSOR_COMMENT_COPYRIGHT 1
186+#define XCURSOR_COMMENT_LICENSE 2
187+#define XCURSOR_COMMENT_OTHER 3
188+#define XCURSOR_COMMENT_MAX_LEN 0x100000
189+
190+typedef struct _XcursorComment {
191+ XcursorUInt version;
192+ XcursorUInt comment_type;
193+ char *comment;
194+} XcursorComment;
195+
196+/*
197+ * Each cursor image occupies a separate image chunk.
198+ * The length of the image header follows the chunk header
199+ * so that future versions can extend the header without
200+ * breaking older applications
201+ *
202+ * Image:
203+ * ChunkHeader header chunk header
204+ * CARD32 width actual width
205+ * CARD32 height actual height
206+ * CARD32 xhot hot spot x
207+ * CARD32 yhot hot spot y
208+ * CARD32 delay animation delay
209+ * LISTofCARD32 pixels ARGB pixels
210+ */
211+
212+#define XCURSOR_IMAGE_TYPE 0xfffd0002
213+#define XCURSOR_IMAGE_VERSION 1
214+#define XCURSOR_IMAGE_HEADER_LEN (XCURSOR_CHUNK_HEADER_LEN + (5*4))
215+#define XCURSOR_IMAGE_MAX_SIZE 0x7fff /* 32767x32767 max cursor size */
216+
217+typedef struct _XcursorFile XcursorFile;
218+
219+struct _XcursorFile {
220+ void *closure;
221+ int (*read) (XcursorFile *file, unsigned char *buf, int len);
222+ int (*write) (XcursorFile *file, unsigned char *buf, int len);
223+ int (*seek) (XcursorFile *file, long offset, int whence);
224+};
225+
226+typedef struct _XcursorComments {
227+ int ncomment; /* number of comments */
228+ XcursorComment **comments; /* array of XcursorComment pointers */
229+} XcursorComments;
230+
231+/*
232+ * From libXcursor/src/file.c
233+ */
234+
235+static XcursorImage *
236+XcursorImageCreate (int width, int height)
237+{
238+ XcursorImage *image;
239+
240+ image = malloc (sizeof (XcursorImage) +
241+ width * height * sizeof (XcursorPixel));
242+ if (!image)
243+ return NULL;
244+ image->version = XCURSOR_IMAGE_VERSION;
245+ image->pixels = (XcursorPixel *) (image + 1);
246+ image->size = width > height ? width : height;
247+ image->width = width;
248+ image->height = height;
249+ image->delay = 0;
250+ return image;
251+}
252+
253+static void
254+XcursorImageDestroy (XcursorImage *image)
255+{
256+ free (image);
257+}
258+
259+static XcursorImages *
260+XcursorImagesCreate (int size)
261+{
262+ XcursorImages *images;
263+
264+ images = malloc (sizeof (XcursorImages) +
265+ size * sizeof (XcursorImage *));
266+ if (!images)
267+ return NULL;
268+ images->nimage = 0;
269+ images->images = (XcursorImage **) (images + 1);
270+ images->name = NULL;
271+ return images;
272+}
273+
274+void
275+XcursorImagesDestroy (XcursorImages *images)
276+{
277+ int n;
278+
279+ if (!images)
280+ return;
281+
282+ for (n = 0; n < images->nimage; n++)
283+ XcursorImageDestroy (images->images[n]);
284+ if (images->name)
285+ free (images->name);
286+ free (images);
287+}
288+
289+static void
290+XcursorImagesSetName (XcursorImages *images, const char *name)
291+{
292+ char *new;
293+
294+ if (!images || !name)
295+ return;
296+
297+ new = malloc (strlen (name) + 1);
298+
299+ if (!new)
300+ return;
301+
302+ strcpy (new, name);
303+ if (images->name)
304+ free (images->name);
305+ images->name = new;
306+}
307+
308+static XcursorBool
309+_XcursorReadUInt (XcursorFile *file, XcursorUInt *u)
310+{
311+ unsigned char bytes[4];
312+
313+ if (!file || !u)
314+ return XcursorFalse;
315+
316+ if ((*file->read) (file, bytes, 4) != 4)
317+ return XcursorFalse;
318+ *u = ((bytes[0] << 0) |
319+ (bytes[1] << 8) |
320+ (bytes[2] << 16) |
321+ (bytes[3] << 24));
322+ return XcursorTrue;
323+}
324+
325+static void
326+_XcursorFileHeaderDestroy (XcursorFileHeader *fileHeader)
327+{
328+ free (fileHeader);
329+}
330+
331+static XcursorFileHeader *
332+_XcursorFileHeaderCreate (int ntoc)
333+{
334+ XcursorFileHeader *fileHeader;
335+
336+ if (ntoc > 0x10000)
337+ return NULL;
338+ fileHeader = malloc (sizeof (XcursorFileHeader) +
339+ ntoc * sizeof (XcursorFileToc));
340+ if (!fileHeader)
341+ return NULL;
342+ fileHeader->magic = XCURSOR_MAGIC;
343+ fileHeader->header = XCURSOR_FILE_HEADER_LEN;
344+ fileHeader->version = XCURSOR_FILE_VERSION;
345+ fileHeader->ntoc = ntoc;
346+ fileHeader->tocs = (XcursorFileToc *) (fileHeader + 1);
347+ return fileHeader;
348+}
349+
350+static XcursorFileHeader *
351+_XcursorReadFileHeader (XcursorFile *file)
352+{
353+ XcursorFileHeader head, *fileHeader;
354+ XcursorUInt skip;
355+ unsigned int n;
356+
357+ if (!file)
358+ return NULL;
359+
360+ if (!_XcursorReadUInt (file, &head.magic))
361+ return NULL;
362+ if (head.magic != XCURSOR_MAGIC)
363+ return NULL;
364+ if (!_XcursorReadUInt (file, &head.header))
365+ return NULL;
366+ if (!_XcursorReadUInt (file, &head.version))
367+ return NULL;
368+ if (!_XcursorReadUInt (file, &head.ntoc))
369+ return NULL;
370+ skip = head.header - XCURSOR_FILE_HEADER_LEN;
371+ if (skip)
372+ if ((*file->seek) (file, skip, SEEK_CUR) == EOF)
373+ return NULL;
374+ fileHeader = _XcursorFileHeaderCreate (head.ntoc);
375+ if (!fileHeader)
376+ return NULL;
377+ fileHeader->magic = head.magic;
378+ fileHeader->header = head.header;
379+ fileHeader->version = head.version;
380+ fileHeader->ntoc = head.ntoc;
381+ for (n = 0; n < fileHeader->ntoc; n++)
382+ {
383+ if (!_XcursorReadUInt (file, &fileHeader->tocs[n].type))
384+ break;
385+ if (!_XcursorReadUInt (file, &fileHeader->tocs[n].subtype))
386+ break;
387+ if (!_XcursorReadUInt (file, &fileHeader->tocs[n].position))
388+ break;
389+ }
390+ if (n != fileHeader->ntoc)
391+ {
392+ _XcursorFileHeaderDestroy (fileHeader);
393+ return NULL;
394+ }
395+ return fileHeader;
396+}
397+
398+static XcursorBool
399+_XcursorSeekToToc (XcursorFile *file,
400+ XcursorFileHeader *fileHeader,
401+ int toc)
402+{
403+ if (!file || !fileHeader || \
404+ (*file->seek) (file, fileHeader->tocs[toc].position, SEEK_SET) == EOF)
405+ return XcursorFalse;
406+ return XcursorTrue;
407+}
408+
409+static XcursorBool
410+_XcursorFileReadChunkHeader (XcursorFile *file,
411+ XcursorFileHeader *fileHeader,
412+ int toc,
413+ XcursorChunkHeader *chunkHeader)
414+{
415+ if (!file || !fileHeader || !chunkHeader)
416+ return XcursorFalse;
417+ if (!_XcursorSeekToToc (file, fileHeader, toc))
418+ return XcursorFalse;
419+ if (!_XcursorReadUInt (file, &chunkHeader->header))
420+ return XcursorFalse;
421+ if (!_XcursorReadUInt (file, &chunkHeader->type))
422+ return XcursorFalse;
423+ if (!_XcursorReadUInt (file, &chunkHeader->subtype))
424+ return XcursorFalse;
425+ if (!_XcursorReadUInt (file, &chunkHeader->version))
426+ return XcursorFalse;
427+ /* sanity check */
428+ if (chunkHeader->type != fileHeader->tocs[toc].type ||
429+ chunkHeader->subtype != fileHeader->tocs[toc].subtype)
430+ return XcursorFalse;
431+ return XcursorTrue;
432+}
433+
434+#define dist(a,b) ((a) > (b) ? (a) - (b) : (b) - (a))
435+
436+static XcursorDim
437+_XcursorFindBestSize (XcursorFileHeader *fileHeader,
438+ XcursorDim size,
439+ int *nsizesp)
440+{
441+ unsigned int n;
442+ int nsizes = 0;
443+ XcursorDim bestSize = 0;
444+ XcursorDim thisSize;
445+
446+ if (!fileHeader || !nsizesp)
447+ return 0;
448+
449+ for (n = 0; n < fileHeader->ntoc; n++)
450+ {
451+ if (fileHeader->tocs[n].type != XCURSOR_IMAGE_TYPE)
452+ continue;
453+ thisSize = fileHeader->tocs[n].subtype;
454+ if (!bestSize || dist (thisSize, size) < dist (bestSize, size))
455+ {
456+ bestSize = thisSize;
457+ nsizes = 1;
458+ }
459+ else if (thisSize == bestSize)
460+ nsizes++;
461+ }
462+ *nsizesp = nsizes;
463+ return bestSize;
464+}
465+
466+static int
467+_XcursorFindImageToc (XcursorFileHeader *fileHeader,
468+ XcursorDim size,
469+ int count)
470+{
471+ unsigned int toc;
472+ XcursorDim thisSize;
473+
474+ if (!fileHeader)
475+ return 0;
476+
477+ for (toc = 0; toc < fileHeader->ntoc; toc++)
478+ {
479+ if (fileHeader->tocs[toc].type != XCURSOR_IMAGE_TYPE)
480+ continue;
481+ thisSize = fileHeader->tocs[toc].subtype;
482+ if (thisSize != size)
483+ continue;
484+ if (!count)
485+ break;
486+ count--;
487+ }
488+ if (toc == fileHeader->ntoc)
489+ return -1;
490+ return toc;
491+}
492+
493+static XcursorImage *
494+_XcursorReadImage (XcursorFile *file,
495+ XcursorFileHeader *fileHeader,
496+ int toc)
497+{
498+ XcursorChunkHeader chunkHeader;
499+ XcursorImage head;
500+ XcursorImage *image;
501+ int n;
502+ XcursorPixel *p;
503+
504+ if (!file || !fileHeader)
505+ return NULL;
506+
507+ if (!_XcursorFileReadChunkHeader (file, fileHeader, toc, &chunkHeader))
508+ return NULL;
509+ if (!_XcursorReadUInt (file, &head.width))
510+ return NULL;
511+ if (!_XcursorReadUInt (file, &head.height))
512+ return NULL;
513+ if (!_XcursorReadUInt (file, &head.xhot))
514+ return NULL;
515+ if (!_XcursorReadUInt (file, &head.yhot))
516+ return NULL;
517+ if (!_XcursorReadUInt (file, &head.delay))
518+ return NULL;
519+ /* sanity check data */
520+ if (head.width >= 0x10000 || head.height > 0x10000)
521+ return NULL;
522+ if (head.width == 0 || head.height == 0)
523+ return NULL;
524+ if (head.xhot > head.width || head.yhot > head.height)
525+ return NULL;
526+
527+ /* Create the image and initialize it */
528+ image = XcursorImageCreate (head.width, head.height);
529+ if (image == NULL)
530+ return NULL;
531+ if (chunkHeader.version < image->version)
532+ image->version = chunkHeader.version;
533+ image->size = chunkHeader.subtype;
534+ image->xhot = head.xhot;
535+ image->yhot = head.yhot;
536+ image->delay = head.delay;
537+ n = image->width * image->height;
538+ p = image->pixels;
539+ while (n--)
540+ {
541+ if (!_XcursorReadUInt (file, p))
542+ {
543+ XcursorImageDestroy (image);
544+ return NULL;
545+ }
546+ p++;
547+ }
548+ return image;
549+}
550+
551+static XcursorImages *
552+XcursorXcFileLoadImages (XcursorFile *file, int size)
553+{
554+ XcursorFileHeader *fileHeader;
555+ XcursorDim bestSize;
556+ int nsize;
557+ XcursorImages *images;
558+ int n;
559+ int toc;
560+
561+ if (!file || size < 0)
562+ return NULL;
563+ fileHeader = _XcursorReadFileHeader (file);
564+ if (!fileHeader)
565+ return NULL;
566+ bestSize = _XcursorFindBestSize (fileHeader, (XcursorDim) size, &nsize);
567+ if (!bestSize)
568+ {
569+ _XcursorFileHeaderDestroy (fileHeader);
570+ return NULL;
571+ }
572+ images = XcursorImagesCreate (nsize);
573+ if (!images)
574+ {
575+ _XcursorFileHeaderDestroy (fileHeader);
576+ return NULL;
577+ }
578+ for (n = 0; n < nsize; n++)
579+ {
580+ toc = _XcursorFindImageToc (fileHeader, bestSize, n);
581+ if (toc < 0)
582+ break;
583+ images->images[images->nimage] = _XcursorReadImage (file, fileHeader,
584+ toc);
585+ if (!images->images[images->nimage])
586+ break;
587+ images->nimage++;
588+ }
589+ _XcursorFileHeaderDestroy (fileHeader);
590+ if (images->nimage != nsize)
591+ {
592+ XcursorImagesDestroy (images);
593+ images = NULL;
594+ }
595+ return images;
596+}
597+
598+static int
599+_XcursorStdioFileRead (XcursorFile *file, unsigned char *buf, int len)
600+{
601+ FILE *f = file->closure;
602+ return fread (buf, 1, len, f);
603+}
604+
605+static int
606+_XcursorStdioFileWrite (XcursorFile *file, unsigned char *buf, int len)
607+{
608+ FILE *f = file->closure;
609+ return fwrite (buf, 1, len, f);
610+}
611+
612+static int
613+_XcursorStdioFileSeek (XcursorFile *file, long offset, int whence)
614+{
615+ FILE *f = file->closure;
616+ return fseek (f, offset, whence);
617+}
618+
619+static void
620+_XcursorStdioFileInitialize (FILE *stdfile, XcursorFile *file)
621+{
622+ file->closure = stdfile;
623+ file->read = _XcursorStdioFileRead;
624+ file->write = _XcursorStdioFileWrite;
625+ file->seek = _XcursorStdioFileSeek;
626+}
627+
628+static XcursorImages *
629+XcursorFileLoadImages (FILE *file, int size)
630+{
631+ XcursorFile f;
632+
633+ if (!file)
634+ return NULL;
635+
636+ _XcursorStdioFileInitialize (file, &f);
637+ return XcursorXcFileLoadImages (&f, size);
638+}
639+
640+/*
641+ * From libXcursor/src/library.c
642+ */
643+
644+#ifndef ICONDIR
645+#define ICONDIR "/usr/X11R6/lib/X11/icons"
646+#endif
647+
648+#ifndef XCURSORPATH
649+#define XCURSORPATH "~/.icons:/usr/share/icons:/usr/share/pixmaps:~/.cursors:/usr/share/cursors/xorg-x11:"ICONDIR
650+#endif
651+
652+static const char *
653+XcursorLibraryPath (void)
654+{
655+ static const char *path;
656+
657+ if (!path)
658+ {
659+ path = getenv ("XCURSOR_PATH");
660+ if (!path)
661+ path = XCURSORPATH;
662+ }
663+ return path;
664+}
665+
666+static void
667+_XcursorAddPathElt (char *path, const char *elt, int len)
668+{
669+ int pathlen = strlen (path);
670+
671+ /* append / if the path doesn't currently have one */
672+ if (path[0] == '\0' || path[pathlen - 1] != '/')
673+ {
674+ strcat (path, "/");
675+ pathlen++;
676+ }
677+ if (len == -1)
678+ len = strlen (elt);
679+ /* strip leading slashes */
680+ while (len && elt[0] == '/')
681+ {
682+ elt++;
683+ len--;
684+ }
685+ strncpy (path + pathlen, elt, len);
686+ path[pathlen + len] = '\0';
687+}
688+
689+static char *
690+_XcursorBuildThemeDir (const char *dir, const char *theme)
691+{
692+ const char *colon;
693+ const char *tcolon;
694+ char *full;
695+ char *home;
696+ int dirlen;
697+ int homelen;
698+ int themelen;
699+ int len;
700+
701+ if (!dir || !theme)
702+ return NULL;
703+
704+ colon = strchr (dir, ':');
705+ if (!colon)
706+ colon = dir + strlen (dir);
707+
708+ dirlen = colon - dir;
709+
710+ tcolon = strchr (theme, ':');
711+ if (!tcolon)
712+ tcolon = theme + strlen (theme);
713+
714+ themelen = tcolon - theme;
715+
716+ home = NULL;
717+ homelen = 0;
718+ if (*dir == '~')
719+ {
720+ home = getenv ("HOME");
721+ if (!home)
722+ return NULL;
723+ homelen = strlen (home);
724+ dir++;
725+ dirlen--;
726+ }
727+
728+ /*
729+ * add space for any needed directory separators, one per component,
730+ * and one for the trailing null
731+ */
732+ len = 1 + homelen + 1 + dirlen + 1 + themelen + 1;
733+
734+ full = malloc (len);
735+ if (!full)
736+ return NULL;
737+ full[0] = '\0';
738+
739+ if (home)
740+ _XcursorAddPathElt (full, home, -1);
741+ _XcursorAddPathElt (full, dir, dirlen);
742+ _XcursorAddPathElt (full, theme, themelen);
743+ return full;
744+}
745+
746+static char *
747+_XcursorBuildFullname (const char *dir, const char *subdir, const char *file)
748+{
749+ char *full;
750+
751+ if (!dir || !subdir || !file)
752+ return NULL;
753+
754+ full = malloc (strlen (dir) + 1 + strlen (subdir) + 1 + strlen (file) + 1);
755+ if (!full)
756+ return NULL;
757+ full[0] = '\0';
758+ _XcursorAddPathElt (full, dir, -1);
759+ _XcursorAddPathElt (full, subdir, -1);
760+ _XcursorAddPathElt (full, file, -1);
761+ return full;
762+}
763+
764+static const char *
765+_XcursorNextPath (const char *path)
766+{
767+ char *colon = strchr (path, ':');
768+
769+ if (!colon)
770+ return NULL;
771+ return colon + 1;
772+}
773+
774+#define XcursorWhite(c) ((c) == ' ' || (c) == '\t' || (c) == '\n')
775+#define XcursorSep(c) ((c) == ';' || (c) == ',')
776+
777+static char *
778+_XcursorThemeInherits (const char *full)
779+{
780+ char line[8192];
781+ char *result = NULL;
782+ FILE *f;
783+
784+ if (!full)
785+ return NULL;
786+
787+ f = fopen (full, "r");
788+ if (f)
789+ {
790+ while (fgets (line, sizeof (line), f))
791+ {
792+ if (!strncmp (line, "Inherits", 8))
793+ {
794+ char *l = line + 8;
795+ char *r;
796+ while (*l == ' ') l++;
797+ if (*l != '=') continue;
798+ l++;
799+ while (*l == ' ') l++;
800+ result = malloc (strlen (l) + 1);
801+ if (result)
802+ {
803+ r = result;
804+ while (*l)
805+ {
806+ while (XcursorSep(*l) || XcursorWhite (*l)) l++;
807+ if (!*l)
808+ break;
809+ if (r != result)
810+ *r++ = ':';
811+ while (*l && !XcursorWhite(*l) &&
812+ !XcursorSep(*l))
813+ *r++ = *l++;
814+ }
815+ *r++ = '\0';
816+ }
817+ break;
818+ }
819+ }
820+ fclose (f);
821+ }
822+ return result;
823+}
824+
825+static FILE *
826+XcursorScanTheme (const char *theme, const char *name)
827+{
828+ FILE *f = NULL;
829+ char *full;
830+ char *dir;
831+ const char *path;
832+ char *inherits = NULL;
833+ const char *i;
834+
835+ if (!theme || !name)
836+ return NULL;
837+
838+ /*
839+ * Scan this theme
840+ */
841+ for (path = XcursorLibraryPath ();
842+ path && f == NULL;
843+ path = _XcursorNextPath (path))
844+ {
845+ dir = _XcursorBuildThemeDir (path, theme);
846+ if (dir)
847+ {
848+ full = _XcursorBuildFullname (dir, "cursors", name);
849+ if (full)
850+ {
851+ f = fopen (full, "r");
852+ free (full);
853+ }
854+ if (!f && !inherits)
855+ {
856+ full = _XcursorBuildFullname (dir, "", "index.theme");
857+ if (full)
858+ {
859+ inherits = _XcursorThemeInherits (full);
860+ free (full);
861+ }
862+ }
863+ free (dir);
864+ }
865+ }
866+ /*
867+ * Recurse to scan inherited themes
868+ */
869+ for (i = inherits; i && f == NULL; i = _XcursorNextPath (i))
870+ f = XcursorScanTheme (i, name);
871+ if (inherits != NULL)
872+ free (inherits);
873+ return f;
874+}
875+
876+XcursorImages *
877+XcursorLibraryLoadImages (const char *file, const char *theme, int size)
878+{
879+ FILE *f = NULL;
880+ XcursorImages *images = NULL;
881+
882+ if (!file)
883+ return NULL;
884+
885+ if (theme)
886+ f = XcursorScanTheme (theme, file);
887+ if (!f)
888+ f = XcursorScanTheme ("default", file);
889+ if (f)
890+ {
891+ images = XcursorFileLoadImages (f, size);
892+ if (images)
893+ XcursorImagesSetName (images, file);
894+ fclose (f);
895+ }
896+ return images;
897+}
898+
899+static void
900+load_all_cursors_from_dir(const char *path, int size,
901+ void (*load_callback)(XcursorImages *, void *),
902+ void *user_data)
903+{
904+ FILE *f;
905+ DIR *dir = opendir(path);
906+ struct dirent *ent;
907+ char *full;
908+ XcursorImages *images;
909+
910+ if (!dir)
911+ return;
912+
913+ for(ent = readdir(dir); ent; ent = readdir(dir)) {
914+#ifdef _DIRENT_HAVE_D_TYPE
915+ if (ent->d_type != DT_UNKNOWN &&
916+ (ent->d_type != DT_REG && ent->d_type != DT_LNK))
917+ continue;
918+#endif
919+
920+ full = _XcursorBuildFullname(path, "", ent->d_name);
921+ if (!full)
922+ continue;
923+
924+ f = fopen(full, "r");
925+ if (!f) {
926+ free(full);
927+ continue;
928+ }
929+
930+ images = XcursorFileLoadImages(f, size);
931+
932+ if (images) {
933+ XcursorImagesSetName(images, ent->d_name);
934+ load_callback(images, user_data);
935+ }
936+
937+ fclose (f);
938+ free(full);
939+ }
940+
941+ closedir(dir);
942+}
943+
944+/** Load all the cursor of a theme
945+ *
946+ * This function loads all the cursor images of a given theme and its
947+ * inherited themes. Each cursor is loaded into an XcursorImages object
948+ * which is passed to the caller's load callback. If a cursor appears
949+ * more than once across all the inherited themes, the load callback
950+ * will be called multiple times, with possibly different XcursorImages
951+ * object which have the same name. The user is expected to destroy the
952+ * XcursorImages objects passed to the callback with
953+ * XcursorImagesDestroy().
954+ *
955+ * \param theme The name of theme that should be loaded
956+ * \param size The desired size of the cursor images
957+ * \param load_callback A callback function that will be called
958+ * for each cursor loaded. The first parameter is the XcursorImages
959+ * object representing the loaded cursor and the second is a pointer
960+ * to data provided by the user.
961+ * \param user_data The data that should be passed to the load callback
962+ */
963+void
964+xcursor_load_theme(const char *theme, int size,
965+ void (*load_callback)(XcursorImages *, void *),
966+ void *user_data)
967+{
968+ char *full, *dir;
969+ char *inherits = NULL;
970+ const char *path, *i;
971+
972+ if (!theme)
973+ theme = "default";
974+
975+ for (path = XcursorLibraryPath();
976+ path;
977+ path = _XcursorNextPath(path)) {
978+ dir = _XcursorBuildThemeDir(path, theme);
979+ if (!dir)
980+ continue;
981+
982+ full = _XcursorBuildFullname(dir, "cursors", "");
983+
984+ if (full) {
985+ load_all_cursors_from_dir(full, size, load_callback,
986+ user_data);
987+ free(full);
988+ }
989+
990+ if (!inherits) {
991+ full = _XcursorBuildFullname(dir, "", "index.theme");
992+ if (full) {
993+ inherits = _XcursorThemeInherits(full);
994+ free(full);
995+ }
996+ }
997+
998+ free(dir);
999+ }
1000+
1001+ for (i = inherits; i; i = _XcursorNextPath(i))
1002+ xcursor_load_theme(i, size, load_callback, user_data);
1003+
1004+ if (inherits)
1005+ free(inherits);
1006+}
1007
1008=== added file '3rd_party/xcursor/xcursor.h'
1009--- 3rd_party/xcursor/xcursor.h 1970-01-01 00:00:00 +0000
1010+++ 3rd_party/xcursor/xcursor.h 2015-08-27 14:51:37 +0000
1011@@ -0,0 +1,65 @@
1012+/*
1013+ * Copyright © 2002 Keith Packard
1014+ *
1015+ * Permission to use, copy, modify, distribute, and sell this software and its
1016+ * documentation for any purpose is hereby granted without fee, provided that
1017+ * the above copyright notice appear in all copies and that both that
1018+ * copyright notice and this permission notice appear in supporting
1019+ * documentation, and that the name of Keith Packard not be used in
1020+ * advertising or publicity pertaining to distribution of the software without
1021+ * specific, written prior permission. Keith Packard makes no
1022+ * representations about the suitability of this software for any purpose. It
1023+ * is provided "as is" without express or implied warranty.
1024+ *
1025+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
1026+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
1027+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
1028+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
1029+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
1030+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
1031+ * PERFORMANCE OF THIS SOFTWARE.
1032+ */
1033+
1034+#ifndef XCURSOR_H
1035+#define XCURSOR_H
1036+
1037+#include <stdint.h>
1038+
1039+
1040+typedef int XcursorBool;
1041+typedef uint32_t XcursorUInt;
1042+
1043+typedef XcursorUInt XcursorDim;
1044+typedef XcursorUInt XcursorPixel;
1045+
1046+typedef struct _XcursorImage {
1047+ XcursorUInt version; /* version of the image data */
1048+ XcursorDim size; /* nominal size for matching */
1049+ XcursorDim width; /* actual width */
1050+ XcursorDim height; /* actual height */
1051+ XcursorDim xhot; /* hot spot x (must be inside image) */
1052+ XcursorDim yhot; /* hot spot y (must be inside image) */
1053+ XcursorUInt delay; /* animation delay to next frame (ms) */
1054+ XcursorPixel *pixels; /* pointer to pixels */
1055+} XcursorImage;
1056+
1057+/*
1058+ * Other data structures exposed by the library API
1059+ */
1060+typedef struct _XcursorImages {
1061+ int nimage; /* number of images */
1062+ XcursorImage **images; /* array of XcursorImage pointers */
1063+ char *name; /* name used to load images */
1064+} XcursorImages;
1065+
1066+XcursorImages *
1067+XcursorLibraryLoadImages (const char *file, const char *theme, int size);
1068+
1069+void
1070+XcursorImagesDestroy (XcursorImages *images);
1071+
1072+void
1073+xcursor_load_theme(const char *theme, int size,
1074+ void (*load_callback)(XcursorImages *, void *),
1075+ void *user_data);
1076+#endif
1077
1078=== modified file 'CMakeLists.txt'
1079--- CMakeLists.txt 2015-08-11 19:25:04 +0000
1080+++ CMakeLists.txt 2015-08-27 14:51:37 +0000
1081@@ -74,7 +74,7 @@
1082 pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)
1083 pkg_check_modules(QTDBUSTEST libqtdbustest-1 REQUIRED)
1084 pkg_check_modules(QTDBUSMOCK libqtdbusmock-1 REQUIRED)
1085-pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=7)
1086+pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=8)
1087
1088 include_directories(${APPLICATION_API_INCLUDE_DIRS})
1089
1090@@ -157,4 +157,5 @@
1091
1092
1093 # add subdirectories to build
1094+add_subdirectory(3rd_party)
1095 add_subdirectory(src)
1096
1097=== modified file 'README'
1098--- README 2014-12-10 10:33:48 +0000
1099+++ README 2015-08-27 14:51:37 +0000
1100@@ -17,18 +17,27 @@
1101 To avoid building the tests (to speed up the build):
1102 $ cmake -DNO_TESTS=true
1103
1104-To test, enter the demos directory, run:
1105+To test the server, enter the demos directory, and run (NB: server should be run as root):
1106
1107+$ sudo su
1108 $ export QT_QPA_PLATFORM=mirserver
1109+$ export MIR_SERVER_FILE=/tmp/mir_socket
1110+$ unset QT_QPA_PLATFORMTHEME
1111
1112 then run the Qt application of your choice (qmlscene best). As example, try
1113
1114 $ qmlscene qml-demo-shell/qml-demo-shell.qml
1115
1116+prepare the environment for running mir clients:
1117+
1118+$ sudo chmod a+rw /tmp/mir_socket
1119+$ export MIR_SOCKET=/tmp/mir_socket
1120+
1121 and then try running an application:
1122
1123 $ mir_demo_client_egltriangle --desktop_file_hint=/usr/share/applications/gallery-app.desktop
1124 or
1125+$ unset QT_QPA_PLATFORMTHEME
1126 $ export QT_QPA_PLATFORM=ubuntumirclient
1127 $ qmlscene qml-demo-client/qml-demo-client.qml --desktop_file_hint=/usr/share/click/preinstalled/com.ubuntu.calendar/0.4.172/calendar-app.desktop
1128
1129
1130=== modified file 'debian/changelog'
1131--- debian/changelog 2015-08-24 05:10:23 +0000
1132+++ debian/changelog 2015-08-27 14:51:37 +0000
1133@@ -1,3 +1,4 @@
1134+<<<<<<< TREE
1135 qtmir (0.4.5+15.10.20150817-0ubuntu1) wily; urgency=medium
1136
1137 *
1138@@ -5,6 +6,16 @@
1139 -- CI Train Bot <ci-train-bot@canonical.com> Mon, 17 Aug 2015 19:28:26 +0000
1140
1141 qtmir (0.4.5+15.10.20150812.1-0ubuntu1) vivid; urgency=medium
1142+=======
1143+qtmir (0.4.6) UNRELEASED; urgency=medium
1144+
1145+ * Enable multiple MirSurfaceItems rendering the same MirSurface
1146+ * Add better MultiMonitor support
1147+
1148+ -- Daniel d'Andrada <daniel.dandrada@canonical.com> Mon, 27 Jul 2015 13:16:20 -0300
1149+
1150+qtmir (0.4.5+15.04.20150812.1-0ubuntu1) vivid; urgency=medium
1151+>>>>>>> MERGE-SOURCE
1152
1153 [ Daniel van Vugt ]
1154 * MirSurfaceItem: Remove an unnecessary and potentially infinite loop
1155@@ -20,7 +31,7 @@
1156
1157 qtmir (0.4.5+15.10.20150804.1-0ubuntu1) vivid; urgency=medium
1158
1159- * Dual release with wily
1160+ * Vivid release in step with wily
1161
1162 -- Gerry Boland <gerry.boland@canonical.com> Tue, 04 Aug 2015 17:21:12 +0000
1163
1164
1165=== modified file 'debian/copyright'
1166--- debian/copyright 2015-08-11 12:10:03 +0000
1167+++ debian/copyright 2015-08-27 14:51:37 +0000
1168@@ -13,6 +13,27 @@
1169 Copyright: 2013-2014 Canonical Ltd.
1170 License: LGPL-3
1171
1172+Files: 3rd_party/xcursor/*
1173+Copyright: 2002 Keith Packard
1174+License: Keith Packard
1175+ Permission to use, copy, modify, distribute, and sell this software and its
1176+ documentation for any purpose is hereby granted without fee, provided that
1177+ the above copyright notice appear in all copies and that both that
1178+ copyright notice and this permission notice appear in supporting
1179+ documentation, and that the name of Keith Packard not be used in
1180+ advertising or publicity pertaining to distribution of the software without
1181+ specific, written prior permission. Keith Packard makes no
1182+ representations about the suitability of this software for any purpose. It
1183+ is provided "as is" without express or implied warranty.
1184+ .
1185+ KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
1186+ INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
1187+ EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
1188+ CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
1189+ DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
1190+ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
1191+ PERFORMANCE OF THIS SOFTWARE.
1192+
1193 License: LGPL-3
1194 This package is free software; you can redistribute it and/or
1195 modify it under the terms of the GNU Lesser General Public
1196
1197=== added file 'demos/qml-demo-shell/ResizeArea.qml'
1198--- demos/qml-demo-shell/ResizeArea.qml 1970-01-01 00:00:00 +0000
1199+++ demos/qml-demo-shell/ResizeArea.qml 2015-08-27 14:51:37 +0000
1200@@ -0,0 +1,119 @@
1201+import QtQuick 2.4
1202+import Unity.Application 0.1
1203+
1204+MouseArea {
1205+ id: root
1206+
1207+ // to be set from outside
1208+ property Item target
1209+ property bool leftBorder: false
1210+ property bool rightBorder: false
1211+ property bool topBorder: false
1212+ property bool bottomBorder: false
1213+
1214+ property bool dragging: false
1215+ property real startX
1216+ property real startY
1217+ property real startWidth
1218+ property real startHeight
1219+
1220+ hoverEnabled: true
1221+
1222+ property string cursorName: {
1223+ if (leftBorder && !topBorder && !bottomBorder) {
1224+ return "left_side";
1225+ } else if (rightBorder && !topBorder && !bottomBorder) {
1226+ return "right_side";
1227+ } else if (topBorder && !leftBorder && !rightBorder) {
1228+ return "top_side";
1229+ } else if (bottomBorder && !leftBorder && !rightBorder) {
1230+ return "bottom_side";
1231+ } else if (leftBorder && topBorder) {
1232+ return "top_left_corner";
1233+ } else if (leftBorder && bottomBorder) {
1234+ return "bottom_left_corner";
1235+ } else if (rightBorder && topBorder) {
1236+ return "top_right_corner";
1237+ } else if (rightBorder && bottomBorder) {
1238+ return "bottom_right_corner";
1239+ }
1240+ }
1241+
1242+ function updateCursorName() {
1243+ if (containsMouse || pressed) {
1244+ Mir.cursorName = root.cursorName;
1245+ } else {
1246+ Mir.cursorName = "";
1247+ }
1248+ }
1249+
1250+ onContainsMouseChanged: {
1251+ updateCursorName();
1252+ }
1253+
1254+ onPressedChanged: {
1255+ updateCursorName();
1256+ if (pressed) {
1257+ var pos = mapToItem(target.parent, mouseX, mouseY);
1258+ startX = pos.x;
1259+ startY = pos.y;
1260+ startWidth = target.width;
1261+ startHeight = target.height;
1262+ dragging = true;
1263+ } else {
1264+ dragging = false;
1265+ }
1266+ }
1267+
1268+ onMouseXChanged: {
1269+ if (!pressed || !dragging) {
1270+ return;
1271+ }
1272+
1273+ var pos = mapToItem(target.parent, mouseX, mouseY);
1274+
1275+ if (leftBorder) {
1276+ if (startX + startWidth - pos.x > target.minWidth) {
1277+ target.x = pos.x;
1278+ target.width = startX + startWidth - target.x;
1279+ startX = target.x;
1280+ startWidth = target.width;
1281+ }
1282+
1283+ } else if (rightBorder) {
1284+ var deltaX = pos.x - startX;
1285+ if (startWidth + deltaX >= target.minWidth) {
1286+ target.width = startWidth + deltaX;
1287+ } else {
1288+ target.width = target.minWidth;
1289+ }
1290+ }
1291+ }
1292+
1293+ onMouseYChanged: {
1294+ if (!pressed || !dragging) {
1295+ return;
1296+ }
1297+
1298+ var pos = mapToItem(target.parent, mouseX, mouseY);
1299+
1300+ if (topBorder) {
1301+
1302+ if (startY + startHeight - pos.y > target.minHeight) {
1303+ target.y = pos.y;
1304+ target.height = startY + startHeight - target.y;
1305+ startY = target.y;
1306+ startHeight = target.height;
1307+ }
1308+
1309+ } else if (bottomBorder) {
1310+ var deltaY = pos.y - startY;
1311+ if (startHeight + deltaY >= target.minHeight) {
1312+ target.height = startHeight + deltaY;
1313+ } else {
1314+ target.height = target.minHeight;
1315+ }
1316+ }
1317+ }
1318+}
1319+
1320
1321=== added file 'demos/qml-demo-shell/TitleBar.qml'
1322--- demos/qml-demo-shell/TitleBar.qml 1970-01-01 00:00:00 +0000
1323+++ demos/qml-demo-shell/TitleBar.qml 2015-08-27 14:51:37 +0000
1324@@ -0,0 +1,72 @@
1325+import QtQuick 2.4
1326+import Unity.Application 0.1
1327+
1328+Rectangle {
1329+ id: root
1330+ color: "brown"
1331+ height: 25
1332+
1333+ property Item target
1334+ property bool cloned: false
1335+ property bool closeRequested: false
1336+ signal cloneRequested()
1337+
1338+ MouseArea {
1339+ anchors.fill: parent
1340+ property real distanceX
1341+ property real distanceY
1342+ property bool dragging
1343+ onPressedChanged: {
1344+ if (pressed) {
1345+ var pos = mapToItem(root.target, mouseX, mouseY);
1346+ distanceX = pos.x;
1347+ distanceY = pos.y;
1348+ dragging = true;
1349+ Mir.cursorName = "grabbing";
1350+ } else {
1351+ dragging = false;
1352+ Mir.cursorName = "";
1353+ }
1354+ }
1355+ onMouseXChanged: {
1356+ if (dragging) {
1357+ var pos = mapToItem(root.target.parent, mouseX, mouseY);
1358+ root.target.x = pos.x - distanceX;
1359+ root.target.y = pos.y - distanceY;
1360+ }
1361+ }
1362+ }
1363+
1364+ Text {
1365+ visible: !root.cloned
1366+ anchors.top: parent.top
1367+ anchors.bottom: parent.bottom
1368+ text: "CLONE"
1369+ MouseArea {
1370+ anchors.fill: parent
1371+ onClicked: {
1372+ root.cloneRequested();
1373+ }
1374+ }
1375+ }
1376+
1377+ Text {
1378+ anchors.top: parent.top
1379+ anchors.bottom: parent.bottom
1380+ anchors.right: parent.right
1381+ width: contentWidth
1382+ text: "X"
1383+ fontSizeMode: Text.VerticalFit
1384+ minimumPixelSize: 10; font.pixelSize: 72
1385+ font.weight: Font.Bold
1386+ horizontalAlignment: Text.AlignRight
1387+ verticalAlignment: Text.AlignVCenter
1388+ MouseArea {
1389+ anchors.fill: parent
1390+ onClicked: {
1391+ root.closeRequested = true;
1392+ }
1393+ }
1394+ }
1395+}
1396+
1397
1398=== modified file 'demos/qml-demo-shell/Window.qml'
1399--- demos/qml-demo-shell/Window.qml 2014-05-22 13:47:20 +0000
1400+++ demos/qml-demo-shell/Window.qml 2015-08-27 14:51:37 +0000
1401@@ -1,46 +1,173 @@
1402 import QtQuick 2.0
1403+import Unity.Application 0.1
1404
1405 Rectangle {
1406 id: root
1407 color: "red"
1408- readonly property int margin: 5
1409-
1410- function setSurface(surface) {
1411- surface.parent = root //windowContainer;
1412- root.width = surface.width //+ 2*margin;
1413- root.height = surface.height //+ margin + title.height;
1414-
1415- surface.anchors.fill = root //windowContainer;
1416-// surface.opacity = 0.99;
1417-
1418-// title.text = surface.name;
1419- }
1420-
1421-// Text {
1422-// id: title
1423-// anchors {
1424-// left: parent.left
1425-// right: parent.right
1426-// top: parent.top
1427-// leftMargin: margin
1428-// rightMargin: margin
1429-// }
1430-// font.pixelSize: 40
1431-// }
1432-
1433- Rectangle {
1434- id: windowContainer
1435- anchors {
1436- left: parent.left
1437- right: parent.right
1438- top: parent.top
1439-// top: title.bottom
1440- bottom: parent.bottom
1441- leftMargin: margin
1442- rightMargin: margin
1443- bottomMargin: margin
1444- }
1445- color: "pink"
1446- opacity: 0.2
1447+
1448+ property alias surface: surfaceItem.surface
1449+ property bool touchMode: false
1450+
1451+ width: surfaceItem.implicitWidth + 2*borderThickness
1452+ height: surfaceItem.implicitHeight + 2*borderThickness + titleBar.height
1453+
1454+ signal cloneRequested()
1455+ property bool cloned: false
1456+
1457+ onTouchModeChanged: {
1458+ if (touchMode) {
1459+ x -= borderThicknessTouch - borderThicknessMouse;
1460+ width += 2*(borderThicknessTouch - borderThicknessMouse);
1461+ y -= borderThicknessTouch - borderThicknessMouse;
1462+ height += 2*(borderThicknessTouch - borderThicknessMouse);
1463+ } else {
1464+ x += borderThicknessTouch - borderThicknessMouse;
1465+ width -= 2*(borderThicknessTouch - borderThicknessMouse);
1466+ y += borderThicknessTouch - borderThicknessMouse;
1467+ height -= 2*(borderThicknessTouch - borderThicknessMouse);
1468+ }
1469+ }
1470+
1471+ readonly property real minWidth: 100
1472+ readonly property real minHeight: 100
1473+
1474+ property real borderThickness: touchMode ? borderThicknessTouch : borderThicknessMouse
1475+ readonly property real borderThicknessMouse: 10
1476+ readonly property real borderThicknessTouch: 40
1477+
1478+ states: [
1479+ State {
1480+ name: "closed"
1481+ when: (surface && !surface.live) || titleBar.closeRequested
1482+ }
1483+ ]
1484+ transitions: [
1485+ Transition {
1486+ from: ""; to: "closed"
1487+ SequentialAnimation {
1488+ PropertyAnimation {
1489+ target: root
1490+ property: "scale"
1491+ easing.type: Easing.InBack
1492+ duration: 400
1493+ from: 1.0
1494+ to: 0.0
1495+ }
1496+ ScriptAction { script: { root.destroy(); } }
1497+ }
1498+ }
1499+ ]
1500+
1501+ ResizeArea {
1502+ anchors.top: root.top
1503+ anchors.bottom: root.bottom
1504+ anchors.margins: root.borderThickness
1505+ width: root.borderThickness
1506+
1507+ leftBorder: true
1508+ target: root
1509+ }
1510+ ResizeArea {
1511+ anchors.right: root.right
1512+ anchors.top: root.top
1513+ anchors.topMargin: root.borderThickness
1514+ anchors.bottom: root.bottom
1515+ anchors.bottomMargin: root.borderThickness
1516+ width: root.borderThickness
1517+
1518+ rightBorder: true
1519+ target: root
1520+ }
1521+ ResizeArea {
1522+ anchors.left: root.left
1523+ anchors.leftMargin: root.borderThickness
1524+ anchors.right: root.right
1525+ anchors.rightMargin: root.borderThickness
1526+ anchors.top: root.top
1527+ height: root.borderThickness
1528+
1529+ topBorder: true
1530+ target: root
1531+ }
1532+ ResizeArea {
1533+ anchors.left: root.left
1534+ anchors.leftMargin: root.borderThickness
1535+ anchors.right: root.right
1536+ anchors.rightMargin: root.borderThickness
1537+ anchors.bottom: root.bottom
1538+ height: root.borderThickness
1539+
1540+ bottomBorder: true
1541+ target: root
1542+ }
1543+ ResizeArea {
1544+ anchors.left: root.left
1545+ anchors.top: root.top
1546+ width: root.borderThickness
1547+ height: root.borderThickness
1548+
1549+ topBorder: true
1550+ leftBorder: true
1551+ target: root
1552+ }
1553+ ResizeArea {
1554+ anchors.left: root.left
1555+ anchors.bottom: root.bottom
1556+ width: root.borderThickness
1557+ height: root.borderThickness
1558+
1559+ bottomBorder: true
1560+ leftBorder: true
1561+ target: root
1562+ }
1563+ ResizeArea {
1564+ anchors.right: root.right
1565+ anchors.top: root.top
1566+ width: root.borderThickness
1567+ height: root.borderThickness
1568+
1569+ topBorder: true
1570+ rightBorder: true
1571+ target: root
1572+ }
1573+ ResizeArea {
1574+ anchors.right: root.right
1575+ anchors.bottom: root.bottom
1576+ width: root.borderThickness
1577+ height: root.borderThickness
1578+
1579+ bottomBorder: true
1580+ rightBorder: true
1581+ target: root
1582+ }
1583+
1584+ TitleBar {
1585+ id: titleBar
1586+ anchors.left: parent.left
1587+ anchors.leftMargin: root.borderThickness
1588+ anchors.right: parent.right
1589+ anchors.rightMargin: root.borderThickness
1590+ anchors.top: parent.top
1591+ anchors.topMargin: root.borderThickness
1592+
1593+ target: root
1594+ cloned: root.cloned
1595+ onCloneRequested: { root.cloneRequested(); }
1596+ }
1597+
1598+ MirSurfaceItem {
1599+ id: surfaceItem
1600+
1601+ anchors.top: titleBar.bottom
1602+ anchors.left: parent.left
1603+ anchors.leftMargin: root.borderThickness
1604+ anchors.right: parent.right
1605+ anchors.rightMargin: root.borderThickness
1606+ anchors.bottom: parent.bottom
1607+ anchors.bottomMargin: root.borderThickness
1608+
1609+ consumesInput: !root.cloned
1610+ surfaceWidth: root.cloned ? -1 : width
1611+ surfaceHeight: root.cloned ? -1 : height
1612 }
1613 }
1614
1615=== added file 'demos/qml-demo-shell/WindowBufferSized.qml'
1616--- demos/qml-demo-shell/WindowBufferSized.qml 1970-01-01 00:00:00 +0000
1617+++ demos/qml-demo-shell/WindowBufferSized.qml 2015-08-27 14:51:37 +0000
1618@@ -0,0 +1,178 @@
1619+import QtQuick 2.0
1620+import Unity.Application 0.1
1621+
1622+Rectangle {
1623+ id: root
1624+ color: "red"
1625+
1626+ property alias surface: surfaceItem.surface
1627+ property bool touchMode: false
1628+
1629+ width: surfaceItem.width + (borderThickness*2)
1630+ height: surfaceItem.height + titleBar.height + (borderThickness*2)
1631+
1632+ signal cloneRequested()
1633+
1634+ onTouchModeChanged: {
1635+ if (touchMode) {
1636+ x -= borderThicknessTouch - borderThicknessMouse;
1637+ width += 2*(borderThicknessTouch - borderThicknessMouse);
1638+ y -= borderThicknessTouch - borderThicknessMouse;
1639+ height += 2*(borderThicknessTouch - borderThicknessMouse);
1640+ } else {
1641+ x += borderThicknessTouch - borderThicknessMouse;
1642+ width -= 2*(borderThicknessTouch - borderThicknessMouse);
1643+ y += borderThicknessTouch - borderThicknessMouse;
1644+ height -= 2*(borderThicknessTouch - borderThicknessMouse);
1645+ }
1646+ }
1647+
1648+ readonly property real minWidth: 100
1649+ readonly property real minHeight: 100
1650+
1651+ property real borderThickness: touchMode ? borderThicknessTouch : borderThicknessMouse
1652+ readonly property real borderThicknessMouse: 10
1653+ readonly property real borderThicknessTouch: 40
1654+
1655+ states: [
1656+ State {
1657+ name: "closed"
1658+ when: (surface && !surface.live) || titleBar.closeRequested
1659+ }
1660+ ]
1661+ transitions: [
1662+ Transition {
1663+ from: ""; to: "closed"
1664+ SequentialAnimation {
1665+ PropertyAnimation {
1666+ target: root
1667+ property: "scale"
1668+ easing.type: Easing.InBack
1669+ duration: 400
1670+ from: 1.0
1671+ to: 0.0
1672+ }
1673+ ScriptAction { script: { root.destroy(); } }
1674+ }
1675+ }
1676+ ]
1677+
1678+
1679+ MouseArea {
1680+ id: resizeArea
1681+
1682+ anchors.fill: parent
1683+
1684+ property real startX
1685+ property real startY
1686+ property real startWidth
1687+ property real startHeight
1688+ property bool leftBorder
1689+ property bool rightBorder
1690+ property bool topBorder
1691+ property bool bottomBorder
1692+ property bool dragging
1693+ onPressedChanged: {
1694+ if (pressed) {
1695+ var pos = mapToItem(root.parent, mouseX, mouseY);
1696+ startX = pos.x;
1697+ startY = pos.y;
1698+ startWidth = surfaceItem.width;
1699+ startHeight = surfaceItem.height;
1700+ leftBorder = mouseX > 0 && mouseX < root.borderThickness;
1701+ rightBorder = mouseX > (root.width - root.borderThickness) && mouseX < root.width;
1702+ topBorder = mouseY > 0 && mouseY < root.borderThickness;
1703+ bottomBorder = mouseY > (root.height - root.borderThickness) && mouseY < root.height;
1704+ dragging = true;
1705+ } else {
1706+ dragging = false;
1707+ }
1708+ }
1709+
1710+ onMouseXChanged: {
1711+ if (!pressed || !dragging) {
1712+ return;
1713+ }
1714+
1715+ var pos = mapToItem(root.parent, mouseX, mouseY);
1716+
1717+ var deltaX = pos.x - startX;
1718+ if (leftBorder) {
1719+ if (startWidth - deltaX >= root.minWidth) {
1720+ surfaceItem.surfaceWidth = startWidth - deltaX;
1721+ } else {
1722+ surfaceItem.surfaceWidth = root.minWidth;
1723+ }
1724+ } else if (rightBorder) {
1725+ if (startWidth + deltaX >= root.minWidth) {
1726+ surfaceItem.surfaceWidth = startWidth + deltaX;
1727+ } else {
1728+ surfaceItem.surfaceWidth = root.minWidth;
1729+ }
1730+ }
1731+ }
1732+
1733+ onMouseYChanged: {
1734+ if (!pressed || !dragging) {
1735+ return;
1736+ }
1737+
1738+ var pos = mapToItem(root.parent, mouseX, mouseY);
1739+
1740+ var deltaY = pos.y - startY;
1741+ if (topBorder) {
1742+ if (startHeight - deltaY >= root.minHeight) {
1743+ surfaceItem.surfaceHeight = startHeight - deltaY;
1744+ } else {
1745+ surfaceItem.surfaceHeight = root.minHeight;
1746+ }
1747+ } else if (bottomBorder) {
1748+ if (startHeight + deltaY >= root.minHeight) {
1749+ surfaceItem.surfaceHeight = startHeight + deltaY;
1750+ } else {
1751+ surfaceItem.surfaceHeight = root.minHeight;
1752+ }
1753+ }
1754+ }
1755+ }
1756+
1757+ TitleBar {
1758+ id: titleBar
1759+ anchors.left: parent.left
1760+ anchors.leftMargin: root.borderThickness
1761+ anchors.right: parent.right
1762+ anchors.rightMargin: root.borderThickness
1763+ anchors.top: parent.top
1764+ anchors.topMargin: root.borderThickness
1765+
1766+ target: root
1767+ cloned: root.cloned
1768+ onCloneRequested: { root.cloneRequested(); }
1769+ }
1770+
1771+ MirSurfaceItem {
1772+ id: surfaceItem
1773+
1774+ width: surface ? surface.size.width : 50
1775+ height: surface ? surface.size.height : 50
1776+
1777+ onWidthChanged: {
1778+ if (resizeArea.dragging && resizeArea.leftBorder) {
1779+ root.x = resizeArea.startX + resizeArea.startWidth - surfaceItem.width;
1780+ }
1781+ }
1782+
1783+ onHeightChanged: {
1784+ if (resizeArea.dragging && resizeArea.topBorder) {
1785+ root.y = resizeArea.startY + resizeArea.startHeight - surfaceItem.height;
1786+ }
1787+ }
1788+
1789+ anchors.top: titleBar.bottom
1790+ anchors.left: parent.left
1791+ anchors.leftMargin: root.borderThickness
1792+
1793+ consumesInput: true
1794+ }
1795+}
1796+
1797
1798=== modified file 'demos/qml-demo-shell/qml-demo-shell.qml'
1799--- demos/qml-demo-shell/qml-demo-shell.qml 2015-05-01 13:31:30 +0000
1800+++ demos/qml-demo-shell/qml-demo-shell.qml 2015-08-27 14:51:37 +0000
1801@@ -1,5 +1,7 @@
1802-import QtQuick 2.0
1803+import QtQuick 2.4
1804+import QtQuick.Window 2.2
1805 import Unity.Application 0.1
1806+import Unity.Screens 0.1
1807
1808 Rectangle {
1809 id: root
1810@@ -12,11 +14,26 @@
1811 console.log("\"Volume Down\" pressed");
1812 }
1813
1814+ property bool resizeModeStretch: true
1815+
1816 gradient: Gradient {
1817 GradientStop { position: 0.0; color: "lightsteelblue" }
1818 GradientStop { position: 1.0; color: "pink" }
1819 }
1820
1821+ property bool thumbFriendlyBorders: false
1822+
1823+ MultiPointTouchArea {
1824+ anchors.fill: parent
1825+ mouseEnabled: false
1826+ onPressed: {
1827+ root.thumbFriendlyBorders = true;
1828+ }
1829+ onReleased: {
1830+ root.thumbFriendlyBorders = false;
1831+ }
1832+ }
1833+
1834 Image {
1835 id: unityLogo
1836 source: "UnityLogo.png"
1837@@ -35,55 +52,8 @@
1838 loops: Animation.Infinite
1839 }
1840
1841- }
1842-
1843- MultiPointTouchArea {
1844- anchors.fill: parent
1845- minimumTouchPoints: 1
1846- maximumTouchPoints: 1
1847- touchPoints: [
1848- TouchPoint { id: point }
1849- ]
1850- property Item window: null
1851- property real previousX: 0
1852- property real previousY: 0
1853-
1854- onPressed: {
1855- // if at least 2 touch points are within a Window, select that Window
1856- window = windowContainer.childAt(point.x, point.y);
1857-
1858- // save mouse position
1859- previousX = point.x
1860- previousY = point.y
1861- }
1862-
1863- onUpdated: {
1864- if (!window) return;
1865-
1866- var offset = point.x - previousX
1867- if (window.width > 100) {
1868- window.width += offset
1869- }
1870- previousX = point.x
1871-
1872- offset = point.y - previousY
1873- if (window.height > 100) {
1874- window.height += offset
1875- }
1876- previousY = point.y
1877- }
1878-
1879- onReleased: {
1880- window = null
1881- print(window.width, window.height)
1882- }
1883-
1884 MultiPointTouchArea {
1885- id: touchArea
1886- x: unityLogo.x
1887- y: unityLogo.y
1888- width: unityLogo.width
1889- height: unityLogo.height
1890+ anchors.fill: parent
1891 minimumTouchPoints:1
1892 maximumTouchPoints:1
1893 onPressed: {
1894@@ -96,21 +66,15 @@
1895 }
1896 }
1897 }
1898-
1899- Item {
1900- id: windowContainer
1901- anchors.fill: parent
1902- }
1903- }
1904-
1905- Rectangle {
1906- width: 30; height: 30
1907- color: "green"
1908- x: point.x
1909- y: point.y
1910- }
1911-
1912- Rectangle {
1913+ }
1914+
1915+ Item {
1916+ id: windowContainer
1917+ anchors.fill: root
1918+ }
1919+
1920+ Rectangle {
1921+ id: quitButton
1922 width: 60
1923 height: 40
1924 color: "red"
1925@@ -125,24 +89,90 @@
1926 }
1927 }
1928
1929+ Rectangle {
1930+ id: resizeButton
1931+ width: 90
1932+ height: 40
1933+ color: "blue"
1934+ anchors { right: quitButton.left; bottom: parent.bottom }
1935+ Text {
1936+ anchors.centerIn: parent
1937+ text: root.resizeModeStretch ? "Stretch" : "Wait Resize"
1938+ color: "white"
1939+ }
1940+ MouseArea {
1941+ anchors.fill: parent
1942+ onClicked: { root.resizeModeStretch = !root.resizeModeStretch; }
1943+ }
1944+ }
1945+
1946+ Rectangle {
1947+ width: 40
1948+ height: 40
1949+ color: "green"
1950+ anchors { right: resizeButton.left; bottom: parent.bottom }
1951+ Text {
1952+ anchors.centerIn: parent
1953+ text: "⟳"
1954+ color: "white"
1955+ font.pixelSize: 35
1956+ }
1957+ MouseArea {
1958+ anchors.fill: parent
1959+ onClicked: { root.rotation += 180; }
1960+ }
1961+ }
1962+
1963+ Component {
1964+ id: windowStretchComponent
1965+ Window {
1966+ x: 50
1967+ y: 50
1968+ //width: 200
1969+ //height: 200
1970+ touchMode: root.thumbFriendlyBorders
1971+
1972+ onCloneRequested: {
1973+ var window = windowStretchComponent.createObject(windowContainer);
1974+ window.cloned = true;
1975+ window.surface = surface;
1976+ }
1977+ }
1978+ }
1979+
1980+ Component {
1981+ id: windowWaitResizeComponent
1982+ WindowBufferSized {
1983+ x: 50
1984+ y: 50
1985+ touchMode: root.thumbFriendlyBorders
1986+
1987+ onCloneRequested: {
1988+ var window = windowStretchComponent.createObject(windowContainer);
1989+ window.cloned = true;
1990+ window.surface = surface;
1991+ }
1992+ }
1993+ }
1994+
1995+ property var windowComponent: resizeModeStretch ? windowStretchComponent : windowWaitResizeComponent
1996+
1997 Connections {
1998 target: SurfaceManager
1999 onSurfaceCreated: {
2000 print("new surface", surface.name)
2001
2002- var windowComponent = Qt.createComponent("Window.qml");
2003 var window = windowComponent.createObject(windowContainer);
2004- window.setSurface(surface);
2005+ if (!window) {
2006+ console.warn(windowComponent.errorString());
2007+ return;
2008+ }
2009+
2010+ window.surface = surface;
2011
2012 openAnimation.target = window;
2013 openAnimation.start();
2014 }
2015-
2016- onSurfaceDestroyed: {
2017- print("surface destroying", surface.name)
2018- closeAnimation.surface = surface;
2019- closeAnimation.start();
2020- }
2021 }
2022
2023 NumberAnimation {
2024@@ -152,6 +182,8 @@
2025 duration: 1200; easing.type: Easing.InOutQuad
2026 }
2027
2028+ Cursor {}
2029+
2030 SequentialAnimation {
2031 id: closeAnimation
2032 property variant surface: null
2033@@ -169,4 +201,72 @@
2034 }
2035 }
2036 }
2037+
2038+
2039+ Component {
2040+ id: window1
2041+ Window {
2042+ color: "lightgreen"
2043+ visible: true // if not set visible, Window is not created!!
2044+
2045+ Image {
2046+ id: unityLogo1
2047+ source: "UnityLogo.png"
2048+ fillMode: Image.PreserveAspectFit
2049+ anchors.centerIn: parent
2050+ width: 600
2051+ height: 600
2052+
2053+ RotationAnimation {
2054+ id: logoAnimation1
2055+ target: unityLogo1
2056+ from: 359
2057+ to: 0
2058+ duration: 7000
2059+ easing.type: Easing.Linear
2060+ loops: Animation.Infinite
2061+ }
2062+ Component.onCompleted: print("new window!!")
2063+ Component.onDestruction: print("window destroyed!!")
2064+ }
2065+
2066+ Rectangle {
2067+ width: 50; height: 50
2068+ color: "blue"
2069+ x: point1.x
2070+ y: point1.y
2071+ }
2072+
2073+ MultiPointTouchArea {
2074+ anchors.fill: parent
2075+ minimumTouchPoints: 1
2076+ maximumTouchPoints: 1
2077+ touchPoints: [
2078+ TouchPoint { id: point1 }
2079+ ]
2080+ onPressed: {
2081+ if (logoAnimation1.paused) {
2082+ logoAnimation1.resume();
2083+ } else if (logoAnimation1.running) {
2084+ logoAnimation1.pause();
2085+ } else {
2086+ logoAnimation1.start();
2087+ }
2088+ }
2089+ }
2090+ }
2091+ }
2092+
2093+ Screens {
2094+ id: screens
2095+ property variant secondWindow: null
2096+ onScreenAdded: {
2097+ print("Screen added!!")
2098+ secondWindow = window1.createObject(root)
2099+ }
2100+ onScreenRemoved: {
2101+ print("Screen removed!!!")
2102+ secondWindow.destroy();
2103+ }
2104+ }
2105 }
2106
2107=== modified file 'src/common/debughelpers.cpp'
2108--- src/common/debughelpers.cpp 2015-05-13 09:40:03 +0000
2109+++ src/common/debughelpers.cpp 2015-08-27 14:51:37 +0000
2110@@ -208,6 +208,17 @@
2111 }
2112 }
2113
2114+QString mirPointerEventToString(MirPointerEvent const* event)
2115+{
2116+ QString string = QString("MirPointerEvent(x=%1,y=%2,relative_x=%3,relative_y=%4)")
2117+ .arg(mir_pointer_event_axis_value(event, mir_pointer_axis_x))
2118+ .arg(mir_pointer_event_axis_value(event, mir_pointer_axis_y))
2119+ .arg(mir_pointer_event_axis_value(event, mir_pointer_axis_relative_x))
2120+ .arg(mir_pointer_event_axis_value(event, mir_pointer_axis_relative_y));
2121+
2122+ return string;
2123+}
2124+
2125 QString mirTouchEventToString(MirTouchEvent const* event)
2126 {
2127 const int pointerCount = mir_touch_event_point_count(event);
2128
2129=== modified file 'src/common/debughelpers.h'
2130--- src/common/debughelpers.h 2015-06-24 23:08:44 +0000
2131+++ src/common/debughelpers.h 2015-08-27 14:51:37 +0000
2132@@ -36,6 +36,7 @@
2133
2134 const char *applicationStateToStr(int state);
2135
2136+QString mirPointerEventToString(MirPointerEvent const* event);
2137 QString mirTouchEventToString(MirTouchEvent const* event);
2138 const char *mirTouchActionToString(MirTouchAction touchAction);
2139
2140
2141=== modified file 'src/modules/Unity/Application/CMakeLists.txt'
2142--- src/modules/Unity/Application/CMakeLists.txt 2015-06-15 17:01:28 +0000
2143+++ src/modules/Unity/Application/CMakeLists.txt 2015-08-27 14:51:37 +0000
2144@@ -8,6 +8,7 @@
2145 ${UBUNTU_APP_LAUNCH_INCLUDE_DIRS}
2146 ${CMAKE_SOURCE_DIR}/src/platforms/mirserver
2147 ${CMAKE_SOURCE_DIR}/src/common
2148+ ${CMAKE_SOURCE_DIR}/3rd_party/xcursor
2149 ${GSETTINGS_QT_INCLUDE_DIRS}
2150
2151 ${LTTNG_INCLUDE_DIRS}
2152@@ -26,6 +27,7 @@
2153 application.cpp
2154 ../../../common/abstractdbusservicemonitor.cpp
2155 ../../../common/debughelpers.cpp
2156+ cursorimageprovider.cpp
2157 desktopfilereader.cpp
2158 plugin.cpp
2159 applicationscreenshotprovider.cpp
2160@@ -33,8 +35,12 @@
2161 taskcontroller.cpp
2162 mirsurfacemanager.cpp
2163 ubuntukeyboardinfo.cpp
2164+ mirsurface.cpp
2165+ mirsurfaceinterface.h
2166 mirsurfaceitem.cpp
2167 mirbuffersgtexture.cpp
2168+ mirsingleton.cpp
2169+ mousepointer.cpp
2170 proc_info.cpp
2171 session.cpp
2172 sessionmanager.cpp
2173@@ -45,8 +51,10 @@
2174 # We need to run moc on these headers
2175 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationInfoInterface.h
2176 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationManagerInterface.h
2177+ ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/MirSurfaceInterface.h
2178+ ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/MirSurfaceItemInterface.h
2179+ ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/Mir.h
2180 # Feed the automoc monster
2181- mirsurfaceiteminterface.h
2182 session_interface.h
2183 applicationcontroller.h
2184 settings_interface.h
2185@@ -77,6 +85,7 @@
2186 Qt5::Quick
2187
2188 qpa-mirserver
2189+ xcursorloader-static
2190 )
2191
2192 # Generate tracepoints.c and .h from tracepoints.tp
2193@@ -87,4 +96,3 @@
2194 # install
2195 add_qml_plugin(Unity.Application 0.1 Unity/Application TARGETS unityapplicationplugin)
2196 install(FILES com.canonical.qtmir.gschema.xml DESTINATION ${CMAKE_INSTALL_DATADIR}/glib-2.0/schemas)
2197-
2198
2199=== added file 'src/modules/Unity/Application/Cursor.qml'
2200--- src/modules/Unity/Application/Cursor.qml 1970-01-01 00:00:00 +0000
2201+++ src/modules/Unity/Application/Cursor.qml 2015-08-27 14:51:37 +0000
2202@@ -0,0 +1,12 @@
2203+import QtQuick 2.4
2204+import Unity.Application 0.1
2205+
2206+MousePointer {
2207+ id: mousePointer
2208+
2209+ Image {
2210+ x: -mousePointer.hotspotX
2211+ y: -mousePointer.hotspotY
2212+ source: "image://cursor/" + mousePointer.themeName + "/" + mousePointer.cursorName
2213+ }
2214+}
2215
2216=== added file 'src/modules/Unity/Application/cursorimageprovider.cpp'
2217--- src/modules/Unity/Application/cursorimageprovider.cpp 1970-01-01 00:00:00 +0000
2218+++ src/modules/Unity/Application/cursorimageprovider.cpp 2015-08-27 14:51:37 +0000
2219@@ -0,0 +1,146 @@
2220+/*
2221+ * Copyright (C) 2015 Canonical, Ltd.
2222+ *
2223+ * This program is free software: you can redistribute it and/or modify it under
2224+ * the terms of the GNU Lesser General Public License version 3, as published by
2225+ * the Free Software Foundation.
2226+ *
2227+ * This program is distributed in the hope that it will be useful, but WITHOUT
2228+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
2229+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2230+ * Lesser General Public License for more details.
2231+ *
2232+ * You should have received a copy of the GNU Lesser General Public License
2233+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2234+ */
2235+
2236+#include "cursorimageprovider.h"
2237+
2238+#include <QFile>
2239+
2240+using namespace qtmir;
2241+
2242+CursorImageProvider *CursorImageProvider::m_instance = nullptr;
2243+
2244+CursorImage::CursorImage(const QString &theme, const QString &file)
2245+ : xcursorImages(nullptr)
2246+{
2247+
2248+ xcursorImages = XcursorLibraryLoadImages(QFile::encodeName(file), QFile::encodeName(theme), 32);
2249+ if (!xcursorImages) {
2250+ return;
2251+ }
2252+
2253+ bool loaded = false;
2254+ for (int i = 0; i < xcursorImages->nimage && !loaded; ++i) {
2255+ XcursorImage *xcursorImage = xcursorImages->images[i];
2256+ if (xcursorImage->size == 32) {
2257+
2258+ qimage = QImage((uchar*)xcursorImage->pixels,
2259+ xcursorImage->width, xcursorImage->height, QImage::Format_ARGB32);
2260+
2261+ hotspot.setX(xcursorImage->xhot);
2262+ hotspot.setY(xcursorImage->yhot);
2263+
2264+ loaded = true;
2265+ }
2266+ }
2267+}
2268+
2269+CursorImage::~CursorImage()
2270+{
2271+ XcursorImagesDestroy(xcursorImages);
2272+}
2273+
2274+CursorImageProvider::CursorImageProvider()
2275+ : QQuickImageProvider(QQuickImageProvider::Image)
2276+{
2277+ if (m_instance) {
2278+ qFatal("QPA mirsever: cannot have multiple CursorImageProvider instances");
2279+ }
2280+ m_instance = this;
2281+}
2282+
2283+CursorImageProvider::~CursorImageProvider()
2284+{
2285+ {
2286+ QList< QMap<QString, CursorImage*> > cursorList = m_cursors.values();
2287+
2288+ for (int i = 0; i < cursorList.count(); ++i) {
2289+ QList<CursorImage*> cursorImageList = cursorList[i].values();
2290+ for (int j = 0; j < cursorImageList.count(); ++j) {
2291+ delete cursorImageList[j];
2292+ }
2293+ }
2294+ }
2295+
2296+ m_cursors.clear();
2297+ m_instance = nullptr;
2298+}
2299+
2300+QImage CursorImageProvider::requestImage(const QString &cursorThemeAndName, QSize *size, const QSize & /*requestedSize*/)
2301+{
2302+ CursorImage *cursorImage = fetchCursor(cursorThemeAndName);
2303+ size->setWidth(cursorImage->qimage.width());
2304+ size->setHeight(cursorImage->qimage.height());
2305+
2306+ return cursorImage->qimage;
2307+}
2308+
2309+QPoint CursorImageProvider::hotspot(const QString &themeName, const QString &cursorName)
2310+{
2311+ CursorImage *cursorImage = fetchCursor(themeName, cursorName);
2312+ if (cursorImage) {
2313+ return cursorImage->hotspot;
2314+ } else {
2315+ return QPoint(0,0);
2316+ }
2317+}
2318+
2319+CursorImage *CursorImageProvider::fetchCursor(const QString &cursorThemeAndName)
2320+{
2321+ QString themeName;
2322+ QString cursorName;
2323+ {
2324+ QStringList themeAndNameList = cursorThemeAndName.split("/");
2325+ if (themeAndNameList.size() != 2) {
2326+ return nullptr;
2327+ }
2328+ themeName = themeAndNameList[0];
2329+ cursorName = themeAndNameList[1];
2330+ }
2331+
2332+ return fetchCursor(themeName, cursorName);
2333+}
2334+
2335+CursorImage *CursorImageProvider::fetchCursor(const QString &themeName, const QString &cursorName)
2336+{
2337+ CursorImage *cursorImage = fetchCursorHelper(themeName, cursorName);
2338+
2339+ // Try some fallbacks
2340+ if (cursorImage->qimage.isNull()) {
2341+ if (cursorName == "ibeam") {
2342+ cursorImage = fetchCursorHelper(themeName, "xterm");
2343+ } else if (cursorName == "xterm") {
2344+ cursorImage = fetchCursorHelper(themeName, "ibeam");
2345+ }
2346+ }
2347+
2348+ // if it all fails, there must be at least a left_ptr
2349+ if (cursorImage->qimage.isNull()) {
2350+ cursorImage = fetchCursorHelper(themeName, "left_ptr");
2351+ }
2352+
2353+ return cursorImage;
2354+}
2355+
2356+CursorImage *CursorImageProvider::fetchCursorHelper(const QString &themeName, const QString &cursorName)
2357+{
2358+ QMap<QString, CursorImage*> &themeCursors = m_cursors[themeName];
2359+
2360+ if (!themeCursors.contains(cursorName)) {
2361+ themeCursors[cursorName] = new CursorImage(themeName, cursorName);
2362+ }
2363+
2364+ return themeCursors[cursorName];
2365+}
2366
2367=== added file 'src/modules/Unity/Application/cursorimageprovider.h'
2368--- src/modules/Unity/Application/cursorimageprovider.h 1970-01-01 00:00:00 +0000
2369+++ src/modules/Unity/Application/cursorimageprovider.h 2015-08-27 14:51:37 +0000
2370@@ -0,0 +1,68 @@
2371+/*
2372+ * Copyright (C) 2015 Canonical, Ltd.
2373+ *
2374+ * This program is free software: you can redistribute it and/or modify it under
2375+ * the terms of the GNU Lesser General Public License version 3, as published by
2376+ * the Free Software Foundation.
2377+ *
2378+ * This program is distributed in the hope that it will be useful, but WITHOUT
2379+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
2380+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2381+ * Lesser General Public License for more details.
2382+ *
2383+ * You should have received a copy of the GNU Lesser General Public License
2384+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2385+ */
2386+
2387+#ifndef QTMIR_CURSORIMAGEPROVIDER_H
2388+#define QTMIR_CURSORIMAGEPROVIDER_H
2389+
2390+#include <QQuickImageProvider>
2391+
2392+// xcursor static lib
2393+extern "C"
2394+{
2395+#include <xcursor.h>
2396+}
2397+
2398+namespace qtmir
2399+{
2400+
2401+class CursorImage {
2402+public:
2403+ CursorImage(const QString &theme, const QString &file);
2404+ ~CursorImage();
2405+
2406+ QImage qimage;
2407+ QPoint hotspot;
2408+ XcursorImages *xcursorImages;
2409+};
2410+
2411+class CursorImageProvider : public QQuickImageProvider
2412+{
2413+public:
2414+ CursorImageProvider();
2415+ virtual ~CursorImageProvider();
2416+
2417+ static CursorImageProvider *instance() { return m_instance; }
2418+
2419+
2420+ QImage requestImage(const QString &cursorName, QSize *size, const QSize &requestedSize) override;
2421+
2422+ QPoint hotspot(const QString &themeName, const QString &cursorName);
2423+
2424+private:
2425+ CursorImage *fetchCursor(const QString &cursorThemeAndName);
2426+ CursorImage *fetchCursor(const QString &themeName, const QString &cursorName);
2427+ CursorImage *fetchCursorHelper(const QString &themeName, const QString &cursorName);
2428+
2429+ // themeName -> (cursorName -> cursorImage)
2430+ QMap<QString, QMap<QString, CursorImage*> > m_cursors;
2431+
2432+ static CursorImageProvider *m_instance;
2433+};
2434+
2435+} // namespace qtmir
2436+
2437+
2438+#endif // QTMIR_CURSORIMAGEPROVIDER_H
2439
2440=== modified file 'src/modules/Unity/Application/mirbuffersgtexture.cpp'
2441--- src/modules/Unity/Application/mirbuffersgtexture.cpp 2015-08-11 12:08:32 +0000
2442+++ src/modules/Unity/Application/mirbuffersgtexture.cpp 2015-08-27 14:51:37 +0000
2443@@ -22,9 +22,10 @@
2444
2445 namespace mg = mir::geometry;
2446
2447-MirBufferSGTexture::MirBufferSGTexture(std::shared_ptr<mir::graphics::Buffer> buffer)
2448+MirBufferSGTexture::MirBufferSGTexture()
2449 : QSGTexture()
2450- , m_mirBuffer(buffer)
2451+ , m_width(0)
2452+ , m_height(0)
2453 , m_textureId(0)
2454 {
2455 glGenTextures(1, &m_textureId);
2456@@ -32,10 +33,6 @@
2457 setFiltering(QSGTexture::Linear);
2458 setHorizontalWrapMode(QSGTexture::ClampToEdge);
2459 setVerticalWrapMode(QSGTexture::ClampToEdge);
2460-
2461- mg::Size size = m_mirBuffer->size();
2462- m_height = size.height.as_int();
2463- m_width = size.width.as_int();
2464 }
2465
2466 MirBufferSGTexture::~MirBufferSGTexture()
2467@@ -48,6 +45,8 @@
2468 void MirBufferSGTexture::freeBuffer()
2469 {
2470 m_mirBuffer.reset();
2471+ m_width = 0;
2472+ m_height = 0;
2473 }
2474
2475 void MirBufferSGTexture::setBuffer(std::shared_ptr<mir::graphics::Buffer> buffer)
2476
2477=== modified file 'src/modules/Unity/Application/mirbuffersgtexture.h'
2478--- src/modules/Unity/Application/mirbuffersgtexture.h 2015-08-11 12:08:32 +0000
2479+++ src/modules/Unity/Application/mirbuffersgtexture.h 2015-08-27 14:51:37 +0000
2480@@ -29,7 +29,7 @@
2481 {
2482 Q_OBJECT
2483 public:
2484- MirBufferSGTexture(std::shared_ptr<mir::graphics::Buffer>);
2485+ MirBufferSGTexture();
2486 virtual ~MirBufferSGTexture();
2487
2488 void setBuffer(std::shared_ptr<mir::graphics::Buffer> buffer);
2489@@ -44,8 +44,8 @@
2490
2491 private:
2492 std::shared_ptr<mir::graphics::Buffer> m_mirBuffer;
2493+ int m_width;
2494 int m_height;
2495- int m_width;
2496 GLuint m_textureId;
2497 };
2498
2499
2500=== added file 'src/modules/Unity/Application/mirsingleton.cpp'
2501--- src/modules/Unity/Application/mirsingleton.cpp 1970-01-01 00:00:00 +0000
2502+++ src/modules/Unity/Application/mirsingleton.cpp 2015-08-27 14:51:37 +0000
2503@@ -0,0 +1,33 @@
2504+#include "mirsingleton.h"
2505+
2506+qtmir::Mir *qtmir::Mir::m_instance = nullptr;
2507+
2508+qtmir::Mir::Mir()
2509+{
2510+}
2511+
2512+qtmir::Mir::~Mir()
2513+{
2514+ m_instance = nullptr;
2515+}
2516+
2517+qtmir::Mir *qtmir::Mir::instance()
2518+{
2519+ if (!m_instance) {
2520+ m_instance = new qtmir::Mir;
2521+ }
2522+ return m_instance;
2523+}
2524+
2525+void qtmir::Mir::setCursorName(const QString &cursorName)
2526+{
2527+ if (m_cursorName != cursorName) {
2528+ m_cursorName = cursorName;
2529+ Q_EMIT cursorNameChanged(m_cursorName);
2530+ }
2531+}
2532+
2533+QString qtmir::Mir::cursorName() const
2534+{
2535+ return m_cursorName;
2536+}
2537
2538=== added file 'src/modules/Unity/Application/mirsingleton.h'
2539--- src/modules/Unity/Application/mirsingleton.h 1970-01-01 00:00:00 +0000
2540+++ src/modules/Unity/Application/mirsingleton.h 2015-08-27 14:51:37 +0000
2541@@ -0,0 +1,45 @@
2542+/*
2543+ * Copyright (C) 2015 Canonical, Ltd.
2544+ *
2545+ * This program is free software: you can redistribute it and/or modify it under
2546+ * the terms of the GNU Lesser General Public License version 3, as published by
2547+ * the Free Software Foundation.
2548+ *
2549+ * This program is distributed in the hope that it will be useful, but WITHOUT
2550+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
2551+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2552+ * Lesser General Public License for more details.
2553+ *
2554+ * You should have received a copy of the GNU Lesser General Public License
2555+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2556+ */
2557+
2558+#ifndef QTMIR_MIRSINGLETON_H
2559+#define QTMIR_MIRSINGLETON_H
2560+
2561+// unity-api
2562+#include <unity/shell/application/Mir.h>
2563+
2564+namespace qtmir {
2565+
2566+class Mir : public ::Mir
2567+{
2568+ Q_OBJECT
2569+public:
2570+ virtual ~Mir();
2571+
2572+ static Mir *instance();
2573+
2574+ void setCursorName(const QString &cursorName) override;
2575+ QString cursorName() const override;
2576+
2577+private:
2578+ Mir();
2579+
2580+ QString m_cursorName;
2581+ static qtmir::Mir *m_instance;
2582+};
2583+
2584+} // namespace qtmir
2585+
2586+#endif // QTMIR_MIRSINGLETON_H
2587
2588=== added file 'src/modules/Unity/Application/mirsurface.cpp'
2589--- src/modules/Unity/Application/mirsurface.cpp 1970-01-01 00:00:00 +0000
2590+++ src/modules/Unity/Application/mirsurface.cpp 2015-08-27 14:51:37 +0000
2591@@ -0,0 +1,631 @@
2592+/*
2593+ * Copyright (C) 2015 Canonical, Ltd.
2594+ *
2595+ * This program is free software: you can redistribute it and/or modify it under
2596+ * the terms of the GNU Lesser General Public License version 3, as published by
2597+ * the Free Software Foundation.
2598+ *
2599+ * This program is distributed in the hope that it will be useful, but WITHOUT
2600+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
2601+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2602+ * Lesser General Public License for more details.
2603+ *
2604+ * You should have received a copy of the GNU Lesser General Public License
2605+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2606+ */
2607+
2608+#include "mirsurface.h"
2609+
2610+// mirserver
2611+#include <surfaceobserver.h>
2612+
2613+// Mir
2614+#include <mir/geometry/rectangle.h>
2615+#include <mir/events/event_builders.h>
2616+#include <mir/shell/shell.h>
2617+#include <mir_toolkit/event.h>
2618+
2619+// mirserver
2620+#include <logging.h>
2621+
2622+using namespace qtmir;
2623+
2624+namespace {
2625+
2626+// Would be better if QMouseEvent had nativeModifiers
2627+MirInputEventModifiers
2628+getMirModifiersFromQt(Qt::KeyboardModifiers mods)
2629+{
2630+ MirInputEventModifiers m_mods = mir_input_event_modifier_none;
2631+ if (mods & Qt::ShiftModifier)
2632+ m_mods |= mir_input_event_modifier_shift;
2633+ if (mods & Qt::ControlModifier)
2634+ m_mods |= mir_input_event_modifier_ctrl;
2635+ if (mods & Qt::AltModifier)
2636+ m_mods |= mir_input_event_modifier_alt;
2637+ if (mods & Qt::MetaModifier)
2638+ m_mods |= mir_input_event_modifier_meta;
2639+
2640+ return m_mods;
2641+}
2642+
2643+mir::EventUPtr makeMirEvent(QMouseEvent *qtEvent, MirPointerAction action)
2644+{
2645+ auto timestamp = std::chrono::milliseconds(qtEvent->timestamp());
2646+ auto modifiers = getMirModifiersFromQt(qtEvent->modifiers());
2647+
2648+ MirPointerButtons buttons = 0;
2649+ if (qtEvent->buttons() & Qt::LeftButton)
2650+ buttons |= mir_pointer_button_primary;
2651+ if (qtEvent->buttons() & Qt::RightButton)
2652+ buttons |= mir_pointer_button_secondary;
2653+ if (qtEvent->buttons() & Qt::MidButton)
2654+ buttons |= mir_pointer_button_tertiary;
2655+
2656+ return mir::events::make_event(0 /*DeviceID */, timestamp, modifiers, action,
2657+ buttons, qtEvent->x(), qtEvent->y(), 0, 0);
2658+}
2659+
2660+mir::EventUPtr makeMirEvent(QHoverEvent *qtEvent, MirPointerAction action)
2661+{
2662+ auto timestamp = std::chrono::milliseconds(qtEvent->timestamp());
2663+
2664+ MirPointerButtons buttons = 0;
2665+
2666+ return mir::events::make_event(0 /*DeviceID */, timestamp, mir_input_event_modifier_none, action,
2667+ buttons, qtEvent->posF().x(), qtEvent->posF().y(), 0, 0);
2668+}
2669+
2670+mir::EventUPtr makeMirEvent(QKeyEvent *qtEvent)
2671+{
2672+ MirKeyboardAction action = mir_keyboard_action_down;
2673+ switch (qtEvent->type())
2674+ {
2675+ case QEvent::KeyPress:
2676+ action = mir_keyboard_action_down;
2677+ break;
2678+ case QEvent::KeyRelease:
2679+ action = mir_keyboard_action_up;
2680+ break;
2681+ default:
2682+ break;
2683+ }
2684+ if (qtEvent->isAutoRepeat())
2685+ action = mir_keyboard_action_repeat;
2686+
2687+ return mir::events::make_event(0 /* DeviceID */, std::chrono::milliseconds(qtEvent->timestamp()),
2688+ action, qtEvent->nativeVirtualKey(),
2689+ qtEvent->nativeScanCode(),
2690+ qtEvent->nativeModifiers());
2691+}
2692+
2693+mir::EventUPtr makeMirEvent(Qt::KeyboardModifiers qmods,
2694+ const QList<QTouchEvent::TouchPoint> &qtTouchPoints,
2695+ Qt::TouchPointStates /* qtTouchPointStates */,
2696+ ulong qtTimestamp)
2697+{
2698+ auto modifiers = getMirModifiersFromQt(qmods);
2699+ auto ev = mir::events::make_event(0, std::chrono::milliseconds(qtTimestamp),
2700+ modifiers);
2701+
2702+ for (int i = 0; i < qtTouchPoints.count(); ++i) {
2703+ auto touchPoint = qtTouchPoints.at(i);
2704+ auto id = touchPoint.id();
2705+
2706+ MirTouchAction action = mir_touch_action_change;
2707+ if (touchPoint.state() == Qt::TouchPointReleased)
2708+ {
2709+ action = mir_touch_action_up;
2710+ }
2711+ if (touchPoint.state() == Qt::TouchPointPressed)
2712+ {
2713+ action = mir_touch_action_down;
2714+ }
2715+
2716+ MirTouchTooltype tooltype = mir_touch_tooltype_finger;
2717+ if (touchPoint.flags() & QTouchEvent::TouchPoint::Pen)
2718+ tooltype = mir_touch_tooltype_stylus;
2719+
2720+ mir::events::add_touch(*ev, id, action, tooltype,
2721+ touchPoint.pos().x(), touchPoint.pos().y(),
2722+ touchPoint.pressure(),
2723+ touchPoint.rect().width(),
2724+ touchPoint.rect().height(),
2725+ 0 /* size */);
2726+ }
2727+
2728+ return ev;
2729+}
2730+
2731+} // namespace {
2732+
2733+MirSurface::MirSurface(std::shared_ptr<mir::scene::Surface> surface,
2734+ SessionInterface* session,
2735+ MirShell *shell,
2736+ std::shared_ptr<SurfaceObserver> observer)
2737+ : MirSurfaceInterface()
2738+ , m_surface(surface)
2739+ , m_session(session)
2740+ , m_shell(shell)
2741+ , m_firstFrameDrawn(false)
2742+ , m_orientationAngle(Mir::Angle0)
2743+ , m_textureUpdated(false)
2744+ , m_currentFrameNumber(0)
2745+ , m_live(true)
2746+ , m_viewCount(0)
2747+{
2748+ m_surfaceObserver = observer;
2749+ if (observer) {
2750+ connect(observer.get(), &SurfaceObserver::framesPosted, this, &MirSurface::onFramesPostedObserved);
2751+ connect(observer.get(), &SurfaceObserver::attributeChanged, this, &MirSurface::onAttributeChanged);
2752+ observer->setListener(this);
2753+ }
2754+
2755+ connect(session, &QObject::destroyed, this, &MirSurface::onSessionDestroyed);
2756+
2757+ connect(&m_frameDropperTimer, &QTimer::timeout,
2758+ this, &MirSurface::dropPendingBuffer);
2759+ // Rationale behind the frame dropper and its interval value:
2760+ //
2761+ // We want to give ample room for Qt scene graph to have a chance to fetch and render
2762+ // the next pending buffer before we take the drastic action of dropping it (so don't set
2763+ // it anywhere close to our target render interval).
2764+ //
2765+ // We also want to guarantee a minimal frames-per-second (fps) frequency for client applications
2766+ // as they get stuck on swap_buffers() if there's no free buffer to swap to yet (ie, they
2767+ // are all pending consumption by the compositor, us). But on the other hand, we don't want
2768+ // that minimal fps to be too high as that would mean this timer would be triggered way too often
2769+ // for nothing causing unnecessary overhead as actually dropping frames from an app should
2770+ // in practice rarely happen.
2771+ m_frameDropperTimer.setInterval(200);
2772+ m_frameDropperTimer.setSingleShot(false);
2773+}
2774+
2775+MirSurface::~MirSurface()
2776+{
2777+ qCDebug(QTMIR_SURFACES).nospace() << "MirSurface::~MirSurface this=" << this << " viewCount=" << m_viewCount;
2778+
2779+ Q_ASSERT(m_viewCount == 0);
2780+
2781+ if (m_session) {
2782+ m_session->setSurface(nullptr);
2783+ }
2784+
2785+ QMutexLocker locker(&m_mutex);
2786+ m_surface->remove_observer(m_surfaceObserver);
2787+}
2788+
2789+void MirSurface::onFramesPostedObserved()
2790+{
2791+ if (!m_firstFrameDrawn) {
2792+ m_firstFrameDrawn = true;
2793+ Q_EMIT firstFrameDrawn();
2794+ }
2795+
2796+ // restart the frame dropper so that items have enough time to render the next frame.
2797+ m_frameDropperTimer.start();
2798+
2799+ Q_EMIT framesPosted();
2800+}
2801+
2802+void MirSurface::onAttributeChanged(const MirSurfaceAttrib attribute, const int /*value*/)
2803+{
2804+ switch (attribute) {
2805+ case mir_surface_attrib_type:
2806+ Q_EMIT typeChanged(type());
2807+ break;
2808+ case mir_surface_attrib_state:
2809+ Q_EMIT stateChanged(state());
2810+ break;
2811+ default:
2812+ break;
2813+ }
2814+}
2815+
2816+SessionInterface* MirSurface::session() const
2817+{
2818+ return m_session.data();
2819+}
2820+
2821+Mir::Type MirSurface::type() const
2822+{
2823+ switch (m_surface->type()) {
2824+ case mir_surface_type_normal:
2825+ return Mir::NormalType;
2826+
2827+ case mir_surface_type_utility:
2828+ return Mir::UtilityType;
2829+
2830+ case mir_surface_type_dialog:
2831+ return Mir::DialogType;
2832+
2833+ case mir_surface_type_gloss:
2834+ return Mir::GlossType;
2835+
2836+ case mir_surface_type_freestyle:
2837+ return Mir::FreeStyleType;
2838+
2839+ case mir_surface_type_menu:
2840+ return Mir::MenuType;
2841+
2842+ case mir_surface_type_inputmethod:
2843+ return Mir::InputMethodType;
2844+
2845+ case mir_surface_type_satellite:
2846+ return Mir::SatelliteType;
2847+
2848+ case mir_surface_type_tip:
2849+ return Mir::TipType;
2850+
2851+ default:
2852+ return Mir::UnknownType;
2853+ }
2854+}
2855+
2856+void MirSurface::dropPendingBuffer()
2857+{
2858+ QMutexLocker locker(&m_mutex);
2859+
2860+ const void* const userId = (void*)123;
2861+
2862+ const int framesPending = m_surface->buffers_ready_for_compositor(userId);
2863+ if (framesPending > 0) {
2864+ for (auto const &renderable : m_surface->generate_renderables(userId)) {
2865+ // The line below looks like an innocent, effect-less, getter. But as this
2866+ // method returns a unique_pointer, not holding its reference causes the
2867+ // buffer to be destroyed/released straight away.
2868+ renderable->buffer();
2869+ }
2870+ qCDebug(QTMIR_SURFACES) << "MirSurface::dropPendingBuffer()"
2871+ << "surface =" << this
2872+ << "buffer dropped."
2873+ << framesPending-1
2874+ << "left.";
2875+ }
2876+}
2877+
2878+void MirSurface::stopFrameDropper()
2879+{
2880+ qCDebug(QTMIR_SURFACES) << "MirSurface::stopFrameDropper surface = " << this;
2881+ m_frameDropperTimer.stop();
2882+}
2883+
2884+void MirSurface::startFrameDropper()
2885+{
2886+ qCDebug(QTMIR_SURFACES) << "MirSurface::startFrameDropper surface = " << this;
2887+ if (!m_frameDropperTimer.isActive()) {
2888+ m_frameDropperTimer.start();
2889+ }
2890+}
2891+
2892+QSharedPointer<QSGTexture> MirSurface::texture()
2893+{
2894+ if (!m_texture) {
2895+ QSharedPointer<QSGTexture> texture(new MirBufferSGTexture);
2896+ m_texture = texture.toWeakRef();
2897+ return texture;
2898+ } else {
2899+ return m_texture.toStrongRef();
2900+ }
2901+}
2902+
2903+void MirSurface::updateTexture()
2904+{
2905+ QMutexLocker locker(&m_mutex);
2906+
2907+ if (m_textureUpdated) {
2908+ return;
2909+ }
2910+
2911+ Q_ASSERT(!m_texture.isNull());
2912+ MirBufferSGTexture *texture = static_cast<MirBufferSGTexture*>(m_texture.data());
2913+
2914+ const void* const userId = (void*)123;
2915+ auto renderables = m_surface->generate_renderables(userId);
2916+
2917+ if (m_surface->buffers_ready_for_compositor(userId) > 0 && renderables.size() > 0) {
2918+ // Avoid holding two buffers for the compositor at the same time. Thus free the current
2919+ // before acquiring the next
2920+ texture->freeBuffer();
2921+ texture->setBuffer(renderables[0]->buffer());
2922+ ++m_currentFrameNumber;
2923+
2924+ if (texture->textureSize() != m_size) {
2925+ m_size = texture->textureSize();
2926+ QMetaObject::invokeMethod(this, "emitSizeChanged", Qt::QueuedConnection);
2927+ }
2928+ }
2929+
2930+ if (m_surface->buffers_ready_for_compositor(userId) > 0) {
2931+ // restart the frame dropper to give MirSurfaceItems enough time to render the next frame.
2932+ // queued since the timer lives in a different thread
2933+ QMetaObject::invokeMethod(&m_frameDropperTimer, "start", Qt::QueuedConnection);
2934+ }
2935+
2936+ m_textureUpdated = true;
2937+}
2938+
2939+void MirSurface::onCompositorSwappedBuffers()
2940+{
2941+ m_textureUpdated = false;
2942+}
2943+
2944+bool MirSurface::numBuffersReadyForCompositor()
2945+{
2946+ QMutexLocker locker(&m_mutex);
2947+ const void* const userId = (void*)123;
2948+ return m_surface->buffers_ready_for_compositor(userId);
2949+}
2950+
2951+void MirSurface::setFocus(bool focus)
2952+{
2953+ if (focus) {
2954+ m_shell->set_surface_attribute(m_session->session(), m_surface, mir_surface_attrib_focus, mir_surface_focused);
2955+ } else {
2956+ m_shell->set_surface_attribute(m_session->session(), m_surface, mir_surface_attrib_focus, mir_surface_unfocused);
2957+ }
2958+}
2959+
2960+void MirSurface::resize(int width, int height)
2961+{
2962+ int mirWidth = m_surface->size().width.as_int();
2963+ int mirHeight = m_surface->size().height.as_int();
2964+
2965+ bool mirSizeIsDifferent = width != mirWidth || height != mirHeight;
2966+
2967+ if (clientIsRunning() && mirSizeIsDifferent) {
2968+ mir::geometry::Size newMirSize(width, height);
2969+ m_surface->resize(newMirSize);
2970+ qCDebug(QTMIR_SURFACES) << "MirSurface::resize"
2971+ << "surface =" << this
2972+ << ", old (" << mirWidth << "," << mirHeight << ")"
2973+ << ", new (" << width << "," << height << ")";
2974+ }
2975+}
2976+
2977+QSize MirSurface::size() const
2978+{
2979+ return m_size;
2980+}
2981+
2982+Mir::State MirSurface::state() const
2983+{
2984+ switch (m_surface->state()) {
2985+ case mir_surface_state_unknown:
2986+ return Mir::UnknownState;
2987+ case mir_surface_state_restored:
2988+ return Mir::RestoredState;
2989+ case mir_surface_state_minimized:
2990+ return Mir::MinimizedState;
2991+ case mir_surface_state_maximized:
2992+ return Mir::MaximizedState;
2993+ case mir_surface_state_vertmaximized:
2994+ return Mir::VertMaximizedState;
2995+ case mir_surface_state_fullscreen:
2996+ return Mir::FullscreenState;
2997+ case mir_surface_state_horizmaximized:
2998+ return Mir::HorizMaximizedState;
2999+ case mir_surface_state_hidden:
3000+ return Mir::HiddenState;
3001+ default:
3002+ return Mir::UnknownState;
3003+ }
3004+}
3005+
3006+Mir::OrientationAngle MirSurface::orientationAngle() const
3007+{
3008+ return m_orientationAngle;
3009+}
3010+
3011+void MirSurface::setOrientationAngle(Mir::OrientationAngle angle)
3012+{
3013+ MirOrientation mirOrientation;
3014+
3015+ if (angle == m_orientationAngle) {
3016+ return;
3017+ }
3018+
3019+ m_orientationAngle = angle;
3020+
3021+ switch (angle) {
3022+ case Mir::Angle0:
3023+ mirOrientation = mir_orientation_normal;
3024+ break;
3025+ case Mir::Angle90:
3026+ mirOrientation = mir_orientation_right;
3027+ break;
3028+ case Mir::Angle180:
3029+ mirOrientation = mir_orientation_inverted;
3030+ break;
3031+ case Mir::Angle270:
3032+ mirOrientation = mir_orientation_left;
3033+ break;
3034+ default:
3035+ qCWarning(QTMIR_SURFACES, "Unsupported orientation angle: %d", angle);
3036+ return;
3037+ }
3038+
3039+ if (m_surface) {
3040+ m_surface->set_orientation(mirOrientation);
3041+ }
3042+
3043+ Q_EMIT orientationAngleChanged(angle);
3044+}
3045+
3046+QString MirSurface::name() const
3047+{
3048+ //FIXME - how to listen to change in this property?
3049+ return QString::fromStdString(m_surface->name());
3050+}
3051+
3052+void MirSurface::setState(Mir::State qmlState)
3053+{
3054+ int mirState;
3055+
3056+ switch (qmlState) {
3057+ default:
3058+ case Mir::UnknownState:
3059+ mirState = mir_surface_state_unknown;
3060+ break;
3061+
3062+ case Mir::RestoredState:
3063+ mirState = mir_surface_state_restored;
3064+ break;
3065+
3066+ case Mir::MinimizedState:
3067+ mirState = mir_surface_state_minimized;
3068+ break;
3069+
3070+ case Mir::MaximizedState:
3071+ mirState = mir_surface_state_maximized;
3072+ break;
3073+
3074+ case Mir::VertMaximizedState:
3075+ mirState = mir_surface_state_vertmaximized;
3076+ break;
3077+
3078+ case Mir::FullscreenState:
3079+ mirState = mir_surface_state_fullscreen;
3080+ break;
3081+
3082+ case Mir::HorizMaximizedState:
3083+ mirState = mir_surface_state_horizmaximized;
3084+ break;
3085+
3086+ case Mir::HiddenState:
3087+ mirState = mir_surface_state_hidden;
3088+ break;
3089+ }
3090+
3091+ m_shell->set_surface_attribute(m_session->session(), m_surface, mir_surface_attrib_state, mirState);
3092+}
3093+
3094+void MirSurface::setLive(bool value)
3095+{
3096+ if (value != m_live) {
3097+ m_live = value;
3098+ Q_EMIT liveChanged(value);
3099+ }
3100+}
3101+
3102+bool MirSurface::live() const
3103+{
3104+ return m_live;
3105+}
3106+
3107+void MirSurface::mousePressEvent(QMouseEvent *event)
3108+{
3109+ auto ev = makeMirEvent(event, mir_pointer_action_button_down);
3110+ m_surface->consume(*ev);
3111+ event->accept();
3112+}
3113+
3114+void MirSurface::mouseMoveEvent(QMouseEvent *event)
3115+{
3116+ auto ev = makeMirEvent(event, mir_pointer_action_motion);
3117+ m_surface->consume(*ev);
3118+ event->accept();
3119+}
3120+
3121+void MirSurface::mouseReleaseEvent(QMouseEvent *event)
3122+{
3123+ auto ev = makeMirEvent(event, mir_pointer_action_button_up);
3124+ m_surface->consume(*ev);
3125+ event->accept();
3126+}
3127+
3128+void MirSurface::hoverEnterEvent(QHoverEvent *event)
3129+{
3130+ auto ev = makeMirEvent(event, mir_pointer_action_enter);
3131+ m_surface->consume(*ev);
3132+ event->accept();
3133+}
3134+
3135+void MirSurface::hoverLeaveEvent(QHoverEvent *event)
3136+{
3137+ auto ev = makeMirEvent(event, mir_pointer_action_leave);
3138+ m_surface->consume(*ev);
3139+ event->accept();
3140+}
3141+
3142+void MirSurface::hoverMoveEvent(QHoverEvent *event)
3143+{
3144+ auto ev = makeMirEvent(event, mir_pointer_action_motion);
3145+ m_surface->consume(*ev);
3146+ event->accept();
3147+}
3148+
3149+void MirSurface::keyPressEvent(QKeyEvent *qtEvent)
3150+{
3151+ auto ev = makeMirEvent(qtEvent);
3152+ m_surface->consume(*ev);
3153+ qtEvent->accept();
3154+}
3155+
3156+void MirSurface::keyReleaseEvent(QKeyEvent *qtEvent)
3157+{
3158+ auto ev = makeMirEvent(qtEvent);
3159+ m_surface->consume(*ev);
3160+ qtEvent->accept();
3161+}
3162+
3163+void MirSurface::touchEvent(Qt::KeyboardModifiers mods,
3164+ const QList<QTouchEvent::TouchPoint> &touchPoints,
3165+ Qt::TouchPointStates touchPointStates,
3166+ ulong timestamp)
3167+{
3168+ auto ev = makeMirEvent(mods, touchPoints, touchPointStates, timestamp);
3169+ m_surface->consume(*ev);
3170+}
3171+
3172+bool MirSurface::clientIsRunning() const
3173+{
3174+ return (m_session &&
3175+ (m_session->state() == Session::State::Running
3176+ || m_session->state() == Session::State::Starting))
3177+ || !m_session;
3178+}
3179+
3180+bool MirSurface::isBeingDisplayed() const
3181+{
3182+ return m_viewCount > 0;
3183+}
3184+
3185+void MirSurface::incrementViewCount()
3186+{
3187+ ++m_viewCount;
3188+ qCDebug(QTMIR_SURFACES).nospace() << "MirSurface::incrementViewCount after=" << m_viewCount;
3189+ if (m_viewCount == 1) {
3190+ Q_EMIT isBeingDisplayedChanged();
3191+ }
3192+}
3193+
3194+void MirSurface::decrementViewCount()
3195+{
3196+ Q_ASSERT(m_viewCount > 0);
3197+ --m_viewCount;
3198+ qCDebug(QTMIR_SURFACES).nospace() << "MirSurface::decrementViewCount after=" << m_viewCount;
3199+ if (m_viewCount == 0) {
3200+ Q_EMIT isBeingDisplayedChanged();
3201+ if (m_session.isNull() || !m_live) {
3202+ deleteLater();
3203+ }
3204+ }
3205+}
3206+
3207+unsigned int MirSurface::currentFrameNumber() const
3208+{
3209+ return m_currentFrameNumber;
3210+}
3211+
3212+void MirSurface::onSessionDestroyed()
3213+{
3214+ if (m_viewCount == 0) {
3215+ deleteLater();
3216+ }
3217+}
3218+
3219+void MirSurface::emitSizeChanged()
3220+{
3221+ Q_EMIT sizeChanged(m_size);
3222+}
3223
3224=== added file 'src/modules/Unity/Application/mirsurface.h'
3225--- src/modules/Unity/Application/mirsurface.h 1970-01-01 00:00:00 +0000
3226+++ src/modules/Unity/Application/mirsurface.h 2015-08-27 14:51:37 +0000
3227@@ -0,0 +1,152 @@
3228+/*
3229+ * Copyright (C) 2015 Canonical, Ltd.
3230+ *
3231+ * This program is free software: you can redistribute it and/or modify it under
3232+ * the terms of the GNU Lesser General Public License version 3, as published by
3233+ * the Free Software Foundation.
3234+ *
3235+ * This program is distributed in the hope that it will be useful, but WITHOUT
3236+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
3237+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
3238+ * Lesser General Public License for more details.
3239+ *
3240+ * You should have received a copy of the GNU Lesser General Public License
3241+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3242+ */
3243+
3244+#ifndef QTMIR_MIRSURFACE_H
3245+#define QTMIR_MIRSURFACE_H
3246+
3247+#include "mirsurfaceinterface.h"
3248+
3249+// Qt
3250+#include <QMutex>
3251+#include <QPointer>
3252+#include <QSharedPointer>
3253+#include <QSGTextureProvider>
3254+#include <QTimer>
3255+#include <QWeakPointer>
3256+
3257+#include "mirbuffersgtexture.h"
3258+#include "session.h"
3259+#include "mirserver.h"
3260+
3261+// mir
3262+#include <mir/scene/surface.h>
3263+#include <mir_toolkit/common.h>
3264+
3265+class SurfaceObserver;
3266+
3267+namespace qtmir {
3268+
3269+class MirSurface : public MirSurfaceInterface
3270+{
3271+ Q_OBJECT
3272+
3273+public:
3274+ MirSurface(std::shared_ptr<mir::scene::Surface> surface,
3275+ SessionInterface* session,
3276+ MirShell *shell,
3277+ std::shared_ptr<SurfaceObserver> observer);
3278+ virtual ~MirSurface();
3279+
3280+ ////
3281+ // unity::shell::application::MirSurfaceInterface
3282+
3283+ Mir::Type type() const override;
3284+
3285+ QString name() const override;
3286+
3287+ QSize size() const override;
3288+ void resize(int width, int height) override;
3289+
3290+ Mir::State state() const override;
3291+ void setState(Mir::State qmlState) override;
3292+
3293+ bool live() const override;
3294+
3295+ Mir::OrientationAngle orientationAngle() const override;
3296+ void setOrientationAngle(Mir::OrientationAngle angle) override;
3297+
3298+ ////
3299+ // qtmir::MirSurfaceInterface
3300+
3301+ void setLive(bool value) override;
3302+
3303+ bool isFirstFrameDrawn() const override { return m_firstFrameDrawn; }
3304+
3305+ SessionInterface *session() const override;
3306+
3307+ void stopFrameDropper() override;
3308+ void startFrameDropper() override;
3309+
3310+ bool isBeingDisplayed() const override;
3311+ void incrementViewCount() override;
3312+ void decrementViewCount() override;
3313+
3314+ // methods called from the rendering (scene graph) thread:
3315+ QSharedPointer<QSGTexture> texture() override;
3316+ void updateTexture() override;
3317+ unsigned int currentFrameNumber() const override;
3318+ bool numBuffersReadyForCompositor() override;
3319+ // end of methods called from the rendering (scene graph) thread
3320+
3321+ void setFocus(bool focus) override;
3322+
3323+ void mousePressEvent(QMouseEvent *event) override;
3324+ void mouseMoveEvent(QMouseEvent *event) override;
3325+ void mouseReleaseEvent(QMouseEvent *event) override;
3326+ void hoverEnterEvent(QHoverEvent *event) override;
3327+ void hoverLeaveEvent(QHoverEvent *event) override;
3328+ void hoverMoveEvent(QHoverEvent *event) override;
3329+
3330+ void keyPressEvent(QKeyEvent *event) override;
3331+ void keyReleaseEvent(QKeyEvent *event) override;
3332+
3333+ void touchEvent(Qt::KeyboardModifiers qmods,
3334+ const QList<QTouchEvent::TouchPoint> &qtTouchPoints,
3335+ Qt::TouchPointStates qtTouchPointStates,
3336+ ulong qtTimestamp) override;
3337+
3338+public Q_SLOTS:
3339+ void onCompositorSwappedBuffers() override;
3340+
3341+private Q_SLOTS:
3342+ void dropPendingBuffer();
3343+ void onAttributeChanged(const MirSurfaceAttrib, const int);
3344+ void onFramesPostedObserved();
3345+ void onSessionDestroyed();
3346+ void emitSizeChanged();
3347+
3348+private:
3349+ void syncSurfaceSizeWithItemSize();
3350+ bool clientIsRunning() const;
3351+
3352+ std::shared_ptr<mir::scene::Surface> m_surface;
3353+ QPointer<SessionInterface> m_session;
3354+ MirShell *const m_shell;
3355+ bool m_firstFrameDrawn;
3356+
3357+ //FIXME - have to save the state as Mir has no getter for it (bug:1357429)
3358+ Mir::OrientationAngle m_orientationAngle;
3359+
3360+ QTimer m_frameDropperTimer;
3361+
3362+ QMutex m_mutex;
3363+
3364+ // Lives in the rendering (scene graph) thread
3365+ QWeakPointer<QSGTexture> m_texture;
3366+ bool m_textureUpdated;
3367+ unsigned int m_currentFrameNumber;
3368+
3369+ bool m_live;
3370+ int m_viewCount;
3371+
3372+ std::shared_ptr<SurfaceObserver> m_surfaceObserver;
3373+
3374+ QSize m_size;
3375+};
3376+
3377+} // namespace qtmir
3378+
3379+#endif // QTMIR_MIRSURFACE_H
3380
3381=== added file 'src/modules/Unity/Application/mirsurfaceinterface.h'
3382--- src/modules/Unity/Application/mirsurfaceinterface.h 1970-01-01 00:00:00 +0000
3383+++ src/modules/Unity/Application/mirsurfaceinterface.h 2015-08-27 14:51:37 +0000
3384@@ -0,0 +1,90 @@
3385+/*
3386+ * Copyright (C) 2015 Canonical, Ltd.
3387+ *
3388+ * This program is free software: you can redistribute it and/or modify it under
3389+ * the terms of the GNU Lesser General Public License version 3, as published by
3390+ * the Free Software Foundation.
3391+ *
3392+ * This program is distributed in the hope that it will be useful, but WITHOUT
3393+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
3394+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
3395+ * Lesser General Public License for more details.
3396+ *
3397+ * You should have received a copy of the GNU Lesser General Public License
3398+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3399+ */
3400+
3401+#ifndef QTMIR_MIRSURFACEINTERFACE_H
3402+#define QTMIR_MIRSURFACEINTERFACE_H
3403+
3404+// Unity API
3405+#include <unity/shell/application/MirSurfaceInterface.h>
3406+
3407+#include "session_interface.h"
3408+
3409+// Qt
3410+#include <QTouchEvent>
3411+
3412+class QHoverEvent;
3413+class QMouseEvent;
3414+class QKeyEvent;
3415+class QSGTexture;
3416+
3417+namespace qtmir {
3418+
3419+class MirSurfaceInterface : public unity::shell::application::MirSurfaceInterface
3420+{
3421+ Q_OBJECT
3422+public:
3423+ MirSurfaceInterface(QObject *parent = nullptr) : unity::shell::application::MirSurfaceInterface(parent) {}
3424+ virtual ~MirSurfaceInterface() {}
3425+
3426+ virtual void setLive(bool value) = 0;
3427+
3428+ virtual bool isFirstFrameDrawn() const = 0;
3429+
3430+ virtual SessionInterface *session() const = 0;
3431+
3432+ virtual void stopFrameDropper() = 0;
3433+ virtual void startFrameDropper() = 0;
3434+
3435+ virtual bool isBeingDisplayed() const = 0;
3436+ virtual void incrementViewCount() = 0;
3437+ virtual void decrementViewCount() = 0;
3438+
3439+ // methods called from the rendering (scene graph) thread:
3440+ virtual QSharedPointer<QSGTexture> texture() = 0;
3441+ virtual void updateTexture() = 0;
3442+ virtual unsigned int currentFrameNumber() const = 0;
3443+ virtual bool numBuffersReadyForCompositor() = 0;
3444+ // end of methods called from the rendering (scene graph) thread
3445+
3446+ virtual void setFocus(bool focus) = 0;
3447+
3448+ virtual void mousePressEvent(QMouseEvent *event) = 0;
3449+ virtual void mouseMoveEvent(QMouseEvent *event) = 0;
3450+ virtual void mouseReleaseEvent(QMouseEvent *event) = 0;
3451+ virtual void hoverEnterEvent(QHoverEvent *event) = 0;
3452+ virtual void hoverLeaveEvent(QHoverEvent *event) = 0;
3453+ virtual void hoverMoveEvent(QHoverEvent *event) = 0;
3454+
3455+ virtual void keyPressEvent(QKeyEvent *event) = 0;
3456+ virtual void keyReleaseEvent(QKeyEvent *event) = 0;
3457+
3458+ virtual void touchEvent(Qt::KeyboardModifiers qmods,
3459+ const QList<QTouchEvent::TouchPoint> &qtTouchPoints,
3460+ Qt::TouchPointStates qtTouchPointStates,
3461+ ulong qtTimestamp) = 0;
3462+
3463+public Q_SLOTS:
3464+ virtual void onCompositorSwappedBuffers() = 0;
3465+
3466+Q_SIGNALS:
3467+ void firstFrameDrawn();
3468+ void framesPosted();
3469+ void isBeingDisplayedChanged();
3470+};
3471+
3472+} // namespace qtmir
3473+
3474+#endif // QTMIR_MIRSURFACEINTERFACE_H
3475
3476=== modified file 'src/modules/Unity/Application/mirsurfaceitem.cpp'
3477--- src/modules/Unity/Application/mirsurfaceitem.cpp 2015-08-20 12:38:34 +0000
3478+++ src/modules/Unity/Application/mirsurfaceitem.cpp 2015-08-27 14:51:37 +0000
3479@@ -16,424 +16,214 @@
3480
3481 // local
3482 #include "application.h"
3483-#include "mirbuffersgtexture.h"
3484 #include "session.h"
3485 #include "mirsurfaceitem.h"
3486 #include "logging.h"
3487 #include "ubuntukeyboardinfo.h"
3488
3489-// mirserver
3490-#include "surfaceobserver.h"
3491-
3492 // common
3493 #include <debughelpers.h>
3494
3495 // Qt
3496 #include <QDebug>
3497 #include <QGuiApplication>
3498+#include <QMutexLocker>
3499 #include <QQmlEngine>
3500 #include <QQuickWindow>
3501 #include <QScreen>
3502 #include <private/qsgdefaultimagenode_p.h>
3503-#include <QSGTextureProvider>
3504+#include <QRunnable>
3505 #include <QTimer>
3506
3507-// Mir
3508-#include <mir/geometry/rectangle.h>
3509-#include <mir/events/event_builders.h>
3510-#include <mir_toolkit/event.h>
3511-#include <mir/shell/shell.h>
3512-
3513-namespace mg = mir::graphics;
3514-
3515 namespace qtmir {
3516
3517 namespace {
3518
3519-// Would be better if QMouseEvent had nativeModifiers
3520-MirInputEventModifiers
3521-getMirModifiersFromQt(Qt::KeyboardModifiers mods)
3522-{
3523- MirInputEventModifiers m_mods = mir_input_event_modifier_none;
3524- if (mods & Qt::ShiftModifier)
3525- m_mods |= mir_input_event_modifier_shift;
3526- if (mods & Qt::ControlModifier)
3527- m_mods |= mir_input_event_modifier_ctrl;
3528- if (mods & Qt::AltModifier)
3529- m_mods |= mir_input_event_modifier_alt;
3530- if (mods & Qt::MetaModifier)
3531- m_mods |= mir_input_event_modifier_meta;
3532-
3533- return m_mods;
3534-}
3535-
3536-mir::EventUPtr makeMirEvent(QMouseEvent *qtEvent, MirPointerAction action)
3537-{
3538- auto timestamp = std::chrono::milliseconds(qtEvent->timestamp());
3539- auto modifiers = getMirModifiersFromQt(qtEvent->modifiers());
3540-
3541- MirPointerButtons buttons = 0;
3542- if (qtEvent->buttons() & Qt::LeftButton)
3543- buttons |= mir_pointer_button_primary;
3544- if (qtEvent->buttons() & Qt::RightButton)
3545- buttons |= mir_pointer_button_secondary;
3546- if (qtEvent->buttons() & Qt::MidButton)
3547- buttons |= mir_pointer_button_tertiary;
3548-
3549- return mir::events::make_event(0 /*DeviceID */, timestamp, modifiers, action,
3550- buttons, qtEvent->x(), qtEvent->y(), 0, 0);
3551-}
3552-
3553-mir::EventUPtr makeMirEvent(QHoverEvent *qtEvent, MirPointerAction action)
3554-{
3555- auto timestamp = std::chrono::milliseconds(qtEvent->timestamp());
3556-
3557- MirPointerButtons buttons = 0;
3558-
3559- return mir::events::make_event(0 /*DeviceID */, timestamp, mir_input_event_modifier_none, action,
3560- buttons, qtEvent->posF().x(), qtEvent->posF().y(), 0, 0);
3561-}
3562-
3563-mir::EventUPtr makeMirEvent(QKeyEvent *qtEvent)
3564-{
3565- MirKeyboardAction action = mir_keyboard_action_down;
3566- switch (qtEvent->type())
3567- {
3568- case QEvent::KeyPress:
3569- action = mir_keyboard_action_down;
3570- break;
3571- case QEvent::KeyRelease:
3572- action = mir_keyboard_action_up;
3573- break;
3574- default:
3575- break;
3576- }
3577- if (qtEvent->isAutoRepeat())
3578- action = mir_keyboard_action_repeat;
3579-
3580- return mir::events::make_event(0 /* DeviceID */, std::chrono::milliseconds(qtEvent->timestamp()),
3581- action, qtEvent->nativeVirtualKey(),
3582- qtEvent->nativeScanCode(),
3583- qtEvent->nativeModifiers());
3584-}
3585-
3586-mir::EventUPtr makeMirEvent(Qt::KeyboardModifiers qmods,
3587- const QList<QTouchEvent::TouchPoint> &qtTouchPoints,
3588- Qt::TouchPointStates /* qtTouchPointStates */,
3589- ulong qtTimestamp)
3590-{
3591- auto modifiers = getMirModifiersFromQt(qmods);
3592- auto ev = mir::events::make_event(0, std::chrono::milliseconds(qtTimestamp),
3593- modifiers);
3594-
3595- for (int i = 0; i < qtTouchPoints.count(); ++i) {
3596- auto touchPoint = qtTouchPoints.at(i);
3597- auto id = touchPoint.id();
3598-
3599- MirTouchAction action = mir_touch_action_change;
3600- if (touchPoint.state() == Qt::TouchPointReleased)
3601- {
3602- action = mir_touch_action_up;
3603- }
3604- if (touchPoint.state() == Qt::TouchPointPressed)
3605- {
3606- action = mir_touch_action_down;
3607- }
3608-
3609- MirTouchTooltype tooltype = mir_touch_tooltype_finger;
3610- if (touchPoint.flags() & QTouchEvent::TouchPoint::Pen)
3611- tooltype = mir_touch_tooltype_stylus;
3612-
3613- mir::events::add_touch(*ev, id, action, tooltype,
3614- touchPoint.pos().x(), touchPoint.pos().y(),
3615- touchPoint.pressure(),
3616- touchPoint.rect().width(),
3617- touchPoint.rect().height(),
3618- 0 /* size */);
3619- }
3620-
3621- return ev;
3622-}
3623+class MirSurfaceItemReleaseResourcesJob : public QRunnable
3624+{
3625+public:
3626+ MirSurfaceItemReleaseResourcesJob() : textureProvider(nullptr) {}
3627+ void run() {
3628+ delete textureProvider;
3629+ textureProvider = nullptr;
3630+ }
3631+ QObject *textureProvider;
3632+};
3633
3634 } // namespace {
3635
3636-class QMirSurfaceTextureProvider : public QSGTextureProvider
3637+class MirTextureProvider : public QSGTextureProvider
3638 {
3639 Q_OBJECT
3640 public:
3641- QMirSurfaceTextureProvider() : t(0) { }
3642- ~QMirSurfaceTextureProvider() { delete t; }
3643-
3644+ MirTextureProvider(QSharedPointer<QSGTexture> texture) : t(texture) {}
3645 QSGTexture *texture() const {
3646 if (t)
3647 t->setFiltering(smooth ? QSGTexture::Linear : QSGTexture::Nearest);
3648- return t;
3649+ return t.data();
3650 }
3651
3652 bool smooth;
3653- MirBufferSGTexture *t;
3654-
3655-public Q_SLOTS:
3656- void invalidate()
3657- {
3658- delete t;
3659- t = 0;
3660- }
3661+
3662+ void releaseTexture() {
3663+ t.reset();
3664+ }
3665+
3666+ void setTexture(QSharedPointer<QSGTexture> newTexture) {
3667+ t = newTexture;
3668+ }
3669+
3670+private:
3671+ QSharedPointer<QSGTexture> t;
3672 };
3673
3674-MirSurfaceItem::MirSurfaceItem(std::shared_ptr<mir::scene::Surface> surface,
3675- SessionInterface* session,
3676- MirShell *shell,
3677- std::shared_ptr<SurfaceObserver> observer,
3678- QQuickItem *parent)
3679+MirSurfaceItem::MirSurfaceItem(QQuickItem *parent)
3680 : MirSurfaceItemInterface(parent)
3681- , m_surface(surface)
3682- , m_session(session)
3683- , m_shell(shell)
3684- , m_firstFrameDrawn(false)
3685- , m_live(true)
3686- , m_orientationAngle(Angle0)
3687+ , m_surface(nullptr)
3688 , m_textureProvider(nullptr)
3689 , m_lastTouchEvent(nullptr)
3690+ , m_lastFrameNumberRendered(nullptr)
3691+ , m_surfaceWidth(0)
3692+ , m_surfaceHeight(0)
3693+ , m_orientationAngle(nullptr)
3694+ , m_consumesInput(false)
3695 {
3696 qCDebug(QTMIR_SURFACES) << "MirSurfaceItem::MirSurfaceItem";
3697
3698- m_surfaceObserver = observer;
3699- if (observer) {
3700- connect(observer.get(), &SurfaceObserver::framesPosted, this, &MirSurfaceItem::surfaceDamaged);
3701- connect(observer.get(), &SurfaceObserver::attributeChanged, this, &MirSurfaceItem::onAttributeChanged);
3702- observer->setListener(this);
3703- }
3704-
3705 setSmooth(true);
3706 setFlag(QQuickItem::ItemHasContents, true); //so scene graph will render this item
3707- setAcceptedMouseButtons(Qt::LeftButton | Qt::MiddleButton | Qt::RightButton |
3708- Qt::ExtraButton1 | Qt::ExtraButton2 | Qt::ExtraButton3 | Qt::ExtraButton4 |
3709- Qt::ExtraButton5 | Qt::ExtraButton6 | Qt::ExtraButton7 | Qt::ExtraButton8 |
3710- Qt::ExtraButton9 | Qt::ExtraButton10 | Qt::ExtraButton11 |
3711- Qt::ExtraButton12 | Qt::ExtraButton13);
3712- setAcceptHoverEvents(true);
3713-
3714- // fetch surface geometry
3715- setImplicitSize(static_cast<qreal>(m_surface->size().width.as_float()),
3716- static_cast<qreal>(m_surface->size().height.as_float()));
3717
3718 if (!UbuntuKeyboardInfo::instance()) {
3719 new UbuntuKeyboardInfo;
3720 }
3721
3722- // Ensure C++ (MirSurfaceManager) retains ownership of this object
3723- // TODO: Investigate if having the Javascript engine have ownership of this object
3724- // might create a less error-prone API design (concern: QML forgets to call "release()"
3725- // for a surface, and thus Mir will not release the surface buffers etc.)
3726- QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership);
3727-
3728- connect(&m_frameDropperTimer, &QTimer::timeout,
3729- this, &MirSurfaceItem::dropPendingBuffer);
3730- // Rationale behind the frame dropper and its interval value:
3731- //
3732- // We want to give ample room for Qt scene graph to have a chance to fetch and render
3733- // the next pending buffer before we take the drastic action of dropping it (so don't set
3734- // it anywhere close to our target render interval).
3735- //
3736- // We also want to guarantee a minimal frames-per-second (fps) frequency for client applications
3737- // as they get stuck on swap_buffers() if there's no free buffer to swap to yet (ie, they
3738- // are all pending consumption by the compositor, us). But on the other hand, we don't want
3739- // that minimal fps to be too high as that would mean this timer would be triggered way too often
3740- // for nothing causing unnecessary overhead as actually dropping frames from an app should
3741- // in practice rarely happen.
3742- m_frameDropperTimer.setInterval(200);
3743- m_frameDropperTimer.setSingleShot(false);
3744-
3745 m_updateMirSurfaceSizeTimer.setSingleShot(true);
3746 m_updateMirSurfaceSizeTimer.setInterval(1);
3747 connect(&m_updateMirSurfaceSizeTimer, &QTimer::timeout, this, &MirSurfaceItem::updateMirSurfaceSize);
3748- connect(this, &QQuickItem::widthChanged, this, &MirSurfaceItem::scheduleMirSurfaceSizeUpdate);
3749- connect(this, &QQuickItem::heightChanged, this, &MirSurfaceItem::scheduleMirSurfaceSizeUpdate);
3750
3751- // FIXME - setting surface unfocused immediately breaks camera & video apps, but is
3752- // technically the correct thing to do (surface should be unfocused until shell focuses it)
3753- //m_surface->configure(mir_surface_attrib_focus, mir_surface_unfocused);
3754 connect(this, &QQuickItem::activeFocusChanged, this, &MirSurfaceItem::updateMirSurfaceFocus);
3755-
3756- if (m_session) {
3757- connect(m_session.data(), &Session::stateChanged, this, &MirSurfaceItem::onSessionStateChanged);
3758- }
3759 }
3760
3761 MirSurfaceItem::~MirSurfaceItem()
3762 {
3763- if (m_session) {
3764- m_session->setSurface(nullptr);
3765- }
3766-
3767 qCDebug(QTMIR_SURFACES) << "MirSurfaceItem::~MirSurfaceItem - this=" << this;
3768- QMutexLocker locker(&m_mutex);
3769- m_surface->remove_observer(m_surfaceObserver);
3770- if (m_textureProvider)
3771- m_textureProvider->deleteLater();
3772+
3773+ setSurface(nullptr);
3774
3775 delete m_lastTouchEvent;
3776-}
3777-
3778-// For QML to destroy this surface
3779-void MirSurfaceItem::release()
3780-{
3781- qCDebug(QTMIR_SURFACES) << "MirSurfaceItem::release - this=" << this;
3782-
3783- if (m_session) {
3784- m_session->setSurface(nullptr);
3785- }
3786- deleteLater();
3787-}
3788-
3789-SessionInterface* MirSurfaceItem::session() const
3790-{
3791- return m_session.data();
3792-}
3793-
3794-MirSurfaceItem::Type MirSurfaceItem::type() const
3795-{
3796- return static_cast<MirSurfaceItem::Type>(m_surface->type());
3797-}
3798-
3799-MirSurfaceItem::State MirSurfaceItem::state() const
3800-{
3801- return static_cast<MirSurfaceItem::State>(m_surface->state());
3802-}
3803-
3804-MirSurfaceItem::OrientationAngle MirSurfaceItem::orientationAngle() const
3805-{
3806- return m_orientationAngle;
3807-}
3808-
3809-void MirSurfaceItem::setOrientationAngle(MirSurfaceItem::OrientationAngle angle)
3810+ delete m_lastFrameNumberRendered;
3811+ delete m_orientationAngle;
3812+ delete m_textureProvider;
3813+}
3814+
3815+Mir::Type MirSurfaceItem::type() const
3816+{
3817+ if (m_surface) {
3818+ return m_surface->type();
3819+ } else {
3820+ return Mir::UnknownType;
3821+ }
3822+}
3823+
3824+Mir::OrientationAngle MirSurfaceItem::orientationAngle() const
3825+{
3826+ if (m_orientationAngle) {
3827+ Q_ASSERT(!m_surface);
3828+ return *m_orientationAngle;
3829+ } else if (m_surface) {
3830+ return m_surface->orientationAngle();
3831+ } else {
3832+ return Mir::Angle0;
3833+ }
3834+}
3835+
3836+void MirSurfaceItem::setOrientationAngle(Mir::OrientationAngle angle)
3837 {
3838 qCDebug(QTMIR_SURFACES, "MirSurfaceItem::setOrientationAngle(%d)", angle);
3839
3840- if (m_orientationAngle == angle)
3841- return;
3842-
3843- MirOrientation mirOrientation;
3844-
3845- switch (angle) {
3846- case Angle0:
3847- mirOrientation = mir_orientation_normal;
3848- break;
3849- case Angle90:
3850- mirOrientation = mir_orientation_right;
3851- break;
3852- case Angle180:
3853- mirOrientation = mir_orientation_inverted;
3854- break;
3855- case Angle270:
3856- mirOrientation = mir_orientation_left;
3857- break;
3858- default:
3859- qCWarning(QTMIR_SURFACES, "Unsupported orientation angle: %d", angle);
3860- return;
3861+ if (m_surface) {
3862+ Q_ASSERT(!m_orientationAngle);
3863+ m_surface->setOrientationAngle(angle);
3864+ } else if (!m_orientationAngle) {
3865+ m_orientationAngle = new Mir::OrientationAngle;
3866+ *m_orientationAngle = angle;
3867+ Q_EMIT orientationAngleChanged(angle);
3868+ } else if (*m_orientationAngle != angle) {
3869+ *m_orientationAngle = angle;
3870+ Q_EMIT orientationAngleChanged(angle);
3871 }
3872-
3873- m_surface->set_orientation(mirOrientation);
3874-
3875- m_orientationAngle = angle;
3876- Q_EMIT orientationAngleChanged(angle);
3877 }
3878
3879 QString MirSurfaceItem::name() const
3880 {
3881- //FIXME - how to listen to change in this property?
3882- return QString::fromStdString(m_surface->name());
3883+ if (m_surface) {
3884+ return m_surface->name();
3885+ } else {
3886+ return QString();
3887+ }
3888 }
3889
3890 bool MirSurfaceItem::live() const
3891 {
3892- return m_live;
3893+ return m_surface && m_surface->live();
3894 }
3895
3896 // Called from the rendering (scene graph) thread
3897 QSGTextureProvider *MirSurfaceItem::textureProvider() const
3898 {
3899- const_cast<MirSurfaceItem *>(this)->ensureProvider();
3900+ QMutexLocker mutexLocker(const_cast<QMutex*>(&m_mutex));
3901+ const_cast<MirSurfaceItem *>(this)->ensureTextureProvider();
3902 return m_textureProvider;
3903 }
3904
3905-void MirSurfaceItem::ensureProvider()
3906+void MirSurfaceItem::ensureTextureProvider()
3907 {
3908+ if (!m_surface) {
3909+ return;
3910+ }
3911+
3912 if (!m_textureProvider) {
3913- m_textureProvider = new QMirSurfaceTextureProvider();
3914- connect(window(), SIGNAL(sceneGraphInvalidated()),
3915- m_textureProvider, SLOT(invalidate()), Qt::DirectConnection);
3916- }
3917-}
3918-
3919-void MirSurfaceItem::surfaceDamaged()
3920-{
3921- if (!m_firstFrameDrawn) {
3922- m_firstFrameDrawn = true;
3923- Q_EMIT firstFrameDrawn();
3924- }
3925-
3926- scheduleTextureUpdate();
3927-}
3928-
3929-bool MirSurfaceItem::updateTexture() // called by rendering thread (scene graph)
3930-{
3931- QMutexLocker locker(&m_mutex);
3932- ensureProvider();
3933- bool textureUpdated = false;
3934-
3935- const void* const userId = (void*)123;
3936- auto renderables = m_surface->generate_renderables(userId);
3937-
3938- if (m_surface->buffers_ready_for_compositor(userId) > 0 && renderables.size() > 0) {
3939- if (!m_textureProvider->t) {
3940- m_textureProvider->t = new MirBufferSGTexture(renderables[0]->buffer());
3941- } else {
3942- // Avoid holding two buffers for the compositor at the same time. Thus free the current
3943- // before acquiring the next
3944- m_textureProvider->t->freeBuffer();
3945- m_textureProvider->t->setBuffer(renderables[0]->buffer());
3946- }
3947- textureUpdated = true;
3948- }
3949-
3950- if (m_surface->buffers_ready_for_compositor(userId) > 0) {
3951+ m_textureProvider = new MirTextureProvider(m_surface->texture());
3952+ } else if (!m_textureProvider->texture()) {
3953+ m_textureProvider->setTexture(m_surface->texture());
3954+ }
3955+}
3956+
3957+QSGNode *MirSurfaceItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *) // called by render thread
3958+{
3959+ QMutexLocker mutexLocker(&m_mutex);
3960+
3961+ if (!m_surface) {
3962+ delete oldNode;
3963+ return 0;
3964+ }
3965+
3966+ ensureTextureProvider();
3967+
3968+ m_surface->updateTexture();
3969+
3970+ if (m_surface->numBuffersReadyForCompositor() > 0) {
3971 QTimer::singleShot(0, this, SLOT(update()));
3972- // restart the frame dropper so that we have enough time to render the next frame.
3973- // queued since the timer lives in a different thread
3974- QMetaObject::invokeMethod(&m_frameDropperTimer, "start", Qt::QueuedConnection);
3975+ }
3976+
3977+ if (!m_textureProvider->texture()) {
3978+ delete oldNode;
3979+ return 0;
3980 }
3981
3982 m_textureProvider->smooth = smooth();
3983
3984- return textureUpdated;
3985-}
3986-
3987-QSGNode *MirSurfaceItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *) // called by render thread
3988-{
3989- if (!m_surface) {
3990- delete oldNode;
3991- return 0;
3992- }
3993-
3994- bool textureUpdated = updateTexture();
3995- if (!m_textureProvider->t) {
3996- delete oldNode;
3997- return 0;
3998- }
3999-
4000 QSGDefaultImageNode *node = static_cast<QSGDefaultImageNode*>(oldNode);
4001 if (!node) {
4002 node = new QSGDefaultImageNode;
4003- node->setTexture(m_textureProvider->t);
4004+ node->setTexture(m_textureProvider->texture());
4005
4006 node->setMipmapFiltering(QSGTexture::None);
4007 node->setHorizontalWrapMode(QSGTexture::ClampToEdge);
4008 node->setVerticalWrapMode(QSGTexture::ClampToEdge);
4009 node->setSubSourceRect(QRectF(0, 0, 1, 1));
4010 } else {
4011- if (textureUpdated) {
4012+ if (!m_lastFrameNumberRendered || (*m_lastFrameNumberRendered != m_surface->currentFrameNumber())) {
4013 node->markDirty(QSGNode::DirtyMaterial);
4014 }
4015 }
4016@@ -446,39 +236,48 @@
4017
4018 node->update();
4019
4020+ if (!m_lastFrameNumberRendered) {
4021+ m_lastFrameNumberRendered = new unsigned int;
4022+ }
4023+ *m_lastFrameNumberRendered = m_surface->currentFrameNumber();
4024+
4025 return node;
4026 }
4027
4028 void MirSurfaceItem::mousePressEvent(QMouseEvent *event)
4029 {
4030- if (type() == InputMethod) {
4031- // FIXME: Hack to get the VKB use case working while we don't have the proper solution in place.
4032- if (isMouseInsideUbuntuKeyboard(event)) {
4033- auto ev = makeMirEvent(event, mir_pointer_action_button_down);
4034- m_surface->consume(*ev);
4035- event->accept();
4036+ if (m_consumesInput && m_surface && m_surface->live()) {
4037+ if (type() == Mir::InputMethodType) {
4038+ // FIXME: Hack to get the VKB use case working while we don't have the proper solution in place.
4039+ if (isMouseInsideUbuntuKeyboard(event)) {
4040+ m_surface->mousePressEvent(event);
4041+ } else {
4042+ event->ignore();
4043+ }
4044 } else {
4045- event->ignore();
4046+ m_surface->mousePressEvent(event);
4047 }
4048 } else {
4049- auto ev = makeMirEvent(event, mir_pointer_action_button_down);
4050- m_surface->consume(*ev);
4051- event->accept();
4052+ event->ignore();
4053 }
4054 }
4055
4056 void MirSurfaceItem::mouseMoveEvent(QMouseEvent *event)
4057 {
4058- auto ev = makeMirEvent(event, mir_pointer_action_motion);
4059- m_surface->consume(*ev);
4060- event->accept();
4061+ if (m_consumesInput && m_surface && m_surface->live()) {
4062+ m_surface->mouseMoveEvent(event);
4063+ } else {
4064+ event->ignore();
4065+ }
4066 }
4067
4068 void MirSurfaceItem::mouseReleaseEvent(QMouseEvent *event)
4069 {
4070- auto ev = makeMirEvent(event, mir_pointer_action_button_up);
4071- m_surface->consume(*ev);
4072- event->accept();
4073+ if (m_consumesInput && m_surface && m_surface->live()) {
4074+ m_surface->mouseReleaseEvent(event);
4075+ } else {
4076+ event->ignore();
4077+ }
4078 }
4079
4080 void MirSurfaceItem::wheelEvent(QWheelEvent *event)
4081@@ -488,44 +287,57 @@
4082
4083 void MirSurfaceItem::hoverEnterEvent(QHoverEvent *event)
4084 {
4085- auto ev = makeMirEvent(event, mir_pointer_action_enter);
4086- m_surface->consume(*ev);
4087- event->accept();
4088+ if (m_consumesInput && m_surface && m_surface->live()) {
4089+ m_surface->hoverEnterEvent(event);
4090+ } else {
4091+ event->ignore();
4092+ }
4093 }
4094
4095 void MirSurfaceItem::hoverLeaveEvent(QHoverEvent *event)
4096 {
4097- auto ev = makeMirEvent(event, mir_pointer_action_leave);
4098- m_surface->consume(*ev);
4099- event->accept();
4100+ if (m_consumesInput && m_surface && m_surface->live()) {
4101+ m_surface->hoverLeaveEvent(event);
4102+ } else {
4103+ event->ignore();
4104+ }
4105 }
4106
4107 void MirSurfaceItem::hoverMoveEvent(QHoverEvent *event)
4108 {
4109- auto ev = makeMirEvent(event, mir_pointer_action_motion);
4110- m_surface->consume(*ev);
4111- event->accept();
4112-}
4113-
4114-void MirSurfaceItem::keyPressEvent(QKeyEvent *qtEvent)
4115-{
4116- auto ev = makeMirEvent(qtEvent);
4117- m_surface->consume(*ev);
4118- qtEvent->accept();
4119-}
4120-
4121-void MirSurfaceItem::keyReleaseEvent(QKeyEvent *qtEvent)
4122-{
4123- auto ev = makeMirEvent(qtEvent);
4124- m_surface->consume(*ev);
4125- qtEvent->accept();
4126+ if (m_consumesInput && m_surface && m_surface->live()) {
4127+ m_surface->hoverMoveEvent(event);
4128+ } else {
4129+ event->ignore();
4130+ }
4131+}
4132+
4133+void MirSurfaceItem::keyPressEvent(QKeyEvent *event)
4134+{
4135+ if (m_consumesInput && m_surface && m_surface->live()) {
4136+ m_surface->keyPressEvent(event);
4137+ } else {
4138+ event->ignore();
4139+ }
4140+}
4141+
4142+void MirSurfaceItem::keyReleaseEvent(QKeyEvent *event)
4143+{
4144+ if (m_consumesInput && m_surface && m_surface->live()) {
4145+ m_surface->keyReleaseEvent(event);
4146+ } else {
4147+ event->ignore();
4148+ }
4149 }
4150
4151 QString MirSurfaceItem::appId() const
4152 {
4153 QString appId;
4154- if (session() && session()->application()) {
4155- appId = session()->application()->appId();
4156+
4157+ SessionInterface *session = m_surface ? m_surface->session() : nullptr;
4158+
4159+ if (session && session->application()) {
4160+ appId = session->application()->appId();
4161 } else {
4162 appId.append("-");
4163 }
4164@@ -557,9 +369,8 @@
4165
4166 touchEvent.updateTouchPointStatesAndType();
4167
4168- auto ev = makeMirEvent(touchEvent.modifiers, touchEvent.touchPoints,
4169+ m_surface->touchEvent(touchEvent.modifiers, touchEvent.touchPoints,
4170 touchEvent.touchPointStates, touchEvent.timestamp);
4171- m_surface->consume(*ev);
4172
4173 *m_lastTouchEvent = touchEvent;
4174
4175@@ -580,8 +391,7 @@
4176 endCurrentTouchSequence(timestamp);
4177 }
4178
4179- auto ev = makeMirEvent(mods, touchPoints, touchPointStates, timestamp);
4180- m_surface->consume(*ev);
4181+ m_surface->touchEvent(mods, touchPoints, touchPointStates, timestamp);
4182
4183 if (!m_lastTouchEvent) {
4184 m_lastTouchEvent = new TouchEvent;
4185@@ -609,8 +419,13 @@
4186 const QList<QTouchEvent::TouchPoint> &touchPoints,
4187 Qt::TouchPointStates touchPointStates)
4188 {
4189+
4190+ if (!m_consumesInput || !m_surface || !m_surface->live()) {
4191+ return false;
4192+ }
4193+
4194 bool accepted = true;
4195- if (type() == InputMethod && eventType == QEvent::TouchBegin) {
4196+ if (type() == Mir::InputMethodType && eventType == QEvent::TouchBegin) {
4197 // FIXME: Hack to get the VKB use case working while we don't have the proper solution in place.
4198 if (hasTouchInsideUbuntuKeyboard(touchPoints)) {
4199 validateAndDeliverTouchEvent(eventType, timestamp, mods, touchPoints, touchPointStates);
4200@@ -654,75 +469,45 @@
4201 && pos.y() <= (ubuntuKeyboardInfo->y() + ubuntuKeyboardInfo->height());
4202 }
4203
4204-void MirSurfaceItem::setType(const Type &type)
4205-{
4206- if (this->type() != type) {
4207- m_shell->set_surface_attribute(m_session->session(), m_surface, mir_surface_attrib_type, static_cast<int>(type));
4208- }
4209-}
4210-
4211-void MirSurfaceItem::setState(const State &state)
4212-{
4213- if (this->state() != state) {
4214- m_shell->set_surface_attribute(m_session->session(), m_surface, mir_surface_attrib_state, static_cast<int>(state));
4215- }
4216-}
4217-
4218-void MirSurfaceItem::setLive(bool live)
4219-{
4220- if (m_live != live) {
4221- m_live = live;
4222- Q_EMIT liveChanged(m_live);
4223- }
4224-}
4225-
4226-void MirSurfaceItem::onAttributeChanged(const MirSurfaceAttrib attribute, const int /*value*/)
4227-{
4228- switch (attribute) {
4229- case mir_surface_attrib_type:
4230- Q_EMIT typeChanged();
4231- break;
4232- case mir_surface_attrib_state:
4233- Q_EMIT stateChanged();
4234- break;
4235- default:
4236- break;
4237+Mir::State MirSurfaceItem::surfaceState() const
4238+{
4239+ if (m_surface) {
4240+ return m_surface->state();
4241+ } else {
4242+ return Mir::UnknownState;
4243+ }
4244+}
4245+
4246+void MirSurfaceItem::setSurfaceState(Mir::State state)
4247+{
4248+ if (m_surface) {
4249+ m_surface->setState(state);
4250 }
4251 }
4252
4253 void MirSurfaceItem::scheduleMirSurfaceSizeUpdate()
4254 {
4255- if (clientIsRunning() && !m_updateMirSurfaceSizeTimer.isActive()) {
4256+ if (!m_updateMirSurfaceSizeTimer.isActive()) {
4257 m_updateMirSurfaceSizeTimer.start();
4258 }
4259 }
4260
4261 void MirSurfaceItem::updateMirSurfaceSize()
4262 {
4263- int mirWidth = m_surface->size().width.as_int();
4264- int mirHeight = m_surface->size().height.as_int();
4265-
4266- int qmlWidth = (int)width();
4267- int qmlHeight = (int)height();
4268-
4269- bool mirSizeIsDifferent = qmlWidth != mirWidth || qmlHeight != mirHeight;
4270-
4271- const char *didResize = clientIsRunning() && mirSizeIsDifferent ? "surface resized" : "surface NOT resized";
4272- qCDebug(QTMIR_SURFACES) << "MirSurfaceItem::updateMirSurfaceSize"
4273- << "surface =" << this
4274- << ", old (" << mirWidth << "," << mirHeight << ")"
4275- << ", new (" << qmlWidth << "," << qmlHeight << ")"
4276- << didResize;
4277-
4278- if (clientIsRunning() && mirSizeIsDifferent) {
4279- mir::geometry::Size newMirSize(qmlWidth, qmlHeight);
4280- m_surface->resize(newMirSize);
4281- setImplicitSize(qmlWidth, qmlHeight);
4282+ if (!m_surface || !m_surface->live() || (m_surfaceWidth <= 0 && m_surfaceHeight <= 0)) {
4283+ return;
4284 }
4285+
4286+ // If one dimension is not set, fallback to the current value
4287+ int width = m_surfaceWidth > 0 ? m_surfaceWidth : m_surface->size().width();
4288+ int height = m_surfaceHeight > 0 ? m_surfaceHeight : m_surface->size().height();
4289+
4290+ m_surface->resize(width, height);
4291 }
4292
4293 void MirSurfaceItem::updateMirSurfaceFocus(bool focused)
4294 {
4295+<<<<<<< TREE
4296 qCDebug(QTMIR_SURFACES) << "MirSurfaceItem::updateMirSurfaceFocus" << focused;
4297
4298 // Temporary hotfix for http://pad.lv/1483752
4299@@ -820,6 +605,17 @@
4300 (m_session->state() == Session::State::Running
4301 || m_session->state() == Session::State::Starting))
4302 || !m_session;
4303+=======
4304+ if (m_surface && m_consumesInput && m_surface->live()) {
4305+ m_surface->setFocus(focused);
4306+ }
4307+}
4308+
4309+void MirSurfaceItem::invalidateSceneGraph()
4310+{
4311+ delete m_textureProvider;
4312+ m_textureProvider = nullptr;
4313+>>>>>>> MERGE-SOURCE
4314 }
4315
4316 void MirSurfaceItem::TouchEvent::updateTouchPointStatesAndType()
4317@@ -838,6 +634,142 @@
4318 }
4319 }
4320
4321+bool MirSurfaceItem::consumesInput() const
4322+{
4323+ return m_consumesInput;
4324+}
4325+
4326+void MirSurfaceItem::setConsumesInput(bool value)
4327+{
4328+ if (m_consumesInput == value) {
4329+ return;
4330+ }
4331+
4332+ m_consumesInput = value;
4333+ if (m_consumesInput) {
4334+ setAcceptedMouseButtons(Qt::LeftButton | Qt::MiddleButton | Qt::RightButton |
4335+ Qt::ExtraButton1 | Qt::ExtraButton2 | Qt::ExtraButton3 | Qt::ExtraButton4 |
4336+ Qt::ExtraButton5 | Qt::ExtraButton6 | Qt::ExtraButton7 | Qt::ExtraButton8 |
4337+ Qt::ExtraButton9 | Qt::ExtraButton10 | Qt::ExtraButton11 |
4338+ Qt::ExtraButton12 | Qt::ExtraButton13);
4339+ setAcceptHoverEvents(true);
4340+ } else {
4341+ setAcceptedMouseButtons(Qt::NoButton);
4342+ setAcceptHoverEvents(false);
4343+ }
4344+
4345+ Q_EMIT consumesInputChanged(value);
4346+}
4347+
4348+unity::shell::application::MirSurfaceInterface* MirSurfaceItem::surface() const
4349+{
4350+ return m_surface;
4351+}
4352+
4353+void MirSurfaceItem::setSurface(unity::shell::application::MirSurfaceInterface *unitySurface)
4354+{
4355+ QMutexLocker mutexLocker(&m_mutex);
4356+
4357+ qtmir::MirSurface *surface = static_cast<qtmir::MirSurface*>(unitySurface);
4358+ qCDebug(QTMIR_SURFACES).nospace() << "MirSurfaceItem::setSurface surface=" << surface;
4359+
4360+ if (surface == m_surface) {
4361+ return;
4362+ }
4363+
4364+ if (m_surface) {
4365+ disconnect(m_surface, nullptr, this, nullptr);
4366+ m_surface->decrementViewCount();
4367+ if (!m_surface->isBeingDisplayed() && window()) {
4368+ disconnect(window(), nullptr, m_surface, nullptr);
4369+ }
4370+ if (m_textureProvider) {
4371+ m_textureProvider->releaseTexture();
4372+ }
4373+ }
4374+
4375+ m_surface = surface;
4376+
4377+ if (m_surface) {
4378+ m_surface->incrementViewCount();
4379+
4380+ // When a new mir frame gets posted we notify the QML engine that this item needs redrawing,
4381+ // schedules call to updatePaintNode() from the rendering thread
4382+ connect(m_surface, &MirSurface::framesPosted, this, &QQuickItem::update);
4383+
4384+ connect(m_surface, &MirSurface::stateChanged, this, &MirSurfaceItem::surfaceStateChanged);
4385+ connect(m_surface, &MirSurface::liveChanged, this, &MirSurfaceItem::liveChanged);
4386+ connect(m_surface, &MirSurface::sizeChanged, this, &MirSurfaceItem::onActualSurfaceSizeChanged);
4387+
4388+ connect(window(), &QQuickWindow::frameSwapped, m_surface, &MirSurface::onCompositorSwappedBuffers,
4389+ (Qt::ConnectionType) (Qt::DirectConnection | Qt::UniqueConnection));
4390+
4391+ Q_EMIT typeChanged(m_surface->type());
4392+ Q_EMIT liveChanged(true);
4393+ Q_EMIT surfaceStateChanged(m_surface->state());
4394+
4395+ updateMirSurfaceSize();
4396+ setImplicitSize(m_surface->size().width(), m_surface->size().height());
4397+
4398+ if (m_orientationAngle) {
4399+ m_surface->setOrientationAngle(*m_orientationAngle);
4400+ connect(m_surface, &MirSurface::orientationAngleChanged, this, &MirSurfaceItem::orientationAngleChanged);
4401+ delete m_orientationAngle;
4402+ m_orientationAngle = nullptr;
4403+ } else {
4404+ connect(m_surface, &MirSurface::orientationAngleChanged, this, &MirSurfaceItem::orientationAngleChanged);
4405+ Q_EMIT orientationAngleChanged(m_surface->orientationAngle());
4406+ }
4407+ }
4408+
4409+ Q_EMIT surfaceChanged(m_surface);
4410+}
4411+
4412+void MirSurfaceItem::releaseResources()
4413+{
4414+ if (m_textureProvider) {
4415+ Q_ASSERT(window());
4416+
4417+ MirSurfaceItemReleaseResourcesJob *job = new MirSurfaceItemReleaseResourcesJob;
4418+ job->textureProvider = m_textureProvider;
4419+ m_textureProvider = nullptr;
4420+ window()->scheduleRenderJob(job, QQuickWindow::AfterSynchronizingStage);
4421+ }
4422+}
4423+
4424+int MirSurfaceItem::surfaceWidth() const
4425+{
4426+ return m_surfaceWidth;
4427+}
4428+
4429+void MirSurfaceItem::setSurfaceWidth(int value)
4430+{
4431+ if (value != m_surfaceWidth) {
4432+ m_surfaceWidth = value;
4433+ scheduleMirSurfaceSizeUpdate();
4434+ Q_EMIT surfaceWidthChanged(value);
4435+ }
4436+}
4437+
4438+void MirSurfaceItem::onActualSurfaceSizeChanged(const QSize &size)
4439+{
4440+ setImplicitSize(size.width(), size.height());
4441+}
4442+
4443+int MirSurfaceItem::surfaceHeight() const
4444+{
4445+ return m_surfaceHeight;
4446+}
4447+
4448+void MirSurfaceItem::setSurfaceHeight(int value)
4449+{
4450+ if (value != m_surfaceHeight) {
4451+ m_surfaceHeight = value;
4452+ scheduleMirSurfaceSizeUpdate();
4453+ Q_EMIT surfaceHeightChanged(value);
4454+ }
4455+}
4456+
4457 } // namespace qtmir
4458
4459 #include "mirsurfaceitem.moc"
4460
4461=== modified file 'src/modules/Unity/Application/mirsurfaceitem.h'
4462--- src/modules/Unity/Application/mirsurfaceitem.h 2015-08-12 11:35:49 +0000
4463+++ src/modules/Unity/Application/mirsurfaceitem.h 2015-08-27 14:51:37 +0000
4464@@ -21,61 +21,66 @@
4465
4466 // Qt
4467 #include <QMutex>
4468-#include <QPointer>
4469 #include <QTimer>
4470-#include <QQmlListProperty>
4471-
4472-// mir
4473-#include <mir/scene/surface.h>
4474-#include <mir_toolkit/common.h>
4475-
4476-#include "mirsurfaceiteminterface.h"
4477+
4478+// Unity API
4479+#include <unity/shell/application/MirSurfaceItemInterface.h>
4480+
4481+#include "mirsurface.h"
4482 #include "session_interface.h"
4483
4484-namespace mir { namespace shell { class Shell; }}
4485+//namespace mir { namespace shell { class Shell; }}
4486
4487 class SurfaceObserver;
4488-using MirShell = mir::shell::Shell;
4489+//using MirShell = mir::shell::Shell;
4490
4491 namespace qtmir {
4492
4493 class MirSurfaceManager;
4494 class QSGMirSurfaceNode;
4495-class QMirSurfaceTextureProvider;
4496+class MirTextureProvider;
4497
4498-class MirSurfaceItem : public MirSurfaceItemInterface
4499+class MirSurfaceItem : public unity::shell::application::MirSurfaceItemInterface
4500 {
4501 Q_OBJECT
4502
4503 public:
4504- explicit MirSurfaceItem(std::shared_ptr<mir::scene::Surface> surface,
4505- SessionInterface* session,
4506- MirShell *shell,
4507- std::shared_ptr<SurfaceObserver> observer,
4508- QQuickItem *parent = 0);
4509+ explicit MirSurfaceItem(QQuickItem *parent = 0);
4510 virtual ~MirSurfaceItem();
4511
4512- //getters
4513- Type type() const override;
4514- State state() const override;
4515+ ////////
4516+ // MirSurfaceItemInterface
4517+
4518+ Mir::Type type() const override;
4519 QString name() const override;
4520 bool live() const override;
4521- SessionInterface *session() const override;
4522- OrientationAngle orientationAngle() const override;
4523-
4524- Q_INVOKABLE void release() override;
4525-
4526- // Item surface/texture management
4527- bool isTextureProvider() const { return true; }
4528- QSGTextureProvider *textureProvider() const;
4529-
4530- void stopFrameDropper() override;
4531- void startFrameDropper() override;
4532-
4533- bool isFirstFrameDrawn() const override { return m_firstFrameDrawn; }
4534-
4535- void setOrientationAngle(OrientationAngle angle) override;
4536- void setSession(SessionInterface *app) override;
4537+
4538+ Mir::State surfaceState() const override;
4539+ void setSurfaceState(Mir::State) override;
4540+
4541+ Mir::OrientationAngle orientationAngle() const override;
4542+ void setOrientationAngle(Mir::OrientationAngle angle) override;
4543+
4544+ unity::shell::application::MirSurfaceInterface* surface() const override;
4545+ void setSurface(unity::shell::application::MirSurfaceInterface*) override;
4546+
4547+ bool consumesInput() const override;
4548+ void setConsumesInput(bool value) override;
4549+
4550+ int surfaceWidth() const override;
4551+ void setSurfaceWidth(int value) override;
4552+
4553+ int surfaceHeight() const override;
4554+ void setSurfaceHeight(int value) override;
4555+
4556+ ////////
4557+ // QQuickItem
4558+
4559+ bool isTextureProvider() const override { return true; }
4560+ QSGTextureProvider *textureProvider() const override;
4561+
4562+ ////////
4563+ // own API
4564
4565 // to allow easy touch event injection from tests
4566 bool processTouchEvent(int eventType,
4567@@ -84,8 +89,10 @@
4568 const QList<QTouchEvent::TouchPoint> &touchPoints,
4569 Qt::TouchPointStates touchPointStates);
4570
4571-protected Q_SLOTS:
4572- void onSessionStateChanged(SessionInterface::State state);
4573+
4574+public Q_SLOTS:
4575+ // Called by QQuickWindow from the rendering thread
4576+ void invalidateSceneGraph();
4577
4578 protected:
4579 void mousePressEvent(QMouseEvent *event) override;
4580@@ -103,33 +110,21 @@
4581
4582 QSGNode *updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *);
4583
4584+ void releaseResources() override;
4585+
4586 private Q_SLOTS:
4587- void surfaceDamaged();
4588- void dropPendingBuffer();
4589- void scheduleTextureUpdate();
4590-
4591 void scheduleMirSurfaceSizeUpdate();
4592 void updateMirSurfaceSize();
4593
4594 void updateMirSurfaceFocus(bool focused);
4595- void onAttributeChanged(const MirSurfaceAttrib, const int);
4596+
4597+ void onActualSurfaceSizeChanged(const QSize &size);
4598
4599 private:
4600- bool updateTexture();
4601- void ensureProvider();
4602-
4603- void setType(const Type&);
4604- void setState(const State&);
4605- void setLive(bool) override;
4606-
4607- // called by MirSurfaceManager
4608- void setSurfaceValid(const bool);
4609+ void ensureTextureProvider();
4610
4611 bool hasTouchInsideUbuntuKeyboard(const QList<QTouchEvent::TouchPoint> &touchPoints);
4612 bool isMouseInsideUbuntuKeyboard(const QMouseEvent *event);
4613- void syncSurfaceSizeWithItemSize();
4614-
4615- bool clientIsRunning() const;
4616
4617 QString appId() const;
4618 void endCurrentTouchSequence(ulong timestamp);
4619@@ -139,22 +134,10 @@
4620 const QList<QTouchEvent::TouchPoint> &touchPoints,
4621 Qt::TouchPointStates touchPointStates);
4622
4623+ MirSurface* m_surface;
4624+
4625 QMutex m_mutex;
4626-
4627- std::shared_ptr<mir::scene::Surface> m_surface;
4628- QPointer<SessionInterface> m_session;
4629- MirShell *const m_shell;
4630- bool m_firstFrameDrawn;
4631- bool m_live;
4632-
4633- //FIXME - have to save the state as Mir has no getter for it (bug:1357429)
4634- OrientationAngle m_orientationAngle;
4635-
4636- QMirSurfaceTextureProvider *m_textureProvider;
4637-
4638- std::shared_ptr<SurfaceObserver> m_surfaceObserver;
4639-
4640- QTimer m_frameDropperTimer;
4641+ MirTextureProvider *m_textureProvider;
4642
4643 QTimer m_updateMirSurfaceSizeTimer;
4644
4645@@ -177,6 +160,14 @@
4646 QList<QTouchEvent::TouchPoint> touchPoints;
4647 Qt::TouchPointStates touchPointStates;
4648 } *m_lastTouchEvent;
4649+
4650+ unsigned int *m_lastFrameNumberRendered;
4651+
4652+ int m_surfaceWidth;
4653+ int m_surfaceHeight;
4654+ Mir::OrientationAngle *m_orientationAngle;
4655+
4656+ bool m_consumesInput;
4657 };
4658
4659 } // namespace qtmir
4660
4661=== removed file 'src/modules/Unity/Application/mirsurfaceiteminterface.h'
4662--- src/modules/Unity/Application/mirsurfaceiteminterface.h 2015-06-15 17:01:28 +0000
4663+++ src/modules/Unity/Application/mirsurfaceiteminterface.h 1970-01-01 00:00:00 +0000
4664@@ -1,116 +0,0 @@
4665-/*
4666- * Copyright (C) 2015 Canonical, Ltd.
4667- *
4668- * This program is free software: you can redistribute it and/or modify it under
4669- * the terms of the GNU Lesser General Public License version 3, as published by
4670- * the Free Software Foundation.
4671- *
4672- * This program is distributed in the hope that it will be useful, but WITHOUT
4673- * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
4674- * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
4675- * Lesser General Public License for more details.
4676- *
4677- * You should have received a copy of the GNU Lesser General Public License
4678- * along with this program. If not, see <http://www.gnu.org/licenses/>.
4679- */
4680-
4681-#ifndef MIRSURFACEITEMINTERFACE_H
4682-#define MIRSURFACEITEMINTERFACE_H
4683-
4684-// Qt
4685-#include <QQuickItem>
4686-
4687-// mir
4688-#include <mir_toolkit/common.h>
4689-
4690-#include "session_interface.h"
4691-
4692-namespace qtmir {
4693-
4694-class MirSurfaceItemInterface : public QQuickItem
4695-{
4696- Q_OBJECT
4697- Q_ENUMS(Type)
4698- Q_ENUMS(State)
4699- Q_ENUMS(OrientationAngle)
4700-
4701- Q_PROPERTY(Type type READ type NOTIFY typeChanged)
4702- Q_PROPERTY(State state READ state NOTIFY stateChanged)
4703- Q_PROPERTY(QString name READ name NOTIFY nameChanged)
4704- Q_PROPERTY(bool live READ live NOTIFY liveChanged)
4705-
4706- // How many degrees, clockwise, the UI in the surface has to rotate to match with the
4707- // shell UI orientation
4708- Q_PROPERTY(OrientationAngle orientationAngle READ orientationAngle WRITE setOrientationAngle
4709- NOTIFY orientationAngleChanged DESIGNABLE false)
4710-
4711-public:
4712- MirSurfaceItemInterface(QQuickItem *parent) : QQuickItem(parent) {}
4713- virtual ~MirSurfaceItemInterface() {}
4714-
4715- enum Type {
4716- Normal = mir_surface_type_normal,
4717- Utility = mir_surface_type_utility,
4718- Dialog = mir_surface_type_dialog,
4719- Overlay = mir_surface_type_overlay,
4720- Freestyle = mir_surface_type_freestyle,
4721- Popover = mir_surface_type_popover,
4722- InputMethod = mir_surface_type_inputmethod,
4723- };
4724-
4725- enum State {
4726- Unknown = mir_surface_state_unknown,
4727- Restored = mir_surface_state_restored,
4728- Minimized = mir_surface_state_minimized,
4729- Maximized = mir_surface_state_maximized,
4730- VertMaximized = mir_surface_state_vertmaximized,
4731- /* SemiMaximized = mir_surface_state_semimaximized, // see mircommon/mir_toolbox/common.h*/
4732- Fullscreen = mir_surface_state_fullscreen,
4733- };
4734-
4735- enum OrientationAngle {
4736- Angle0 = 0,
4737- Angle90 = 90,
4738- Angle180 = 180,
4739- Angle270 = 270
4740- };
4741-
4742- //getters
4743- virtual Type type() const = 0;
4744- virtual State state() const = 0;
4745- virtual QString name() const = 0;
4746- virtual bool live() const = 0;
4747- virtual SessionInterface *session() const = 0;
4748- virtual OrientationAngle orientationAngle() const = 0;
4749-
4750- virtual Q_INVOKABLE void release() = 0;
4751-
4752- virtual void stopFrameDropper() = 0;
4753- virtual void startFrameDropper() = 0;
4754-
4755- virtual bool isFirstFrameDrawn() const = 0;
4756-
4757- virtual void setOrientationAngle(OrientationAngle angle) = 0;
4758- virtual void setSession(SessionInterface *app) = 0;
4759-
4760-Q_SIGNALS:
4761- void typeChanged();
4762- void stateChanged();
4763- void nameChanged();
4764- void orientationAngleChanged(OrientationAngle angle);
4765- void liveChanged(bool live);
4766- void firstFrameDrawn();
4767-
4768-private:
4769- virtual void setLive(bool) = 0;
4770-
4771- friend class MirSurfaceManager;
4772-};
4773-
4774-} // namespace qtmir
4775-
4776-Q_DECLARE_METATYPE(qtmir::MirSurfaceItemInterface*)
4777-Q_DECLARE_METATYPE(qtmir::MirSurfaceItemInterface::OrientationAngle)
4778-
4779-#endif // MIRSURFACEITEMINTERFACE_H
4780-
4781
4782=== removed file 'src/modules/Unity/Application/mirsurfaceitemmodel.h'
4783--- src/modules/Unity/Application/mirsurfaceitemmodel.h 2015-05-27 21:07:45 +0000
4784+++ src/modules/Unity/Application/mirsurfaceitemmodel.h 1970-01-01 00:00:00 +0000
4785@@ -1,32 +0,0 @@
4786-/*
4787- * Copyright (C) 2014 Canonical, Ltd.
4788- *
4789- * This program is free software: you can redistribute it and/or modify it under
4790- * the terms of the GNU Lesser General Public License version 3, as published by
4791- * the Free Software Foundation.
4792- *
4793- * This program is distributed in the hope that it will be useful, but WITHOUT
4794- * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
4795- * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
4796- * Lesser General Public License for more details.
4797- *
4798- * You should have received a copy of the GNU Lesser General Public License
4799- * along with this program. If not, see <http://www.gnu.org/licenses/>.
4800- */
4801-
4802-#ifndef MIRSURFACEITEMMODEL_H
4803-#define MIRSURFACEITEMMODEL_H
4804-
4805-// Local
4806-#include "objectlistmodel.h"
4807-
4808-namespace qtmir {
4809-
4810-class MirSurfaceItemInterface;
4811-typedef ObjectListModel<MirSurfaceItemInterface> MirSurfaceItemModel;
4812-
4813-} // namespace qtmir
4814-
4815-Q_DECLARE_METATYPE(qtmir::MirSurfaceItemModel*)
4816-
4817-#endif // MIRSURFACEITEMMODEL_H
4818
4819=== modified file 'src/modules/Unity/Application/mirsurfacemanager.cpp'
4820--- src/modules/Unity/Application/mirsurfacemanager.cpp 2015-08-11 12:08:32 +0000
4821+++ src/modules/Unity/Application/mirsurfacemanager.cpp 2015-08-27 14:51:37 +0000
4822@@ -14,12 +14,14 @@
4823 * along with this program. If not, see <http://www.gnu.org/licenses/>.
4824 */
4825
4826+#include "mirsurfacemanager.h"
4827+
4828 // Qt
4829 #include <QGuiApplication>
4830 #include <QMutexLocker>
4831
4832 // local
4833-#include "mirsurfacemanager.h"
4834+#include "mirsurface.h"
4835 #include "sessionmanager.h"
4836 #include "application_manager.h"
4837 #include "tracepoints.h" // generated from tracepoints.tp
4838@@ -39,7 +41,7 @@
4839
4840 namespace qtmir {
4841
4842-MirSurfaceManager *MirSurfaceManager::the_surface_manager = nullptr;
4843+MirSurfaceManager *MirSurfaceManager::instance = nullptr;
4844
4845
4846 void connectToSessionListener(MirSurfaceManager *manager, SessionListener *listener)
4847@@ -52,7 +54,7 @@
4848
4849 MirSurfaceManager* MirSurfaceManager::singleton()
4850 {
4851- if (!the_surface_manager) {
4852+ if (!instance) {
4853
4854 NativeInterface *nativeInterface = dynamic_cast<NativeInterface*>(QGuiApplication::platformNativeInterface());
4855
4856@@ -65,11 +67,11 @@
4857 SessionListener *sessionListener = static_cast<SessionListener*>(nativeInterface->nativeResourceForIntegration("SessionListener"));
4858 MirShell *shell = static_cast<MirShell*>(nativeInterface->nativeResourceForIntegration("Shell"));
4859
4860- the_surface_manager = new MirSurfaceManager(nativeInterface->m_mirServer, shell, SessionManager::singleton());
4861+ instance = new MirSurfaceManager(nativeInterface->m_mirServer, shell, SessionManager::singleton());
4862
4863- connectToSessionListener(the_surface_manager, sessionListener);
4864+ connectToSessionListener(instance, sessionListener);
4865 }
4866- return the_surface_manager;
4867+ return instance;
4868 }
4869
4870 MirSurfaceManager::MirSurfaceManager(
4871@@ -77,7 +79,7 @@
4872 MirShell *shell,
4873 SessionManager* sessionManager,
4874 QObject *parent)
4875- : MirSurfaceItemModel(parent)
4876+ : QObject(parent)
4877 , m_mirServer(mirServer)
4878 , m_shell(shell)
4879 , m_sessionManager(sessionManager)
4880@@ -90,7 +92,7 @@
4881 {
4882 qCDebug(QTMIR_SURFACES) << "MirSurfaceManager::~MirSurfaceManager - this=" << this;
4883
4884- m_mirSurfaceToItemHash.clear();
4885+ m_mirSurfaceToQmlSurfaceHash.clear();
4886 }
4887
4888 void MirSurfaceManager::onSessionCreatedSurface(const mir::scene::Session *mirSession,
4889@@ -101,32 +103,29 @@
4890 << "surface=" << surface.get() << "surface.name=" << surface->name().c_str();
4891
4892 SessionInterface* session = m_sessionManager->findSession(mirSession);
4893- auto qmlSurface = new MirSurfaceItem(surface, session, m_shell, observer);
4894+ auto qmlSurface = new MirSurface(surface, session, m_shell, observer);
4895 {
4896 QMutexLocker lock(&m_mutex);
4897- m_mirSurfaceToItemHash.insert(surface.get(), qmlSurface);
4898+ m_mirSurfaceToQmlSurfaceHash.insert(surface.get(), qmlSurface);
4899 }
4900
4901 if (session)
4902 session->setSurface(qmlSurface);
4903
4904 // Only notify QML of surface creation once it has drawn its first frame.
4905- connect(qmlSurface, &MirSurfaceItemInterface::firstFrameDrawn, this, [=]() {
4906+ connect(qmlSurface, &MirSurfaceInterface::firstFrameDrawn, this, [=]() {
4907 tracepoint(qtmir, firstFrameDrawn);
4908 Q_EMIT surfaceCreated(qmlSurface);
4909-
4910- insert(0, qmlSurface);
4911 });
4912
4913- // clean up after MirSurfaceItem is destroyed
4914- connect(qmlSurface, &MirSurfaceItem::destroyed, this, [&](QObject *item) {
4915- auto mirSurfaceItem = static_cast<MirSurfaceItem*>(item);
4916+ // clean up after MirSurface is destroyed
4917+ connect(qmlSurface, &QObject::destroyed, this, [&](QObject *obj) {
4918+ auto qmlSurface = static_cast<MirSurfaceInterface*>(obj);
4919 {
4920 QMutexLocker lock(&m_mutex);
4921- m_mirSurfaceToItemHash.remove(m_mirSurfaceToItemHash.key(mirSurfaceItem));
4922+ m_mirSurfaceToQmlSurfaceHash.remove(m_mirSurfaceToQmlSurfaceHash.key(qmlSurface));
4923 }
4924
4925- remove(mirSurfaceItem);
4926 tracepoint(qtmir, surfaceDestroyed);
4927 });
4928 tracepoint(qtmir, surfaceCreated);
4929@@ -138,25 +137,24 @@
4930 qCDebug(QTMIR_SURFACES) << "MirSurfaceManager::onSessionDestroyingSurface - session=" << session
4931 << "surface=" << surface.get() << "surface.name=" << surface->name().c_str();
4932
4933- MirSurfaceItemInterface* item = nullptr;
4934+ MirSurfaceInterface* qmlSurface = nullptr;
4935 {
4936 QMutexLocker lock(&m_mutex);
4937- auto it = m_mirSurfaceToItemHash.find(surface.get());
4938- if (it != m_mirSurfaceToItemHash.end()) {
4939-
4940- item = it.value();
4941-
4942- m_mirSurfaceToItemHash.remove(m_mirSurfaceToItemHash.key(item));
4943+ auto it = m_mirSurfaceToQmlSurfaceHash.find(surface.get());
4944+ if (it != m_mirSurfaceToQmlSurfaceHash.end()) {
4945+
4946+ qmlSurface = it.value();
4947+
4948+ m_mirSurfaceToQmlSurfaceHash.remove(m_mirSurfaceToQmlSurfaceHash.key(qmlSurface));
4949 } else {
4950- qCritical() << "MirSurfaceManager::onSessionDestroyingSurface: unable to find MirSurfaceItem corresponding"
4951+ qCritical() << "MirSurfaceManager::onSessionDestroyingSurface: unable to find MirSurface corresponding"
4952 << "to surface=" << surface.get() << "surface.name=" << surface->name().c_str();
4953 return;
4954 }
4955 }
4956
4957- item->setEnabled(false); //disable input events
4958- item->setLive(false); //disable input events
4959- Q_EMIT surfaceDestroyed(item);
4960+ qmlSurface->setLive(false);
4961+ Q_EMIT surfaceDestroyed(qmlSurface);
4962 }
4963
4964 } // namespace qtmir
4965
4966=== modified file 'src/modules/Unity/Application/mirsurfacemanager.h'
4967--- src/modules/Unity/Application/mirsurfacemanager.h 2015-08-11 12:08:32 +0000
4968+++ src/modules/Unity/Application/mirsurfacemanager.h 2015-08-27 14:51:37 +0000
4969@@ -21,15 +21,16 @@
4970 #include <memory>
4971
4972 // Qt
4973+#include <QObject>
4974 #include <QHash>
4975 #include <QMutex>
4976+#include <QSharedPointer>
4977
4978 // Mir
4979 #include <mir_toolkit/common.h>
4980
4981 // local
4982-#include "mirsurfaceitem.h"
4983-#include "mirsurfaceitemmodel.h"
4984+#include <mirserver.h>
4985
4986 namespace mir {
4987 namespace scene {
4988@@ -40,14 +41,16 @@
4989 }
4990
4991 class MirServer;
4992+class SurfaceObserver;
4993
4994 namespace qtmir {
4995
4996 class Application;
4997 class ApplicationManager;
4998+class MirSurfaceInterface;
4999 class SessionManager;
5000
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches