Mir

Merge lp:~robertcarr/mir/focus-tell-dont-ask into lp:~mir-team/mir/trunk

Proposed by Robert Carr
Status: Superseded
Proposed branch: lp:~robertcarr/mir/focus-tell-dont-ask
Merge into: lp:~mir-team/mir/trunk
Diff against target: 478 lines (+160/-105)
14 files modified
include/server/mir/frontend/communicator_report.h (+0/-1)
include/server/mir/shell/application_session.h (+6/-0)
include/server/mir/shell/default_focus_mechanism.h (+2/-2)
include/server/mir/shell/session.h (+5/-0)
include/test/mir_test_doubles/mock_shell_session.h (+3/-0)
include/test/mir_test_doubles/stub_shell_session.h (+8/-0)
src/server/frontend/protobuf_socket_communicator.cpp (+1/-1)
src/server/frontend/socket_messenger.cpp (+13/-3)
src/server/frontend/socket_messenger.h (+6/-1)
src/server/shell/application_session.cpp (+38/-3)
src/server/shell/default_focus_mechanism.cpp (+10/-18)
tests/unit-tests/frontend/CMakeLists.txt (+1/-0)
tests/unit-tests/frontend/test_socket_messenger.cpp (+37/-0)
tests/unit-tests/shell/test_default_focus_mechanism.cpp (+30/-76)
To merge this branch: bzr merge lp:~robertcarr/mir/focus-tell-dont-ask
Reviewer Review Type Date Requested Status
Alan Griffiths Pending
Daniel van Vugt Pending
PS Jenkins bot continuous-integration Pending
Alexandros Frantzis Pending
Review via email: mp+186655@code.launchpad.net

This proposal supersedes a proposal from 2013-09-06.

This proposal has been superseded by a proposal from 2013-09-23.

Description of the change

== Old Description ==

Fix the races around focus. Essentially these stem from that holding std::shared_ptr<msh::Surface> doesn't guarantee that calling methods on that surface will be safe (the underlying surface could be destroyed via Surface::destroy and then your method call will throw).

So this branch changes ApplicationSession to not destroy the surface explicitly and instead rely on ~msh::Surface, which means that you really can hold a safe pointer. I think this as a reasonable choice, as the shell might want to do similar things, i.e. continue to animate a surface after a session has closed it.

==

New approach relies on ApplicationSession to hold the last focused ptr...WIP

To post a comment you must log in.
Revision history for this message
Robert Carr (robertcarr) wrote : Posted in a previous version of this proposal

I was able to run the stress test with continuous cursor input for the full ten minute run. There is also good reason to believe this fixes: https://bugs.launchpad.net/mir/+bug/1220845

The exception in ~SessionMediator can be triggered if session_manager->close_session throws (due to this focus race), causing SessionMediator::disconnect to fail to reset it's session member-variable pointer. This exception is caught in frontend. However now in ~SessionMediator the pointer has not been reset so it closes the session again throwing an Invalid Session exception. causing the session to be closed again in ~

Revision history for this message
Robert Carr (robertcarr) wrote : Posted in a previous version of this proposal

The unsafely held surface pointer in this case is the previously focused app.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Approve (continuous-integration)
Revision history for this message
Alexandros Frantzis (afrantzis) wrote : Posted in a previous version of this proposal

There is an inconsistency with this approach: when a session is closed its surface resources are destroyed immediately, but when a surface is explicitly destroyed the resources are not destroyed until there are no more users.

Would it (make sense|be possible) for msh::Surface to own (hold a strong pointer to) ms::Surface and rely on ~msh::Surface() in both the cases above, thus removing the msh::Surface -> ms::Surface weak_ptr dance?

review: Needs Information
Revision history for this message
Alan Griffiths (alan-griffiths) wrote : Posted in a previous version of this proposal

