Merge lp:~nick-dedekind/qtmir/multiwindow.configuration into lp:qtmir

Proposed by Nick Dedekind
Status: Needs review
Proposed branch: lp:~nick-dedekind/qtmir/multiwindow.configuration
Merge into: lp:qtmir
Prerequisite: lp:~nick-dedekind/qtmir/multiwindow.screenwindow
Diff against target: 1940 lines (+900/-297)
40 files modified
debian/changelog (+3/-2)
demos/qml-demo-client/CMakeLists.txt (+4/-1)
demos/qml-demo-shell/CMakeLists.txt (+3/-0)
demos/qml-demo-shell/ScreenConfiguration.qml (+78/-0)
demos/qml-demo-shell/Shell.qml (+0/-182)
demos/qml-demo-shell/main.cpp (+85/-19)
demos/qml-demo-shell/pointerposition.cpp (+4/-1)
demos/qml-demo-shell/qml-demo-shell.qml (+18/-25)
src/modules/Unity/Screens/CMakeLists.txt (+2/-0)
src/modules/Unity/Screens/plugin.cpp (+5/-1)
src/modules/Unity/Screens/qquickscreenwindow.cpp (+23/-3)
src/modules/Unity/Screens/qquickscreenwindow.h (+12/-3)
src/modules/Unity/Screens/screen.cpp (+213/-0)
src/modules/Unity/Screens/screen.h (+99/-0)
src/modules/Unity/Screens/screens.cpp (+55/-20)
src/modules/Unity/Screens/screens.h (+10/-3)
src/modules/Unity/Screens/types.h (+41/-0)
src/platforms/mirserver/CMakeLists.txt (+3/-0)
src/platforms/mirserver/cursor.h (+1/-0)
src/platforms/mirserver/customscreenconfiguration.h (+2/-0)
src/platforms/mirserver/displayconfigurationpolicy.cpp (+2/-2)
src/platforms/mirserver/mirdisplayconfigurationobserver.cpp (+63/-0)
src/platforms/mirserver/mirdisplayconfigurationobserver.h (+56/-0)
src/platforms/mirserver/mirserverhooks.cpp (+1/-1)
src/platforms/mirserver/mirserverhooks.h (+1/-1)
src/platforms/mirserver/mirserverintegration.cpp (+2/-2)
src/platforms/mirserver/platformscreen.cpp (+3/-1)
src/platforms/mirserver/qmirserver.cpp (+1/-1)
src/platforms/mirserver/qmirserver.h (+1/-1)
src/platforms/mirserver/qmirserver_p.h (+1/-1)
src/platforms/mirserver/qteventfeeder.cpp (+4/-4)
src/platforms/mirserver/qteventfeeder.h (+5/-3)
src/platforms/mirserver/screenscontroller.cpp (+61/-2)
src/platforms/mirserver/screenscontroller.h (+5/-2)
src/platforms/mirserver/screensmodel.cpp (+16/-4)
src/platforms/mirserver/screensmodel.h (+3/-1)
src/platforms/mirserver/setqtcompositor.cpp (+3/-1)
src/platforms/mirserver/setqtcompositor.h (+2/-2)
tests/mirserver/QtEventFeeder/mock_qtwindowsystem.h (+8/-4)
tests/mirserver/QtEventFeeder/qteventfeeder_test.cpp (+1/-4)
To merge this branch: bzr merge lp:~nick-dedekind/qtmir/multiwindow.configuration
Reviewer Review Type Date Requested Status
Unity8 CI Bot (community) continuous-integration Needs Fixing
Mir development team Pending
Review via email: mp+316548@code.launchpad.net

Commit message

Screen configuration

Description of the change

Prereq-archive: ppa:ci-train-ppa-service/ubuntu/2373

To post a comment you must log in.
Revision history for this message
Gerry Boland (gerboland) wrote :

+class ScreenAdapter : public QObject
could this not inherit QScreen?

The config design is good IMO, some things cannot be declarative.

+class ScreenMode : public QObject
http://doc.qt.io/qt-5/qobject.html#Q_GADGET would be lighter.

Overall design looks good IMO.

Revision history for this message
Gerry Boland (gerboland) wrote :

One request: please keep a qml server demo with spinny logo that I must tap/click to start/stop. I use that lot as a quick test for input and rendering speeds.

Revision history for this message
Nick Dedekind (nick-dedekind) wrote :

> One request: please keep a qml server demo with spinny logo that I must
> tap/click to start/stop. I use that lot as a quick test for input and
> rendering speeds.

It didnt seem to be used so i removed it. I'm guessing you were just loading the qml file.
I've added the spinny logo to the qtmir-demo-shell.
Is this enough, or do you want the qml file to load separately?

Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote :
review: Needs Fixing (continuous-integration)

Unmerged revisions

620. By Nick Dedekind

changelog

619. By Nick Dedekind

merged pre-req

618. By Nick Dedekind

merged pre-req

617. By Nick Dedekind

merged pre-req

616. By Nick Dedekind

added spinny logo to shell demo

615. By Nick Dedekind

merged parent

614. By Nick Dedekind

merged with parent

613. By Nick Dedekind

merged with parent

612. By Nick Dedekind

merged parent

611. By Nick Dedekind

