Mir

Merge lp:~mir-team/mir/wayland-fix-keymaps-re-attempt into lp:mir

Proposed by Brandon Schaefer
Status: Merged
Approved by: Alan Griffiths
Approved revision: no longer in the source branch.
Merged at revision: 4284
Proposed branch: lp:~mir-team/mir/wayland-fix-keymaps-re-attempt
Merge into: lp:mir
Prerequisite: lp:~raof/mir/fixish-wayland-keyboard
Diff against target: 599 lines (+302/-27)
12 files modified
include/core/mir/optional_value.h (+5/-0)
include/server/mir/server_action_queue.h (+10/-0)
src/include/server/mir/glib_main_loop.h (+5/-0)
src/server/frontend/wayland/wayland_connector.cpp (+130/-18)
src/server/frontend/wayland/wayland_connector.h (+5/-1)
src/server/frontend/wayland/wayland_default_configuration.cpp (+1/-0)
src/server/glib_main_loop.cpp (+55/-1)
src/server/input/default_input_device_hub.cpp (+8/-7)
tests/include/mir/test/doubles/triggered_main_loop.h (+1/-0)
tests/mir_test_doubles/triggered_main_loop.cpp (+6/-0)
tests/unit-tests/scene/test_mediating_display_changer.cpp (+6/-0)
tests/unit-tests/test_glib_main_loop.cpp (+70/-0)
To merge this branch: bzr merge lp:~mir-team/mir/wayland-fix-keymaps-re-attempt
Reviewer Review Type Date Requested Status
Alan Griffiths Approve
Mir CI Bot continuous-integration Approve
Review via email: mp+331793@code.launchpad.net

Commit message

Wayland: Handle keymaps vaguely appropriately.

This will work for the common case of one system-wide keymap and no per-surface keymaps.

It does not handle having multiple keyboards with different keymaps, or per-surface keymaps. This is left as an exercise for the reader.

Description of the change

Re proposing https://code.launchpad.net/~mir-team/mir/wayland-fix-keymaps/+merge/331695

Since it didnt want to update its diffs or anything.

Wayland: Handle keymaps vaguely appropriately.

This will work for the common case of one system-wide keymap and no per-surface keymaps.

It does not handle having multiple keyboards with different keymaps, or per-surface keymaps. This is left as an exercise for the reader.

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

FAILED: Continuous integration, rev:4292
https://mir-jenkins.ubuntu.com/job/mir-ci/3714/
Executed test runs:
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-mir/5095/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/5333
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=artful/5320
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/5320
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/5320
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=artful/5139/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/5139/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=artful/5139/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/5139/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/5139/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=artful/5139
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=artful/5139/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=zesty/5139
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=zesty/5139/artifact/output/*zip*/output.zip
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/5139/console

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

review: Needs Fixing (continuous-integration)
Revision history for this message
MichaƂ Sawicz (saviq) wrote :

I'm afraid CI is quite insistent on the test failures :/

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

FAILED: Continuous integration, rev:4292
https://mir-jenkins.ubuntu.com/job/mir-ci/3715/
Executed test runs:
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-mir/5098/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/5336
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=artful/5323
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/5323
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/5323
    ABORTED: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=artful/5142/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/5142/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=artful/5142/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/5142/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/5142/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=artful/5142
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=artful/5142/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=zesty/5142
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=zesty/5142/artifact/output/*zip*/output.zip
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/5142/console

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

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

FAILED: Continuous integration, rev:4292
https://mir-jenkins.ubuntu.com/job/mir-ci/3717/
Executed test runs:
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-mir/5100/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/5338
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=artful/5325
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/5325
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/5325
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=artful/5144/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/5144
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/5144/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=artful/5144
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=artful/5144/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/5144
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/5144/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/5144
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/5144/artifact/output/*zip*/output.zip
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=artful/5144/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=zesty/5144
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=zesty/5144/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/5144
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/5144/artifact/output/*zip*/output.zip

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

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