> There is an inconsistency with this approach: when a session is closed its
> surface resources are destroyed immediately, but when a surface is explicitly
> destroyed the resources are not destroyed until there are no more users.
>
> Would it (make sense|be possible) for msh::Surface to own (hold a strong
> pointer to) ms::Surface and rely on ~msh::Surface() in both the cases above,
> thus removing the msh::Surface -> ms::Surface weak_ptr dance?

I've not yet looked at the MP, but I can contribute the origin of the "weak_ptr dance".

Once a surface has been "destroyed" it is no longer in the scenegraph (ok, SurfaceStack) and therefore not composited. If the ms::Surface continued to exist it could reach a state where it has client buffers meaning threads that require them will wait forever.

It may well be that subsequent changes (particularly the introduction of force_requests_to_complete()) permits a better solution than the "weak_ptr dance".

Revision history for this message
Alan Griffiths (alan-griffiths) wrote : Posted in a previous version of this proposal

I don't think this is the right evolution of the code, but I don't think it makes things worse.

The right solution would be more complex and should probably come as part of fixing the data model.

review: Abstain
Revision history for this message
Robert Carr (robertcarr) wrote : Posted in a previous version of this proposal

I think it makes sense to not destroy the surfaces explicitly from the session (as in the last committ). It may be possible to fix the weak_ptr dance (it almost surely is possible). It's not really clear what direction this code should go in right now though (except probably not further down this one), so I am trying to just fix the crashes non invasively

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Approve (continuous-integration)
Revision history for this message
Daniel van Vugt (vanvugt) wrote : Posted in a previous version of this proposal

