Merge lp:~dandrader/qtmir/surfaceItemFillMode into lp:qtmir
- surfaceItemFillMode
- Merge into trunk
| Status: | Superseded | ||||
|---|---|---|---|---|---|
| Proposed branch: | lp:~dandrader/qtmir/surfaceItemFillMode | ||||
| Merge into: | lp:qtmir | ||||
| Prerequisite: | lp:~dandrader/qtmir/mousePointer | ||||
| Diff against target: |
4154 lines (+2325/-508) 62 files modified
CMakeLists.txt (+3/-3) demos/qml-demo-shell/qml-demo-shell.qml (+19/-0) src/common/debughelpers.cpp (+30/-1) src/common/debughelpers.h (+1/-0) src/modules/Unity/Application/mirbuffersgtexture.cpp (+29/-11) src/modules/Unity/Application/mirbuffersgtexture.h (+1/-0) src/modules/Unity/Application/mirsurface.cpp (+38/-18) src/modules/Unity/Application/mirsurface.h (+11/-2) src/modules/Unity/Application/mirsurfaceinterface.h (+5/-1) src/modules/Unity/Application/mirsurfaceitem.cpp (+52/-10) src/modules/Unity/Application/mirsurfaceitem.h (+9/-0) src/modules/Unity/CMakeLists.txt (+1/-0) src/modules/Unity/Screens/CMakeLists.txt (+24/-0) src/modules/Unity/Screens/plugin.cpp (+41/-0) src/modules/Unity/Screens/qmldir (+2/-0) src/modules/Unity/Screens/screens.cpp (+107/-0) src/modules/Unity/Screens/screens.h (+82/-0) src/platforms/mirserver/CMakeLists.txt (+5/-2) src/platforms/mirserver/display.cpp (+0/-44) src/platforms/mirserver/display.h (+0/-37) src/platforms/mirserver/logging.h (+1/-0) src/platforms/mirserver/miropenglcontext.cpp (+25/-10) src/platforms/mirserver/miropenglcontext.h (+1/-0) src/platforms/mirserver/mirserver.cpp (+39/-5) src/platforms/mirserver/mirserver.h (+8/-2) src/platforms/mirserver/mirserverintegration.cpp (+42/-39) src/platforms/mirserver/mirserverintegration.h (+4/-7) src/platforms/mirserver/offscreensurface.cpp (+61/-0) src/platforms/mirserver/offscreensurface.h (+43/-0) src/platforms/mirserver/qmirserver.cpp (+12/-2) src/platforms/mirserver/qmirserver.h (+3/-0) src/platforms/mirserver/qmirserver_p.h (+2/-0) src/platforms/mirserver/qtcompositor.cpp (+19/-31) src/platforms/mirserver/qtcompositor.h (+25/-5) src/platforms/mirserver/qteventfeeder.cpp (+108/-85) src/platforms/mirserver/qteventfeeder.h (+11/-8) src/platforms/mirserver/screen.cpp (+109/-7) src/platforms/mirserver/screen.h (+33/-3) src/platforms/mirserver/screencontroller.cpp (+211/-0) src/platforms/mirserver/screencontroller.h (+95/-0) src/platforms/mirserver/screenwindow.cpp (+73/-98) src/platforms/mirserver/screenwindow.h (+13/-24) src/platforms/mirserver/tileddisplayconfigurationpolicy.cpp (+44/-0) src/platforms/mirserver/tileddisplayconfigurationpolicy.h (+35/-0) tests/common/fake_displayconfigurationoutput.h (+77/-0) tests/common/gmock_fixes.h (+124/-0) tests/common/mock_display.h (+53/-0) tests/common/mock_display_configuration.h (+35/-0) tests/common/mock_gl_display_buffer.h (+49/-0) tests/common/mock_main_loop.h (+53/-0) tests/mirserver/CMakeLists.txt (+1/-0) tests/mirserver/QtEventFeeder/mock_qtwindowsystem.h (+16/-9) tests/mirserver/QtEventFeeder/qteventfeeder_test.cpp (+27/-16) tests/mirserver/Screen/CMakeLists.txt (+1/-0) tests/mirserver/Screen/screen_test.cpp (+38/-26) tests/mirserver/ScreenController/CMakeLists.txt (+29/-0) tests/mirserver/ScreenController/screencontroller_test.cpp (+177/-0) tests/mirserver/ScreenController/stub_display.h (+96/-0) tests/mirserver/ScreenController/stub_screen.h (+31/-0) tests/mirserver/ScreenController/testable_screencontroller.h (+37/-0) tests/modules/common/fake_mirsurface.h (+3/-1) tests/modules/common/qtmir_test.h (+1/-1) |
||||
| To merge this branch: | bzr merge lp:~dandrader/qtmir/surfaceItemFillMode | ||||
| Related bugs: |
|
| Reviewer | Review Type | Date Requested | Status |
|---|---|---|---|
| PS Jenkins bot | continuous-integration | 2015-10-14 | Needs Fixing on 2015-10-14 |
| Michael Zanetti | 2015-10-14 | Pending | |
|
Review via email:
|
|||
This proposal supersedes a proposal from 2015-09-11.
This proposal has been superseded by a proposal from 2015-10-16.
Commit Message
Add MirSurfaceItem.
Ensure that by the time we enter the phase of updating the scene graph, all qml items are up to date regarding the size of the buffer about to be rendered.
NB: This rendering scheme needs triple buffering to work.
Description of the Change
* Are there any related MPs required for this MP to build/function as expected? Please list.
https:/
https:/
* Did you perform an exploratory manual test run of your code change and any related functionality?
Yes
* If you changed the packaging (debian), did you subscribe the ubuntu-unity team to this MP?
Not applicable
| PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
| Daniel van Vugt (vanvugt) wrote : Posted in a previous version of this proposal | # |
Glad to have helped. This isn't the first time someone has told me I'm wrong and then they went ahead and copied my code :)
| Gerry Boland (gerboland) wrote : Posted in a previous version of this proposal | # |
What's the use-case of this fillMode? The crop ability might have use in the spread? But it's not a proper solution for the stretched frames issue on rotation.
| Daniel d'Andrada (dandrader) wrote : Posted in a previous version of this proposal | # |
On 18/09/15 08:02, Gerry Boland wrote:
> What's the use-case of this fillMode? The crop ability might have use in the spread? But it's not a proper solution for the stretched frames issue on rotation.
Resize untiy8-dash in desktop mode on a Nexus device and you'll see.
| Michael Zanetti (mzanetti) wrote : Posted in a previous version of this proposal | # |
Code looks ok, but as noticed on the related unity8 branch, I'm not sure if this is the proper place to calculate the innerRect stuff. It has the effect that it makes window content and window decoration/shadow go out of sync.
| Daniel d'Andrada (dandrader) wrote : Posted in a previous version of this proposal | # |
On 23/09/2015 07:32, Michael Zanetti wrote:
> Review: Needs Information
>
> Code looks ok, but as noticed on the related unity8 branch, I'm not sure if this is the proper place to calculate the innerRect stuff. It has the effect that it makes window content and window decoration/shadow go out of sync.
They're two separate things. fillMode is there to ensure that you never
see a stretched surface even if the MirSurfaceItem size doesn't match
it. See it as yet another MirSurface feature that shells (unity8) can
take and use it on their UI/interaction designs.
What unity8 *does with it* is another thing. That shadow "going out of
sync" is a crude implementation or that unity7 window resize mode where
the window is not resize live, but you drag a translucent orang bounding
rect of it and only on release does the window get committed to that
bounding rect size (or actually a hint for the possibility doing the same).
| PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:389
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 387. By Albert Astals Cid on 2015-10-21
-
Don't search for the element again
Approved by: Gerry Boland, PS Jenkins bot
- 388. By Daniel d'Andrada on 2015-10-21
-
Shell draws its own cursor using the new Cursor QML element
Approved by: Lukáš Tinkl, Gerry Boland - 389. By Gerry Boland on 2015-10-21
-
Initial multimonitor support - react correctly to Mir DisplayConfigur
ation changes. On Mir DisplayConfigur
ation changes, QtMir now correctly:
1. blocks Mir until it has stopped all renderers and has their GL contexts released
2. reads the new DisplayConfiguration, matches any existing ScreenWindows to new DisplayBuffers should they change (as Mir may destroy and create it on us)
3. restarts all renderersThis also solves shutdown crash issues due to raciness of mir destroying the GL context backing the shell's QWindow before its renderer had stopped.
Add Unity.Screens qml module to advertise current screen state to QML. Fixes: #1436735, #1488831, #1488863
Approved by: Daniel d'Andrada - 390. By Michał Sawicz on 2015-10-21
-
MirSurfaceItem: Survive holding a surface with an empty texture
Survive having a surface whose texture holds no mir buffer at all.
Instead of crashing in such situation we simply don't render it.
Approved by: Gerry Boland - 391. By Michał Sawicz on 2015-10-21
-
Improve multimonitor support
* Removed magic:
- Don't automagically select the screen where a window will be show.
Let shell decide.
- Don't automagically focus a window. Let shell handle it.* Let shell know when a screen is about to be removed so that it has
the opportunity to move or destroy a window in it before it's too late.
- Added QGuiApplication::onScreenAbout ToBeRemoved * Added logging to key events
Approved by: Michał Sawicz - 392. By Alan Griffiths on 2015-10-21
-
Opaquify MirWindowManager to control visibility of upcoming Window Management work
Approved by: Gerry Boland, PS Jenkins bot - 393. By Lukáš Tinkl on 2015-10-21
-
React to surface modifications (window caption)
Approved by: Daniel d'Andrada - 394. By Nick Dedekind on 2015-10-21
-
Removed the manipulation of the CMAKE_INSTALL_
PREFIX from debian/rules
Approved by: Gerry Boland - 395. By Nick Dedekind on 2015-10-21
-
Added touch performance tracing and test.
Approved by: Gerry Boland - 396. By Lukáš Tinkl on 2015-10-21
-
Implement support for mouse wheel events; correctly pass around buttons Fixes: #1497091
Approved by: Gerry Boland - 397. By Gerry Boland on 2015-10-21
-
Workaround for AutoPilot input coordinate positioning being outside screen geometry
- 398. By CI Train Bot Account on 2015-10-21
-
Releasing 0.4.6+15.
10.20151021- 0ubuntu1 - 399. By Michał Sawicz on 2015-11-02
-
Clean up packaging and fix autopkgtest on armhf
Approved by: Gerry Boland - 400. By Michael Terry on 2015-11-02
-
Support new isTouchApp property to ApplicationInfo
Interface and move lifecycle policy logic out of qtmir. Now that qtmir won't decide policy for suspending anymore, we don't need all the lifecycleException handling in qtmir either. That can move to unity8.
But since the GSettings key for that was registered under the qtmir namespace (and there's no technical reason to migrate settings), I left the schema and classes dealing with GSettings alone, for future use.
- 401. By Nick Dedekind on 2015-11-02
-
Support server->client visibility change to stop rendering (lp:#1475678) Fixes: #1475678
Approved by: Daniel d'Andrada - 402. By Alan Griffiths on 2015-11-02
-
Test harness for MirWindowManager (in preparation for more intelligent window management)
Approved by: Gerry Boland - 403. By Nick Dedekind on 2015-11-02
-
Hand Qt millisecond timestamps rather than nanosecond. Fixes: #1510571, #1511076, #1511711
Approved by: Gerry Boland - 404. By CI Train Bot Account on 2015-11-02
-
Releasing 0.4.6+16.
04.20151102- 0ubuntu1 - 405. By Nick Dedekind on 2015-11-10
-
Reverted occlusion detection (lp#1514556) Fixes: #1514556
- 406. By CI Train Bot Account on 2015-11-10
-
Releasing 0.4.6+16.
04.20151110- 0ubuntu1 - 407. By Gerry Boland on 2015-11-12
-
Fix armhf builds on Xenial by using -std=gnu99 instead of c99
Fixes this FTBFS on xenial:
In file included from /usr/include/
lttng/tracepoin t-rcu.h: 26:0,
from /usr/include/ lttng/tracepoin t.h:29,
from /home/phablet/ dev/projects/ qtmir/qtmir/ BUILD-xen/ src/platforms/ mirserver/ tracepoints. h:10,
from /home/phablet/ dev/projects/ qtmir/qtmir/ BUILD-xen/ src/platforms/ mirserver/ tracepoints. c:7:
/usr/include/urcu/arch/ generic. h: In function ‘caa_get_cycles’:
/usr/include/urcu/arch/ generic. h:165:6: error: ‘CLOCK_MONOTONIC’ undeclared (first use in this function)
if (caa_unlikely(clock_gettime( CLOCK_MONOTONIC , &ts)))
^
/usr/include/urcu/arch/ generic. h:165:6: note: each undeclared identifier is reported only once for each function it appears in Strictly should compile code with -std=gnu99 instead of -std=c99 to have the identifiers SIGEV_SIGNAL, sigeventStruct, and CLOCK_MONOTONIC available. These identifiers are declared when _POSIX_C_SOURCE is set to a value >= 199309L, which is the case with -std=gnu99. I could also have used -D_POSIX_
C_SOURCE= 199309L -std=c99 or have the macro defined in source code. Did not impact wily as libuctu only started looking for CLOCK_MONOTONIC in Xenial release.
Approved by: Daniel d'Andrada - 408. By CI Train Bot Account on 2015-11-12
-
Releasing 0.4.6+16.
04.20151112- 0ubuntu1 - 409. By Nick Dedekind on 2015-11-13
-
Update surface textures when dropping frames. Fixes: #1515356
Approved by: Gerry Boland - 410. By CI Train Bot Account on 2015-11-13
-
Releasing 0.4.6+16.
04.20151113- 0ubuntu1 - 411. By Gerry Boland on 2015-11-19
-
Fix use of uninitialized variable
Approved by: Daniel d'Andrada, PS Jenkins bot - 412. By Albert Astals Cid on 2015-11-19
-
Enable Efficient String Construction by default
See http://
blog.qt. io/blog/ 2011/06/ 13/string- concatenation- with-qstringbui lder/
Approved by: Gerry Boland, PS Jenkins bot - 413. By Michał Sawicz on 2015-11-19
-
Build with clang (tests/gmock fails and is unfixable on our side i'd say)
Approved by: Gerry Boland - 414. By Gerry Boland on 2015-11-19
-
Use pid_t for PIDs.
Approved by: Daniel d'Andrada, PS Jenkins bot - 415. By Loïc Molinari on 2015-11-19
-
Ensured Mir surface items with size less than or equal to zero are not rendered, as it's usually done for standard QtQuick items.
Approved by: Gerry Boland - 416. By Nick Dedekind on 2015-11-19
-
Fix a crash when dropping a surface frame before Qt draws a surface item. Fixes: #1517139
Approved by: Gerry Boland - 417. By CI Train Bot Account on 2015-11-19
-
Releasing 0.4.6+16.
04.20151119- 0ubuntu1 - 418. By Daniel d'Andrada on 2015-11-25
-
Implemented support for cursors set by client surfaces
Approved by: Lukáš Tinkl - 419. By Gerry Boland on 2015-11-25
-
Manage frameSwapped signal/slot connection with MirSurface more strictly to avoid crash.
Direct Signal/slot connections across thread boundaries incur the same risks as any cross-thread calls. While connect/disconnect are thread safe methods, it is possible for a slot to be called while the slot owner is being deconstructed - and so not yet disconnected.
So watch for the Item's window change signal and disconnect signal immediately. Also move slot ownership to MirSurfaceItem to auto-disconnect more aggressively.
Fixes: #1517571
Approved by: Daniel d'Andrada - 420. By Daniel d'Andrada on 2015-11-25
-
Forward Mir mouse wheel events to the shell cursor Fixes: #1497091
Approved by: Lukáš Tinkl - 421. By Daniel d'Andrada on 2015-11-25
-
Revert revision 415
The commit "Ensured Mir surface items with size less than or equal to zero are not rendered,
as it's usually done for standard QtQuick items." caused a regression.MirSurface.size was being kept uninitialized, as QSize(-1,-1).
- 422. By CI Train Bot Account on 2015-11-25
-
Releasing 0.4.6+16.
04.20151125- 0ubuntu1 - 423. By Timo Jyrinki on 2015-12-01
-
Rebuild against Qt 5.5.1.
- 424. By Daniel d'Andrada on 2015-12-04
- 425. By Daniel d'Andrada on 2015-12-04
-
Add MirSurfaceItem.
fillMode - 426. By Daniel d'Andrada on 2015-12-04
-
Fix bad merge of polite-close
Unmerged revisions
- 426. By Daniel d'Andrada on 2015-12-04
-
Fix bad merge of polite-close
- 425. By Daniel d'Andrada on 2015-12-04
-
Add MirSurfaceItem.
fillMode - 424. By Daniel d'Andrada on 2015-12-04
Preview Diff
| 1 | === modified file 'CMakeLists.txt' |
| 2 | --- CMakeLists.txt 2015-10-16 17:43:47 +0000 |
| 3 | +++ CMakeLists.txt 2015-10-16 17:43:47 +0000 |
| 4 | @@ -60,9 +60,9 @@ |
| 5 | |
| 6 | find_package(Threads REQUIRED) |
| 7 | |
| 8 | -pkg_check_modules(MIRSERVER mirserver>=0.16 REQUIRED) |
| 9 | -pkg_check_modules(MIRCLIENT mirclient>=0.16 REQUIRED) |
| 10 | -pkg_check_modules(MIRRENDERERGLDEV mir-renderer-gl-dev>=0.16 REQUIRED) |
| 11 | +pkg_check_modules(MIRSERVER mirserver>=0.17 REQUIRED) |
| 12 | +pkg_check_modules(MIRCLIENT mirclient>=0.17 REQUIRED) |
| 13 | +pkg_check_modules(MIRRENDERERGLDEV mir-renderer-gl-dev>=0.17 REQUIRED) |
| 14 | |
| 15 | pkg_check_modules(GLIB glib-2.0 REQUIRED) |
| 16 | pkg_check_modules(PROCESS_CPP process-cpp REQUIRED) |
| 17 | |
| 18 | === renamed file 'demos/qml-demo-shell/qml-demo-shell.qml' => 'demos/qml-demo-shell/Shell.qml' |
| 19 | === added file 'demos/qml-demo-shell/qml-demo-shell.qml' |
| 20 | --- demos/qml-demo-shell/qml-demo-shell.qml 1970-01-01 00:00:00 +0000 |
| 21 | +++ demos/qml-demo-shell/qml-demo-shell.qml 2015-10-16 17:43:47 +0000 |
| 22 | @@ -0,0 +1,19 @@ |
| 23 | +import QtQuick 2.3 |
| 24 | +import QtQuick.Window 2.2 as QQW |
| 25 | +import Unity.Screens 0.1 |
| 26 | + |
| 27 | +Instantiator { |
| 28 | + id: root |
| 29 | + |
| 30 | + property var screens: Screens{} |
| 31 | + |
| 32 | + model: screens |
| 33 | + QQW.Window { |
| 34 | + id: window |
| 35 | + visible: true |
| 36 | + Shell{ anchors.fill: parent } |
| 37 | + Component.onCompleted: { |
| 38 | + print("HEY", screen, screen.geometry, outputType, Screens.HDMIA) |
| 39 | + } |
| 40 | + } |
| 41 | +} |
| 42 | |
| 43 | === modified file 'src/common/debughelpers.cpp' |
| 44 | --- src/common/debughelpers.cpp 2015-08-27 16:10:20 +0000 |
| 45 | +++ src/common/debughelpers.cpp 2015-10-16 17:43:47 +0000 |
| 46 | @@ -223,7 +223,7 @@ |
| 47 | { |
| 48 | const int pointerCount = mir_touch_event_point_count(event); |
| 49 | |
| 50 | - QString string("MirTouchInputEvent("); |
| 51 | + QString string("MirTouchEvent("); |
| 52 | |
| 53 | for (int i = 0; i < pointerCount; ++i) { |
| 54 | |
| 55 | @@ -265,3 +265,32 @@ |
| 56 | break; |
| 57 | } |
| 58 | } |
| 59 | + |
| 60 | +namespace { |
| 61 | +const char *mirKeyboardActionToString(MirKeyboardAction keyboardAction) |
| 62 | +{ |
| 63 | + switch (keyboardAction) |
| 64 | + { |
| 65 | + case mir_keyboard_action_up: |
| 66 | + return "up"; |
| 67 | + case mir_keyboard_action_down: |
| 68 | + return "down"; |
| 69 | + case mir_keyboard_action_repeat: |
| 70 | + return "repeat"; |
| 71 | + default: |
| 72 | + return "???"; |
| 73 | + break; |
| 74 | + } |
| 75 | +} |
| 76 | +} |
| 77 | + |
| 78 | +QString mirKeyboardEventToString(MirKeyboardEvent const* event) |
| 79 | +{ |
| 80 | + MirKeyboardAction keyboardAction = mir_keyboard_event_action(event); |
| 81 | + |
| 82 | + xkb_keysym_t keyCode = mir_keyboard_event_key_code(event); |
| 83 | + |
| 84 | + return QString("MirKeyboardEvent(action=%1,key_code=0x%2)") |
| 85 | + .arg(mirKeyboardActionToString(keyboardAction)) |
| 86 | + .arg(keyCode, 4, 16, QLatin1Char('0')); |
| 87 | +} |
| 88 | |
| 89 | === modified file 'src/common/debughelpers.h' |
| 90 | --- src/common/debughelpers.h 2015-08-27 16:10:20 +0000 |
| 91 | +++ src/common/debughelpers.h 2015-10-16 17:43:47 +0000 |
| 92 | @@ -38,6 +38,7 @@ |
| 93 | |
| 94 | QString mirPointerEventToString(MirPointerEvent const* event); |
| 95 | QString mirTouchEventToString(MirTouchEvent const* event); |
| 96 | +QString mirKeyboardEventToString(MirKeyboardEvent const* event); |
| 97 | const char *mirTouchActionToString(MirTouchAction touchAction); |
| 98 | |
| 99 | #endif // UBUNTUGESTURES_DEBUG_HELPER_H |
| 100 | |
| 101 | === modified file 'src/modules/Unity/Application/mirbuffersgtexture.cpp' |
| 102 | --- src/modules/Unity/Application/mirbuffersgtexture.cpp 2015-09-17 16:46:37 +0000 |
| 103 | +++ src/modules/Unity/Application/mirbuffersgtexture.cpp 2015-10-16 17:43:47 +0000 |
| 104 | @@ -21,6 +21,9 @@ |
| 105 | #include <mir/geometry/size.h> |
| 106 | #include <mir/renderer/gl/texture_source.h> |
| 107 | |
| 108 | +// mirserver |
| 109 | +#include <logging.h> |
| 110 | + |
| 111 | namespace mg = mir::geometry; |
| 112 | namespace mrg = mir::renderer::gl; |
| 113 | |
| 114 | @@ -59,6 +62,11 @@ |
| 115 | m_width = size.width.as_int(); |
| 116 | } |
| 117 | |
| 118 | +bool MirBufferSGTexture::hasBuffer() const |
| 119 | +{ |
| 120 | + return !!m_mirBuffer; |
| 121 | +} |
| 122 | + |
| 123 | int MirBufferSGTexture::textureId() const |
| 124 | { |
| 125 | return m_textureId; |
| 126 | @@ -71,19 +79,29 @@ |
| 127 | |
| 128 | bool MirBufferSGTexture::hasAlphaChannel() const |
| 129 | { |
| 130 | - return m_mirBuffer->pixel_format() == mir_pixel_format_abgr_8888 |
| 131 | - || m_mirBuffer->pixel_format() == mir_pixel_format_argb_8888; |
| 132 | + if (hasBuffer()) { |
| 133 | + return m_mirBuffer->pixel_format() == mir_pixel_format_abgr_8888 |
| 134 | + || m_mirBuffer->pixel_format() == mir_pixel_format_argb_8888; |
| 135 | + } else { |
| 136 | + qCWarning(QTMIR_SURFACES) << "MirBufferSGTexture: hasAlphaChannel() called but there's no mir buffer to query"; |
| 137 | + return false; |
| 138 | + } |
| 139 | } |
| 140 | |
| 141 | void MirBufferSGTexture::bind() |
| 142 | { |
| 143 | - glBindTexture(GL_TEXTURE_2D, m_textureId); |
| 144 | - updateBindOptions(true/* force */); |
| 145 | - |
| 146 | - auto const texture_source = |
| 147 | - dynamic_cast<mrg::TextureSource*>(m_mirBuffer->native_buffer_base()); |
| 148 | - if (!texture_source) |
| 149 | - throw std::logic_error("Buffer does not support GL rendering"); |
| 150 | - |
| 151 | - texture_source->gl_bind_to_texture(); |
| 152 | + if (hasBuffer()) { |
| 153 | + glBindTexture(GL_TEXTURE_2D, m_textureId); |
| 154 | + updateBindOptions(true/* force */); |
| 155 | + |
| 156 | + auto const texture_source = |
| 157 | + dynamic_cast<mrg::TextureSource*>(m_mirBuffer->native_buffer_base()); |
| 158 | + if (!texture_source) |
| 159 | + throw std::logic_error("Buffer does not support GL rendering"); |
| 160 | + |
| 161 | + texture_source->gl_bind_to_texture(); |
| 162 | + } else { |
| 163 | + qCWarning(QTMIR_SURFACES) << "MirBufferSGTexture: bind() called but there's no mir buffer to bind to"; |
| 164 | + glBindTexture(GL_TEXTURE_2D, 0); |
| 165 | + } |
| 166 | } |
| 167 | |
| 168 | === modified file 'src/modules/Unity/Application/mirbuffersgtexture.h' |
| 169 | --- src/modules/Unity/Application/mirbuffersgtexture.h 2015-08-31 09:51:28 +0000 |
| 170 | +++ src/modules/Unity/Application/mirbuffersgtexture.h 2015-10-16 17:43:47 +0000 |
| 171 | @@ -34,6 +34,7 @@ |
| 172 | |
| 173 | void setBuffer(std::shared_ptr<mir::graphics::Buffer> buffer); |
| 174 | void freeBuffer(); |
| 175 | + bool hasBuffer() const; |
| 176 | |
| 177 | int textureId() const override; |
| 178 | QSize textureSize() const override; |
| 179 | |
| 180 | === modified file 'src/modules/Unity/Application/mirsurface.cpp' |
| 181 | --- src/modules/Unity/Application/mirsurface.cpp 2015-09-18 16:33:06 +0000 |
| 182 | +++ src/modules/Unity/Application/mirsurface.cpp 2015-10-16 17:43:47 +0000 |
| 183 | @@ -21,6 +21,7 @@ |
| 184 | |
| 185 | // Mir |
| 186 | #include <mir/geometry/rectangle.h> |
| 187 | +#include <mir/graphics/buffer.h> |
| 188 | #include <mir/events/event_builders.h> |
| 189 | #include <mir/shell/shell.h> |
| 190 | #include <mir_toolkit/event.h> |
| 191 | @@ -309,45 +310,64 @@ |
| 192 | } |
| 193 | } |
| 194 | |
| 195 | -void MirSurface::updateTexture() |
| 196 | +bool MirSurface::updateTexture() |
| 197 | { |
| 198 | QMutexLocker locker(&m_mutex); |
| 199 | - |
| 200 | - if (m_textureUpdated) { |
| 201 | - return; |
| 202 | - } |
| 203 | - |
| 204 | Q_ASSERT(!m_texture.isNull()); |
| 205 | + |
| 206 | MirBufferSGTexture *texture = static_cast<MirBufferSGTexture*>(m_texture.data()); |
| 207 | |
| 208 | - const void* const userId = (void*)123; |
| 209 | - auto renderables = m_surface->generate_renderables(userId); |
| 210 | + if (m_textureUpdated) { |
| 211 | + return texture->hasBuffer(); |
| 212 | + } |
| 213 | |
| 214 | - if (m_surface->buffers_ready_for_compositor(userId) > 0 && renderables.size() > 0) { |
| 215 | + if (m_pendingBuffer) { |
| 216 | // Avoid holding two buffers for the compositor at the same time. Thus free the current |
| 217 | // before acquiring the next |
| 218 | texture->freeBuffer(); |
| 219 | - texture->setBuffer(renderables[0]->buffer()); |
| 220 | + texture->setBuffer(m_pendingBuffer); |
| 221 | + m_pendingBuffer.reset(); |
| 222 | ++m_currentFrameNumber; |
| 223 | - |
| 224 | - if (texture->textureSize() != m_size) { |
| 225 | - m_size = texture->textureSize(); |
| 226 | - QMetaObject::invokeMethod(this, "emitSizeChanged", Qt::QueuedConnection); |
| 227 | + } |
| 228 | + |
| 229 | + m_textureUpdated = true; |
| 230 | + |
| 231 | + return texture->hasBuffer(); |
| 232 | +} |
| 233 | + |
| 234 | +void MirSurface::consumeBuffer() |
| 235 | +{ |
| 236 | + QMutexLocker locker(&m_mutex); |
| 237 | + const void* const userId = (void*)123; |
| 238 | + auto renderables = m_surface->generate_renderables(userId); |
| 239 | + |
| 240 | + if (renderables.size() > 0 && m_surface->buffers_ready_for_compositor(userId) > 0) { |
| 241 | + m_pendingBuffer = renderables[0]->buffer(); |
| 242 | + |
| 243 | + QSize size(m_pendingBuffer->size().width.as_int(), |
| 244 | + m_pendingBuffer->size().height.as_int()); |
| 245 | + if (size != m_size) { |
| 246 | + m_size = size; |
| 247 | + Q_EMIT sizeChanged(m_size); |
| 248 | } |
| 249 | } |
| 250 | |
| 251 | if (m_surface->buffers_ready_for_compositor(userId) > 0) { |
| 252 | // restart the frame dropper to give MirSurfaceItems enough time to render the next frame. |
| 253 | - // queued since the timer lives in a different thread |
| 254 | - QMetaObject::invokeMethod(&m_frameDropperTimer, "start", Qt::QueuedConnection); |
| 255 | + QMetaObject::invokeMethod(&m_frameDropperTimer, "start", Qt::AutoConnection); |
| 256 | } |
| 257 | - |
| 258 | - m_textureUpdated = true; |
| 259 | } |
| 260 | |
| 261 | void MirSurface::onCompositorSwappedBuffers() |
| 262 | { |
| 263 | + QMutexLocker locker(&m_mutex); |
| 264 | m_textureUpdated = false; |
| 265 | + |
| 266 | + if (m_texture && m_pendingBuffer) { |
| 267 | + // No need to hold onto this buffer as it won't be used on the next frame. |
| 268 | + MirBufferSGTexture *texture = static_cast<MirBufferSGTexture*>(m_texture.data()); |
| 269 | + texture->freeBuffer(); |
| 270 | + } |
| 271 | } |
| 272 | |
| 273 | bool MirSurface::numBuffersReadyForCompositor() |
| 274 | |
| 275 | === modified file 'src/modules/Unity/Application/mirsurface.h' |
| 276 | --- src/modules/Unity/Application/mirsurface.h 2015-09-25 17:30:26 +0000 |
| 277 | +++ src/modules/Unity/Application/mirsurface.h 2015-10-16 17:43:47 +0000 |
| 278 | @@ -34,7 +34,10 @@ |
| 279 | #include <mir/scene/surface.h> |
| 280 | #include <mir_toolkit/common.h> |
| 281 | |
| 282 | -namespace mir { namespace shell { class Shell; }} |
| 283 | +namespace mir { |
| 284 | + namespace shell { class Shell; } |
| 285 | + namespace graphics { class Buffer; } |
| 286 | +} |
| 287 | |
| 288 | class SurfaceObserver; |
| 289 | |
| 290 | @@ -84,10 +87,12 @@ |
| 291 | void incrementViewCount() override; |
| 292 | void decrementViewCount() override; |
| 293 | |
| 294 | + void consumeBuffer() override; |
| 295 | + |
| 296 | // methods called from the rendering (scene graph) thread: |
| 297 | QSharedPointer<QSGTexture> texture() override; |
| 298 | QSGTexture *weakTexture() const override { return m_texture.data(); } |
| 299 | - void updateTexture() override; |
| 300 | + bool updateTexture() override; |
| 301 | unsigned int currentFrameNumber() const override; |
| 302 | bool numBuffersReadyForCompositor() override; |
| 303 | // end of methods called from the rendering (scene graph) thread |
| 304 | @@ -112,7 +117,9 @@ |
| 305 | QString appId() const override; |
| 306 | |
| 307 | public Q_SLOTS: |
| 308 | + // methods called from the rendering (scene graph) thread: |
| 309 | void onCompositorSwappedBuffers() override; |
| 310 | + // end of methods called from the rendering (scene graph) thread |
| 311 | |
| 312 | private Q_SLOTS: |
| 313 | void dropPendingBuffer(); |
| 314 | @@ -148,6 +155,8 @@ |
| 315 | std::shared_ptr<SurfaceObserver> m_surfaceObserver; |
| 316 | |
| 317 | QSize m_size; |
| 318 | + |
| 319 | + std::shared_ptr<mir::graphics::Buffer> m_pendingBuffer; |
| 320 | }; |
| 321 | |
| 322 | } // namespace qtmir |
| 323 | |
| 324 | === modified file 'src/modules/Unity/Application/mirsurfaceinterface.h' |
| 325 | --- src/modules/Unity/Application/mirsurfaceinterface.h 2015-09-25 17:30:26 +0000 |
| 326 | +++ src/modules/Unity/Application/mirsurfaceinterface.h 2015-10-16 17:43:47 +0000 |
| 327 | @@ -51,10 +51,12 @@ |
| 328 | virtual void incrementViewCount() = 0; |
| 329 | virtual void decrementViewCount() = 0; |
| 330 | |
| 331 | + virtual void consumeBuffer() = 0; |
| 332 | + |
| 333 | // methods called from the rendering (scene graph) thread: |
| 334 | virtual QSharedPointer<QSGTexture> texture() = 0; |
| 335 | virtual QSGTexture *weakTexture() const = 0; |
| 336 | - virtual void updateTexture() = 0; |
| 337 | + virtual bool updateTexture() = 0; |
| 338 | virtual unsigned int currentFrameNumber() const = 0; |
| 339 | virtual bool numBuffersReadyForCompositor() = 0; |
| 340 | // end of methods called from the rendering (scene graph) thread |
| 341 | @@ -79,7 +81,9 @@ |
| 342 | virtual QString appId() const = 0; |
| 343 | |
| 344 | public Q_SLOTS: |
| 345 | + // methods called from the rendering (scene graph) thread: |
| 346 | virtual void onCompositorSwappedBuffers() = 0; |
| 347 | + // end of methods called from the rendering (scene graph) thread |
| 348 | |
| 349 | Q_SIGNALS: |
| 350 | void firstFrameDrawn(); |
| 351 | |
| 352 | === modified file 'src/modules/Unity/Application/mirsurfaceitem.cpp' |
| 353 | --- src/modules/Unity/Application/mirsurfaceitem.cpp 2015-09-28 14:24:48 +0000 |
| 354 | +++ src/modules/Unity/Application/mirsurfaceitem.cpp 2015-10-16 17:43:47 +0000 |
| 355 | @@ -89,6 +89,7 @@ |
| 356 | , m_surfaceHeight(0) |
| 357 | , m_orientationAngle(nullptr) |
| 358 | , m_consumesInput(false) |
| 359 | + , m_fillMode(Stretch) |
| 360 | { |
| 361 | qCDebug(QTMIR_SURFACES) << "MirSurfaceItem::MirSurfaceItem"; |
| 362 | |
| 363 | @@ -216,17 +217,15 @@ |
| 364 | |
| 365 | ensureTextureProvider(); |
| 366 | |
| 367 | - m_surface->updateTexture(); |
| 368 | + if (!m_textureProvider->texture() || !m_surface->updateTexture()) { |
| 369 | + delete oldNode; |
| 370 | + return 0; |
| 371 | + } |
| 372 | |
| 373 | if (m_surface->numBuffersReadyForCompositor() > 0) { |
| 374 | QTimer::singleShot(0, this, SLOT(update())); |
| 375 | } |
| 376 | |
| 377 | - if (!m_textureProvider->texture()) { |
| 378 | - delete oldNode; |
| 379 | - return 0; |
| 380 | - } |
| 381 | - |
| 382 | m_textureProvider->smooth = smooth(); |
| 383 | |
| 384 | QSGDefaultImageNode *node = static_cast<QSGDefaultImageNode*>(oldNode); |
| 385 | @@ -237,15 +236,31 @@ |
| 386 | node->setMipmapFiltering(QSGTexture::None); |
| 387 | node->setHorizontalWrapMode(QSGTexture::ClampToEdge); |
| 388 | node->setVerticalWrapMode(QSGTexture::ClampToEdge); |
| 389 | - node->setSubSourceRect(QRectF(0, 0, 1, 1)); |
| 390 | } else { |
| 391 | if (!m_lastFrameNumberRendered || (*m_lastFrameNumberRendered != m_surface->currentFrameNumber())) { |
| 392 | node->markDirty(QSGNode::DirtyMaterial); |
| 393 | } |
| 394 | } |
| 395 | |
| 396 | - node->setTargetRect(QRectF(0, 0, width(), height())); |
| 397 | - node->setInnerTargetRect(QRectF(0, 0, width(), height())); |
| 398 | + if (m_fillMode == PadOrCrop) { |
| 399 | + const QSize &textureSize = m_textureProvider->texture()->textureSize(); |
| 400 | + |
| 401 | + QRectF targetRect; |
| 402 | + targetRect.setWidth(qMin(width(), static_cast<qreal>(textureSize.width()))); |
| 403 | + targetRect.setHeight(qMin(height(), static_cast<qreal>(textureSize.height()))); |
| 404 | + |
| 405 | + qreal u = targetRect.width() / textureSize.width(); |
| 406 | + qreal v = targetRect.height() / textureSize.height(); |
| 407 | + node->setSubSourceRect(QRectF(0, 0, u, v)); |
| 408 | + |
| 409 | + node->setTargetRect(targetRect); |
| 410 | + node->setInnerTargetRect(targetRect); |
| 411 | + } else { |
| 412 | + // Stretch |
| 413 | + node->setSubSourceRect(QRectF(0, 0, 1, 1)); |
| 414 | + node->setTargetRect(QRectF(0, 0, width(), height())); |
| 415 | + node->setInnerTargetRect(QRectF(0, 0, width(), height())); |
| 416 | + } |
| 417 | |
| 418 | node->setFiltering(smooth() ? QSGTexture::Linear : QSGTexture::Nearest); |
| 419 | node->setAntialiasing(antialiasing()); |
| 420 | @@ -609,7 +624,7 @@ |
| 421 | |
| 422 | // When a new mir frame gets posted we notify the QML engine that this item needs redrawing, |
| 423 | // schedules call to updatePaintNode() from the rendering thread |
| 424 | - connect(m_surface, &MirSurfaceInterface::framesPosted, this, &QQuickItem::update); |
| 425 | + connect(m_surface, &MirSurfaceInterface::framesPosted, this, &MirSurfaceItem::onSurfacePostedFrames); |
| 426 | |
| 427 | connect(m_surface, &MirSurfaceInterface::stateChanged, this, &MirSurfaceItem::surfaceStateChanged); |
| 428 | connect(m_surface, &MirSurfaceInterface::liveChanged, this, &MirSurfaceItem::liveChanged); |
| 429 | @@ -690,6 +705,33 @@ |
| 430 | } |
| 431 | } |
| 432 | |
| 433 | +MirSurfaceItem::FillMode MirSurfaceItem::fillMode() const |
| 434 | +{ |
| 435 | + return m_fillMode; |
| 436 | +} |
| 437 | + |
| 438 | +void MirSurfaceItem::setFillMode(FillMode value) |
| 439 | +{ |
| 440 | + if (m_fillMode != value) { |
| 441 | + m_fillMode = value; |
| 442 | + Q_EMIT fillModeChanged(m_fillMode); |
| 443 | + } |
| 444 | +} |
| 445 | + |
| 446 | +void MirSurfaceItem::onSurfacePostedFrames() |
| 447 | +{ |
| 448 | + polish(); |
| 449 | + update(); |
| 450 | +} |
| 451 | + |
| 452 | +void MirSurfaceItem::updatePolish() |
| 453 | +{ |
| 454 | + if (!m_surface || !m_surface->live()) { |
| 455 | + return; |
| 456 | + } |
| 457 | + m_surface->consumeBuffer(); |
| 458 | +} |
| 459 | + |
| 460 | } // namespace qtmir |
| 461 | |
| 462 | #include "mirsurfaceitem.moc" |
| 463 | |
| 464 | === modified file 'src/modules/Unity/Application/mirsurfaceitem.h' |
| 465 | --- src/modules/Unity/Application/mirsurfaceitem.h 2015-09-18 20:11:50 +0000 |
| 466 | +++ src/modules/Unity/Application/mirsurfaceitem.h 2015-10-16 17:43:47 +0000 |
| 467 | @@ -68,6 +68,9 @@ |
| 468 | int surfaceHeight() const override; |
| 469 | void setSurfaceHeight(int value) override; |
| 470 | |
| 471 | + FillMode fillMode() const override; |
| 472 | + void setFillMode(FillMode value) override; |
| 473 | + |
| 474 | //////// |
| 475 | // QQuickItem |
| 476 | |
| 477 | @@ -107,6 +110,8 @@ |
| 478 | |
| 479 | void releaseResources() override; |
| 480 | |
| 481 | + void updatePolish() override; |
| 482 | + |
| 483 | private Q_SLOTS: |
| 484 | void scheduleMirSurfaceSizeUpdate(); |
| 485 | void updateMirSurfaceSize(); |
| 486 | @@ -115,6 +120,8 @@ |
| 487 | |
| 488 | void onActualSurfaceSizeChanged(const QSize &size); |
| 489 | |
| 490 | + void onSurfacePostedFrames(); |
| 491 | + |
| 492 | private: |
| 493 | void ensureTextureProvider(); |
| 494 | |
| 495 | @@ -163,6 +170,8 @@ |
| 496 | Mir::OrientationAngle *m_orientationAngle; |
| 497 | |
| 498 | bool m_consumesInput; |
| 499 | + |
| 500 | + FillMode m_fillMode; |
| 501 | }; |
| 502 | |
| 503 | } // namespace qtmir |
| 504 | |
| 505 | === modified file 'src/modules/Unity/CMakeLists.txt' |
| 506 | --- src/modules/Unity/CMakeLists.txt 2014-09-22 18:06:58 +0000 |
| 507 | +++ src/modules/Unity/CMakeLists.txt 2015-10-16 17:43:47 +0000 |
| 508 | @@ -1,1 +1,2 @@ |
| 509 | add_subdirectory(Application) |
| 510 | +add_subdirectory(Screens) |
| 511 | |
| 512 | === added directory 'src/modules/Unity/Screens' |
| 513 | === added file 'src/modules/Unity/Screens/CMakeLists.txt' |
| 514 | --- src/modules/Unity/Screens/CMakeLists.txt 1970-01-01 00:00:00 +0000 |
| 515 | +++ src/modules/Unity/Screens/CMakeLists.txt 2015-10-16 17:43:47 +0000 |
| 516 | @@ -0,0 +1,24 @@ |
| 517 | +include_directories( |
| 518 | + ${CMAKE_SOURCE_DIR}/src/platforms/mirserver |
| 519 | + ${Qt5Gui_PRIVATE_INCLUDE_DIRS} |
| 520 | + ${MIRSERVER_INCLUDE_DIRS} |
| 521 | + ) |
| 522 | + |
| 523 | +set(SCREENSPLUGIN_SRC |
| 524 | + plugin.cpp |
| 525 | + screens.cpp |
| 526 | + ) |
| 527 | + |
| 528 | +add_library(unityscreensplugin SHARED |
| 529 | + ${SCREENSPLUGIN_SRC} |
| 530 | +) |
| 531 | + |
| 532 | +target_link_libraries( |
| 533 | + unityscreensplugin |
| 534 | + |
| 535 | + Qt5::Gui |
| 536 | + Qt5::Qml |
| 537 | +) |
| 538 | + |
| 539 | +# install |
| 540 | +add_qml_plugin(Unity.Screens 0.1 Unity/Screens TARGETS unityscreensplugin) |
| 541 | |
| 542 | === added file 'src/modules/Unity/Screens/plugin.cpp' |
| 543 | --- src/modules/Unity/Screens/plugin.cpp 1970-01-01 00:00:00 +0000 |
| 544 | +++ src/modules/Unity/Screens/plugin.cpp 2015-10-16 17:43:47 +0000 |
| 545 | @@ -0,0 +1,41 @@ |
| 546 | +/* |
| 547 | + * Copyright (C) 2015 Canonical, Ltd. |
| 548 | + * |
| 549 | + * This program is free software: you can redistribute it and/or modify it under |
| 550 | + * the terms of the GNU Lesser General Public License version 3, as published by |
| 551 | + * the Free Software Foundation. |
| 552 | + * |
| 553 | + * This program is distributed in the hope that it will be useful, but WITHOUT |
| 554 | + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
| 555 | + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 556 | + * Lesser General Public License for more details. |
| 557 | + * |
| 558 | + * You should have received a copy of the GNU Lesser General Public License |
| 559 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 560 | + */ |
| 561 | + |
| 562 | +// Qt |
| 563 | +#include <QQmlExtensionPlugin> |
| 564 | +#include <QtQml/qqml.h> |
| 565 | +#include <QScreen> |
| 566 | + |
| 567 | +// local |
| 568 | +#include "screens.h" |
| 569 | + |
| 570 | +using namespace qtmir; |
| 571 | + |
| 572 | +class UnityScreensPlugin : public QQmlExtensionPlugin { |
| 573 | + Q_OBJECT |
| 574 | + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface/1.0") |
| 575 | + |
| 576 | + virtual void registerTypes(const char* uri) |
| 577 | + { |
| 578 | + Q_ASSERT(QLatin1String(uri) == QLatin1String("Unity.Screens")); |
| 579 | + |
| 580 | + qRegisterMetaType<QScreen*>("QScreen*"); |
| 581 | + |
| 582 | + qmlRegisterType<qtmir::Screens>(uri, 0, 1, "Screens"); |
| 583 | + } |
| 584 | +}; |
| 585 | + |
| 586 | +#include "plugin.moc" |
| 587 | |
| 588 | === added file 'src/modules/Unity/Screens/qmldir' |
| 589 | --- src/modules/Unity/Screens/qmldir 1970-01-01 00:00:00 +0000 |
| 590 | +++ src/modules/Unity/Screens/qmldir 2015-10-16 17:43:47 +0000 |
| 591 | @@ -0,0 +1,2 @@ |
| 592 | +module Unity.Screens |
| 593 | +plugin unityscreensplugin |
| 594 | |
| 595 | === added file 'src/modules/Unity/Screens/screens.cpp' |
| 596 | --- src/modules/Unity/Screens/screens.cpp 1970-01-01 00:00:00 +0000 |
| 597 | +++ src/modules/Unity/Screens/screens.cpp 2015-10-16 17:43:47 +0000 |
| 598 | @@ -0,0 +1,107 @@ |
| 599 | +/* |
| 600 | + * Copyright (C) 2015 Canonical, Ltd. |
| 601 | + * |
| 602 | + * This program is free software: you can redistribute it and/or modify it under |
| 603 | + * the terms of the GNU Lesser General Public License version 3, as published by |
| 604 | + * the Free Software Foundation. |
| 605 | + * |
| 606 | + * This program is distributed in the hope that it will be useful, but WITHOUT |
| 607 | + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
| 608 | + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 609 | + * Lesser General Public License for more details. |
| 610 | + * |
| 611 | + * You should have received a copy of the GNU Lesser General Public License |
| 612 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 613 | + */ |
| 614 | + |
| 615 | +#include "screens.h" |
| 616 | + |
| 617 | +// mirserver |
| 618 | +#include "screen.h" |
| 619 | + |
| 620 | +// Qt |
| 621 | +#include <QGuiApplication> |
| 622 | +#include <QScreen> |
| 623 | + |
| 624 | +Q_DECLARE_METATYPE(QScreen*) |
| 625 | + |
| 626 | +namespace qtmir { |
| 627 | + |
| 628 | +Screens::Screens(QObject *parent) : |
| 629 | + QAbstractListModel(parent) |
| 630 | +{ |
| 631 | + auto app = static_cast<QGuiApplication *>(QGuiApplication::instance()); |
| 632 | + if (!app) { |
| 633 | + return; |
| 634 | + } |
| 635 | + connect(app, &QGuiApplication::screenAdded, this, &Screens::onScreenAdded); |
| 636 | + connect(app, &QGuiApplication::screenRemoved, this, &Screens::onScreenRemoved); |
| 637 | + |
| 638 | + m_screenList = QGuiApplication::screens(); |
| 639 | +} |
| 640 | + |
| 641 | +QHash<int, QByteArray> Screens::roleNames() const |
| 642 | +{ |
| 643 | + QHash<int, QByteArray> roles; |
| 644 | + roles[ScreenRole] = "screen"; |
| 645 | + roles[OutputTypeRole] = "outputType"; |
| 646 | + return roles; |
| 647 | +} |
| 648 | + |
| 649 | +QVariant Screens::data(const QModelIndex &index, int role) const |
| 650 | +{ |
| 651 | + if (!index.isValid() || index.row() >= m_screenList.size()) { |
| 652 | + return QVariant(); |
| 653 | + } |
| 654 | + |
| 655 | + switch(role) { |
| 656 | + case ScreenRole: |
| 657 | + return QVariant::fromValue(m_screenList.at(index.row())); |
| 658 | + case OutputTypeRole: |
| 659 | + auto screen = static_cast<Screen*>(m_screenList.at(index.row())->handle()); |
| 660 | + if (screen) { |
| 661 | + return QVariant(static_cast<OutputTypes>(screen->outputType())); //FIXME: cheeky |
| 662 | + } else |
| 663 | + return OutputTypes::Unknown; |
| 664 | + } |
| 665 | + |
| 666 | + return QVariant(); |
| 667 | +} |
| 668 | + |
| 669 | +int Screens::rowCount(const QModelIndex &) const |
| 670 | +{ |
| 671 | + return count(); |
| 672 | +} |
| 673 | + |
| 674 | +int Screens::count() const |
| 675 | +{ |
| 676 | + return m_screenList.size(); |
| 677 | +} |
| 678 | + |
| 679 | +void Screens::onScreenAdded(QScreen *screen) |
| 680 | +{ |
| 681 | + if (m_screenList.contains(screen)) |
| 682 | + return; |
| 683 | + |
| 684 | + beginInsertRows(QModelIndex(), count(), count()); |
| 685 | + m_screenList.push_back(screen); |
| 686 | + endInsertRows(); |
| 687 | + Q_EMIT screenAdded(screen); |
| 688 | + Q_EMIT countChanged(); |
| 689 | +} |
| 690 | + |
| 691 | +void Screens::onScreenRemoved(QScreen *screen) |
| 692 | +{ |
| 693 | + int index = m_screenList.indexOf(screen); |
| 694 | + if (index < 0) |
| 695 | + return; |
| 696 | + |
| 697 | + beginRemoveRows(QModelIndex(), index, index); |
| 698 | + m_screenList.removeAt(index); |
| 699 | + endRemoveRows(); |
| 700 | + Q_EMIT screenRemoved(screen); |
| 701 | + Q_EMIT countChanged(); |
| 702 | +} |
| 703 | + |
| 704 | + |
| 705 | +} // namespace qtmir |
| 706 | |
| 707 | === added file 'src/modules/Unity/Screens/screens.h' |
| 708 | --- src/modules/Unity/Screens/screens.h 1970-01-01 00:00:00 +0000 |
| 709 | +++ src/modules/Unity/Screens/screens.h 2015-10-16 17:43:47 +0000 |
| 710 | @@ -0,0 +1,82 @@ |
| 711 | +/* |
| 712 | + * Copyright (C) 2015 Canonical, Ltd. |
| 713 | + * |
| 714 | + * This program is free software: you can redistribute it and/or modify it under |
| 715 | + * the terms of the GNU Lesser General Public License version 3, as published by |
| 716 | + * the Free Software Foundation. |
| 717 | + * |
| 718 | + * This program is distributed in the hope that it will be useful, but WITHOUT |
| 719 | + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
| 720 | + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 721 | + * Lesser General Public License for more details. |
| 722 | + * |
| 723 | + * You should have received a copy of the GNU Lesser General Public License |
| 724 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 725 | + */ |
| 726 | + |
| 727 | +#ifndef SCREENS_H |
| 728 | +#define SCREENS_H |
| 729 | + |
| 730 | +#include <QAbstractListModel> |
| 731 | + |
| 732 | +class QScreen; |
| 733 | + |
| 734 | +namespace qtmir { |
| 735 | + |
| 736 | +class Screens : public QAbstractListModel |
| 737 | +{ |
| 738 | + Q_OBJECT |
| 739 | + Q_ENUMS(OutputTypes) |
| 740 | + |
| 741 | + Q_PROPERTY(int count READ count NOTIFY countChanged) |
| 742 | + |
| 743 | +public: |
| 744 | + enum ItemRoles { |
| 745 | + ScreenRole = Qt::UserRole + 1, |
| 746 | + OutputTypeRole |
| 747 | + }; |
| 748 | + |
| 749 | + enum OutputTypes { |
| 750 | + Unknown, |
| 751 | + VGA, |
| 752 | + DVII, |
| 753 | + DVID, |
| 754 | + DVIA, |
| 755 | + Composite, |
| 756 | + SVideo, |
| 757 | + LVDS, |
| 758 | + Component, |
| 759 | + NinePinDIN, |
| 760 | + DisplayPort, |
| 761 | + HDMIA, |
| 762 | + HDMIB, |
| 763 | + TV, |
| 764 | + EDP |
| 765 | + }; |
| 766 | + |
| 767 | + explicit Screens(QObject *parent = 0); |
| 768 | + virtual ~Screens() noexcept = default; |
| 769 | + |
| 770 | + /* QAbstractItemModel */ |
| 771 | + QHash<int, QByteArray> roleNames() const override; |
| 772 | + QVariant data(const QModelIndex &index, int role = ScreenRole) const override; |
| 773 | + int rowCount(const QModelIndex &parent = QModelIndex()) const override; |
| 774 | + |
| 775 | + int count() const; |
| 776 | + |
| 777 | +Q_SIGNALS: |
| 778 | + void countChanged(); |
| 779 | + void screenAdded(QScreen *screen); |
| 780 | + void screenRemoved(QScreen *screen); |
| 781 | + |
| 782 | +private Q_SLOTS: |
| 783 | + void onScreenAdded(QScreen *screen); |
| 784 | + void onScreenRemoved(QScreen *screen); |
| 785 | + |
| 786 | +private: |
| 787 | + QList<QScreen *> m_screenList; |
| 788 | +}; |
| 789 | + |
| 790 | +} // namespace qtmir |
| 791 | + |
| 792 | +#endif // SCREENS_H |
| 793 | |
| 794 | === modified file 'src/platforms/mirserver/CMakeLists.txt' |
| 795 | --- src/platforms/mirserver/CMakeLists.txt 2015-10-16 17:43:47 +0000 |
| 796 | +++ src/platforms/mirserver/CMakeLists.txt 2015-10-16 17:43:47 +0000 |
| 797 | @@ -31,6 +31,7 @@ |
| 798 | ${QT5PLATFORM_SUPPORT_INCLUDE_DIRS} |
| 799 | ${Qt5Gui_PRIVATE_INCLUDE_DIRS} |
| 800 | ${QT5_PLATFORMSUPPORT_INCLUDE_DIRS} |
| 801 | + ${Qt5Quick_PRIVATE_INCLUDE_DIRS} |
| 802 | |
| 803 | ${APPLICATION_API_INCLUDE_DIRS} |
| 804 | ) |
| 805 | @@ -55,16 +56,18 @@ |
| 806 | promptsessionlistener.cpp |
| 807 | mirserver.cpp |
| 808 | mirserverstatuslistener.cpp |
| 809 | - display.cpp |
| 810 | screen.cpp |
| 811 | - displaywindow.cpp |
| 812 | + screencontroller.cpp |
| 813 | + screenwindow.cpp |
| 814 | mirserverintegration.cpp |
| 815 | miropenglcontext.cpp |
| 816 | nativeinterface.cpp |
| 817 | + offscreensurface.cpp |
| 818 | qtcompositor.cpp |
| 819 | services.cpp |
| 820 | ubuntutheme.cpp |
| 821 | clipboard.cpp |
| 822 | + tileddisplayconfigurationpolicy.cpp |
| 823 | tracepoints.c |
| 824 | # We need to run moc on these headers |
| 825 | ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/Mir.h |
| 826 | |
| 827 | === removed file 'src/platforms/mirserver/display.cpp' |
| 828 | --- src/platforms/mirserver/display.cpp 2015-08-11 12:08:32 +0000 |
| 829 | +++ src/platforms/mirserver/display.cpp 1970-01-01 00:00:00 +0000 |
| 830 | @@ -1,44 +0,0 @@ |
| 831 | -/* |
| 832 | - * Copyright (C) 2013-2015 Canonical, Ltd. |
| 833 | - * |
| 834 | - * This program is free software: you can redistribute it and/or modify it under |
| 835 | - * the terms of the GNU Lesser General Public License version 3, as published by |
| 836 | - * the Free Software Foundation. |
| 837 | - * |
| 838 | - * This program is distributed in the hope that it will be useful, but WITHOUT |
| 839 | - * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
| 840 | - * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 841 | - * Lesser General Public License for more details. |
| 842 | - * |
| 843 | - * You should have received a copy of the GNU Lesser General Public License |
| 844 | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 845 | - */ |
| 846 | - |
| 847 | -#include "display.h" |
| 848 | - |
| 849 | -#include "screen.h" |
| 850 | -#include "mirserver.h" |
| 851 | - |
| 852 | -#include <mir/graphics/display.h> |
| 853 | -#include <mir/graphics/display_configuration.h> |
| 854 | - |
| 855 | -namespace mg = mir::graphics; |
| 856 | - |
| 857 | -// TODO: Listen for display changes and update the list accordingly |
| 858 | - |
| 859 | -Display::Display(const std::shared_ptr<mir::graphics::DisplayConfiguration> &displayConfig) |
| 860 | -{ |
| 861 | - displayConfig->for_each_output([this](mg::DisplayConfigurationOutput const& output) { |
| 862 | - if (output.used) { |
| 863 | - auto screen = new Screen(output); |
| 864 | - m_screens.push_back(screen); |
| 865 | - } |
| 866 | - }); |
| 867 | -} |
| 868 | - |
| 869 | -Display::~Display() |
| 870 | -{ |
| 871 | - for (auto screen : m_screens) |
| 872 | - delete screen; |
| 873 | - m_screens.clear(); |
| 874 | -} |
| 875 | |
| 876 | === removed file 'src/platforms/mirserver/display.h' |
| 877 | --- src/platforms/mirserver/display.h 2015-08-11 12:08:32 +0000 |
| 878 | +++ src/platforms/mirserver/display.h 1970-01-01 00:00:00 +0000 |
| 879 | @@ -1,37 +0,0 @@ |
| 880 | -/* |
| 881 | - * Copyright (C) 2013-2015 Canonical, Ltd. |
| 882 | - * |
| 883 | - * This program is free software: you can redistribute it and/or modify it under |
| 884 | - * the terms of the GNU Lesser General Public License version 3, as published by |
| 885 | - * the Free Software Foundation. |
| 886 | - * |
| 887 | - * This program is distributed in the hope that it will be useful, but WITHOUT |
| 888 | - * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
| 889 | - * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 890 | - * Lesser General Public License for more details. |
| 891 | - * |
| 892 | - * You should have received a copy of the GNU Lesser General Public License |
| 893 | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 894 | - */ |
| 895 | - |
| 896 | -#ifndef DISPLAY_H |
| 897 | -#define DISPLAY_H |
| 898 | - |
| 899 | -#include <qpa/qplatformscreen.h> |
| 900 | -#include <memory> |
| 901 | - |
| 902 | -namespace mir { namespace graphics { class DisplayConfiguration; }} |
| 903 | - |
| 904 | -class Display |
| 905 | -{ |
| 906 | -public: |
| 907 | - Display(const std::shared_ptr<mir::graphics::DisplayConfiguration> &displayConfig); |
| 908 | - virtual ~Display(); |
| 909 | - |
| 910 | - QList<QPlatformScreen *> screens() const { return m_screens; } |
| 911 | - |
| 912 | -private: |
| 913 | - QList<QPlatformScreen *> m_screens; |
| 914 | -}; |
| 915 | - |
| 916 | -#endif // DISPLAY_H |
| 917 | |
| 918 | === modified file 'src/platforms/mirserver/logging.h' |
| 919 | --- src/platforms/mirserver/logging.h 2014-10-01 18:42:26 +0000 |
| 920 | +++ src/platforms/mirserver/logging.h 2015-10-16 17:43:47 +0000 |
| 921 | @@ -25,5 +25,6 @@ |
| 922 | Q_DECLARE_LOGGING_CATEGORY(QTMIR_SENSOR_MESSAGES) |
| 923 | Q_DECLARE_LOGGING_CATEGORY(QTMIR_MIR_INPUT) |
| 924 | Q_DECLARE_LOGGING_CATEGORY(QTMIR_CLIPBOARD) |
| 925 | +Q_DECLARE_LOGGING_CATEGORY(QTMIR_SCREENS) |
| 926 | |
| 927 | #endif // UBUNTU_APPLICATION_PLUGIN_LOGGING_H |
| 928 | |
| 929 | === modified file 'src/platforms/mirserver/miropenglcontext.cpp' |
| 930 | --- src/platforms/mirserver/miropenglcontext.cpp 2015-08-11 12:08:32 +0000 |
| 931 | +++ src/platforms/mirserver/miropenglcontext.cpp 2015-10-16 17:43:47 +0000 |
| 932 | @@ -16,12 +16,14 @@ |
| 933 | |
| 934 | #include "miropenglcontext.h" |
| 935 | |
| 936 | -#include "displaywindow.h" |
| 937 | +#include "offscreensurface.h" |
| 938 | +#include "mirglconfig.h" |
| 939 | #include "mirserver.h" |
| 940 | -#include "mirglconfig.h" |
| 941 | +#include "screenwindow.h" |
| 942 | |
| 943 | #include <QDebug> |
| 944 | |
| 945 | +#include <QOpenGLFramebufferObject> |
| 946 | #include <QSurfaceFormat> |
| 947 | #include <QtPlatformSupport/private/qeglconvenience_p.h> |
| 948 | |
| 949 | @@ -38,7 +40,7 @@ |
| 950 | : m_logger(new QOpenGLDebugLogger(this)) |
| 951 | #endif |
| 952 | { |
| 953 | - std::shared_ptr<mir::graphics::Display> display = server->the_display(); |
| 954 | + auto display = server->the_display(); |
| 955 | |
| 956 | // create a temporary GL context to fetch the EGL display and config, so Qt can determine the surface format |
| 957 | std::unique_ptr<mir::graphics::GLContext> mirContext = display->create_gl_context(); |
| 958 | @@ -106,17 +108,30 @@ |
| 959 | |
| 960 | void MirOpenGLContext::swapBuffers(QPlatformSurface *surface) |
| 961 | { |
| 962 | - // ultimately calls Mir's DisplayBuffer::post_update() |
| 963 | - DisplayWindow *displayBuffer = static_cast<DisplayWindow*>(surface); |
| 964 | - displayBuffer->swapBuffers(); //blocks for vsync |
| 965 | + if (surface->surface()->surfaceClass() == QSurface::Offscreen) { |
| 966 | + // NOOP |
| 967 | + } else { |
| 968 | + // ultimately calls Mir's DisplayBuffer::post_update() |
| 969 | + ScreenWindow *screenWindow = static_cast<ScreenWindow*>(surface); |
| 970 | + screenWindow->swapBuffers(); //blocks for vsync |
| 971 | + } |
| 972 | } |
| 973 | |
| 974 | bool MirOpenGLContext::makeCurrent(QPlatformSurface *surface) |
| 975 | { |
| 976 | + if (surface->surface()->surfaceClass() == QSurface::Offscreen) { |
| 977 | + auto offscreen = static_cast<OffscreenSurface *>(surface); |
| 978 | + if (!offscreen->buffer()) { |
| 979 | + auto buffer = new QOpenGLFramebufferObject(surface->surface()->size()); |
| 980 | + offscreen->setBuffer(buffer); |
| 981 | + } |
| 982 | + return offscreen->buffer()->bind(); |
| 983 | + } |
| 984 | + |
| 985 | // ultimately calls Mir's DisplayBuffer::make_current() |
| 986 | - DisplayWindow *displayBuffer = static_cast<DisplayWindow*>(surface); |
| 987 | - if (displayBuffer) { |
| 988 | - displayBuffer->makeCurrent(); |
| 989 | + ScreenWindow *screenWindow = static_cast<ScreenWindow*>(surface); |
| 990 | + if (screenWindow) { |
| 991 | + screenWindow->makeCurrent(); |
| 992 | |
| 993 | #ifndef QT_NO_DEBUG |
| 994 | if (!m_logger->isLogging() && m_logger->initialize()) { |
| 995 | @@ -133,7 +148,7 @@ |
| 996 | |
| 997 | void MirOpenGLContext::doneCurrent() |
| 998 | { |
| 999 | - // could call Mir's DisplayBuffer::release_current(), but for what DisplayBuffer? |
| 1000 | + // FIXME: create a temporary GL context just to release? Would be better to get existing one. |
| 1001 | } |
| 1002 | |
| 1003 | QFunctionPointer MirOpenGLContext::getProcAddress(const QByteArray &procName) |
| 1004 | |
| 1005 | === modified file 'src/platforms/mirserver/miropenglcontext.h' |
| 1006 | --- src/platforms/mirserver/miropenglcontext.h 2015-08-11 12:08:32 +0000 |
| 1007 | +++ src/platforms/mirserver/miropenglcontext.h 2015-10-16 17:43:47 +0000 |
| 1008 | @@ -23,6 +23,7 @@ |
| 1009 | #include <QOpenGLDebugLogger> |
| 1010 | #endif |
| 1011 | |
| 1012 | + |
| 1013 | class MirServer; |
| 1014 | |
| 1015 | class MirOpenGLContext : public QObject, public QPlatformOpenGLContext |
| 1016 | |
| 1017 | === modified file 'src/platforms/mirserver/mirserver.cpp' |
| 1018 | --- src/platforms/mirserver/mirserver.cpp 2015-10-16 17:43:47 +0000 |
| 1019 | +++ src/platforms/mirserver/mirserver.cpp 2015-10-16 17:43:47 +0000 |
| 1020 | @@ -23,18 +23,25 @@ |
| 1021 | #include "mirglconfig.h" |
| 1022 | #include "mirserverstatuslistener.h" |
| 1023 | #include "promptsessionlistener.h" |
| 1024 | +#include "screencontroller.h" |
| 1025 | #include "sessionlistener.h" |
| 1026 | #include "sessionauthorizer.h" |
| 1027 | #include "qtcompositor.h" |
| 1028 | #include "qteventfeeder.h" |
| 1029 | +#include "tileddisplayconfigurationpolicy.h" |
| 1030 | #include "logging.h" |
| 1031 | |
| 1032 | +// std |
| 1033 | +#include <memory> |
| 1034 | + |
| 1035 | // egl |
| 1036 | +#define MESA_EGL_NO_X11_HEADERS |
| 1037 | #include <EGL/egl.h> |
| 1038 | |
| 1039 | // mir |
| 1040 | #include <mir/graphics/cursor.h> |
| 1041 | |
| 1042 | +namespace mg = mir::graphics; |
| 1043 | namespace mo = mir::options; |
| 1044 | namespace msh = mir::shell; |
| 1045 | namespace ms = mir::scene; |
| 1046 | @@ -48,8 +55,10 @@ |
| 1047 | |
| 1048 | Q_LOGGING_CATEGORY(QTMIR_MIR_MESSAGES, "qtmir.mir") |
| 1049 | |
| 1050 | -MirServer::MirServer(int argc, char const* argv[], QObject* parent) |
| 1051 | +MirServer::MirServer(int argc, char const* argv[], |
| 1052 | + const QSharedPointer<ScreenController> &screenController, QObject* parent) |
| 1053 | : QObject(parent) |
| 1054 | + , m_screenController(screenController) |
| 1055 | { |
| 1056 | set_command_line_handler(&ignore_unparsed_arguments); |
| 1057 | set_command_line(argc, argv); |
| 1058 | @@ -74,9 +83,9 @@ |
| 1059 | return std::make_shared<QtCompositor>(); |
| 1060 | }); |
| 1061 | |
| 1062 | - override_the_input_dispatcher([] |
| 1063 | + override_the_input_dispatcher([&screenController] |
| 1064 | { |
| 1065 | - return std::make_shared<QtEventFeeder>(); |
| 1066 | + return std::make_shared<QtEventFeeder>(screenController); |
| 1067 | }); |
| 1068 | |
| 1069 | override_the_gl_config([] |
| 1070 | @@ -95,20 +104,45 @@ |
| 1071 | return std::make_shared<MirWindowManager>(the_shell_display_layout()); |
| 1072 | }); |
| 1073 | |
| 1074 | - set_terminator([&](int) |
| 1075 | + wrap_display_configuration_policy( |
| 1076 | + [](const std::shared_ptr<mg::DisplayConfigurationPolicy> &wrapped) |
| 1077 | + -> std::shared_ptr<mg::DisplayConfigurationPolicy> |
| 1078 | + { |
| 1079 | + return std::make_shared<TiledDisplayConfigurationPolicy>(wrapped); |
| 1080 | + }); |
| 1081 | + |
| 1082 | + set_terminator([](int) |
| 1083 | { |
| 1084 | qDebug() << "Signal caught by Mir, stopping Mir server.."; |
| 1085 | QCoreApplication::quit(); |
| 1086 | }); |
| 1087 | |
| 1088 | + add_init_callback([this, &screenController] { |
| 1089 | + screenController->init(the_display(), the_compositor()); |
| 1090 | + }); |
| 1091 | + |
| 1092 | apply_settings(); |
| 1093 | |
| 1094 | // We will draw our own cursor. |
| 1095 | - add_init_callback([this](){ the_cursor()->hide(); }); |
| 1096 | + // FIXME: Call override_the_cusor() instead once this method becomes available in a |
| 1097 | + // future version of Mir. |
| 1098 | + add_init_callback([this]() { |
| 1099 | + the_cursor()->hide(); |
| 1100 | + // Hack to work around https://bugs.launchpad.net/mir/+bug/1502200 |
| 1101 | + static_cast<QtCompositor*>(the_compositor().get())->setCursor(the_cursor()); |
| 1102 | + }); |
| 1103 | |
| 1104 | qCDebug(QTMIR_MIR_MESSAGES) << "MirServer created"; |
| 1105 | } |
| 1106 | |
| 1107 | +// Override default implementation to ensure we terminate the ScreenController first. |
| 1108 | +// Code path followed when Qt tries to shutdown the server. |
| 1109 | +void MirServer::stop() |
| 1110 | +{ |
| 1111 | + m_screenController->terminate(); |
| 1112 | + mir::Server::stop(); |
| 1113 | +} |
| 1114 | + |
| 1115 | |
| 1116 | /************************************ Shell side ************************************/ |
| 1117 | |
| 1118 | |
| 1119 | === modified file 'src/platforms/mirserver/mirserver.h' |
| 1120 | --- src/platforms/mirserver/mirserver.h 2015-08-11 12:08:32 +0000 |
| 1121 | +++ src/platforms/mirserver/mirserver.h 2015-10-16 17:43:47 +0000 |
| 1122 | @@ -18,6 +18,7 @@ |
| 1123 | #define MIRSERVER_H |
| 1124 | |
| 1125 | #include <QObject> |
| 1126 | +#include <QSharedPointer> |
| 1127 | #include <mir/server.h> |
| 1128 | |
| 1129 | class QtEventFeeder; |
| 1130 | @@ -25,6 +26,7 @@ |
| 1131 | class SessionAuthorizer; |
| 1132 | using MirShell = mir::shell::Shell; |
| 1133 | class PromptSessionListener; |
| 1134 | +class ScreenController; |
| 1135 | |
| 1136 | // We use virtual inheritance of mir::Server to facilitate derived classes (e.g. testing) |
| 1137 | // calling initialization functions before MirServer is constructed. |
| 1138 | @@ -38,12 +40,12 @@ |
| 1139 | Q_PROPERTY(PromptSessionListener* promptSessionListener READ promptSessionListener CONSTANT) |
| 1140 | |
| 1141 | public: |
| 1142 | - MirServer(int argc, char const* argv[], QObject* parent = 0); |
| 1143 | + MirServer(int argc, char const* argv[], const QSharedPointer<ScreenController> &, QObject* parent = 0); |
| 1144 | ~MirServer() = default; |
| 1145 | |
| 1146 | /* mir specific */ |
| 1147 | using mir::Server::run; |
| 1148 | - using mir::Server::stop; |
| 1149 | + using mir::Server::the_compositor; |
| 1150 | using mir::Server::the_display; |
| 1151 | using mir::Server::the_gl_config; |
| 1152 | using mir::Server::the_main_loop; |
| 1153 | @@ -52,6 +54,8 @@ |
| 1154 | using mir::Server::the_session_authorizer; |
| 1155 | using mir::Server::the_session_listener; |
| 1156 | |
| 1157 | + void stop(); |
| 1158 | + |
| 1159 | /* qt specific */ |
| 1160 | // getters |
| 1161 | SessionAuthorizer *sessionAuthorizer(); |
| 1162 | @@ -60,7 +64,9 @@ |
| 1163 | MirShell *shell(); |
| 1164 | |
| 1165 | private: |
| 1166 | + std::weak_ptr<MirShell> m_shell; |
| 1167 | std::shared_ptr<QtEventFeeder> m_qtEventFeeder; |
| 1168 | + const QSharedPointer<ScreenController> m_screenController; |
| 1169 | }; |
| 1170 | |
| 1171 | #endif // MIRSERVER_H |
| 1172 | |
| 1173 | === modified file 'src/platforms/mirserver/mirserverintegration.cpp' |
| 1174 | --- src/platforms/mirserver/mirserverintegration.cpp 2015-08-11 12:08:32 +0000 |
| 1175 | +++ src/platforms/mirserver/mirserverintegration.cpp 2015-10-16 17:43:47 +0000 |
| 1176 | @@ -26,7 +26,8 @@ |
| 1177 | #include <qpa/qplatforminputcontextfactory_p.h> |
| 1178 | #include <qpa/qwindowsysteminterface.h> |
| 1179 | |
| 1180 | -#include <QCoreApplication> |
| 1181 | +#include <QGuiApplication> |
| 1182 | +#include <QStringList> |
| 1183 | #include <QOpenGLContext> |
| 1184 | #include <QDebug> |
| 1185 | |
| 1186 | @@ -36,13 +37,16 @@ |
| 1187 | |
| 1188 | // local |
| 1189 | #include "clipboard.h" |
| 1190 | -#include "display.h" |
| 1191 | -#include "displaywindow.h" |
| 1192 | #include "miropenglcontext.h" |
| 1193 | #include "nativeinterface.h" |
| 1194 | +#include "offscreensurface.h" |
| 1195 | #include "qmirserver.h" |
| 1196 | +#include "screen.h" |
| 1197 | +#include "screencontroller.h" |
| 1198 | +#include "screenwindow.h" |
| 1199 | #include "services.h" |
| 1200 | #include "ubuntutheme.h" |
| 1201 | +#include "logging.h" |
| 1202 | |
| 1203 | namespace mg = mir::graphics; |
| 1204 | using qtmir::Clipboard; |
| 1205 | @@ -52,7 +56,6 @@ |
| 1206 | , m_fontDb(new QGenericUnixFontDatabase()) |
| 1207 | , m_services(new Services) |
| 1208 | , m_mirServer(new QMirServer(QCoreApplication::arguments())) |
| 1209 | - , m_display(nullptr) |
| 1210 | , m_nativeInterface(nullptr) |
| 1211 | , m_clipboard(new Clipboard) |
| 1212 | { |
| 1213 | @@ -72,12 +75,14 @@ |
| 1214 | QCoreApplication::instance(), &QCoreApplication::quit); |
| 1215 | |
| 1216 | m_inputContext = QPlatformInputContextFactory::create(); |
| 1217 | + |
| 1218 | + // Default Qt behaviour doesn't match a shell's intentions, so customize: |
| 1219 | + qGuiApp->setQuitOnLastWindowClosed(false); |
| 1220 | } |
| 1221 | |
| 1222 | MirServerIntegration::~MirServerIntegration() |
| 1223 | { |
| 1224 | delete m_nativeInterface; |
| 1225 | - delete m_display; |
| 1226 | } |
| 1227 | |
| 1228 | bool MirServerIntegration::hasCapability(QPlatformIntegration::Capability cap) const |
| 1229 | @@ -87,7 +92,7 @@ |
| 1230 | case OpenGL: return true; |
| 1231 | case ThreadedOpenGL: return true; |
| 1232 | case BufferQueueingOpenGL: return true; |
| 1233 | - case MultipleWindows: return false; // multi-monitor support |
| 1234 | + case MultipleWindows: return true; // multi-monitor support |
| 1235 | case WindowManagement: return false; // platform has no WM, as this implements the WM! |
| 1236 | case NonFullScreenWindows: return false; |
| 1237 | default: return QPlatformIntegration::hasCapability(cap); |
| 1238 | @@ -98,44 +103,30 @@ |
| 1239 | { |
| 1240 | QWindowSystemInterface::flushWindowSystemEvents(); |
| 1241 | |
| 1242 | - DisplayWindow* displayWindow = nullptr; |
| 1243 | - |
| 1244 | - auto const mirServer = m_mirServer->mirServer().lock(); |
| 1245 | - mg::DisplayBuffer* first_buffer{nullptr}; |
| 1246 | - mg::DisplaySyncGroup* first_group{nullptr}; |
| 1247 | - if (mirServer) { |
| 1248 | - mirServer->the_display()->for_each_display_sync_group([&](mg::DisplaySyncGroup &group) { |
| 1249 | - if (!first_group) { |
| 1250 | - first_group = &group; |
| 1251 | - } |
| 1252 | - group.for_each_display_buffer([&](mg::DisplayBuffer &buffer) { |
| 1253 | - if (!first_buffer) { |
| 1254 | - first_buffer = &buffer; |
| 1255 | - } |
| 1256 | - }); |
| 1257 | - }); |
| 1258 | - } |
| 1259 | - |
| 1260 | - // FIXME(gerry) this will go very bad for >1 display buffer |
| 1261 | - if (first_group && first_buffer) |
| 1262 | - displayWindow = new DisplayWindow(window, first_group, first_buffer); |
| 1263 | - |
| 1264 | - if (!displayWindow) |
| 1265 | + auto screens = m_mirServer->screenController().lock(); |
| 1266 | + if (!screens) { |
| 1267 | + qCritical("Screens are not initialized, unable to create a new QWindow/ScreenWindow"); |
| 1268 | return nullptr; |
| 1269 | - |
| 1270 | - //displayWindow->requestActivateWindow(); |
| 1271 | - return displayWindow; |
| 1272 | + } |
| 1273 | + |
| 1274 | + auto platformWindow = new ScreenWindow(window); |
| 1275 | + if (screens->compositing()) { |
| 1276 | + platformWindow->setExposed(true); |
| 1277 | + } |
| 1278 | + |
| 1279 | + qCDebug(QTMIR_SCREENS) << "QWindow" << window << "with geom" << window->geometry() |
| 1280 | + << "is backed by a" << static_cast<Screen *>(window->screen()->handle()) |
| 1281 | + << "with geometry" << window->screen()->geometry(); |
| 1282 | + return platformWindow; |
| 1283 | } |
| 1284 | |
| 1285 | -QPlatformBackingStore *MirServerIntegration::createPlatformBackingStore(QWindow *window) const |
| 1286 | +QPlatformBackingStore *MirServerIntegration::createPlatformBackingStore(QWindow */*window*/) const |
| 1287 | { |
| 1288 | - qDebug() << "createPlatformBackingStore" << window; |
| 1289 | return nullptr; |
| 1290 | } |
| 1291 | |
| 1292 | QPlatformOpenGLContext *MirServerIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const |
| 1293 | { |
| 1294 | - qDebug() << "createPlatformOpenGLContext" << context; |
| 1295 | return new MirOpenGLContext(m_mirServer->mirServer(), context->format()); |
| 1296 | } |
| 1297 | |
| 1298 | @@ -151,12 +142,18 @@ |
| 1299 | exit(2); |
| 1300 | } |
| 1301 | |
| 1302 | - m_display = new Display(m_mirServer->mirServer().data()->the_display()->configuration()); |
| 1303 | + auto screens = m_mirServer->screenController().lock(); |
| 1304 | + if (!screens) { |
| 1305 | + qFatal("ScreenController not initialized"); |
| 1306 | + } |
| 1307 | + QObject::connect(screens.data(), &ScreenController::screenAdded, |
| 1308 | + [this](Screen *screen) { this->screenAdded(screen); }); |
| 1309 | + Q_FOREACH(auto screen, screens->screens()) { |
| 1310 | + screenAdded(screen); |
| 1311 | + } |
| 1312 | + |
| 1313 | m_nativeInterface = new NativeInterface(m_mirServer->mirServer()); |
| 1314 | |
| 1315 | - for (QPlatformScreen *screen : m_display->screens()) |
| 1316 | - screenAdded(screen); |
| 1317 | - |
| 1318 | m_clipboard->setupDBusService(); |
| 1319 | } |
| 1320 | |
| 1321 | @@ -195,3 +192,9 @@ |
| 1322 | { |
| 1323 | return m_clipboard.data(); |
| 1324 | } |
| 1325 | + |
| 1326 | +QPlatformOffscreenSurface *MirServerIntegration::createPlatformOffscreenSurface( |
| 1327 | + QOffscreenSurface *surface) const |
| 1328 | +{ |
| 1329 | + return new OffscreenSurface(surface); |
| 1330 | +} |
| 1331 | |
| 1332 | === modified file 'src/platforms/mirserver/mirserverintegration.h' |
| 1333 | --- src/platforms/mirserver/mirserverintegration.h 2015-08-11 12:08:32 +0000 |
| 1334 | +++ src/platforms/mirserver/mirserverintegration.h 2015-10-16 17:43:47 +0000 |
| 1335 | @@ -19,13 +19,9 @@ |
| 1336 | |
| 1337 | // qt |
| 1338 | #include <qpa/qplatformintegration.h> |
| 1339 | - |
| 1340 | -// local |
| 1341 | -#include "mirserver.h" |
| 1342 | - |
| 1343 | -class Display; |
| 1344 | +#include <QScopedPointer> |
| 1345 | + |
| 1346 | class NativeInterface; |
| 1347 | -class MirServer; |
| 1348 | class QMirServer; |
| 1349 | |
| 1350 | namespace qtmir { |
| 1351 | @@ -60,6 +56,8 @@ |
| 1352 | |
| 1353 | QPlatformNativeInterface *nativeInterface() const override; |
| 1354 | |
| 1355 | + QPlatformOffscreenSurface *createPlatformOffscreenSurface(QOffscreenSurface *surface) const override; |
| 1356 | + |
| 1357 | private: |
| 1358 | QScopedPointer<QPlatformAccessibility> m_accessibility; |
| 1359 | QScopedPointer<QPlatformFontDatabase> m_fontDb; |
| 1360 | @@ -67,7 +65,6 @@ |
| 1361 | |
| 1362 | QScopedPointer<QMirServer> m_mirServer; |
| 1363 | |
| 1364 | - Display *m_display; |
| 1365 | NativeInterface *m_nativeInterface; |
| 1366 | QPlatformInputContext* m_inputContext; |
| 1367 | QScopedPointer<qtmir::Clipboard> m_clipboard; |
| 1368 | |
| 1369 | === added file 'src/platforms/mirserver/offscreensurface.cpp' |
| 1370 | --- src/platforms/mirserver/offscreensurface.cpp 1970-01-01 00:00:00 +0000 |
| 1371 | +++ src/platforms/mirserver/offscreensurface.cpp 2015-10-16 17:43:47 +0000 |
| 1372 | @@ -0,0 +1,61 @@ |
| 1373 | +/* |
| 1374 | + * Copyright (C) 2015 Canonical, Ltd. |
| 1375 | + * |
| 1376 | + * This program is free software: you can redistribute it and/or modify it under |
| 1377 | + * the terms of the GNU Lesser General Public License version 3, as published by |
| 1378 | + * the Free Software Foundation. |
| 1379 | + * |
| 1380 | + * This program is distributed in the hope that it will be useful, but WITHOUT |
| 1381 | + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
| 1382 | + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 1383 | + * Lesser General Public License for more details. |
| 1384 | + * |
| 1385 | + * You should have received a copy of the GNU Lesser General Public License |
| 1386 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 1387 | + */ |
| 1388 | + |
| 1389 | +#include "offscreensurface.h" |
| 1390 | + |
| 1391 | +#include "mirserver.h" |
| 1392 | + |
| 1393 | +// Mir |
| 1394 | +#include <mir/graphics/display.h> |
| 1395 | +#include <mir/graphics/gl_context.h> |
| 1396 | + |
| 1397 | +//Qt |
| 1398 | +#include <QOffscreenSurface> |
| 1399 | +#include <QOpenGLFramebufferObject> |
| 1400 | +#include <QSurfaceFormat> |
| 1401 | +#include <QtPlatformSupport/private/qeglconvenience_p.h> |
| 1402 | + |
| 1403 | +namespace mg = mir::graphics; |
| 1404 | + |
| 1405 | +OffscreenSurface::OffscreenSurface(QOffscreenSurface *offscreenSurface) |
| 1406 | + : QPlatformOffscreenSurface(offscreenSurface) |
| 1407 | + , m_buffer(nullptr) |
| 1408 | + , m_format(offscreenSurface->requestedFormat()) |
| 1409 | +{ |
| 1410 | +} |
| 1411 | + |
| 1412 | +QSurfaceFormat OffscreenSurface::format() const |
| 1413 | +{ |
| 1414 | + return m_format; |
| 1415 | +} |
| 1416 | + |
| 1417 | +bool OffscreenSurface::isValid() const |
| 1418 | +{ |
| 1419 | + if (m_buffer) { |
| 1420 | + return m_buffer->isValid(); |
| 1421 | + } |
| 1422 | + return false; |
| 1423 | +} |
| 1424 | + |
| 1425 | +QOpenGLFramebufferObject* OffscreenSurface::buffer() const |
| 1426 | +{ |
| 1427 | + return m_buffer; |
| 1428 | +} |
| 1429 | + |
| 1430 | +void OffscreenSurface::setBuffer(QOpenGLFramebufferObject *buffer) |
| 1431 | +{ |
| 1432 | + m_buffer = buffer; |
| 1433 | +} |
| 1434 | |
| 1435 | === added file 'src/platforms/mirserver/offscreensurface.h' |
| 1436 | --- src/platforms/mirserver/offscreensurface.h 1970-01-01 00:00:00 +0000 |
| 1437 | +++ src/platforms/mirserver/offscreensurface.h 2015-10-16 17:43:47 +0000 |
| 1438 | @@ -0,0 +1,43 @@ |
| 1439 | +/* |
| 1440 | + * Copyright (C) 2015 Canonical, Ltd. |
| 1441 | + * |
| 1442 | + * This program is free software: you can redistribute it and/or modify it under |
| 1443 | + * the terms of the GNU Lesser General Public License version 3, as published by |
| 1444 | + * the Free Software Foundation. |
| 1445 | + * |
| 1446 | + * This program is distributed in the hope that it will be useful, but WITHOUT |
| 1447 | + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
| 1448 | + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 1449 | + * Lesser General Public License for more details. |
| 1450 | + * |
| 1451 | + * You should have received a copy of the GNU Lesser General Public License |
| 1452 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 1453 | + */ |
| 1454 | + |
| 1455 | +#ifndef OFFSCREENSURFACE_H |
| 1456 | +#define OFFSCREENSURFACE_H |
| 1457 | + |
| 1458 | +#include <qpa/qplatformoffscreensurface.h> |
| 1459 | +#include <QSurfaceFormat> |
| 1460 | +#include <QSharedPointer> |
| 1461 | + |
| 1462 | +class MirServer; |
| 1463 | +class QOpenGLFramebufferObject; |
| 1464 | + |
| 1465 | +class OffscreenSurface : public QPlatformOffscreenSurface |
| 1466 | +{ |
| 1467 | +public: |
| 1468 | + OffscreenSurface(QOffscreenSurface *offscreenSurface); |
| 1469 | + |
| 1470 | + QSurfaceFormat format() const override; |
| 1471 | + bool isValid() const override; |
| 1472 | + |
| 1473 | + QOpenGLFramebufferObject* buffer() const; |
| 1474 | + void setBuffer(QOpenGLFramebufferObject *buffer); |
| 1475 | + |
| 1476 | +private: |
| 1477 | + QOpenGLFramebufferObject *m_buffer; |
| 1478 | + QSurfaceFormat m_format; |
| 1479 | +}; |
| 1480 | + |
| 1481 | +#endif // OFFSCREENSURFACE_H |
| 1482 | |
| 1483 | === modified file 'src/platforms/mirserver/qmirserver.cpp' |
| 1484 | --- src/platforms/mirserver/qmirserver.cpp 2015-05-19 15:36:17 +0000 |
| 1485 | +++ src/platforms/mirserver/qmirserver.cpp 2015-10-16 17:43:47 +0000 |
| 1486 | @@ -23,7 +23,8 @@ |
| 1487 | #include "mirserver.h" |
| 1488 | #include "qmirserver.h" |
| 1489 | #include "qmirserver_p.h" |
| 1490 | - |
| 1491 | +#include "screencontroller.h" |
| 1492 | +#include "screen.h" |
| 1493 | |
| 1494 | QMirServer::QMirServer(const QStringList &arguments, QObject *parent) |
| 1495 | : QObject(parent) |
| 1496 | @@ -40,7 +41,9 @@ |
| 1497 | } |
| 1498 | argv[argc] = '\0'; |
| 1499 | |
| 1500 | - d->server = QSharedPointer<MirServer>(new MirServer(argc, const_cast<const char**>(argv))); |
| 1501 | + d->screenController = QSharedPointer<ScreenController>(new ScreenController()); |
| 1502 | + |
| 1503 | + d->server = QSharedPointer<MirServer>(new MirServer(argc, const_cast<const char**>(argv), d->screenController)); |
| 1504 | |
| 1505 | d->serverThread = new MirServerThread(d->server); |
| 1506 | |
| 1507 | @@ -63,6 +66,7 @@ |
| 1508 | qCritical() << "ERROR: QMirServer - Mir failed to start"; |
| 1509 | return false; |
| 1510 | } |
| 1511 | + d->screenController->update(); |
| 1512 | |
| 1513 | Q_EMIT started(); |
| 1514 | return true; |
| 1515 | @@ -93,3 +97,9 @@ |
| 1516 | Q_D(const QMirServer); |
| 1517 | return d->server.toWeakRef(); |
| 1518 | } |
| 1519 | + |
| 1520 | +QWeakPointer<ScreenController> QMirServer::screenController() const |
| 1521 | +{ |
| 1522 | + Q_D(const QMirServer); |
| 1523 | + return d->screenController; |
| 1524 | +} |
| 1525 | |
| 1526 | === modified file 'src/platforms/mirserver/qmirserver.h' |
| 1527 | --- src/platforms/mirserver/qmirserver.h 2015-05-18 20:39:09 +0000 |
| 1528 | +++ src/platforms/mirserver/qmirserver.h 2015-10-16 17:43:47 +0000 |
| 1529 | @@ -23,6 +23,7 @@ |
| 1530 | |
| 1531 | class QMirServerPrivate; |
| 1532 | class MirServer; |
| 1533 | +class ScreenController; |
| 1534 | |
| 1535 | class QMirServer: public QObject |
| 1536 | { |
| 1537 | @@ -38,6 +39,8 @@ |
| 1538 | |
| 1539 | QWeakPointer<MirServer> mirServer() const; |
| 1540 | |
| 1541 | + QWeakPointer<ScreenController> screenController() const; |
| 1542 | + |
| 1543 | Q_SIGNALS: |
| 1544 | void started(); |
| 1545 | void stopped(); |
| 1546 | |
| 1547 | === modified file 'src/platforms/mirserver/qmirserver_p.h' |
| 1548 | --- src/platforms/mirserver/qmirserver_p.h 2015-05-18 18:30:33 +0000 |
| 1549 | +++ src/platforms/mirserver/qmirserver_p.h 2015-10-16 17:43:47 +0000 |
| 1550 | @@ -27,6 +27,7 @@ |
| 1551 | |
| 1552 | // local |
| 1553 | #include "mirserver.h" |
| 1554 | +#include "screencontroller.h" |
| 1555 | |
| 1556 | class QMirServer; |
| 1557 | class MirServerThread; |
| 1558 | @@ -34,6 +35,7 @@ |
| 1559 | struct QMirServerPrivate |
| 1560 | { |
| 1561 | QSharedPointer<MirServer> server; |
| 1562 | + QSharedPointer<ScreenController> screenController; |
| 1563 | MirServerThread *serverThread; |
| 1564 | }; |
| 1565 | |
| 1566 | |
| 1567 | === modified file 'src/platforms/mirserver/qtcompositor.cpp' |
| 1568 | --- src/platforms/mirserver/qtcompositor.cpp 2015-08-11 12:08:32 +0000 |
| 1569 | +++ src/platforms/mirserver/qtcompositor.cpp 2015-10-16 17:43:47 +0000 |
| 1570 | @@ -15,44 +15,32 @@ |
| 1571 | */ |
| 1572 | |
| 1573 | #include "qtcompositor.h" |
| 1574 | -#include "displaywindow.h" |
| 1575 | - |
| 1576 | -#include <QGuiApplication> |
| 1577 | -#include <QWindow> |
| 1578 | - |
| 1579 | -#include <QDebug> |
| 1580 | - |
| 1581 | -QtCompositor::QtCompositor() |
| 1582 | -{ |
| 1583 | - |
| 1584 | -} |
| 1585 | - |
| 1586 | +#include "logging.h" |
| 1587 | + |
| 1588 | +#include <mir/graphics/cursor.h> |
| 1589 | + |
| 1590 | +// Lives in a Mir thread |
| 1591 | void QtCompositor::start() |
| 1592 | { |
| 1593 | - // (Re)Start Qt's render thread by setting all its windows to exposed |
| 1594 | - setAllWindowsExposed(true); |
| 1595 | + qCDebug(QTMIR_SCREENS) << "QtCompositor::start"; |
| 1596 | + |
| 1597 | + // FIXME: Hack to work around https://bugs.launchpad.net/mir/+bug/1502200 |
| 1598 | + // See the FIXME in mirserver.cpp |
| 1599 | + if (m_cursor) { |
| 1600 | + m_cursor->hide(); |
| 1601 | + } |
| 1602 | + |
| 1603 | + Q_EMIT starting(); // blocks |
| 1604 | } |
| 1605 | |
| 1606 | void QtCompositor::stop() |
| 1607 | { |
| 1608 | - // Stop Qt's render threads by setting all its windows it obscured |
| 1609 | - setAllWindowsExposed(false); |
| 1610 | + qCDebug(QTMIR_SCREENS) << "QtCompositor::stop"; |
| 1611 | + |
| 1612 | + Q_EMIT stopping(); // blocks |
| 1613 | } |
| 1614 | |
| 1615 | -void QtCompositor::setAllWindowsExposed(const bool exposed) |
| 1616 | +void QtCompositor::setCursor(std::shared_ptr<mir::graphics::Cursor> cursor) |
| 1617 | { |
| 1618 | - qDebug() << "QtCompositor::setAllWindowsExposed" << exposed; |
| 1619 | - QList<QWindow *> windowList = QGuiApplication::allWindows(); |
| 1620 | - |
| 1621 | - // manipulate Qt object's indirectly via posted events as we're not in Qt's GUI thread |
| 1622 | - auto iterator = windowList.constBegin(); |
| 1623 | - while (iterator != windowList.constEnd()) { |
| 1624 | - QWindow *window = *iterator; |
| 1625 | - DisplayWindow *displayWindow = static_cast<DisplayWindow*>(window->handle()); |
| 1626 | - if (displayWindow) { |
| 1627 | - QCoreApplication::postEvent(displayWindow, |
| 1628 | - new QEvent( (exposed) ? QEvent::Show : QEvent::Hide)); |
| 1629 | - } |
| 1630 | - iterator++; |
| 1631 | - } |
| 1632 | + m_cursor = cursor; |
| 1633 | } |
| 1634 | |
| 1635 | === modified file 'src/platforms/mirserver/qtcompositor.h' |
| 1636 | --- src/platforms/mirserver/qtcompositor.h 2015-08-11 12:08:32 +0000 |
| 1637 | +++ src/platforms/mirserver/qtcompositor.h 2015-10-16 17:43:47 +0000 |
| 1638 | @@ -17,18 +17,38 @@ |
| 1639 | #ifndef QTCOMPOSITOR_H |
| 1640 | #define QTCOMPOSITOR_H |
| 1641 | |
| 1642 | -#include "mir/compositor/compositor.h" |
| 1643 | - |
| 1644 | -class QtCompositor : public mir::compositor::Compositor |
| 1645 | +#include <mir/compositor/compositor.h> |
| 1646 | + |
| 1647 | +// std lib |
| 1648 | +#include <memory> |
| 1649 | + |
| 1650 | +// Qt |
| 1651 | +#include <QObject> |
| 1652 | + |
| 1653 | +namespace mir { |
| 1654 | + namespace graphics { |
| 1655 | + class Cursor; |
| 1656 | + } |
| 1657 | +} |
| 1658 | + |
| 1659 | +class QtCompositor : public QObject, public mir::compositor::Compositor |
| 1660 | { |
| 1661 | + Q_OBJECT |
| 1662 | public: |
| 1663 | - QtCompositor(); |
| 1664 | + QtCompositor() = default; |
| 1665 | + virtual ~QtCompositor() noexcept = default; |
| 1666 | |
| 1667 | void start(); |
| 1668 | void stop(); |
| 1669 | |
| 1670 | + void setCursor(std::shared_ptr<mir::graphics::Cursor>); |
| 1671 | + |
| 1672 | +Q_SIGNALS: |
| 1673 | + void starting(); |
| 1674 | + void stopping(); |
| 1675 | + |
| 1676 | private: |
| 1677 | - void setAllWindowsExposed(const bool exposed); |
| 1678 | + std::shared_ptr<mir::graphics::Cursor> m_cursor; |
| 1679 | }; |
| 1680 | |
| 1681 | #endif // QTCOMPOSITOR_H |
| 1682 | |
| 1683 | === modified file 'src/platforms/mirserver/qteventfeeder.cpp' |
| 1684 | --- src/platforms/mirserver/qteventfeeder.cpp 2015-10-16 17:43:47 +0000 |
| 1685 | +++ src/platforms/mirserver/qteventfeeder.cpp 2015-10-16 17:43:47 +0000 |
| 1686 | @@ -17,7 +17,8 @@ |
| 1687 | #include "qteventfeeder.h" |
| 1688 | #include "cursor.h" |
| 1689 | #include "logging.h" |
| 1690 | -#include "screen.h" |
| 1691 | +#include "screen.h" // NEEDED? |
| 1692 | +#include "screencontroller.h" |
| 1693 | |
| 1694 | #include <qpa/qplatforminputcontext.h> |
| 1695 | #include <qpa/qplatformintegration.h> |
| 1696 | @@ -367,7 +368,8 @@ |
| 1697 | |
| 1698 | namespace { |
| 1699 | |
| 1700 | -class QtWindowSystem : public QtEventFeeder::QtWindowSystemInterface { |
| 1701 | +class QtWindowSystem : public QtEventFeeder::QtWindowSystemInterface |
| 1702 | +{ |
| 1703 | public: |
| 1704 | QtWindowSystem() |
| 1705 | { |
| 1706 | @@ -376,18 +378,19 @@ |
| 1707 | qRegisterMetaType<Qt::MouseButtons>("Qt::MouseButtons"); |
| 1708 | } |
| 1709 | |
| 1710 | - bool hasTargetWindow() override |
| 1711 | - { |
| 1712 | - if (mTopLevelWindow.isNull() && !QGuiApplication::topLevelWindows().isEmpty()) { |
| 1713 | - mTopLevelWindow = QGuiApplication::topLevelWindows().first(); |
| 1714 | - } |
| 1715 | - return !mTopLevelWindow.isNull(); |
| 1716 | - } |
| 1717 | - |
| 1718 | - QRect targetWindowGeometry() override |
| 1719 | - { |
| 1720 | - Q_ASSERT(!mTopLevelWindow.isNull()); |
| 1721 | - return mTopLevelWindow->geometry(); |
| 1722 | + void setScreenController(const QSharedPointer<ScreenController> &sc) override |
| 1723 | + { |
| 1724 | + m_screenController = sc; |
| 1725 | + } |
| 1726 | + |
| 1727 | + virtual QWindow* focusedWindow() override |
| 1728 | + { |
| 1729 | + return QGuiApplication::focusWindow(); |
| 1730 | + } |
| 1731 | + |
| 1732 | + QWindow* getWindowForTouchPoint(const QPoint &point) override //FIXME: not efficient, not updating focused window |
| 1733 | + { |
| 1734 | + return m_screenController->getWindowForPoint(point); |
| 1735 | } |
| 1736 | |
| 1737 | void registerTouchDevice(QTouchDevice *device) override |
| 1738 | @@ -395,47 +398,55 @@ |
| 1739 | QWindowSystemInterface::registerTouchDevice(device); |
| 1740 | } |
| 1741 | |
| 1742 | - void handleExtendedKeyEvent(ulong timestamp, QEvent::Type type, int key, |
| 1743 | + void handleExtendedKeyEvent(QWindow *window, ulong timestamp, QEvent::Type type, int key, |
| 1744 | Qt::KeyboardModifiers modifiers, |
| 1745 | quint32 nativeScanCode, quint32 nativeVirtualKey, |
| 1746 | quint32 nativeModifiers, |
| 1747 | const QString& text, bool autorep, ushort count) override |
| 1748 | { |
| 1749 | - Q_ASSERT(!mTopLevelWindow.isNull()); |
| 1750 | - QWindowSystemInterface::handleExtendedKeyEvent(mTopLevelWindow.data(), timestamp, type, key, modifiers, |
| 1751 | + QWindowSystemInterface::handleExtendedKeyEvent(window, timestamp, type, key, modifiers, |
| 1752 | nativeScanCode, nativeVirtualKey, nativeModifiers, text, autorep, count); |
| 1753 | } |
| 1754 | |
| 1755 | - void handleTouchEvent(ulong timestamp, QTouchDevice *device, |
| 1756 | + void handleTouchEvent(QWindow *window, ulong timestamp, QTouchDevice *device, |
| 1757 | const QList<struct QWindowSystemInterface::TouchPoint> &points, Qt::KeyboardModifiers mods) override |
| 1758 | { |
| 1759 | - Q_ASSERT(!mTopLevelWindow.isNull()); |
| 1760 | - QWindowSystemInterface::handleTouchEvent(mTopLevelWindow.data(), timestamp, device, points, mods); |
| 1761 | + QWindowSystemInterface::handleTouchEvent(window, timestamp, device, points, mods); |
| 1762 | } |
| 1763 | |
| 1764 | void handleMouseEvent(ulong timestamp, QPointF movement, Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers) override |
| 1765 | { |
| 1766 | - Q_ASSERT(!mTopLevelWindow.isNull()); |
| 1767 | - auto platformCursor = static_cast<qtmir::Cursor*>(mTopLevelWindow->screen()->handle()->cursor()); |
| 1768 | - platformCursor->handleMouseEvent(timestamp, movement, buttons, modifiers); |
| 1769 | + // Send to the first screen that handles the mouse event |
| 1770 | + // TODO: Have a mechanism to tell which screen currently has the logical mouse pointer |
| 1771 | + // (because they all might have their own separate graphical mouse pointer item) |
| 1772 | + // This will probably come once we implement the feature of having the mouse pointer |
| 1773 | + // crossing adjacent screens. |
| 1774 | + |
| 1775 | + QList<Screen*> screens = m_screenController->screens(); |
| 1776 | + bool eventHandled = false; |
| 1777 | + int i = 0; |
| 1778 | + while (i < screens.count() && !eventHandled) { |
| 1779 | + auto platformCursor = static_cast<qtmir::Cursor*>(screens[i]->cursor()); |
| 1780 | + eventHandled = platformCursor->handleMouseEvent(timestamp, movement, buttons, modifiers); |
| 1781 | + ++i; |
| 1782 | + } |
| 1783 | } |
| 1784 | |
| 1785 | - |
| 1786 | private: |
| 1787 | - QPointer<QWindow> mTopLevelWindow; |
| 1788 | + QSharedPointer<ScreenController> m_screenController; |
| 1789 | }; |
| 1790 | |
| 1791 | } // anonymous namespace |
| 1792 | |
| 1793 | - |
| 1794 | -QtEventFeeder::QtEventFeeder(QtEventFeeder::QtWindowSystemInterface *windowSystem) |
| 1795 | -{ |
| 1796 | - if (windowSystem) { |
| 1797 | - mQtWindowSystem = windowSystem; |
| 1798 | - } else { |
| 1799 | - mQtWindowSystem = new QtWindowSystem; |
| 1800 | - } |
| 1801 | - |
| 1802 | +QtEventFeeder::QtEventFeeder(const QSharedPointer<ScreenController> &screenController) |
| 1803 | + : QtEventFeeder(screenController, new QtWindowSystem) |
| 1804 | +{ |
| 1805 | +} |
| 1806 | + |
| 1807 | +QtEventFeeder::QtEventFeeder(const QSharedPointer<ScreenController> &screenController, |
| 1808 | + QtEventFeeder::QtWindowSystemInterface *windowSystem) |
| 1809 | + : mQtWindowSystem(windowSystem) |
| 1810 | +{ |
| 1811 | // Initialize touch device. Hardcoded just like in qtubuntu |
| 1812 | // TODO: Create them from info gathered from Mir and store things like device id and source |
| 1813 | // in a QTouchDevice-derived class created by us. So that we can properly assemble back |
| 1814 | @@ -445,6 +456,7 @@ |
| 1815 | mTouchDevice->setCapabilities( |
| 1816 | QTouchDevice::Position | QTouchDevice::Area | QTouchDevice::Pressure | |
| 1817 | QTouchDevice::NormalizedPosition); |
| 1818 | + mQtWindowSystem->setScreenController(screenController); |
| 1819 | mQtWindowSystem->registerTouchDevice(mTouchDevice); |
| 1820 | } |
| 1821 | |
| 1822 | @@ -458,6 +470,7 @@ |
| 1823 | auto type = mir_event_get_type(&event); |
| 1824 | if (type != mir_event_type_input) |
| 1825 | return false; |
| 1826 | + |
| 1827 | auto iev = mir_event_get_input_event(&event); |
| 1828 | |
| 1829 | switch (mir_input_event_get_type(iev)) { |
| 1830 | @@ -517,9 +530,6 @@ |
| 1831 | |
| 1832 | void QtEventFeeder::dispatchPointer(MirInputEvent const* ev) |
| 1833 | { |
| 1834 | - if (!mQtWindowSystem->hasTargetWindow()) |
| 1835 | - return; |
| 1836 | - |
| 1837 | auto timestamp = mir_input_event_get_event_time(ev) / 1000000; |
| 1838 | |
| 1839 | auto pev = mir_input_event_get_pointer_event(ev); |
| 1840 | @@ -527,6 +537,7 @@ |
| 1841 | |
| 1842 | auto modifiers = getQtModifiersFromMir(mir_pointer_event_modifiers(pev)); |
| 1843 | auto buttons = getQtMouseButtonsfromMirPointerEvent(pev); |
| 1844 | + |
| 1845 | auto movement = QPointF(mir_pointer_event_axis_value(pev, mir_pointer_axis_relative_x), |
| 1846 | mir_pointer_event_axis_value(pev, mir_pointer_axis_relative_y)); |
| 1847 | |
| 1848 | @@ -535,9 +546,6 @@ |
| 1849 | |
| 1850 | void QtEventFeeder::dispatchKey(MirInputEvent const* event) |
| 1851 | { |
| 1852 | - if (!mQtWindowSystem->hasTargetWindow()) |
| 1853 | - return; |
| 1854 | - |
| 1855 | ulong timestamp = mir_input_event_get_event_time(event) / 1000000; |
| 1856 | |
| 1857 | auto kev = mir_input_event_get_keyboard_event(event); |
| 1858 | @@ -579,12 +587,17 @@ |
| 1859 | text, is_auto_rep); |
| 1860 | qKeyEvent.setTimestamp(timestamp); |
| 1861 | if (context->filterEvent(&qKeyEvent)) { |
| 1862 | - // key event filtered out by input context |
| 1863 | + qCDebug(QTMIR_MIR_INPUT) << "Received" << qPrintable(mirKeyboardEventToString(kev)) |
| 1864 | + << "but not dispatching as it was filtered out by input context"; |
| 1865 | return; |
| 1866 | } |
| 1867 | } |
| 1868 | |
| 1869 | - mQtWindowSystem->handleExtendedKeyEvent(timestamp, keyType, keyCode, modifiers, |
| 1870 | + qCDebug(QTMIR_MIR_INPUT).nospace() << "Received" << qPrintable(mirKeyboardEventToString(kev)) |
| 1871 | + << ". Dispatching to " << mQtWindowSystem->focusedWindow(); |
| 1872 | + |
| 1873 | + mQtWindowSystem->handleExtendedKeyEvent(mQtWindowSystem->focusedWindow(), |
| 1874 | + timestamp, keyType, keyCode, modifiers, |
| 1875 | mir_keyboard_event_scan_code(kev), |
| 1876 | mir_keyboard_event_key_code(kev), |
| 1877 | mir_keyboard_event_modifiers(kev), text, is_auto_rep); |
| 1878 | @@ -592,59 +605,69 @@ |
| 1879 | |
| 1880 | void QtEventFeeder::dispatchTouch(MirInputEvent const* event) |
| 1881 | { |
| 1882 | - if (!mQtWindowSystem->hasTargetWindow()) |
| 1883 | - return; |
| 1884 | - |
| 1885 | auto tev = mir_input_event_get_touch_event(event); |
| 1886 | qCDebug(QTMIR_MIR_INPUT) << "Received" << qPrintable(mirTouchEventToString(tev)); |
| 1887 | |
| 1888 | // FIXME(loicm) Max pressure is device specific. That one is for the Samsung Galaxy Nexus. That |
| 1889 | // needs to be fixed as soon as the compat input lib adds query support. |
| 1890 | const float kMaxPressure = 1.28; |
| 1891 | - const QRect kWindowGeometry = mQtWindowSystem->targetWindowGeometry(); |
| 1892 | + const int kPointerCount = mir_touch_event_point_count(tev); |
| 1893 | QList<QWindowSystemInterface::TouchPoint> touchPoints; |
| 1894 | - |
| 1895 | - // TODO: Is it worth setting the Qt::TouchPointStationary ones? Currently they are left |
| 1896 | - // as Qt::TouchPointMoved |
| 1897 | - const int kPointerCount = mir_touch_event_point_count(tev); |
| 1898 | - for (int i = 0; i < kPointerCount; ++i) { |
| 1899 | - QWindowSystemInterface::TouchPoint touchPoint; |
| 1900 | - |
| 1901 | - const float kX = mir_touch_event_axis_value(tev, i, mir_touch_axis_x); |
| 1902 | - const float kY = mir_touch_event_axis_value(tev, i, mir_touch_axis_y); |
| 1903 | - const float kW = mir_touch_event_axis_value(tev, i, mir_touch_axis_touch_major); |
| 1904 | - const float kH = mir_touch_event_axis_value(tev, i, mir_touch_axis_touch_minor); |
| 1905 | - const float kP = mir_touch_event_axis_value(tev, i, mir_touch_axis_pressure); |
| 1906 | - touchPoint.id = mir_touch_event_id(tev, i); |
| 1907 | - |
| 1908 | - touchPoint.normalPosition = QPointF(kX / kWindowGeometry.width(), kY / kWindowGeometry.height()); |
| 1909 | - touchPoint.area = QRectF(kX - (kW / 2.0), kY - (kH / 2.0), kW, kH); |
| 1910 | - touchPoint.pressure = kP / kMaxPressure; |
| 1911 | - switch (mir_touch_event_action(tev, i)) |
| 1912 | - { |
| 1913 | - case mir_touch_action_up: |
| 1914 | - touchPoint.state = Qt::TouchPointReleased; |
| 1915 | - break; |
| 1916 | - case mir_touch_action_down: |
| 1917 | - touchPoint.state = Qt::TouchPointPressed; |
| 1918 | - break; |
| 1919 | - case mir_touch_action_change: |
| 1920 | - touchPoint.state = Qt::TouchPointMoved; |
| 1921 | - break; |
| 1922 | - default: |
| 1923 | - break; |
| 1924 | - } |
| 1925 | - |
| 1926 | - touchPoints.append(touchPoint); |
| 1927 | + QWindow *window = nullptr; |
| 1928 | + |
| 1929 | + if (kPointerCount > 0) { |
| 1930 | + window = mQtWindowSystem->getWindowForTouchPoint( |
| 1931 | + QPoint(mir_touch_event_axis_value(tev, 0, mir_touch_axis_x), |
| 1932 | + mir_touch_event_axis_value(tev, 0, mir_touch_axis_y))); |
| 1933 | + |
| 1934 | + if (!window) { |
| 1935 | + qCDebug(QTMIR_MIR_INPUT) << "REJECTING INPUT EVENT, no matching window"; |
| 1936 | + return; |
| 1937 | + } |
| 1938 | + |
| 1939 | + const QRect kWindowGeometry = window->geometry(); |
| 1940 | + |
| 1941 | + // TODO: Is it worth setting the Qt::TouchPointStationary ones? Currently they are left |
| 1942 | + // as Qt::TouchPointMoved |
| 1943 | + for (int i = 0; i < kPointerCount; ++i) { |
| 1944 | + QWindowSystemInterface::TouchPoint touchPoint; |
| 1945 | + |
| 1946 | + const float kX = mir_touch_event_axis_value(tev, i, mir_touch_axis_x); |
| 1947 | + const float kY = mir_touch_event_axis_value(tev, i, mir_touch_axis_y); |
| 1948 | + const float kW = mir_touch_event_axis_value(tev, i, mir_touch_axis_touch_major); |
| 1949 | + const float kH = mir_touch_event_axis_value(tev, i, mir_touch_axis_touch_minor); |
| 1950 | + const float kP = mir_touch_event_axis_value(tev, i, mir_touch_axis_pressure); |
| 1951 | + touchPoint.id = mir_touch_event_id(tev, i); |
| 1952 | + |
| 1953 | + touchPoint.normalPosition = QPointF(kX / kWindowGeometry.width(), kY / kWindowGeometry.height()); |
| 1954 | + touchPoint.area = QRectF(kX - (kW / 2.0), kY - (kH / 2.0), kW, kH); |
| 1955 | + touchPoint.pressure = kP / kMaxPressure; |
| 1956 | + switch (mir_touch_event_action(tev, i)) |
| 1957 | + { |
| 1958 | + case mir_touch_action_up: |
| 1959 | + touchPoint.state = Qt::TouchPointReleased; |
| 1960 | + break; |
| 1961 | + case mir_touch_action_down: |
| 1962 | + touchPoint.state = Qt::TouchPointPressed; |
| 1963 | + break; |
| 1964 | + case mir_touch_action_change: |
| 1965 | + touchPoint.state = Qt::TouchPointMoved; |
| 1966 | + break; |
| 1967 | + default: |
| 1968 | + break; |
| 1969 | + } |
| 1970 | + |
| 1971 | + touchPoints.append(touchPoint); |
| 1972 | + } |
| 1973 | } |
| 1974 | |
| 1975 | // Qt needs a happy, sane stream of touch events. So let's make sure we're not forwarding |
| 1976 | // any insanity. |
| 1977 | - validateTouches(mir_input_event_get_event_time(event) / 1000000, touchPoints); |
| 1978 | + validateTouches(window, mir_input_event_get_event_time(event) / 1000000, touchPoints); |
| 1979 | |
| 1980 | // Touch event propagation. |
| 1981 | qCDebug(QTMIR_MIR_INPUT) << "Sending to Qt" << qPrintable(touchesToString(touchPoints)); |
| 1982 | - mQtWindowSystem->handleTouchEvent( |
| 1983 | + mQtWindowSystem->handleTouchEvent(window, |
| 1984 | //scales down the nsec_t (int64) to fit a ulong, precision lost but time difference suitable |
| 1985 | mir_input_event_get_event_time(event) / 1000000, |
| 1986 | mTouchDevice, |
| 1987 | @@ -661,7 +684,7 @@ |
| 1988 | // not used |
| 1989 | } |
| 1990 | |
| 1991 | -void QtEventFeeder::validateTouches(ulong timestamp, |
| 1992 | +void QtEventFeeder::validateTouches(QWindow *window, ulong timestamp, |
| 1993 | QList<QWindowSystemInterface::TouchPoint> &touchPoints) |
| 1994 | { |
| 1995 | QSet<int> updatedTouches; |
| 1996 | @@ -685,7 +708,7 @@ |
| 1997 | if (!updatedTouches.contains(it.key())) { |
| 1998 | qCWarning(QTMIR_MIR_INPUT) |
| 1999 | << "There's a touch (id =" << it.key() << ") missing. Releasing it."; |
| 2000 | - sendActiveTouchRelease(timestamp, it.key()); |
| 2001 | + sendActiveTouchRelease(window, timestamp, it.key()); |
| 2002 | it = mActiveTouches.erase(it); |
| 2003 | } else { |
| 2004 | ++it; |
| 2005 | @@ -703,7 +726,7 @@ |
| 2006 | } |
| 2007 | } |
| 2008 | |
| 2009 | -void QtEventFeeder::sendActiveTouchRelease(ulong timestamp, int id) |
| 2010 | +void QtEventFeeder::sendActiveTouchRelease(QWindow *window, ulong timestamp, int id) |
| 2011 | { |
| 2012 | QList<QWindowSystemInterface::TouchPoint> touchPoints = mActiveTouches.values(); |
| 2013 | |
| 2014 | @@ -717,7 +740,7 @@ |
| 2015 | } |
| 2016 | |
| 2017 | qCDebug(QTMIR_MIR_INPUT) << "Sending to Qt" << qPrintable(touchesToString(touchPoints)); |
| 2018 | - mQtWindowSystem->handleTouchEvent(timestamp, mTouchDevice, touchPoints); |
| 2019 | + mQtWindowSystem->handleTouchEvent(window, timestamp, mTouchDevice, touchPoints); |
| 2020 | } |
| 2021 | |
| 2022 | bool QtEventFeeder::validateTouch(QWindowSystemInterface::TouchPoint &touchPoint) |
| 2023 | |
| 2024 | === modified file 'src/platforms/mirserver/qteventfeeder.h' |
| 2025 | --- src/platforms/mirserver/qteventfeeder.h 2015-10-16 17:43:47 +0000 |
| 2026 | +++ src/platforms/mirserver/qteventfeeder.h 2015-10-16 17:43:47 +0000 |
| 2027 | @@ -23,6 +23,7 @@ |
| 2028 | #include <qpa/qwindowsysteminterface.h> |
| 2029 | |
| 2030 | class QTouchDevice; |
| 2031 | +class ScreenController; |
| 2032 | |
| 2033 | /* |
| 2034 | Fills Qt's event loop with input events from Mir |
| 2035 | @@ -33,27 +34,29 @@ |
| 2036 | // Interface between QtEventFeeder and the actual QWindowSystemInterface functions |
| 2037 | // and other related Qt methods and objects to enable replacing them with mocks in |
| 2038 | // pure unit tests. |
| 2039 | - // TODO - Make it work with multimonitor scenarios |
| 2040 | class QtWindowSystemInterface { |
| 2041 | public: |
| 2042 | virtual ~QtWindowSystemInterface() {} |
| 2043 | - virtual bool hasTargetWindow() = 0; |
| 2044 | - virtual QRect targetWindowGeometry() = 0; |
| 2045 | + virtual void setScreenController(const QSharedPointer<ScreenController> &sc) = 0; |
| 2046 | + virtual QWindow* getWindowForTouchPoint(const QPoint &point) = 0; |
| 2047 | + virtual QWindow* focusedWindow() = 0; |
| 2048 | virtual void registerTouchDevice(QTouchDevice *device) = 0; |
| 2049 | - virtual void handleExtendedKeyEvent(ulong timestamp, QEvent::Type type, int key, |
| 2050 | + virtual void handleExtendedKeyEvent(QWindow *window, ulong timestamp, QEvent::Type type, int key, |
| 2051 | Qt::KeyboardModifiers modifiers, |
| 2052 | quint32 nativeScanCode, quint32 nativeVirtualKey, |
| 2053 | quint32 nativeModifiers, |
| 2054 | const QString& text = QString(), bool autorep = false, |
| 2055 | ushort count = 1) = 0; |
| 2056 | - virtual void handleTouchEvent(ulong timestamp, QTouchDevice *device, |
| 2057 | + virtual void handleTouchEvent(QWindow *window, ulong timestamp, QTouchDevice *device, |
| 2058 | const QList<struct QWindowSystemInterface::TouchPoint> &points, |
| 2059 | Qt::KeyboardModifiers mods = Qt::NoModifier) = 0; |
| 2060 | virtual void handleMouseEvent(ulong timestamp, QPointF movement, Qt::MouseButtons buttons, |
| 2061 | Qt::KeyboardModifiers modifiers) = 0; |
| 2062 | }; |
| 2063 | |
| 2064 | - QtEventFeeder(QtWindowSystemInterface *windowSystem = nullptr); |
| 2065 | + QtEventFeeder(const QSharedPointer<ScreenController> &screenController); |
| 2066 | + QtEventFeeder(const QSharedPointer<ScreenController> &screenController, |
| 2067 | + QtWindowSystemInterface *windowSystem); |
| 2068 | virtual ~QtEventFeeder(); |
| 2069 | |
| 2070 | static const int MirEventActionMask; |
| 2071 | @@ -68,9 +71,9 @@ |
| 2072 | void dispatchKey(MirInputEvent const* event); |
| 2073 | void dispatchTouch(MirInputEvent const* event); |
| 2074 | void dispatchPointer(MirInputEvent const* event); |
| 2075 | - void validateTouches(ulong timestamp, QList<QWindowSystemInterface::TouchPoint> &touchPoints); |
| 2076 | + void validateTouches(QWindow *window, ulong timestamp, QList<QWindowSystemInterface::TouchPoint> &touchPoints); |
| 2077 | bool validateTouch(QWindowSystemInterface::TouchPoint &touchPoint); |
| 2078 | - void sendActiveTouchRelease(ulong timestamp, int id); |
| 2079 | + void sendActiveTouchRelease(QWindow *window, ulong timestamp, int id); |
| 2080 | |
| 2081 | QString touchesToString(const QList<struct QWindowSystemInterface::TouchPoint> &points); |
| 2082 | |
| 2083 | |
| 2084 | === modified file 'src/platforms/mirserver/screen.cpp' |
| 2085 | --- src/platforms/mirserver/screen.cpp 2015-10-16 17:43:47 +0000 |
| 2086 | +++ src/platforms/mirserver/screen.cpp 2015-10-16 17:43:47 +0000 |
| 2087 | @@ -20,12 +20,14 @@ |
| 2088 | |
| 2089 | // Mir |
| 2090 | #include "mir/geometry/size.h" |
| 2091 | +#include "mir/graphics/buffer.h" |
| 2092 | +#include "mir/graphics/display_buffer.h" |
| 2093 | +#include "mir/graphics/display.h" |
| 2094 | +#include <mir/renderer/gl/render_target.h> |
| 2095 | |
| 2096 | // Qt |
| 2097 | #include <QCoreApplication> |
| 2098 | #include <qpa/qwindowsysteminterface.h> |
| 2099 | -#include <QtSensors/QOrientationSensor> |
| 2100 | -#include <QtSensors/QOrientationReading> |
| 2101 | #include <QThread> |
| 2102 | |
| 2103 | // Qt sensors |
| 2104 | @@ -42,6 +44,17 @@ |
| 2105 | char *c = (char*)&i; |
| 2106 | return *c == 1; |
| 2107 | } |
| 2108 | +static mir::renderer::gl::RenderTarget *as_render_target( |
| 2109 | + mir::graphics::DisplayBuffer *displayBuffer) |
| 2110 | +{ |
| 2111 | + auto const render_target = |
| 2112 | + dynamic_cast<mir::renderer::gl::RenderTarget*>( |
| 2113 | + displayBuffer->native_display_buffer()); |
| 2114 | + if (!render_target) |
| 2115 | + throw std::logic_error("DisplayBuffer does not support GL rendering"); |
| 2116 | + |
| 2117 | + return render_target; |
| 2118 | +} |
| 2119 | |
| 2120 | enum QImage::Format qImageFormatFromMirPixelFormat(MirPixelFormat mirPixelFormat) { |
| 2121 | switch (mirPixelFormat) { |
| 2122 | @@ -102,12 +115,15 @@ |
| 2123 | |
| 2124 | bool Screen::skipDBusRegistration = false; |
| 2125 | |
| 2126 | -Screen::Screen(mir::graphics::DisplayConfigurationOutput const &screen) |
| 2127 | +Screen::Screen(const mir::graphics::DisplayConfigurationOutput &screen) |
| 2128 | : QObject(nullptr) |
| 2129 | + , m_renderTarget(nullptr) |
| 2130 | + , m_displayGroup(nullptr) |
| 2131 | , m_orientationSensor(new QOrientationSensor(this)) |
| 2132 | + , m_screenWindow(nullptr) |
| 2133 | , m_unityScreen(nullptr) |
| 2134 | { |
| 2135 | - readMirDisplayConfiguration(screen); |
| 2136 | + setMirDisplayConfiguration(screen); |
| 2137 | |
| 2138 | // Set the default orientation based on the initial screen dimmensions. |
| 2139 | m_nativeOrientation = (m_geometry.width() >= m_geometry.height()) |
| 2140 | @@ -139,6 +155,14 @@ |
| 2141 | } |
| 2142 | } |
| 2143 | |
| 2144 | +Screen::~Screen() |
| 2145 | +{ |
| 2146 | + //if a ScreenWindow associated with this screen, kill it |
| 2147 | + if (m_screenWindow) { |
| 2148 | + m_screenWindow->window()->destroy(); // ends up destroying m_ScreenWindow |
| 2149 | + } |
| 2150 | +} |
| 2151 | + |
| 2152 | bool Screen::orientationSensorEnabled() |
| 2153 | { |
| 2154 | return m_orientationSensor->isActive(); |
| 2155 | @@ -150,8 +174,15 @@ |
| 2156 | toggleSensors(status); |
| 2157 | } |
| 2158 | |
| 2159 | -void Screen::readMirDisplayConfiguration(mir::graphics::DisplayConfigurationOutput const &screen) |
| 2160 | +void Screen::setMirDisplayConfiguration(const mir::graphics::DisplayConfigurationOutput &screen) |
| 2161 | { |
| 2162 | + // Note: DisplayConfigurationOutput will be destroyed after this function returns |
| 2163 | + |
| 2164 | + // Output data - each output has a unique id and corresponding type. Can be multiple cards. |
| 2165 | + m_outputId = screen.id; |
| 2166 | + m_cardId = screen.card_id; |
| 2167 | + m_type = screen.type; |
| 2168 | + |
| 2169 | // Physical screen size |
| 2170 | m_physicalSize.setWidth(screen.physical_size_mm.width.as_float()); |
| 2171 | m_physicalSize.setHeight(screen.physical_size_mm.height.as_float()); |
| 2172 | @@ -162,12 +193,34 @@ |
| 2173 | // Pixel depth |
| 2174 | m_depth = 8 * MIR_BYTES_PER_PIXEL(screen.current_format); |
| 2175 | |
| 2176 | - // Mode = Resolution & refresh rate |
| 2177 | + // Power mode |
| 2178 | + m_powerMode = screen.power_mode; |
| 2179 | + |
| 2180 | + QRect oldGeometry = m_geometry; |
| 2181 | + // Position of screen in virtual desktop coordinate space |
| 2182 | + m_geometry.setTop(screen.top_left.y.as_int()); |
| 2183 | + m_geometry.setLeft(screen.top_left.x.as_int()); |
| 2184 | + |
| 2185 | + // Mode = current resolution & refresh rate |
| 2186 | mir::graphics::DisplayConfigurationMode mode = screen.modes.at(screen.current_mode_index); |
| 2187 | m_geometry.setWidth(mode.size.width.as_int()); |
| 2188 | m_geometry.setHeight(mode.size.height.as_int()); |
| 2189 | |
| 2190 | - m_refreshRate = mode.vrefresh_hz; |
| 2191 | + // DPI - unnecessary to calculate, default implementation in QPlatformScreen is sufficient |
| 2192 | + |
| 2193 | + // Check for Screen geometry change |
| 2194 | + if (m_geometry != oldGeometry) { |
| 2195 | + QWindowSystemInterface::handleScreenGeometryChange(this->screen(), m_geometry, m_geometry); |
| 2196 | + if (m_screenWindow) { // resize corresponding window immediately |
| 2197 | + m_screenWindow->setGeometry(m_geometry); |
| 2198 | + } |
| 2199 | + } |
| 2200 | + |
| 2201 | + // Refresh rate |
| 2202 | + if (m_refreshRate != mode.vrefresh_hz) { |
| 2203 | + m_refreshRate = mode.vrefresh_hz; |
| 2204 | + QWindowSystemInterface::handleScreenRefreshRateChange(this->screen(), mode.vrefresh_hz); |
| 2205 | + } |
| 2206 | } |
| 2207 | |
| 2208 | void Screen::toggleSensors(const bool enable) const |
| 2209 | @@ -232,3 +285,52 @@ |
| 2210 | const QPlatformCursor *platformCursor = &m_cursor; |
| 2211 | return const_cast<QPlatformCursor *>(platformCursor); |
| 2212 | } |
| 2213 | + |
| 2214 | +ScreenWindow *Screen::window() const |
| 2215 | +{ |
| 2216 | + return m_screenWindow; |
| 2217 | +} |
| 2218 | + |
| 2219 | +void Screen::setWindow(ScreenWindow *window) |
| 2220 | +{ |
| 2221 | + if (window && m_screenWindow) { |
| 2222 | + qCDebug(QTMIR_SENSOR_MESSAGES) << "Screen::setWindow - overwriting existing ScreenWindow"; |
| 2223 | + } |
| 2224 | + m_screenWindow = window; |
| 2225 | +} |
| 2226 | + |
| 2227 | +void Screen::setMirDisplayBuffer(mir::graphics::DisplayBuffer *buffer, mir::graphics::DisplaySyncGroup *group) |
| 2228 | +{ |
| 2229 | + qCDebug(QTMIR_SCREENS) << "Screen::setMirDisplayBuffer" << buffer << group; |
| 2230 | + // This operation should only be performed while rendering is stopped |
| 2231 | + m_renderTarget = as_render_target(buffer); |
| 2232 | + m_displayGroup = group; |
| 2233 | +} |
| 2234 | + |
| 2235 | +void Screen::swapBuffers() |
| 2236 | +{ |
| 2237 | + m_renderTarget->swap_buffers(); |
| 2238 | + |
| 2239 | + /* FIXME this exposes a QtMir architecture problem, as Screen is supposed to wrap a mg::DisplayBuffer. |
| 2240 | + * We use Qt's multithreaded renderer, where each Screen is rendered to relatively independently, and |
| 2241 | + * post() called also individually. |
| 2242 | + * |
| 2243 | + * But if this is a native server on Android, in the multimonitor case a DisplaySyncGroup can contain |
| 2244 | + * 2+ DisplayBuffers, one post() call will submit all mg::DisplayBuffers in the group for flipping. |
| 2245 | + * This will cause just one Screen to be updated, blocking the swap call for the other Screens, which |
| 2246 | + * will slow rendering dramatically. |
| 2247 | + * |
| 2248 | + * Integrating the Qt Scenegraph renderer as a Mir renderer should solve this issue. |
| 2249 | + */ |
| 2250 | + m_displayGroup->post(); |
| 2251 | +} |
| 2252 | + |
| 2253 | +void Screen::makeCurrent() |
| 2254 | +{ |
| 2255 | + m_renderTarget->make_current(); |
| 2256 | +} |
| 2257 | + |
| 2258 | +void Screen::doneCurrent() |
| 2259 | +{ |
| 2260 | + m_renderTarget->release_current(); |
| 2261 | +} |
| 2262 | |
| 2263 | === modified file 'src/platforms/mirserver/screen.h' |
| 2264 | --- src/platforms/mirserver/screen.h 2015-10-16 17:43:47 +0000 |
| 2265 | +++ src/platforms/mirserver/screen.h 2015-10-16 17:43:47 +0000 |
| 2266 | @@ -17,22 +17,31 @@ |
| 2267 | #ifndef SCREEN_H |
| 2268 | #define SCREEN_H |
| 2269 | |
| 2270 | +// Qt |
| 2271 | #include <QObject> |
| 2272 | #include <QTimer> |
| 2273 | #include <QtDBus/QDBusInterface> |
| 2274 | #include <qpa/qplatformscreen.h> |
| 2275 | |
| 2276 | +// Mir |
| 2277 | #include <mir/graphics/display_configuration.h> |
| 2278 | |
| 2279 | +// local |
| 2280 | #include "cursor.h" |
| 2281 | +#include "screenwindow.h" |
| 2282 | |
| 2283 | class QOrientationSensor; |
| 2284 | +namespace mir { |
| 2285 | + namespace graphics { class DisplayBuffer; class DisplaySyncGroup; } |
| 2286 | + namespace renderer { namespace gl { class RenderTarget; }} |
| 2287 | +} |
| 2288 | |
| 2289 | class Screen : public QObject, public QPlatformScreen |
| 2290 | { |
| 2291 | Q_OBJECT |
| 2292 | public: |
| 2293 | - Screen(mir::graphics::DisplayConfigurationOutput const&); |
| 2294 | + Screen(const mir::graphics::DisplayConfigurationOutput &); |
| 2295 | + ~Screen(); |
| 2296 | |
| 2297 | // QPlatformScreen methods. |
| 2298 | QRect geometry() const override { return m_geometry; } |
| 2299 | @@ -45,6 +54,9 @@ |
| 2300 | QPlatformCursor *cursor() const override; |
| 2301 | |
| 2302 | void toggleSensors(const bool enable) const; |
| 2303 | + mir::graphics::DisplayConfigurationOutputType outputType() const { return m_type; } |
| 2304 | + |
| 2305 | + ScreenWindow* window() const; |
| 2306 | |
| 2307 | // QObject methods. |
| 2308 | void customEvent(QEvent* event) override; |
| 2309 | @@ -57,22 +69,40 @@ |
| 2310 | void onDisplayPowerStateChanged(int, int); |
| 2311 | void onOrientationReadingChanged(); |
| 2312 | |
| 2313 | +protected: |
| 2314 | + void setWindow(ScreenWindow *window); |
| 2315 | + |
| 2316 | + void setMirDisplayConfiguration(const mir::graphics::DisplayConfigurationOutput &); |
| 2317 | + void setMirDisplayBuffer(mir::graphics::DisplayBuffer *, mir::graphics::DisplaySyncGroup *); |
| 2318 | + void swapBuffers(); |
| 2319 | + void makeCurrent(); |
| 2320 | + void doneCurrent(); |
| 2321 | + |
| 2322 | private: |
| 2323 | - void readMirDisplayConfiguration(mir::graphics::DisplayConfigurationOutput const&); |
| 2324 | - |
| 2325 | QRect m_geometry; |
| 2326 | int m_depth; |
| 2327 | QImage::Format m_format; |
| 2328 | QSizeF m_physicalSize; |
| 2329 | qreal m_refreshRate; |
| 2330 | |
| 2331 | + mir::renderer::gl::RenderTarget *m_renderTarget; |
| 2332 | + mir::graphics::DisplaySyncGroup *m_displayGroup; |
| 2333 | + mir::graphics::DisplayConfigurationOutputId m_outputId; |
| 2334 | + mir::graphics::DisplayConfigurationCardId m_cardId; |
| 2335 | + mir::graphics::DisplayConfigurationOutputType m_type; |
| 2336 | + MirPowerMode m_powerMode; |
| 2337 | + |
| 2338 | Qt::ScreenOrientation m_nativeOrientation; |
| 2339 | Qt::ScreenOrientation m_currentOrientation; |
| 2340 | QOrientationSensor *m_orientationSensor; |
| 2341 | |
| 2342 | + ScreenWindow *m_screenWindow; |
| 2343 | QDBusInterface *m_unityScreen; |
| 2344 | |
| 2345 | qtmir::Cursor m_cursor; |
| 2346 | + |
| 2347 | + friend class ScreenController; |
| 2348 | + friend class ScreenWindow; |
| 2349 | }; |
| 2350 | |
| 2351 | #endif // SCREEN_H |
| 2352 | |
| 2353 | === added file 'src/platforms/mirserver/screencontroller.cpp' |
| 2354 | --- src/platforms/mirserver/screencontroller.cpp 1970-01-01 00:00:00 +0000 |
| 2355 | +++ src/platforms/mirserver/screencontroller.cpp 2015-10-16 17:43:47 +0000 |
| 2356 | @@ -0,0 +1,211 @@ |
| 2357 | +/* |
| 2358 | + * Copyright (C) 2015 Canonical, Ltd. |
| 2359 | + * |
| 2360 | + * This program is free software: you can redistribute it and/or modify it under |
| 2361 | + * the terms of the GNU Lesser General Public License version 3, as published by |
| 2362 | + * the Free Software Foundation. |
| 2363 | + * |
| 2364 | + * This program is distributed in the hope that it will be useful, but WITHOUT |
| 2365 | + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
| 2366 | + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 2367 | + * Lesser General Public License for more details. |
| 2368 | + * |
| 2369 | + * You should have received a copy of the GNU Lesser General Public License |
| 2370 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 2371 | + */ |
| 2372 | + |
| 2373 | +#include "screencontroller.h" |
| 2374 | + |
| 2375 | +#include "screenwindow.h" |
| 2376 | +#include "qtcompositor.h" |
| 2377 | +#include "logging.h" |
| 2378 | +#include "mirserverintegration.h" |
| 2379 | +#include "screen.h" |
| 2380 | + |
| 2381 | +// Mir |
| 2382 | +#include <mir/graphics/display.h> |
| 2383 | +#include <mir/graphics/display_buffer.h> |
| 2384 | + |
| 2385 | +// Qt |
| 2386 | +#include <QScreen> |
| 2387 | +#include <QQuickWindow> |
| 2388 | +#include <qpa/qwindowsysteminterface.h> |
| 2389 | +#include <QGuiApplication> // for qApp |
| 2390 | + |
| 2391 | +// std |
| 2392 | +#include <memory> |
| 2393 | + |
| 2394 | +Q_LOGGING_CATEGORY(QTMIR_SCREENS, "qtmir.screens") |
| 2395 | + |
| 2396 | +namespace mg = mir::graphics; |
| 2397 | + |
| 2398 | + |
| 2399 | +ScreenController::ScreenController(QObject *parent) |
| 2400 | + : QObject(parent) |
| 2401 | + , m_compositing(false) |
| 2402 | +{ |
| 2403 | + qCDebug(QTMIR_SCREENS) << "ScreenController::ScreenController"; |
| 2404 | +} |
| 2405 | + |
| 2406 | +// init only after MirServer has initialized - runs on MirServerThread!!! |
| 2407 | +void ScreenController::init(const std::shared_ptr<mir::graphics::Display> &display, |
| 2408 | + const std::shared_ptr<mir::compositor::Compositor> &compositor) |
| 2409 | +{ |
| 2410 | + m_display = display; |
| 2411 | + m_compositor = compositor; |
| 2412 | + |
| 2413 | + // Use a Blocking Queued Connection to enforce synchronization of Qt GUI thread with Mir thread(s) |
| 2414 | + // on compositor shutdown. Compositor startup can be lazy. |
| 2415 | + // Queued connections work because the thread affinity of this class is with the Qt GUI thread. |
| 2416 | + auto qtCompositor = static_cast<QtCompositor *>(compositor.get()); |
| 2417 | + connect(qtCompositor, &QtCompositor::starting, |
| 2418 | + this, &ScreenController::onCompositorStarting); |
| 2419 | + connect(qtCompositor, &QtCompositor::stopping, |
| 2420 | + this, &ScreenController::onCompositorStopping, Qt::BlockingQueuedConnection); |
| 2421 | +} |
| 2422 | + |
| 2423 | +// terminate before shutting down the Mir server, or else liable to deadlock with the blocking connection above |
| 2424 | +// Runs on MirServerThread!!! |
| 2425 | +void ScreenController::terminate() |
| 2426 | +{ |
| 2427 | + auto qtCompositor = static_cast<QtCompositor *>(m_compositor.get()); |
| 2428 | + qtCompositor->disconnect(); |
| 2429 | +} |
| 2430 | + |
| 2431 | +void ScreenController::onCompositorStarting() |
| 2432 | +{ |
| 2433 | + qCDebug(QTMIR_SCREENS) << "ScreenController::onCompositorStarting"; |
| 2434 | + m_compositing = true; |
| 2435 | + |
| 2436 | + update(); |
| 2437 | + |
| 2438 | + // (Re)Start Qt's render thread by setting all windows with a corresponding screen to exposed. |
| 2439 | + for (auto screen : m_screenList) { |
| 2440 | + auto window = static_cast<ScreenWindow *>(screen->window()); |
| 2441 | + if (window && window->window()) { |
| 2442 | + window->setExposed(true); |
| 2443 | + } |
| 2444 | + } |
| 2445 | +} |
| 2446 | + |
| 2447 | +void ScreenController::onCompositorStopping() |
| 2448 | +{ |
| 2449 | + qCDebug(QTMIR_SCREENS) << "ScreenController::onCompositorStopping"; |
| 2450 | + m_compositing = false; |
| 2451 | + |
| 2452 | + // Stop Qt's render threads by setting all its windows it obscured. Must |
| 2453 | + // block until all windows have their GL contexts released. |
| 2454 | + for (auto screen : m_screenList) { |
| 2455 | + auto window = static_cast<ScreenWindow *>(screen->window()); |
| 2456 | + if (window && window->window()) { |
| 2457 | + window->setExposed(false); |
| 2458 | + } |
| 2459 | + } |
| 2460 | + |
| 2461 | + update(); |
| 2462 | +} |
| 2463 | + |
| 2464 | +void ScreenController::update() |
| 2465 | +{ |
| 2466 | + qCDebug(QTMIR_SCREENS) << "ScreenController::update"; |
| 2467 | + auto display = m_display.lock(); |
| 2468 | + if (!display) |
| 2469 | + return; |
| 2470 | + auto displayConfig = display->configuration(); |
| 2471 | + |
| 2472 | + // Mir only tells us something changed, it is up to us to figure out what. |
| 2473 | + QList<Screen*> newScreenList; |
| 2474 | + QList<Screen*> oldScreenList = m_screenList; |
| 2475 | + m_screenList.clear(); |
| 2476 | + |
| 2477 | + displayConfig->for_each_output( |
| 2478 | + [this, &oldScreenList, &newScreenList](const mg::DisplayConfigurationOutput &output) { |
| 2479 | + if (output.used && output.connected) { |
| 2480 | + Screen *screen = findScreenWithId(oldScreenList, output.id); |
| 2481 | + if (screen) { // we've already set up this display before, refresh its internals |
| 2482 | + screen->setMirDisplayConfiguration(output); |
| 2483 | + oldScreenList.removeAll(screen); |
| 2484 | + } else { |
| 2485 | + // new display, so create Screen for it |
| 2486 | + screen = this->createScreen(output); |
| 2487 | + newScreenList.append(screen); |
| 2488 | + qCDebug(QTMIR_SCREENS) << "Added Screen with id" << output.id.as_value() |
| 2489 | + << "and geometry" << screen->geometry(); |
| 2490 | + } |
| 2491 | + m_screenList.append(screen); |
| 2492 | + } |
| 2493 | + } |
| 2494 | + ); |
| 2495 | + |
| 2496 | + // Delete any old & unused Screens |
| 2497 | + for (auto screen: oldScreenList) { |
| 2498 | + qCDebug(QTMIR_SCREENS) << "Removed Screen with id" << screen->m_outputId.as_value() |
| 2499 | + << "and geometry" << screen->geometry(); |
| 2500 | + // The screen is automatically removed from Qt's internal list by the QPlatformScreen destructor. |
| 2501 | + auto window = static_cast<ScreenWindow *>(screen->window()); |
| 2502 | + if (window && window->window() && window->isExposed()) { |
| 2503 | + window->window()->hide(); |
| 2504 | + } |
| 2505 | + bool ok = QMetaObject::invokeMethod(qApp, "onScreenAboutToBeRemoved", Qt::DirectConnection, Q_ARG(QScreen*, screen->screen())); |
| 2506 | + if (!ok) { |
| 2507 | + qCWarning(QTMIR_SCREENS) << "Failed to invoke QGuiApplication::onScreenAboutToBeRemoved(QScreen*) slot."; |
| 2508 | + } |
| 2509 | + delete screen; |
| 2510 | + } |
| 2511 | + |
| 2512 | + // Match up the new Mir DisplayBuffers with each Screen |
| 2513 | + display->for_each_display_sync_group([&](mg::DisplaySyncGroup &group) { |
| 2514 | + group.for_each_display_buffer([&](mg::DisplayBuffer &buffer) { |
| 2515 | + // only way to match Screen to a DisplayBuffer is by matching the geometry |
| 2516 | + QRect dbGeom(buffer.view_area().top_left.x.as_int(), |
| 2517 | + buffer.view_area().top_left.y.as_int(), |
| 2518 | + buffer.view_area().size.width.as_int(), |
| 2519 | + buffer.view_area().size.height.as_int()); |
| 2520 | + |
| 2521 | + for (auto screen : m_screenList) { |
| 2522 | + if (dbGeom == screen->geometry()) { |
| 2523 | + screen->setMirDisplayBuffer(&buffer, &group); |
| 2524 | + break; |
| 2525 | + } |
| 2526 | + } |
| 2527 | + }); |
| 2528 | + }); |
| 2529 | + |
| 2530 | + qCDebug(QTMIR_SCREENS) << "======================================="; |
| 2531 | + for (auto screen: m_screenList) { |
| 2532 | + qCDebug(QTMIR_SCREENS) << screen << "- id:" << screen->m_outputId.as_value() |
| 2533 | + << "geometry:" << screen->geometry() |
| 2534 | + << "window:" << screen->window() |
| 2535 | + << "type" << static_cast<int>(screen->outputType()); |
| 2536 | + } |
| 2537 | + qCDebug(QTMIR_SCREENS) << "======================================="; |
| 2538 | + |
| 2539 | + for (auto screen : newScreenList) { |
| 2540 | + Q_EMIT screenAdded(screen); |
| 2541 | + } |
| 2542 | +} |
| 2543 | + |
| 2544 | +Screen* ScreenController::createScreen(const mir::graphics::DisplayConfigurationOutput &output) const |
| 2545 | +{ |
| 2546 | + return new Screen(output); |
| 2547 | +} |
| 2548 | + |
| 2549 | +Screen* ScreenController::findScreenWithId(const QList<Screen *> &list, const mg::DisplayConfigurationOutputId id) |
| 2550 | +{ |
| 2551 | + for (Screen *screen : list) { |
| 2552 | + if (screen->m_outputId == id) { |
| 2553 | + return screen; |
| 2554 | + } |
| 2555 | + } |
| 2556 | + return nullptr; |
| 2557 | +} |
| 2558 | + |
| 2559 | +QWindow* ScreenController::getWindowForPoint(const QPoint &point) //FIXME - not thread safe & not efficient |
| 2560 | +{ |
| 2561 | + for (Screen *screen : m_screenList) { |
| 2562 | + if (screen->window() && screen->geometry().contains(point)) { |
| 2563 | + return screen->window()->window(); |
| 2564 | + } |
| 2565 | + } |
| 2566 | + return nullptr; |
| 2567 | +} |
| 2568 | |
| 2569 | === added file 'src/platforms/mirserver/screencontroller.h' |
| 2570 | --- src/platforms/mirserver/screencontroller.h 1970-01-01 00:00:00 +0000 |
| 2571 | +++ src/platforms/mirserver/screencontroller.h 2015-10-16 17:43:47 +0000 |
| 2572 | @@ -0,0 +1,95 @@ |
| 2573 | +/* |
| 2574 | + * Copyright (C) 2015 Canonical, Ltd. |
| 2575 | + * |
| 2576 | + * This program is free software: you can redistribute it and/or modify it under |
| 2577 | + * the terms of the GNU Lesser General Public License version 3, as published by |
| 2578 | + * the Free Software Foundation. |
| 2579 | + * |
| 2580 | + * This program is distributed in the hope that it will be useful, but WITHOUT |
| 2581 | + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
| 2582 | + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 2583 | + * Lesser General Public License for more details. |
| 2584 | + * |
| 2585 | + * You should have received a copy of the GNU Lesser General Public License |
| 2586 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 2587 | + */ |
| 2588 | + |
| 2589 | +#ifndef SCREENCONTROLLER_H |
| 2590 | +#define SCREENCONTROLLER_H |
| 2591 | + |
| 2592 | +#include <QObject> |
| 2593 | +#include <QPoint> |
| 2594 | + |
| 2595 | +// Mir |
| 2596 | +#include <mir/graphics/display_configuration.h> |
| 2597 | + |
| 2598 | +// std |
| 2599 | +#include <memory> |
| 2600 | + |
| 2601 | +namespace mir { |
| 2602 | + namespace graphics { class Display; } |
| 2603 | + namespace compositor { class Compositor; } |
| 2604 | +} |
| 2605 | +class Screen; |
| 2606 | +class QWindow; |
| 2607 | + |
| 2608 | +/* |
| 2609 | + * ScreenController monitors the Mir display configuration and compositor status, and updates |
| 2610 | + * the relevant QScreen and QWindow states accordingly. |
| 2611 | + * |
| 2612 | + * Primary purposes are: |
| 2613 | + * 1. to update QScreen state on Mir display configuration changes |
| 2614 | + * 2. to stop the Qt renderer by hiding its QWindow when Mir wants to stop all compositing, |
| 2615 | + * and resume Qt's renderer by showing its QWindow when Mir wants to resume compositing. |
| 2616 | + * |
| 2617 | + * |
| 2618 | + * Threading Note: |
| 2619 | + * This object must have affinity to the main Qt GUI thread, as it creates & destroys Platform |
| 2620 | + * objects which Qt uses internally. However beware as the init() & terminate() methods need to |
| 2621 | + * be called on the MirServerThread thread, as we need to monitor the screen state *after* |
| 2622 | + * Mir has initialized but before Qt's event loop has started, and tear down before Mir terminates. |
| 2623 | + * Also note the MirServerThread does not have an QEventLoop. |
| 2624 | + * |
| 2625 | + * All other methods must be called on the Qt GUI thread. |
| 2626 | + */ |
| 2627 | + |
| 2628 | +class ScreenController : public QObject |
| 2629 | +{ |
| 2630 | + Q_OBJECT |
| 2631 | +public: |
| 2632 | + explicit ScreenController(QObject *parent = 0); |
| 2633 | + |
| 2634 | + QList<Screen*> screens() const { return m_screenList; } |
| 2635 | + bool compositing() const { return m_compositing; } |
| 2636 | + |
| 2637 | + QWindow* getWindowForPoint(const QPoint &point); |
| 2638 | + |
| 2639 | +Q_SIGNALS: |
| 2640 | + void screenAdded(Screen *screen); |
| 2641 | + |
| 2642 | +public Q_SLOTS: |
| 2643 | + void update(); |
| 2644 | + |
| 2645 | +public: |
| 2646 | + // called by MirServer |
| 2647 | + void init(const std::shared_ptr<mir::graphics::Display> &display, |
| 2648 | + const std::shared_ptr<mir::compositor::Compositor> &compositor); |
| 2649 | + void terminate(); |
| 2650 | + |
| 2651 | + // override for testing purposes |
| 2652 | + virtual Screen *createScreen(const mir::graphics::DisplayConfigurationOutput &output) const; |
| 2653 | + |
| 2654 | +protected Q_SLOTS: |
| 2655 | + void onCompositorStarting(); |
| 2656 | + void onCompositorStopping(); |
| 2657 | + |
| 2658 | +private: |
| 2659 | + Screen* findScreenWithId(const QList<Screen*> &list, const mir::graphics::DisplayConfigurationOutputId id); |
| 2660 | + |
| 2661 | + std::weak_ptr<mir::graphics::Display> m_display; |
| 2662 | + std::shared_ptr<mir::compositor::Compositor> m_compositor; |
| 2663 | + QList<Screen*> m_screenList; |
| 2664 | + bool m_compositing; |
| 2665 | +}; |
| 2666 | + |
| 2667 | +#endif // SCREENCONTROLLER_H |
| 2668 | |
| 2669 | === renamed file 'src/platforms/mirserver/displaywindow.cpp' => 'src/platforms/mirserver/screenwindow.cpp' |
| 2670 | --- src/platforms/mirserver/displaywindow.cpp 2015-10-07 14:38:44 +0000 |
| 2671 | +++ src/platforms/mirserver/screenwindow.cpp 2015-10-16 17:43:47 +0000 |
| 2672 | @@ -14,15 +14,22 @@ |
| 2673 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 2674 | */ |
| 2675 | |
| 2676 | -#include "displaywindow.h" |
| 2677 | - |
| 2678 | -#include "mir/geometry/size.h" |
| 2679 | - |
| 2680 | +#include "screenwindow.h" |
| 2681 | +#include "screen.h" |
| 2682 | + |
| 2683 | +// Mir |
| 2684 | +#include <mir/geometry/size.h> |
| 2685 | +#include <mir/graphics/display_buffer.h> |
| 2686 | + |
| 2687 | +// Qt |
| 2688 | #include <qpa/qwindowsysteminterface.h> |
| 2689 | #include <qpa/qplatformscreen.h> |
| 2690 | - |
| 2691 | +#include <QQuickWindow> |
| 2692 | +#include <QtQuick/private/qsgrenderloop_p.h> |
| 2693 | #include <QDebug> |
| 2694 | |
| 2695 | +#include "logging.h" |
| 2696 | + |
| 2697 | static WId newWId() |
| 2698 | { |
| 2699 | static WId id = 0; |
| 2700 | @@ -33,106 +40,74 @@ |
| 2701 | return ++id; |
| 2702 | } |
| 2703 | |
| 2704 | -static mir::renderer::gl::RenderTarget *as_render_target( |
| 2705 | - mir::graphics::DisplayBuffer *displayBuffer) |
| 2706 | -{ |
| 2707 | - auto const render_target = |
| 2708 | - dynamic_cast<mir::renderer::gl::RenderTarget*>( |
| 2709 | - displayBuffer->native_display_buffer()); |
| 2710 | - if (!render_target) |
| 2711 | - throw std::logic_error("DisplayBuffer does not support GL rendering"); |
| 2712 | - |
| 2713 | - return render_target; |
| 2714 | -} |
| 2715 | - |
| 2716 | -DisplayWindow::DisplayWindow( |
| 2717 | - QWindow *window, |
| 2718 | - mir::graphics::DisplaySyncGroup *displayGroup, |
| 2719 | - mir::graphics::DisplayBuffer *displayBuffer) |
| 2720 | - : QObject(nullptr), QPlatformWindow(window) |
| 2721 | - , m_isExposed(true) |
| 2722 | +ScreenWindow::ScreenWindow(QWindow *window) |
| 2723 | + : QPlatformWindow(window) |
| 2724 | + , m_exposed(false) |
| 2725 | , m_winId(newWId()) |
| 2726 | - , m_displayGroup(displayGroup) |
| 2727 | - , m_renderTarget(as_render_target(displayBuffer)) |
| 2728 | { |
| 2729 | - qDebug() << "DisplayWindow::DisplayWindow"; |
| 2730 | - qWarning("Window %p: %p 0x%x\n", this, window, uint(m_winId)); |
| 2731 | + // Register with the Screen it is associated with |
| 2732 | + auto myScreen = static_cast<Screen *>(screen()); |
| 2733 | + Q_ASSERT(myScreen); |
| 2734 | + myScreen->setWindow(this); |
| 2735 | + |
| 2736 | + qCDebug(QTMIR_SCREENS) << "ScreenWindow" << this << "with window ID" << uint(m_winId) << "backed by" << myScreen; |
| 2737 | |
| 2738 | QRect screenGeometry(screen()->availableGeometry()); |
| 2739 | if (window->geometry() != screenGeometry) { |
| 2740 | setGeometry(screenGeometry); |
| 2741 | + window->setGeometry(screenGeometry); |
| 2742 | } |
| 2743 | window->setSurfaceType(QSurface::OpenGLSurface); |
| 2744 | - |
| 2745 | - // The compositor window is always active. I.e., it's always focused so that |
| 2746 | - // it always processes key events, etc |
| 2747 | - requestActivateWindow(); |
| 2748 | -} |
| 2749 | - |
| 2750 | -QRect DisplayWindow::geometry() const |
| 2751 | -{ |
| 2752 | - // For yet-to-become-fullscreen windows report the geometry covering the entire |
| 2753 | - // screen. This is particularly important for Quick where the root object may get |
| 2754 | - // sized to some geometry queried before calling create(). |
| 2755 | - return screen()->availableGeometry(); |
| 2756 | -} |
| 2757 | - |
| 2758 | -void DisplayWindow::setGeometry(const QRect &) |
| 2759 | -{ |
| 2760 | - // We only support full-screen windows |
| 2761 | - QRect rect(screen()->availableGeometry()); |
| 2762 | - QWindowSystemInterface::handleGeometryChange(window(), rect); |
| 2763 | - QPlatformWindow::setGeometry(rect); |
| 2764 | -} |
| 2765 | - |
| 2766 | -bool DisplayWindow::isExposed() const |
| 2767 | -{ |
| 2768 | - return m_isExposed; |
| 2769 | -} |
| 2770 | - |
| 2771 | -bool DisplayWindow::event(QEvent *event) |
| 2772 | -{ |
| 2773 | - // Intercept Hide event and convert to Expose event, as Hide causes Qt to release GL |
| 2774 | - // resources, which we don't want. Must intercept Show to un-do hide. |
| 2775 | - if (event->type() == QEvent::Hide) { |
| 2776 | - qDebug() << "DisplayWindow::event got QEvent::Hide"; |
| 2777 | - m_isExposed = false; |
| 2778 | - QWindowSystemInterface::handleExposeEvent(window(), QRect()); |
| 2779 | - QWindowSystemInterface::flushWindowSystemEvents(); |
| 2780 | - return true; |
| 2781 | - } else if (event->type() == QEvent::Show) { |
| 2782 | - qDebug() << "DisplayWindow::event got QEvent::Show"; |
| 2783 | - m_isExposed = true; |
| 2784 | - QRect rect(QPoint(), geometry().size()); |
| 2785 | - QWindowSystemInterface::handleExposeEvent(window(), rect); |
| 2786 | - QWindowSystemInterface::flushWindowSystemEvents(); |
| 2787 | - return true; |
| 2788 | +} |
| 2789 | + |
| 2790 | +ScreenWindow::~ScreenWindow() |
| 2791 | +{ |
| 2792 | + qCDebug(QTMIR_SCREENS) << "Destroying ScreenWindow" << this; |
| 2793 | + static_cast<Screen *>(screen())->setWindow(nullptr); |
| 2794 | +} |
| 2795 | + |
| 2796 | +bool ScreenWindow::isExposed() const |
| 2797 | +{ |
| 2798 | + return m_exposed; |
| 2799 | +} |
| 2800 | + |
| 2801 | +void ScreenWindow::setExposed(const bool exposed) |
| 2802 | +{ |
| 2803 | + qCDebug(QTMIR_SCREENS) << "ScreenWindow::setExposed" << this << exposed; |
| 2804 | + if (m_exposed == exposed) |
| 2805 | + return; |
| 2806 | + |
| 2807 | + m_exposed = exposed; |
| 2808 | + if (!window()) |
| 2809 | + return; |
| 2810 | + |
| 2811 | + // If backing a QQuickWindow, need to stop/start its renderer immediately |
| 2812 | + auto quickWindow = static_cast<QQuickWindow *>(window()); |
| 2813 | + if (!quickWindow) |
| 2814 | + return; |
| 2815 | + |
| 2816 | + auto renderer = QSGRenderLoop::instance(); |
| 2817 | + if (exposed) { |
| 2818 | + renderer->show(quickWindow); |
| 2819 | + QWindowSystemInterface::handleExposeEvent(window(), QRegion()); // else it won't redraw |
| 2820 | + } else { |
| 2821 | + quickWindow->setPersistentOpenGLContext(false); |
| 2822 | + quickWindow->setPersistentSceneGraph(false); |
| 2823 | + renderer->hide(quickWindow); // ExposeEvent will arrive too late, need to stop compositor immediately |
| 2824 | } |
| 2825 | - return QObject::event(event); |
| 2826 | -} |
| 2827 | - |
| 2828 | -void DisplayWindow::swapBuffers() |
| 2829 | -{ |
| 2830 | - m_renderTarget->swap_buffers(); |
| 2831 | - |
| 2832 | - // FIXME this exposes a QtMir architecture problem now, as DisplayWindow |
| 2833 | - // is supposed to wrap a mg::DisplayBuffer. We use Qt's multithreaded |
| 2834 | - // renderer, where each DisplayWindow is rendered to relatively |
| 2835 | - // independently, and post() called also individually. |
| 2836 | - // |
| 2837 | - // But in multimonitor case where a DisplaySyncGroup contains 2 |
| 2838 | - // DisplayBuffers, one post() call will submit both |
| 2839 | - // mg::DisplayBuffers for flipping, which can happen before the other |
| 2840 | - // DisplayWindow has been rendered to, causing visual artifacts |
| 2841 | - m_displayGroup->post(); |
| 2842 | -} |
| 2843 | - |
| 2844 | -void DisplayWindow::makeCurrent() |
| 2845 | -{ |
| 2846 | - m_renderTarget->make_current(); |
| 2847 | -} |
| 2848 | - |
| 2849 | -void DisplayWindow::doneCurrent() |
| 2850 | -{ |
| 2851 | - m_renderTarget->release_current(); |
| 2852 | +} |
| 2853 | + |
| 2854 | +void ScreenWindow::swapBuffers() |
| 2855 | +{ |
| 2856 | + static_cast<Screen *>(screen())->swapBuffers(); |
| 2857 | +} |
| 2858 | + |
| 2859 | +void ScreenWindow::makeCurrent() |
| 2860 | +{ |
| 2861 | + static_cast<Screen *>(screen())->makeCurrent(); |
| 2862 | +} |
| 2863 | + |
| 2864 | +void ScreenWindow::doneCurrent() |
| 2865 | +{ |
| 2866 | + static_cast<Screen *>(screen())->doneCurrent(); |
| 2867 | } |
| 2868 | |
| 2869 | === renamed file 'src/platforms/mirserver/displaywindow.h' => 'src/platforms/mirserver/screenwindow.h' |
| 2870 | --- src/platforms/mirserver/displaywindow.h 2015-10-07 14:38:44 +0000 |
| 2871 | +++ src/platforms/mirserver/screenwindow.h 2015-10-16 17:43:47 +0000 |
| 2872 | @@ -14,44 +14,33 @@ |
| 2873 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 2874 | */ |
| 2875 | |
| 2876 | -#ifndef DISPLAYWINDOW_H |
| 2877 | -#define DISPLAYWINDOW_H |
| 2878 | +#ifndef SCREENWINDOW_H |
| 2879 | +#define SCREENWINDOW_H |
| 2880 | |
| 2881 | #include <qpa/qplatformwindow.h> |
| 2882 | |
| 2883 | -#include <mir/graphics/display.h> |
| 2884 | -#include <mir/graphics/display_buffer.h> |
| 2885 | -#include <mir/renderer/gl/render_target.h> |
| 2886 | - |
| 2887 | -#include <QObject> |
| 2888 | - |
| 2889 | -// DisplayWindow wraps the whatever implementation Mir creates of a DisplayBuffer, |
| 2890 | -// which is the buffer output for an individual display. |
| 2891 | - |
| 2892 | -class DisplayWindow : public QObject, public QPlatformWindow |
| 2893 | +// ScreenWindow implements the basics of a QPlatformWindow. |
| 2894 | +// QtMir enforces one Window per Screen, so Window and Screen are tightly coupled. |
| 2895 | +// All Mir specifics live in the associated Screen object. |
| 2896 | + |
| 2897 | +class ScreenWindow : public QPlatformWindow |
| 2898 | { |
| 2899 | - Q_OBJECT |
| 2900 | public: |
| 2901 | - explicit DisplayWindow(QWindow *window, mir::graphics::DisplaySyncGroup*, mir::graphics::DisplayBuffer*); |
| 2902 | + explicit ScreenWindow(QWindow *window); |
| 2903 | + virtual ~ScreenWindow(); |
| 2904 | |
| 2905 | - QRect geometry() const override; |
| 2906 | - void setGeometry(const QRect &rect) override; |
| 2907 | + bool isExposed() const override; |
| 2908 | + void setExposed(const bool exposed); |
| 2909 | |
| 2910 | WId winId() const override { return m_winId; } |
| 2911 | |
| 2912 | - bool isExposed() const override; |
| 2913 | - |
| 2914 | - bool event(QEvent *event) override; |
| 2915 | - |
| 2916 | void swapBuffers(); |
| 2917 | void makeCurrent(); |
| 2918 | void doneCurrent(); |
| 2919 | |
| 2920 | private: |
| 2921 | - bool m_isExposed; |
| 2922 | + bool m_exposed; |
| 2923 | WId m_winId; |
| 2924 | - mir::graphics::DisplaySyncGroup *m_displayGroup; |
| 2925 | - mir::renderer::gl::RenderTarget *m_renderTarget; |
| 2926 | }; |
| 2927 | |
| 2928 | -#endif // DISPLAYWINDOW_H |
| 2929 | +#endif // SCREENWINDOW_H |
| 2930 | |
| 2931 | === added file 'src/platforms/mirserver/tileddisplayconfigurationpolicy.cpp' |
| 2932 | --- src/platforms/mirserver/tileddisplayconfigurationpolicy.cpp 1970-01-01 00:00:00 +0000 |
| 2933 | +++ src/platforms/mirserver/tileddisplayconfigurationpolicy.cpp 2015-10-16 17:43:47 +0000 |
| 2934 | @@ -0,0 +1,44 @@ |
| 2935 | +/* |
| 2936 | + * Copyright (C) 2015 Canonical, Ltd. |
| 2937 | + * |
| 2938 | + * This program is free software: you can redistribute it and/or modify it under |
| 2939 | + * the terms of the GNU Lesser General Public License version 3, as published by |
| 2940 | + * the Free Software Foundation. |
| 2941 | + * |
| 2942 | + * This program is distributed in the hope that it will be useful, but WITHOUT |
| 2943 | + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
| 2944 | + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 2945 | + * Lesser General Public License for more details. |
| 2946 | + * |
| 2947 | + * You should have received a copy of the GNU Lesser General Public License |
| 2948 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 2949 | + */ |
| 2950 | + |
| 2951 | +#include "tileddisplayconfigurationpolicy.h" |
| 2952 | + |
| 2953 | +#include <mir/graphics/display_configuration.h> |
| 2954 | +#include <mir/geometry/point.h> |
| 2955 | + |
| 2956 | +namespace mg = mir::graphics; |
| 2957 | + |
| 2958 | +TiledDisplayConfigurationPolicy::TiledDisplayConfigurationPolicy( |
| 2959 | + const std::shared_ptr<mir::graphics::DisplayConfigurationPolicy> &wrapped) |
| 2960 | + : m_wrapped(wrapped) |
| 2961 | +{ |
| 2962 | +} |
| 2963 | + |
| 2964 | +void TiledDisplayConfigurationPolicy::apply_to(mg::DisplayConfiguration& conf) |
| 2965 | +{ |
| 2966 | + int nextTopLeftPosition = 0; |
| 2967 | + |
| 2968 | + m_wrapped->apply_to(conf); |
| 2969 | + |
| 2970 | + conf.for_each_output( |
| 2971 | + [&](mg::UserDisplayConfigurationOutput& output) |
| 2972 | + { |
| 2973 | + if (output.connected && output.used) { |
| 2974 | + output.top_left = mir::geometry::Point{nextTopLeftPosition, 0}; |
| 2975 | + nextTopLeftPosition += output.modes[output.preferred_mode_index].size.width.as_int(); |
| 2976 | + } |
| 2977 | + }); |
| 2978 | +} |
| 2979 | |
| 2980 | === added file 'src/platforms/mirserver/tileddisplayconfigurationpolicy.h' |
| 2981 | --- src/platforms/mirserver/tileddisplayconfigurationpolicy.h 1970-01-01 00:00:00 +0000 |
| 2982 | +++ src/platforms/mirserver/tileddisplayconfigurationpolicy.h 2015-10-16 17:43:47 +0000 |
| 2983 | @@ -0,0 +1,35 @@ |
| 2984 | +/* |
| 2985 | + * Copyright (C) 2015 Canonical, Ltd. |
| 2986 | + * |
| 2987 | + * This program is free software: you can redistribute it and/or modify it under |
| 2988 | + * the terms of the GNU Lesser General Public License version 3, as published by |
| 2989 | + * the Free Software Foundation. |
| 2990 | + * |
| 2991 | + * This program is distributed in the hope that it will be useful, but WITHOUT |
| 2992 | + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
| 2993 | + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 2994 | + * Lesser General Public License for more details. |
| 2995 | + * |
| 2996 | + * You should have received a copy of the GNU Lesser General Public License |
| 2997 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 2998 | + */ |
| 2999 | + |
| 3000 | +#ifndef TILEDDISPLAYCONFIGURATIONPOLICY_H |
| 3001 | +#define TILEDDISPLAYCONFIGURATIONPOLICY_H |
| 3002 | + |
| 3003 | +#include <mir/graphics/display_configuration_policy.h> |
| 3004 | + |
| 3005 | +#include <memory> |
| 3006 | + |
| 3007 | +class TiledDisplayConfigurationPolicy : public mir::graphics::DisplayConfigurationPolicy |
| 3008 | +{ |
| 3009 | +public: |
| 3010 | + TiledDisplayConfigurationPolicy(const std::shared_ptr<mir::graphics::DisplayConfigurationPolicy> &wrapped); |
| 3011 | + |
| 3012 | + void apply_to(mir::graphics::DisplayConfiguration& conf) override; |
| 3013 | + |
| 3014 | +private: |
| 3015 | + const std::shared_ptr<mir::graphics::DisplayConfigurationPolicy> m_wrapped; |
| 3016 | +}; |
| 3017 | + |
| 3018 | +#endif // TILEDDISPLAYCONFIGURATIONPOLICY_H |
| 3019 | |
| 3020 | === added directory 'tests/common' |
| 3021 | === added file 'tests/common/fake_displayconfigurationoutput.h' |
| 3022 | --- tests/common/fake_displayconfigurationoutput.h 1970-01-01 00:00:00 +0000 |
| 3023 | +++ tests/common/fake_displayconfigurationoutput.h 2015-10-16 17:43:47 +0000 |
| 3024 | @@ -0,0 +1,77 @@ |
| 3025 | +/* |
| 3026 | + * Copyright (C) 2015 Canonical, Ltd. |
| 3027 | + * |
| 3028 | + * This program is free software: you can redistribute it and/or modify it under |
| 3029 | + * the terms of the GNU Lesser General Public License version 3, as published by |
| 3030 | + * the Free Software Foundation. |
| 3031 | + * |
| 3032 | + * This program is distributed in the hope that it will be useful, but WITHOUT |
| 3033 | + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
| 3034 | + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 3035 | + * Lesser General Public License for more details. |
| 3036 | + * |
| 3037 | + * You should have received a copy of the GNU Lesser General Public License |
| 3038 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 3039 | + */ |
| 3040 | + |
| 3041 | +#ifndef FAKE_DISPLAYCONFIGURATIONOUTPUT_H |
| 3042 | +#define FAKE_DISPLAYCONFIGURATIONOUTPUT_H |
| 3043 | + |
| 3044 | +#include <mir/graphics/display_configuration.h> |
| 3045 | + |
| 3046 | +namespace mg = mir::graphics; |
| 3047 | +namespace geom = mir::geometry; |
| 3048 | + |
| 3049 | +const mg::DisplayConfigurationOutput fakeOutput1 |
| 3050 | +{ |
| 3051 | + mg::DisplayConfigurationOutputId{3}, |
| 3052 | + mg::DisplayConfigurationCardId{2}, |
| 3053 | + mg::DisplayConfigurationOutputType::dvid, |
| 3054 | + { |
| 3055 | + mir_pixel_format_abgr_8888 |
| 3056 | + }, |
| 3057 | + { |
| 3058 | + {geom::Size{100, 200}, 60.0}, |
| 3059 | + {geom::Size{100, 200}, 59.0}, |
| 3060 | + {geom::Size{150, 200}, 59.0} |
| 3061 | + }, |
| 3062 | + 0, |
| 3063 | + geom::Size{1111, 2222}, |
| 3064 | + true, |
| 3065 | + true, |
| 3066 | + geom::Point(), |
| 3067 | + 2, |
| 3068 | + mir_pixel_format_abgr_8888, |
| 3069 | + mir_power_mode_on, |
| 3070 | + mir_orientation_normal, |
| 3071 | + 1.0f, |
| 3072 | + mir_form_factor_unknown |
| 3073 | +}; |
| 3074 | + |
| 3075 | +const mg::DisplayConfigurationOutput fakeOutput2 |
| 3076 | +{ |
| 3077 | + mg::DisplayConfigurationOutputId{2}, |
| 3078 | + mg::DisplayConfigurationCardId{4}, |
| 3079 | + mg::DisplayConfigurationOutputType::lvds, |
| 3080 | + { |
| 3081 | + mir_pixel_format_xbgr_8888 |
| 3082 | + }, |
| 3083 | + { |
| 3084 | + {geom::Size{800, 1200}, 90.0}, |
| 3085 | + {geom::Size{1600, 2400}, 60.0}, |
| 3086 | + {geom::Size{1500, 2000}, 75.0} |
| 3087 | + }, |
| 3088 | + 0, |
| 3089 | + geom::Size{1000, 2000}, |
| 3090 | + true, |
| 3091 | + true, |
| 3092 | + geom::Point(500, 600), |
| 3093 | + 2, |
| 3094 | + mir_pixel_format_xbgr_8888, |
| 3095 | + mir_power_mode_on, |
| 3096 | + mir_orientation_left, |
| 3097 | + 1.0f, |
| 3098 | + mir_form_factor_unknown |
| 3099 | +}; |
| 3100 | + |
| 3101 | +#endif // FAKE_DISPLAYCONFIGURATIONOUTPUT_H |
| 3102 | |
| 3103 | === added file 'tests/common/gmock_fixes.h' |
| 3104 | --- tests/common/gmock_fixes.h 1970-01-01 00:00:00 +0000 |
| 3105 | +++ tests/common/gmock_fixes.h 2015-10-16 17:43:47 +0000 |
| 3106 | @@ -0,0 +1,124 @@ |
| 3107 | +// |
| 3108 | +// Copyright © 2012 Canonical Ltd. Copyright 2007, Google Inc. |
| 3109 | +// |
| 3110 | +// All rights reserved. |
| 3111 | +// |
| 3112 | +// Redistribution and use in source and binary forms, with or without |
| 3113 | +// modification, are permitted provided that the following conditions are |
| 3114 | +// met: |
| 3115 | +// |
| 3116 | +// * Redistributions of source code must retain the above copyright |
| 3117 | +// notice, this list of conditions and the following disclaimer. |
| 3118 | +// * Redistributions in binary form must reproduce the above |
| 3119 | +// copyright notice, this list of conditions and the following disclaimer |
| 3120 | +// in the documentation and/or other materials provided with the |
| 3121 | +// distribution. |
| 3122 | +// * Neither the name of Google Inc. nor the names of its |
| 3123 | +// contributors may be used to endorse or promote products derived from |
| 3124 | +// this software without specific prior written permission. |
| 3125 | +// |
| 3126 | +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 3127 | +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 3128 | +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 3129 | +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 3130 | +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 3131 | +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 3132 | +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 3133 | +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 3134 | +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 3135 | +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 3136 | +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 3137 | +// |
| 3138 | +// Author: wan@google.com (Zhanyong Wan) |
| 3139 | +// Authored by: Alan Griffiths <alan@octopull.co.uk> |
| 3140 | + |
| 3141 | +#ifndef MIR_TEST_GMOCK_FIXES_H_ |
| 3142 | +#define MIR_TEST_GMOCK_FIXES_H_ |
| 3143 | + |
| 3144 | +#include <memory> |
| 3145 | +#include <gmock/gmock.h> |
| 3146 | + |
| 3147 | +namespace testing |
| 3148 | +{ |
| 3149 | +namespace internal |
| 3150 | +{ |
| 3151 | + |
| 3152 | +template<typename T> |
| 3153 | +class ActionResultHolder<std::unique_ptr<T>> |
| 3154 | +: public UntypedActionResultHolderBase { |
| 3155 | + public: |
| 3156 | + explicit ActionResultHolder(std::unique_ptr<T>&& a_value) : |
| 3157 | + value_(std::move(a_value)) {} |
| 3158 | + |
| 3159 | + // The compiler-generated copy constructor and assignment operator |
| 3160 | + // are exactly what we need, so we don't need to define them. |
| 3161 | + |
| 3162 | + // Returns the held value and deletes this object. |
| 3163 | + std::unique_ptr<T> GetValueAndDelete() const { |
| 3164 | + std::unique_ptr<T> retval(std::move(value_)); |
| 3165 | + delete this; |
| 3166 | + return retval; |
| 3167 | + } |
| 3168 | + |
| 3169 | + // Prints the held value as an action's result to os. |
| 3170 | + virtual void PrintAsActionResult(::std::ostream* os) const { |
| 3171 | + *os << "\n Returns: "; |
| 3172 | + // T may be a reference type, so we don't use UniversalPrint(). |
| 3173 | + UniversalPrinter<std::unique_ptr<T>>::Print(value_, os); |
| 3174 | + } |
| 3175 | + |
| 3176 | + // Performs the given mock function's default action and returns the |
| 3177 | + // result in a new-ed ActionResultHolder. |
| 3178 | + template <typename F> |
| 3179 | + static ActionResultHolder* PerformDefaultAction( |
| 3180 | + const FunctionMockerBase<F>* func_mocker, |
| 3181 | + const typename Function<F>::ArgumentTuple& args, |
| 3182 | + const string& call_description) { |
| 3183 | + return new ActionResultHolder( |
| 3184 | + func_mocker->PerformDefaultAction(args, call_description)); |
| 3185 | + } |
| 3186 | + |
| 3187 | + // Performs the given action and returns the result in a new-ed |
| 3188 | + // ActionResultHolder. |
| 3189 | + template <typename F> |
| 3190 | + static ActionResultHolder* |
| 3191 | + PerformAction(const Action<F>& action, |
| 3192 | + const typename Function<F>::ArgumentTuple& args) { |
| 3193 | + return new ActionResultHolder(action.Perform(args)); |
| 3194 | + } |
| 3195 | + |
| 3196 | + private: |
| 3197 | + std::unique_ptr<T> mutable value_; |
| 3198 | + |
| 3199 | + // T could be a reference type, so = isn't supported. |
| 3200 | + GTEST_DISALLOW_ASSIGN_(ActionResultHolder); |
| 3201 | +}; |
| 3202 | + |
| 3203 | +} |
| 3204 | + |
| 3205 | +template<typename T> |
| 3206 | +class DefaultValue<std::unique_ptr<T>> { |
| 3207 | + public: |
| 3208 | + // Unsets the default value for type T. |
| 3209 | + static void Clear() {} |
| 3210 | + |
| 3211 | + // Returns true iff the user has set the default value for type T. |
| 3212 | + static bool IsSet() { return false; } |
| 3213 | + |
| 3214 | + // Returns true if T has a default return value set by the user or there |
| 3215 | + // exists a built-in default value. |
| 3216 | + static bool Exists() { |
| 3217 | + return true; |
| 3218 | + } |
| 3219 | + |
| 3220 | + // Returns the default value for type T if the user has set one; |
| 3221 | + // otherwise returns the built-in default value if there is one; |
| 3222 | + // otherwise aborts the process. |
| 3223 | + static std::unique_ptr<T> Get() { |
| 3224 | + return std::unique_ptr<T>(); |
| 3225 | + } |
| 3226 | +}; |
| 3227 | + |
| 3228 | +} |
| 3229 | + |
| 3230 | +#endif /* MIR_TEST_GMOCK_FIXES_H_ */ |
| 3231 | |
| 3232 | === added file 'tests/common/mock_display.h' |
| 3233 | --- tests/common/mock_display.h 1970-01-01 00:00:00 +0000 |
| 3234 | +++ tests/common/mock_display.h 2015-10-16 17:43:47 +0000 |
| 3235 | @@ -0,0 +1,53 @@ |
| 3236 | +/* |
| 3237 | + * Copyright (C) 2015 Canonical, Ltd. |
| 3238 | + * |
| 3239 | + * This program is free software: you can redistribute it and/or modify it under |
| 3240 | + * the terms of the GNU Lesser General Public License version 3, as published by |
| 3241 | + * the Free Software Foundation. |
| 3242 | + * |
| 3243 | + * This program is distributed in the hope that it will be useful, but WITHOUT |
| 3244 | + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
| 3245 | + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 3246 | + * Lesser General Public License for more details. |
| 3247 | + * |
| 3248 | + * You should have received a copy of the GNU Lesser General Public License |
| 3249 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 3250 | + */ |
| 3251 | + |
| 3252 | +#ifndef MOCKDISPLAY_H |
| 3253 | +#define MOCKDISPLAY_H |
| 3254 | + |
| 3255 | +#include <mir/graphics/display.h> |
| 3256 | +#include <mir/graphics/gl_context.h> |
| 3257 | + |
| 3258 | +#include <gmock/gmock.h> |
| 3259 | +#include "gmock_fixes.h" |
| 3260 | + |
| 3261 | +class MockDisplaySyncGroup : public mir::graphics::DisplaySyncGroup |
| 3262 | +{ |
| 3263 | +public: |
| 3264 | + MOCK_METHOD1(for_each_display_buffer, void(std::function<void(mir::graphics::DisplayBuffer&)> const& f)); |
| 3265 | + MOCK_METHOD0(post, void()); |
| 3266 | +}; |
| 3267 | + |
| 3268 | +struct MockDisplay : public mir::graphics::Display |
| 3269 | +{ |
| 3270 | +public: |
| 3271 | + MOCK_METHOD1(for_each_display_sync_group, void(std::function<void(mir::graphics::DisplaySyncGroup&)> const&)); |
| 3272 | + MOCK_CONST_METHOD0(configuration, std::unique_ptr<mir::graphics::DisplayConfiguration>()); |
| 3273 | + MOCK_METHOD1(configure, void(mir::graphics::DisplayConfiguration const&)); |
| 3274 | + MOCK_METHOD2(register_configuration_change_handler, |
| 3275 | + void(mir::graphics::EventHandlerRegister&, mir::graphics::DisplayConfigurationChangeHandler const&)); |
| 3276 | + |
| 3277 | + MOCK_METHOD3(register_pause_resume_handlers, void(mir::graphics::EventHandlerRegister&, |
| 3278 | + mir::graphics::DisplayPauseHandler const&, |
| 3279 | + mir::graphics::DisplayResumeHandler const&)); |
| 3280 | + MOCK_METHOD0(pause, void()); |
| 3281 | + MOCK_METHOD0(resume, void()); |
| 3282 | + MOCK_METHOD1(create_hardware_cursor, std::shared_ptr<mir::graphics::Cursor>(std::shared_ptr<mir::graphics::CursorImage> const&)); |
| 3283 | + MOCK_METHOD0(create_gl_context, std::unique_ptr<mir::graphics::GLContext>()); |
| 3284 | +}; |
| 3285 | + |
| 3286 | + |
| 3287 | + |
| 3288 | +#endif // MOCKDISPLAY_H |
| 3289 | |
| 3290 | === added file 'tests/common/mock_display_configuration.h' |
| 3291 | --- tests/common/mock_display_configuration.h 1970-01-01 00:00:00 +0000 |
| 3292 | +++ tests/common/mock_display_configuration.h 2015-10-16 17:43:47 +0000 |
| 3293 | @@ -0,0 +1,35 @@ |
| 3294 | +/* |
| 3295 | + * Copyright (C) 2015 Canonical, Ltd. |
| 3296 | + * |
| 3297 | + * This program is free software: you can redistribute it and/or modify it under |
| 3298 | + * the terms of the GNU Lesser General Public License version 3, as published by |
| 3299 | + * the Free Software Foundation. |
| 3300 | + * |
| 3301 | + * This program is distributed in the hope that it will be useful, but WITHOUT |
| 3302 | + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
| 3303 | + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 3304 | + * Lesser General Public License for more details. |
| 3305 | + * |
| 3306 | + * You should have received a copy of the GNU Lesser General Public License |
| 3307 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 3308 | + */ |
| 3309 | + |
| 3310 | +#ifndef MOCK_DISPLAY_CONFIGURATION_H |
| 3311 | +#define MOCK_DISPLAY_CONFIGURATION_H |
| 3312 | + |
| 3313 | +#include <mir/graphics/display_configuration.h> |
| 3314 | + |
| 3315 | +#include <gmock/gmock.h> |
| 3316 | +#include "gmock_fixes.h" |
| 3317 | + |
| 3318 | +class MockDisplayConfiguration : public mir::graphics::DisplayConfiguration |
| 3319 | +{ |
| 3320 | +public: |
| 3321 | + MOCK_CONST_METHOD1(for_each_card, void(std::function<void(mir::graphics::DisplayConfigurationCard const&)>)); |
| 3322 | + |
| 3323 | + MOCK_CONST_METHOD1(for_each_output, void(std::function<void(mir::graphics::DisplayConfigurationOutput const&)>)); |
| 3324 | + MOCK_METHOD1(for_each_output, void(std::function<void(mir::graphics::UserDisplayConfigurationOutput&)>)); |
| 3325 | + |
| 3326 | + MOCK_CONST_METHOD0(valid, bool()); |
| 3327 | +}; |
| 3328 | +#endif // MOCK_DISPLAY_CONFIGURATION_H |
| 3329 | |
| 3330 | === added file 'tests/common/mock_gl_display_buffer.h' |
| 3331 | --- tests/common/mock_gl_display_buffer.h 1970-01-01 00:00:00 +0000 |
| 3332 | +++ tests/common/mock_gl_display_buffer.h 2015-10-16 17:43:47 +0000 |
| 3333 | @@ -0,0 +1,49 @@ |
| 3334 | +/* |
| 3335 | + * Copyright (C) 2015 Canonical, Ltd. |
| 3336 | + * |
| 3337 | + * This program is free software: you can redistribute it and/or modify it under |
| 3338 | + * the terms of the GNU Lesser General Public License version 3, as published by |
| 3339 | + * the Free Software Foundation. |
| 3340 | + * |
| 3341 | + * This program is distributed in the hope that it will be useful, but WITHOUT |
| 3342 | + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
| 3343 | + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 3344 | + * Lesser General Public License for more details. |
| 3345 | + * |
| 3346 | + * You should have received a copy of the GNU Lesser General Public License |
| 3347 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 3348 | + */ |
| 3349 | + |
| 3350 | +#ifndef MOCK_GL_DISPLAY_BUFFER_H |
| 3351 | +#define MOCK_GL_DISPLAY_BUFFER_H |
| 3352 | + |
| 3353 | +#include <mir/graphics/display_buffer.h> |
| 3354 | +#include <mir/renderer/gl/render_target.h> |
| 3355 | + |
| 3356 | +#include <gmock/gmock.h> |
| 3357 | + |
| 3358 | +class MockGLDisplayBuffer : public mir::graphics::DisplayBuffer, |
| 3359 | + public mir::renderer::gl::RenderTarget, |
| 3360 | + public mir::graphics::NativeDisplayBuffer |
| 3361 | +{ |
| 3362 | +public: |
| 3363 | + MockGLDisplayBuffer() |
| 3364 | + { |
| 3365 | + using namespace testing; |
| 3366 | + ON_CALL(*this, view_area()) |
| 3367 | + .WillByDefault(Return(mir::geometry::Rectangle{{0,0},{0,0}})); |
| 3368 | + ON_CALL(*this, native_display_buffer()) |
| 3369 | + .WillByDefault(Return(dynamic_cast<mir::graphics::NativeDisplayBuffer*>(this))); |
| 3370 | + } |
| 3371 | + MOCK_CONST_METHOD0(view_area, mir::geometry::Rectangle()); |
| 3372 | + MOCK_METHOD1(post_renderables_if_optimizable, bool(mir::graphics::RenderableList const&)); |
| 3373 | + MOCK_CONST_METHOD0(orientation, MirOrientation()); |
| 3374 | + MOCK_METHOD0(native_display_buffer, mir::graphics::NativeDisplayBuffer*()); |
| 3375 | + |
| 3376 | + MOCK_METHOD0(make_current, void()); |
| 3377 | + MOCK_METHOD0(release_current, void()); |
| 3378 | + MOCK_METHOD0(swap_buffers, void()); |
| 3379 | +}; |
| 3380 | + |
| 3381 | + |
| 3382 | +#endif // MOCK_GL_DISPLAY_BUFFER_H |
| 3383 | |
| 3384 | === added file 'tests/common/mock_main_loop.h' |
| 3385 | --- tests/common/mock_main_loop.h 1970-01-01 00:00:00 +0000 |
| 3386 | +++ tests/common/mock_main_loop.h 2015-10-16 17:43:47 +0000 |
| 3387 | @@ -0,0 +1,53 @@ |
| 3388 | +/* |
| 3389 | + * Copyright (C) 2015 Canonical, Ltd. |
| 3390 | + * |
| 3391 | + * This program is free software: you can redistribute it and/or modify it under |
| 3392 | + * the terms of the GNU Lesser General Public License version 3, as published by |
| 3393 | + * the Free Software Foundation. |
| 3394 | + * |
| 3395 | + * This program is distributed in the hope that it will be useful, but WITHOUT |
| 3396 | + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
| 3397 | + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 3398 | + * Lesser General Public License for more details. |
| 3399 | + * |
| 3400 | + * You should have received a copy of the GNU Lesser General Public License |
| 3401 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 3402 | + */ |
| 3403 | + |
| 3404 | +#ifndef MOCKMAINLOOP_H |
| 3405 | +#define MOCKMAINLOOP_H |
| 3406 | + |
| 3407 | +#include <gmock/gmock.h> |
| 3408 | + |
| 3409 | +#include <mir/main_loop.h> |
| 3410 | + |
| 3411 | +#include <memory> |
| 3412 | + |
| 3413 | +class MockMainLoop : public mir::MainLoop |
| 3414 | +{ |
| 3415 | +public: |
| 3416 | + ~MockMainLoop() noexcept {} |
| 3417 | + |
| 3418 | + void run() override {} |
| 3419 | + void stop() override {} |
| 3420 | + |
| 3421 | + MOCK_METHOD2(register_signal_handler, |
| 3422 | + void(std::initializer_list<int>, |
| 3423 | + std::function<void(int)> const&)); |
| 3424 | + |
| 3425 | + MOCK_METHOD3(register_fd_handler, |
| 3426 | + void(std::initializer_list<int>, void const*, |
| 3427 | + std::function<void(int)> const&)); |
| 3428 | + |
| 3429 | + MOCK_METHOD1(unregister_fd_handler, void(void const*)); |
| 3430 | + |
| 3431 | + MOCK_METHOD2(enqueue, void(void const*, mir::ServerAction const&)); |
| 3432 | + MOCK_METHOD1(pause_processing_for,void (void const*)); |
| 3433 | + MOCK_METHOD1(resume_processing_for,void (void const*)); |
| 3434 | + |
| 3435 | + MOCK_METHOD1(create_alarm, std::unique_ptr<mir::time::Alarm>(std::function<void()> const& callback)); |
| 3436 | + MOCK_METHOD1(create_alarm, std::unique_ptr<mir::time::Alarm>(std::shared_ptr<mir::LockableCallback> const& callback)); |
| 3437 | +}; |
| 3438 | + |
| 3439 | + |
| 3440 | +#endif // MOCKMAINLOOP_H |
| 3441 | |
| 3442 | === modified file 'tests/mirserver/CMakeLists.txt' |
| 3443 | --- tests/mirserver/CMakeLists.txt 2014-11-13 15:47:30 +0000 |
| 3444 | +++ tests/mirserver/CMakeLists.txt 2015-10-16 17:43:47 +0000 |
| 3445 | @@ -1,3 +1,4 @@ |
| 3446 | add_subdirectory(QtEventFeeder) |
| 3447 | add_subdirectory(Clipboard) |
| 3448 | add_subdirectory(Screen) |
| 3449 | +add_subdirectory(ScreenController) |
| 3450 | |
| 3451 | === modified file 'tests/mirserver/QtEventFeeder/mock_qtwindowsystem.h' |
| 3452 | --- tests/mirserver/QtEventFeeder/mock_qtwindowsystem.h 2015-10-16 17:43:47 +0000 |
| 3453 | +++ tests/mirserver/QtEventFeeder/mock_qtwindowsystem.h 2015-10-16 17:43:47 +0000 |
| 3454 | @@ -19,19 +19,26 @@ |
| 3455 | #define MOCK_QTWINDOWSYSTEM_H |
| 3456 | |
| 3457 | #include <qteventfeeder.h> |
| 3458 | +#include <QWindow> |
| 3459 | |
| 3460 | class MockQtWindowSystem : public QtEventFeeder::QtWindowSystemInterface { |
| 3461 | public: |
| 3462 | - MOCK_METHOD0(hasTargetWindow, bool()); |
| 3463 | - MOCK_METHOD0(targetWindowGeometry, QRect()); |
| 3464 | + MOCK_CONST_METHOD0(ready, bool()); |
| 3465 | + MOCK_METHOD1(setScreenController, void(const QSharedPointer<ScreenController> &)); |
| 3466 | + MOCK_METHOD1(getWindowForTouchPoint, QWindow*(const QPoint &point)); |
| 3467 | + MOCK_METHOD0(lastWindow, QWindow*()); |
| 3468 | + MOCK_METHOD0(focusedWindow, QWindow*()); |
| 3469 | MOCK_METHOD1(registerTouchDevice, void(QTouchDevice* device)); |
| 3470 | - MOCK_METHOD10(handleExtendedKeyEvent, void(ulong timestamp, QEvent::Type type, int key, |
| 3471 | - Qt::KeyboardModifiers modifiers, |
| 3472 | - quint32 nativeScanCode, quint32 nativeVirtualKey, |
| 3473 | - quint32 nativeModifiers, |
| 3474 | - const QString& text, bool autorep, |
| 3475 | - ushort count)); |
| 3476 | - MOCK_METHOD4(handleTouchEvent, void(ulong timestamp, QTouchDevice *device, |
| 3477 | + |
| 3478 | + // Wanted to use GMock, but MOCK_METHOD11 not implemented |
| 3479 | + void handleExtendedKeyEvent(QWindow */*window*/, ulong /*timestamp*/, QEvent::Type /*type*/, int /*key*/, |
| 3480 | + Qt::KeyboardModifiers /*modifiers*/, |
| 3481 | + quint32 /*nativeScanCode*/, quint32 /*nativeVirtualKey*/, |
| 3482 | + quint32 /*nativeModifiers*/, |
| 3483 | + const QString& /*text*/ = QString(), bool /*autorep*/ = false, |
| 3484 | + ushort /*count*/ = 1) {} |
| 3485 | + |
| 3486 | + MOCK_METHOD5(handleTouchEvent, void(QWindow *window, ulong timestamp, QTouchDevice *device, |
| 3487 | const QList<struct QWindowSystemInterface::TouchPoint> &points, |
| 3488 | Qt::KeyboardModifiers mods)); |
| 3489 | MOCK_METHOD4(handleMouseEvent, void(ulong, QPointF, Qt::MouseButtons, Qt::KeyboardModifiers)); |
| 3490 | |
| 3491 | === modified file 'tests/mirserver/QtEventFeeder/qteventfeeder_test.cpp' |
| 3492 | --- tests/mirserver/QtEventFeeder/qteventfeeder_test.cpp 2015-09-18 16:33:06 +0000 |
| 3493 | +++ tests/mirserver/QtEventFeeder/qteventfeeder_test.cpp 2015-10-16 17:43:47 +0000 |
| 3494 | @@ -69,33 +69,44 @@ |
| 3495 | |
| 3496 | MockQtWindowSystem *mockWindowSystem; |
| 3497 | QtEventFeeder *qtEventFeeder; |
| 3498 | + QWindow *window; |
| 3499 | + QGuiApplication *app; |
| 3500 | }; |
| 3501 | |
| 3502 | void QtEventFeederTest::SetUp() |
| 3503 | { |
| 3504 | mockWindowSystem = new MockQtWindowSystem; |
| 3505 | + auto screens = QSharedPointer<ScreenController>(); |
| 3506 | |
| 3507 | EXPECT_CALL(*mockWindowSystem, registerTouchDevice(_)); |
| 3508 | |
| 3509 | - qtEventFeeder = new QtEventFeeder(mockWindowSystem); |
| 3510 | + qtEventFeeder = new QtEventFeeder(screens, mockWindowSystem); |
| 3511 | |
| 3512 | ASSERT_TRUE(Mock::VerifyAndClearExpectations(mockWindowSystem)); |
| 3513 | + |
| 3514 | + int argc = 0; |
| 3515 | + char **argv = nullptr; |
| 3516 | + setenv("QT_QPA_PLATFORM", "minimal", 1); |
| 3517 | + app = new QGuiApplication(argc, argv); |
| 3518 | + window = new QWindow; |
| 3519 | } |
| 3520 | |
| 3521 | void QtEventFeederTest::TearDown() |
| 3522 | { |
| 3523 | // mockWindowSystem will be deleted by QtEventFeeder |
| 3524 | delete qtEventFeeder; |
| 3525 | + delete window; |
| 3526 | + delete app; |
| 3527 | } |
| 3528 | |
| 3529 | void QtEventFeederTest::setIrrelevantMockWindowSystemExpectations() |
| 3530 | { |
| 3531 | - EXPECT_CALL(*mockWindowSystem, hasTargetWindow()) |
| 3532 | - .Times(AnyNumber()) |
| 3533 | - .WillRepeatedly(Return(true)); |
| 3534 | - EXPECT_CALL(*mockWindowSystem, targetWindowGeometry()) |
| 3535 | - .Times(AnyNumber()) |
| 3536 | - .WillRepeatedly(Return(QRect(0,0,100,100))); |
| 3537 | + EXPECT_CALL(*mockWindowSystem, getWindowForTouchPoint(_)) |
| 3538 | + .Times(AnyNumber()) |
| 3539 | + .WillRepeatedly(Return(window)); |
| 3540 | + EXPECT_CALL(*mockWindowSystem, focusedWindow()) |
| 3541 | + .Times(AnyNumber()) |
| 3542 | + .WillRepeatedly(Return(window)); |
| 3543 | } |
| 3544 | |
| 3545 | |
| 3546 | @@ -113,7 +124,7 @@ |
| 3547 | |
| 3548 | setIrrelevantMockWindowSystemExpectations(); |
| 3549 | |
| 3550 | - EXPECT_CALL(*mockWindowSystem, handleTouchEvent(_,_,AllOf(SizeIs(1), |
| 3551 | + EXPECT_CALL(*mockWindowSystem, handleTouchEvent(_,_,_,AllOf(SizeIs(1), |
| 3552 | Contains(AllOf(HasId(0), |
| 3553 | IsPressed()))),_)).Times(1); |
| 3554 | |
| 3555 | @@ -132,12 +143,12 @@ |
| 3556 | InSequence sequence; |
| 3557 | |
| 3558 | EXPECT_CALL(*mockWindowSystem, |
| 3559 | - handleTouchEvent(_,_,AllOf(SizeIs(1), |
| 3560 | + handleTouchEvent(_,_,_,AllOf(SizeIs(1), |
| 3561 | Contains(AllOf(HasId(0),IsReleased())) |
| 3562 | ),_)).Times(1); |
| 3563 | |
| 3564 | EXPECT_CALL(*mockWindowSystem, |
| 3565 | - handleTouchEvent(_,_,AllOf(SizeIs(1), |
| 3566 | + handleTouchEvent(_,_,_,AllOf(SizeIs(1), |
| 3567 | Contains(AllOf(HasId(1),IsPressed())) |
| 3568 | ),_)).Times(1); |
| 3569 | } |
| 3570 | @@ -161,7 +172,7 @@ |
| 3571 | 10, 10, 10 /* x, y, pressure*/, |
| 3572 | 1, 1, 10 /* touch major, minor, size */); |
| 3573 | |
| 3574 | - EXPECT_CALL(*mockWindowSystem, handleTouchEvent(_,_,AllOf(SizeIs(1), |
| 3575 | + EXPECT_CALL(*mockWindowSystem, handleTouchEvent(_,_,_,AllOf(SizeIs(1), |
| 3576 | Contains(AllOf(HasId(0), |
| 3577 | IsPressed()))),_)).Times(1); |
| 3578 | qtEventFeeder->dispatch(*ev1); |
| 3579 | @@ -181,7 +192,7 @@ |
| 3580 | 1, 1, 10 /* touch major, minor, size */); |
| 3581 | |
| 3582 | EXPECT_CALL(*mockWindowSystem, |
| 3583 | - handleTouchEvent(_,_,AllOf(SizeIs(2), |
| 3584 | + handleTouchEvent(_,_,_,AllOf(SizeIs(2), |
| 3585 | Contains(AllOf(HasId(0), StateIsMoved())), |
| 3586 | Contains(AllOf(HasId(1), IsPressed())) |
| 3587 | ),_)).Times(1); |
| 3588 | @@ -208,14 +219,14 @@ |
| 3589 | |
| 3590 | // first release touch 0 |
| 3591 | EXPECT_CALL(*mockWindowSystem, |
| 3592 | - handleTouchEvent(_,_,AllOf(SizeIs(2), |
| 3593 | + handleTouchEvent(_,_,_,AllOf(SizeIs(2), |
| 3594 | Contains(AllOf(HasId(0), IsReleased())), |
| 3595 | Contains(AllOf(HasId(1), IsStationary())) |
| 3596 | ),_)).Times(1); |
| 3597 | |
| 3598 | // then press touch 2 |
| 3599 | EXPECT_CALL(*mockWindowSystem, |
| 3600 | - handleTouchEvent(_,_,AllOf(SizeIs(2), |
| 3601 | + handleTouchEvent(_,_,_,AllOf(SizeIs(2), |
| 3602 | Contains(AllOf(HasId(1), StateIsMoved())), |
| 3603 | Contains(AllOf(HasId(2), IsPressed())) |
| 3604 | ),_)).Times(1); |
| 3605 | @@ -230,7 +241,7 @@ |
| 3606 | { |
| 3607 | setIrrelevantMockWindowSystemExpectations(); |
| 3608 | |
| 3609 | - EXPECT_CALL(*mockWindowSystem, handleTouchEvent(_,_,AllOf(SizeIs(1), |
| 3610 | + EXPECT_CALL(*mockWindowSystem, handleTouchEvent(_,_,_,AllOf(SizeIs(1), |
| 3611 | Contains(AllOf(HasId(0), |
| 3612 | IsPressed()))),_)).Times(1); |
| 3613 | |
| 3614 | @@ -243,7 +254,7 @@ |
| 3615 | |
| 3616 | setIrrelevantMockWindowSystemExpectations(); |
| 3617 | |
| 3618 | - EXPECT_CALL(*mockWindowSystem, handleTouchEvent(_,_,AllOf(SizeIs(1), |
| 3619 | + EXPECT_CALL(*mockWindowSystem, handleTouchEvent(_,_,_,AllOf(SizeIs(1), |
| 3620 | Contains(AllOf(HasId(0), StateIsMoved())) |
| 3621 | ),_)).Times(1); |
| 3622 | |
| 3623 | |
| 3624 | === modified file 'tests/mirserver/Screen/CMakeLists.txt' |
| 3625 | --- tests/mirserver/Screen/CMakeLists.txt 2014-12-03 08:56:35 +0000 |
| 3626 | +++ tests/mirserver/Screen/CMakeLists.txt 2015-10-16 17:43:47 +0000 |
| 3627 | @@ -5,6 +5,7 @@ |
| 3628 | ) |
| 3629 | |
| 3630 | include_directories( |
| 3631 | + ${CMAKE_SOURCE_DIR}/tests/common |
| 3632 | ${CMAKE_SOURCE_DIR}/src/platforms/mirserver |
| 3633 | ${CMAKE_SOURCE_DIR}/src/common |
| 3634 | ${Qt5Gui_PRIVATE_INCLUDE_DIRS} |
| 3635 | |
| 3636 | === modified file 'tests/mirserver/Screen/screen_test.cpp' |
| 3637 | --- tests/mirserver/Screen/screen_test.cpp 2015-10-08 12:33:06 +0000 |
| 3638 | +++ tests/mirserver/Screen/screen_test.cpp 2015-10-16 17:43:47 +0000 |
| 3639 | @@ -18,39 +18,21 @@ |
| 3640 | #include <gtest/gtest.h> |
| 3641 | |
| 3642 | #include "mir/graphics/display_configuration.h" |
| 3643 | +#include "fake_displayconfigurationoutput.h" |
| 3644 | |
| 3645 | #include <screen.h> |
| 3646 | |
| 3647 | +using namespace ::testing; |
| 3648 | + |
| 3649 | namespace mg = mir::graphics; |
| 3650 | namespace geom = mir::geometry; |
| 3651 | |
| 3652 | -mg::DisplayConfigurationOutput const fake_output |
| 3653 | -{ |
| 3654 | - mg::DisplayConfigurationOutputId{3}, |
| 3655 | - mg::DisplayConfigurationCardId{2}, |
| 3656 | - mg::DisplayConfigurationOutputType::dvid, |
| 3657 | - { |
| 3658 | - mir_pixel_format_abgr_8888 |
| 3659 | - }, |
| 3660 | - { |
| 3661 | - {geom::Size{10, 20}, 60.0}, |
| 3662 | - {geom::Size{10, 20}, 59.0}, |
| 3663 | - {geom::Size{15, 20}, 59.0} |
| 3664 | - }, |
| 3665 | - 0, |
| 3666 | - geom::Size{10, 20}, |
| 3667 | - true, |
| 3668 | - true, |
| 3669 | - geom::Point(), |
| 3670 | - 2, |
| 3671 | - mir_pixel_format_abgr_8888, |
| 3672 | - mir_power_mode_on, |
| 3673 | - mir_orientation_normal, |
| 3674 | - 1.0f, |
| 3675 | - mir_form_factor_unknown |
| 3676 | +class ScreenTest : public ::testing::Test { |
| 3677 | +protected: |
| 3678 | + void SetUp() override; |
| 3679 | }; |
| 3680 | |
| 3681 | -TEST(ScreenTest, OrientationSensor) |
| 3682 | +void ScreenTest::SetUp() |
| 3683 | { |
| 3684 | if (!qEnvironmentVariableIsSet("QT_ACCEL_FILEPATH")) { |
| 3685 | // Trick Qt >= 5.4.1 to load the generic sensors |
| 3686 | @@ -58,7 +40,11 @@ |
| 3687 | } |
| 3688 | |
| 3689 | Screen::skipDBusRegistration = true; |
| 3690 | - Screen *screen = new Screen(fake_output); |
| 3691 | +} |
| 3692 | + |
| 3693 | +TEST_F(ScreenTest, OrientationSensor) |
| 3694 | +{ |
| 3695 | + Screen *screen = new Screen(fakeOutput1); |
| 3696 | |
| 3697 | // Default state should be active |
| 3698 | ASSERT_TRUE(screen->orientationSensorEnabled()); |
| 3699 | @@ -69,3 +55,29 @@ |
| 3700 | screen->onDisplayPowerStateChanged(1,0); |
| 3701 | ASSERT_TRUE(screen->orientationSensorEnabled()); |
| 3702 | } |
| 3703 | + |
| 3704 | +TEST_F(ScreenTest, ReadConfigurationFromDisplayConfig) |
| 3705 | +{ |
| 3706 | + Screen *screen = new Screen(fakeOutput1); |
| 3707 | + |
| 3708 | + EXPECT_EQ(screen->geometry(), QRect(0, 0, 150, 200)); |
| 3709 | + EXPECT_EQ(screen->availableGeometry(), QRect(0, 0, 150, 200)); |
| 3710 | + EXPECT_EQ(screen->depth(), 32); |
| 3711 | + EXPECT_EQ(screen->format(), QImage::Format_RGBA8888); |
| 3712 | + EXPECT_EQ(screen->refreshRate(), 59); |
| 3713 | + EXPECT_EQ(screen->physicalSize(), QSize(1111, 2222)); |
| 3714 | + EXPECT_EQ(screen->outputType(), mg::DisplayConfigurationOutputType::dvid); |
| 3715 | +} |
| 3716 | + |
| 3717 | +TEST_F(ScreenTest, ReadDifferentConfigurationFromDisplayConfig) |
| 3718 | +{ |
| 3719 | + Screen *screen = new Screen(fakeOutput2); |
| 3720 | + |
| 3721 | + EXPECT_EQ(screen->geometry(), QRect(500, 600, 1500, 2000)); |
| 3722 | + EXPECT_EQ(screen->availableGeometry(), QRect(500, 600, 1500, 2000)); |
| 3723 | + EXPECT_EQ(screen->depth(), 32); |
| 3724 | + EXPECT_EQ(screen->format(), QImage::Format_RGBX8888); |
| 3725 | + EXPECT_EQ(screen->refreshRate(), 75); |
| 3726 | + EXPECT_EQ(screen->physicalSize(), QSize(1000, 2000)); |
| 3727 | + EXPECT_EQ(screen->outputType(), mg::DisplayConfigurationOutputType::lvds); |
| 3728 | +} |
| 3729 | |
| 3730 | === added directory 'tests/mirserver/ScreenController' |
| 3731 | === added file 'tests/mirserver/ScreenController/CMakeLists.txt' |
| 3732 | --- tests/mirserver/ScreenController/CMakeLists.txt 1970-01-01 00:00:00 +0000 |
| 3733 | +++ tests/mirserver/ScreenController/CMakeLists.txt 2015-10-16 17:43:47 +0000 |
| 3734 | @@ -0,0 +1,29 @@ |
| 3735 | +set( |
| 3736 | + SCREENCONTROLLER_TEST_SOURCES |
| 3737 | + screencontroller_test.cpp |
| 3738 | + ${CMAKE_SOURCE_DIR}/src/common/debughelpers.cpp |
| 3739 | + # to be moc-ed |
| 3740 | + stub_screen.h |
| 3741 | + testable_screencontroller.h |
| 3742 | +) |
| 3743 | + |
| 3744 | +include_directories( |
| 3745 | + ${CMAKE_SOURCE_DIR}/tests/common |
| 3746 | + ${CMAKE_SOURCE_DIR}/src/platforms/mirserver |
| 3747 | + ${CMAKE_SOURCE_DIR}/src/common |
| 3748 | + ${Qt5Gui_PRIVATE_INCLUDE_DIRS} |
| 3749 | + ${MIRSERVER_INCLUDE_DIRS} |
| 3750 | + ${MIRRENDERERGLDEV_INCLUDE_DIRS} |
| 3751 | +) |
| 3752 | + |
| 3753 | +add_executable(ScreenControllerTest ${SCREENCONTROLLER_TEST_SOURCES}) |
| 3754 | + |
| 3755 | +target_link_libraries( |
| 3756 | + ScreenControllerTest |
| 3757 | + qpa-mirserver |
| 3758 | + |
| 3759 | + ${GTEST_BOTH_LIBRARIES} |
| 3760 | + ${GMOCK_LIBRARIES} |
| 3761 | +) |
| 3762 | + |
| 3763 | +add_test(ScreenController, ScreenControllerTest) |
| 3764 | |
| 3765 | === added file 'tests/mirserver/ScreenController/screencontroller_test.cpp' |
| 3766 | --- tests/mirserver/ScreenController/screencontroller_test.cpp 1970-01-01 00:00:00 +0000 |
| 3767 | +++ tests/mirserver/ScreenController/screencontroller_test.cpp 2015-10-16 17:43:47 +0000 |
| 3768 | @@ -0,0 +1,177 @@ |
| 3769 | +/* |
| 3770 | + * Copyright (C) 2015 Canonical, Ltd. |
| 3771 | + * |
| 3772 | + * This program is free software: you can redistribute it and/or modify it under |
| 3773 | + * the terms of the GNU Lesser General Public License version 3, as published by |
| 3774 | + * the Free Software Foundation. |
| 3775 | + * |
| 3776 | + * This program is distributed in the hope that it will be useful, but WITHOUT |
| 3777 | + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
| 3778 | + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 3779 | + * Lesser General Public License for more details. |
| 3780 | + * |
| 3781 | + * You should have received a copy of the GNU Lesser General Public License |
| 3782 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 3783 | + */ |
| 3784 | + |
| 3785 | +#include <gtest/gtest.h> |
| 3786 | +#include "gmock_fixes.h" |
| 3787 | + |
| 3788 | +#include "stub_display.h" |
| 3789 | +#include "mock_main_loop.h" |
| 3790 | +#include "qtcompositor.h" |
| 3791 | +#include "fake_displayconfigurationoutput.h" |
| 3792 | + |
| 3793 | +#include "testable_screencontroller.h" |
| 3794 | +#include "screen.h" |
| 3795 | +#include "screenwindow.h" |
| 3796 | + |
| 3797 | +#include <QGuiApplication> |
| 3798 | + |
| 3799 | +using namespace ::testing; |
| 3800 | + |
| 3801 | +namespace mg = mir::graphics; |
| 3802 | +namespace geom = mir::geometry; |
| 3803 | + |
| 3804 | +class ScreenControllerTest : public ::testing::Test { |
| 3805 | +protected: |
| 3806 | + void SetUp() override; |
| 3807 | + void TearDown() override; |
| 3808 | + |
| 3809 | + ScreenController *screenController; |
| 3810 | + std::shared_ptr<StubDisplay> display; |
| 3811 | + std::shared_ptr<QtCompositor> compositor; |
| 3812 | + QGuiApplication *app; |
| 3813 | +}; |
| 3814 | + |
| 3815 | +void ScreenControllerTest::SetUp() |
| 3816 | +{ |
| 3817 | + setenv("QT_QPA_PLATFORM", "minimal", 1); |
| 3818 | + Screen::skipDBusRegistration = true; |
| 3819 | + |
| 3820 | + screenController = new TestableScreenController; |
| 3821 | + display = std::make_shared<StubDisplay>(); |
| 3822 | + compositor = std::make_shared<QtCompositor>(); |
| 3823 | + |
| 3824 | + static_cast<TestableScreenController*>(screenController)->do_init(display, compositor); |
| 3825 | + |
| 3826 | + int argc = 0; |
| 3827 | + char **argv = nullptr; |
| 3828 | + setenv("QT_QPA_PLATFORM", "minimal", 1); |
| 3829 | + app = new QGuiApplication(argc, argv); |
| 3830 | +} |
| 3831 | + |
| 3832 | +void ScreenControllerTest::TearDown() |
| 3833 | +{ |
| 3834 | + delete screenController; |
| 3835 | +} |
| 3836 | + |
| 3837 | +TEST_F(ScreenControllerTest, SingleScreenFound) |
| 3838 | +{ |
| 3839 | + // Set up display state |
| 3840 | + std::vector<mg::DisplayConfigurationOutput> config{fakeOutput1}; |
| 3841 | + std::vector<MockGLDisplayBuffer*> bufferConfig; // only used to match buffer with display, unecessary here |
| 3842 | + display->setFakeConfiguration(config, bufferConfig); |
| 3843 | + |
| 3844 | + screenController->update(); |
| 3845 | + |
| 3846 | + ASSERT_EQ(1, screenController->screens().count()); |
| 3847 | + Screen* screen = screenController->screens().first(); |
| 3848 | + EXPECT_EQ(QRect(0, 0, 150, 200), screen->geometry()); |
| 3849 | +} |
| 3850 | + |
| 3851 | +TEST_F(ScreenControllerTest, MultipleScreenFound) |
| 3852 | +{ |
| 3853 | + std::vector<mg::DisplayConfigurationOutput> config{fakeOutput1, fakeOutput2}; |
| 3854 | + std::vector<MockGLDisplayBuffer*> bufferConfig; // only used to match buffer with display, unecessary here |
| 3855 | + display->setFakeConfiguration(config, bufferConfig); |
| 3856 | + |
| 3857 | + screenController->update(); |
| 3858 | + |
| 3859 | + ASSERT_EQ(2, screenController->screens().count()); |
| 3860 | + EXPECT_EQ(QRect(0, 0, 150, 200), screenController->screens().at(0)->geometry()); |
| 3861 | + EXPECT_EQ(QRect(500, 600, 1500, 2000), screenController->screens().at(1)->geometry()); |
| 3862 | +} |
| 3863 | + |
| 3864 | +TEST_F(ScreenControllerTest, ScreenAdded) |
| 3865 | +{ |
| 3866 | + std::vector<mg::DisplayConfigurationOutput> config{fakeOutput1}; |
| 3867 | + std::vector<MockGLDisplayBuffer*> bufferConfig; // only used to match buffer with display, unecessary here |
| 3868 | + display->setFakeConfiguration(config, bufferConfig); |
| 3869 | + |
| 3870 | + screenController->update(); |
| 3871 | + |
| 3872 | + config.push_back(fakeOutput2); |
| 3873 | + display->setFakeConfiguration(config, bufferConfig); |
| 3874 | + |
| 3875 | + ASSERT_EQ(1, screenController->screens().count()); |
| 3876 | + EXPECT_EQ(QRect(0, 0, 150, 200), screenController->screens().at(0)->geometry()); |
| 3877 | + |
| 3878 | + screenController->update(); |
| 3879 | + |
| 3880 | + ASSERT_EQ(2, screenController->screens().count()); |
| 3881 | + EXPECT_EQ(QRect(0, 0, 150, 200), screenController->screens().at(0)->geometry()); |
| 3882 | + EXPECT_EQ(QRect(500, 600, 1500, 2000), screenController->screens().at(1)->geometry()); |
| 3883 | +} |
| 3884 | + |
| 3885 | +TEST_F(ScreenControllerTest, ScreenRemoved) |
| 3886 | +{ |
| 3887 | + std::vector<mg::DisplayConfigurationOutput> config{fakeOutput2, fakeOutput1}; |
| 3888 | + std::vector<MockGLDisplayBuffer*> bufferConfig; // only used to match buffer with display, unecessary here |
| 3889 | + display->setFakeConfiguration(config, bufferConfig); |
| 3890 | + |
| 3891 | + screenController->update(); |
| 3892 | + |
| 3893 | + config.pop_back(); |
| 3894 | + display->setFakeConfiguration(config, bufferConfig); |
| 3895 | + |
| 3896 | + ASSERT_EQ(2, screenController->screens().count()); |
| 3897 | + EXPECT_EQ(QRect(500, 600, 1500, 2000), screenController->screens().at(0)->geometry()); |
| 3898 | + EXPECT_EQ(QRect(0, 0, 150, 200), screenController->screens().at(1)->geometry()); |
| 3899 | + |
| 3900 | + screenController->update(); |
| 3901 | + |
| 3902 | + ASSERT_EQ(1, screenController->screens().count()); |
| 3903 | + EXPECT_EQ(QRect(500, 600, 1500, 2000), screenController->screens().at(0)->geometry()); |
| 3904 | +} |
| 3905 | + |
| 3906 | +TEST_F(ScreenControllerTest, MatchBufferWithDisplay) |
| 3907 | +{ |
| 3908 | + std::vector<mg::DisplayConfigurationOutput> config{fakeOutput1}; |
| 3909 | + MockGLDisplayBuffer buffer1; |
| 3910 | + std::vector<MockGLDisplayBuffer*> buffers {&buffer1}; |
| 3911 | + |
| 3912 | + geom::Rectangle buffer1Geom{{0, 0}, {150, 200}}; |
| 3913 | + EXPECT_CALL(buffer1, view_area()) |
| 3914 | + .WillRepeatedly(Return(buffer1Geom)); |
| 3915 | + |
| 3916 | + display->setFakeConfiguration(config, buffers); |
| 3917 | + screenController->update(); |
| 3918 | + |
| 3919 | + ASSERT_EQ(1, screenController->screens().count()); |
| 3920 | + EXPECT_CALL(buffer1, make_current()); |
| 3921 | + static_cast<StubScreen*>(screenController->screens().at(0))->makeCurrent(); |
| 3922 | +} |
| 3923 | + |
| 3924 | +TEST_F(ScreenControllerTest, MultipleMatchBuffersWithDisplays) |
| 3925 | +{ |
| 3926 | + std::vector<mg::DisplayConfigurationOutput> config{fakeOutput1, fakeOutput2}; |
| 3927 | + MockGLDisplayBuffer buffer1, buffer2; |
| 3928 | + std::vector<MockGLDisplayBuffer*> buffers {&buffer1, &buffer2}; |
| 3929 | + |
| 3930 | + geom::Rectangle buffer1Geom{{500, 600}, {1500, 2000}}; |
| 3931 | + geom::Rectangle buffer2Geom{{0, 0}, {150, 200}}; |
| 3932 | + EXPECT_CALL(buffer1, view_area()) |
| 3933 | + .WillRepeatedly(Return(buffer1Geom)); |
| 3934 | + EXPECT_CALL(buffer2, view_area()) |
| 3935 | + .WillRepeatedly(Return(buffer2Geom)); |
| 3936 | + |
| 3937 | + display->setFakeConfiguration(config, buffers); |
| 3938 | + screenController->update(); |
| 3939 | + |
| 3940 | + ASSERT_EQ(2, screenController->screens().count()); |
| 3941 | + EXPECT_CALL(buffer1, make_current()); |
| 3942 | + EXPECT_CALL(buffer2, make_current()); |
| 3943 | + static_cast<StubScreen*>(screenController->screens().at(0))->makeCurrent(); |
| 3944 | + static_cast<StubScreen*>(screenController->screens().at(1))->makeCurrent(); |
| 3945 | +} |
| 3946 | |
| 3947 | === added file 'tests/mirserver/ScreenController/stub_display.h' |
| 3948 | --- tests/mirserver/ScreenController/stub_display.h 1970-01-01 00:00:00 +0000 |
| 3949 | +++ tests/mirserver/ScreenController/stub_display.h 2015-10-16 17:43:47 +0000 |
| 3950 | @@ -0,0 +1,96 @@ |
| 3951 | +/* |
| 3952 | + * Copyright (C) 2015 Canonical, Ltd. |
| 3953 | + * |
| 3954 | + * This program is free software: you can redistribute it and/or modify it under |
| 3955 | + * the terms of the GNU Lesser General Public License version 3, as published by |
| 3956 | + * the Free Software Foundation. |
| 3957 | + * |
| 3958 | + * This program is distributed in the hope that it will be useful, but WITHOUT |
| 3959 | + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
| 3960 | + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 3961 | + * Lesser General Public License for more details. |
| 3962 | + * |
| 3963 | + * You should have received a copy of the GNU Lesser General Public License |
| 3964 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 3965 | + */ |
| 3966 | + |
| 3967 | +#ifndef STUB_DISPLAY_H |
| 3968 | +#define STUB_DISPLAY_H |
| 3969 | + |
| 3970 | +#include "mock_display.h" |
| 3971 | +#include "mock_gl_display_buffer.h" |
| 3972 | +#include "mock_display_configuration.h" |
| 3973 | + |
| 3974 | +namespace mg = mir::graphics; |
| 3975 | +namespace geom = mir::geometry; |
| 3976 | + |
| 3977 | +class StubDisplayConfiguration : public MockDisplayConfiguration |
| 3978 | +{ |
| 3979 | +public: |
| 3980 | + StubDisplayConfiguration(const std::vector<mg::DisplayConfigurationOutput> &config) |
| 3981 | + : m_config(config) |
| 3982 | + {} |
| 3983 | + |
| 3984 | + void for_each_output(std::function<void(mg::DisplayConfigurationOutput const&)> f) const override |
| 3985 | + { |
| 3986 | + for (auto config : m_config) { |
| 3987 | + f(config); |
| 3988 | + } |
| 3989 | + } |
| 3990 | + |
| 3991 | +private: |
| 3992 | + const std::vector<mg::DisplayConfigurationOutput> m_config; |
| 3993 | +}; |
| 3994 | + |
| 3995 | + |
| 3996 | +class StubDisplaySyncGroup : public MockDisplaySyncGroup |
| 3997 | +{ |
| 3998 | +public: |
| 3999 | + StubDisplaySyncGroup(MockGLDisplayBuffer *buffer) : buffer(buffer) {} |
| 4000 | + |
| 4001 | + void for_each_display_buffer(std::function<void(mg::DisplayBuffer&)> const& f) override |
| 4002 | + { |
| 4003 | + f(*buffer); |
| 4004 | + } |
| 4005 | + std::chrono::milliseconds recommended_sleep() const |
| 4006 | + { |
| 4007 | + std::chrono::milliseconds one{1}; |
| 4008 | + return one; |
| 4009 | + } |
| 4010 | +private: |
| 4011 | + MockGLDisplayBuffer *buffer; |
| 4012 | +}; |
| 4013 | + |
| 4014 | + |
| 4015 | +class StubDisplay : public MockDisplay |
| 4016 | +{ |
| 4017 | +public: |
| 4018 | + // Note, GMock cannot mock functions which return non-copyable objects, so stubbing needed |
| 4019 | + std::unique_ptr<mg::DisplayConfiguration> configuration() const override |
| 4020 | + { |
| 4021 | + return std::unique_ptr<mg::DisplayConfiguration>( |
| 4022 | + new StubDisplayConfiguration(m_config) |
| 4023 | + ); |
| 4024 | + } |
| 4025 | + |
| 4026 | + void for_each_display_sync_group(std::function<void(mg::DisplaySyncGroup&)> const& f) override |
| 4027 | + { |
| 4028 | + for (auto displayBuffer : m_displayBuffers) { |
| 4029 | + StubDisplaySyncGroup b(displayBuffer); |
| 4030 | + f(b); |
| 4031 | + } |
| 4032 | + } |
| 4033 | + |
| 4034 | + void setFakeConfiguration(std::vector<mg::DisplayConfigurationOutput> &config, |
| 4035 | + std::vector<MockGLDisplayBuffer*> &displayBuffers) |
| 4036 | + { |
| 4037 | + m_config = config; |
| 4038 | + m_displayBuffers = displayBuffers; |
| 4039 | + } |
| 4040 | + |
| 4041 | +private: |
| 4042 | + std::vector<mg::DisplayConfigurationOutput> m_config; |
| 4043 | + std::vector<MockGLDisplayBuffer*> m_displayBuffers; |
| 4044 | +}; |
| 4045 | + |
| 4046 | +#endif // STUB_DISPLAY_H |
| 4047 | |
| 4048 | === added file 'tests/mirserver/ScreenController/stub_screen.h' |
| 4049 | --- tests/mirserver/ScreenController/stub_screen.h 1970-01-01 00:00:00 +0000 |
| 4050 | +++ tests/mirserver/ScreenController/stub_screen.h 2015-10-16 17:43:47 +0000 |
| 4051 | @@ -0,0 +1,31 @@ |
| 4052 | +/* |
| 4053 | + * Copyright (C) 2015 Canonical, Ltd. |
| 4054 | + * |
| 4055 | + * This program is free software: you can redistribute it and/or modify it under |
| 4056 | + * the terms of the GNU Lesser General Public License version 3, as published by |
| 4057 | + * the Free Software Foundation. |
| 4058 | + * |
| 4059 | + * This program is distributed in the hope that it will be useful, but WITHOUT |
| 4060 | + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
| 4061 | + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 4062 | + * Lesser General Public License for more details. |
| 4063 | + * |
| 4064 | + * You should have received a copy of the GNU Lesser General Public License |
| 4065 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 4066 | + */ |
| 4067 | + |
| 4068 | +#ifndef STUBSCREEN_H |
| 4069 | +#define STUBSCREEN_H |
| 4070 | + |
| 4071 | +#include "screen.h" |
| 4072 | + |
| 4073 | +class StubScreen : public Screen |
| 4074 | +{ |
| 4075 | + Q_OBJECT |
| 4076 | +public: |
| 4077 | + StubScreen(const mir::graphics::DisplayConfigurationOutput &output) : Screen(output) {} |
| 4078 | + |
| 4079 | + void makeCurrent() { Screen::makeCurrent(); } |
| 4080 | +}; |
| 4081 | + |
| 4082 | +#endif // STUBSCREEN_H |
| 4083 | |
| 4084 | === added file 'tests/mirserver/ScreenController/testable_screencontroller.h' |
| 4085 | --- tests/mirserver/ScreenController/testable_screencontroller.h 1970-01-01 00:00:00 +0000 |
| 4086 | +++ tests/mirserver/ScreenController/testable_screencontroller.h 2015-10-16 17:43:47 +0000 |
| 4087 | @@ -0,0 +1,37 @@ |
| 4088 | +/* |
| 4089 | + * Copyright (C) 2015 Canonical, Ltd. |
| 4090 | + * |
| 4091 | + * This program is free software: you can redistribute it and/or modify it under |
| 4092 | + * the terms of the GNU Lesser General Public License version 3, as published by |
| 4093 | + * the Free Software Foundation. |
| 4094 | + * |
| 4095 | + * This program is distributed in the hope that it will be useful, but WITHOUT |
| 4096 | + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
| 4097 | + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 4098 | + * Lesser General Public License for more details. |
| 4099 | + * |
| 4100 | + * You should have received a copy of the GNU Lesser General Public License |
| 4101 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 4102 | + */ |
| 4103 | + |
| 4104 | +#include "screencontroller.h" |
| 4105 | +#include "stub_screen.h" |
| 4106 | + |
| 4107 | +struct TestableScreenController : public ScreenController |
| 4108 | +{ |
| 4109 | + Q_OBJECT |
| 4110 | + |
| 4111 | +public: |
| 4112 | + Screen *createScreen(const mir::graphics::DisplayConfigurationOutput &output) const override |
| 4113 | + { |
| 4114 | + return new StubScreen(output); |
| 4115 | + } |
| 4116 | + |
| 4117 | + void do_init(const std::shared_ptr<mir::graphics::Display> &display, |
| 4118 | + const std::shared_ptr<mir::compositor::Compositor> &compositor) |
| 4119 | + { |
| 4120 | + init(display, compositor); |
| 4121 | + } |
| 4122 | + |
| 4123 | + void do_terminate() { terminate(); } |
| 4124 | +}; |
| 4125 | |
| 4126 | === modified file 'tests/modules/common/fake_mirsurface.h' |
| 4127 | --- tests/modules/common/fake_mirsurface.h 2015-09-25 17:30:26 +0000 |
| 4128 | +++ tests/modules/common/fake_mirsurface.h 2015-10-16 17:43:47 +0000 |
| 4129 | @@ -130,10 +130,12 @@ |
| 4130 | } |
| 4131 | } |
| 4132 | |
| 4133 | + void consumeBuffer() override {} |
| 4134 | + |
| 4135 | // methods called from the rendering (scene graph) thread: |
| 4136 | QSharedPointer<QSGTexture> texture() override { return QSharedPointer<QSGTexture>(); } |
| 4137 | QSGTexture *weakTexture() const override { return nullptr; } |
| 4138 | - void updateTexture() override {} |
| 4139 | + bool updateTexture() override { return true; } |
| 4140 | unsigned int currentFrameNumber() const override { return 0; } |
| 4141 | bool numBuffersReadyForCompositor() override { return 0; } |
| 4142 | // end of methods called from the rendering (scene graph) thread |
| 4143 | |
| 4144 | === modified file 'tests/modules/common/qtmir_test.h' |
| 4145 | --- tests/modules/common/qtmir_test.h 2015-08-11 12:08:32 +0000 |
| 4146 | +++ tests/modules/common/qtmir_test.h 2015-10-16 17:43:47 +0000 |
| 4147 | @@ -78,7 +78,7 @@ |
| 4148 | { |
| 4149 | public: |
| 4150 | FakeMirServer() |
| 4151 | - : MirServer(0, argv) |
| 4152 | + : MirServer(0, argv, QSharedPointer<ScreenController>()) |
| 4153 | { |
| 4154 | } |
| 4155 |

FAILED: Continuous integration, rev:370 jenkins. qa.ubuntu. com/job/ qtmir-ci/ 412/ jenkins. qa.ubuntu. com/job/ qtmir-wily- amd64-ci/ 145/console jenkins. qa.ubuntu. com/job/ qtmir-wily- armhf-ci/ 145/console
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/qtmir- ci/412/ rebuild
http://