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 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Mir development team | Pending | ||
Review via email: mp+264172@code.launchpad.net |
Commit message
DO NOT MERGE
Description of the change
- 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
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 |