Bug 1216727 is still happening :(

terminate called after throwing an instance of 'boost::exception_detail::clone_impl<boost::exception_detail::error_info_injector<std::logic_error> >'
  what(): Requesting handle for an unregistered channel

Should we just unlink it from the branch?

review: Needs Fixing
Revision history for this message
Daniel van Vugt (vanvugt) wrote : Posted in a previous version of this proposal

P.S. Before declaring bug 1216727 fixed, please find a machine on which you can reproduce it (using trunk). To be sure the changes are actually having an effect.

Revision history for this message
Robert Carr (robertcarr) wrote : Posted in a previous version of this proposal

Can someone review this again?

Revision history for this message
Daniel van Vugt (vanvugt) : Posted in a previous version of this proposal
review: Abstain
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
Daniel van Vugt (vanvugt) wrote : Posted in a previous version of this proposal

Weirdly, merging this branch now causes an almost immediate hang:

Running tests...
Test project /home/dan/bzr/mir/tmp.focus/build
        Start 1: LGPL-required
  1/145 Test #1: LGPL-required ............................................... Passed 0.01 sec
        Start 2: GPL-required
  2/145 Test #2: GPL-required ................................................ Passed 0.01 sec
        Start 3: acceptance-tests.BespokeDisplayServerTestFixture.*

review: Needs Fixing
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
Daniel van Vugt (vanvugt) wrote : Posted in a previous version of this proposal

Another bug with this branch is that on Alt+Tab in demo_server_shell, the client rendering freezes. Permanently.

review: Needs Fixing
1085. By Robert Carr

Typo

1086. By Robert Carr

Merge development-branch

1087. By Robert Carr

Merge socket-messenger-reporitng

1088. By Robert Carr

Fix error in relinquish focus

Unmerged revisions

1088. By Robert Carr

Fix error in relinquish focus

1087. By Robert Carr

Merge socket-messenger-reporitng

1086. By Robert Carr

Merge development-branch

1085. By Robert Carr

Typo

1084. By Robert Carr

application_session: Introduce default_surface_locked to dedupe some code

1083. By Robert Carr

Merge fix-1226139

1082. By Robert Carr

More cleanup

1081. By Robert Carr

Merge trunk

1080. By Robert Carr

Cleanup

1079. By Robert Carr

Mutex for surface

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'include/server/mir/frontend/communicator_report.h'
--- include/server/mir/frontend/communicator_report.h 2013-06-19 16:14:40 +0000
+++ include/server/mir/frontend/communicator_report.h 2013-09-23 14:32:39 +0000
@@ -42,7 +42,6 @@
42class NullCommunicatorReport : public CommunicatorReport42class NullCommunicatorReport : public CommunicatorReport
43{43{
44public:44public:
45
46 void error(std::exception const& error);45 void error(std::exception const& error);
47};46};
48}47}
4948
=== modified file 'include/server/mir/shell/application_session.h'
--- include/server/mir/shell/application_session.h 2013-08-28 03:41:48 +0000
+++ include/server/mir/shell/application_session.h 2013-09-23 14:32:39 +0000
@@ -67,6 +67,9 @@
6767
68 void set_lifecycle_state(MirLifecycleState state);68 void set_lifecycle_state(MirLifecycleState state);
6969
70 void receive_focus(std::shared_ptr<InputTargeter> const& targeter, std::shared_ptr<SurfaceController> const& controller);
71 void relinquish_focus();
72
70protected:73protected:
71 ApplicationSession(ApplicationSession const&) = delete;74 ApplicationSession(ApplicationSession const&) = delete;
72 ApplicationSession& operator=(ApplicationSession const&) = delete;75 ApplicationSession& operator=(ApplicationSession const&) = delete;
@@ -79,6 +82,7 @@
79 std::shared_ptr<frontend::EventSink> const event_sink;82 std::shared_ptr<frontend::EventSink> const event_sink;
8083
81 frontend::SurfaceId next_id();84 frontend::SurfaceId next_id();
85 std::shared_ptr<Surface> default_surface_locked(std::unique_lock<std::mutex> const& lock) const;
8286
83 std::atomic<int> next_surface_id;87 std::atomic<int> next_surface_id;
8488
@@ -86,6 +90,8 @@
86 Surfaces::const_iterator checked_find(frontend::SurfaceId id) const;90 Surfaces::const_iterator checked_find(frontend::SurfaceId id) const;
87 std::mutex mutable surfaces_mutex;91 std::mutex mutable surfaces_mutex;
88 Surfaces surfaces;92 Surfaces surfaces;
93
94 std::weak_ptr<Surface> last_focused_surface;
89};95};
9096
91}97}
9298
=== modified file 'include/server/mir/shell/default_focus_mechanism.h'
--- include/server/mir/shell/default_focus_mechanism.h 2013-08-28 03:41:48 +0000
+++ include/server/mir/shell/default_focus_mechanism.h 2013-09-23 14:32:39 +0000
@@ -50,8 +50,8 @@
50 std::shared_ptr<InputTargeter> const input_targeter;50 std::shared_ptr<InputTargeter> const input_targeter;
51 std::shared_ptr<SurfaceController> const surface_controller;51 std::shared_ptr<SurfaceController> const surface_controller;
5252
53 std::mutex surface_focus_lock;53 std::mutex focus_lock;
54 std::weak_ptr<Surface> currently_focused_surface;54 std::weak_ptr<Session> currently_focused_session;
55};55};
5656
57}57}
5858
=== modified file 'include/server/mir/shell/session.h'
--- include/server/mir/shell/session.h 2013-08-28 03:41:48 +0000
+++ include/server/mir/shell/session.h 2013-09-23 14:32:39 +0000
@@ -28,6 +28,8 @@
28namespace shell28namespace shell
29{29{
30class Surface;30class Surface;
31class InputTargeter;
32class SurfaceController;
3133
32class Session : public frontend::Session34class Session : public frontend::Session
33{35{
@@ -37,6 +39,9 @@
3739
38 virtual void take_snapshot(SnapshotCallback const& snapshot_taken) = 0;40 virtual void take_snapshot(SnapshotCallback const& snapshot_taken) = 0;
39 virtual std::shared_ptr<Surface> default_surface() const = 0;41 virtual std::shared_ptr<Surface> default_surface() const = 0;
42
43 virtual void receive_focus(std::shared_ptr<InputTargeter> const& targeter, std::shared_ptr<SurfaceController> const& controller) = 0;
44 virtual void relinquish_focus() = 0;
40};45};
4146
42}47}
4348
=== modified file 'include/test/mir_test_doubles/mock_shell_session.h'
--- include/test/mir_test_doubles/mock_shell_session.h 2013-08-28 03:41:48 +0000
+++ include/test/mir_test_doubles/mock_shell_session.h 2013-09-23 14:32:39 +0000
@@ -49,6 +49,9 @@
49 49
50 MOCK_METHOD1(send_display_config, void(graphics::DisplayConfiguration const&));50 MOCK_METHOD1(send_display_config, void(graphics::DisplayConfiguration const&));
51 MOCK_METHOD3(configure_surface, int(frontend::SurfaceId, MirSurfaceAttrib, int));51 MOCK_METHOD3(configure_surface, int(frontend::SurfaceId, MirSurfaceAttrib, int));
52
53 MOCK_METHOD2(receive_focus, void(std::shared_ptr<shell::InputTargeter> const&, std::shared_ptr<shell::SurfaceController> const&));
54 MOCK_METHOD0(relinquish_focus, void());
52};55};
5356
54}57}
5558
=== modified file 'include/test/mir_test_doubles/stub_shell_session.h'
--- include/test/mir_test_doubles/stub_shell_session.h 2013-08-13 22:20:37 +0000
+++ include/test/mir_test_doubles/stub_shell_session.h 2013-09-23 14:32:39 +0000
@@ -71,6 +71,14 @@
71 {71 {
72 return std::shared_ptr<shell::Surface>();72 return std::shared_ptr<shell::Surface>();
73 }73 }
74
75 void receive_focus(std::shared_ptr<shell::InputTargeter> const&,
76 std::shared_ptr<shell::SurfaceController> const&)
77 {
78 }
79 void relinquish_focus()
80 {
81 }
74};82};
7583
76}84}
7785
=== modified file 'src/server/frontend/protobuf_socket_communicator.cpp'
--- src/server/frontend/protobuf_socket_communicator.cpp 2013-08-28 03:41:48 +0000
+++ src/server/frontend/protobuf_socket_communicator.cpp 2013-09-23 14:32:39 +0000
@@ -135,7 +135,7 @@
135{135{
136 if (!ec)136 if (!ec)
137 {137 {
138 auto messenger = std::make_shared<detail::SocketMessenger>(socket);138 auto messenger = std::make_shared<detail::SocketMessenger>(socket, report);
139 auto client_pid = messenger->client_pid(); 139 auto client_pid = messenger->client_pid();
140 if (session_authorizer->connection_is_allowed(client_pid))140 if (session_authorizer->connection_is_allowed(client_pid))
141 {141 {
142142
=== modified file 'src/server/frontend/socket_messenger.cpp'
--- src/server/frontend/socket_messenger.cpp 2013-08-28 03:41:48 +0000
+++ src/server/frontend/socket_messenger.cpp 2013-09-23 14:32:39 +0000
@@ -18,13 +18,16 @@
1818
19#include "socket_messenger.h"19#include "socket_messenger.h"
20#include "mir/frontend/client_constants.h"20#include "mir/frontend/client_constants.h"
21#include "mir/frontend/communicator_report.h"
2122
22namespace mfd = mir::frontend::detail;23namespace mfd = mir::frontend::detail;
23namespace bs = boost::system;24namespace bs = boost::system;
24namespace ba = boost::asio;25namespace ba = boost::asio;
2526
26mfd::SocketMessenger::SocketMessenger(std::shared_ptr<ba::local::stream_protocol::socket> const& socket)27mfd::SocketMessenger::SocketMessenger(std::shared_ptr<ba::local::stream_protocol::socket> const& socket,
27 : socket(socket)28 std::shared_ptr<CommunicatorReport> const& report)
29 : socket(socket),
30 report(report)
28{31{
29 whole_message.reserve(serialization_buffer_size);32 whole_message.reserve(serialization_buffer_size);
30}33}
@@ -59,7 +62,14 @@
59 // function has completed (if it would be executed asynchronously.62 // function has completed (if it would be executed asynchronously.
60 // NOTE: we rely on this synchronous behavior as per the comment in63 // NOTE: we rely on this synchronous behavior as per the comment in
61 // mf::SessionMediator::create_surface64 // mf::SessionMediator::create_surface
62 ba::write(*socket, ba::buffer(whole_message));65 try
66 {
67 ba::write(*socket, ba::buffer(whole_message));
68 }
69 catch (std::exception &ex)
70 {
71 report->error(ex);
72 }
63}73}
6474
65void mfd::SocketMessenger::send_fds(std::vector<int32_t> const& fds)75void mfd::SocketMessenger::send_fds(std::vector<int32_t> const& fds)
6676
=== modified file 'src/server/frontend/socket_messenger.h'
--- src/server/frontend/socket_messenger.h 2013-08-28 03:41:48 +0000
+++ src/server/frontend/socket_messenger.h 2013-09-23 14:32:39 +0000
@@ -26,13 +26,16 @@
26{26{
27namespace frontend27namespace frontend
28{28{
29class CommunicatorReport;
30
29namespace detail31namespace detail
30{32{
31class SocketMessenger : public MessageSender,33class SocketMessenger : public MessageSender,
32 public MessageReceiver34 public MessageReceiver
33{35{
34public:36public:
35 SocketMessenger(std::shared_ptr<boost::asio::local::stream_protocol::socket> const& socket);37 SocketMessenger(std::shared_ptr<boost::asio::local::stream_protocol::socket> const& socket,
38 std::shared_ptr<frontend::CommunicatorReport> const& report);
3639
37 void send(std::string const& body);40 void send(std::string const& body);
38 void send_fds(std::vector<int32_t> const& fds);41 void send_fds(std::vector<int32_t> const& fds);
@@ -42,6 +45,8 @@
4245
43private:46private:
44 std::shared_ptr<boost::asio::local::stream_protocol::socket> socket;47 std::shared_ptr<boost::asio::local::stream_protocol::socket> socket;
48 std::shared_ptr<CommunicatorReport> const& report;
49
45 std::vector<char> whole_message;50 std::vector<char> whole_message;
46};51};
47}52}
4853
=== modified file 'src/server/shell/application_session.cpp'
--- src/server/shell/application_session.cpp 2013-08-28 03:41:48 +0000
+++ src/server/shell/application_session.cpp 2013-09-23 14:32:39 +0000
@@ -21,6 +21,7 @@
21#include "mir/shell/surface_factory.h"21#include "mir/shell/surface_factory.h"
22#include "mir/shell/snapshot_strategy.h"22#include "mir/shell/snapshot_strategy.h"
23#include "mir/shell/session_listener.h"23#include "mir/shell/session_listener.h"
24#include "mir/shell/input_targeter.h"
24#include "mir/frontend/event_sink.h"25#include "mir/frontend/event_sink.h"
2526
26#include <boost/throw_exception.hpp>27#include <boost/throw_exception.hpp>
@@ -99,16 +100,21 @@
99 snapshot_strategy->take_snapshot_of(default_surface(), snapshot_taken);100 snapshot_strategy->take_snapshot_of(default_surface(), snapshot_taken);
100}101}
101102
102std::shared_ptr<msh::Surface> msh::ApplicationSession::default_surface() const103std::shared_ptr<msh::Surface> msh::ApplicationSession::default_surface_locked(std::unique_lock<std::mutex> const& /* lock */) const
103{104{
104 std::unique_lock<std::mutex> lock(surfaces_mutex);
105
106 if (surfaces.size())105 if (surfaces.size())
107 return surfaces.begin()->second;106 return surfaces.begin()->second;
108 else107 else
109 return std::shared_ptr<msh::Surface>();108 return std::shared_ptr<msh::Surface>();
110}109}
111110
111std::shared_ptr<msh::Surface> msh::ApplicationSession::default_surface() const
112{
113 std::unique_lock<std::mutex> lock(surfaces_mutex);
114
115 return default_surface_locked(lock);
116}
117
112void msh::ApplicationSession::destroy_surface(mf::SurfaceId id)118void msh::ApplicationSession::destroy_surface(mf::SurfaceId id)
113{119{
114 std::unique_lock<std::mutex> lock(surfaces_mutex);120 std::unique_lock<std::mutex> lock(surfaces_mutex);
@@ -171,3 +177,32 @@
171{177{
172 event_sink->handle_lifecycle_event(state);178 event_sink->handle_lifecycle_event(state);
173}179}
180
181void msh::ApplicationSession::receive_focus(std::shared_ptr<msh::InputTargeter> const& targeter,
182 std::shared_ptr<SurfaceController> const& controller)
183{
184 std::unique_lock<std::mutex> lock(surfaces_mutex);
185 if (surfaces.size() == 0)
186 {
187 targeter->focus_cleared();
188 return;
189 }
190 // Use default_surface_locked idiom instead
191 auto focus_surface = surfaces.begin()->second;
192
193 focus_surface->raise(controller);
194 focus_surface->take_input_focus(targeter);
195 focus_surface->configure(mir_surface_attrib_focus, mir_surface_focused);
196
197 last_focused_surface = focus_surface;
198}
199
200void msh::ApplicationSession::relinquish_focus()
201{
202 std::unique_lock<std::mutex> lock(surfaces_mutex);
203 auto surf = default_surface_locked(lock);
204 if (surf)
205 {
206 surf->configure(mir_surface_attrib_focus, mir_surface_unfocused);
207 }
208}
174209
=== modified file 'src/server/shell/default_focus_mechanism.cpp'
--- src/server/shell/default_focus_mechanism.cpp 2013-08-28 03:41:48 +0000
+++ src/server/shell/default_focus_mechanism.cpp 2013-09-23 14:32:39 +0000
@@ -35,28 +35,20 @@
3535
36void msh::DefaultFocusMechanism::set_focus_to(std::shared_ptr<Session> const& focus_session)36void msh::DefaultFocusMechanism::set_focus_to(std::shared_ptr<Session> const& focus_session)
37{37{
38 std::lock_guard<std::mutex> lg(focus_lock);
39
40 auto last_session = currently_focused_session.lock();
41 if (last_session)
42 {
43 last_session->relinquish_focus();
44 }
45
38 // TODO: This path should be encapsulated in a seperate clear_focus message46 // TODO: This path should be encapsulated in a seperate clear_focus message
39 if (!focus_session)47 if (!focus_session)
40 {48 {
41 input_targeter->focus_cleared();49 input_targeter->focus_cleared();
42 return;50 return;
43 }51 }
44 52 focus_session->receive_focus(input_targeter, surface_controller);
45 auto surface = focus_session->default_surface();53 currently_focused_session = focus_session;
46 if (surface)
47 {
48 std::lock_guard<std::mutex> lg(surface_focus_lock);
49 auto current_focus = currently_focused_surface.lock();
50 if (current_focus)
51 current_focus->configure(mir_surface_attrib_focus, mir_surface_unfocused);
52 surface->configure(mir_surface_attrib_focus, mir_surface_focused);
53 currently_focused_surface = surface;
54
55 surface->raise(surface_controller);
56 surface->take_input_focus(input_targeter);
57 }
58 else
59 {
60 input_targeter->focus_cleared();
61 }
62}54}
6355
=== modified file 'tests/unit-tests/frontend/CMakeLists.txt'
--- tests/unit-tests/frontend/CMakeLists.txt 2013-08-28 03:41:48 +0000
+++ tests/unit-tests/frontend/CMakeLists.txt 2013-09-23 14:32:39 +0000
@@ -8,6 +8,7 @@
8 ${CMAKE_CURRENT_SOURCE_DIR}/test_resource_cache.cpp8 ${CMAKE_CURRENT_SOURCE_DIR}/test_resource_cache.cpp
9 ${CMAKE_CURRENT_SOURCE_DIR}/test_session_mediator.cpp9 ${CMAKE_CURRENT_SOURCE_DIR}/test_session_mediator.cpp
10 ${CMAKE_CURRENT_SOURCE_DIR}/test_socket_session.cpp10 ${CMAKE_CURRENT_SOURCE_DIR}/test_socket_session.cpp
11 ${CMAKE_CURRENT_SOURCE_DIR}/test_socket_messenger.cpp
11 ${CMAKE_CURRENT_SOURCE_DIR}/test_event_sender.cpp12 ${CMAKE_CURRENT_SOURCE_DIR}/test_event_sender.cpp
12 ${CMAKE_CURRENT_SOURCE_DIR}/test_global_event_sender.cpp13 ${CMAKE_CURRENT_SOURCE_DIR}/test_global_event_sender.cpp
13)14)
1415
=== added file 'tests/unit-tests/frontend/test_socket_messenger.cpp'
--- tests/unit-tests/frontend/test_socket_messenger.cpp 1970-01-01 00:00:00 +0000
+++ tests/unit-tests/frontend/test_socket_messenger.cpp 2013-09-23 14:32:39 +0000
@@ -0,0 +1,37 @@
1/*
2 * Copyright © 2013 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 3 as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by: Daniel van Vugt <daniel.van.vugt@canonical.com>
17 */
18
19#include "mir/frontend/communicator_report.h"
20#include "src/server/frontend/socket_messenger.h"
21
22#include <gmock/gmock.h>
23#include <gtest/gtest.h>
24
25namespace mf = mir::frontend;
26
27using namespace mf::detail;
28using namespace boost::asio;
29
30TEST(SocketMessengerTest, write_failures_never_throw)
31{
32 io_service svc;
33 auto sock = std::make_shared<local::stream_protocol::socket>(svc);
34 SocketMessenger mess(sock, std::make_shared<mf::NullCommunicatorReport>());
35
36 EXPECT_NO_THROW( mess.send("foo") );
37}
038
=== modified file 'tests/unit-tests/shell/test_default_focus_mechanism.cpp'
--- tests/unit-tests/shell/test_default_focus_mechanism.cpp 2013-08-28 03:41:48 +0000
+++ tests/unit-tests/shell/test_default_focus_mechanism.cpp 2013-09-23 14:32:39 +0000
@@ -47,80 +47,34 @@
47namespace mt = mir::test;47namespace mt = mir::test;
48namespace mtd = mir::test::doubles;48namespace mtd = mir::test::doubles;
4949
50TEST(DefaultFocusMechanism, raises_default_surface)50TEST(DefaultFocusMechanism, hands_focus_to_session)
51{51{
52 using namespace ::testing;52 using namespace ::testing;
53 53
54 NiceMock<mtd::MockShellSession> app1;54 mtd::MockShellSession app1;
55 mtd::MockSurface mock_surface(&app1, std::make_shared<mtd::StubSurfaceBuilder>());55 EXPECT_CALL(app1, receive_focus(_, _)).Times(1);
56 {56
57 InSequence seq;57 msh::DefaultFocusMechanism focus_mechanism(std::make_shared<mtd::StubInputTargeter>(), std::make_shared<mtd::StubSurfaceController>());
58 EXPECT_CALL(app1, default_surface()).Times(1)58
59 .WillOnce(Return(mt::fake_shared(mock_surface)));59 focus_mechanism.set_focus_to(mt::fake_shared(app1));
60 }60}
6161
62 auto controller = std::make_shared<mtd::StubSurfaceController>();62TEST(DefaultFocusMechanism, relinquishes_focus_from_last_session)
63 EXPECT_CALL(mock_surface, raise(Eq(controller))).Times(1);63{
64 mtd::StubInputTargeter targeter;64 using namespace ::testing;
65 msh::DefaultFocusMechanism focus_mechanism(mt::fake_shared(targeter), controller);65
66 66 auto app1 = std::make_shared<mtd::MockShellSession>();
67 focus_mechanism.set_focus_to(mt::fake_shared(app1));67 auto app2 = std::make_shared<mtd::MockShellSession>();
68}68
6969 {
70TEST(DefaultFocusMechanism, mechanism_notifies_default_surface_of_focus_changes)70 InSequence seq;
71{71 EXPECT_CALL(*app1, receive_focus(_, _)).Times(1);
72 using namespace ::testing;72 EXPECT_CALL(*app1, relinquish_focus()).Times(1);
7373 EXPECT_CALL(*app2, receive_focus(_, _)).Times(1);
74 NiceMock<mtd::MockShellSession> app1, app2;74 }
75 mtd::MockSurface mock_surface1(&app1, std::make_shared<mtd::StubSurfaceBuilder>());75
76 mtd::MockSurface mock_surface2(&app2, std::make_shared<mtd::StubSurfaceBuilder>());76 msh::DefaultFocusMechanism focus_mechanism(std::make_shared<mtd::StubInputTargeter>(), std::make_shared<mtd::StubSurfaceController>());
77 77
78 ON_CALL(app1, default_surface()).WillByDefault(Return(mt::fake_shared(mock_surface1)));78 focus_mechanism.set_focus_to(app1);
79 ON_CALL(app2, default_surface()).WillByDefault(Return(mt::fake_shared(mock_surface2)));79 focus_mechanism.set_focus_to(app2);
80
81
82 {
83 InSequence seq;
84 EXPECT_CALL(mock_surface1, configure(mir_surface_attrib_focus, mir_surface_focused)).Times(1);
85 EXPECT_CALL(mock_surface1, configure(mir_surface_attrib_focus, mir_surface_unfocused)).Times(1);
86 EXPECT_CALL(mock_surface2, configure(mir_surface_attrib_focus, mir_surface_focused)).Times(1);
87 }
88
89 msh::DefaultFocusMechanism focus_mechanism(std::make_shared<mtd::StubInputTargeter>(),
90 std::make_shared<mtd::StubSurfaceController>());
91
92 focus_mechanism.set_focus_to(mt::fake_shared(app1));
93 focus_mechanism.set_focus_to(mt::fake_shared(app2));
94}
95
96TEST(DefaultFocusMechanism, sets_input_focus)
97{
98 using namespace ::testing;
99
100 NiceMock<mtd::MockShellSession> app1;
101 mtd::MockSurface mock_surface(&app1, std::make_shared<mtd::StubSurfaceBuilder>());
102 {
103 InSequence seq;
104 EXPECT_CALL(app1, default_surface()).Times(1)
105 .WillOnce(Return(mt::fake_shared(mock_surface)));
106 EXPECT_CALL(app1, default_surface()).Times(1)
107 .WillOnce(Return(std::shared_ptr<msh::Surface>()));
108 }
109
110 mtd::MockInputTargeter targeter;
111
112 msh::DefaultFocusMechanism focus_mechanism(mt::fake_shared(targeter), std::make_shared<mtd::StubSurfaceController>());
113
114 {
115 InSequence seq;
116 EXPECT_CALL(mock_surface, take_input_focus(_)).Times(1);
117 // When we have no default surface.
118 EXPECT_CALL(targeter, focus_cleared()).Times(1);
119 // When we have no session.
120 EXPECT_CALL(targeter, focus_cleared()).Times(1);
121 }
122
123 focus_mechanism.set_focus_to(mt::fake_shared(app1));
124 focus_mechanism.set_focus_to(mt::fake_shared(app1));
125 focus_mechanism.set_focus_to(std::shared_ptr<msh::Session>());
126}80}

Subscribers

People subscribed via source and target branches