PASSED: Continuous integration, rev:4292
https://mir-jenkins.ubuntu.com/job/mir-ci/3718/
Executed test runs:
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-mir/5101
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/5339
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=artful/5326
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/5326
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/5326
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=artful/5145
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=artful/5145/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/5145
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/5145/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=artful/5145
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=artful/5145/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/5145
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/5145/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/5145
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/5145/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=artful/5145
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=artful/5145/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=zesty/5145
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=zesty/5145/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/5145
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/5145/artifact/output/*zip*/output.zip

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

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

Nit:

+ void device_added (std::shared_ptr<input::Device> const& device) override;
+ void device_changed (std::shared_ptr<input::Device> const& device) override;
+ void device_removed (std::shared_ptr<input::Device> const& device) override;
+ void changes_complete () override;

We don't leave a space before function call parentheses.

Otherwise looks plausible and works for me

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

PASSED: Continuous integration, rev:4283
https://mir-jenkins.ubuntu.com/job/mir-ci/3719/
Executed test runs:
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-mir/5104
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/5342
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=artful/5329
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/5329
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/5329
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=artful/5148
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=artful/5148/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/5148
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/5148/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=artful/5148
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=artful/5148/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/5148
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/5148/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/5148
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/5148/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=artful/5148
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=artful/5148/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=zesty/5148
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=zesty/5148/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/5148
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/5148/artifact/output/*zip*/output.zip

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

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

