Mir

Merge lp:~andreas-pokorny/mir/map-touchscreen-to-output into lp:mir

Proposed by Andreas Pokorny
Status: Merged
Approved by: Daniel van Vugt
Approved revision: no longer in the source branch.
Merged at revision: 4067
Proposed branch: lp:~andreas-pokorny/mir/map-touchscreen-to-output
Merge into: lp:mir
Prerequisite: lp:~andreas-pokorny/mir/add-touchscreen-settings
Diff against target: 1859 lines (+946/-126)
29 files modified
include/client/mir_toolkit/client_types.h (+1/-0)
include/client/mir_toolkit/mir_input_device.h (+68/-0)
include/core/mir_toolkit/mir_input_device_types.h (+2/-2)
include/platform/mir/input/input_sink.h (+34/-1)
include/platform/mir/input/touchscreen_settings.h (+5/-0)
include/test/mir_test_framework/fake_input_device.h (+9/-0)
src/client/mir_input_device_api.cpp (+35/-0)
src/client/symbols.map (+6/-0)
src/include/server/mir/input/seat.h (+5/-1)
src/platforms/evdev/libinput_device.cpp (+49/-4)
src/platforms/evdev/libinput_device.h (+3/-0)
src/server/graphics/nested/input_platform.cpp (+18/-2)
src/server/input/basic_seat.cpp (+132/-12)
src/server/input/basic_seat.h (+15/-7)
src/server/input/default_configuration.cpp (+1/-1)
src/server/input/default_input_device_hub.cpp (+9/-1)
src/server/input/default_input_device_hub.h (+2/-1)
src/server/input/seat_input_device_tracker.cpp (+8/-4)
src/server/input/seat_input_device_tracker.h (+11/-2)
src/server/scene/surface_stack.cpp (+1/-5)
tests/acceptance-tests/test_client_input.cpp (+207/-33)
tests/include/mir/test/doubles/mock_input_seat.h (+3/-1)
tests/include/mir/test/doubles/mock_input_sink.h (+1/-0)
tests/integration-tests/input/test_single_seat_setup.cpp (+47/-14)
tests/mir_test_framework/fake_input_device_impl.cpp (+76/-14)
tests/mir_test_framework/fake_input_device_impl.h (+14/-0)
tests/unit-tests/input/evdev/test_libinput_device.cpp (+181/-15)
tests/unit-tests/input/test_seat_input_device_tracker.cpp (+1/-4)
tests/unit-tests/scene/test_surface_stack.cpp (+2/-2)
To merge this branch: bzr merge lp:~andreas-pokorny/mir/map-touchscreen-to-output
Reviewer Review Type Date Requested Status
Daniel van Vugt Abstain
Mir CI Bot continuous-integration Approve
Alan Griffiths Approve
Review via email: mp+316709@code.launchpad.net

Commit message

Map Touchscreen to Output: Allow clients to configure a relation between touchscreen and display outputs

When configured the touch contact coordinates will be mapped into the screen space occupied by the output. Previously the first output was used as default and orientation information was ignored. This default behavior is still in place - when not configured the builtin output on android devices will be used. Additionally the connection between input devices and outputs is used to disable input events from deactivated outputs.

Description of the change

This change allows clients to configure a mapping of touchscreen onto actual outputs. Such that the coordinates originating from the configured device will map into the screen space occupied by the output.

This change also bypasses the existing code around InputRegion which removed the output information to early in the stack..

The information about output to input device relation is forwarded to the host server, and handled in stub and evdev platform. Thus the feature needed an ABI/API break in input platform - which is the second inside the yet unreleased 0.27 series - so there is no ABI bump in this MP.

To post a comment you must log in.
Revision history for this message
Mir CI Bot (mir-ci-bot) wrote :

FAILED: Continuous integration, rev:4009
https://mir-jenkins.ubuntu.com/job/mir-ci/2954/
Executed test runs:
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-mir/3915/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-0-fetch/4001/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/3991/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial+overlay/3991/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/3991/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/3942/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial+overlay/3942/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/3942/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/3942/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/3942/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial+overlay/3942/console

Click here to trigger a rebuild:
https://mir-jenkins.ubuntu.com/job/mir-ci/2954/rebuild

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

FAILED: Continuous integration, rev:4011
https://mir-jenkins.ubuntu.com/job/mir-ci/2962/
Executed test runs:
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-mir/3930/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-0-fetch/4016/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/4006/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial+overlay/4006/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/4006/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/3957/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial+overlay/3957/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/3957/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/3957/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/3957/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial+overlay/3957/console

Click here to trigger a rebuild:
https://mir-jenkins.ubuntu.com/job/mir-ci/2962/rebuild

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

FAILED: Continuous integration, rev:4014
https://mir-jenkins.ubuntu.com/job/mir-ci/2972/
Executed test runs:
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-mir/3948/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/4034
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/4024
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial+overlay/4024
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/4024
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/3975/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial+overlay/3975/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/3975/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/3975
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/3975/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/3975
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/3975/artifact/output/*zip*/output.zip
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial+overlay/3975/console

Click here to trigger a rebuild:
https://mir-jenkins.ubuntu.com/job/mir-ci/2972/rebuild

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

PASSED: Continuous integration, rev:4015
https://mir-jenkins.ubuntu.com/job/mir-ci/2973/
Executed test runs:
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-mir/3951
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/4037
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/4027
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial+overlay/4027
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/4027
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/3978
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/3978/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial+overlay/3978
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial+overlay/3978/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/3978
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/3978/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/3978
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/3978/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/3978
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/3978/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial+overlay/3978
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial+overlay/3978/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://mir-jenkins.ubuntu.com/job/mir-ci/2973/rebuild

review: Approve (continuous-integration)
Revision history for this message
Mir CI Bot (mir-ci-bot) wrote :

FAILED: Continuous integration, rev:4016
https://mir-jenkins.ubuntu.com/job/mir-ci/3020/
Executed test runs:
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-mir/4032/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/4119
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/4109
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial+overlay/4109
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/4109
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4059/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial+overlay/4059
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial+overlay/4059/artifact/output/*zip*/output.zip
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4059/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/4059
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/4059/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/4059
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/4059/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial+overlay/4059
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial+overlay/4059/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://mir-jenkins.ubuntu.com/job/mir-ci/3020/rebuild

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

PASSED: Continuous integration, rev:4017
https://mir-jenkins.ubuntu.com/job/mir-ci/3033/
Executed test runs:
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-mir/4052
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/4139
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/4129
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial+overlay/4129
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/4129
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4079
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4079/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial+overlay/4079
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial+overlay/4079/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4079
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4079/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/4079
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/4079/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/4079
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/4079/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial+overlay/4079
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial+overlay/4079/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://mir-jenkins.ubuntu.com/job/mir-ci/3033/rebuild

review: Approve (continuous-integration)
Revision history for this message
Mir CI Bot (mir-ci-bot) wrote :

PASSED: Continuous integration, rev:4018
https://mir-jenkins.ubuntu.com/job/mir-ci/3037/
Executed test runs:
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-mir/4059
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/4146
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/4136
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial+overlay/4136
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/4136
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4086
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4086/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial+overlay/4086
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial+overlay/4086/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4086
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4086/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/4086
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/4086/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/4086
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/4086/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial+overlay/4086
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial+overlay/4086/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://mir-jenkins.ubuntu.com/job/mir-ci/3037/rebuild

review: Approve (continuous-integration)
Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

+void mir_touchscreen_config_set_mapping_mode(MirTouchscreenConfig* config, enum MirTouchscreenMappingMode mode);

We shouldn't need to type "enum MirTouchscreenMappingMode" in C code. There's a missing typedef in the existing code...

    enum MirTouchscreenMappingMode
    {
    ...
    };

=>

    typedef enum MirTouchscreenMappingMode
    {
    ...
    } MirTouchscreenMappingMode;

Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

1. Is it worthwhile having both mutable and immutable MirTouchscreenConfig?

2. Are we confident this API won't ever change? (If it might change then it ought to be accessed via the extensions mechanism.)

review: Needs Information
Revision history for this message
Andreas Pokorny (andreas-pokorny) wrote :

> 1. Is it worthwhile having both mutable and immutable MirTouchscreenConfig?

We have a non const / const API for all configurations. Touchscreen is not different or special in that reguard.

> 2. Are we confident this API won't ever change? (If it might change then it
> ought to be accessed via the extensions mechanism.)

Revision history for this message
Andreas Pokorny (andreas-pokorny) wrote :

> 2. Are we confident this API won't ever change? (If it might change then it
> ought to be accessed via the extensions mechanism.)

I cannot respond for the group but this proposal contains the minimum necessary information to get touchscreen coordinates into the system.. I do not expect we would need less in the future - maybe more.. but even that is rather unlikely.

Revision history for this message
Mir CI Bot (mir-ci-bot) wrote :

FAILED: Continuous integration, rev:4019
https://mir-jenkins.ubuntu.com/job/mir-ci/3048/
Executed test runs:
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-mir/4074/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-0-fetch/4161/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/4151/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial+overlay/4151/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/4151/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4101/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial+overlay/4101/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4101/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/4101/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/4101/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial+overlay/4101/console

Click here to trigger a rebuild:
https://mir-jenkins.ubuntu.com/job/mir-ci/3048/rebuild

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

PASSED: Continuous integration, rev:4020
https://mir-jenkins.ubuntu.com/job/mir-ci/3049/
Executed test runs:
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-mir/4075
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/4162
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/4152
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial+overlay/4152
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/4152
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4102
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4102/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial+overlay/4102
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial+overlay/4102/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4102
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4102/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/4102
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/4102/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/4102
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/4102/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial+overlay/4102
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial+overlay/4102/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://mir-jenkins.ubuntu.com/job/mir-ci/3049/rebuild

review: Approve (continuous-integration)
Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

Nits:

+enum MirTouchscreenMappingMode mir_touchscreen_config_get_mapping_mode(MirTouchscreenConfig const* device);
...
+void mir_touchscreen_config_set_mapping_mode(MirTouchscreenConfig* config, enum MirTouchscreenMappingMode mode);

Don't need "enum" now.

review: Approve
Revision history for this message
Daniel van Vugt (vanvugt) wrote :

I'm slightly concerned about this (but only if it hasn't been tested):

527 + if (output.current_mode_index < output.modes.size())
528 + {
529 + data.output_size = output.modes[output.current_mode_index].size;
530 + if (data.active)
531 + output_rectangles.add(output.extents());
532 + }

Can you confirm that the touch coordinates are correct (like in target or fingerpaint) when the current mode is lower resolution than the screen's native mode? In future the opposite might also be true (screen is mirroring a higher res output and is scaled down)...

review: Needs Information
Revision history for this message
Daniel van Vugt (vanvugt) wrote :

Don't we want preferred_mode_index rather than current_mode_index?

preferred_mode_index will more reliably tell you the pixel-size of the screen that will more likely match with touchscreen coordinates.

review: Needs Information
Revision history for this message
Daniel van Vugt (vanvugt) wrote :

The current_mode_index is already taken into consideration in the implementation of extents(). So that's your (target) logical rectangle. Your (source) physical touchscreen rectangle should be from preferred_mode_index.

Revision history for this message
Andreas Pokorny (andreas-pokorny) wrote :

> Don't we want preferred_mode_index rather than current_mode_index?
>
> preferred_mode_index will more reliably tell you the pixel-size of the screen
> that will more likely match with touchscreen coordinates.

But the intent is not to get the original screen size but the position size and orientation of the output inside the scene. Actually the native resolution does not matter all..

If the touchscreen coordinate values are not in the range defined by the evdev axis for x and y. The system vendor should either fix the kernel driver or the users has to set a calibration matrix via udev. libinput uses the evdev axis ranges and the calibration matrix to return proper device coordinates.

Revision history for this message
Daniel van Vugt (vanvugt) wrote :

If preferred_mode_index is incorrect then so is current_mode_index. Because in the near future we'll have a logical output size that's different to the current mode dimensions (bug 1639226). So the current mode dimensions must be ignored. Instead please use "extents().size" to get the correct size of the output in the scene.

Soon "output.modes[output.current_mode_index].size" will be completely irrelevant to the logical size of the screen. Although in some cases "output.modes[output.preferred_mode_index].size" might be useful for figuring out the physical pixel size.

review: Needs Fixing
Revision history for this message
Andreas Pokorny (andreas-pokorny) wrote :

> If preferred_mode_index is incorrect then so is current_mode_index. Because in
> the near future we'll have a logical output size that's different to the
> current mode dimensions (bug 1639226). So the current mode dimensions must be
> ignored. Instead please use "extents().size" to get the correct size of the
> output in the scene.

So you are requiring a change based on an future change that may or may not affect the validity of the modes vector?

But you do understand that I do need an untransformed coordinate range for the x and y axis of the touchscreen? I can use the preferred_mode_index as a basis for that, but then I need to do additional scaling after that to get to the current mode. Or instead use the current size directly.
extents().size would be incorrect now and later since it already applies rotation.

I do think about changing the Output to expose a transformation matrix instead of the output orientation and output position. But then still libinput needs an output size.

