Merge lp:~dandrader/qtmir/content-hub-clipboard into lp:qtmir
- content-hub-clipboard
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Michael Terry |
Approved revision: | no longer in the source branch. |
Merged at revision: | 556 |
Proposed branch: | lp:~dandrader/qtmir/content-hub-clipboard |
Merge into: | lp:qtmir |
Prerequisite: | lp:~dandrader/qtmir/focusInfoSurfaceId |
Diff against target: |
806 lines (+218/-408) 13 files modified
CMakeLists.txt (+1/-0) debian/control (+1/-0) src/modules/Unity/Application/dbusfocusinfo.cpp (+11/-2) src/platforms/mirserver/CMakeLists.txt (+5/-0) src/platforms/mirserver/clipboard.cpp (+91/-241) src/platforms/mirserver/clipboard.h (+36/-53) src/platforms/mirserver/mirserverintegration.cpp (+5/-4) src/platforms/mirserver/mirserverintegration.h (+0/-5) src/platforms/mirserver/shelluuid.cpp (+35/-0) src/platforms/mirserver/shelluuid.h (+33/-0) tests/mirserver/CMakeLists.txt (+0/-1) tests/mirserver/Clipboard/CMakeLists.txt (+0/-27) tests/mirserver/Clipboard/clipboard_test.cpp (+0/-75) |
To merge this branch: | bzr merge lp:~dandrader/qtmir/content-hub-clipboard |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Michael Terry (community) | testing | Approve | |
Unity8 CI Bot (community) | continuous-integration | Needs Fixing | |
Gerry Boland | code | Pending | |
Review via email: mp+303863@code.launchpad.net |
This proposal supersedes a proposal from 2016-08-01.
Commit message
Use content-hub for clipboard services
And remove our own implementation of such service
Description of the change
* Are there any related MPs required for this MP to build/function as expected? Please list.
It's all in silo 037 (https:/
* Did you perform an exploratory manual test run of your code change and any related functionality?
Yes
To test copy-and-paste from inside unity8 add this snippet to Shell.qml:
http://
That will give you a a text field on the bottom right of shell UI.
* If you changed the packaging (debian), did you subscribe the ubuntu-unity team to this MP?
N/A
Unity8 CI Bot (unity8-ci-bot) wrote : Posted in a previous version of this proposal | # |
Gerry Boland (gerboland) wrote : Posted in a previous version of this proposal | # |
=== modified file 'src/platforms/
+ * Copyright (C) 2014,2016 Canonical, Ltd.
2014-2016
+ QMimeData *mMimeData;
Using a QScopedPointer here would mean you don't have to worry about deleting the contents before you change it.
Similar for mPasteReply, that I don't see ever being deleted here - leak?
=== modified file 'src/platforms/
+ QDBusPendingCal
one of those times "auto" is nicer, since you state the type twice.
Everything else quite sensible. I need to test the silo though
Daniel d'Andrada (dandrader) wrote : Posted in a previous version of this proposal | # |
On 03/08/2016 13:30, Gerry Boland wrote:
> Review: Needs Fixing
>
> === modified file 'src/platforms/
> + * Copyright (C) 2014,2016 Canonical, Ltd.
> 2014-2016
Done.
> + QMimeData *mMimeData;
> Using a QScopedPointer here would mean you don't have to worry about deleting the contents before you change it.
Done.
> Similar for mPasteReply, that I don't see ever being deleted here - leak?
Yes, leak. Fixed. Thanks!
> === modified file 'src/platforms/
> + QDBusPendingCal
> one of those times "auto" is nicer, since you state the type twice.
>
Right. Done.
Unity8 CI Bot (unity8-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:531
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
Unity8 CI Bot (unity8-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:534
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
Gerry Boland (gerboland) wrote : Posted in a previous version of this proposal | # |
+Clipboard:
+{
+ mMimeData.reset(new QMimeData);
This is nicer:
+Clipboard:
+ : mMimeData(new QMimeData);
+void Clipboard:
+ QDBusPendingCall reply = mContentHub-
+
+ // Don't care whether it succeeded
+ auto *watcher = new QDBusPendingCal
+ connect(watcher, &QDBusPendingCa
+ watcher, &QObject:
if you don't care, why do you do this at all? I would think just calling createPaste and throwing away the returned QDBusPendingCall is enough.
Rest looks good though
Daniel d'Andrada (dandrader) wrote : Posted in a previous version of this proposal | # |
> +void Clipboard:
> + QDBusPendingCall reply = mContentHub-
> +
> + // Don't care whether it succeeded
> + auto *watcher = new QDBusPendingCal
> + connect(watcher, &QDBusPendingCa
> + watcher, &QObject:
> if you don't care, why do you do this at all? I would think just calling
> createPaste and throwing away the returned QDBusPendingCall is enough.
I also thought that when I first wrote it. But the destructor of a QDBusPendingCall cancels the call if it's still ongoing and we don't want that. Thus we have to keep a QDBusPendingCall instance around (such as a QDBusPendingCal
Daniel d'Andrada (dandrader) wrote : Posted in a previous version of this proposal | # |
> +Clipboard:
> +{
> + mMimeData.reset(new QMimeData);
> This is nicer:
> +Clipboard:
> + : mMimeData(new QMimeData);
Done.
Unity8 CI Bot (unity8-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:535
https:/
Executed test runs:
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
Gerry Boland (gerboland) wrote : Posted in a previous version of this proposal | # |
> > if you don't care, why do you do this at all? I would think just calling
> > createPaste and throwing away the returned QDBusPendingCall is enough.
>
> I also thought that when I first wrote it. But the destructor of a
> QDBusPendingCall cancels the call if it's still ongoing and we don't want
> that. Thus we have to keep a QDBusPendingCall instance around (such as a
> QDBusPendingCal
Oh wow, that's unexpected. Would you please add comment saying this? It's totally code that someone would delete in the future if they just looked at it:)
Daniel d'Andrada (dandrader) wrote : Posted in a previous version of this proposal | # |
> > > if you don't care, why do you do this at all? I would think just calling
> > > createPaste and throwing away the returned QDBusPendingCall is enough.
> >
> > I also thought that when I first wrote it. But the destructor of a
> > QDBusPendingCall cancels the call if it's still ongoing and we don't want
> > that. Thus we have to keep a QDBusPendingCall instance around (such as a
> > QDBusPendingCal
>
> Oh wow, that's unexpected. Would you please add comment saying this? It's
> totally code that someone would delete in the future if they just looked at
> it:)
Sure, done.
Unity8 CI Bot (unity8-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:536
https:/
Executed test runs:
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
Unity8 CI Bot (unity8-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:540
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
Gerry Boland (gerboland) wrote : Posted in a previous version of this proposal | # |
Am waiting for the silo to be rebuilt before testing. Code is fine however
Unity8 CI Bot (unity8-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:549
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
Unity8 CI Bot (unity8-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:549
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
Unity8 CI Bot (unity8-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:550
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
- 550. By Daniel d'Andrada
-
DBusFocusInfo.
isPidFocused: search sessions recursively (LP: #1612166) Approved by: Gerry Boland, Unity8 CI Bot
- 551. By Michał Sawicz
-
Revert r538 that's causing a unity8 crash when launching emergency dialer over greeter (LP: #1616842)
Approved by: Unity8 CI Bot
- 552. By CI Train Bot Account
-
Releasing 0.4.8+16.
10.20160826. 1-0ubuntu1
Unity8 CI Bot (unity8-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:552
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
Michael Terry (mterry) wrote : | # |
I did not review the code (but Gerry did and liked it above). I did test silo 37 though and it worked fine (was able to copy/paste text from notification into app and the reverse).
CI is failing because of lttng apparently.
- 553. By Daniel d'Andrada
- 554. By Daniel d'Andrada
-
DBusFocusInfo: added isSurfaceFocuse
d(serializedId) - 555. By Daniel d'Andrada
-
Use content-hub for clipboard services
And remove our own implementation of such service
Preview Diff
1 | === modified file 'CMakeLists.txt' |
2 | --- CMakeLists.txt 2016-08-30 12:33:06 +0000 |
3 | +++ CMakeLists.txt 2016-08-30 12:33:06 +0000 |
4 | @@ -85,6 +85,7 @@ |
5 | pkg_check_modules(QTDBUSMOCK libqtdbusmock-1 REQUIRED) |
6 | pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=21) |
7 | pkg_check_modules(CGMANAGER libcgmanager REQUIRED) |
8 | +pkg_check_modules(CONTENT_HUB libcontent-hub>=0.2 REQUIRED) |
9 | |
10 | include_directories(SYSTEM ${APPLICATION_API_INCLUDE_DIRS}) |
11 | |
12 | |
13 | === modified file 'debian/control' |
14 | --- debian/control 2016-08-30 12:33:06 +0000 |
15 | +++ debian/control 2016-08-30 12:33:06 +0000 |
16 | @@ -7,6 +7,7 @@ |
17 | debhelper (>= 9), |
18 | google-mock (>= 1.6.0+svn437), |
19 | libcgmanager-dev, |
20 | + libcontent-hub-dev (>= 0.2), |
21 | libfontconfig1-dev, |
22 | libgles2-mesa-dev, |
23 | libglib2.0-dev, |
24 | |
25 | === modified file 'src/modules/Unity/Application/dbusfocusinfo.cpp' |
26 | --- src/modules/Unity/Application/dbusfocusinfo.cpp 2016-08-30 12:33:06 +0000 |
27 | +++ src/modules/Unity/Application/dbusfocusinfo.cpp 2016-08-30 12:33:06 +0000 |
28 | @@ -24,6 +24,7 @@ |
29 | |
30 | // QPA mirserver |
31 | #include <logging.h> |
32 | +#include <shelluuid.h> |
33 | |
34 | #include <QDBusConnection> |
35 | |
36 | @@ -99,8 +100,16 @@ |
37 | |
38 | bool DBusFocusInfo::isSurfaceFocused(const QString &serializedId) |
39 | { |
40 | - MirSurfaceInterface *qmlSurface = findQmlSurface(serializedId); |
41 | - bool result = qmlSurface ? qmlSurface->activeFocus() : false; |
42 | + // TODO: Implement a penalty for negative queries, such as stalling for some time before answering |
43 | + // further queries. That's in order to avoid brute-force approaches to find a valid surface id. |
44 | + // That's particularly important for shell's own surface id as it's always valid. |
45 | + bool result = false; |
46 | + if (serializedId == ShellUuId::toString()) { |
47 | + result = true; |
48 | + } else { |
49 | + MirSurfaceInterface *qmlSurface = findQmlSurface(serializedId); |
50 | + result = qmlSurface ? qmlSurface->activeFocus() : false; |
51 | + } |
52 | qCDebug(QTMIR_DBUS).nospace() << "DBusFocusInfo: isSurfaceFocused("<<serializedId<<") -> " << result; |
53 | return result; |
54 | } |
55 | |
56 | === modified file 'src/platforms/mirserver/CMakeLists.txt' |
57 | --- src/platforms/mirserver/CMakeLists.txt 2016-07-15 15:38:04 +0000 |
58 | +++ src/platforms/mirserver/CMakeLists.txt 2016-08-30 12:33:06 +0000 |
59 | @@ -44,6 +44,8 @@ |
60 | ${Qt5Quick_PRIVATE_INCLUDE_DIRS} |
61 | |
62 | ${APPLICATION_API_INCLUDE_DIRS} |
63 | + |
64 | + ${CONTENT_HUB_INCLUDE_DIRS} |
65 | ) |
66 | |
67 | # We have to remove -pedantic for tracepoints.c |
68 | @@ -66,6 +68,7 @@ |
69 | qmirserver_p.cpp |
70 | sessionauthorizer.cpp |
71 | sessionlistener.cpp |
72 | + shelluuid.cpp |
73 | surfaceobserver.cpp |
74 | promptsessionlistener.cpp |
75 | mirserver.cpp |
76 | @@ -112,6 +115,8 @@ |
77 | ${FONTCONFIG_LDFLAGS} |
78 | ${XKBCOMMON_LIBRARIES} |
79 | |
80 | + ${CONTENT_HUB_LIBRARIES} |
81 | + |
82 | Qt5::Core |
83 | Qt5::DBus |
84 | Qt5::Quick |
85 | |
86 | === modified file 'src/platforms/mirserver/clipboard.cpp' |
87 | --- src/platforms/mirserver/clipboard.cpp 2016-06-06 19:25:20 +0000 |
88 | +++ src/platforms/mirserver/clipboard.cpp 2016-08-30 12:33:06 +0000 |
89 | @@ -1,5 +1,5 @@ |
90 | /* |
91 | - * Copyright (C) 2014-2015 Canonical, Ltd. |
92 | + * Copyright (C) 2014,2016 Canonical, Ltd. |
93 | * |
94 | * This program is free software: you can redistribute it and/or modify it under |
95 | * the terms of the GNU Lesser General Public License version 3, as published by |
96 | @@ -15,245 +15,95 @@ |
97 | */ |
98 | |
99 | #include "clipboard.h" |
100 | -#include "logging.h" |
101 | - |
102 | -// C++ std lib |
103 | -#include <utility> |
104 | - |
105 | -#include <QDBusConnection> |
106 | -#include <QDBusError> |
107 | -#include <QMimeData> |
108 | - |
109 | -// FIXME(loicm) The clipboard data format is not defined by Ubuntu Platform API |
110 | -// which makes it impossible to have non-Qt applications communicate with Qt |
111 | -// applications through the clipboard API. The solution would be to have |
112 | -// Ubuntu Platform define the data format or propose an API that supports |
113 | -// embedding different mime types in the clipboard. |
114 | - |
115 | -// Data format: |
116 | -// number of mime types (sizeof(int)) |
117 | -// data layout ((4 * sizeof(int)) * number of mime types) |
118 | -// mime type string offset (sizeof(int)) |
119 | -// mime type string size (sizeof(int)) |
120 | -// data offset (sizeof(int)) |
121 | -// data size (sizeof(int)) |
122 | -// data (n bytes) |
123 | - |
124 | -namespace { |
125 | - |
126 | -const int maxFormatsCount = 16; |
127 | - |
128 | -} |
129 | - |
130 | -namespace qtmir { |
131 | - |
132 | -QByteArray serializeMimeData(QMimeData *mimeData) |
133 | -{ |
134 | - const QStringList formats = mimeData->formats(); |
135 | - const int formatCount = qMin(formats.size(), maxFormatsCount); |
136 | - const int headerSize = sizeof(int) + (formatCount * 4 * sizeof(int)); |
137 | - int bufferSize = headerSize; |
138 | - |
139 | - for (int i = 0; i < formatCount; i++) |
140 | - bufferSize += formats[i].size() + mimeData->data(formats[i]).size(); |
141 | - |
142 | - // Serialize data. |
143 | - QByteArray serializedMimeData(bufferSize, 0 /* char to fill with */); |
144 | - { |
145 | - char *buffer = serializedMimeData.data(); |
146 | - int* header = reinterpret_cast<int*>(serializedMimeData.data()); |
147 | - int offset = headerSize; |
148 | - header[0] = formatCount; |
149 | - for (int i = 0; i < formatCount; i++) { |
150 | - const QByteArray data = mimeData->data(formats[i]); |
151 | - const int formatOffset = offset; |
152 | - const int formatSize = formats[i].size(); |
153 | - const int dataOffset = offset + formatSize; |
154 | - const int dataSize = data.size(); |
155 | - memcpy(&buffer[formatOffset], formats[i].toLatin1().data(), formatSize); |
156 | - memcpy(&buffer[dataOffset], data.data(), dataSize); |
157 | - header[i*4+1] = formatOffset; |
158 | - header[i*4+2] = formatSize; |
159 | - header[i*4+3] = dataOffset; |
160 | - header[i*4+4] = dataSize; |
161 | - offset += formatSize + dataSize; |
162 | - } |
163 | - } |
164 | - |
165 | - return serializedMimeData; |
166 | -} |
167 | - |
168 | -QMimeData *deserializeMimeData(const QByteArray &serializedMimeData) |
169 | -{ |
170 | - if (static_cast<std::size_t>(serializedMimeData.size()) < sizeof(int)) { |
171 | - // Data is invalid |
172 | - return nullptr; |
173 | - } |
174 | - |
175 | - QMimeData *mimeData = new QMimeData; |
176 | - |
177 | - const char* const buffer = serializedMimeData.constData(); |
178 | - const int* const header = reinterpret_cast<const int*>(serializedMimeData.constData()); |
179 | - |
180 | - const int count = qMin(header[0], maxFormatsCount); |
181 | - |
182 | - for (int i = 0; i < count; i++) { |
183 | - const int formatOffset = header[i*4+1]; |
184 | - const int formatSize = header[i*4+2]; |
185 | - const int dataOffset = header[i*4+3]; |
186 | - const int dataSize = header[i*4+4]; |
187 | - |
188 | - if (formatOffset + formatSize <= serializedMimeData.size() |
189 | - && dataOffset + dataSize <= serializedMimeData.size()) { |
190 | - |
191 | - QString mimeType = QString::fromLatin1(&buffer[formatOffset], formatSize); |
192 | - QByteArray mimeDataBytes(&buffer[dataOffset], dataSize); |
193 | - |
194 | - mimeData->setData(mimeType, mimeDataBytes); |
195 | - } |
196 | - } |
197 | - |
198 | - return mimeData; |
199 | -} |
200 | - |
201 | -/************************************ DBusClipboard *****************************************/ |
202 | - |
203 | -bool DBusClipboard::skipDBusRegistration = false; |
204 | - |
205 | -DBusClipboard::DBusClipboard(QObject *parent) |
206 | - : QObject(parent) |
207 | -{ |
208 | - if (!skipDBusRegistration) { |
209 | - performDBusRegistration(); |
210 | - } |
211 | -} |
212 | - |
213 | -void DBusClipboard::setContents(QByteArray newContents) |
214 | -{ |
215 | - setContentsHelper(std::move(newContents)); |
216 | -} |
217 | - |
218 | -void DBusClipboard::SetContents(QByteArray newContents) |
219 | -{ |
220 | - qCDebug(QTMIR_CLIPBOARD, "D-Bus SetContents - %d bytes", newContents.size()); |
221 | - |
222 | - if (setContentsHelper(std::move(newContents))) { |
223 | - Q_EMIT contentsChangedRemotely(); |
224 | - } |
225 | -} |
226 | - |
227 | -bool DBusClipboard::setContentsHelper(QByteArray newContents) |
228 | -{ |
229 | - if (newContents.size() > maxContentsSize) { |
230 | - qCWarning(QTMIR_CLIPBOARD, "D-Bus clipboard refused the new contents (%d bytes) as they're" |
231 | - " bigger than the maximum allowed size of %d bytes.", |
232 | - newContents.size(), maxContentsSize); |
233 | - return false; |
234 | - } |
235 | - |
236 | - if (newContents != m_contents) { |
237 | - m_contents = std::move(newContents); |
238 | - Q_EMIT ContentsChanged(m_contents); |
239 | - return true; |
240 | - } else { |
241 | - return false; |
242 | - } |
243 | -} |
244 | - |
245 | -QByteArray DBusClipboard::GetContents() const |
246 | -{ |
247 | - qCDebug(QTMIR_CLIPBOARD, "D-Bus GetContents - returning %d bytes", m_contents.size()); |
248 | - return m_contents; |
249 | -} |
250 | - |
251 | -void DBusClipboard::performDBusRegistration() |
252 | -{ |
253 | - QDBusConnection connection = QDBusConnection::sessionBus(); |
254 | - const char *serviceName = "com.canonical.QtMir"; |
255 | - const char *objectName = "/com/canonical/QtMir/Clipboard"; |
256 | - |
257 | - bool serviceOk = connection.registerService(serviceName); |
258 | - if (!serviceOk) { |
259 | - QDBusError error = connection.lastError(); |
260 | - QString errorMessage; |
261 | - if (error.isValid()) { |
262 | - errorMessage = error.message(); |
263 | - } |
264 | - qCCritical(QTMIR_CLIPBOARD, "Failed to register service %s. %s", serviceName, qPrintable(errorMessage)); |
265 | - } |
266 | - |
267 | - bool objectOk = connection.registerObject(objectName, this, |
268 | - QDBusConnection::ExportScriptableSignals |
269 | - | QDBusConnection::ExportScriptableSlots); |
270 | - if (!objectOk) { |
271 | - QDBusError error = connection.lastError(); |
272 | - QString errorMessage; |
273 | - if (error.isValid()) { |
274 | - errorMessage = error.message(); |
275 | - } |
276 | - qCCritical(QTMIR_CLIPBOARD, "Failed to register object %s. %s", objectName, qPrintable(errorMessage)); |
277 | - } |
278 | - |
279 | - if (serviceOk && objectOk) { |
280 | - qCDebug(QTMIR_CLIPBOARD, "D-Bus registration successful."); |
281 | - } |
282 | -} |
283 | - |
284 | -/************************************ Clipboard *****************************************/ |
285 | - |
286 | -Clipboard::Clipboard(QObject *parent) |
287 | - : QObject(parent) |
288 | - , m_dbusClipboard(nullptr) |
289 | -{ |
290 | -} |
291 | - |
292 | -QMimeData *Clipboard::mimeData(QClipboard::Mode mode) |
293 | -{ |
294 | - if (mode == QClipboard::Clipboard) { |
295 | - return QPlatformClipboard::mimeData(mode); |
296 | - } else { |
297 | - return nullptr; |
298 | - } |
299 | -} |
300 | - |
301 | -void Clipboard::setMimeData(QMimeData *data, QClipboard::Mode mode) |
302 | +#include "shelluuid.h" |
303 | + |
304 | +#include <QDBusPendingCallWatcher> |
305 | +#include <QSignalBlocker> |
306 | + |
307 | +// content-hub |
308 | +#include <com/ubuntu/content/hub.h> |
309 | + |
310 | +// get this cumbersome nested namespace out of the way |
311 | +using namespace com::ubuntu::content; |
312 | + |
313 | +using namespace qtmir; |
314 | + |
315 | +Clipboard::Clipboard() |
316 | + : QObject(nullptr) |
317 | + , m_mimeData(new QMimeData) |
318 | + , m_contentHub(Hub::Client::instance()) |
319 | +{ |
320 | + connect(m_contentHub, &Hub::pasteboardChanged, this, [this]() { |
321 | + if (m_clipboardState == Clipboard::SyncedClipboard) { |
322 | + m_clipboardState = Clipboard::OutdatedClipboard; |
323 | + requestMimeData(); |
324 | + } |
325 | + }); |
326 | + |
327 | + requestMimeData(); |
328 | +} |
329 | + |
330 | +Clipboard::~Clipboard() |
331 | +{ |
332 | +} |
333 | + |
334 | +QMimeData* Clipboard::mimeData(QClipboard::Mode mode) |
335 | { |
336 | if (mode != QClipboard::Clipboard) |
337 | - return; |
338 | - |
339 | - if (m_dbusClipboard) { |
340 | - QByteArray serializedMimeData = serializeMimeData(data); |
341 | - m_dbusClipboard->setContents(std::move(serializedMimeData)); |
342 | - } |
343 | - |
344 | - QPlatformClipboard::setMimeData(data, mode); |
345 | -} |
346 | - |
347 | -void Clipboard::setupDBusService() |
348 | -{ |
349 | - Q_ASSERT(!m_dbusClipboard); |
350 | - |
351 | - m_dbusClipboard = new DBusClipboard(this); |
352 | - |
353 | - connect(m_dbusClipboard, &DBusClipboard::contentsChangedRemotely, |
354 | - this, &Clipboard::setMimeDataWithDBusClibpboardContents); |
355 | -} |
356 | - |
357 | -void Clipboard::setMimeDataWithDBusClibpboardContents() |
358 | -{ |
359 | - Q_ASSERT(m_dbusClipboard); |
360 | - QMimeData *newMimeData = deserializeMimeData(m_dbusClipboard->contents()); |
361 | - if (newMimeData) { |
362 | - // Don't call Clipboard::setMimeData as it will also propagate the change |
363 | - // to the D-Bus clipboard, which doesn't make sense here as we're doing |
364 | - // the other way round (propagating the D-Bus clipboard change to the local |
365 | - // clipboard). |
366 | - QPlatformClipboard::setMimeData(newMimeData, QClipboard::Clipboard); |
367 | - } else { |
368 | - qCWarning(QTMIR_CLIPBOARD, "Failed to deserialize D-Bus clipboard contents (%d bytes)", |
369 | - m_dbusClipboard->contents().size()); |
370 | - } |
371 | -} |
372 | - |
373 | -} // namespace qtmir |
374 | - |
375 | + return nullptr; |
376 | + |
377 | + return m_mimeData.data(); |
378 | +} |
379 | + |
380 | +void Clipboard::setMimeData(QMimeData* mimeData, QClipboard::Mode mode) |
381 | +{ |
382 | + if (mode == QClipboard::Clipboard && mimeData != nullptr) { |
383 | + QDBusPendingCall reply = m_contentHub->createPaste(ShellUuId::toString(), *mimeData); |
384 | + |
385 | + // Don't care whether it succeeded |
386 | + // But I have to keep a QDBusPendingCall instance around (such as this watcher) until |
387 | + // the call is finished otherwise the QDBusPendingCall destructor will cancel the call |
388 | + // if it's still ongoing. |
389 | + auto *watcher = new QDBusPendingCallWatcher(reply, this); |
390 | + connect(watcher, &QDBusPendingCallWatcher::finished, |
391 | + watcher, &QObject::deleteLater); |
392 | + |
393 | + m_mimeData.reset(mimeData); |
394 | + m_clipboardState = SyncedClipboard; |
395 | + emitChanged(QClipboard::Clipboard); |
396 | + } |
397 | +} |
398 | + |
399 | +bool Clipboard::supportsMode(QClipboard::Mode mode) const |
400 | +{ |
401 | + return mode == QClipboard::Clipboard; |
402 | +} |
403 | + |
404 | +bool Clipboard::ownsMode(QClipboard::Mode mode) const |
405 | +{ |
406 | + Q_UNUSED(mode); |
407 | + return false; |
408 | +} |
409 | + |
410 | +void Clipboard::updateMimeData() |
411 | +{ |
412 | + m_mimeData.reset(m_contentHub->latestPaste(ShellUuId::toString())); |
413 | + m_clipboardState = SyncedClipboard; |
414 | + emitChanged(QClipboard::Clipboard); |
415 | +} |
416 | + |
417 | +void Clipboard::requestMimeData() |
418 | +{ |
419 | + QDBusPendingCall reply = m_contentHub->requestLatestPaste(ShellUuId::toString()); |
420 | + m_clipboardState = SyncingClipboard; |
421 | + |
422 | + m_pasteReply = new QDBusPendingCallWatcher(reply, this); |
423 | + connect(m_pasteReply, &QDBusPendingCallWatcher::finished, |
424 | + this, [this]() { |
425 | + m_mimeData.reset(m_contentHub->paste(*m_pasteReply)); |
426 | + m_clipboardState = SyncedClipboard; |
427 | + m_pasteReply->deleteLater(); |
428 | + m_pasteReply = nullptr; |
429 | + emitChanged(QClipboard::Clipboard); |
430 | + }); |
431 | +} |
432 | |
433 | === modified file 'src/platforms/mirserver/clipboard.h' |
434 | --- src/platforms/mirserver/clipboard.h 2015-08-11 12:08:32 +0000 |
435 | +++ src/platforms/mirserver/clipboard.h 2016-08-30 12:33:06 +0000 |
436 | @@ -1,5 +1,5 @@ |
437 | /* |
438 | - * Copyright (C) 2014-2015 Canonical, Ltd. |
439 | + * Copyright (C) 2014-2016 Canonical, Ltd. |
440 | * |
441 | * This program is free software: you can redistribute it and/or modify it under |
442 | * the terms of the GNU Lesser General Public License version 3, as published by |
443 | @@ -18,69 +18,52 @@ |
444 | #define QTMIR_CLIPBOARD_H |
445 | |
446 | #include <qpa/qplatformclipboard.h> |
447 | -#include <QObject> |
448 | + |
449 | +#include <QMimeData> |
450 | +#include <QScopedPointer> |
451 | + |
452 | +namespace com { |
453 | + namespace ubuntu { |
454 | + namespace content { |
455 | + class Hub; |
456 | + } |
457 | + } |
458 | +} |
459 | + |
460 | +class QDBusPendingCallWatcher; |
461 | |
462 | namespace qtmir { |
463 | |
464 | -class DBusClipboard : public QObject { |
465 | - Q_OBJECT |
466 | - Q_CLASSINFO("D-Bus Interface", "com.canonical.QtMir.Clipboard") |
467 | -public: |
468 | - DBusClipboard(QObject *parent = nullptr); |
469 | - virtual ~DBusClipboard() {} |
470 | - |
471 | - void setContents(QByteArray contents); |
472 | - const QByteArray &contents() const { return m_contents; } |
473 | - |
474 | - static const int maxContentsSize = 4 * 1024 * 1024; // 4 Mb |
475 | - |
476 | - // To make it testable |
477 | - static bool skipDBusRegistration; |
478 | - |
479 | -Q_SIGNALS: |
480 | - Q_SCRIPTABLE void ContentsChanged(const QByteArray &contents); |
481 | - void contentsChangedRemotely(); |
482 | - |
483 | -public Q_SLOTS: |
484 | - Q_SCRIPTABLE QByteArray GetContents() const; |
485 | - Q_SCRIPTABLE void SetContents(QByteArray contents); |
486 | - |
487 | -private: |
488 | - void performDBusRegistration(); |
489 | - bool setContentsHelper(QByteArray newContents); |
490 | - |
491 | - // Contains a serialized QMimeData |
492 | - // Serialization and deserialization is done by the QPlatformClipboard |
493 | - // implementation. |
494 | - QByteArray m_contents; |
495 | -}; |
496 | - |
497 | class Clipboard : public QObject, public QPlatformClipboard |
498 | { |
499 | Q_OBJECT |
500 | public: |
501 | - Clipboard(QObject *parent = nullptr); |
502 | - virtual ~Clipboard() {} |
503 | - |
504 | - QMimeData *mimeData(QClipboard::Mode mode = QClipboard::Clipboard) override; |
505 | - void setMimeData(QMimeData *data, QClipboard::Mode mode) override; |
506 | - |
507 | - void setupDBusService(); |
508 | - |
509 | -private Q_SLOTS: |
510 | - void setMimeDataWithDBusClibpboardContents(); |
511 | + Clipboard(); |
512 | + virtual ~Clipboard(); |
513 | + |
514 | + // QPlatformClipboard methods. |
515 | + QMimeData* mimeData(QClipboard::Mode mode = QClipboard::Clipboard) override; |
516 | + void setMimeData(QMimeData* data, QClipboard::Mode mode = QClipboard::Clipboard) override; |
517 | + bool supportsMode(QClipboard::Mode mode) const override; |
518 | + bool ownsMode(QClipboard::Mode mode) const override; |
519 | |
520 | private: |
521 | - |
522 | - DBusClipboard *m_dbusClipboard; |
523 | + void updateMimeData(); |
524 | + void requestMimeData(); |
525 | + |
526 | + QScopedPointer<QMimeData> m_mimeData; |
527 | + |
528 | + enum { |
529 | + OutdatedClipboard, // Our mimeData is outdated, need to fetch latest from ContentHub |
530 | + SyncingClipboard, // Our mimeData is outdated and we are waiting for ContentHub to reply with the latest paste |
531 | + SyncedClipboard // Our mimeData is in sync with what ContentHub has |
532 | + } m_clipboardState{OutdatedClipboard}; |
533 | + |
534 | + com::ubuntu::content::Hub *m_contentHub; |
535 | + |
536 | + QDBusPendingCallWatcher *m_pasteReply{nullptr}; |
537 | }; |
538 | |
539 | -// NB: Copied from qtubuntu. Must be kept in sync with the original version! |
540 | -// Best thing would be to share this code somehow, but not bothering with it right now |
541 | -// as the clipboard will move to content-hub at some point. |
542 | -QByteArray serializeMimeData(QMimeData *mimeData); |
543 | -QMimeData *deserializeMimeData(const QByteArray &serializedMimeData); |
544 | - |
545 | } // namespace qtmir |
546 | |
547 | #endif // QTMIR_CLIPBOARD_H |
548 | |
549 | === modified file 'src/platforms/mirserver/mirserverintegration.cpp' |
550 | --- src/platforms/mirserver/mirserverintegration.cpp 2016-08-10 06:51:37 +0000 |
551 | +++ src/platforms/mirserver/mirserverintegration.cpp 2016-08-30 12:33:06 +0000 |
552 | @@ -56,7 +56,6 @@ |
553 | , m_services(new Services) |
554 | , m_mirServer(new QMirServer(argc, argv)) |
555 | , m_nativeInterface(nullptr) |
556 | - , m_clipboard(new Clipboard) |
557 | { |
558 | // For access to sensors, qtmir uses qtubuntu-sensors. qtubuntu-sensors reads the |
559 | // UBUNTU_PLATFORM_API_BACKEND variable to decide if to load a valid sensor backend or not. |
560 | @@ -159,8 +158,6 @@ |
561 | } |
562 | |
563 | m_nativeInterface = new NativeInterface(m_mirServer.data()); |
564 | - |
565 | - m_clipboard->setupDBusService(); |
566 | } |
567 | |
568 | QPlatformAccessibility *MirServerIntegration::accessibility() const |
569 | @@ -196,7 +193,11 @@ |
570 | |
571 | QPlatformClipboard *MirServerIntegration::clipboard() const |
572 | { |
573 | - return m_clipboard.data(); |
574 | + static QPlatformClipboard *clipboard = nullptr; |
575 | + if (!clipboard) { |
576 | + clipboard = new Clipboard; |
577 | + } |
578 | + return clipboard; |
579 | } |
580 | |
581 | QPlatformOffscreenSurface *MirServerIntegration::createPlatformOffscreenSurface( |
582 | |
583 | === modified file 'src/platforms/mirserver/mirserverintegration.h' |
584 | --- src/platforms/mirserver/mirserverintegration.h 2015-10-29 19:51:56 +0000 |
585 | +++ src/platforms/mirserver/mirserverintegration.h 2016-08-30 12:33:06 +0000 |
586 | @@ -24,10 +24,6 @@ |
587 | class NativeInterface; |
588 | class QMirServer; |
589 | |
590 | -namespace qtmir { |
591 | - class Clipboard; |
592 | -} |
593 | - |
594 | class MirServerIntegration : public QPlatformIntegration |
595 | { |
596 | public: |
597 | @@ -67,7 +63,6 @@ |
598 | |
599 | NativeInterface *m_nativeInterface; |
600 | QPlatformInputContext* m_inputContext; |
601 | - QScopedPointer<qtmir::Clipboard> m_clipboard; |
602 | }; |
603 | |
604 | #endif // MIRSERVERINTEGRATION_H |
605 | |
606 | === added file 'src/platforms/mirserver/shelluuid.cpp' |
607 | --- src/platforms/mirserver/shelluuid.cpp 1970-01-01 00:00:00 +0000 |
608 | +++ src/platforms/mirserver/shelluuid.cpp 2016-08-30 12:33:06 +0000 |
609 | @@ -0,0 +1,35 @@ |
610 | +/* |
611 | + * Copyright (C) 2016 Canonical, Ltd. |
612 | + * |
613 | + * This program is free software: you can redistribute it and/or modify it under |
614 | + * the terms of the GNU Lesser General Public License version 3, as published by |
615 | + * the Free Software Foundation. |
616 | + * |
617 | + * This program is distributed in the hope that it will be useful, but WITHOUT |
618 | + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
619 | + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
620 | + * Lesser General Public License for more details. |
621 | + * |
622 | + * You should have received a copy of the GNU Lesser General Public License |
623 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
624 | + */ |
625 | + |
626 | +#include "shelluuid.h" |
627 | + |
628 | +#include <QMutexLocker> |
629 | + |
630 | +using namespace qtmir; |
631 | + |
632 | +QUuid ShellUuId::m_uuid; |
633 | +QMutex ShellUuId::m_mutex; |
634 | + |
635 | +QString ShellUuId::toString() |
636 | +{ |
637 | + QMutexLocker mutexLocker(&m_mutex); |
638 | + |
639 | + if (m_uuid.isNull()) { |
640 | + m_uuid = QUuid::createUuid(); |
641 | + } |
642 | + |
643 | + return m_uuid.toString(); |
644 | +} |
645 | |
646 | === added file 'src/platforms/mirserver/shelluuid.h' |
647 | --- src/platforms/mirserver/shelluuid.h 1970-01-01 00:00:00 +0000 |
648 | +++ src/platforms/mirserver/shelluuid.h 2016-08-30 12:33:06 +0000 |
649 | @@ -0,0 +1,33 @@ |
650 | +/* |
651 | + * Copyright (C) 2016 Canonical, Ltd. |
652 | + * |
653 | + * This program is free software: you can redistribute it and/or modify it under |
654 | + * the terms of the GNU Lesser General Public License version 3, as published by |
655 | + * the Free Software Foundation. |
656 | + * |
657 | + * This program is distributed in the hope that it will be useful, but WITHOUT |
658 | + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
659 | + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
660 | + * Lesser General Public License for more details. |
661 | + * |
662 | + * You should have received a copy of the GNU Lesser General Public License |
663 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
664 | + */ |
665 | + |
666 | +#include <QUuid> |
667 | +#include <QMutex> |
668 | + |
669 | +namespace qtmir { |
670 | + |
671 | +/* |
672 | + A UUID accessible by all shell code. |
673 | + */ |
674 | +class ShellUuId { |
675 | +public: |
676 | + static QString toString(); |
677 | +private: |
678 | + static QUuid m_uuid; |
679 | + static QMutex m_mutex; |
680 | +}; |
681 | + |
682 | +} // namespace qtmir |
683 | |
684 | === modified file 'tests/mirserver/CMakeLists.txt' |
685 | --- tests/mirserver/CMakeLists.txt 2016-04-13 14:25:42 +0000 |
686 | +++ tests/mirserver/CMakeLists.txt 2016-08-30 12:33:06 +0000 |
687 | @@ -1,6 +1,5 @@ |
688 | add_subdirectory(ArgvHelper) |
689 | add_subdirectory(QtEventFeeder) |
690 | -add_subdirectory(Clipboard) |
691 | add_subdirectory(Screen) |
692 | add_subdirectory(ScreensModel) |
693 | add_subdirectory(WindowManager) |
694 | |
695 | === removed directory 'tests/mirserver/Clipboard' |
696 | === removed file 'tests/mirserver/Clipboard/CMakeLists.txt' |
697 | --- tests/mirserver/Clipboard/CMakeLists.txt 2016-06-06 18:12:07 +0000 |
698 | +++ tests/mirserver/Clipboard/CMakeLists.txt 1970-01-01 00:00:00 +0000 |
699 | @@ -1,27 +0,0 @@ |
700 | -set( |
701 | - CLIPBOARD_TEST_SOURCES |
702 | - clipboard_test.cpp |
703 | - ${CMAKE_SOURCE_DIR}/src/common/debughelpers.cpp |
704 | -) |
705 | - |
706 | -include_directories( |
707 | - ${CMAKE_SOURCE_DIR}/src/platforms/mirserver |
708 | -) |
709 | - |
710 | -include_directories( |
711 | - SYSTEM |
712 | - ${Qt5Gui_PRIVATE_INCLUDE_DIRS} |
713 | - ${MIRSERVER_INCLUDE_DIRS} |
714 | -) |
715 | - |
716 | -add_executable(ClipboardTest ${CLIPBOARD_TEST_SOURCES}) |
717 | - |
718 | -target_link_libraries( |
719 | - ClipboardTest |
720 | - qpa-mirserver |
721 | - |
722 | - ${GTEST_BOTH_LIBRARIES} |
723 | - ${GMOCK_LIBRARIES} |
724 | -) |
725 | - |
726 | -add_test(Clipboard, ClipboardTest) |
727 | |
728 | === removed file 'tests/mirserver/Clipboard/clipboard_test.cpp' |
729 | --- tests/mirserver/Clipboard/clipboard_test.cpp 2015-08-11 12:08:32 +0000 |
730 | +++ tests/mirserver/Clipboard/clipboard_test.cpp 1970-01-01 00:00:00 +0000 |
731 | @@ -1,75 +0,0 @@ |
732 | -/* |
733 | - * Copyright (C) 2014-2015 Canonical, Ltd. |
734 | - * |
735 | - * This program is free software: you can redistribute it and/or modify it under |
736 | - * the terms of the GNU Lesser General Public License version 3, as published by |
737 | - * the Free Software Foundation. |
738 | - * |
739 | - * This program is distributed in the hope that it will be useful, but WITHOUT |
740 | - * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
741 | - * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
742 | - * Lesser General Public License for more details. |
743 | - * |
744 | - * You should have received a copy of the GNU Lesser General Public License |
745 | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
746 | - */ |
747 | - |
748 | -#include <gtest/gtest.h> |
749 | - |
750 | -#include <clipboard.h> |
751 | - |
752 | -#include <QLoggingCategory> |
753 | -#include <QMimeData> |
754 | - |
755 | -using namespace qtmir; |
756 | - |
757 | -TEST(ClipboardTest, MimeDataSerialization) |
758 | -{ |
759 | - QMimeData *mimeData = new QMimeData; |
760 | - mimeData->setData("text/plain", "Hello World!"); |
761 | - mimeData->setData("text/html", "<html lang=\"en\"><body>Hello World!</body></html>"); |
762 | - |
763 | - QByteArray serializedMimeData = serializeMimeData(mimeData); |
764 | - |
765 | - ASSERT_TRUE(serializedMimeData.size() > 0); |
766 | - |
767 | - QMimeData *deserializedMimeData = deserializeMimeData(serializedMimeData); |
768 | - |
769 | - ASSERT_TRUE(deserializedMimeData != nullptr); |
770 | - |
771 | - ASSERT_TRUE(deserializedMimeData->hasFormat("text/plain")); |
772 | - ASSERT_EQ(mimeData->data("text/plain"), deserializedMimeData->data("text/plain")); |
773 | - |
774 | - ASSERT_TRUE(deserializedMimeData->hasFormat("text/html")); |
775 | - ASSERT_EQ(mimeData->data("text/html"), deserializedMimeData->data("text/html")); |
776 | - |
777 | - delete mimeData; |
778 | - delete deserializedMimeData; |
779 | -} |
780 | - |
781 | -TEST(ClipboardTest, RefuseContentsThatAreTooBig) |
782 | -{ |
783 | - QLoggingCategory::setFilterRules(QStringLiteral("*=false")); |
784 | - DBusClipboard::skipDBusRegistration = true; |
785 | - DBusClipboard *dbusClipboard = new DBusClipboard; |
786 | - |
787 | - // Was getting a "warning: overflow in implicit constant conversion [-Woverflow]" |
788 | - // when I used that constant directly in the QByteArray constructors below. Don't |
789 | - // understand why so here's the workaround for it. |
790 | - int maxContentsSize = DBusClipboard::maxContentsSize; |
791 | - |
792 | - QByteArray reasonableContents(maxContentsSize * 0.9, 'R'); |
793 | - QByteArray tooBigContents(maxContentsSize * 1.2, 'B'); |
794 | - |
795 | - dbusClipboard->SetContents(reasonableContents); |
796 | - |
797 | - ASSERT_EQ(dbusClipboard->contents(), reasonableContents); |
798 | - |
799 | - dbusClipboard->SetContents(tooBigContents); |
800 | - |
801 | - // tooBigContents were refused. So it stays with the previously |
802 | - // set contents |
803 | - ASSERT_EQ(dbusClipboard->contents(), reasonableContents); |
804 | - |
805 | - delete dbusClipboard; |
806 | -} |
FAILED: Continuous integration, rev:530 /code.launchpad .net/~dandrader /qtmir/ content- hub-clipboard/ +merge/ 301705/ +edit-commit- message
No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want a jenkins rebuild you need to trigger it yourself):
https:/
https:/ /unity8- jenkins. ubuntu. com/job/ lp-qtmir- ci/317/ /unity8- jenkins. ubuntu. com/job/ build/2430/ console /unity8- jenkins. ubuntu. com/job/ build-0- fetch/2458 /unity8- jenkins. ubuntu. com/job/ build-1- sourcepkg/ release= vivid+overlay/ 2345 /unity8- jenkins. ubuntu. com/job/ build-1- sourcepkg/ release= xenial+ overlay/ 2345 /unity8- jenkins. ubuntu. com/job/ build-1- sourcepkg/ release= yakkety/ 2345 /unity8- jenkins. ubuntu. com/job/ build-2- binpkg/ arch=amd64, release= vivid+overlay/ 2338/console /unity8- jenkins. ubuntu. com/job/ build-2- binpkg/ arch=amd64, release= xenial+ overlay/ 2338/console /unity8- jenkins. ubuntu. com/job/ build-2- binpkg/ arch=amd64, release= yakkety/ 2338/console /unity8- jenkins. ubuntu. com/job/ build-2- binpkg/ arch=armhf, release= vivid+overlay/ 2338/console /unity8- jenkins. ubuntu. com/job/ build-2- binpkg/ arch=armhf, release= xenial+ overlay/ 2338/console /unity8- jenkins. ubuntu. com/job/ build-2- binpkg/ arch=armhf, release= yakkety/ 2338/console /unity8- jenkins. ubuntu. com/job/ build-2- binpkg/ arch=i386, release= vivid+overlay/ 2338/console /unity8- jenkins. ubuntu. com/job/ build-2- binpkg/ arch=i386, release= xenial+ overlay/ 2338/console /unity8- jenkins. ubuntu. com/job/ build-2- binpkg/ arch=i386, release= yakkety/ 2338/console
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild: /unity8- jenkins. ubuntu. com/job/ lp-qtmir- ci/317/ rebuild
https:/