Fixed

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'include/core/mir/optional_value.h'
--- include/core/mir/optional_value.h 2017-07-28 17:00:43 +0000
+++ include/core/mir/optional_value.h 2017-10-09 17:50:36 +0000
@@ -59,6 +59,11 @@
59 return std::move(value_);59 return std::move(value_);
60 }60 }
6161
62 operator bool() const
63 {
64 return is_set();
65 }
66
62private:67private:
63 void die_if_unset() const68 void die_if_unset() const
64 {69 {
6570
=== modified file 'include/server/mir/server_action_queue.h'
--- include/server/mir/server_action_queue.h 2017-07-28 17:00:43 +0000
+++ include/server/mir/server_action_queue.h 2017-10-09 17:50:36 +0000
@@ -32,6 +32,16 @@
32 virtual ~ServerActionQueue() = default;32 virtual ~ServerActionQueue() = default;
3333
34 virtual void enqueue(void const* owner, ServerAction const& action) = 0;34 virtual void enqueue(void const* owner, ServerAction const& action) = 0;
35 /**
36 * Enqueue an action to be run, guaranteeing that it *will* be run.
37 *
38 * The action will be run even if the queue is not normally being drained
39 * (for example, if the main loop is suspended). If running on the queue is
40 * not possible, the action will be run on the caller's thread.
41 *
42 * \param [in] action Functor to invoke.
43 */
44 virtual void enqueue_with_guaranteed_execution(ServerAction const& action) = 0;
35 virtual void pause_processing_for(void const* owner) = 0;45 virtual void pause_processing_for(void const* owner) = 0;
36 virtual void resume_processing_for(void const* owner) = 0;46 virtual void resume_processing_for(void const* owner) = 0;
3747
3848
=== modified file 'src/include/server/mir/glib_main_loop.h'
--- src/include/server/mir/glib_main_loop.h 2017-07-28 17:00:43 +0000
+++ src/include/server/mir/glib_main_loop.h 2017-10-09 17:50:36 +0000
@@ -28,6 +28,7 @@
28#include <exception>28#include <exception>
2929
30#include <glib.h>30#include <glib.h>
31#include <deque>
3132
32namespace mir33namespace mir
33{34{
@@ -76,6 +77,8 @@
76 void unregister_fd_handler(void const* owner) override;77 void unregister_fd_handler(void const* owner) override;
7778
78 void enqueue(void const* owner, ServerAction const& action) override;79 void enqueue(void const* owner, ServerAction const& action) override;
80 void enqueue_with_guaranteed_execution(ServerAction const& action) override;
81
79 void pause_processing_for(void const* owner) override;82 void pause_processing_for(void const* owner) override;
80 void resume_processing_for(void const* owner) override;83 void resume_processing_for(void const* owner) override;
8184
@@ -100,6 +103,8 @@
100 detail::SignalSources signal_sources;103 detail::SignalSources signal_sources;
101 std::mutex do_not_process_mutex;104 std::mutex do_not_process_mutex;
102 std::vector<void const*> do_not_process;105 std::vector<void const*> do_not_process;
106 std::mutex run_on_halt_mutex;
107 std::deque<ServerAction> run_on_halt_queue;
103 std::function<void()> before_iteration_hook;108 std::function<void()> before_iteration_hook;
104 std::exception_ptr main_loop_exception;109 std::exception_ptr main_loop_exception;
105};110};
106111
=== modified file 'src/server/frontend/wayland/wayland_connector.cpp'
--- src/server/frontend/wayland/wayland_connector.cpp 2017-10-08 02:12:58 +0000
+++ src/server/frontend/wayland/wayland_connector.cpp 2017-10-09 17:50:36 +0000
@@ -43,6 +43,11 @@
4343
44#include "mir/client/event.h"44#include "mir/client/event.h"
4545
46#include "mir/input/device.h"
47#include "mir/input/mir_keyboard_config.h"
48#include "mir/input/input_device_hub.h"
49#include "mir/input/input_device_observer.h"
50
46#include <system_error>51#include <system_error>
47#include <sys/eventfd.h>52#include <sys/eventfd.h>
48#include <wayland-server-core.h>53#include <wayland-server-core.h>
@@ -75,6 +80,7 @@
75namespace ms = mir::scene;80namespace ms = mir::scene;
76namespace geom = mir::geometry;81namespace geom = mir::geometry;
77namespace mcl = mir::client;82namespace mcl = mir::client;
83namespace mi = mir::input;
7884
79namespace mir85namespace mir
80{86{
@@ -798,6 +804,7 @@
798 wl_client* client,804 wl_client* client,
799 wl_resource* parent,805 wl_resource* parent,
800 uint32_t id,806 uint32_t id,
807 mir::input::Keymap const& initial_keymap,
801 std::function<void(WlKeyboard*)> const& on_destroy,808 std::function<void(WlKeyboard*)> const& on_destroy,
802 std::shared_ptr<mir::Executor> const& executor)809 std::shared_ptr<mir::Executor> const& executor)
803 : Keyboard(client, parent, id),810 : Keyboard(client, parent, id),
@@ -811,19 +818,14 @@
811 // TODO: We should really grab the keymap for the focused surface when818 // TODO: We should really grab the keymap for the focused surface when
812 // we receive focus.819 // we receive focus.
813820
814 xkb_rule_names default_rules;821 // TODO: Maintain per-device keymaps, and send the appropriate map before
815 memset(&default_rules, 0, sizeof(default_rules));822 // sending an event from a keyboard with a different map.
816823
817 keymap = decltype(keymap){824 /* The wayland::Keyboard constructor has already run, creating the keyboard
818 xkb_keymap_new_from_names(825 * resource. It is thus safe to send a keymap event to it; the client will receive
819 context.get(),826 * the keyboard object before this event.
820 &default_rules,827 */
821 XKB_KEYMAP_COMPILE_NO_FLAGS),828 set_keymap(initial_keymap);
822 &xkb_keymap_unref};
823
824 state = decltype(state){
825 xkb_state_new(keymap.get()),
826 &xkb_state_unref};
827 }829 }
828830
829 ~WlKeyboard()831 ~WlKeyboard()
@@ -966,6 +968,38 @@
966 state = decltype(state)(xkb_state_new(keymap.get()), &xkb_state_unref);968 state = decltype(state)(xkb_state_new(keymap.get()), &xkb_state_unref);
967 }969 }
968970
971 void set_keymap(mir::input::Keymap const& new_keymap)
972 {
973 xkb_rule_names const names = {
974 "evdev",
975 new_keymap.model.c_str(),
976 new_keymap.layout.c_str(),
977 new_keymap.variant.c_str(),
978 new_keymap.options.c_str()
979 };
980 keymap = decltype(keymap){
981 xkb_keymap_new_from_names(
982 context.get(),
983 &names,
984 XKB_KEYMAP_COMPILE_NO_FLAGS),
985 &xkb_keymap_unref};
986
987 // TODO: We might need to copy across the existing depressed keys?
988 state = decltype(state)(xkb_state_new(keymap.get()), &xkb_state_unref);
989
990 auto buffer = xkb_keymap_get_as_string(keymap.get(), XKB_KEYMAP_FORMAT_TEXT_V1);
991 auto length = strlen(buffer);
992
993 mir::AnonymousShmFile shm_buffer{length};
994 memcpy(shm_buffer.base_ptr(), buffer, length);
995
996 wl_keyboard_send_keymap(
997 resource,
998 WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1,
999 shm_buffer.fd(),
1000 length);
1001 }
1002
969private:1003private:
970 std::unique_ptr<xkb_keymap, decltype(&xkb_keymap_unref)> keymap;1004 std::unique_ptr<xkb_keymap, decltype(&xkb_keymap_unref)> keymap;
971 std::unique_ptr<xkb_state, decltype(&xkb_state_unref)> state;1005 std::unique_ptr<xkb_state, decltype(&xkb_state_unref)> state;
@@ -1320,8 +1354,20 @@
1320class WlSeat1354class WlSeat
1321{1355{
1322public:1356public:
1323 WlSeat(wl_display* display, std::shared_ptr<mir::Executor> const& executor)1357 WlSeat(
1324 : executor{executor},1358 wl_display* display,
1359 std::shared_ptr<mi::InputDeviceHub> const& input_hub,
1360 std::shared_ptr<mir::Executor> const& executor)
1361 : config_observer{
1362 std::make_shared<ConfigObserver>(
1363 keymap,
1364 [this](mir::input::Keymap const& new_keymap)
1365 {
1366 keymap = new_keymap;
1367
1368 })},
1369 input_hub{input_hub},
1370 executor{executor},
1325 global{wl_global_create(1371 global{wl_global_create(
1326 display,1372 display,
1327 &wl_seat_interface,1373 &wl_seat_interface,
@@ -1333,10 +1379,12 @@
1333 {1379 {
1334 BOOST_THROW_EXCEPTION(std::runtime_error("Failed to export wl_seat interface"));1380 BOOST_THROW_EXCEPTION(std::runtime_error("Failed to export wl_seat interface"));
1335 }1381 }
1382 input_hub->add_observer(config_observer);
1336 }1383 }
13371384
1338 ~WlSeat()1385 ~WlSeat()
1339 {1386 {
1387 input_hub->remove_observer(config_observer);
1340 wl_global_destroy(global);1388 wl_global_destroy(global);
1341 }1389 }
13421390
@@ -1350,9 +1398,38 @@
1350 }1398 }
13511399
1352private:1400private:
1401 class ConfigObserver : public mi::InputDeviceObserver
1402 {
1403 public:
1404 ConfigObserver(
1405 mir::input::Keymap const& keymap,
1406 std::function<void(mir::input::Keymap const&)> const& on_keymap_commit)
1407 : current_keymap{keymap},
1408 on_keymap_commit{on_keymap_commit}
1409 {
1410 }
1411
1412 void device_added(std::shared_ptr<input::Device> const& device) override;
1413 void device_changed(std::shared_ptr<input::Device> const& device) override;
1414 void device_removed(std::shared_ptr<input::Device> const& device) override;
1415 void changes_complete() override;
1416
1417 private:
1418 mir::input::Keymap const& current_keymap;
1419 mir::input::Keymap pending_keymap;
1420 std::function<void(mir::input::Keymap const&)> const on_keymap_commit;
1421 };
1422
1423 mir::input::Keymap keymap;
1424 std::shared_ptr<ConfigObserver> const config_observer;
1425
1353 std::unordered_map<wl_client*, InputCtx<WlPointer>> mutable pointer;1426 std::unordered_map<wl_client*, InputCtx<WlPointer>> mutable pointer;
1354 std::unordered_map<wl_client*, InputCtx<WlKeyboard>> mutable keyboard;1427 std::unordered_map<wl_client*, InputCtx<WlKeyboard>> mutable keyboard;
1355 std::unordered_map<wl_client*, InputCtx<WlTouch>> mutable touch;1428 std::unordered_map<wl_client*, InputCtx<WlTouch>> mutable touch;
1429
1430 std::shared_ptr<mi::InputDeviceHub> const input_hub;
1431
1432
1356 std::shared_ptr<mir::Executor> const executor;1433 std::shared_ptr<mir::Executor> const executor;
13571434
1358 static void bind(struct wl_client* client, void* data, uint32_t version, uint32_t id)1435 static void bind(struct wl_client* client, void* data, uint32_t version, uint32_t id)
@@ -1413,6 +1490,7 @@
1413 client,1490 client,
1414 resource,1491 resource,
1415 id,1492 id,
1493 me->keymap,
1416 [&input_ctx](WlKeyboard* listener)1494 [&input_ctx](WlKeyboard* listener)
1417 {1495 {
1418 input_ctx.unregister_listener(listener);1496 input_ctx.unregister_listener(listener);
@@ -1435,8 +1513,10 @@
1435 },1513 },
1436 me->executor});1514 me->executor});
1437 }1515 }
1438 static void release(struct wl_client* /*client*/, struct wl_resource* /*resource*/) {}1516 static void release(struct wl_client* /*client*/, struct wl_resource* us)
14391517 {
1518 wl_resource_destroy(us);
1519 }
14401520
1441 wl_global* const global;1521 wl_global* const global;
1442 static struct wl_seat_interface const vtable;1522 static struct wl_seat_interface const vtable;
@@ -1464,6 +1544,37 @@
1464 return touch[client];1544 return touch[client];
1465}1545}
14661546
1547void WlSeat::ConfigObserver::device_added(std::shared_ptr<input::Device> const& device)
1548{
1549 if (auto keyboard_config = device->keyboard_configuration())
1550 {
1551 if (current_keymap != keyboard_config.value().device_keymap())
1552 {
1553 pending_keymap = keyboard_config.value().device_keymap();
1554 }
1555 }
1556}
1557
1558void WlSeat::ConfigObserver::device_changed(std::shared_ptr<input::Device> const& device)
1559{
1560 if (auto keyboard_config = device->keyboard_configuration())
1561 {
1562 if (current_keymap != keyboard_config.value().device_keymap())
1563 {
1564 pending_keymap = keyboard_config.value().device_keymap();
1565 }
1566 }
1567}
1568
1569void WlSeat::ConfigObserver::device_removed(std::shared_ptr<input::Device> const& /*device*/)
1570{
1571}
1572
1573void WlSeat::ConfigObserver::changes_complete()
1574{
1575 on_keymap_commit(pending_keymap);
1576}
1577
1467void WaylandEventSink::send_buffer(BufferStreamId /*id*/, graphics::Buffer& /*buffer*/, graphics::BufferIpcMsgType)1578void WaylandEventSink::send_buffer(BufferStreamId /*id*/, graphics::Buffer& /*buffer*/, graphics::BufferIpcMsgType)
1468{1579{
1469}1580}
@@ -2055,6 +2166,7 @@
2055 optional_value<std::string> const& display_name,2166 optional_value<std::string> const& display_name,
2056 std::shared_ptr<mf::Shell> const& shell,2167 std::shared_ptr<mf::Shell> const& shell,
2057 DisplayChanger& display_config,2168 DisplayChanger& display_config,
2169 std::shared_ptr<mi::InputDeviceHub> const& input_hub,
2058 std::shared_ptr<mg::GraphicBufferAllocator> const& allocator,2170 std::shared_ptr<mg::GraphicBufferAllocator> const& allocator,
2059 bool arw_socket)2171 bool arw_socket)
2060 : display{wl_display_create(), &cleanup_display},2172 : display{wl_display_create(), &cleanup_display},
@@ -2089,7 +2201,7 @@
2089 display.get(),2201 display.get(),
2090 executor,2202 executor,
2091 this->allocator);2203 this->allocator);
2092 seat_global = std::make_unique<mf::WlSeat>(display.get(), executor);2204 seat_global = std::make_unique<mf::WlSeat>(display.get(), input_hub, executor);
2093 output_manager = std::make_unique<mf::OutputManager>(2205 output_manager = std::make_unique<mf::OutputManager>(
2094 display.get(),2206 display.get(),
2095 display_config);2207 display_config);
20962208
=== modified file 'src/server/frontend/wayland/wayland_connector.h'
--- src/server/frontend/wayland/wayland_connector.h 2017-09-15 16:34:13 +0000
+++ src/server/frontend/wayland/wayland_connector.h 2017-10-09 17:50:36 +0000
@@ -29,7 +29,10 @@
29namespace mir29namespace mir
30{30{
3131
3232namespace input
33{
34class InputDeviceHub;
35}
33namespace graphics36namespace graphics
34{37{
35class GraphicBufferAllocator;38class GraphicBufferAllocator;
@@ -54,6 +57,7 @@
54 optional_value<std::string> const& display_name,57 optional_value<std::string> const& display_name,
55 std::shared_ptr<Shell> const& shell,58 std::shared_ptr<Shell> const& shell,
56 DisplayChanger& display_config,59 DisplayChanger& display_config,
60 std::shared_ptr<input::InputDeviceHub> const& input_hub,
57 std::shared_ptr<graphics::GraphicBufferAllocator> const& allocator,61 std::shared_ptr<graphics::GraphicBufferAllocator> const& allocator,
58 bool arw_socket);62 bool arw_socket);
5963
6064
=== modified file 'src/server/frontend/wayland/wayland_default_configuration.cpp'
--- src/server/frontend/wayland/wayland_default_configuration.cpp 2017-09-15 16:34:13 +0000
+++ src/server/frontend/wayland/wayland_default_configuration.cpp 2017-10-09 17:50:36 +0000
@@ -42,6 +42,7 @@
42 display_name,42 display_name,
43 the_frontend_shell(),43 the_frontend_shell(),
44 *the_frontend_display_changer(),44 *the_frontend_display_changer(),
45 the_input_device_hub(),
45 the_buffer_allocator(),46 the_buffer_allocator(),
46 arw_socket);47 arw_socket);
47 });48 });
4849
=== modified file 'src/server/glib_main_loop.cpp'
--- src/server/glib_main_loop.cpp 2017-07-28 17:00:43 +0000
+++ src/server/glib_main_loop.cpp 2017-10-09 17:50:36 +0000
@@ -154,7 +154,19 @@
154 detail::add_idle_gsource(main_context, G_PRIORITY_HIGH,154 detail::add_idle_gsource(main_context, G_PRIORITY_HIGH,
155 [this]155 [this]
156 {156 {
157 running = false;157 {
158 std::lock_guard<std::mutex> lock{run_on_halt_mutex};
159 running = false;
160 }
161 // We know any other thread sees running == false here, so don't need
162 // to lock run_on_halt_queue.
163 for (auto& action : run_on_halt_queue)
164 {
165 try { action(); }
166 catch (...) { handle_exception(std::current_exception()); }
167 }
168 run_on_halt_queue.clear();
169
158 g_main_context_wakeup(main_context);170 g_main_context_wakeup(main_context);
159 });171 });
160}172}
@@ -246,6 +258,48 @@
246 });258 });
247}259}
248260
261
262void mir::GLibMainLoop::enqueue_with_guaranteed_execution(mir::ServerAction const& action)
263{
264 auto const action_with_exception_handling =
265 [this]
266 {
267 try
268 {
269 mir::ServerAction action;
270 {
271 std::lock_guard<std::mutex> lock{run_on_halt_mutex};
272 action = run_on_halt_queue.front();
273 run_on_halt_queue.pop_front();
274 }
275 action();
276 }
277 catch (...)
278 {
279 handle_exception(std::current_exception());
280 }
281 };
282
283 {
284 std::lock_guard<std::mutex> lock{run_on_halt_mutex};
285
286 if (!running)
287 {
288 action();
289 return;
290 }
291 else
292 {
293 run_on_halt_queue.push_back(action);
294 }
295 }
296
297 detail::add_idle_gsource(
298 main_context,
299 G_PRIORITY_DEFAULT,
300 action_with_exception_handling);
301}
302
249void mir::GLibMainLoop::pause_processing_for(void const* owner)303void mir::GLibMainLoop::pause_processing_for(void const* owner)
250{304{
251 std::lock_guard<std::mutex> lock{do_not_process_mutex};305 std::lock_guard<std::mutex> lock{do_not_process_mutex};
252306
=== modified file 'src/server/input/default_input_device_hub.cpp'
--- src/server/input/default_input_device_hub.cpp 2017-07-28 17:00:43 +0000
+++ src/server/input/default_input_device_hub.cpp 2017-10-09 17:50:36 +0000
@@ -88,25 +88,26 @@
88 auto observer = obs.lock();88 auto observer = obs.lock();
89 if (observer)89 if (observer)
90 {90 {
91 std::mutex mutex;
92 std::condition_variable cv;91 std::condition_variable cv;
93 std::unique_lock<decltype(mutex)> lock{mutex};92 std::atomic<bool> removed{false};
94 bool removed{false};
9593
96 data->observer_queue->enqueue(94 data->observer_queue->enqueue_with_guaranteed_execution(
97 data.get(),
98 [&,this]95 [&,this]
99 {96 {
100 // Unless remove() is on the same thread as add() external synchronization would be needed97 // Unless remove() is on the same thread as add() external synchronization would be needed
101 data->observers.remove(observer);98 data->observers.remove(observer);
10299
103 std::lock_guard<decltype(mutex)> lock{mutex};100 // We do *not* take a lock and instead rely on removed being atomic,
101 // as enqueue_with_guaranteed_execution may run on our stack.
104 removed = true;102 removed = true;
105 cv.notify_one();103 cv.notify_one();
106 });104 });
107105
106 std::mutex mutex;
107 std::unique_lock<decltype(mutex)> lock{mutex};
108
108 // Before returning wait for the remove - otherwise notifications can still happen109 // Before returning wait for the remove - otherwise notifications can still happen
109 cv.wait(lock, [&] { return removed; });110 cv.wait(lock, [&] { return removed.load(); });
110 }111 }
111}112}
112113
113114
=== modified file 'tests/include/mir/test/doubles/triggered_main_loop.h'
--- tests/include/mir/test/doubles/triggered_main_loop.h 2017-07-28 17:00:43 +0000
+++ tests/include/mir/test/doubles/triggered_main_loop.h 2017-10-09 17:50:36 +0000
@@ -41,6 +41,7 @@
41 void unregister_fd_handler(void const* owner) override;41 void unregister_fd_handler(void const* owner) override;
42 std::unique_ptr<mir::time::Alarm> create_alarm(callback const& call) override;42 std::unique_ptr<mir::time::Alarm> create_alarm(callback const& call) override;
43 void enqueue(void const* owner, ServerAction const& action) override;43 void enqueue(void const* owner, ServerAction const& action) override;
44 void enqueue_with_guaranteed_execution(ServerAction const& action) override;
4445
45 void spawn(std::function<void()>&& work) override;46 void spawn(std::function<void()>&& work) override;
4647
4748
=== modified file 'tests/mir_test_doubles/triggered_main_loop.cpp'
--- tests/mir_test_doubles/triggered_main_loop.cpp 2017-07-28 17:00:43 +0000
+++ tests/mir_test_doubles/triggered_main_loop.cpp 2017-10-09 17:50:36 +0000
@@ -81,6 +81,12 @@
81 actions.push_back(action);81 actions.push_back(action);
82}82}
8383
84void mtd::TriggeredMainLoop::enqueue_with_guaranteed_execution(ServerAction const& action)
85{
86 base::enqueue(nullptr, action);
87 actions.push_back(action);
88}
89
84void mtd::TriggeredMainLoop::trigger_server_actions()90void mtd::TriggeredMainLoop::trigger_server_actions()
85{91{
86 for (auto const& action : actions)92 for (auto const& action : actions)
8793
=== modified file 'tests/unit-tests/scene/test_mediating_display_changer.cpp'
--- tests/unit-tests/scene/test_mediating_display_changer.cpp 2017-08-09 11:30:59 +0000
+++ tests/unit-tests/scene/test_mediating_display_changer.cpp 2017-10-09 17:50:36 +0000
@@ -100,6 +100,10 @@
100 {100 {
101 action();101 action();
102 }102 }
103 void enqueue_with_guaranteed_execution(mir::ServerAction const& action) override
104 {
105 action();
106 }
103107
104 void pause_processing_for(void const* /*owner*/) override {}108 void pause_processing_for(void const* /*owner*/) override {}
105 void resume_processing_for(void const* /*owner*/) override {}109 void resume_processing_for(void const* /*owner*/) override {}
@@ -110,8 +114,10 @@
110 MockServerActionQueue()114 MockServerActionQueue()
111 {115 {
112 ON_CALL(*this, enqueue(_, _)).WillByDefault(InvokeArgument<1>());116 ON_CALL(*this, enqueue(_, _)).WillByDefault(InvokeArgument<1>());
117 ON_CALL(*this, enqueue_with_guaranteed_execution(_)).WillByDefault(InvokeArgument<0>());
113 }118 }
114 MOCK_METHOD2(enqueue, void(void const*, mir::ServerAction const&));119 MOCK_METHOD2(enqueue, void(void const*, mir::ServerAction const&));
120 MOCK_METHOD1(enqueue_with_guaranteed_execution, void(mir::ServerAction const&));
115 MOCK_METHOD1(pause_processing_for, void(void const*));121 MOCK_METHOD1(pause_processing_for, void(void const*));
116 MOCK_METHOD1(resume_processing_for, void(void const*));122 MOCK_METHOD1(resume_processing_for, void(void const*));
117};123};
118124
=== modified file 'tests/unit-tests/test_glib_main_loop.cpp'
--- tests/unit-tests/test_glib_main_loop.cpp 2017-07-28 17:00:43 +0000
+++ tests/unit-tests/test_glib_main_loop.cpp 2017-10-09 17:50:36 +0000
@@ -833,6 +833,76 @@
833 destroy_glib_main_loop);833 destroy_glib_main_loop);
834}834}
835835
836TEST_F(GLibMainLoopTest, enqueue_with_guaranteed_execution_executes_before_run)
837{
838 using namespace testing;
839
840 int num_actions{0};
841
842 ml.enqueue_with_guaranteed_execution(
843 [&num_actions]
844 {
845 ++num_actions;
846 });
847
848 EXPECT_THAT(num_actions, Eq(1));
849}
850
851TEST_F(GLibMainLoopTest, enqueue_with_guaranteed_execution_executes_after_stop)
852{
853 using namespace testing;
854
855 int num_actions{0};
856
857 ml.enqueue(
858 nullptr,
859 [this]()
860 {
861 ml.stop();
862 });
863
864 ml.run();
865
866 ml.enqueue_with_guaranteed_execution(
867 [&num_actions]
868 {
869 ++num_actions;
870 });
871
872 EXPECT_THAT(num_actions, Eq(1));
873}
874
875TEST_F(GLibMainLoopTest, enqueue_with_guaranteed_execution_executes_on_mainloop)
876{
877 using namespace testing;
878
879 mt::Signal loop_running;
880 mt::Signal loop_finished;
881
882 ml.enqueue(
883 nullptr,
884 [&loop_running]() { loop_running.raise(); });
885
886 mt::AutoJoinThread t{
887 [&]
888 {
889 ml.run();
890 loop_finished.raise();
891 }};
892
893 ASSERT_TRUE(loop_running.wait_for(std::chrono::seconds{5}));
894
895 ml.enqueue_with_guaranteed_execution(
896 [main_thread = std::this_thread::get_id()]()
897 {
898 EXPECT_THAT(std::this_thread::get_id(), Ne(main_thread));
899 });
900
901 ml.stop();
902
903 EXPECT_TRUE(loop_finished.wait_for(std::chrono::seconds{30}));
904}
905
836namespace906namespace
837{907{
838908

Subscribers

People subscribed via source and target branches