Revision history for this message
Mir CI Bot (mir-ci-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Mir CI Bot (mir-ci-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Mir CI Bot (mir-ci-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Mir CI Bot (mir-ci-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Daniel van Vugt (vanvugt) wrote :

> So you are requiring a change based on an future change that may or may not
> affect the validity of the modes vector?

Yes, that "future change" I am told is my #1 priority to get working for Mir 1.0 (bug 1639226).

> But you do understand that I do need an untransformed coordinate range for the
> x and y axis of the touchscreen? I can use the preferred_mode_index as a basis
> for that,

Yes, that's why I suggested preferred_mode_index.

> I do think about changing the Output to expose a transformation matrix instead
> of the output orientation and output position. But then still libinput needs
> an output size.

Yes, I agree and have been thinking that Output may soon need to expose a transformation matrix. DisplayBuffer already does (since r4001), but I think it may need to be guided by a transformation matrix of the output in future.

Revision history for this message
Mir CI Bot (mir-ci-bot) wrote :

FAILED: Continuous integration, rev:4026
https://mir-jenkins.ubuntu.com/job/mir-ci/3082/
Executed test runs:
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-mir/4125/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/4212
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/4202
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial+overlay/4202
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/4202
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4152/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial+overlay/4152/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4152/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/4152/console
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/4152/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/4152
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/4152/artifact/output/*zip*/output.zip
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial+overlay/4152/console

Click here to trigger a rebuild:
https://mir-jenkins.ubuntu.com/job/mir-ci/3082/rebuild

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

FAILED: Continuous integration, rev:4027
https://mir-jenkins.ubuntu.com/job/mir-ci/3086/
Executed test runs:
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-mir/4130/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/4217
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/4207
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial+overlay/4207
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/4207
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4157/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial+overlay/4157/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4157/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/4157/console
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/4157/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/4157
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/4157/artifact/output/*zip*/output.zip
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial+overlay/4157/console

Click here to trigger a rebuild:
https://mir-jenkins.ubuntu.com/job/mir-ci/3086/rebuild

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

FAILED: Continuous integration, rev:4028
https://mir-jenkins.ubuntu.com/job/mir-ci/3090/
Executed test runs:
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-mir/4135/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/4222
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/4212
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial+overlay/4212
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/4212
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4162/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial+overlay/4162
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial+overlay/4162/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4162
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4162/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/4162
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/4162/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/4162
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/4162/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial+overlay/4162
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial+overlay/4162/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://mir-jenkins.ubuntu.com/job/mir-ci/3090/rebuild

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

PASSED: Continuous integration, rev:4029
https://mir-jenkins.ubuntu.com/job/mir-ci/3091/
Executed test runs:
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-mir/4136
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/4223
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/4213
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial+overlay/4213
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/4213
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4163
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4163/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial+overlay/4163
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial+overlay/4163/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4163
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4163/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/4163
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/4163/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/4163
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/4163/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial+overlay/4163
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial+overlay/4163/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://mir-jenkins.ubuntu.com/job/mir-ci/3091/rebuild

review: Approve (continuous-integration)
Revision history for this message
Daniel van Vugt (vanvugt) wrote :

Oh, sorry... Are you using current_mode_index because the raw touch coordinates from the kernel/libinput change based on the current display mode? I was assuming raw touch coordinates from the kernel would always just match the native resolution (preferred_mode_index).

review: Needs Information
Revision history for this message
Andreas Pokorny (andreas-pokorny) wrote :

> Oh, sorry... Are you using current_mode_index because the raw touch
> coordinates from the kernel/libinput change based on the current display mode?
> I was assuming raw touch coordinates from the kernel would always just match
> the native resolution (preferred_mode_index).

No neither is true. The kernel gives touch coordinates in the ranges the device offers. The two ranges sometimes contain information to calculate physical coordinates (as in mm or inch), but on android device that factor is either zero or one. We cannot assume that the ranges given will match the display resolution. (side note: one can affect the values by setting udev properties, but those are meant to make the coordinate axis align with the display axis, those calibration settings cannot account for runtime configuration of the display) Because of that libinput requires a range parameter when reading pixel coordinates from touch screens. Since the touchscreen itself is not rotated when the display is rotated via kms or software rotation I use the number of pixels in unrotated x and y direction (extent() gives me the axis ranges after rotation). By already using the (currently) final scalings of the x and y coordinate axis the code that does rotation and translation to the scene setup of the output is easier to follow.. i.e does not involve further scaling steps..

So with the last change I tried to detangle the display configuration properties from the touchscreen to output mapping. No more orientation enum and position parameter. So with a transformation matrix in place you will be able to modify that as needed.. I.e. make all scalings inside the matrix and make the output sizes such that the coordinates get mapped into unit-square.. or supply an already scaled output size..

Revision history for this message
Daniel van Vugt (vanvugt) wrote :

OK. If there are any real problems with this approach, we won't notice any time soon. It's unlikely many people will be using touchscreens in the non-native mode or as clones other outputs.

I mean we may hit bugs in this code but we'll really need to release it first to see what those bugs are...

review: Abstain

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'include/client/mir_toolkit/client_types.h'
--- include/client/mir_toolkit/client_types.h 2017-02-22 14:36:45 +0000
+++ include/client/mir_toolkit/client_types.h 2017-03-01 16:08:29 +0000
@@ -394,6 +394,7 @@
394typedef struct MirKeyboardConfig MirKeyboardConfig;394typedef struct MirKeyboardConfig MirKeyboardConfig;
395typedef struct MirPointerConfig MirPointerConfig;395typedef struct MirPointerConfig MirPointerConfig;
396typedef struct MirTouchpadConfig MirTouchpadConfig;396typedef struct MirTouchpadConfig MirTouchpadConfig;
397typedef struct MirTouchscreenConfig MirTouchscreenConfig;
397398
398/**399/**
399 * MirScreencastParameters is the structure of required information that400 * MirScreencastParameters is the structure of required information that
400401
=== modified file 'include/client/mir_toolkit/mir_input_device.h'
--- include/client/mir_toolkit/mir_input_device.h 2017-02-14 16:08:27 +0000
+++ include/client/mir_toolkit/mir_input_device.h 2017-03-01 16:08:29 +0000
@@ -572,6 +572,74 @@
572void mir_touchpad_config_set_disable_while_typing(572void mir_touchpad_config_set_disable_while_typing(
573 MirTouchpadConfig* conf, bool active);573 MirTouchpadConfig* conf, bool active);
574574
575/**
576 * Retrieve a structure containing the touchscreen related config options
577 * of the input device.
578 *
579 * If the input device does not contain a touchscreen, there are no
580 * config options, and the function will return a null pointer.
581 *
582 * \param [in] device The input device
583 *
584 * \return The touchscreen config
585 */
586MirTouchscreenConfig const* mir_input_device_get_touchscreen_config(
587 MirInputDevice const* device);
588
589/**
590 * Get the output ID of the display the coordinates of this device will be mapped to.
591 *
592 * This setting is ignored when the mapping mode is set to
593 * mir_touchscreen_mapping_mode_to_display_wall.
594 *
595 * \param [in] device The touchscreen configuration
596 *
597 * \return The output id
598 */
599uint32_t mir_touchscreen_config_get_output_id(MirTouchscreenConfig const* device);
600
601/**
602 * Get the mapping mode used for the touchscreen
603 *
604 * \param [in] device The touchscreen configuration
605 *
606 * \return The mapping mode
607 */
608enum MirTouchscreenMappingMode mir_touchscreen_config_get_mapping_mode(MirTouchscreenConfig const* device);
609
610/**
611 * Retrieve a mutable structure containing the touchscreen related options
612 * of the input device to change the device configuration.
613 *
614 * If the input device does not contain a touchscreen, there are no
615 * config options, and the function will return a null pointer.
616 *
617 * \param [in] device The input device
618 *
619 * \return The touchscreen config
620 */
621MirTouchscreenConfig* mir_input_device_get_mutable_touchscreen_config(
622 MirInputDevice* device);
623
624/**
625 * Set the output ID of the display the coordinates of this device will be mapped to.
626 *
627 * This setting is ignored when the mapping mode is set to
628 * mir_touchscreen_mapping_mode_to_display_wall.
629 *
630 * \param [in] config The touchscreen configuration
631 * \param [in] output The output id
632 */
633void mir_touchscreen_config_set_output_id(MirTouchscreenConfig* config, uint32_t output);
634
635/**
636 * Set the mapping mode used for the touchscreen.
637 *
638 * \param [in] config The touchscreen configuration
639 * \param [in] mode The mapping mode
640 */
641void mir_touchscreen_config_set_mapping_mode(MirTouchscreenConfig* config, enum MirTouchscreenMappingMode mode);
642
575#ifdef __cplusplus643#ifdef __cplusplus
576}644}
577#endif645#endif
578646
=== modified file 'include/core/mir_toolkit/mir_input_device_types.h'
--- include/core/mir_toolkit/mir_input_device_types.h 2017-01-18 02:29:37 +0000
+++ include/core/mir_toolkit/mir_input_device_types.h 2017-03-01 16:08:29 +0000
@@ -113,7 +113,7 @@
113 * i.e handheld devices with builtin touchscreens or external graphic tablets or113 * i.e handheld devices with builtin touchscreens or external graphic tablets or
114 * external monitors with touchscreen capabilities.114 * external monitors with touchscreen capabilities.
115 */115 */
116enum MirTouchscreenMappingMode116typedef enum MirTouchscreenMappingMode
117{117{
118 /**118 /**
119 * Map the device coordinates onto specific output.119 * Map the device coordinates onto specific output.
@@ -123,7 +123,7 @@
123 * Map the device coordinates onto the whole wall of outputs.123 * Map the device coordinates onto the whole wall of outputs.
124 */124 */
125 mir_touchscreen_mapping_mode_to_display_wall125 mir_touchscreen_mapping_mode_to_display_wall
126};126} MirTouchscreenMappingMode;
127127
128128
129#ifdef __cplusplus129#ifdef __cplusplus
130130
=== modified file 'include/platform/mir/input/input_sink.h'
--- include/platform/mir/input/input_sink.h 2016-07-07 09:59:19 +0000
+++ include/platform/mir/input/input_sink.h 2017-03-01 16:08:29 +0000
@@ -22,14 +22,40 @@
2222
23#include "mir_toolkit/event.h"23#include "mir_toolkit/event.h"
24#include "mir/geometry/rectangle.h"24#include "mir/geometry/rectangle.h"
25#include "mir/geometry/displacement.h"25#include "mir/geometry/point.h"
2626
27#include <vector>27#include <vector>
28#include <array>
2829
29namespace mir30namespace mir
30{31{
31namespace input32namespace input
32{33{
34
35struct OutputInfo
36{
37 using Matrix = std::array<float,6>; // 2x3 row major matrix
38 OutputInfo() {}
39 OutputInfo(bool active, geometry::Size size, Matrix const& transformation)
40 : active{active}, output_size{size}, output_to_scene(transformation)
41 {}
42
43 bool active{false};
44 geometry::Size output_size;
45 Matrix output_to_scene{{1,0,0,
46 0,1,0}};
47
48 inline void transform_to_scene(float& x, float& y) const
49 {
50 auto original_x = x;
51 auto original_y = y;
52 auto const& mat = output_to_scene;
53
54 x = mat[0]*original_x + mat[1]*original_y + mat[2]*1;
55 y = mat[3]*original_x + mat[4]*original_y + mat[5]*1;
56 }
57};
58
33class InputSink59class InputSink
34{60{
35public:61public:
@@ -41,6 +67,13 @@
41 */67 */
42 virtual mir::geometry::Rectangle bounding_rectangle() const = 0;68 virtual mir::geometry::Rectangle bounding_rectangle() const = 0;
4369
70 /**!
71 * Obtain the output information for a specific ouput.
72 *
73 * \param[in] output_id the id of the output
74 */
75 virtual OutputInfo output_info(uint32_t output_id) const = 0;
76
44 /**77 /**
45 * \name Device State interface of InputSink78 * \name Device State interface of InputSink
46 *79 *
4780
=== modified file 'include/platform/mir/input/touchscreen_settings.h'
--- include/platform/mir/input/touchscreen_settings.h 2017-02-03 13:42:56 +0000
+++ include/platform/mir/input/touchscreen_settings.h 2017-03-01 16:08:29 +0000
@@ -30,6 +30,11 @@
3030
31struct TouchscreenSettings31struct TouchscreenSettings
32{32{
33 TouchscreenSettings() {}
34 TouchscreenSettings(uint32_t output_id, MirTouchscreenMappingMode mode)
35 : output_id{output_id}, mapping_mode{mode}
36 {}
37
33 /**38 /**
34 * Configures the output the input device should map its coordinates to.39 * Configures the output the input device should map its coordinates to.
35 * The value of this setting is only relevant when the mapping mode is40 * The value of this setting is only relevant when the mapping mode is
3641
=== modified file 'include/test/mir_test_framework/fake_input_device.h'
--- include/test/mir_test_framework/fake_input_device.h 2017-01-18 02:29:37 +0000
+++ include/test/mir_test_framework/fake_input_device.h 2017-03-01 16:08:29 +0000
@@ -24,6 +24,14 @@
24#include <chrono>24#include <chrono>
25#include <functional>25#include <functional>
2626
27namespace mir
28{
29namespace input
30{
31class InputDevice;
32}
33}
34
27namespace mir_test_framework35namespace mir_test_framework
28{36{
2937
@@ -52,6 +60,7 @@
52 virtual void emit_touch_sequence(std::function<mir::input::synthesis::TouchParameters(int)> const& generate_parameters,60 virtual void emit_touch_sequence(std::function<mir::input::synthesis::TouchParameters(int)> const& generate_parameters,
53 int count,61 int count,
54 std::chrono::duration<double> delay) = 0;62 std::chrono::duration<double> delay) = 0;
63 virtual void on_new_configuration_do(std::function<void(mir::input::InputDevice const& device)> callback) = 0;
5564
56 FakeInputDevice(FakeInputDevice const&) = delete;65 FakeInputDevice(FakeInputDevice const&) = delete;
57 FakeInputDevice& operator=(FakeInputDevice const&) = delete;66 FakeInputDevice& operator=(FakeInputDevice const&) = delete;
5867
=== modified file 'src/client/mir_input_device_api.cpp'
--- src/client/mir_input_device_api.cpp 2017-02-09 10:49:40 +0000
+++ src/client/mir_input_device_api.cpp 2017-03-01 16:08:29 +0000
@@ -20,6 +20,7 @@
20#include "mir/input/mir_keyboard_config.h"20#include "mir/input/mir_keyboard_config.h"
21#include "mir/input/mir_pointer_config.h"21#include "mir/input/mir_pointer_config.h"
22#include "mir/input/mir_touchpad_config.h"22#include "mir/input/mir_touchpad_config.h"
23#include "mir/input/mir_touchscreen_config.h"
23#include "mir/require.h"24#include "mir/require.h"
24#include "handle_event_exception.h"25#include "handle_event_exception.h"
2526
@@ -282,3 +283,37 @@
282{283{
283 conf->disable_while_typing(active);284 conf->disable_while_typing(active);
284})285})
286
287MirTouchscreenConfig const* mir_input_device_get_touchscreen_config(MirInputDevice const* device) MIR_HANDLE_EVENT_EXCEPTION(
288{
289 if (device->has_touchscreen_config())
290 return &device->touchscreen_config();
291 return nullptr;
292})
293
294uint32_t mir_touchscreen_config_get_output_id(MirTouchscreenConfig const* config) MIR_HANDLE_EVENT_EXCEPTION(
295{
296 return config->output_id();
297})
298
299MirTouchscreenMappingMode mir_touchscreen_config_get_mapping_mode(MirTouchscreenConfig const* config) MIR_HANDLE_EVENT_EXCEPTION(
300{
301 return config->mapping_mode();
302})
303
304MirTouchscreenConfig* mir_input_device_get_mutable_touchscreen_config(MirInputDevice* device) MIR_HANDLE_EVENT_EXCEPTION(
305{
306 if (device->has_touchscreen_config())
307 return &device->touchscreen_config();
308 return nullptr;
309})
310
311void mir_touchscreen_config_set_output_id(MirTouchscreenConfig* config, uint32_t id) MIR_HANDLE_EVENT_EXCEPTION(
312{
313 return config->output_id(id);
314})
315
316void mir_touchscreen_config_set_mapping_mode(MirTouchscreenConfig* config, MirTouchscreenMappingMode mode) MIR_HANDLE_EVENT_EXCEPTION(
317{
318 return config->mapping_mode(mode);
319})
285320
=== modified file 'src/client/symbols.map'
--- src/client/symbols.map 2017-02-24 14:11:28 +0000
+++ src/client/symbols.map 2017-03-01 16:08:29 +0000
@@ -616,6 +616,8 @@
616 mir_get_client_api_version;616 mir_get_client_api_version;
617 mir_input_device_get_keyboard_config;617 mir_input_device_get_keyboard_config;
618 mir_input_device_get_mutable_keyboard_config;618 mir_input_device_get_mutable_keyboard_config;
619 mir_input_device_get_mutable_touchscreen_config;
620 mir_input_device_get_touchscreen_config;
619 mir_keyboard_config_get_keymap_layout;621 mir_keyboard_config_get_keymap_layout;
620 mir_keyboard_config_get_keymap_model;622 mir_keyboard_config_get_keymap_model;
621 mir_keyboard_config_get_keymap_options;623 mir_keyboard_config_get_keymap_options;
@@ -627,4 +629,8 @@
627 mir_keyboard_event_key_text;629 mir_keyboard_event_key_text;
628 mir_output_get_logical_height;630 mir_output_get_logical_height;
629 mir_output_get_logical_width;631 mir_output_get_logical_width;
632 mir_touchscreen_config_get_mapping_mode;
633 mir_touchscreen_config_get_output_id;
634 mir_touchscreen_config_set_mapping_mode;
635 mir_touchscreen_config_set_output_id;
630} MIR_CLIENT_0.26.1;636} MIR_CLIENT_0.26.1;
631637
=== modified file 'src/include/server/mir/input/seat.h'
--- src/include/server/mir/input/seat.h 2017-01-18 02:29:37 +0000
+++ src/include/server/mir/input/seat.h 2017-03-01 16:08:29 +0000
@@ -33,6 +33,8 @@
33namespace input33namespace input
34{34{
35class Device;35class Device;
36class OutputInfo;
37
36class Seat38class Seat
37{39{
38public:40public:
@@ -41,7 +43,6 @@
41 virtual void add_device(Device const& device) = 0;43 virtual void add_device(Device const& device) = 0;
42 virtual void remove_device(Device const& device) = 0;44 virtual void remove_device(Device const& device) = 0;
43 virtual void dispatch_event(MirEvent& event) = 0;45 virtual void dispatch_event(MirEvent& event) = 0;
44 virtual geometry::Rectangle get_rectangle_for(Device const& dev) = 0;
45 virtual EventUPtr create_device_state() = 0;46 virtual EventUPtr create_device_state() = 0;
4647
47 virtual void set_key_state(Device const& dev, std::vector<uint32_t> const& scan_codes) = 0;48 virtual void set_key_state(Device const& dev, std::vector<uint32_t> const& scan_codes) = 0;
@@ -49,6 +50,9 @@
49 virtual void set_cursor_position(float cursor_x, float cursor_y) = 0;50 virtual void set_cursor_position(float cursor_x, float cursor_y) = 0;
50 virtual void set_confinement_regions(geometry::Rectangles const& regions) = 0;51 virtual void set_confinement_regions(geometry::Rectangles const& regions) = 0;
51 virtual void reset_confinement_regions() = 0;52 virtual void reset_confinement_regions() = 0;
53
54 virtual geometry::Rectangle bounding_rectangle() const = 0;
55 virtual input::OutputInfo output_info(uint32_t output_id) const = 0;
52private:56private:
53 Seat(Seat const&) = delete;57 Seat(Seat const&) = delete;
54 Seat& operator=(Seat const&) = delete;58 Seat& operator=(Seat const&) = delete;
5559
=== modified file 'src/platforms/evdev/libinput_device.cpp'
--- src/platforms/evdev/libinput_device.cpp 2017-02-03 01:10:42 +0000
+++ src/platforms/evdev/libinput_device.cpp 2017-03-01 16:08:29 +0000
@@ -114,7 +114,10 @@
114 // Not yet provided by libinput.114 // Not yet provided by libinput.
115 break;115 break;
116 case LIBINPUT_EVENT_TOUCH_FRAME:116 case LIBINPUT_EVENT_TOUCH_FRAME:
117 sink->handle_input(*convert_touch_frame(libinput_event_get_touch_event(event)));117 if (is_output_active())
118 {
119 sink->handle_input(*convert_touch_frame(libinput_event_get_touch_event(event)));
120 }
118 break;121 break;
119 default:122 default:
120 break;123 break;
@@ -184,6 +187,7 @@
184 auto const action = mir_pointer_action_motion;187 auto const action = mir_pointer_action_motion;
185 auto const hscroll_value = 0.0f;188 auto const hscroll_value = 0.0f;
186 auto const vscroll_value = 0.0f;189 auto const vscroll_value = 0.0f;
190 // either the bounding box .. or the specific output ..
187 auto const screen = sink->bounding_rectangle();191 auto const screen = sink->bounding_rectangle();
188 uint32_t const width = screen.size.width.as_int();192 uint32_t const width = screen.size.width.as_int();
189 uint32_t const height = screen.size.height.as_int();193 uint32_t const height = screen.size.height.as_int();
@@ -290,9 +294,10 @@
290294
291void mie::LibInputDevice::update_contact_data(ContactData & data, MirTouchAction action, libinput_event_touch* touch)295void mie::LibInputDevice::update_contact_data(ContactData & data, MirTouchAction action, libinput_event_touch* touch)
292{296{
293 auto const screen = sink->bounding_rectangle();297 auto info = get_output_info();
294 uint32_t const width = screen.size.width.as_int();298
295 uint32_t const height = screen.size.height.as_int();299 uint32_t width = info.output_size.width.as_int();
300 uint32_t height = info.output_size.height.as_int();
296301
297 data.action = action;302 data.action = action;
298 data.pressure = libinput_event_touch_get_pressure(touch);303 data.pressure = libinput_event_touch_get_pressure(touch);
@@ -300,6 +305,8 @@
300 data.y = libinput_event_touch_get_y_transformed(touch, height);305 data.y = libinput_event_touch_get_y_transformed(touch, height);
301 data.major = libinput_event_touch_get_major_transformed(touch, width, height);306 data.major = libinput_event_touch_get_major_transformed(touch, width, height);
302 data.minor = libinput_event_touch_get_minor_transformed(touch, width, height);307 data.minor = libinput_event_touch_get_minor_transformed(touch, width, height);
308
309 info.transform_to_scene(data.x, data.y);
303}310}
304311
305void mie::LibInputDevice::handle_touch_motion(libinput_event_touch* touch)312void mie::LibInputDevice::handle_touch_motion(libinput_event_touch* touch)
@@ -351,6 +358,10 @@
351 }358 }
352 }359 }
353360
361 if (contains(caps, mi::DeviceCapability::touchscreen) &&
362 !contains(info.capabilities, mi::DeviceCapability::touchscreen))
363 touchscreen = mi::TouchscreenSettings{};
364
354 info = mi::InputDeviceInfo{name, unique_id.str(), caps};365 info = mi::InputDeviceInfo{name, unique_id.str(), caps};
355}366}
356367
@@ -364,6 +375,40 @@
364 return devices.front().get();375 return devices.front().get();
365}376}
366377
378mi::OutputInfo mie::LibInputDevice::get_output_info() const
379{
380 if (touchscreen.is_set() && touchscreen.value().mapping_mode == mir_touchscreen_mapping_mode_to_output)
381 {
382 return sink->output_info(touchscreen.value().output_id);
383 }
384 else
385 {
386 auto scene_bbox = sink->bounding_rectangle();
387 return mi::OutputInfo(
388 true,
389 scene_bbox.size,
390 mi::OutputInfo::Matrix{{1.0f, 0.0f, float(scene_bbox.top_left.x.as_int()),
391 0.0f, 1.0f, float(scene_bbox.top_left.y.as_int())}});
392 }
393}
394
395bool mie::LibInputDevice::is_output_active() const
396{
397 if (!sink)
398 return false;
399
400 if (touchscreen.is_set())
401 {
402 auto const& touchscreen_config = touchscreen.value();
403 if (touchscreen_config.mapping_mode == mir_touchscreen_mapping_mode_to_output)
404 {
405 auto output = sink->output_info(touchscreen_config.output_id);
406 return output.active;
407 }
408 }
409 return true;
410}
411
367mir::optional_value<mi::PointerSettings> mie::LibInputDevice::get_pointer_settings() const412mir::optional_value<mi::PointerSettings> mie::LibInputDevice::get_pointer_settings() const
368{413{
369 if (!contains(info.capabilities, mi::DeviceCapability::pointer))414 if (!contains(info.capabilities, mi::DeviceCapability::pointer))
370415
=== modified file 'src/platforms/evdev/libinput_device.h'
--- src/platforms/evdev/libinput_device.h 2017-02-03 01:10:42 +0000
+++ src/platforms/evdev/libinput_device.h 2017-03-01 16:08:29 +0000
@@ -41,6 +41,7 @@
41{41{
42namespace input42namespace input
43{43{
44class OutputInfo;
44class InputReport;45class InputReport;
45namespace evdev46namespace evdev
46{47{
@@ -77,6 +78,8 @@
77 void handle_touch_up(libinput_event_touch* touch);78 void handle_touch_up(libinput_event_touch* touch);
78 void handle_touch_motion(libinput_event_touch* touch);79 void handle_touch_motion(libinput_event_touch* touch);
79 void update_device_info();80 void update_device_info();
81 bool is_output_active() const;
82 OutputInfo get_output_info() const;
8083
81 std::shared_ptr<InputReport> report;84 std::shared_ptr<InputReport> report;
82 std::shared_ptr<::libinput> lib;85 std::shared_ptr<::libinput> lib;
8386
=== modified file 'src/server/graphics/nested/input_platform.cpp'
--- src/server/graphics/nested/input_platform.cpp 2017-02-20 13:19:28 +0000
+++ src/server/graphics/nested/input_platform.cpp 2017-03-01 16:08:29 +0000
@@ -104,7 +104,15 @@
104 touchpad_settings = settings;104 touchpad_settings = settings;
105 }105 }
106106
107 // TODO Forwars config when mirclient API is there107 auto touchscreen_config = mir_input_device_get_touchscreen_config(dev);
108 if (touchscreen_config && contains(device_info.capabilities, mi::DeviceCapability::touchscreen))
109 {
110 mi::TouchscreenSettings settings;
111 settings.output_id = mir_touchscreen_config_get_output_id(touchscreen_config);
112 settings.mapping_mode = mir_touchscreen_config_get_mapping_mode(touchscreen_config);
113
114 touchscreen_settings = settings;
115 }
108 }116 }
109117
110 void start(mi::InputSink* destination, mi::EventBuilder* builder) override118 void start(mi::InputSink* destination, mi::EventBuilder* builder) override
@@ -251,7 +259,15 @@
251 if (touchscreen_settings.is_set() && touchscreen_settings.value() == new_settings)259 if (touchscreen_settings.is_set() && touchscreen_settings.value() == new_settings)
252 return;260 return;
253261
254 // TODO update the MirInputConfig..262 auto ts_conf = mir_input_device_get_mutable_touchscreen_config(device);
263
264 if (ts_conf)
265 {
266 mir_touchscreen_config_set_output_id(ts_conf, new_settings.output_id);
267 mir_touchscreen_config_set_mapping_mode(ts_conf, new_settings.mapping_mode);
268
269 emit_device_change();
270 }
255 }271 }
256272
257 MirInputDeviceId device_id;273 MirInputDeviceId device_id;
258274
=== modified file 'src/server/input/basic_seat.cpp'
--- src/server/input/basic_seat.cpp 2017-01-18 02:29:37 +0000
+++ src/server/input/basic_seat.cpp 2017-03-01 16:08:29 +0000
@@ -19,29 +19,147 @@
1919
20#include "basic_seat.h"20#include "basic_seat.h"
21#include "mir/input/device.h"21#include "mir/input/device.h"
22#include "mir/input/input_region.h"22#include "mir/input/input_sink.h"
23#include "mir/graphics/display_configuration_observer.h"
24#include "mir/graphics/display_configuration.h"
25#include "mir/graphics/transformation.h"
26#include "mir/geometry/rectangle.h"
27#include "mir/geometry/point.h"
28#include "mir/geometry/size.h"
29#include "mir_toolkit/common.h"
2330
24#include <algorithm>31#include <algorithm>
32#include <array>
2533
26namespace mi = mir::input;34namespace mi = mir::input;
27namespace mf = mir::frontend;35namespace mf = mir::frontend;
36namespace mg = mir::graphics;
37namespace geom = mir::geometry;
38
39struct mi::BasicSeat::OutputTracker : mg::DisplayConfigurationObserver
40{
41 OutputTracker(SeatInputDeviceTracker& tracker)
42 : input_state_tracker{tracker}
43 {
44 }
45
46 void update_outputs(mg::DisplayConfiguration const& conf)
47 {
48 std::lock_guard<std::mutex> lock(output_mutex);
49 outputs.clear();
50 geom::Rectangles output_rectangles;
51 conf.for_each_output(
52 [this, &output_rectangles](mg::DisplayConfigurationOutput const& output)
53 {
54 if (!output.used || !output.connected)
55 return;
56 if (!output.valid() || (output.current_mode_index >= output.modes.size()))
57 return;
58
59 // TODO make the decision whether display that is used but powered off should emit
60 // touch screen events in a policy
61 bool active = output.power_mode == mir_power_mode_on;
62
63 auto output_size = output.modes[output.current_mode_index].size;
64 auto width = output_size.width.as_int();
65 auto height = output_size.height.as_int();
66 OutputInfo::Matrix output_matrix{{
67 1.0f, 0.0f, float(output.top_left.x.as_int()),
68 0.0f, 1.0f, float(output.top_left.y.as_int())}};
69
70 switch(output.orientation)
71 {
72 case mir_orientation_left:
73 output_matrix[3] = -1;
74 output_matrix[5] += width;
75 break;
76 case mir_orientation_right:
77 output_matrix[1] = -1;
78 output_matrix[2] += height;
79 break;
80 case mir_orientation_inverted:
81 output_matrix[0] = -1;
82 output_matrix[2] += width;
83 output_matrix[4] = -1;
84 output_matrix[5] += height;
85 default:
86 break;
87 }
88 if (active)
89 output_rectangles.add(output.extents());
90 outputs.insert(std::make_pair(output.id.as_value(), OutputInfo{active, output_size, output_matrix}));
91 });
92 input_state_tracker.update_outputs(output_rectangles);
93 bounding_rectangle = output_rectangles.bounding_rectangle();
94 }
95
96 void initial_configuration(std::shared_ptr<mg::DisplayConfiguration const> const& config) override
97 {
98 update_outputs(*config.get());
99 }
100
101 void configuration_applied(std::shared_ptr<mg::DisplayConfiguration const> const& config) override
102 {
103 update_outputs(*config.get());
104 }
105
106 void base_configuration_updated(std::shared_ptr<mg::DisplayConfiguration const> const&) override
107 {}
108
109 void session_configuration_applied(std::shared_ptr<mf::Session> const&,
110 std::shared_ptr<mg::DisplayConfiguration> const&) override
111 {}
112
113 void session_configuration_removed(std::shared_ptr<mf::Session> const&) override
114 {}
115
116 void configuration_failed(
117 std::shared_ptr<mg::DisplayConfiguration const> const&,
118 std::exception const&) override
119 {}
120
121 void catastrophic_configuration_error(
122 std::shared_ptr<mg::DisplayConfiguration const> const&,
123 std::exception const&) override
124 {}
125
126 geom::Rectangle get_bounding_rectangle() const
127 {
128 std::lock_guard<std::mutex> lock(output_mutex);
129 return bounding_rectangle;
130 }
131
132 mi::OutputInfo get_output_info(uint32_t output) const
133 {
134 std::lock_guard<std::mutex> lock(output_mutex);
135 auto pos = outputs.find(output);
136 if (pos != end(outputs))
137 return pos->second;
138 return OutputInfo{};
139 }
140private:
141 mutable std::mutex output_mutex;
142 mi::SeatInputDeviceTracker& input_state_tracker;
143 std::unordered_map<uint32_t, mi::OutputInfo> outputs;
144 geom::Rectangle bounding_rectangle;
145};
28146
29mi::BasicSeat::BasicSeat(std::shared_ptr<mi::InputDispatcher> const& dispatcher,147mi::BasicSeat::BasicSeat(std::shared_ptr<mi::InputDispatcher> const& dispatcher,
30 std::shared_ptr<mi::TouchVisualizer> const& touch_visualizer,148 std::shared_ptr<mi::TouchVisualizer> const& touch_visualizer,
31 std::shared_ptr<mi::CursorListener> const& cursor_listener,149 std::shared_ptr<mi::CursorListener> const& cursor_listener,
32 std::shared_ptr<mi::InputRegion> const& input_region,150 std::shared_ptr<Registrar> const& registrar,
33 std::shared_ptr<mi::KeyMapper> const& key_mapper,151 std::shared_ptr<mi::KeyMapper> const& key_mapper,
34 std::shared_ptr<time::Clock> const& clock,152 std::shared_ptr<time::Clock> const& clock,
35 std::shared_ptr<mi::SeatObserver> const& observer) :153 std::shared_ptr<mi::SeatObserver> const& observer) :
36 input_state_tracker{dispatcher,154 input_state_tracker{dispatcher,
37 touch_visualizer,155 touch_visualizer,
38 cursor_listener,156 cursor_listener,
39 input_region,
40 key_mapper,157 key_mapper,
41 clock,158 clock,
42 observer},159 observer},
43 input_region{input_region}160 output_tracker{std::make_shared<OutputTracker>(input_state_tracker)}
44{161{
162 registrar->register_interest(output_tracker);
45}163}
46164
47void mi::BasicSeat::add_device(input::Device const& device)165void mi::BasicSeat::add_device(input::Device const& device)
@@ -59,13 +177,14 @@
59 input_state_tracker.dispatch(event);177 input_state_tracker.dispatch(event);
60}178}
61179
62mir::geometry::Rectangle mi::BasicSeat::get_rectangle_for(input::Device const&)180geom::Rectangle mi::BasicSeat::bounding_rectangle() const
63{181{
64 // TODO: With knowledge of the outputs attached to this seat and the output the given input182 return output_tracker->get_bounding_rectangle();
65 // device is associated this method should only return the rectangle of that output. For now183}
66 // we rely on the existing workaround in DisplayInputRegion::bounding_rectangle() which184
67 // assumes that only the first output may have a touch screen associated to it.185mi::OutputInfo mi::BasicSeat::output_info(uint32_t output_id) const
68 return input_region->bounding_rectangle();186{
187 return output_tracker->get_output_info(output_id);
69}188}
70189
71mir::EventUPtr mi::BasicSeat::create_device_state()190mir::EventUPtr mi::BasicSeat::create_device_state()
@@ -88,7 +207,7 @@
88 input_state_tracker.set_cursor_position(cursor_x, cursor_y);207 input_state_tracker.set_cursor_position(cursor_x, cursor_y);
89}208}
90209
91void mi::BasicSeat::set_confinement_regions(geometry::Rectangles const& regions)210void mi::BasicSeat::set_confinement_regions(geom::Rectangles const& regions)
92{211{
93 input_state_tracker.set_confinement_regions(regions);212 input_state_tracker.set_confinement_regions(regions);
94}213}
@@ -97,3 +216,4 @@
97{216{
98 input_state_tracker.reset_confinement_regions();217 input_state_tracker.reset_confinement_regions();
99}218}
219
100220
=== modified file 'src/server/input/basic_seat.h'
--- src/server/input/basic_seat.h 2017-01-18 02:29:37 +0000
+++ src/server/input/basic_seat.h 2017-03-01 16:08:29 +0000
@@ -20,9 +20,10 @@
20#ifndef MIR_BASIC_SEAT_H_20#ifndef MIR_BASIC_SEAT_H_
21#define MIR_BASIC_SEAT_H_21#define MIR_BASIC_SEAT_H_
2222
23#include "seat_input_device_tracker.h"
23#include "mir/input/seat.h"24#include "mir/input/seat.h"
24#include "mir/frontend/event_sink.h"25#include "mir/frontend/event_sink.h"
25#include "seat_input_device_tracker.h"26#include "mir/observer_registrar.h"
2627
27#include <mutex>28#include <mutex>
2829
@@ -32,6 +33,10 @@
32{33{
33class Clock;34class Clock;
34}35}
36namespace graphics
37{
38class DisplayConfigurationObserver;
39}
35namespace input40namespace input
36{41{
37class TouchVisualizer;42class TouchVisualizer;
@@ -44,10 +49,11 @@
44class BasicSeat : public Seat49class BasicSeat : public Seat
45{50{
46public:51public:
52 using Registrar = ObserverRegistrar<graphics::DisplayConfigurationObserver>;
47 BasicSeat(std::shared_ptr<InputDispatcher> const& dispatcher,53 BasicSeat(std::shared_ptr<InputDispatcher> const& dispatcher,
48 std::shared_ptr<TouchVisualizer> const& touch_visualizer,54 std::shared_ptr<TouchVisualizer> const& touch_visualizer,
49 std::shared_ptr<CursorListener> const& cursor_listener,55 std::shared_ptr<CursorListener> const& cursor_listener,
50 std::shared_ptr<InputRegion> const& input_region,56 std::shared_ptr<Registrar> const& registrar,
51 std::shared_ptr<KeyMapper> const& key_mapper,57 std::shared_ptr<KeyMapper> const& key_mapper,
52 std::shared_ptr<time::Clock> const& clock,58 std::shared_ptr<time::Clock> const& clock,
53 std::shared_ptr<SeatObserver> const& observer);59 std::shared_ptr<SeatObserver> const& observer);
@@ -55,17 +61,19 @@
55 void add_device(Device const& device) override;61 void add_device(Device const& device) override;
56 void remove_device(Device const& device) override;62 void remove_device(Device const& device) override;
57 void dispatch_event(MirEvent& event) override;63 void dispatch_event(MirEvent& event) override;
58 geometry::Rectangle get_rectangle_for(Device const& dev) override;64 geometry::Rectangle bounding_rectangle() const override;
59 virtual EventUPtr create_device_state() override;65 input::OutputInfo output_info(uint32_t output_id) const override;
60 virtual void set_confinement_regions(geometry::Rectangles const& regions) override;66 EventUPtr create_device_state() override;
61 virtual void reset_confinement_regions() override;67 void set_confinement_regions(geometry::Rectangles const& regions) override;
68 void reset_confinement_regions() override;
6269
63 void set_key_state(Device const& dev, std::vector<uint32_t> const& scan_codes) override;70 void set_key_state(Device const& dev, std::vector<uint32_t> const& scan_codes) override;
64 void set_pointer_state(Device const& dev, MirPointerButtons buttons) override;71 void set_pointer_state(Device const& dev, MirPointerButtons buttons) override;
65 void set_cursor_position(float cursor_x, float cursor_y) override;72 void set_cursor_position(float cursor_x, float cursor_y) override;
66private:73private:
67 SeatInputDeviceTracker input_state_tracker;74 SeatInputDeviceTracker input_state_tracker;
68 std::shared_ptr<InputRegion> const input_region;75 struct OutputTracker;
76 std::shared_ptr<OutputTracker> const output_tracker;
69};77};
70}78}
71}79}
7280
=== modified file 'src/server/input/default_configuration.cpp'
--- src/server/input/default_configuration.cpp 2017-02-16 05:44:15 +0000
+++ src/server/input/default_configuration.cpp 2017-03-01 16:08:29 +0000
@@ -297,7 +297,7 @@
297 the_input_dispatcher(),297 the_input_dispatcher(),
298 the_touch_visualizer(),298 the_touch_visualizer(),
299 the_cursor_listener(),299 the_cursor_listener(),
300 the_input_region(),300 the_display_configuration_observer_registrar(),
301 the_key_mapper(),301 the_key_mapper(),
302 the_clock(),302 the_clock(),
303 the_seat_observer());303 the_seat_observer());
304304
=== modified file 'src/server/input/default_input_device_hub.cpp'
--- src/server/input/default_input_device_hub.cpp 2017-02-27 18:23:08 +0000
+++ src/server/input/default_input_device_hub.cpp 2017-03-01 16:08:29 +0000
@@ -201,7 +201,15 @@
201 if (!seat)201 if (!seat)
202 BOOST_THROW_EXCEPTION(std::runtime_error("Device not started and has no seat assigned"));202 BOOST_THROW_EXCEPTION(std::runtime_error("Device not started and has no seat assigned"));
203203
204 return seat->get_rectangle_for(*handle);204 return seat->bounding_rectangle();
205}
206
207mi::OutputInfo mi::DefaultInputDeviceHub::RegisteredDevice::output_info(uint32_t output_id) const
208{
209 if (!seat)
210 BOOST_THROW_EXCEPTION(std::runtime_error("Device not started and has no seat assigned"));
211
212 return seat->output_info(output_id);
205}213}
206214
207void mi::DefaultInputDeviceHub::RegisteredDevice::key_state(std::vector<uint32_t> const& scan_codes)215void mi::DefaultInputDeviceHub::RegisteredDevice::key_state(std::vector<uint32_t> const& scan_codes)
208216
=== modified file 'src/server/input/default_input_device_hub.h'
--- src/server/input/default_input_device_hub.h 2017-02-27 18:23:08 +0000
+++ src/server/input/default_input_device_hub.h 2017-03-01 16:08:29 +0000
@@ -104,7 +104,8 @@
104 std::shared_ptr<cookie::Authority> const& cookie_authority,104 std::shared_ptr<cookie::Authority> const& cookie_authority,
105 std::shared_ptr<DefaultDevice> const& handle);105 std::shared_ptr<DefaultDevice> const& handle);
106 void handle_input(MirEvent& event) override;106 void handle_input(MirEvent& event) override;
107 mir::geometry::Rectangle bounding_rectangle() const override;107 geometry::Rectangle bounding_rectangle() const override;
108 input::OutputInfo output_info(uint32_t output_id) const override;
108 bool device_matches(std::shared_ptr<InputDevice> const& dev) const;109 bool device_matches(std::shared_ptr<InputDevice> const& dev) const;
109 void start(std::shared_ptr<Seat> const& seat);110 void start(std::shared_ptr<Seat> const& seat);
110 void stop();111 void stop();
111112
=== modified file 'src/server/input/seat_input_device_tracker.cpp'
--- src/server/input/seat_input_device_tracker.cpp 2017-02-17 07:03:56 +0000
+++ src/server/input/seat_input_device_tracker.cpp 2017-03-01 16:08:29 +0000
@@ -20,7 +20,6 @@
20#include "seat_input_device_tracker.h"20#include "seat_input_device_tracker.h"
21#include "mir/input/device.h"21#include "mir/input/device.h"
22#include "mir/input/cursor_listener.h"22#include "mir/input/cursor_listener.h"
23#include "mir/input/input_region.h"
24#include "mir/input/input_dispatcher.h"23#include "mir/input/input_dispatcher.h"
25#include "mir/input/key_mapper.h"24#include "mir/input/key_mapper.h"
26#include "mir/input/seat_observer.h"25#include "mir/input/seat_observer.h"
@@ -45,12 +44,11 @@
45mi::SeatInputDeviceTracker::SeatInputDeviceTracker(std::shared_ptr<InputDispatcher> const& dispatcher,44mi::SeatInputDeviceTracker::SeatInputDeviceTracker(std::shared_ptr<InputDispatcher> const& dispatcher,
46 std::shared_ptr<TouchVisualizer> const& touch_visualizer,45 std::shared_ptr<TouchVisualizer> const& touch_visualizer,
47 std::shared_ptr<CursorListener> const& cursor_listener,46 std::shared_ptr<CursorListener> const& cursor_listener,
48 std::shared_ptr<InputRegion> const& input_region,
49 std::shared_ptr<KeyMapper> const& key_mapper,47 std::shared_ptr<KeyMapper> const& key_mapper,
50 std::shared_ptr<time::Clock> const& clock,48 std::shared_ptr<time::Clock> const& clock,
51 std::shared_ptr<SeatObserver> const& observer)49 std::shared_ptr<SeatObserver> const& observer)
52 : dispatcher{dispatcher}, touch_visualizer{touch_visualizer}, cursor_listener{cursor_listener},50 : dispatcher{dispatcher}, touch_visualizer{touch_visualizer}, cursor_listener{cursor_listener},
53 input_region{input_region}, key_mapper{key_mapper}, clock{clock}, observer{observer}, buttons{0}51 key_mapper{key_mapper}, clock{clock}, observer{observer}, buttons{0}
54{52{
55}53}
5654
@@ -231,10 +229,16 @@
231 observer->seat_reset_confinement_regions();229 observer->seat_reset_confinement_regions();
232}230}
233231
232void mi::SeatInputDeviceTracker::update_outputs(geom::Rectangles const& output_regions)
233{
234 std::lock_guard<std::mutex> lg(output_mutex);
235 input_region = output_regions;
236}
237
234void mi::SeatInputDeviceTracker::confine_function(mir::geometry::Point& p) const238void mi::SeatInputDeviceTracker::confine_function(mir::geometry::Point& p) const
235{239{
236 std::lock_guard<std::mutex> lg(region_mutex);240 std::lock_guard<std::mutex> lg(region_mutex);
237 input_region->confine(p);241 input_region.confine(p);
238 confined_region.confine(p);242 confined_region.confine(p);
239}243}
240244
241245
=== modified file 'src/server/input/seat_input_device_tracker.h'
--- src/server/input/seat_input_device_tracker.h 2017-02-17 07:03:56 +0000
+++ src/server/input/seat_input_device_tracker.h 2017-03-01 16:08:29 +0000
@@ -23,7 +23,10 @@
23#include "mir/input/touch_visualizer.h"23#include "mir/input/touch_visualizer.h"
24#include "mir/geometry/point.h"24#include "mir/geometry/point.h"
25#include "mir/geometry/rectangles.h"25#include "mir/geometry/rectangles.h"
26#include "mir/geometry/size.h"
27#include "mir/optional_value.h"
26#include "mir_toolkit/event.h"28#include "mir_toolkit/event.h"
29
27#include <unordered_map>30#include <unordered_map>
28#include <memory>31#include <memory>
29#include <mutex>32#include <mutex>
@@ -56,7 +59,6 @@
56 SeatInputDeviceTracker(std::shared_ptr<InputDispatcher> const& dispatcher,59 SeatInputDeviceTracker(std::shared_ptr<InputDispatcher> const& dispatcher,
57 std::shared_ptr<TouchVisualizer> const& touch_visualizer,60 std::shared_ptr<TouchVisualizer> const& touch_visualizer,
58 std::shared_ptr<CursorListener> const& cursor_listener,61 std::shared_ptr<CursorListener> const& cursor_listener,
59 std::shared_ptr<InputRegion> const& input_region,
60 std::shared_ptr<KeyMapper> const& key_mapper,62 std::shared_ptr<KeyMapper> const& key_mapper,
61 std::shared_ptr<time::Clock> const& clock,63 std::shared_ptr<time::Clock> const& clock,
62 std::shared_ptr<SeatObserver> const& observer);64 std::shared_ptr<SeatObserver> const& observer);
@@ -74,6 +76,8 @@
74 void set_cursor_position(float cursor_x, float cursor_y);76 void set_cursor_position(float cursor_x, float cursor_y);
75 void set_confinement_regions(geometry::Rectangles const& region);77 void set_confinement_regions(geometry::Rectangles const& region);
76 void reset_confinement_regions();78 void reset_confinement_regions();
79
80 void update_outputs(geometry::Rectangles const& outputs);
77private:81private:
78 void update_seat_properties(MirInputEvent const* event);82 void update_seat_properties(MirInputEvent const* event);
79 void update_cursor(MirPointerEvent const* event);83 void update_cursor(MirPointerEvent const* event);
@@ -86,7 +90,6 @@
86 std::shared_ptr<InputDispatcher> const dispatcher;90 std::shared_ptr<InputDispatcher> const dispatcher;
87 std::shared_ptr<TouchVisualizer> const touch_visualizer;91 std::shared_ptr<TouchVisualizer> const touch_visualizer;
88 std::shared_ptr<CursorListener> const cursor_listener;92 std::shared_ptr<CursorListener> const cursor_listener;
89 std::shared_ptr<InputRegion> const input_region;
90 std::shared_ptr<KeyMapper> const key_mapper;93 std::shared_ptr<KeyMapper> const key_mapper;
91 std::shared_ptr<time::Clock> const clock;94 std::shared_ptr<time::Clock> const clock;
92 std::shared_ptr<SeatObserver> const observer;95 std::shared_ptr<SeatObserver> const observer;
@@ -102,6 +105,9 @@
102 MirPointerButtons buttons{0};105 MirPointerButtons buttons{0};
103 std::vector<TouchVisualizer::Spot> spots;106 std::vector<TouchVisualizer::Spot> spots;
104 std::vector<uint32_t> scan_codes;107 std::vector<uint32_t> scan_codes;
108
109 MirTouchscreenMappingMode mapping_mode{mir_touchscreen_mapping_mode_to_output};
110 mir::optional_value<uint32_t> output_id;
105 };111 };
106112
107 // Libinput's acceleration curve means the cursor moves by non-integer113 // Libinput's acceleration curve means the cursor moves by non-integer
@@ -115,6 +121,9 @@
115121
116 std::mutex mutable device_state_mutex;122 std::mutex mutable device_state_mutex;
117 std::mutex mutable region_mutex;123 std::mutex mutable region_mutex;
124
125 std::mutex mutable output_mutex;
126 geometry::Rectangles input_region;
118};127};
119128
120}129}
121130
=== modified file 'src/server/scene/surface_stack.cpp'
--- src/server/scene/surface_stack.cpp 2017-01-20 12:32:45 +0000
+++ src/server/scene/surface_stack.cpp 2017-03-01 16:08:29 +0000
@@ -309,11 +309,7 @@
309 RecursiveReadLock lg(guard);309 RecursiveReadLock lg(guard);
310 for (auto &surface : surfaces)310 for (auto &surface : surfaces)
311 {311 {
312 if (surface->query(mir_window_attrib_visibility) ==312 callback(surface);
313 MirWindowVisibility::mir_window_visibility_exposed)
314 {
315 callback(surface);
316 }
317 }313 }
318}314}
319315
320316
=== modified file 'tests/acceptance-tests/test_client_input.cpp'
--- tests/acceptance-tests/test_client_input.cpp 2017-02-22 14:36:45 +0000
+++ tests/acceptance-tests/test_client_input.cpp 2017-03-01 16:08:29 +0000
@@ -24,6 +24,8 @@
24#include "mir/scene/surface.h"24#include "mir/scene/surface.h"
25#include "mir/input/mir_touchpad_config.h"25#include "mir/input/mir_touchpad_config.h"
26#include "mir/input/mir_input_config.h"26#include "mir/input/mir_input_config.h"
27#include "mir/input/input_device.h"
28#include "mir/input/touchscreen_settings.h"
2729
28#include "mir_test_framework/headless_in_process_server.h"30#include "mir_test_framework/headless_in_process_server.h"
29#include "mir_test_framework/fake_input_device.h"31#include "mir_test_framework/fake_input_device.h"
@@ -95,6 +97,22 @@
95 }97 }
96};98};
9799
100
101template<typename SetCallback, typename Apply>
102void apply_and_wait_for_completion(MirConnection* connection, SetCallback set_callback, Apply apply)
103{
104 mt::Signal change_complete;
105 set_callback(connection,
106 [](MirConnection*, void* context)
107 {
108 static_cast<mt::Signal*>(context)->raise();
109 },
110 &change_complete
111 );
112 apply(connection);
113 ASSERT_TRUE(change_complete.wait_for(10s));
114}
115
98const int surface_width = 100;116const int surface_width = 100;
99const int surface_height = 100;117const int surface_height = 100;
100118
@@ -356,6 +374,35 @@
356 }374 }
357};375};
358376
377struct TestClientInputWithTwoScreens : TestClientInput
378{
379 geom::Rectangle second_screen{{1000,0}, {200,400}};
380
381 int const width{second_screen.size.width.as_int()};
382 int const height{second_screen.size.height.as_int()};
383 float const touch_range = mtf::FakeInputDevice::maximum_touch_axis_value - mtf::FakeInputDevice::minimum_touch_axis_value + 1;
384 float const scale_to_device_width = touch_range / width;
385 float const scale_to_device_height = touch_range / height;
386
387 void SetUp() override
388 {
389 initial_display_layout({screen_geometry, second_screen});
390
391 server.wrap_shell(
392 [this](std::shared_ptr<mir::shell::Shell> const& wrapped)
393 {
394 shell = std::make_shared<mtf::PlacementApplyingShell>(wrapped, input_regions, positions);
395 return shell;
396 });
397
398 HeadlessInProcessServer::SetUp();
399
400 // make surface span over both outputs to test coordinates mapped into second ouput:
401 positions[first] =
402 geom::Rectangle{{0, 0}, {second_screen.bottom_right().x.as_int(), second_screen.bottom_right().y.as_int()}};
403 }
404};
405
359}406}
360407
361TEST_F(TestClientInput, clients_receive_keys)408TEST_F(TestClientInput, clients_receive_keys)
@@ -1246,19 +1293,14 @@
1246 mir_pointer_config_set_acceleration(pointer_config, mir_pointer_acceleration_adaptive);1293 mir_pointer_config_set_acceleration(pointer_config, mir_pointer_acceleration_adaptive);
1247 mir_pointer_config_set_acceleration_bias(pointer_config, increased_acceleration);1294 mir_pointer_config_set_acceleration_bias(pointer_config, increased_acceleration);
12481295
1249 mt::Signal changes_complete;1296 apply_and_wait_for_completion(
1250 mir_connection_set_input_config_change_callback(
1251 a_client.connection,1297 a_client.connection,
1252 [](MirConnection*, void* context)1298 mir_connection_set_input_config_change_callback,
1299 [config](MirConnection* connection)
1253 {1300 {
1254 static_cast<mt::Signal*>(context)->raise();1301 mir_connection_apply_session_input_config(connection, config);
1255 },1302 mir_input_config_release(config);
1256 &changes_complete1303 });
1257 );
1258 mir_connection_apply_session_input_config(a_client.connection, config);
1259 mir_input_config_release(config);
1260
1261 EXPECT_TRUE(changes_complete.wait_for(10s));
12621304
1263 config = mir_connection_create_input_config(a_client.connection);1305 config = mir_connection_create_input_config(a_client.connection);
1264 mouse = get_mutable_device_with_capabilities(config, mir_input_device_capability_pointer);1306 mouse = get_mutable_device_with_capabilities(config, mir_input_device_capability_pointer);
@@ -1353,19 +1395,14 @@
13531395
1354 mir_pointer_config_set_acceleration(pointer_config, mir_pointer_acceleration_adaptive);1396 mir_pointer_config_set_acceleration(pointer_config, mir_pointer_acceleration_adaptive);
13551397
1356 mt::Signal changes_complete;1398 apply_and_wait_for_completion(
1357 mir_connection_set_input_config_change_callback(
1358 unfocused_client.connection,1399 unfocused_client.connection,
1359 [](MirConnection*, void* context)1400 mir_connection_set_input_config_change_callback,
1401 [config](MirConnection* connection)
1360 {1402 {
1361 static_cast<mt::Signal*>(context)->raise();1403 mir_connection_set_base_input_config(connection, config);
1362 },1404 mir_input_config_release(config);
1363 &changes_complete1405 });
1364 );
1365 mir_connection_set_base_input_config(unfocused_client.connection, config);
1366 mir_input_config_release(config);
1367
1368 EXPECT_TRUE(changes_complete.wait_for(10s));
13691406
1370 config = mir_connection_create_input_config(unfocused_client.connection);1407 config = mir_connection_create_input_config(unfocused_client.connection);
1371 mouse = get_mutable_device_with_capabilities(config, mir_input_device_capability_pointer);1408 mouse = get_mutable_device_with_capabilities(config, mir_input_device_capability_pointer);
@@ -1414,19 +1451,14 @@
14141451
1415 mir_pointer_config_set_acceleration(pointer_config, mir_pointer_acceleration_adaptive);1452 mir_pointer_config_set_acceleration(pointer_config, mir_pointer_acceleration_adaptive);
14161453
1417 mt::Signal changes_complete;1454 apply_and_wait_for_completion(
1418 mir_connection_set_input_config_change_callback(
1419 focused_client.connection,1455 focused_client.connection,
1420 [](MirConnection*, void* context)1456 mir_connection_set_input_config_change_callback,
1457 [config](MirConnection* connection)
1421 {1458 {
1422 static_cast<mt::Signal*>(context)->raise();1459 mir_connection_set_base_input_config(connection, config);
1423 },1460 mir_input_config_release(config);
1424 &changes_complete1461 });
1425 );
1426 mir_connection_set_base_input_config(focused_client.connection, config);
1427 mir_input_config_release(config);
1428
1429 changes_complete.wait_for(10s);
14301462
1431 config = mir_connection_create_input_config(focused_client.connection);1463 config = mir_connection_create_input_config(focused_client.connection);
1432 mouse = get_mutable_device_with_capabilities(config, mir_input_device_capability_pointer);1464 mouse = get_mutable_device_with_capabilities(config, mir_input_device_capability_pointer);
@@ -1511,3 +1543,145 @@
15111543
1512 EXPECT_TRUE(wait_for_error.wait_for(10s));1544 EXPECT_TRUE(wait_for_error.wait_for(10s));
1513}1545}
1546
1547TEST_F(TestClientInput, touchscreen_config_is_mutable)
1548{
1549 wait_for_input_devices();
1550
1551 Client a_client(new_connection(), first);
1552 auto config = mir_connection_create_input_config(a_client.connection);
1553 auto touchscreen = get_mutable_device_with_capabilities(config,
1554 mir_input_device_capability_touchscreen|
1555 mir_input_device_capability_multitouch);
1556 ASSERT_THAT(touchscreen, Ne(nullptr));
1557
1558 auto touchscreen_config = mir_input_device_get_mutable_touchscreen_config(touchscreen);
1559
1560 mir_touchscreen_config_set_output_id(touchscreen_config, 4);
1561 mir_touchscreen_config_set_mapping_mode(touchscreen_config, mir_touchscreen_mapping_mode_to_display_wall);
1562
1563 EXPECT_THAT(mir_touchscreen_config_get_mapping_mode(touchscreen_config), Eq(mir_touchscreen_mapping_mode_to_display_wall));
1564 EXPECT_THAT(mir_touchscreen_config_get_output_id(touchscreen_config), Eq(4));
1565
1566 mir_input_config_release(config);
1567}
1568
1569TEST_F(TestClientInputWithTwoScreens, touchscreen_can_be_mapped_to_second_output)
1570{
1571 wait_for_input_devices();
1572 uint32_t const second_output = 2;
1573 int const touch_x = 10;
1574 int const touch_y = 10;
1575
1576 int const expected_x = touch_x + second_screen.top_left.x.as_int();
1577 int const expected_y = touch_y + second_screen.top_left.y.as_int();
1578
1579 mt::Signal touchscreen_ready;
1580 fake_touch_screen->on_new_configuration_do(
1581 [&touchscreen_ready, second_output](mi::InputDevice const& dev)
1582 {
1583 auto ts = dev.get_touchscreen_settings();
1584 if (ts.is_set() && ts.value().output_id == second_output)
1585 touchscreen_ready.raise();
1586 });
1587
1588 Client client(new_connection(), first);
1589 auto config = mir_connection_create_input_config(client.connection);
1590 auto touchscreen = get_mutable_device_with_capabilities(config,
1591 mir_input_device_capability_touchscreen|
1592 mir_input_device_capability_multitouch);
1593 auto touchscreen_config = mir_input_device_get_mutable_touchscreen_config(touchscreen);
1594 mir_touchscreen_config_set_output_id(touchscreen_config, second_output);
1595 mir_touchscreen_config_set_mapping_mode(touchscreen_config, mir_touchscreen_mapping_mode_to_output);
1596
1597 apply_and_wait_for_completion(
1598 client.connection,
1599 mir_connection_set_input_config_change_callback,
1600 [config](MirConnection* connection)
1601 {
1602 mir_connection_set_base_input_config(connection, config);
1603 mir_input_config_release(config);
1604 });
1605
1606 EXPECT_TRUE(touchscreen_ready.wait_for(10s));
1607 EXPECT_CALL(client, handle_input(mt::TouchEvent(expected_x, expected_y)))
1608 .WillOnce(mt::WakeUp(&client.all_events_received));
1609 fake_touch_screen->emit_event(mis::a_touch_event()
1610 .at_position({touch_x*scale_to_device_width, touch_y*scale_to_device_height}));
1611
1612 EXPECT_TRUE(client.all_events_received.wait_for(10s));
1613}
1614
1615TEST_F(TestClientInputWithTwoScreens, touchscreen_mapped_to_deactivated_output_is_filtered_out)
1616{
1617 wait_for_input_devices();
1618 uint32_t const second_output = 2;
1619 int const touch_x = 10;
1620 int const touch_y = 10;
1621
1622 int const expected_x = second_screen.top_left.x.as_int() + touch_x;
1623 int const expected_y = second_screen.top_left.y.as_int() + touch_y;
1624
1625 Client client(new_connection(), first);
1626 auto display_config = mir_connection_create_display_configuration(client.connection);
1627 auto second_output_ptr = mir_display_config_get_mutable_output(display_config, 1);
1628 mir_output_set_power_mode(second_output_ptr, mir_power_mode_off);
1629
1630 apply_and_wait_for_completion(
1631 client.connection,
1632 mir_connection_set_display_config_change_callback,
1633 [display_config](MirConnection* con)
1634 {
1635 mir_connection_preview_base_display_configuration(con, display_config, 10);
1636 });
1637
1638 apply_and_wait_for_completion(
1639 client.connection,
1640 mir_connection_set_display_config_change_callback,
1641 [display_config](MirConnection* con)
1642 {
1643 mir_connection_confirm_base_display_configuration(con, display_config);
1644 mir_display_config_release(display_config);
1645 });
1646
1647 display_config = mir_connection_create_display_configuration(client.connection);
1648 ASSERT_THAT(mir_output_get_power_mode(mir_display_config_get_output(display_config, 1)), Eq(mir_power_mode_off));
1649 mir_display_config_release(display_config);
1650
1651 mt::Signal touchscreen_ready;
1652 fake_touch_screen->on_new_configuration_do(
1653 [&touchscreen_ready, second_output](mi::InputDevice const& dev)
1654 {
1655 auto ts = dev.get_touchscreen_settings();
1656 if (ts.is_set()
1657 && ts.value().output_id == second_output
1658 && ts.value().mapping_mode == mir_touchscreen_mapping_mode_to_output)
1659 touchscreen_ready.raise();
1660 });
1661
1662 auto config = mir_connection_create_input_config(client.connection);
1663 auto touchscreen = get_mutable_device_with_capabilities(config,
1664 mir_input_device_capability_touchscreen|
1665 mir_input_device_capability_multitouch);
1666 auto touchscreen_config = mir_input_device_get_mutable_touchscreen_config(touchscreen);
1667
1668 mir_touchscreen_config_set_output_id(touchscreen_config, second_output);
1669 mir_touchscreen_config_set_mapping_mode(touchscreen_config, mir_touchscreen_mapping_mode_to_output);
1670
1671 apply_and_wait_for_completion(
1672 client.connection,
1673 mir_connection_set_input_config_change_callback,
1674 [config](MirConnection* connection)
1675 {
1676 mir_connection_set_base_input_config(connection, config);
1677 mir_input_config_release(config);
1678 });
1679
1680 EXPECT_TRUE(touchscreen_ready.wait_for(10s));
1681 ON_CALL(client, handle_input(mt::TouchEvent(expected_x, expected_y)))
1682 .WillByDefault(mt::WakeUp(&client.all_events_received));
1683 fake_touch_screen->emit_event(mis::a_touch_event()
1684 .at_position({touch_x*scale_to_device_width, touch_y*scale_to_device_height}));
1685
1686 EXPECT_FALSE(client.all_events_received.wait_for(5s));
1687}
15141688
=== modified file 'tests/include/mir/test/doubles/mock_input_seat.h'
--- tests/include/mir/test/doubles/mock_input_seat.h 2017-01-18 02:29:37 +0000
+++ tests/include/mir/test/doubles/mock_input_seat.h 2017-03-01 16:08:29 +0000
@@ -21,6 +21,7 @@
2121
22#include "mir/input/seat.h"22#include "mir/input/seat.h"
23#include "mir/input/device.h"23#include "mir/input/device.h"
24#include "mir/input/input_sink.h"
24#include "mir/test/gmock_fixes.h"25#include "mir/test/gmock_fixes.h"
2526
26#include <gmock/gmock.h>27#include <gmock/gmock.h>
@@ -36,13 +37,14 @@
36 MOCK_METHOD1(add_device, void(input::Device const& device));37 MOCK_METHOD1(add_device, void(input::Device const& device));
37 MOCK_METHOD1(remove_device, void(input::Device const& device));38 MOCK_METHOD1(remove_device, void(input::Device const& device));
38 MOCK_METHOD1(dispatch_event, void(MirEvent& event));39 MOCK_METHOD1(dispatch_event, void(MirEvent& event));
39 MOCK_METHOD1(get_rectangle_for, geometry::Rectangle(input::Device const& dev));
40 MOCK_METHOD0(create_device_state, mir::EventUPtr());40 MOCK_METHOD0(create_device_state, mir::EventUPtr());
41 MOCK_METHOD2(set_key_state, void(input::Device const&, std::vector<uint32_t> const&));41 MOCK_METHOD2(set_key_state, void(input::Device const&, std::vector<uint32_t> const&));
42 MOCK_METHOD2(set_pointer_state, void (input::Device const&, MirPointerButtons));42 MOCK_METHOD2(set_pointer_state, void (input::Device const&, MirPointerButtons));
43 MOCK_METHOD2(set_cursor_position, void (float, float));43 MOCK_METHOD2(set_cursor_position, void (float, float));
44 MOCK_METHOD1(set_confinement_regions, void(geometry::Rectangles const&));44 MOCK_METHOD1(set_confinement_regions, void(geometry::Rectangles const&));
45 MOCK_METHOD0(reset_confinement_regions, void());45 MOCK_METHOD0(reset_confinement_regions, void());
46 MOCK_CONST_METHOD0(bounding_rectangle, geometry::Rectangle());
47 MOCK_CONST_METHOD1(output_info, input::OutputInfo(uint32_t));
46};48};
47}49}
48}50}
4951
=== modified file 'tests/include/mir/test/doubles/mock_input_sink.h'
--- tests/include/mir/test/doubles/mock_input_sink.h 2016-07-07 09:59:19 +0000
+++ tests/include/mir/test/doubles/mock_input_sink.h 2017-03-01 16:08:29 +0000
@@ -35,6 +35,7 @@
35 MOCK_METHOD1(handle_input, void(MirEvent&));35 MOCK_METHOD1(handle_input, void(MirEvent&));
36 MOCK_METHOD1(confine_pointer, void(mir::geometry::Point&));36 MOCK_METHOD1(confine_pointer, void(mir::geometry::Point&));
37 MOCK_CONST_METHOD0(bounding_rectangle, mir::geometry::Rectangle());37 MOCK_CONST_METHOD0(bounding_rectangle, mir::geometry::Rectangle());
38 MOCK_CONST_METHOD1(output_info, mir::input::OutputInfo(uint32_t));
38 MOCK_METHOD1(key_state, void(std::vector<uint32_t> const&));39 MOCK_METHOD1(key_state, void(std::vector<uint32_t> const&));
39 MOCK_METHOD1(pointer_state, void(MirPointerButtons));40 MOCK_METHOD1(pointer_state, void(MirPointerButtons));
40};41};
4142
=== modified file 'tests/integration-tests/input/test_single_seat_setup.cpp'
--- tests/integration-tests/input/test_single_seat_setup.cpp 2017-02-15 07:38:33 +0000
+++ tests/integration-tests/input/test_single_seat_setup.cpp 2017-03-01 16:08:29 +0000
@@ -24,7 +24,6 @@
24#include "mir/test/doubles/mock_input_device.h"24#include "mir/test/doubles/mock_input_device.h"
25#include "mir/test/doubles/mock_input_device_observer.h"25#include "mir/test/doubles/mock_input_device_observer.h"
26#include "mir/test/doubles/mock_input_dispatcher.h"26#include "mir/test/doubles/mock_input_dispatcher.h"
27#include "mir/test/doubles/mock_input_region.h"
28#include "mir/test/doubles/mock_touch_visualizer.h"27#include "mir/test/doubles/mock_touch_visualizer.h"
29#include "mir/test/doubles/mock_cursor_listener.h"28#include "mir/test/doubles/mock_cursor_listener.h"
30#include "mir/test/doubles/mock_input_manager.h"29#include "mir/test/doubles/mock_input_manager.h"
@@ -36,10 +35,12 @@
36#include "mir/test/event_matchers.h"35#include "mir/test/event_matchers.h"
37#include "mir/test/doubles/advanceable_clock.h"36#include "mir/test/doubles/advanceable_clock.h"
38#include "mir/test/fake_shared.h"37#include "mir/test/fake_shared.h"
38#include "mir/test/doubles/stub_display_configuration.h"
3939
40#include "mir/dispatch/multiplexing_dispatchable.h"40#include "mir/dispatch/multiplexing_dispatchable.h"
41#include "mir/cookie/authority.h"41#include "mir/cookie/authority.h"
42#include "mir/graphics/buffer.h"42#include "mir/graphics/buffer.h"
43#include "mir/graphics/display_configuration_observer.h"
4344
44#include "mir/input/device.h"45#include "mir/input/device.h"
45#include "mir/input/xkb_mapper.h"46#include "mir/input/xkb_mapper.h"
@@ -73,17 +74,47 @@
73}74}
74}75}
7576
77namespace
78{
79
76MATCHER_P(DeviceMatches, device_info, "")80MATCHER_P(DeviceMatches, device_info, "")
77{81{
78 return arg.name() == device_info.name &&82 return arg.name() == device_info.name &&
79 arg.unique_id() == device_info.unique_id;83 arg.unique_id() == device_info.unique_id;
80}84}
8185
86struct FakeDisplayConfigurationObserverRegistrar : mir::ObserverRegistrar<mir::graphics::DisplayConfigurationObserver>
87{
88 using Observer = mir::graphics::DisplayConfigurationObserver;
89 mtd::StubDisplayConfig output{{geom::Rectangle{{0, 0}, {100, 100}}}};
90 void register_interest(std::weak_ptr<Observer> const& obs) override
91 {
92 observer = obs;
93 auto o = observer.lock();
94 o->initial_configuration(mt::fake_shared(output));
95 }
96 void register_interest(
97 std::weak_ptr<Observer> const& obs,
98 mir::Executor&) override
99 {
100 observer = obs;
101 }
102 void unregister_interest(Observer const&) override
103 {
104 observer.reset();
105 }
106 void update_output(geom::Size const& output_size)
107 {
108 output.outputs[0].modes[0].size = output_size;
109 auto o = observer.lock();
110 o->configuration_applied(mt::fake_shared(output));
111 }
112 std::weak_ptr<Observer> observer;
113};
82struct SingleSeatInputDeviceHubSetup : ::testing::Test114struct SingleSeatInputDeviceHubSetup : ::testing::Test
83{115{
84 mtd::TriggeredMainLoop observer_loop;116 mtd::TriggeredMainLoop observer_loop;
85 NiceMock<mtd::MockInputDispatcher> mock_dispatcher;117 NiceMock<mtd::MockInputDispatcher> mock_dispatcher;
86 NiceMock<mtd::MockInputRegion> mock_region;
87 std::shared_ptr<mir::cookie::Authority> cookie_authority = mir::cookie::Authority::create();118 std::shared_ptr<mir::cookie::Authority> cookie_authority = mir::cookie::Authority::create();
88 NiceMock<mtd::MockCursorListener> mock_cursor_listener;119 NiceMock<mtd::MockCursorListener> mock_cursor_listener;
89 NiceMock<mtd::MockTouchVisualizer> mock_visualizer;120 NiceMock<mtd::MockTouchVisualizer> mock_visualizer;
@@ -95,12 +126,14 @@
95 mtd::MockInputManager mock_input_manager;126 mtd::MockInputManager mock_input_manager;
96 mtd::StubSessionContainer stub_session_container;127 mtd::StubSessionContainer stub_session_container;
97 ms::BroadcastingSessionEventSink session_event_sink;128 ms::BroadcastingSessionEventSink session_event_sink;
98 mi::BasicSeat seat{129 FakeDisplayConfigurationObserverRegistrar display_config;
99 mt::fake_shared(mock_dispatcher),mt::fake_shared(mock_visualizer), mt::fake_shared(mock_cursor_listener),130 mi::BasicSeat seat{mt::fake_shared(mock_dispatcher), mt::fake_shared(mock_visualizer),
100 mt::fake_shared(mock_region), mt::fake_shared(key_mapper), mt::fake_shared(clock), mt::fake_shared(mock_seat_observer)};131 mt::fake_shared(mock_cursor_listener), mt::fake_shared(display_config),
101 mi::DefaultInputDeviceHub hub{132 mt::fake_shared(key_mapper), mt::fake_shared(clock),
102 mt::fake_shared(seat), mt::fake_shared(multiplexer), mt::fake_shared(observer_loop),133 mt::fake_shared(mock_seat_observer)};
103 cookie_authority, mt::fake_shared(key_mapper), mt::fake_shared(mock_status_listener)};134 mi::DefaultInputDeviceHub hub{mt::fake_shared(seat), mt::fake_shared(multiplexer),
135 mt::fake_shared(observer_loop), cookie_authority,
136 mt::fake_shared(key_mapper), mt::fake_shared(mock_status_listener)};
104 NiceMock<mtd::MockInputDeviceObserver> mock_observer;137 NiceMock<mtd::MockInputDeviceObserver> mock_observer;
105 mi::ConfigChanger changer{138 mi::ConfigChanger changer{
106 mt::fake_shared(mock_input_manager),139 mt::fake_shared(mock_input_manager),
@@ -130,6 +163,8 @@
130 }163 }
131};164};
132165
166}
167
133TEST_F(SingleSeatInputDeviceHubSetup, input_sink_posts_events_to_input_dispatcher)168TEST_F(SingleSeatInputDeviceHubSetup, input_sink_posts_events_to_input_dispatcher)
134{169{
135 mi::InputSink* sink;170 mi::InputSink* sink;
@@ -198,13 +233,12 @@
198 sink->handle_input(*touch_event_4);233 sink->handle_input(*touch_event_4);
199}234}
200235
201
202TEST_F(SingleSeatInputDeviceHubSetup, tracks_pointer_position)236TEST_F(SingleSeatInputDeviceHubSetup, tracks_pointer_position)
203{237{
204 geom::Point first{10,10}, second{20,20}, third{10,30};238 geom::Point first{10,10}, second{20,20}, third{10,30};
205 EXPECT_CALL(mock_region, confine(first));239 EXPECT_CALL(mock_cursor_listener, cursor_moved_to(first.x.as_int(), first.y.as_int()));
206 EXPECT_CALL(mock_region, confine(second));240 EXPECT_CALL(mock_cursor_listener, cursor_moved_to(second.x.as_int(), second.y.as_int()));
207 EXPECT_CALL(mock_region, confine(third));241 EXPECT_CALL(mock_cursor_listener, cursor_moved_to(third.x.as_int(), third.y.as_int()));
208242
209 mi::InputSink* sink;243 mi::InputSink* sink;
210 mi::EventBuilder* builder;244 mi::EventBuilder* builder;
@@ -223,9 +257,8 @@
223TEST_F(SingleSeatInputDeviceHubSetup, confines_pointer_movement)257TEST_F(SingleSeatInputDeviceHubSetup, confines_pointer_movement)
224{258{
225 geom::Point confined_pos{10, 18};259 geom::Point confined_pos{10, 18};
260 display_config.update_output(geom::Size{confined_pos.x.as_int() + 1, confined_pos.y.as_int() + 1});
226261
227 ON_CALL(mock_region,confine(_))
228 .WillByDefault(SetArgReferee<0>(confined_pos));
229 EXPECT_CALL(mock_cursor_listener, cursor_moved_to(confined_pos.x.as_int(), confined_pos.y.as_int())).Times(2);262 EXPECT_CALL(mock_cursor_listener, cursor_moved_to(confined_pos.x.as_int(), confined_pos.y.as_int())).Times(2);
230263
231 mi::InputSink* sink;264 mi::InputSink* sink;
232265
=== modified file 'tests/mir_test_framework/fake_input_device_impl.cpp'
--- tests/mir_test_framework/fake_input_device_impl.cpp 2017-02-03 01:10:42 +0000
+++ tests/mir_test_framework/fake_input_device_impl.cpp 2017-03-01 16:08:29 +0000
@@ -110,14 +110,27 @@
110 });110 });
111}111}
112112
113void mtf::FakeInputDeviceImpl::on_new_configuration_do(std::function<void(mir::input::InputDevice const& device)> callback)
114{
115 device->set_apply_settings_callback(callback);
116}
117void mtf::FakeInputDeviceImpl::InputDevice::set_apply_settings_callback(std::function<void(mir::input::InputDevice const&)> const& callback)
118{
119 std::lock_guard<std::mutex> lock(config_callback_mutex);
120 this->callback = callback;
121}
113122
114mtf::FakeInputDeviceImpl::InputDevice::InputDevice(mi::InputDeviceInfo const& info,123mtf::FakeInputDeviceImpl::InputDevice::InputDevice(mi::InputDeviceInfo const& info,
115 std::shared_ptr<mir::dispatch::Dispatchable> const& dispatchable)124 std::shared_ptr<mir::dispatch::Dispatchable> const& dispatchable)
116 : info(info), queue{dispatchable}, buttons{0}125 : info(info), queue{dispatchable}, buttons{0}, callback([](mir::input::InputDevice const&){})
117{126{
118 // the default setup results in a direct mapping of input velocity to output velocity.127 // the default setup results in a direct mapping of input velocity to output velocity.
119 settings.acceleration = mir_pointer_acceleration_none;128 settings.acceleration = mir_pointer_acceleration_none;
120 settings.cursor_acceleration_bias = 0.0;129 settings.cursor_acceleration_bias = 0.0;
130
131 // add default setup for touchscreen..
132 if (contains(info.capabilities, mi::DeviceCapability::touchscreen))
133 touchscreen = mi::TouchscreenSettings{};
121}134}
122135
123void mtf::FakeInputDeviceImpl::InputDevice::synthesize_events(synthesis::KeyParameters const& key_params)136void mtf::FakeInputDeviceImpl::InputDevice::synthesize_events(synthesis::KeyParameters const& key_params)
@@ -211,13 +224,15 @@
211 float abs_x = touch.abs_x;224 float abs_x = touch.abs_x;
212 float abs_y = touch.abs_y;225 float abs_y = touch.abs_y;
213 map_touch_coordinates(abs_x, abs_y);226 map_touch_coordinates(abs_x, abs_y);
214 // those values would need scaling too as soon as they can be controlled by the caller227
215228 if (is_output_active())
216 auto touch_event = builder->touch_event(229 {
217 event_time,230 auto touch_event = builder->touch_event(
218 {{MirTouchId{1}, touch_action, mir_touch_tooltype_finger, abs_x, abs_y, 1.0f, 8.0f, 5.0f, 0.0f}});231 event_time,
219232 {{MirTouchId{1}, touch_action, mir_touch_tooltype_finger, abs_x, abs_y, 1.0f, 8.0f, 5.0f, 0.0f}});
220 sink->handle_input(*touch_event);233
234 sink->handle_input(*touch_event);
235 }
221}236}
222237
223mir::optional_value<mi::PointerSettings> mtf::FakeInputDeviceImpl::InputDevice::get_pointer_settings() const238mir::optional_value<mi::PointerSettings> mtf::FakeInputDeviceImpl::InputDevice::get_pointer_settings() const
@@ -235,6 +250,7 @@
235 if (!contains(info.capabilities, mi::DeviceCapability::pointer))250 if (!contains(info.capabilities, mi::DeviceCapability::pointer))
236 return;251 return;
237 this->settings = settings;252 this->settings = settings;
253 trigger_callback();
238}254}
239255
240mir::optional_value<mi::TouchpadSettings> mtf::FakeInputDeviceImpl::InputDevice::get_touchpad_settings() const256mir::optional_value<mi::TouchpadSettings> mtf::FakeInputDeviceImpl::InputDevice::get_touchpad_settings() const
@@ -250,6 +266,17 @@
250{266{
251 // Not applicable for configuration since FakeInputDevice just267 // Not applicable for configuration since FakeInputDevice just
252 // forwards already interpreted events.268 // forwards already interpreted events.
269 trigger_callback();
270}
271
272void mtf::FakeInputDeviceImpl::InputDevice::trigger_callback() const
273{
274 decltype(callback) stored_callback;
275 {
276 std::lock_guard<std::mutex> lock(config_callback_mutex);
277 stored_callback = callback;
278 }
279 stored_callback(*this);
253}280}
254281
255mir::optional_value<mi::TouchscreenSettings> mtf::FakeInputDeviceImpl::InputDevice::get_touchscreen_settings() const282mir::optional_value<mi::TouchscreenSettings> mtf::FakeInputDeviceImpl::InputDevice::get_touchscreen_settings() const
@@ -267,17 +294,22 @@
267 if (!contains(info.capabilities, mi::DeviceCapability::touchscreen))294 if (!contains(info.capabilities, mi::DeviceCapability::touchscreen))
268 return;295 return;
269 this->touchscreen = new_settings;296 this->touchscreen = new_settings;
297
298 trigger_callback();
270}299}
271300
272void mtf::FakeInputDeviceImpl::InputDevice::map_touch_coordinates(float& x, float& y)301void mtf::FakeInputDeviceImpl::InputDevice::map_touch_coordinates(float& x, float& y)
273{302{
274 // TODO take orientation of input sink into account?303 auto info = get_output_info();
275 auto area = sink->bounding_rectangle();
276 auto touch_range = FakeInputDevice::maximum_touch_axis_value - FakeInputDevice::minimum_touch_axis_value + 1;304 auto touch_range = FakeInputDevice::maximum_touch_axis_value - FakeInputDevice::minimum_touch_axis_value + 1;
277 auto x_scale = area.size.width.as_int() / float(touch_range);305 auto const width = info.output_size.width.as_int();
278 auto y_scale = area.size.height.as_int() / float(touch_range);306 auto const height = info.output_size.height.as_int();
279 x = (x - float(FakeInputDevice::minimum_touch_axis_value))*x_scale + area.top_left.x.as_int();307 auto x_scale = width / float(touch_range);
280 y = (y - float(FakeInputDevice::minimum_touch_axis_value))*y_scale + area.top_left.y.as_int();308 auto y_scale = height / float(touch_range);
309 x = (x - float(FakeInputDevice::minimum_touch_axis_value))*x_scale;
310 y = (y - float(FakeInputDevice::minimum_touch_axis_value))*y_scale;
311
312 info.transform_to_scene(x, y);
281}313}
282314
283void mtf::FakeInputDeviceImpl::InputDevice::start(mi::InputSink* destination, mi::EventBuilder* event_builder)315void mtf::FakeInputDeviceImpl::InputDevice::start(mi::InputSink* destination, mi::EventBuilder* event_builder)
@@ -293,3 +325,33 @@
293 builder = nullptr;325 builder = nullptr;
294 mtf::StubInputPlatform::unregister_dispatchable(queue);326 mtf::StubInputPlatform::unregister_dispatchable(queue);
295}327}
328
329mi::OutputInfo mtf::FakeInputDeviceImpl::InputDevice::get_output_info() const
330{
331 if (touchscreen.mapping_mode == mir_touchscreen_mapping_mode_to_output)
332 {
333 return sink->output_info(touchscreen.output_id);
334 }
335 else
336 {
337 auto scene_bbox = sink->bounding_rectangle();
338 return mi::OutputInfo(
339 true,
340 scene_bbox.size,
341 mi::OutputInfo::Matrix{{1.0f, 0.0f, float(scene_bbox.top_left.x.as_int()),
342 0.0f, 1.0f, float(scene_bbox.top_left.y.as_int())}});
343 }
344}
345
346bool mtf::FakeInputDeviceImpl::InputDevice::is_output_active() const
347{
348 if (!sink)
349 return false;
350
351 if (touchscreen.mapping_mode == mir_touchscreen_mapping_mode_to_output)
352 {
353 auto output = sink->output_info(touchscreen.output_id);
354 return output.active;
355 }
356 return true;
357}
296358
=== modified file 'tests/mir_test_framework/fake_input_device_impl.h'
--- tests/mir_test_framework/fake_input_device_impl.h 2017-02-03 01:10:42 +0000
+++ tests/mir_test_framework/fake_input_device_impl.h 2017-03-01 16:08:29 +0000
@@ -27,8 +27,15 @@
27#include "mir/input/input_device_info.h"27#include "mir/input/input_device_info.h"
28#include "mir/geometry/point.h"28#include "mir/geometry/point.h"
2929
30#include <mutex>
31#include <functional>
32
30namespace mir33namespace mir
31{34{
35namespace input
36{
37class OutputInfo;
38}
32namespace dispatch39namespace dispatch
33{40{
34class ActionQueue;41class ActionQueue;
@@ -50,6 +57,7 @@
50 void emit_touch_sequence(std::function<mir::input::synthesis::TouchParameters(int)> const& event_generator,57 void emit_touch_sequence(std::function<mir::input::synthesis::TouchParameters(int)> const& event_generator,
51 int count,58 int count,
52 std::chrono::duration<double> delay) override;59 std::chrono::duration<double> delay) override;
60 virtual void on_new_configuration_do(std::function<void(mir::input::InputDevice const& device)> callback) override;
5361
54private:62private:
55 class InputDevice : public mir::input::InputDevice63 class InputDevice : public mir::input::InputDevice
@@ -76,11 +84,15 @@
76 void apply_settings(mir::input::TouchpadSettings const& settings) override;84 void apply_settings(mir::input::TouchpadSettings const& settings) override;
77 mir::optional_value<mir::input::TouchscreenSettings> get_touchscreen_settings() const override;85 mir::optional_value<mir::input::TouchscreenSettings> get_touchscreen_settings() const override;
78 void apply_settings(mir::input::TouchscreenSettings const& settings) override;86 void apply_settings(mir::input::TouchscreenSettings const& settings) override;
87 void set_apply_settings_callback(std::function<void(mir::input::InputDevice const&)> const& callback);
7988
80 private:89 private:
81 MirPointerAction update_buttons(mir::input::synthesis::EventAction action, MirPointerButton button);90 MirPointerAction update_buttons(mir::input::synthesis::EventAction action, MirPointerButton button);
82 void update_position(int rel_x, int rel_y);91 void update_position(int rel_x, int rel_y);
83 void map_touch_coordinates(float& x, float& y);92 void map_touch_coordinates(float& x, float& y);
93 mir::input::OutputInfo get_output_info() const;
94 bool is_output_active() const;
95 void trigger_callback() const;
8496
85 mir::input::InputSink* sink{nullptr};97 mir::input::InputSink* sink{nullptr};
86 mir::input::EventBuilder* builder{nullptr};98 mir::input::EventBuilder* builder{nullptr};
@@ -90,6 +102,8 @@
90 MirPointerButtons buttons;102 MirPointerButtons buttons;
91 mir::input::PointerSettings settings;103 mir::input::PointerSettings settings;
92 mir::input::TouchscreenSettings touchscreen;104 mir::input::TouchscreenSettings touchscreen;
105 mutable std::mutex config_callback_mutex;
106 std::function<void(mir::input::InputDevice const&)> callback;
93 };107 };
94 std::shared_ptr<mir::dispatch::ActionQueue> queue;108 std::shared_ptr<mir::dispatch::ActionQueue> queue;
95 std::shared_ptr<InputDevice> device;109 std::shared_ptr<InputDevice> device;
96110
=== modified file 'tests/unit-tests/input/evdev/test_libinput_device.cpp'
--- tests/unit-tests/input/evdev/test_libinput_device.cpp 2017-01-18 02:29:37 +0000
+++ tests/unit-tests/input/evdev/test_libinput_device.cpp 2017-03-01 16:08:29 +0000
@@ -31,6 +31,7 @@
31#include "mir/test/event_matchers.h"31#include "mir/test/event_matchers.h"
32#include "mir/test/doubles/mock_libinput.h"32#include "mir/test/doubles/mock_libinput.h"
33#include "mir/test/doubles/mock_input_seat.h"33#include "mir/test/doubles/mock_input_seat.h"
34#include "mir/test/doubles/mock_input_sink.h"
34#include "mir/test/gmock_fixes.h"35#include "mir/test/gmock_fixes.h"
35#include "mir/test/fake_shared.h"36#include "mir/test/fake_shared.h"
36#include "mir/udev/wrapper.h"37#include "mir/udev/wrapper.h"
@@ -63,20 +64,7 @@
63};64};
6465
65using namespace ::testing;66using namespace ::testing;
6667using Matrix = mi::OutputInfo::Matrix;
67struct MockInputSink : mi::InputSink
68{
69 MockInputSink()
70 {
71 ON_CALL(*this, bounding_rectangle())
72 .WillByDefault(Return(geom::Rectangle({0,0}, {100,100})));
73 }
74 MOCK_METHOD1(handle_input,void(MirEvent &));
75 MOCK_METHOD1(confine_pointer, void(geom::Point&));
76 MOCK_CONST_METHOD0(bounding_rectangle, geom::Rectangle());
77 MOCK_METHOD1(key_state, void(std::vector<uint32_t> const&));
78 MOCK_METHOD1(pointer_state, void(MirPointerButtons));
79};
8068
81struct MockEventBuilder : mi::EventBuilder69struct MockEventBuilder : mi::EventBuilder
82{70{
@@ -128,7 +116,7 @@
128struct LibInputDevice : public ::testing::Test116struct LibInputDevice : public ::testing::Test
129{117{
130 mtf::LibInputEnvironment env;118 mtf::LibInputEnvironment env;
131 ::testing::NiceMock<MockInputSink> mock_sink;119 ::testing::NiceMock<mtd::MockInputSink> mock_sink;
132 ::testing::NiceMock<MockEventBuilder> mock_builder;120 ::testing::NiceMock<MockEventBuilder> mock_builder;
133 std::shared_ptr<libinput> lib;121 std::shared_ptr<libinput> lib;
134122
@@ -145,6 +133,8 @@
145133
146 LibInputDevice()134 LibInputDevice()
147 {135 {
136 ON_CALL(mock_sink, bounding_rectangle())
137 .WillByDefault(Return(geom::Rectangle({0,0}, {100,100})));
148 lib = mie::make_libinput(fake_udev);138 lib = mie::make_libinput(fake_udev);
149 }139 }
150140
@@ -268,6 +258,16 @@
268{258{
269 libinput_device*const fake_device = setup_touchscreen();259 libinput_device*const fake_device = setup_touchscreen();
270 mie::LibInputDevice touch_screen{mir::report::null_input_report(), mie::make_libinput_device(lib, fake_device)};260 mie::LibInputDevice touch_screen{mir::report::null_input_report(), mie::make_libinput_device(lib, fake_device)};
261
262 const float x = 10;
263 const float y = 5;
264 const uint32_t output_id = 2;
265 const float output_x_pos = 20;
266 const float output_y_pos = 50;
267 const float screen_x_pos = 70;
268 const float screen_y_pos = 30;
269 const int width = 100;
270 const int height = 200;
271};271};
272272
273struct LibInputDeviceOnTouchpad : public LibInputDevice273struct LibInputDeviceOnTouchpad : public LibInputDevice
@@ -777,3 +777,169 @@
777 lib.reset();777 lib.reset();
778 device_ptr.reset();778 device_ptr.reset();
779}779}
780
781TEST_F(LibInputDeviceOnTouchScreen, device_maps_to_selected_output)
782{
783 const float x = 30;
784 const float y = 20;
785 const uint32_t output_id = 2;
786 const float output_x_pos = 20;
787 const float output_y_pos = 50;
788 const int width = 100;
789 const int height = 200;
790
791 EXPECT_CALL(mock_sink, bounding_rectangle())
792 .Times(0);
793 EXPECT_CALL(mock_sink, output_info(output_id))
794 .WillRepeatedly(Return(
795 mi::OutputInfo{
796 true,
797 geom::Size{width, height},
798 Matrix{{1.0f, 0.0f, output_x_pos,
799 0.0f, 1.0f, output_y_pos}}}));
800 EXPECT_CALL(mock_sink,
801 handle_input(
802 mt::TouchContact(
803 0,
804 mir_touch_action_down,
805 x + output_x_pos,
806 y + output_y_pos)))
807 .Times(1);
808
809 touch_screen.apply_settings(mi::TouchscreenSettings{output_id, mir_touchscreen_mapping_mode_to_output});
810 touch_screen.start(&mock_sink, &mock_builder);
811
812 env.mock_libinput.setup_touch_event(fake_device, LIBINPUT_EVENT_TOUCH_DOWN, event_time_1, 0, x, y, 0, 0, 0, 0);
813 env.mock_libinput.setup_touch_frame(fake_device, event_time_1);
814
815 process_events(touch_screen);
816}
817
818TEST_F(LibInputDeviceOnTouchScreen, device_maps_to_left_rotated_output)
819{
820 const float x = 10;
821 const float y = 5;
822 const uint32_t output_id = 2;
823 const float output_x_pos = 20;
824 const float output_y_pos = 50;
825 const int width = 100;
826 const int height = 200;
827
828 EXPECT_CALL(mock_sink, bounding_rectangle())
829 .Times(0);
830 EXPECT_CALL(mock_sink, output_info(output_id))
831 .WillRepeatedly(Return(
832 mi::OutputInfo{
833 true,
834 geom::Size{width, height},
835 Matrix{{0.0f, 1.0f, output_x_pos,
836 -1.0f, 0.0f, width + output_y_pos}}}));
837 EXPECT_CALL(mock_sink,
838 handle_input(
839 mt::TouchContact(
840 0,
841 mir_touch_action_down,
842 output_x_pos + y,
843 output_y_pos + width - x)))
844 .Times(1);
845
846 touch_screen.apply_settings(mi::TouchscreenSettings{output_id, mir_touchscreen_mapping_mode_to_output});
847 touch_screen.start(&mock_sink, &mock_builder);
848
849 env.mock_libinput.setup_touch_event(fake_device, LIBINPUT_EVENT_TOUCH_DOWN, event_time_1, 0, x, y, 0, 0, 0, 0);
850 env.mock_libinput.setup_touch_frame(fake_device, event_time_1);
851
852 process_events(touch_screen);
853}
854
855TEST_F(LibInputDeviceOnTouchScreen, device_maps_to_right_rotated_output)
856{
857 EXPECT_CALL(mock_sink, bounding_rectangle())
858 .Times(0);
859 EXPECT_CALL(mock_sink, output_info(output_id))
860 .WillRepeatedly(Return(
861 mi::OutputInfo{
862 true,
863 geom::Size{width, height},
864 Matrix{{0.0f, -1.0f, height + output_x_pos,
865 1.0f, 0.0f, output_y_pos}}}));
866 EXPECT_CALL(mock_sink,
867 handle_input(
868 mt::TouchContact(
869 0,
870 mir_touch_action_down,
871 output_x_pos + height - y,
872 output_y_pos + x)))
873 .Times(1);
874
875 touch_screen.apply_settings(mi::TouchscreenSettings{output_id, mir_touchscreen_mapping_mode_to_output});
876 touch_screen.start(&mock_sink, &mock_builder);
877
878 env.mock_libinput.setup_touch_event(fake_device, LIBINPUT_EVENT_TOUCH_DOWN, event_time_1, 0, x, y, 0, 0, 0, 0);
879 env.mock_libinput.setup_touch_frame(fake_device, event_time_1);
880
881 process_events(touch_screen);
882}
883
884TEST_F(LibInputDeviceOnTouchScreen, device_maps_to_inverted_output)
885{
886 EXPECT_CALL(mock_sink, bounding_rectangle())
887 .Times(0);
888 EXPECT_CALL(mock_sink, output_info(output_id))
889 .WillRepeatedly(Return(
890 mi::OutputInfo{
891 true,
892 geom::Size{width, height},
893 Matrix{{-1.0f, 0.0f, width + output_x_pos,
894 0.0f, -1.0f, height + output_y_pos}}}));
895 EXPECT_CALL(mock_sink,
896 handle_input(
897 mt::TouchContact(
898 0,
899 mir_touch_action_down,
900 output_x_pos + width - x,
901 output_y_pos + height - y)))
902 .Times(1);
903
904 touch_screen.apply_settings(mi::TouchscreenSettings{output_id, mir_touchscreen_mapping_mode_to_output});
905 touch_screen.start(&mock_sink, &mock_builder);
906
907 env.mock_libinput.setup_touch_event(fake_device, LIBINPUT_EVENT_TOUCH_DOWN, event_time_1, 0, x, y, 0, 0, 0, 0);
908 env.mock_libinput.setup_touch_frame(fake_device, event_time_1);
909
910 process_events(touch_screen);
911}
912
913TEST_F(LibInputDeviceOnTouchScreen, display_wall_device_maps_to_bounding_rectangle)
914{
915 EXPECT_CALL(mock_sink, output_info(output_id))
916 .Times(0);
917 EXPECT_CALL(mock_sink, bounding_rectangle())
918 .WillOnce(Return(geom::Rectangle{geom::Point{screen_x_pos, screen_y_pos}, geom::Size{100, 100}}));
919 EXPECT_CALL(mock_sink, handle_input(mt::TouchContact(0, mir_touch_action_down, x + screen_x_pos, y + screen_y_pos)))
920 .Times(1);
921
922 touch_screen.apply_settings(mi::TouchscreenSettings{output_id, mir_touchscreen_mapping_mode_to_display_wall});
923 touch_screen.start(&mock_sink, &mock_builder);
924
925 env.mock_libinput.setup_touch_event(fake_device, LIBINPUT_EVENT_TOUCH_DOWN, event_time_1, 0, x, y, 0, 0, 0, 0);
926 env.mock_libinput.setup_touch_frame(fake_device, event_time_1);
927
928 process_events(touch_screen);
929}
930
931TEST_F(LibInputDeviceOnTouchScreen, drops_touchscreen_event_on_deactivated_output)
932{
933 EXPECT_CALL(mock_sink, handle_input(_)).Times(0);
934
935 ON_CALL(mock_sink, output_info(output_id))
936 .WillByDefault(Return(mi::OutputInfo{false, geom::Size{width, height}, Matrix{{1,0,0,0,1,0}}}));
937
938 touch_screen.apply_settings(mi::TouchscreenSettings{output_id, mir_touchscreen_mapping_mode_to_output});
939
940 touch_screen.start(&mock_sink, &mock_builder);
941 env.mock_libinput.setup_touch_event(fake_device, LIBINPUT_EVENT_TOUCH_DOWN, event_time_1, 0, x, y, 0, 0, 0, 0);
942 env.mock_libinput.setup_touch_frame(fake_device, event_time_1);
943
944 process_events(touch_screen);
945}
780946
=== modified file 'tests/unit-tests/input/test_seat_input_device_tracker.cpp'
--- tests/unit-tests/input/test_seat_input_device_tracker.cpp 2017-01-18 02:29:37 +0000
+++ tests/unit-tests/input/test_seat_input_device_tracker.cpp 2017-03-01 16:08:29 +0000
@@ -22,7 +22,6 @@
22#include "mir/input/xkb_mapper.h"22#include "mir/input/xkb_mapper.h"
23#include "mir/test/doubles/mock_input_device.h"23#include "mir/test/doubles/mock_input_device.h"
24#include "mir/test/doubles/mock_input_dispatcher.h"24#include "mir/test/doubles/mock_input_dispatcher.h"
25#include "mir/test/doubles/mock_input_region.h"
26#include "mir/test/doubles/mock_cursor_listener.h"25#include "mir/test/doubles/mock_cursor_listener.h"
27#include "mir/test/doubles/mock_touch_visualizer.h"26#include "mir/test/doubles/mock_touch_visualizer.h"
28#include "mir/test/doubles/mock_input_seat.h"27#include "mir/test/doubles/mock_input_seat.h"
@@ -53,7 +52,6 @@
53{52{
54 mi::EventBuilder* builder;53 mi::EventBuilder* builder;
55 Nice<mtd::MockInputDispatcher> mock_dispatcher;54 Nice<mtd::MockInputDispatcher> mock_dispatcher;
56 Nice<mtd::MockInputRegion> mock_region;
57 Nice<mtd::MockCursorListener> mock_cursor_listener;55 Nice<mtd::MockCursorListener> mock_cursor_listener;
58 Nice<mtd::MockTouchVisualizer> mock_visualizer;56 Nice<mtd::MockTouchVisualizer> mock_visualizer;
59 Nice<mtd::MockInputSeat> mock_seat;57 Nice<mtd::MockInputSeat> mock_seat;
@@ -70,8 +68,7 @@
70 mi::receiver::XKBMapper mapper;68 mi::receiver::XKBMapper mapper;
71 mi::SeatInputDeviceTracker tracker{69 mi::SeatInputDeviceTracker tracker{
72 mt::fake_shared(mock_dispatcher), mt::fake_shared(mock_visualizer), mt::fake_shared(mock_cursor_listener),70 mt::fake_shared(mock_dispatcher), mt::fake_shared(mock_visualizer), mt::fake_shared(mock_cursor_listener),
73 mt::fake_shared(mock_region), mt::fake_shared(mapper), mt::fake_shared(clock),71 mt::fake_shared(mapper), mt::fake_shared(clock), mt::fake_shared(mock_seat_report)};
74 mt::fake_shared(mock_seat_report)};
7572
76 std::chrono::nanoseconds arbitrary_timestamp;73 std::chrono::nanoseconds arbitrary_timestamp;
77};74};
7875
=== modified file 'tests/unit-tests/scene/test_surface_stack.cpp'
--- tests/unit-tests/scene/test_surface_stack.cpp 2017-02-15 14:45:41 +0000
+++ tests/unit-tests/scene/test_surface_stack.cpp 2017-03-01 16:08:29 +0000
@@ -989,7 +989,7 @@
989 stack.emit_scene_changed();989 stack.emit_scene_changed();
990}990}
991991
992TEST_F(SurfaceStack, only_enumerates_exposed_input_surfaces)992TEST_F(SurfaceStack, for_each_enumerates_all_input_surfaces)
993{993{
994 using namespace ::testing;994 using namespace ::testing;
995995
@@ -1007,7 +1007,7 @@
1007 };1007 };
10081008
1009 stack.for_each(count_exposed_surfaces);1009 stack.for_each(count_exposed_surfaces);
1010 EXPECT_THAT(num_exposed_surfaces, Eq(1));1010 EXPECT_THAT(num_exposed_surfaces, Eq(3));
1011}1011}
10121012
1013using namespace ::testing;1013using namespace ::testing;

Subscribers

People subscribed via source and target branches