merged with parent

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'debian/changelog'
2--- debian/changelog 2017-04-06 08:48:51 +0000
3+++ debian/changelog 2017-04-06 08:48:52 +0000
4@@ -1,11 +1,12 @@
5-qtmir (0.6.0ubuntu1) UNRELEASED; urgency=medium
6+qtmir (0.6.0ubuntu3) UNRELEASED; urgency=medium
7
8 [ Nick Dedekind ]
9 * Introduced QtMir API
10 * Support for multiple compositors per MirSurface
11 * Support multiple screen windows & cursors with qml instantiation
12+ * Screen configuration API & implementation
13
14- -- Nick Dedekind <nick.dedekind@canonical.com> Thu, 06 Apr 2017 09:45:53 +0100
15+ -- Nick Dedekind <nick.dedekind@canonical.com> Thu, 06 Apr 2017 09:48:21 +0100
16
17 qtmir (0.5.1+17.04.20170328-0ubuntu1) zesty; urgency=medium
18
19
20=== modified file 'demos/qml-demo-client/CMakeLists.txt'
21--- demos/qml-demo-client/CMakeLists.txt 2016-06-06 18:12:07 +0000
22+++ demos/qml-demo-client/CMakeLists.txt 2017-04-06 08:48:52 +0000
23@@ -22,6 +22,9 @@
24
25 file(GLOB QML_JS_FILES *.qml *.js *.png)
26
27+add_custom_target(${DEMO_CLIENT}-qmlfiles
28+ SOURCES ${QML_JS_FILES})
29+
30 # install binaries
31 install(TARGETS ${DEMO_CLIENT}
32 RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
33@@ -35,4 +38,4 @@
34 install(FILES
35 ${CMAKE_CURRENT_BINARY_DIR}/${DEMO_CLIENT}.desktop
36 DESTINATION ${CMAKE_INSTALL_PREFIX}/share/applications
37-)
38\ No newline at end of file
39+)
40
41=== modified file 'demos/qml-demo-shell/CMakeLists.txt'
42--- demos/qml-demo-shell/CMakeLists.txt 2017-04-06 08:48:51 +0000
43+++ demos/qml-demo-shell/CMakeLists.txt 2017-04-06 08:48:52 +0000
44@@ -31,6 +31,9 @@
45
46 file(GLOB QML_JS_FILES *.qml *.js *.png)
47
48+add_custom_target(${DEMO_SHELL}-qmlfiles
49+ SOURCES ${QML_JS_FILES})
50+
51 # install binaries
52 install(TARGETS ${DEMO_SHELL}
53 RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
54
55=== added file 'demos/qml-demo-shell/ScreenConfiguration.qml'
56--- demos/qml-demo-shell/ScreenConfiguration.qml 1970-01-01 00:00:00 +0000
57+++ demos/qml-demo-shell/ScreenConfiguration.qml 2017-04-06 08:48:52 +0000
58@@ -0,0 +1,78 @@
59+import QtQuick 2.0
60+import Ubuntu.Components 1.3
61+import Ubuntu.Components.ListItems 1.3
62+
63+Rectangle {
64+
65+ width: column.width + units.gu(2)
66+ height: column.height + units.gu(2)
67+
68+ color: "transparent"
69+ border.width: 1
70+ border.color: "black"
71+
72+ property QtObject screen: null
73+
74+ Column {
75+ id: column
76+ anchors.centerIn: parent
77+ spacing: 10
78+
79+ Label {
80+ text: screen.name
81+ }
82+
83+ ThinDivider {}
84+
85+ Column {
86+ Label { text: "Used" }
87+ CheckBox { id: useChecked; checked: screen.used; }
88+ }
89+
90+ Label {
91+ text: "Mode"
92+ }
93+
94+ ItemSelector {
95+ id: currentMode
96+ width: units.gu(30)
97+
98+ model: screen.availableModes
99+
100+ delegate: OptionSelectorDelegate { text: String(size.width + " x " + size.height + " (" + refreshRate + "Hz)") }
101+ selectedIndex: screen.currentModeIndex
102+ }
103+
104+ Label {
105+ text: "scale"
106+ }
107+
108+ Slider {
109+ id: slider
110+ width: units.gu(30)
111+ minimumValue: 1
112+ maximumValue: 4
113+ stepSize: 1
114+ value: screen.scale
115+ function formatValue(v) { return v; }
116+ }
117+
118+ Button {
119+ text: "Apply"
120+ onClicked: {
121+ var config = screen.beginConfiguration();
122+
123+ config.used = useChecked.checked;
124+ config.currentModeIndex = currentMode.selectedIndex;
125+ config.scale = slider.value;
126+
127+ screen.applyConfiguration(config);
128+
129+ // Fix up control bindings
130+ usedChecked.checked = Qt.binding(function() { return screen.used; });
131+ currentMode.selectedIndex = Qt.binding(function() { return screen.currentModeIndex; });
132+ slider.value = Qt.binding(function() { return screen.scale; });
133+ }
134+ }
135+ }
136+}
137
138=== renamed file 'demos/qml-demo-shell/windowModel.qml' => 'demos/qml-demo-shell/Shell.qml'
139--- demos/qml-demo-shell/windowModel.qml 2016-11-03 20:17:46 +0000
140+++ demos/qml-demo-shell/Shell.qml 2017-04-06 08:48:52 +0000
141@@ -6,6 +6,41 @@
142 id: root
143 focus: true
144
145+ Image {
146+ id: unityLogo
147+ source: "UnityLogo.png"
148+ fillMode: Image.PreserveAspectFit
149+ anchors.centerIn: parent
150+ width: 600
151+ height: 600
152+
153+ RotationAnimation {
154+ id: logoAnimation
155+ target: unityLogo
156+ from: 0
157+ to: 359
158+ duration: 3000
159+ easing.type: Easing.Linear
160+ loops: Animation.Infinite
161+ }
162+
163+ MultiPointTouchArea {
164+ anchors.fill: parent
165+ minimumTouchPoints:1
166+ maximumTouchPoints:1
167+ onPressed: {
168+ if (logoAnimation.paused) {
169+ logoAnimation.resume();
170+ } else if (logoAnimation.running) {
171+ logoAnimation.pause();
172+ } else {
173+ logoAnimation.start();
174+ }
175+ }
176+ }
177+ }
178+
179+
180 WindowModel {
181 id: windowModel;
182 }
183@@ -69,8 +104,8 @@
184 color: "black"
185 width: 6
186 height: 10
187- x: PointerPosition.x
188- y: PointerPosition.y
189+ x: PointerPosition.x - window.screen.position.x
190+ y: PointerPosition.y - window.screen.position.y
191 }
192
193 MouseArea {
194
195=== removed file 'demos/qml-demo-shell/Shell.qml'
196--- demos/qml-demo-shell/Shell.qml 2015-09-30 13:40:06 +0000
197+++ demos/qml-demo-shell/Shell.qml 1970-01-01 00:00:00 +0000
198@@ -1,182 +0,0 @@
199-import QtQuick 2.4
200-import Unity.Application 0.1
201-
202-Rectangle {
203- id: root
204-
205- focus: true
206- Keys.onVolumeUpPressed: {
207- console.log("\"Volume Up\" pressed");
208- }
209- Keys.onVolumeDownPressed: {
210- console.log("\"Volume Down\" pressed");
211- }
212-
213- property bool resizeModeStretch: true
214-
215- gradient: Gradient {
216- GradientStop { position: 0.0; color: "lightsteelblue" }
217- GradientStop { position: 1.0; color: "pink" }
218- }
219-
220- property bool thumbFriendlyBorders: false
221-
222- MultiPointTouchArea {
223- anchors.fill: parent
224- mouseEnabled: false
225- onPressed: {
226- root.thumbFriendlyBorders = true;
227- }
228- onReleased: {
229- root.thumbFriendlyBorders = false;
230- }
231- }
232-
233- Image {
234- id: unityLogo
235- source: "UnityLogo.png"
236- fillMode: Image.PreserveAspectFit
237- anchors.centerIn: parent
238- width: 600
239- height: 600
240-
241- RotationAnimation {
242- id: logoAnimation
243- target: unityLogo
244- from: 0
245- to: 359
246- duration: 3000
247- easing.type: Easing.Linear
248- loops: Animation.Infinite
249- }
250-
251- MultiPointTouchArea {
252- anchors.fill: parent
253- minimumTouchPoints:1
254- maximumTouchPoints:1
255- onPressed: {
256- if (logoAnimation.paused) {
257- logoAnimation.resume();
258- } else if (logoAnimation.running) {
259- logoAnimation.pause();
260- } else {
261- logoAnimation.start();
262- }
263- }
264- }
265- }
266-
267- Item {
268- id: windowContainer
269- anchors.fill: root
270- }
271-
272- Rectangle {
273- id: quitButton
274- width: 60
275- height: 40
276- color: "red"
277- anchors { right: parent.right; bottom: parent.bottom }
278- Text {
279- anchors.centerIn: parent
280- text: "Quit"
281- }
282- MouseArea {
283- anchors.fill: parent
284- onClicked: Qt.quit()
285- }
286- }
287-
288- Rectangle {
289- id: resizeButton
290- width: 90
291- height: 40
292- color: "blue"
293- anchors { right: quitButton.left; bottom: parent.bottom }
294- Text {
295- anchors.centerIn: parent
296- text: root.resizeModeStretch ? "Stretch" : "Wait Resize"
297- color: "white"
298- }
299- MouseArea {
300- anchors.fill: parent
301- onClicked: { root.resizeModeStretch = !root.resizeModeStretch; }
302- }
303- }
304-
305- Rectangle {
306- width: 40
307- height: 40
308- color: "green"
309- anchors { right: resizeButton.left; bottom: parent.bottom }
310- Text {
311- anchors.centerIn: parent
312- text: "⟳"
313- color: "white"
314- font.pixelSize: 35
315- }
316- MouseArea {
317- anchors.fill: parent
318- onClicked: { root.rotation += 180; }
319- }
320- }
321-
322- Component {
323- id: windowStretchComponent
324- Window {
325- x: 50
326- y: 50
327- //width: 200
328- //height: 200
329- touchMode: root.thumbFriendlyBorders
330-
331- onCloneRequested: {
332- var window = windowStretchComponent.createObject(windowContainer);
333- window.cloned = true;
334- window.surface = surface;
335- }
336- }
337- }
338-
339- Component {
340- id: windowWaitResizeComponent
341- WindowBufferSized {
342- x: 50
343- y: 50
344- touchMode: root.thumbFriendlyBorders
345-
346- onCloneRequested: {
347- var window = windowStretchComponent.createObject(windowContainer);
348- window.cloned = true;
349- window.surface = surface;
350- }
351- }
352- }
353-
354- property var windowComponent: resizeModeStretch ? windowStretchComponent : windowWaitResizeComponent
355-
356- Connections {
357- target: SurfaceManager
358- onSurfaceCreated: {
359- print("new surface", surface.name)
360-
361- var window = windowComponent.createObject(windowContainer);
362- if (!window) {
363- console.warn(windowComponent.errorString());
364- return;
365- }
366-
367- window.surface = surface;
368-
369- openAnimation.target = window;
370- openAnimation.start();
371- }
372- }
373-
374- NumberAnimation {
375- id: openAnimation
376- property: "x";
377- from: root.width; to: 10;
378- duration: 1200; easing.type: Easing.InOutQuad
379- }
380-}
381
382=== modified file 'demos/qml-demo-shell/main.cpp'
383--- demos/qml-demo-shell/main.cpp 2017-04-06 08:48:51 +0000
384+++ demos/qml-demo-shell/main.cpp 2017-04-06 08:48:52 +0000
385@@ -17,8 +17,10 @@
386 // Qt
387 #include <QtQuick/QQuickView>
388 #include <QtGui/QGuiApplication>
389-#include <QtQml/QQmlEngine>
390+#include <QtQml/QQmlApplicationEngine>
391 #include <QtQml/QQmlContext>
392+#include <QJsonObject>
393+#include <QJsonDocument>
394 #include <QDebug>
395 #include <libintl.h>
396 #include "../paths.h"
397@@ -29,6 +31,20 @@
398 #include <qtmir/sessionauthorizer.h>
399 #include <qtmir/windowmanagementpolicy.h>
400 #include <qtmir/displayconfigurationstorage.h>
401+#include <qtmir/miral/edid.h>
402+
403+
404+inline QString stringFromEdid(const miral::Edid& edid)
405+{
406+ QString str;
407+ str += QString::fromStdString(edid.vendor);
408+ str += QString("%1%2").arg(edid.product_code).arg(edid.serial_number);
409+
410+ for (int i = 0; i < 4; i++) {
411+ str += QString::fromStdString(edid.descriptors[i].string_value());
412+ }
413+ return str;
414+}
415
416 struct DemoDisplayConfigurationPolicy : qtmir::DisplayConfigurationPolicy
417 {
418@@ -46,23 +62,80 @@
419 : qtmir::WindowManagementPolicy(tools, dd)
420 {}
421
422+ bool handle_pointer_event(const MirPointerEvent *event) override
423+ {
424+ return qtmir::WindowManagementPolicy::handle_pointer_event(event);
425+ }
426+
427 bool handle_keyboard_event(const MirKeyboardEvent *event) override
428 {
429- qDebug() << "OVERRIDE qtmir::WindowManagementPolicy::handle_keyboard_event" << event;
430 return qtmir::WindowManagementPolicy::handle_keyboard_event(event);
431 }
432 };
433
434 struct DemoDisplayConfigurationStorage : miral::DisplayConfigurationStorage
435 {
436- void save(const miral::DisplayId&, const miral::DisplayConfigurationOptions&) override
437+ void save(const miral::DisplayId& displayId, const miral::DisplayConfigurationOptions& options) override
438 {
439- qDebug() << "OVERRIDE miral::DisplayConfigurationStorage::save";
440+ QFile f(stringFromEdid(displayId.edid) + ".edid");
441+ qDebug() << "OVERRIDE miral::DisplayConfigurationStorage::save" << f.fileName();
442+
443+ QJsonObject json;
444+ if (options.used.is_set()) json.insert("used", options.used.value());
445+ if (options.clone_output_index.is_set()) json.insert("clone_output_index", static_cast<int>(options.clone_output_index.value()));
446+ if (options.mode.is_set()) {
447+ auto const& mode = options.mode.value();
448+
449+ QString sz(QString("%1x%2").arg(mode.size.width.as_int()).arg(mode.size.height.as_int()));
450+ QJsonObject jsonMode({
451+ {"size", sz},
452+ {"refresh_rate", mode.refresh_rate }
453+ });
454+ json.insert("mode", jsonMode);
455+ }
456+ if (options.orientation.is_set()) json.insert("orientation", static_cast<int>(options.orientation.value()));
457+ if (options.form_factor.is_set()) json.insert("form_factor", static_cast<int>(options.form_factor.value()));
458+ if (options.scale.is_set()) json.insert("scale", options.scale.value());
459+
460+ if (f.open(QIODevice::WriteOnly)) {
461+ QJsonDocument saveDoc(json);
462+ f.write(saveDoc.toJson());
463+ }
464 }
465
466- bool load(const miral::DisplayId&, miral::DisplayConfigurationOptions&) const override
467+ bool load(const miral::DisplayId& displayId, miral::DisplayConfigurationOptions& options) const override
468 {
469- qDebug() << "OVERRIDE miral::DisplayConfigurationStorage::load";
470+ QFile f(stringFromEdid(displayId.edid) + ".edid");
471+ qDebug() << "OVERRIDE miral::DisplayConfigurationStorage::load" << f.fileName();
472+
473+ if (f.open(QIODevice::ReadOnly)) {
474+ QByteArray saveData = f.readAll();
475+ QJsonDocument loadDoc(QJsonDocument::fromJson(saveData));
476+
477+ QJsonObject json(loadDoc.object());
478+ if (json.contains("used")) options.used = json["used"].toBool();
479+ if (json.contains("clone_output_index")) options.clone_output_index = json["clone_output_index"].toInt();
480+ if (json.contains("mode")) {
481+ QJsonObject jsonMode = json["mode"].toObject();
482+
483+ if (jsonMode.contains("size") && jsonMode.contains("refresh_rate")) {
484+ QString sz(jsonMode["size"].toString());
485+ QStringList geo = sz.split("x", QString::SkipEmptyParts);
486+ if (geo.count() == 2) {
487+ miral::DisplayConfigurationOptions::DisplayMode mode;
488+ mode.size = mir::geometry::Size(geo[0].toInt(), geo[1].toInt());
489+ mode.refresh_rate = jsonMode["refresh_rate"].toDouble();
490+ options.mode = mode;
491+ }
492+ }
493+ }
494+ if (json.contains("orientation")) options.orientation = static_cast<MirOrientation>(json["orientation"].toInt());
495+ if (json.contains("form_factor")) options.form_factor = static_cast<MirFormFactor>(json["form_factor"].toInt());
496+ if (json.contains("scale")) options.scale = json["form_factor"].toDouble();
497+
498+ return true;
499+ }
500+
501 return false;
502 }
503 };
504@@ -110,24 +183,17 @@
505 qtmir::MirServerApplication *application;
506
507 application = new qtmir::MirServerApplication(argc, (char**)argv, { displayConfig, sessionAuth, wmPolicy, displayStorage });
508- QQuickView* view = new QQuickView();
509- view->engine()->addImportPath(::qmlPluginDirectory());
510- view->setResizeMode(QQuickView::SizeRootObjectToView);
511- view->setColor("lightgray");
512- view->setTitle("Demo Shell");
513+ auto qmlEngine = new QQmlApplicationEngine(application);
514+ qmlEngine->setBaseUrl(QUrl::fromLocalFile(::qmlDirectory() + "api-demo-shell"));
515+ qmlEngine->addImportPath(::qmlPluginDirectory());
516+ QObject::connect(qmlEngine, &QQmlEngine::quit, application, &QGuiApplication::quit);
517
518 qmlRegisterSingletonType<PointerPosition>("Mir.Pointer", 0, 1, "PointerPosition",
519 [](QQmlEngine*, QJSEngine*) -> QObject* { return PointerPosition::instance(); });
520
521- QUrl source(::qmlDirectory() + "qml-demo-shell/windowModel.qml");
522-
523- view->setSource(source);
524- QObject::connect(view->engine(), SIGNAL(quit()), application, SLOT(quit()));
525-
526- view->showFullScreen();
527+ qmlEngine->load(::qmlDirectory() + "qml-demo-shell/qml-demo-shell.qml");
528+
529 int result = application->exec();
530-
531- delete view;
532 delete application;
533
534 return result;
535
536=== modified file 'demos/qml-demo-shell/pointerposition.cpp'
537--- demos/qml-demo-shell/pointerposition.cpp 2016-11-03 20:17:46 +0000
538+++ demos/qml-demo-shell/pointerposition.cpp 2017-04-06 08:48:52 +0000
539@@ -52,5 +52,8 @@
540
541 PointerPosition::~PointerPosition()
542 {
543- qGuiApp->removeEventFilter(this);
544+ // If this is a singleton the qApp probably won't exist.
545+ if (qGuiApp) {
546+ qGuiApp->removeEventFilter(this);
547+ }
548 }
549
550=== modified file 'demos/qml-demo-shell/qml-demo-shell.qml'
551--- demos/qml-demo-shell/qml-demo-shell.qml 2016-11-23 16:15:28 +0000
552+++ demos/qml-demo-shell/qml-demo-shell.qml 2017-04-06 08:48:52 +0000
553@@ -1,38 +1,31 @@
554-import QtQuick 2.3
555+import QtQuick 2.5
556 import Unity.Screens 0.1
557
558 Instantiator {
559 id: root
560
561- property var screens: Screens{}
562+ model: Screens
563
564- model: screens
565 ScreenWindow {
566 id: window
567 visible: true
568 screen: model.screen
569- Shell{ anchors.fill: parent }
570- Component.onCompleted: {
571- print("Window created for Screen", screen, screen.geometry, outputType, Screens.HDMIA, screen.devicePixelRatio)
572- }
573- Component.onDestruction: {
574- print("Window destroyed")
575- }
576- onScaleChanged: print("NOTICE: scale changed for", model.screen, "to", scale);
577- onFormFactorChanged: print("NOTICE: form factor changed for", model.screen, "to", formFactor)
578- Button {
579- anchors { left: parent.left; bottom: parent.bottom }
580- height: 100
581- width: parent.width / 2
582- text: "Scale up"
583- onClicked: window.setScaleAndFormFactor(window.scale + 0.2, Screens.FormFactorMonitor)
584- }
585- Button {
586- anchors { right: parent.right; bottom: parent.bottom }
587- height: 100
588- width: parent.width / 2
589- text: "Scale down"
590- onClicked: window.setScaleAndFormFactor(window.scale - 0.2, Screens.FormFactorTablet)
591+
592+ Row {
593+ x: 10
594+ y: 10
595+ Repeater {
596+ model: Screens
597+ ScreenConfiguration {
598+ screen: model.screen
599+ }
600+ }
601+ }
602+
603+ Shell {
604+ width: parent.width
605+ height: parent.height
606+ z: 1
607 }
608 }
609 }
610
611=== modified file 'src/modules/Unity/Screens/CMakeLists.txt'
612--- src/modules/Unity/Screens/CMakeLists.txt 2017-04-06 08:48:51 +0000
613+++ src/modules/Unity/Screens/CMakeLists.txt 2017-04-06 08:48:52 +0000
614@@ -12,7 +12,9 @@
615 set(SCREENSPLUGIN_SRC
616 plugin.cpp
617 screens.cpp
618+ screen.cpp
619 qquickscreenwindow.cpp
620+ types.h
621 )
622
623 add_library(unityscreensplugin SHARED
624
625=== modified file 'src/modules/Unity/Screens/plugin.cpp'
626--- src/modules/Unity/Screens/plugin.cpp 2017-04-06 08:48:51 +0000
627+++ src/modules/Unity/Screens/plugin.cpp 2017-04-06 08:48:52 +0000
628@@ -21,6 +21,7 @@
629
630 // local
631 #include "screens.h"
632+#include "screen.h"
633 #include "qquickscreenwindow.h"
634
635 using namespace qtmir;
636@@ -42,7 +43,10 @@
637 {
638 Q_ASSERT(QLatin1String(uri) == QLatin1String("Unity.Screens"));
639
640- qRegisterMetaType<QScreen*>("QScreen*");
641+ qRegisterMetaType<ScreenAdapter*>("Screen*");
642+ qRegisterMetaType<ScreenMode*>("ScreenMode*");
643+ qRegisterMetaType<ScreenConfig*>("ScreenConfig*");
644+ qmlRegisterUncreatableType<ScreenMode>(uri, 0, 1, "ScreenMode", "ScreenMode is not creatable.");
645
646 qmlRegisterSingletonType<qtmir::Screens>(uri, 0, 1, "Screens", screensSingleton);
647 qRegisterMetaType<qtmir::FormFactor>("qtmir::FormFactor");
648
649=== modified file 'src/modules/Unity/Screens/qquickscreenwindow.cpp'
650--- src/modules/Unity/Screens/qquickscreenwindow.cpp 2017-04-06 08:48:51 +0000
651+++ src/modules/Unity/Screens/qquickscreenwindow.cpp 2017-04-06 08:48:52 +0000
652@@ -17,6 +17,7 @@
653 #include "qquickscreenwindow.h"
654
655 // mirserver
656+#include "screen.h"
657 #include "screenscontroller.h"
658 #include "logging.h"
659
660@@ -36,7 +37,26 @@
661 if (qGuiApp->platformName() != QLatin1String("mirserver")) {
662 qCritical("Not using 'mirserver' QPA plugin. Using ScreenWindow may produce unknown results.");
663 }
664- connect(this, &QWindow::screenChanged, this, &QQuickScreenWindow::screenChanged);
665-
666- DEBUG_MSG << "()";
667+
668+ DEBUG_MSG << "()";
669+}
670+
671+QQuickScreenWindow::~QQuickScreenWindow()
672+{
673+ DEBUG_MSG << "()";
674+}
675+
676+ScreenAdapter *QQuickScreenWindow::screenWrapper() const
677+{
678+ return m_screen.data();
679+}
680+
681+void QQuickScreenWindow::setScreenWrapper(ScreenAdapter *screen)
682+{
683+ DEBUG_MSG << "(screen=" << screen << ")";
684+ if (m_screen != screen) {
685+ m_screen = screen;
686+ Q_EMIT screenWrapperChanged();
687+ }
688+ QQuickWindow::setScreen(screen->screen());
689 }
690
691=== modified file 'src/modules/Unity/Screens/qquickscreenwindow.h'
692--- src/modules/Unity/Screens/qquickscreenwindow.h 2017-04-06 08:48:51 +0000
693+++ src/modules/Unity/Screens/qquickscreenwindow.h 2017-04-06 08:48:52 +0000
694@@ -18,6 +18,9 @@
695 #define QQUICKSCREENWINDOW_H
696
697 #include <QQuickWindow>
698+#include <QPointer>
699+
700+class ScreenAdapter;
701
702 namespace qtmir {
703
704@@ -27,14 +30,20 @@
705 class QQuickScreenWindow : public QQuickWindow
706 {
707 Q_OBJECT
708- Q_PROPERTY(QScreen *screen READ screen WRITE setScreen NOTIFY screenChanged)
709-
710+ Q_PROPERTY(ScreenAdapter *screen READ screenWrapper WRITE setScreenWrapper NOTIFY screenWrapperChanged)
711+ Q_PROPERTY(int winId READ winId CONSTANT)
712 public:
713 explicit QQuickScreenWindow(QQuickWindow *parent = 0);
714+ ~QQuickScreenWindow();
715+
716+ ScreenAdapter *screenWrapper() const;
717+ void setScreenWrapper(ScreenAdapter *screen);
718
719 Q_SIGNALS:
720- void screenChanged(QScreen* screen);
721+ void screenWrapperChanged();
722
723+private:
724+ QPointer<ScreenAdapter> m_screen;
725 };
726
727 } //namespace qtmir
728
729=== added file 'src/modules/Unity/Screens/screen.cpp'
730--- src/modules/Unity/Screens/screen.cpp 1970-01-01 00:00:00 +0000
731+++ src/modules/Unity/Screens/screen.cpp 2017-04-06 08:48:52 +0000
732@@ -0,0 +1,213 @@
733+#include "screen.h"
734+
735+// qtmir
736+#include "platformscreen.h"
737+#include "screenscontroller.h"
738+#include "nativeinterface.h"
739+
740+// Qt
741+#include <QScreen>
742+#include <QQmlEngine>
743+#include <QDebug>
744+#include <QGuiApplication>
745+
746+ScreenAdapter::ScreenAdapter(QScreen* screen, QObject* parent)
747+ : QObject(parent)
748+ , m_screen(screen)
749+ , m_screensController(static_cast<ScreensController*>(qGuiApp->platformNativeInterface()
750+ ->nativeResourceForIntegration("ScreensController")))
751+{
752+ if (!m_screensController) {
753+ qFatal("Screens Controller not initialized");
754+ }
755+
756+ auto platformScreen = static_cast<PlatformScreen*>(m_screen->handle());
757+ if (platformScreen) {
758+ connect(platformScreen, &PlatformScreen::usedChanged, this, &ScreenAdapter::usedChanged);
759+ connect(platformScreen, &PlatformScreen::nameChanged, this, &ScreenAdapter::nameChanged);
760+ connect(platformScreen, &PlatformScreen::outputTypeChanged, this, &ScreenAdapter::outputTypeChanged);
761+ connect(platformScreen, &PlatformScreen::scaleChanged, this, &ScreenAdapter::scaleChanged);
762+ connect(platformScreen, &PlatformScreen::formFactorChanged, this, &ScreenAdapter::formFactorChanged);
763+ connect(platformScreen, &PlatformScreen::physicalSizeChanged, this, &ScreenAdapter::physicalSizeChanged);
764+ connect(platformScreen, &PlatformScreen::positionChanged, this, &ScreenAdapter::positionChanged);
765+ connect(platformScreen, &PlatformScreen::activeChanged, this, &ScreenAdapter::activeChanged);
766+ connect(platformScreen, &PlatformScreen::currentModeIndexChanged, this, &ScreenAdapter::currentModeIndexChanged);
767+ connect(platformScreen, &PlatformScreen::availableModesChanged, this, &ScreenAdapter::updateScreenModes);
768+ }
769+ updateScreenModes();
770+}
771+
772+ScreenAdapter::~ScreenAdapter()
773+{
774+ qDebug() << "delete screens";
775+ qDeleteAll(m_modes);
776+ m_modes.clear();
777+}
778+
779+qtmir::OutputId ScreenAdapter::outputId() const
780+{
781+ if (!m_screen) return qtmir::OutputId(-1);
782+ auto platformScreen = static_cast<PlatformScreen*>(m_screen->handle());
783+ if (!platformScreen) return qtmir::OutputId(-1);
784+
785+ return platformScreen->outputId();
786+}
787+
788+bool ScreenAdapter::used() const
789+{
790+ if (!m_screen) return false;
791+ auto platformScreen = static_cast<PlatformScreen*>(m_screen->handle());
792+ if (!platformScreen) return false;
793+
794+ return platformScreen->used();
795+}
796+
797+QString ScreenAdapter::name() const
798+{
799+ if (!m_screen) return QString();
800+ auto platformScreen = static_cast<PlatformScreen*>(m_screen->handle());
801+ if (!platformScreen) return QString();
802+
803+ return platformScreen->name();
804+}
805+
806+float ScreenAdapter::scale() const
807+{
808+ if (!m_screen) return 1.0;
809+ auto platformScreen = static_cast<PlatformScreen*>(m_screen->handle());
810+ if (!platformScreen) return 1.0;
811+
812+ return platformScreen->scale();
813+}
814+
815+QSizeF ScreenAdapter::physicalSize() const
816+{
817+ if (!m_screen) return QSizeF();
818+ auto platformScreen = static_cast<PlatformScreen*>(m_screen->handle());
819+ if (!platformScreen) return QSizeF();
820+
821+ return platformScreen->physicalSize();
822+}
823+
824+qtmir::FormFactor ScreenAdapter::formFactor() const
825+{
826+ if (!m_screen) return qtmir::FormFactorUnknown;
827+ auto platformScreen = static_cast<PlatformScreen*>(m_screen->handle());
828+ if (!platformScreen) return qtmir::FormFactorUnknown;
829+
830+ return static_cast<qtmir::FormFactor>(platformScreen->formFactor()); // needs compile time check
831+}
832+
833+qtmir::OutputTypes ScreenAdapter::outputType() const
834+{
835+ if (!m_screen) return qtmir::Unknown;
836+ auto platformScreen = static_cast<PlatformScreen*>(m_screen->handle());
837+ if (!platformScreen) return qtmir::Unknown;
838+
839+ return platformScreen->outputType();
840+}
841+
842+QPoint ScreenAdapter::position() const
843+{
844+ if (!m_screen) return QPoint();
845+ auto platformScreen = static_cast<PlatformScreen*>(m_screen->handle());
846+ if (!platformScreen) return QPoint();
847+
848+ return platformScreen->geometry().topLeft();
849+}
850+
851+QQmlListProperty<ScreenMode> ScreenAdapter::availableModes()
852+{
853+ return QQmlListProperty<ScreenMode>(this, m_modes);
854+}
855+
856+uint ScreenAdapter::currentModeIndex() const
857+{
858+ if (!m_screen) return -1;
859+ auto platformScreen = static_cast<PlatformScreen*>(m_screen->handle());
860+ if (!platformScreen) return -1;
861+
862+ return platformScreen->currentModeIndex();
863+}
864+
865+bool ScreenAdapter::isActive() const
866+{
867+ if (!m_screen) return false;
868+ auto platformScreen = static_cast<PlatformScreen*>(m_screen->handle());
869+ if (!platformScreen) return false;
870+
871+ return platformScreen->isActive();
872+}
873+
874+QScreen *ScreenAdapter::screen() const
875+{
876+ return m_screen.data();
877+}
878+
879+ScreenConfig *ScreenAdapter::beginConfiguration() const
880+{
881+ auto newConfig = new ScreenConfig();
882+ auto config = m_screensController->outputConfiguration(this->outputId());
883+ *newConfig = config;
884+
885+ return newConfig;
886+}
887+
888+bool ScreenAdapter::applyConfiguration(ScreenConfig *configuration)
889+{
890+ if (!m_screen) return false;
891+ auto platformScreen = static_cast<PlatformScreen*>(m_screen->handle());
892+ if (!platformScreen) return false;
893+
894+ return m_screensController->setOutputConfiguration(*configuration);
895+}
896+
897+void ScreenAdapter::setActive(bool active)
898+{
899+ if (!m_screen) return;
900+ auto platformScreen = static_cast<PlatformScreen*>(m_screen->handle());
901+ if (!platformScreen) return;
902+
903+ platformScreen->setActive(active);
904+}
905+
906+void ScreenAdapter::updateScreenModes()
907+{
908+ if (!m_screen) return;
909+ auto platformScreen = static_cast<PlatformScreen*>(m_screen->handle());
910+ if (!platformScreen) return;
911+
912+ qDeleteAll(m_modes);
913+ m_modes.clear();
914+ Q_FOREACH(auto mode, platformScreen->availableModes()) {
915+ auto newMode(new ScreenMode);
916+ QQmlEngine::setObjectOwnership(newMode, QQmlEngine::CppOwnership);
917+ newMode->refreshRate = mode.first;
918+ newMode->size = mode.second;
919+ m_modes.append(newMode);
920+ }
921+
922+ Q_EMIT availableModesChanged();
923+}
924+
925+ScreenConfig::ScreenConfig(QObject *parent)
926+ : QObject(parent)
927+{
928+}
929+
930+ScreenConfig &ScreenConfig::operator=(const CustomScreenConfiguration &other)
931+{
932+ if (&other == this) return *this;
933+
934+ valid = other.valid;
935+ id = other.id;
936+ used = other.used;
937+ topLeft = other.topLeft;
938+ currentModeIndex = other.currentModeIndex;
939+ powerMode = other.powerMode;
940+ orientation = other.orientation;
941+ scale = other.scale;
942+ formFactor = other.formFactor;
943+
944+ return *this;
945+}
946
947=== added file 'src/modules/Unity/Screens/screen.h'
948--- src/modules/Unity/Screens/screen.h 1970-01-01 00:00:00 +0000
949+++ src/modules/Unity/Screens/screen.h 2017-04-06 08:48:52 +0000
950@@ -0,0 +1,99 @@
951+#ifndef SCREEN_H
952+#define SCREEN_H
953+
954+#include "types.h"
955+
956+#include <QObject>
957+#include <QPointer>
958+#include <QQmlListProperty>
959+
960+#include <customscreenconfiguration.h>
961+#include <screentypes.h>
962+
963+class QScreen;
964+class ScreenConfig;
965+class ScreensController;
966+
967+/*
968+ * Screen - Adapter for a QScreen exposed to qml which allows user to read screen properties,
969+ * as well as configure the screen properties in a transactional manner.
970+**/
971+class ScreenAdapter : public QObject
972+{
973+ Q_OBJECT
974+
975+ Q_PROPERTY(bool active READ isActive WRITE setActive NOTIFY activeChanged)
976+
977+ Q_PROPERTY(bool used READ used NOTIFY usedChanged)
978+ Q_PROPERTY(QString name READ name NOTIFY nameChanged)
979+ Q_PROPERTY(qtmir::OutputTypes outputType READ outputType NOTIFY outputTypeChanged)
980+ Q_PROPERTY(float scale READ scale NOTIFY scaleChanged)
981+ Q_PROPERTY(qtmir::FormFactor formFactor READ formFactor NOTIFY formFactorChanged)
982+ Q_PROPERTY(QPoint position READ position NOTIFY positionChanged)
983+ Q_PROPERTY(uint currentModeIndex READ currentModeIndex NOTIFY currentModeIndexChanged)
984+ Q_PROPERTY(QQmlListProperty<ScreenMode> availableModes READ availableModes NOTIFY availableModesChanged)
985+ Q_PROPERTY(QSizeF physicalSize READ physicalSize NOTIFY physicalSizeChanged)
986+
987+public:
988+ explicit ScreenAdapter(QScreen* screen, QObject* parent = 0);
989+ ~ScreenAdapter();
990+
991+ qtmir::OutputId outputId() const;
992+ bool used() const;
993+ QString name() const;
994+ float scale() const;
995+ QSizeF physicalSize() const;
996+ qtmir::FormFactor formFactor() const;
997+ qtmir::OutputTypes outputType() const;
998+ QPoint position() const;
999+ QQmlListProperty<ScreenMode> availableModes();
1000+ uint currentModeIndex() const;
1001+ bool isActive() const;
1002+
1003+ QScreen *screen() const;
1004+
1005+ Q_INVOKABLE ScreenConfig *beginConfiguration() const;
1006+ Q_INVOKABLE bool applyConfiguration(ScreenConfig *configuration);
1007+
1008+ void setActive(bool active);
1009+
1010+Q_SIGNALS:
1011+ void usedChanged();
1012+ void nameChanged();
1013+ void outputTypeChanged();
1014+ void scaleChanged();
1015+ void formFactorChanged();
1016+ void positionChanged();
1017+ void currentModeIndexChanged();
1018+ void physicalSizeChanged();
1019+ void availableModesChanged();
1020+ void activeChanged(bool active);
1021+
1022+private Q_SLOTS:
1023+ void updateScreenModes();
1024+
1025+private:
1026+ QList<ScreenMode*> m_modes;
1027+ QPointer<QScreen> m_screen;
1028+ ScreensController *m_screensController;
1029+};
1030+
1031+class ScreenConfig: public QObject,
1032+ public CustomScreenConfiguration
1033+{
1034+ Q_OBJECT
1035+ Q_PROPERTY(bool used MEMBER used)
1036+ Q_PROPERTY(float scale MEMBER scale)
1037+ Q_PROPERTY(qtmir::FormFactor formFactor MEMBER formFactor)
1038+ Q_PROPERTY(uint currentModeIndex MEMBER currentModeIndex)
1039+ Q_PROPERTY(QPoint position MEMBER topLeft)
1040+
1041+public:
1042+ ScreenConfig(QObject* parent = 0);
1043+
1044+ ScreenConfig &operator=(const CustomScreenConfiguration& other);
1045+
1046+ friend class ScreenAdapter;
1047+};
1048+
1049+#endif // SCREEN_H
1050
1051=== modified file 'src/modules/Unity/Screens/screens.cpp'
1052--- src/modules/Unity/Screens/screens.cpp 2017-04-06 08:48:51 +0000
1053+++ src/modules/Unity/Screens/screens.cpp 2017-04-06 08:48:52 +0000
1054@@ -15,6 +15,7 @@
1055 */
1056
1057 #include "screens.h"
1058+#include "screen.h"
1059
1060 // mirserver
1061 #include "platformscreen.h"
1062@@ -33,14 +34,17 @@
1063 Screens::Screens(QObject *parent) :
1064 QAbstractListModel(parent)
1065 {
1066- auto app = static_cast<QGuiApplication *>(QGuiApplication::instance());
1067- if (!app) {
1068- return;
1069- }
1070- connect(app, &QGuiApplication::screenAdded, this, &Screens::onScreenAdded);
1071- connect(app, &QGuiApplication::screenRemoved, this, &Screens::onScreenRemoved);
1072-
1073- m_screenList = QGuiApplication::screens();
1074+ if (qGuiApp->platformName() != QLatin1String("mirserver")) {
1075+ qCritical("Not using 'mirserver' QPA plugin. Using Screens may produce unknown results.");
1076+ }
1077+
1078+ connect(qGuiApp, &QGuiApplication::screenAdded, this, &Screens::onScreenAdded);
1079+ connect(qGuiApp, &QGuiApplication::screenRemoved, this, &Screens::onScreenRemoved);
1080+ connect(qGuiApp, &QGuiApplication::focusWindowChanged, this, &Screens::activeScreenChanged);
1081+
1082+ Q_FOREACH(QScreen* screen, QGuiApplication::screens()) {
1083+ m_screenList.push_back(new ScreenAdapter(screen));
1084+ }
1085 DEBUG_MSG << "(" << m_screenList << ")";
1086 }
1087
1088@@ -75,31 +79,62 @@
1089 return m_screenList.size();
1090 }
1091
1092+QVariant Screens::activeScreen() const
1093+{
1094+ for (int i = 0; i < m_screenList.count(); i++) {
1095+ if (m_screenList[i]->isActive()) return i;
1096+ }
1097+ return QVariant();
1098+}
1099+
1100+void Screens::activateScreen(const QVariant& vindex)
1101+{
1102+ bool ok = false;
1103+ int index = vindex.toInt(&ok);
1104+ if (!ok || index < 0 || m_screenList.count() <= index) return;
1105+
1106+ auto screen = static_cast<ScreenAdapter*>(m_screenList.at(index));
1107+ screen->setActive(true);
1108+}
1109+
1110 void Screens::onScreenAdded(QScreen *screen)
1111 {
1112- if (m_screenList.contains(screen))
1113- return;
1114+ Q_FOREACH(auto screenWrapper, m_screenList) {
1115+ if (screenWrapper->screen() == screen) return;
1116+ }
1117 DEBUG_MSG << "(screen=" << screen << ")";
1118
1119 beginInsertRows(QModelIndex(), count(), count());
1120- m_screenList.push_back(screen);
1121+ auto screenWrapper(new ScreenAdapter(screen));
1122+ m_screenList.push_back(screenWrapper);
1123 endInsertRows();
1124- Q_EMIT screenAdded(screen);
1125+ Q_EMIT screenAdded(screenWrapper);
1126 Q_EMIT countChanged();
1127 }
1128
1129 void Screens::onScreenRemoved(QScreen *screen)
1130 {
1131- int index = m_screenList.indexOf(screen);
1132- if (index < 0)
1133- return;
1134 DEBUG_MSG << "(screen=" << screen << ")";
1135
1136- beginRemoveRows(QModelIndex(), index, index);
1137- m_screenList.removeAt(index);
1138- endRemoveRows();
1139- Q_EMIT screenRemoved(screen);
1140- Q_EMIT countChanged();
1141+ int index = 0;
1142+ QMutableListIterator<ScreenAdapter*> iter(m_screenList);
1143+ while(iter.hasNext()) {
1144+ auto screenWrapper = iter.next();
1145+ if (screenWrapper->screen() == screen) {
1146+
1147+ beginRemoveRows(QModelIndex(), index, index);
1148+ auto screenWrapper = m_screenList.takeAt(index);
1149+ endRemoveRows();
1150+
1151+ Q_EMIT screenRemoved(screenWrapper);
1152+ Q_EMIT countChanged();
1153+
1154+ iter.remove();
1155+ screenWrapper->deleteLater();
1156+ break;
1157+ }
1158+ index++;
1159+ }
1160 }
1161
1162 } // namespace qtmir
1163
1164=== modified file 'src/modules/Unity/Screens/screens.h'
1165--- src/modules/Unity/Screens/screens.h 2017-04-06 08:48:51 +0000
1166+++ src/modules/Unity/Screens/screens.h 2017-04-06 08:48:52 +0000
1167@@ -22,6 +22,7 @@
1168 #include <QAbstractListModel>
1169
1170 class QScreen;
1171+class ScreenAdapter;
1172
1173 namespace qtmir {
1174
1175@@ -29,6 +30,7 @@
1176 {
1177 Q_OBJECT
1178 Q_PROPERTY(int count READ count NOTIFY countChanged)
1179+ Q_PROPERTY(QVariant activeScreen READ activeScreen WRITE activateScreen NOTIFY activeScreenChanged)
1180
1181 public:
1182 enum ItemRoles {
1183@@ -44,18 +46,23 @@
1184 int rowCount(const QModelIndex &parent = QModelIndex()) const override;
1185
1186 int count() const;
1187+ QVariant activeScreen() const;
1188+
1189+public Q_SLOTS:
1190+ void activateScreen(const QVariant& index);
1191
1192 Q_SIGNALS:
1193 void countChanged();
1194- void screenAdded(QScreen *screen);
1195- void screenRemoved(QScreen *screen);
1196+ void activeScreenChanged();
1197+ void screenAdded(ScreenAdapter *screen);
1198+ void screenRemoved(ScreenAdapter *screen);
1199
1200 private Q_SLOTS:
1201 void onScreenAdded(QScreen *screen);
1202 void onScreenRemoved(QScreen *screen);
1203
1204 private:
1205- QList<QScreen *> m_screenList;
1206+ QList<ScreenAdapter *> m_screenList;
1207 };
1208
1209 } // namespace qtmir
1210
1211=== added file 'src/modules/Unity/Screens/types.h'
1212--- src/modules/Unity/Screens/types.h 1970-01-01 00:00:00 +0000
1213+++ src/modules/Unity/Screens/types.h 2017-04-06 08:48:52 +0000
1214@@ -0,0 +1,41 @@
1215+/*
1216+ * Copyright © 2016 Canonical Ltd.
1217+ *
1218+ * This program is free software: you can redistribute it and/or modify it under
1219+ * the terms of the GNU Lesser General Public License version 3, as published by
1220+ * the Free Software Foundation.
1221+ *
1222+ * This program is distributed in the hope that it will be useful, but WITHOUT
1223+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
1224+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1225+ * Lesser General Public License for more details.
1226+ *
1227+ * You should have received a copy of the GNU Lesser General Public License
1228+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1229+ */
1230+
1231+#ifndef UNITY_SCREEN_TYPES_H
1232+#define UNITY_SCREEN_TYPES_H
1233+
1234+#include <QObject>
1235+#include <QSize>
1236+
1237+class ScreenMode : public QObject
1238+{
1239+ Q_OBJECT
1240+ Q_PROPERTY(qreal refreshRate MEMBER refreshRate CONSTANT)
1241+ Q_PROPERTY(QSize size MEMBER size CONSTANT)
1242+public:
1243+ ScreenMode():refreshRate(-1) {}
1244+ ScreenMode(const ScreenMode& other)
1245+ : QObject(nullptr),
1246+ refreshRate{other.refreshRate},size{other.size}
1247+ {}
1248+
1249+ qreal refreshRate;
1250+ QSize size;
1251+};
1252+
1253+Q_DECLARE_METATYPE(ScreenMode)
1254+
1255+#endif //UNITY_SCREEN_TYPES_H
1256
1257=== modified file 'src/platforms/mirserver/CMakeLists.txt'
1258--- src/platforms/mirserver/CMakeLists.txt 2017-04-06 08:48:51 +0000
1259+++ src/platforms/mirserver/CMakeLists.txt 2017-04-06 08:48:52 +0000
1260@@ -40,6 +40,7 @@
1261
1262 ${Qt5Quick_INCLUDE_DIRS}
1263 ${Qt5Quick_PRIVATE_INCLUDE_DIRS}
1264+ ${Qt5Qml_INCLUDE_DIRS}
1265
1266 ${APPLICATION_API_INCLUDE_DIRS}
1267
1268@@ -83,6 +84,7 @@
1269 qtcompositor.cpp
1270 displayconfigurationpolicy.cpp
1271 wrappedwindowmanagementpolicy.cpp
1272+ mirdisplayconfigurationobserver.cpp
1273 mirserverhooks.cpp mirserverhooks.h
1274 setqtcompositor.cpp setqtcompositor.h
1275 eventdispatch.cpp eventdispatch.h
1276@@ -210,6 +212,7 @@
1277 Qt5::DBus
1278 Qt5::Quick
1279 Qt5::Sensors
1280+ Qt5::Qml
1281 )
1282
1283 install(TARGETS qpa-mirserver LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}/qt5/plugins/platforms")
1284
1285=== modified file 'src/platforms/mirserver/cursor.h'
1286--- src/platforms/mirserver/cursor.h 2017-04-06 08:48:51 +0000
1287+++ src/platforms/mirserver/cursor.h 2017-04-06 08:48:52 +0000
1288@@ -26,6 +26,7 @@
1289
1290 namespace qtmir {
1291
1292+
1293 class Cursor : public MirPlatformCursor
1294 {
1295 Q_OBJECT
1296
1297=== modified file 'src/platforms/mirserver/customscreenconfiguration.h'
1298--- src/platforms/mirserver/customscreenconfiguration.h 2017-04-06 08:48:51 +0000
1299+++ src/platforms/mirserver/customscreenconfiguration.h 2017-04-06 08:48:52 +0000
1300@@ -26,8 +26,10 @@
1301
1302 struct CustomScreenConfiguration
1303 {
1304+ bool valid{false};
1305 qtmir::OutputId id;
1306
1307+ bool used;
1308 QPoint topLeft;
1309 uint32_t currentModeIndex;
1310 MirPowerMode powerMode;
1311
1312=== modified file 'src/platforms/mirserver/displayconfigurationpolicy.cpp'
1313--- src/platforms/mirserver/displayconfigurationpolicy.cpp 2017-04-06 08:48:51 +0000
1314+++ src/platforms/mirserver/displayconfigurationpolicy.cpp 2017-04-06 08:48:52 +0000
1315@@ -80,7 +80,7 @@
1316 conf.for_each_output(
1317 [&](const mg::DisplayConfigurationOutput &output )
1318 {
1319- if (output.connected && output.used) {
1320+ if (output.connected) {
1321 screenCount++;
1322
1323 if (output.type == mg::DisplayConfigurationOutputType::lvds) {
1324@@ -92,7 +92,7 @@
1325 conf.for_each_output(
1326 [&](mg::UserDisplayConfigurationOutput &output)
1327 {
1328- if (!output.connected || !output.used) {
1329+ if (!output.connected) {
1330 return;
1331 }
1332
1333
1334=== added file 'src/platforms/mirserver/mirdisplayconfigurationobserver.cpp'
1335--- src/platforms/mirserver/mirdisplayconfigurationobserver.cpp 1970-01-01 00:00:00 +0000
1336+++ src/platforms/mirserver/mirdisplayconfigurationobserver.cpp 2017-04-06 08:48:52 +0000
1337@@ -0,0 +1,63 @@
1338+/*
1339+ * Copyright (C) 2017 Canonical, Ltd.
1340+ *
1341+ * This program is free software: you can redistribute it and/or modify it under
1342+ * the terms of the GNU Lesser General Public License version 3, as published by
1343+ * the Free Software Foundation.
1344+ *
1345+ * This program is distributed in the hope that it will be useful, but WITHOUT
1346+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
1347+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1348+ * Lesser General Public License for more details.
1349+ *
1350+ * You should have received a copy of the GNU Lesser General Public License
1351+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1352+ */
1353+
1354+#include "mirdisplayconfigurationobserver.h"
1355+#include "logging.h"
1356+
1357+namespace mg = mir::graphics;
1358+namespace mf = mir::frontend;
1359+
1360+MirDisplayConfigurationObserver::MirDisplayConfigurationObserver(QObject *parent)
1361+ : QObject(parent)
1362+{
1363+}
1364+
1365+void MirDisplayConfigurationObserver::initial_configuration(const std::shared_ptr<const mg::DisplayConfiguration> &config)
1366+{
1367+ qCDebug(QTMIR_SCREENS) << "MirDisplayConfigurationObserver::initial_configuration";
1368+ Q_EMIT initialConfiguration(config);
1369+}
1370+
1371+void MirDisplayConfigurationObserver::configuration_applied(const std::shared_ptr<const mg::DisplayConfiguration> &config)
1372+{
1373+ qCDebug(QTMIR_SCREENS) << "MirDisplayConfigurationObserver::configuration_applied";
1374+ Q_EMIT configurationApplied(config);
1375+}
1376+
1377+void MirDisplayConfigurationObserver::base_configuration_updated(const std::shared_ptr<const mg::DisplayConfiguration> &base_config)
1378+{
1379+ qCDebug(QTMIR_SCREENS) << "MirDisplayConfigurationObserver::base_configuration_updated";
1380+ Q_EMIT baseConfigurationUpdated(base_config);
1381+}
1382+
1383+void MirDisplayConfigurationObserver::session_configuration_applied(const std::shared_ptr<mf::Session> &,
1384+ const std::shared_ptr<mg::DisplayConfiguration> &)
1385+{
1386+}
1387+
1388+void MirDisplayConfigurationObserver::session_configuration_removed(const std::shared_ptr<mf::Session> &)
1389+{
1390+}
1391+
1392+void MirDisplayConfigurationObserver::configuration_failed(const std::shared_ptr<const mg::DisplayConfiguration> &,
1393+ const std::exception &)
1394+{
1395+}
1396+
1397+void MirDisplayConfigurationObserver::catastrophic_configuration_error(const std::shared_ptr<const mg::DisplayConfiguration> &,
1398+ const std::exception &)
1399+{
1400+}
1401
1402=== added file 'src/platforms/mirserver/mirdisplayconfigurationobserver.h'
1403--- src/platforms/mirserver/mirdisplayconfigurationobserver.h 1970-01-01 00:00:00 +0000
1404+++ src/platforms/mirserver/mirdisplayconfigurationobserver.h 2017-04-06 08:48:52 +0000
1405@@ -0,0 +1,56 @@
1406+/*
1407+ * Copyright (C) 2017 Canonical, Ltd.
1408+ *
1409+ * This program is free software: you can redistribute it and/or modify it under
1410+ * the terms of the GNU Lesser General Public License version 3, as published by
1411+ * the Free Software Foundation.
1412+ *
1413+ * This program is distributed in the hope that it will be useful, but WITHOUT
1414+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
1415+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1416+ * Lesser General Public License for more details.
1417+ *
1418+ * You should have received a copy of the GNU Lesser General Public License
1419+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1420+ */
1421+
1422+#ifndef MIRDISPLAYCONFIGURATIONOBSERVER_H
1423+#define MIRDISPLAYCONFIGURATIONOBSERVER_H
1424+
1425+#include <QObject>
1426+
1427+#include <mir/graphics/display_configuration_observer.h>
1428+
1429+class MirDisplayConfigurationObserver : public QObject,
1430+ public mir::graphics::DisplayConfigurationObserver
1431+{
1432+ Q_OBJECT
1433+public:
1434+ explicit MirDisplayConfigurationObserver(QObject *parent = 0);
1435+
1436+ void initial_configuration(std::shared_ptr<mir::graphics::DisplayConfiguration const> const& config) override;
1437+
1438+ void configuration_applied(std::shared_ptr<mir::graphics::DisplayConfiguration const> const& config) override;
1439+
1440+ void base_configuration_updated(std::shared_ptr<mir::graphics::DisplayConfiguration const> const& base_config) override;
1441+
1442+ void session_configuration_applied(std::shared_ptr<mir::frontend::Session> const& session,
1443+ std::shared_ptr<mir::graphics::DisplayConfiguration> const& config) override;
1444+
1445+ void session_configuration_removed(std::shared_ptr<mir::frontend::Session> const& session);
1446+
1447+ void configuration_failed(
1448+ std::shared_ptr<mir::graphics::DisplayConfiguration const> const& attempted,
1449+ std::exception const& error) override;
1450+
1451+ void catastrophic_configuration_error(
1452+ std::shared_ptr<mir::graphics::DisplayConfiguration const> const& failed_fallback,
1453+ std::exception const& error);
1454+
1455+Q_SIGNALS:
1456+ void initialConfiguration(std::shared_ptr<mir::graphics::DisplayConfiguration const> const& config);
1457+ void configurationApplied(std::shared_ptr<mir::graphics::DisplayConfiguration const> const& config);
1458+ void baseConfigurationUpdated(std::shared_ptr<mir::graphics::DisplayConfiguration const> const& config);
1459+};
1460+
1461+#endif // MIRDISPLAYCONFIGURATIONOBSERVER_H
1462
1463=== modified file 'src/platforms/mirserver/mirserverhooks.cpp'
1464--- src/platforms/mirserver/mirserverhooks.cpp 2017-03-13 16:49:49 +0000
1465+++ src/platforms/mirserver/mirserverhooks.cpp 2017-04-06 08:48:52 +0000
1466@@ -138,7 +138,7 @@
1467 throw std::logic_error("No input device hub available. Server not running?");
1468 }
1469
1470-QSharedPointer<ScreensController> qtmir::MirServerHooks::createScreensController(QSharedPointer<ScreensModel> const &screensModel) const
1471+QSharedPointer<ScreensController> qtmir::MirServerHooks::createScreensController(std::shared_ptr<ScreensModel> const &screensModel) const
1472 {
1473 return QSharedPointer<ScreensController>(
1474 new ScreensController(screensModel, theMirDisplay(), self->m_mirDisplayConfigurationController.lock()));
1475
1476=== modified file 'src/platforms/mirserver/mirserverhooks.h'
1477--- src/platforms/mirserver/mirserverhooks.h 2017-01-02 14:41:06 +0000
1478+++ src/platforms/mirserver/mirserverhooks.h 2017-04-06 08:48:52 +0000
1479@@ -45,7 +45,7 @@
1480 std::shared_ptr<mir::graphics::Display> theMirDisplay() const;
1481 std::shared_ptr<mir::input::InputDeviceHub> theInputDeviceHub() const;
1482
1483- QSharedPointer<ScreensController> createScreensController(QSharedPointer<ScreensModel> const &screensModel) const;
1484+ QSharedPointer<ScreensController> createScreensController(std::shared_ptr<ScreensModel> const &screensModel) const;
1485 void createInputDeviceObserver();
1486
1487 private:
1488
1489=== modified file 'src/platforms/mirserver/mirserverintegration.cpp'
1490--- src/platforms/mirserver/mirserverintegration.cpp 2017-04-06 08:48:51 +0000
1491+++ src/platforms/mirserver/mirserverintegration.cpp 2017-04-06 08:48:52 +0000
1492@@ -138,9 +138,9 @@
1493 // need to create the screens before the integration initialises.
1494 screens->update();
1495
1496- QObject::connect(screens.data(), &ScreensModel::screenAdded,
1497+ QObject::connect(screens.get(), &ScreensModel::screenAdded,
1498 [this](PlatformScreen *screen) { this->screenAdded(screen); });
1499- QObject::connect(screens.data(), &ScreensModel::screenRemoved,
1500+ QObject::connect(screens.get(), &ScreensModel::screenRemoved,
1501 [this](PlatformScreen *screen) {
1502 #if QT_VERSION < QT_VERSION_CHECK(5, 5, 0)
1503 delete screen;
1504
1505=== modified file 'src/platforms/mirserver/platformscreen.cpp'
1506--- src/platforms/mirserver/platformscreen.cpp 2017-04-06 08:48:51 +0000
1507+++ src/platforms/mirserver/platformscreen.cpp 2017-04-06 08:48:52 +0000
1508@@ -156,7 +156,9 @@
1509 , m_unityScreen(nullptr)
1510 {
1511 setMirDisplayConfiguration(screen, false);
1512- DEBUG_MSG_SCREENS << "(output=" << m_outputId.as_value() << ", geometry=" << geometry() << ")";
1513+ DEBUG_MSG_SCREENS << "(output=" << m_outputId.as_value()
1514+ << ", used=" << (m_used ? "true" : "false")
1515+ << ", geometry=" << geometry() << ")";
1516
1517 // Set the default orientation based on the initial screen dimmensions.
1518 m_nativeOrientation = (m_geometry.width() >= m_geometry.height())
1519
1520=== modified file 'src/platforms/mirserver/qmirserver.cpp'
1521--- src/platforms/mirserver/qmirserver.cpp 2017-04-06 08:48:51 +0000
1522+++ src/platforms/mirserver/qmirserver.cpp 2017-04-06 08:48:52 +0000
1523@@ -91,7 +91,7 @@
1524 return d->serverThread->isRunning();
1525 }
1526
1527-QSharedPointer<ScreensModel> QMirServer::screensModel() const
1528+std::shared_ptr<ScreensModel> QMirServer::screensModel() const
1529 {
1530 Q_D(const QMirServer);
1531 return d->screensModel;
1532
1533=== modified file 'src/platforms/mirserver/qmirserver.h'
1534--- src/platforms/mirserver/qmirserver.h 2017-04-06 08:48:51 +0000
1535+++ src/platforms/mirserver/qmirserver.h 2017-04-06 08:48:52 +0000
1536@@ -56,7 +56,7 @@
1537 Q_SLOT void stop();
1538 bool isRunning() const;
1539
1540- QSharedPointer<ScreensModel> screensModel() const;
1541+ std::shared_ptr<ScreensModel> screensModel() const;
1542 QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const;
1543 void *nativeResourceForIntegration(const QByteArray &resource) const;
1544 std::shared_ptr<qtmir::PromptSessionManager> thePromptSessionManager() const;
1545
1546=== modified file 'src/platforms/mirserver/qmirserver_p.h'
1547--- src/platforms/mirserver/qmirserver_p.h 2017-04-06 08:48:51 +0000
1548+++ src/platforms/mirserver/qmirserver_p.h 2017-04-06 08:48:52 +0000
1549@@ -56,7 +56,7 @@
1550 {
1551 public:
1552 QMirServerPrivate();
1553- const QSharedPointer<ScreensModel> screensModel{new ScreensModel()};
1554+ const std::shared_ptr<ScreensModel> screensModel{new ScreensModel()};
1555 QSharedPointer<ScreensController> screensController;
1556 std::shared_ptr<QtEventFeeder> eventFeeder{new QtEventFeeder(screensModel)};
1557 MirServerThread *serverThread;
1558
1559=== modified file 'src/platforms/mirserver/qteventfeeder.cpp'
1560--- src/platforms/mirserver/qteventfeeder.cpp 2017-04-06 08:48:51 +0000
1561+++ src/platforms/mirserver/qteventfeeder.cpp 2017-04-06 08:48:52 +0000
1562@@ -386,7 +386,7 @@
1563 qRegisterMetaType<Qt::MouseButtons>("Qt::MouseButtons");
1564 }
1565
1566- void setScreensModel(const QSharedPointer<ScreensModel> &sc) override
1567+ void setScreensModel(const std::shared_ptr<ScreensModel> &sc) override
1568 {
1569 m_screensModel = sc;
1570 }
1571@@ -453,17 +453,17 @@
1572 }
1573
1574 private:
1575- QSharedPointer<ScreensModel> m_screensModel;
1576+ std::shared_ptr<ScreensModel> m_screensModel;
1577 };
1578
1579 } // anonymous namespace
1580
1581-QtEventFeeder::QtEventFeeder(const QSharedPointer<ScreensModel> &screensModel)
1582+QtEventFeeder::QtEventFeeder(const std::shared_ptr<ScreensModel> &screensModel)
1583 : QtEventFeeder(screensModel, new QtWindowSystem)
1584 {
1585 }
1586
1587-QtEventFeeder::QtEventFeeder(const QSharedPointer<ScreensModel> &screensModel,
1588+QtEventFeeder::QtEventFeeder(const std::shared_ptr<ScreensModel> &screensModel,
1589 QtEventFeeder::QtWindowSystemInterface *windowSystem)
1590 : mQtWindowSystem(windowSystem)
1591 {
1592
1593=== modified file 'src/platforms/mirserver/qteventfeeder.h'
1594--- src/platforms/mirserver/qteventfeeder.h 2017-04-06 08:48:51 +0000
1595+++ src/platforms/mirserver/qteventfeeder.h 2017-04-06 08:48:52 +0000
1596@@ -22,6 +22,8 @@
1597 #include <QObject>
1598 #include <qpa/qwindowsysteminterface.h>
1599
1600+#include <memory>
1601+
1602 class QTouchDevice;
1603 class ScreensModel;
1604
1605@@ -37,7 +39,7 @@
1606 class QtWindowSystemInterface {
1607 public:
1608 virtual ~QtWindowSystemInterface() {}
1609- virtual void setScreensModel(const QSharedPointer<ScreensModel> &sc) = 0;
1610+ virtual void setScreensModel(const std::shared_ptr<ScreensModel> &sc) = 0;
1611 virtual QWindow* getWindowForPoint(const QPoint &point) = 0;
1612 virtual QWindow* focusedWindow() = 0;
1613 virtual void registerTouchDevice(QTouchDevice *device) = 0;
1614@@ -52,8 +54,8 @@
1615 Qt::KeyboardModifiers mods = Qt::NoModifier) = 0;
1616 };
1617
1618- QtEventFeeder(const QSharedPointer<ScreensModel> &screensModel);
1619- QtEventFeeder(const QSharedPointer<ScreensModel> &screensModel,
1620+ QtEventFeeder(const std::shared_ptr<ScreensModel> &screensModel);
1621+ QtEventFeeder(const std::shared_ptr<ScreensModel> &screensModel,
1622 QtWindowSystemInterface *windowSystem);
1623 virtual ~QtEventFeeder();
1624
1625
1626=== modified file 'src/platforms/mirserver/screenscontroller.cpp'
1627--- src/platforms/mirserver/screenscontroller.cpp 2017-04-06 08:48:51 +0000
1628+++ src/platforms/mirserver/screenscontroller.cpp 2017-04-06 08:48:52 +0000
1629@@ -25,7 +25,7 @@
1630
1631 namespace mg = mir::graphics;
1632
1633-ScreensController::ScreensController(const QSharedPointer<ScreensModel> &model,
1634+ScreensController::ScreensController(const std::shared_ptr<ScreensModel> &model,
1635 const std::shared_ptr<mir::graphics::Display> &display,
1636 const std::shared_ptr<mir::shell::DisplayConfigurationController> &controller,
1637 QObject *parent)
1638@@ -43,7 +43,9 @@
1639 Q_FOREACH(auto screen, m_screensModel->screens()) {
1640 list.append(
1641 CustomScreenConfiguration {
1642+ true,
1643 screen->outputId(),
1644+ screen->used(),
1645 screen->geometry().topLeft(),
1646 screen->currentModeIndex(),
1647 screen->powerMode(),
1648@@ -66,8 +68,9 @@
1649 [&config](mg::UserDisplayConfigurationOutput &outputConfig)
1650 {
1651 if (config.id == outputConfig.id) {
1652+ outputConfig.used = config.used;
1653+ outputConfig.top_left = Point{ X{config.topLeft.x()}, Y{config.topLeft.y()}};
1654 outputConfig.current_mode_index = config.currentModeIndex;
1655- outputConfig.top_left = Point{ X{config.topLeft.x()}, Y{config.topLeft.y()}};
1656 outputConfig.power_mode = config.powerMode;
1657 // outputConfig.orientation = config.orientation; // disabling for now
1658 outputConfig.scale = config.scale;
1659@@ -83,3 +86,59 @@
1660 m_displayConfigurationController->set_base_configuration(std::move(displayConfiguration));
1661 return true;
1662 }
1663+
1664+CustomScreenConfiguration ScreensController::outputConfiguration(qtmir::OutputId outputId)
1665+{
1666+ auto displayConfiguration = m_display->configuration();
1667+ CustomScreenConfiguration config;
1668+
1669+ displayConfiguration->for_each_output(
1670+ [&config, outputId](mg::UserDisplayConfigurationOutput &outputConfig)
1671+ {
1672+ if (outputConfig.id == outputId) {
1673+ config.valid = true;
1674+ config.id = outputConfig.id;
1675+ config.used = outputConfig.used;
1676+ config.topLeft = QPoint{outputConfig.top_left.x.as_int(), outputConfig.top_left.y.as_int()};
1677+ config.currentModeIndex = outputConfig.current_mode_index;
1678+ config.powerMode = outputConfig.power_mode;
1679+ config.orientation = outputConfig.orientation;
1680+ config.scale = outputConfig.scale;
1681+ config.formFactor = static_cast<qtmir::FormFactor>(outputConfig.form_factor);
1682+ }
1683+ });
1684+ return config;
1685+}
1686+
1687+bool ScreensController::setOutputConfiguration(const CustomScreenConfiguration &newConfig)
1688+{
1689+ using namespace mir::geometry;
1690+ if (!newConfig.valid)
1691+ return false;
1692+
1693+ auto displayConfiguration = m_display->configuration();
1694+
1695+ // FIXME - probably need to enforce some policy here.
1696+ // Dont disable all sreens
1697+
1698+ displayConfiguration->for_each_output(
1699+ [newConfig](mg::UserDisplayConfigurationOutput &outputConfig)
1700+ {
1701+ if (outputConfig.id == newConfig.id) {
1702+ outputConfig.used = newConfig.used;
1703+ outputConfig.top_left = Point{ X{newConfig.topLeft.x()}, Y{newConfig.topLeft.y()}};
1704+ outputConfig.current_mode_index = newConfig.currentModeIndex;
1705+ outputConfig.power_mode = newConfig.powerMode;
1706+// outputConfig.orientation = newConfig.orientation; // disabling for now
1707+ outputConfig.scale = newConfig.scale;
1708+ outputConfig.form_factor = static_cast<MirFormFactor>(newConfig.formFactor);
1709+ }
1710+ });
1711+
1712+ if (!displayConfiguration->valid()) {
1713+ return false;
1714+ }
1715+
1716+ m_displayConfigurationController->set_base_configuration(std::move(displayConfiguration));
1717+ return true;
1718+}
1719
1720=== modified file 'src/platforms/mirserver/screenscontroller.h'
1721--- src/platforms/mirserver/screenscontroller.h 2016-11-03 20:17:46 +0000
1722+++ src/platforms/mirserver/screenscontroller.h 2017-04-06 08:48:52 +0000
1723@@ -40,7 +40,7 @@
1724 Q_OBJECT
1725
1726 public:
1727- explicit ScreensController(const QSharedPointer<ScreensModel> &model,
1728+ explicit ScreensController(const std::shared_ptr<ScreensModel> &model,
1729 const std::shared_ptr<mir::graphics::Display> &display,
1730 const std::shared_ptr<mir::shell::DisplayConfigurationController> &controller,
1731 QObject *parent = 0);
1732@@ -48,8 +48,11 @@
1733 CustomScreenConfigurationList configuration();
1734 bool setConfiguration(const CustomScreenConfigurationList &newConfig);
1735
1736+ CustomScreenConfiguration outputConfiguration(qtmir::OutputId outputId);
1737+ bool setOutputConfiguration(const CustomScreenConfiguration &newConfig);
1738+
1739 private:
1740- const QSharedPointer<ScreensModel> m_screensModel;
1741+ const std::shared_ptr<ScreensModel> m_screensModel;
1742 const std::shared_ptr<mir::graphics::Display> m_display;
1743 const std::shared_ptr<mir::shell::DisplayConfigurationController> m_displayConfigurationController;
1744 };
1745
1746=== modified file 'src/platforms/mirserver/screensmodel.cpp'
1747--- src/platforms/mirserver/screensmodel.cpp 2017-04-06 08:48:51 +0000
1748+++ src/platforms/mirserver/screensmodel.cpp 2017-04-06 08:48:52 +0000
1749@@ -41,7 +41,7 @@
1750 #define DEBUG_MSG qCDebug(QTMIR_SCREENS).nospace() << "ScreensModel[" << this <<"]::" << __func__
1751
1752 ScreensModel::ScreensModel(QObject *parent)
1753- : QObject(parent)
1754+ : MirDisplayConfigurationObserver(parent)
1755 , m_compositing(false)
1756 {
1757 DEBUG_MSG << "()";
1758@@ -65,6 +65,9 @@
1759 this, &ScreensModel::onCompositorStarting);
1760 connect(qtCompositor, &QtCompositor::stopping,
1761 this, &ScreensModel::onCompositorStopping, Qt::BlockingQueuedConnection);
1762+
1763+ connect(this, &MirDisplayConfigurationObserver::configurationApplied,
1764+ this, &ScreensModel::update, Qt::BlockingQueuedConnection);
1765 }
1766
1767 // terminate before shutting down the Mir server, or else liable to deadlock with the blocking connection above
1768@@ -110,7 +113,7 @@
1769
1770 displayConfig->for_each_output(
1771 [this, &oldScreenList, &newScreenList, &windowMoveList](const mg::DisplayConfigurationOutput &output) {
1772- if (output.used && output.connected) {
1773+ if (output.connected) {
1774 PlatformScreen *screen = findScreenWithId(oldScreenList, output.id);
1775 if (screen) { // we've already set up this display before
1776
1777@@ -141,6 +144,14 @@
1778 newScreenList.append(screen);
1779 m_screenList.append(screen);
1780 }
1781+
1782+ if (!output.used) {
1783+ Q_FOREACH (ScreenPlatformWindow* window, screen->windows()) {
1784+ if (window->window() && window->isExposed()) {
1785+ window->window()->hide();
1786+ }
1787+ }
1788+ }
1789 }
1790 }
1791 );
1792@@ -229,9 +240,9 @@
1793 void ScreensModel::startRenderer()
1794 {
1795 Q_FOREACH (const auto screen, m_screenList) {
1796- // Only set windows exposed on displays which are turned on, as the GL context Mir provided
1797+ // Only set windows exposed on displays which are used and turned on, as the GL context Mir provided
1798 // is invalid in that situation
1799- if (screen->powerMode() == mir_power_mode_on) {
1800+ if (screen->used() && screen->powerMode() == mir_power_mode_on) {
1801 Q_FOREACH (ScreenPlatformWindow* window, screen->windows()) {
1802 window->setExposed(true);
1803 }
1804@@ -247,6 +258,7 @@
1805 void ScreensModel::haltRenderer()
1806 {
1807 Q_FOREACH (const auto screen, m_screenList) {
1808+
1809 Q_FOREACH (ScreenPlatformWindow* window, screen->windows()) {
1810 window->setExposed(false);
1811 }
1812
1813=== modified file 'src/platforms/mirserver/screensmodel.h'
1814--- src/platforms/mirserver/screensmodel.h 2017-04-06 08:48:51 +0000
1815+++ src/platforms/mirserver/screensmodel.h 2017-04-06 08:48:52 +0000
1816@@ -17,6 +17,8 @@
1817 #ifndef SCREENCONTROLLER_H
1818 #define SCREENCONTROLLER_H
1819
1820+#include "mirdisplayconfigurationobserver.h"
1821+
1822 #include <QObject>
1823 #include <QPoint>
1824
1825@@ -54,7 +56,7 @@
1826 * All other methods must be called on the Qt GUI thread.
1827 */
1828
1829-class ScreensModel : public QObject
1830+class ScreensModel : public MirDisplayConfigurationObserver
1831 {
1832 Q_OBJECT
1833 public:
1834
1835=== modified file 'src/platforms/mirserver/setqtcompositor.cpp'
1836--- src/platforms/mirserver/setqtcompositor.cpp 2016-11-03 20:17:46 +0000
1837+++ src/platforms/mirserver/setqtcompositor.cpp 2017-04-06 08:48:52 +0000
1838@@ -25,8 +25,9 @@
1839 // mir
1840 #include <mir/server.h>
1841 #include <mir/shell/shell.h>
1842+#include <mir/observer_registrar.h>
1843
1844-qtmir::SetQtCompositor::SetQtCompositor(QSharedPointer<ScreensModel> const& screensModel) :
1845+qtmir::SetQtCompositor::SetQtCompositor(std::shared_ptr<ScreensModel> const& screensModel) :
1846 m_screensModel{screensModel}
1847 {
1848 }
1849@@ -44,6 +45,7 @@
1850 {
1851 if (auto const compositor = m_compositor.lock())
1852 {
1853+ server.the_display_configuration_observer_registrar()->register_interest(m_screensModel);
1854 m_screensModel->init(server.the_display(), compositor, server.the_shell());
1855 }
1856 else
1857
1858=== modified file 'src/platforms/mirserver/setqtcompositor.h'
1859--- src/platforms/mirserver/setqtcompositor.h 2016-11-03 20:17:46 +0000
1860+++ src/platforms/mirserver/setqtcompositor.h 2017-04-06 08:48:52 +0000
1861@@ -34,12 +34,12 @@
1862 class SetQtCompositor
1863 {
1864 public:
1865- explicit SetQtCompositor(QSharedPointer<ScreensModel> const& screensModel);
1866+ explicit SetQtCompositor(std::shared_ptr<ScreensModel> const& screensModel);
1867
1868 void operator()(mir::Server& server);
1869
1870 private:
1871- QSharedPointer<ScreensModel> const m_screensModel;
1872+ std::shared_ptr<ScreensModel> const m_screensModel;
1873 std::weak_ptr<QtCompositor> m_compositor;
1874 };
1875 }
1876
1877=== modified file 'tests/mirserver/QtEventFeeder/mock_qtwindowsystem.h'
1878--- tests/mirserver/QtEventFeeder/mock_qtwindowsystem.h 2017-04-06 08:48:51 +0000
1879+++ tests/mirserver/QtEventFeeder/mock_qtwindowsystem.h 2017-04-06 08:48:52 +0000
1880@@ -19,13 +19,13 @@
1881 #define MOCK_QTWINDOWSYSTEM_H
1882
1883 #include <qteventfeeder.h>
1884+#include <QGuiApplication>
1885 #include <QWindow>
1886
1887 class MockQtWindowSystem : public QtEventFeeder::QtWindowSystemInterface {
1888 public:
1889 MOCK_CONST_METHOD0(ready, bool());
1890- MOCK_METHOD1(setScreensModel, void(const QSharedPointer<ScreensModel> &));
1891- MOCK_METHOD1(getWindowForPoint, QWindow*(const QPoint &point));
1892+ MOCK_METHOD1(setScreensModel, void(const std::shared_ptr<ScreensModel> &));
1893 MOCK_METHOD0(lastWindow, QWindow*());
1894 MOCK_METHOD0(focusedWindow, QWindow*());
1895 // ignores the last parameter count, due to parameter limit in gmock
1896@@ -51,8 +51,6 @@
1897 MOCK_METHOD5(handleTouchEvent, void(QWindow *window, ulong timestamp, QTouchDevice *device,
1898 const QList<struct QWindowSystemInterface::TouchPoint> &points,
1899 Qt::KeyboardModifiers mods));
1900- MOCK_METHOD5(handleMouseEvent, void(ulong timestamp, QPointF relative, QPointF absolute, Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers));
1901- MOCK_METHOD4(handleWheelEvent, void(ulong timestamp, QPointF absolute, QPoint angleDelta, Qt::KeyboardModifiers modifiers));
1902
1903 ~MockQtWindowSystem()
1904 {
1905@@ -64,6 +62,12 @@
1906 m_devices << device;
1907 }
1908
1909+ QWindow* getWindowForPoint(const QPoint&)
1910+ {
1911+ auto windows = qApp->topLevelWindows();
1912+ return windows.isEmpty() ? nullptr : windows.first();
1913+ }
1914+
1915 QVector<QTouchDevice*> m_devices;
1916 };
1917
1918
1919=== modified file 'tests/mirserver/QtEventFeeder/qteventfeeder_test.cpp'
1920--- tests/mirserver/QtEventFeeder/qteventfeeder_test.cpp 2017-04-06 08:48:51 +0000
1921+++ tests/mirserver/QtEventFeeder/qteventfeeder_test.cpp 2017-04-06 08:48:52 +0000
1922@@ -79,7 +79,7 @@
1923 void QtEventFeederTest::SetUp()
1924 {
1925 mockWindowSystem = new MockQtWindowSystem;
1926- auto screens = QSharedPointer<ScreensModel>();
1927+ auto screens = std::shared_ptr<ScreensModel>();
1928
1929 ASSERT_TRUE(mockWindowSystem->m_devices.count() == 0);
1930
1931@@ -104,9 +104,6 @@
1932
1933 void QtEventFeederTest::setIrrelevantMockWindowSystemExpectations()
1934 {
1935- EXPECT_CALL(*mockWindowSystem, getWindowForPoint(_))
1936- .Times(AnyNumber())
1937- .WillRepeatedly(Return(window));
1938 EXPECT_CALL(*mockWindowSystem, focusedWindow())
1939 .Times(AnyNumber())
1940 .WillRepeatedly(Return(window));

Subscribers

People subscribed via source and target branches