Mir

Merge lp:~afrantzis/mir/always-consume-input-events-in-clients into lp:mir

Proposed by Alexandros Frantzis
Status: Rejected
Rejected by: Alan Griffiths
Proposed branch: lp:~afrantzis/mir/always-consume-input-events-in-clients
Merge into: lp:mir
Diff against target: 248 lines (+113/-82)
2 files modified
src/client/mir_surface.cpp (+13/-6)
tests/unit-tests/client/test_client_mir_surface.cpp (+100/-76)
To merge this branch: bzr merge lp:~afrantzis/mir/always-consume-input-events-in-clients
Reviewer Review Type Date Requested Status
Alan Griffiths Needs Information
PS Jenkins bot (community) continuous-integration Approve
Review via email: mp+209313@code.launchpad.net

Commit message

client: Process input events even in clients that don't handle input

Description of the change

client: Process input events even in clients that don't handle input

This is one alternative solution for bug 1213804. See comments in bug 1213804 for more information and pointers to other options.

Currently, focused client surfaces that don't handle input events don't process them at all. Such clients never acknowledge receiving input events, causing the input system to retry sending the events.

If in the interval between two send attempts another app gains the focus, the input system sends the event to the newly focused app/surface, leading to bug 1213804 (i.e. the target of events is always the currently focused surfaced, not a particular surface).

Ideally, the input system should be able to handle this situation better, e.g., by resending the event only if the focused surface the event was originally targeted at hasn't changed. However, the input subsystem is full of intricacies and I am not familiar enough with it to tell if this behavior is a bug or has a particular reason for being there.

If we decide that the proposed solution/workaround is not acceptable, I can dive more deeply into the abyss known as the input subsystem.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Daniel van Vugt (vanvugt) wrote :

It definitely sounds like a workaround more than a fix. It also leads to clients being woken up by events they should never receive at all. But we possibly already had that problem...

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

> It definitely sounds like a workaround more than a fix. It also leads to
> clients being woken up by events they should never receive at all. But we
> possibly already had that problem...

I guess toolkits will always have event handles set?

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

It sounds to me as though the real problem is in the server - that if a client fails to consume an event then "bad stuff happens". I'd rather fix the "bad stuff happens" - but if that is a lot of work then this attempt to mitigate the problem is OK (at least for now).

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

InputDispatcher.cpp has its own app switching logic which does a lot of interesting things, as there is something like a dedicated app switch key... Maybe we have to drop all key events when focused surface changes?

Revision history for this message
Alexandros Frantzis (afrantzis) wrote :

> I'd rather fix the "bad stuff happens" - but if that is a lot of work then this attempt to mitigate the problem is OK (at least for now).

> Maybe we have to drop all key events when focused surface changes?

I am looking more into the input subsystem to see if there is a clean and safe way we can handle the issue there.

Unmerged revisions

1445. By Alexandros Frantzis

client: Process input events even in clients that don't handle input

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/client/mir_surface.cpp'
--- src/client/mir_surface.cpp 2014-02-10 09:07:48 +0000
+++ src/client/mir_surface.cpp 2014-03-04 17:39:59 +0000
@@ -213,6 +213,8 @@
213 accelerated_window = platform->create_egl_native_window(this);213 accelerated_window = platform->create_egl_native_window(this);
214 }214 }
215215
216 set_event_handler(nullptr);
217
216 connection->on_surface_created(id(), this);218 connection->on_surface_created(id(), this);
217 callback(this, context);219 callback(this, context);
218 create_wait_handle.result_received();220 create_wait_handle.result_received();
@@ -366,13 +368,18 @@
366 handle_event_callback = std::bind(delegate->callback, this,368 handle_event_callback = std::bind(delegate->callback, this,
367 std::placeholders::_1,369 std::placeholders::_1,
368 delegate->context);370 delegate->context);
371 }
372 else
373 {
374 handle_event_callback = [](MirEvent const*) {};
375 }
369376
370 if (surface.fd_size() > 0 && handle_event_callback)377 if (surface.fd_size() > 0)
371 {378 {
372 input_thread = input_platform->create_input_thread(surface.fd(0),379 input_thread =
373 handle_event_callback);380 input_platform->create_input_thread(surface.fd(0),
374 input_thread->start();381 handle_event_callback);
375 }382 input_thread->start();
376 }383 }
377}384}
378385
379386
=== modified file 'tests/unit-tests/client/test_client_mir_surface.cpp'
--- tests/unit-tests/client/test_client_mir_surface.cpp 2014-02-11 03:04:50 +0000
+++ tests/unit-tests/client/test_client_mir_surface.cpp 2014-03-04 17:39:59 +0000
@@ -248,9 +248,16 @@
248248
249struct StubClientInputPlatform : public mircv::InputPlatform249struct StubClientInputPlatform : public mircv::InputPlatform
250{250{
251 std::shared_ptr<mircv::InputReceiverThread> create_input_thread(int /* fd */, std::function<void(MirEvent*)> const& /* callback */)251 std::shared_ptr<mircv::InputReceiverThread> create_input_thread(
252 int /* fd */, std::function<void(MirEvent*)> const& /* callback */)
252 {253 {
253 return std::shared_ptr<mircv::InputReceiverThread>();254 struct NullInputReceiverThread : public mircv::InputReceiverThread
255 {
256 void start() override {}
257 void stop() override {}
258 void join() override {}
259 };
260 return std::make_shared<NullInputReceiverThread>();
254 }261 }
255};262};
256263
@@ -493,38 +500,106 @@
493static void null_event_callback(MirSurface*, MirEvent const*, void*)500static void null_event_callback(MirSurface*, MirEvent const*, void*)
494{501{
495}502}
503
504class StubBuffer : public mcl::ClientBuffer
505{
506public:
507 StubBuffer(geom::Size size, geom::Stride stride, MirPixelFormat pf)
508 : size_{size}, stride_{stride}, pf_{pf}
509 {
510 }
511
512 std::shared_ptr<mcl::MemoryRegion> secure_for_cpu_write() override
513 {
514 auto raw = new mcl::MemoryRegion{size_.width,
515 size_.height,
516 stride_,
517 pf_,
518 nullptr};
519
520 return std::shared_ptr<mcl::MemoryRegion>(raw);
521 }
522
523 geom::Size size() const override { return size_; }
524 geom::Stride stride() const override { return stride_; }
525 MirPixelFormat pixel_format() const override { return pf_; }
526 uint32_t age() const override { return 0; }
527 void increment_age() override {}
528 void mark_as_submitted() override {}
529
530 std::shared_ptr<mg::NativeBuffer> native_buffer_handle() const override
531 {
532 return std::shared_ptr<mg::NativeBuffer>();
533 }
534
535private:
536 geom::Size const size_;
537 geom::Stride const stride_;
538 MirPixelFormat const pf_;
539};
540
541struct StubClientBufferFactory : public mcl::ClientBufferFactory
542{
543 std::shared_ptr<mcl::ClientBuffer> create_buffer(
544 std::shared_ptr<MirBufferPackage> const& package,
545 geom::Size size, MirPixelFormat pf)
546 {
547 return std::make_shared<StubBuffer>(size,
548 geom::Stride{package->stride},
549 pf);
550 }
551};
496}552}
497553
498TEST_F(MirClientSurfaceTest, input_fd_used_to_create_input_thread_when_delegate_specified)554TEST_F(MirClientSurfaceTest, creates_input_thread_at_construction)
499{555{
500 using namespace ::testing;556 using namespace ::testing;
501557
502 auto mock_input_platform = std::make_shared<mt::MockClientInputPlatform>();558 auto const mock_input_platform = std::make_shared<mt::MockClientInputPlatform>();
503 auto mock_input_thread = std::make_shared<NiceMock<mt::MockInputReceiverThread>>();559 auto const mock_input_thread = std::make_shared<NiceMock<mt::MockInputReceiverThread>>();
504 MirEventDelegate delegate = {null_event_callback, nullptr};560
505561 EXPECT_CALL(*mock_input_platform, create_input_thread(_, _))
506 EXPECT_CALL(*mock_buffer_factory, create_buffer(_,_,_)).Times(2);
507
508 EXPECT_CALL(*mock_input_platform, create_input_thread(_, _)).Times(1)
509 .WillOnce(Return(mock_input_thread));562 .WillOnce(Return(mock_input_thread));
510 EXPECT_CALL(*mock_input_thread, start()).Times(1);563 EXPECT_CALL(*mock_input_thread, start()).Times(1);
511 EXPECT_CALL(*mock_input_thread, stop()).Times(1);564 EXPECT_CALL(*mock_input_thread, stop()).Times(1);
512565
513 {566 MirSurface mir_surface(connection.get(), *client_comm_channel,
514 auto surface = std::make_shared<MirSurface> (connection.get(), *client_comm_channel,567 std::make_shared<StubClientBufferFactory>(),
515 mock_buffer_factory, mock_input_platform, params, &empty_callback, nullptr);568 mock_input_platform, params, &empty_callback, nullptr);
516 auto wait_handle = surface->get_create_wait_handle();569
517 wait_handle->wait_for_all();570 mir_surface.get_create_wait_handle()->wait_for_all();
518 surface->set_event_handler(&delegate);571}
519 }572
520573TEST_F(MirClientSurfaceTest, recreates_input_thread_when_setting_event_handler)
521 {574{
522 // This surface should not trigger a call to the input platform as no input delegate is specified.575 using namespace ::testing;
523 auto surface = std::make_shared<MirSurface> (connection.get(), *client_comm_channel,576
524 mock_buffer_factory, mock_input_platform, params, &empty_callback, nullptr);577 auto const mock_input_platform = std::make_shared<mt::MockClientInputPlatform>();
525 auto wait_handle = surface->get_create_wait_handle();578 auto const mock_input_thread1 = std::make_shared<NiceMock<mt::MockInputReceiverThread>>();
526 wait_handle->wait_for_all();579
527 }580 EXPECT_CALL(*mock_input_platform, create_input_thread(_, _))
581 .WillOnce(Return(mock_input_thread1));
582 EXPECT_CALL(*mock_input_thread1, start()).Times(1);
583
584 MirSurface mir_surface(connection.get(), *client_comm_channel,
585 std::make_shared<StubClientBufferFactory>(),
586 mock_input_platform, params, &empty_callback, nullptr);
587
588 mir_surface.get_create_wait_handle()->wait_for_all();
589
590 Mock::VerifyAndClearExpectations(mock_input_platform.get());
591 Mock::VerifyAndClearExpectations(mock_input_thread1.get());
592
593 auto const mock_input_thread2 = std::make_shared<NiceMock<mt::MockInputReceiverThread>>();
594
595 EXPECT_CALL(*mock_input_thread1, stop()).Times(1);
596 EXPECT_CALL(*mock_input_platform, create_input_thread(_, _))
597 .WillOnce(Return(mock_input_thread2));
598 EXPECT_CALL(*mock_input_thread2, start()).Times(1);
599 EXPECT_CALL(*mock_input_thread2, stop()).Times(1);
600
601 MirEventDelegate const delegate = {null_event_callback, nullptr};
602 mir_surface.set_event_handler(&delegate);
528}603}
529604
530TEST_F(MirClientSurfaceTest, get_buffer_returns_last_received_buffer_package)605TEST_F(MirClientSurfaceTest, get_buffer_returns_last_received_buffer_package)
@@ -633,57 +708,6 @@
633 surface->attrib(mir_surface_attrib_state));708 surface->attrib(mir_surface_attrib_state));
634}709}
635710
636namespace
637{
638
639struct StubBuffer : public mcl::ClientBuffer
640{
641 StubBuffer(geom::Size size, geom::Stride stride, MirPixelFormat pf)
642 : size_{size}, stride_{stride}, pf_{pf}
643 {
644 }
645
646 std::shared_ptr<mcl::MemoryRegion> secure_for_cpu_write()
647 {
648 auto raw = new mcl::MemoryRegion{size_.width,
649 size_.height,
650 stride_,
651 pf_,
652 nullptr};
653
654 return std::shared_ptr<mcl::MemoryRegion>(raw);
655 }
656
657 geom::Size size() const { return size_; }
658 geom::Stride stride() const { return stride_; }
659 MirPixelFormat pixel_format() const { return pf_; }
660 uint32_t age() const { return 0; }
661 void increment_age() {}
662 void mark_as_submitted() {}
663
664 std::shared_ptr<mg::NativeBuffer> native_buffer_handle() const
665 {
666 return std::shared_ptr<mg::NativeBuffer>();
667 }
668
669 geom::Size size_;
670 geom::Stride stride_;
671 MirPixelFormat pf_;
672};
673
674struct StubClientBufferFactory : public mcl::ClientBufferFactory
675{
676 std::shared_ptr<mcl::ClientBuffer> create_buffer(
677 std::shared_ptr<MirBufferPackage> const& package,
678 geom::Size size, MirPixelFormat pf)
679 {
680 return std::make_shared<StubBuffer>(size,
681 geom::Stride{package->stride},
682 pf);
683 }
684};
685
686}
687TEST_F(MirClientSurfaceTest, get_cpu_region_returns_correct_data)711TEST_F(MirClientSurfaceTest, get_cpu_region_returns_correct_data)
688{712{
689 using namespace testing;713 using namespace testing;

Subscribers

People subscribed via source and target branches