Mir

Merge lp:~alan-griffiths/mir/a-simpler-server-setup into lp:mir

Proposed by Alan Griffiths
Status: Merged
Approved by: Alan Griffiths
Approved revision: no longer in the source branch.
Merged at revision: 1984
Proposed branch: lp:~alan-griffiths/mir/a-simpler-server-setup
Merge into: lp:mir
Diff against target: 713 lines (+630/-0)
5 files modified
include/server/mir/server.h (+217/-0)
server-ABI-sha1sums (+1/-0)
src/server/CMakeLists.txt (+1/-0)
src/server/server.cpp (+373/-0)
src/server/symbols.map (+38/-0)
To merge this branch: bzr merge lp:~alan-griffiths/mir/a-simpler-server-setup
Reviewer Review Type Date Requested Status
Kevin DuBois (community) Approve
PS Jenkins bot (community) continuous-integration Approve
Alexandros Frantzis (community) Approve
Cemil Azizoglu (community) Needs Fixing
Andreas Pokorny (community) Approve
Review via email: mp+237990@code.launchpad.net

Commit message

mir: A simpler to use (and easier to maintain) way to customise and run a Mir server

Description of the change

mir: A simpler to use (and easier to maintain) way to customise and run a Mir server

The idea is to provide a declarative API for setting up the server that doesn't tie the client code into DefautServerConfiguration or another equally volatile interface.

Functions can be added to mir::Server without breaking backward API as they are non-virtual.

If clients are able to use an interface like this we can move DefaultServerConfiguration (and a bunch of other stuff) out of the public API/ABI.

This is extracted from lp:~alan-griffiths/mir/spike-a-simpler-server-setup/+merge/237625 by dropping the experimental changes to examples used as a proof-of-concept.

I'd like to land this and then work through the examples and acceptance tests to ensure they are implementable in terms of this interface. (Doing this as a single MP would be hard to review.)

NOTE: there is an alternative proposal, please consider both approaches when voting:

   https://code.launchpad.net/~andreas-pokorny/mir/abi-stable-server-configuration-with-type_info/+merge/238144

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
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

Rebuilding (third time lucky?)

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Alexandros Frantzis (afrantzis) wrote :

65 +

Extra blank line.

219 + bool exit_status{false};
220 + std::weak_ptr<options::Option> options;
222 + ServerConfiguration* server_config{nullptr};

Since ABI break protection is a major concern, we should hide all of these in 'Self'.

Nit (non-blocking):

227 +class detail::ServerAddConfigurationOptions

As mentioned in the past, I am not fond of this mechanism, but if people find it more convenient...

review: Needs Fixing
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Andreas Pokorny (andreas-pokorny) wrote :

the header checksums contain additional files probably left overs from merges?

review: Needs Fixing
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
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 :

Oh, a Server class like I've been asking for for almost two years :D

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Alexandros Frantzis (afrantzis) wrote :

218 + struct ServerConfiguration;

Do we need this?

513 + self->server_config = nullptr;

Indentation (tab instead of spaces)

523 + std::cerr << "DEBUG: " << __PRETTY_FUNCTION__ << std::endl;

Not needed.

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

Two more things:

Whats the thought behind writing {*this} instead of just *this?
I think:

523 + std::cerr << "DEBUG: " << __PRETTY_FUNCTION__ << std::endl;

and iostream is not needed anymore?

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

> Two more things:
>
> Whats the thought behind writing {*this} instead of just *this?

We're constructing a helper object (which as the constructor isn't tagged explicit could be done the way you suggest).

> I think:
>
> 523 + std::cerr << "DEBUG: " << __PRETTY_FUNCTION__ << std::endl;

Done

> and iostream is not needed anymore?

std::cerr is used: "mir::report_exception(std::cerr);"

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

> > Two more things:
> >
> > Whats the thought behind writing {*this} instead of just *this?
>
> We're constructing a helper object (which as the constructor isn't tagged
> explicit could be done the way you suggest).

ok, my gcc didnt complain about - maybe clang would.

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

> > > Two more things:
> > >
> > > Whats the thought behind writing {*this} instead of just *this?
> >
> > We're constructing a helper object (which as the constructor isn't tagged
> > explicit could be done the way you suggest).
>
> ok, my gcc didnt complain about - maybe clang would.

misunderstood what you just said. interesting syntax idea to indicate the conversion in the return statement.

review: Approve
Revision history for this message
Kevin DuBois (kdub) wrote :

So I guess I favor this MP over the alternative, mostly because this one is more straightforward to reason (from a user's perspective) about what is available for use.

In light of the proposed plan, the following is more of a comment; but I'm concerned that we're exposing too much of our internal composition scheduling with the functions that remain exposed. (It would be good for mir's ease-of-use to be able to reuse MultiThreadedCompositor)

nits:
#1
31 +namespace compositor{ class Compositor; }
spacing

#2
148 + /// \return the graphics display options.
151 + /// \return the graphics platform options.
In light of the other mentions of 'options' in this header, we should drop 'options' off the end of these comments

#3
detail::ServerAddConfigurationOptions
AdditionalConfigurationOptions or NonstandardConfigurationOptions seems like a stronger name.

#4
OptionType::null seems more like OptionType::bool to me.

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

> 218 + struct ServerConfiguration;
> Do we need this?

What I meant was: do we need for this to be a private mir::Server struct instead of a only a struct inside server.cpp ? Doesn't affect ABI either way, but there is no point exposing the type at all either.

208 + void override_the_surface_configurator(std::function<std::shared_ptr<scene::SurfaceConfigurator>()> const& surface_configurator_builder);
209 +
210 + /// Sets a wrapper functor for creating the session coordinator.
211 + void wrap_session_coordinator(std::function<std::shared_ptr<scene::SessionCoordinator>(std::shared_ptr<scene::SessionCoordinator> const& wrapped)> const& wrapper);

Lines are too long and there is too much repetition, so I think the code would benefit from function types for the parameters, e.g.:

template<typename T> using Builder = std::function<std::shared_ptr<T>()>;
template<typename T> using Wrapper = std::function<std::shared_ptr<T>(std::shared_ptr<T> const&)>;

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

> #3
> detail::ServerAddConfigurationOptions
> AdditionalConfigurationOptions or NonstandardConfigurationOptions seems like a
> stronger name.

Or I could just drop the chaining functionality this supports.

Any opinions? (I know Alexandros would drop it>)

> #4
> OptionType::null seems more like OptionType::bool to me.

Not so. This is a flag that exists or not, not one that takes [true|false]

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

> > 218 + struct ServerConfiguration;
> > Do we need this?
>
> What I meant was: do we need for this to be a private mir::Server struct
> instead of a only a struct inside server.cpp ? Doesn't affect ABI either way,
> but there is no point exposing the type at all either.

It isn't obvious, but either Self needs to be a public type or there needs to be a way of giving ServerConfiguration access to it.

> 208 + void override_the_surface_configurator(std::function<std::shared_ptr
> <scene::SurfaceConfigurator>()> const& surface_configurator_builder);
> 209 +
> 210 + /// Sets a wrapper functor for creating the session coordinator.
> 211 + void wrap_session_coordinator(std::function<std::shared_ptr<scene::S
> essionCoordinator>(std::shared_ptr<scene::SessionCoordinator> const& wrapped)>
> const& wrapper);
>
> Lines are too long and there is too much repetition, so I think the code would
> benefit from function types for the parameters, e.g.:
>
> template<typename T> using Builder = std::function<std::shared_ptr<T>()>;
> template<typename T> using Wrapper =
> std::function<std::shared_ptr<T>(std::shared_ptr<T> const&)>;

This would make the declarations more concise.

But it makes it harder for the user see the type they need to supply as a parameter.

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

> nits:
> #1
> 31 +namespace compositor{ class Compositor; }
> spacing
>
> #2
> 148 + /// \return the graphics display options.
> 151 + /// \return the graphics platform options.
> In light of the other mentions of 'options' in this header, we should drop
> 'options' off the end of these comments

fixed

Revision history for this message
Cemil Azizoglu (cemil-azizoglu) wrote :

1. Should we reserve a buffer zone after accessors, overrides, and wrappers for future expansion? Otherwise we'll likely have interleaved accessors/overrides/wrappers areas.

2. No tests?

3.
s/hander/handler
111 + /// If set_command_line_hander is not called the default action is to exit by
114 + void set_command_line_hander(
115 + std::function<void(int argc, char const* const* argv)> const& command_line_hander);
365 + std::function<void(int argc, char const* const* argv)> command_line_hander{};
439 + std::function<void(int argc, char const* const* argv)> const& command_line_hander)
441 + if (command_line_hander)
442 + return std::make_shared<mo::DefaultConfiguration>(argc, argv, command_line_hander);
493 + auto const options = configuration_options(self->argc, self->argv, self->command_line_hander);
701 + mir::Server::set_command_line_hander*;

4.
s/add/Add
s/an/a
125 + /// add an callback to be invoked when the server has been initialized,

5.
s/set/Set
107 + /// set a handler for any command line options Mir does not recognise.

6.
66 + * These are the commands used to start and stop.
Based on this comment, to be consistent, should 'run' be named 'start'?
71 + /// Run the Mir server until it exits
72 + void run();

review: Needs Fixing
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Alexandros Frantzis (afrantzis) wrote :

> It isn't obvious, but either Self needs to be a public type or there needs to be a
> way of giving ServerConfiguration access to it.

Ah, indeed.

> This would make the declarations more concise.
> But it makes it harder for the user see the type they need to supply as a parameter.

Perhaps the first couple times the user will have to look up the type definition (which isn't hard since it will be in the same code block). But subsequently the user will read, e.g., "WrapperFunction<Type>" and just know what's expected, instead of having to mentally reparse the long parameter type every time.

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

> 1. Should we reserve a buffer zone after accessors, overrides, and wrappers
> for future expansion? Otherwise we'll likely have interleaved
> accessors/overrides/wrappers areas.

A buffer zone where? These are non-virtual functions.

> 2. No tests?

True. If you can think of an effective way to test that the system gets configured & run correctly then I'd be delighted to add them.

In practice, this will get exercised properly when the acceptance tests get migrated to this interface. (Which is on my TODO list.)

> 3.
> s/hander/handler
> 111 + /// If set_command_line_hander is not called the default action
> is to exit by
> 114 + void set_command_line_hander(
> 115 + std::function<void(int argc, char const* const* argv)> const&
> command_line_hander);
> 365 + std::function<void(int argc, char const* const* argv)>
> command_line_hander{};
> 439 + std::function<void(int argc, char const* const* argv)> const&
> command_line_hander)
> 441 + if (command_line_hander)
> 442 + return std::make_shared<mo::DefaultConfiguration>(argc, argv,
> command_line_hander);
> 493 + auto const options = configuration_options(self->argc,
> self->argv, self->command_line_hander);
> 701 + mir::Server::set_command_line_hander*;

Fixed

> 4.
> s/add/Add
> s/an/a
> 125 + /// add an callback to be invoked when the server has been
> initialized,

Fixed

> 5.
> s/set/Set
> 107 + /// set a handler for any command line options Mir does not
> recognise.

Fixed.

> 6.
> 66 + * These are the commands used to start and stop.
> Based on this comment, to be consistent, should 'run' be named 'start'?
> 71 + /// Run the Mir server until it exits
> 72 + void run();

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

> > This would make the declarations more concise.
> > But it makes it harder for the user see the type they need to supply as a
> parameter.
>
> Perhaps the first couple times the user will have to look up the type
> definition (which isn't hard since it will be in the same code block). But
> subsequently the user will read, e.g., "WrapperFunction<Type>" and just know
> what's expected, instead of having to mentally reparse the long parameter type
> every time.

The first couple of times are the "barrier to entry" - after that it doesn't matter which way we write them as the user knows what to expect and doesn't read the parameter type.

It is *very* important to make adopting Mir as easy as possible.

Practically, can we land with this spelling and I'll MP your suggestion on top of that for discussion? (It isn't an API/ABI change.)

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

> 227 +class detail::ServerAddConfigurationOptions
>
> As mentioned in the past, I am not fond of this mechanism, but if people find
> it more convenient...

dropped

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

> The first couple of times are the "barrier to entry" - after that it doesn't matter
> which way we write them as the user knows what to expect and doesn't read the parameter type.

We may be consistent, but we should make this explicit and easily discoverable. Users can't really be sure that the signature is the same without re-reading the (long and not easily parsable) parameter type.

> It is *very* important to make adopting Mir as easy as possible.

I doubt that this is a barrier to adoption. If we think that target developers can't bother to find a definition in the same code block they are currently looking at, then we should surely get rid of "detail::ServerAddConfigurationOptions" and "auto get_options() const -> std::shared_ptr<options::Option>" and "enum class OptionType"...

> Practically, can we land with this spelling and I'll MP your suggestion on

No problem.

review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Kevin DuBois (kdub) wrote :

okay, looks good to me

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== added file 'include/server/mir/server.h'
--- include/server/mir/server.h 1970-01-01 00:00:00 +0000
+++ include/server/mir/server.h 2014-10-15 09:19:21 +0000
@@ -0,0 +1,217 @@
1/*
2 * Copyright © 2014 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3,
6 * as 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: Alan Griffiths <alan@octopull.co.uk>
17 */
18
19#ifndef MIR_SERVER_H_
20#define MIR_SERVER_H_
21
22#include <functional>
23#include <memory>
24
25namespace mir
26{
27namespace compositor { class Compositor; }
28namespace frontend { class SessionAuthorizer; }
29namespace graphics { class Platform; class Display; class GLConfig; }
30namespace input { class CompositeEventFilter; class InputDispatcher; class CursorListener; }
31namespace options { class Option; }
32namespace shell { class FocusSetter; class DisplayLayout; }
33namespace scene
34{
35class PlacementStrategy;
36class SessionListener;
37class PromptSessionListener;
38class SurfaceConfigurator;
39class SessionCoordinator;
40class SurfaceCoordinator;
41}
42
43class MainLoop;
44class ServerStatusListener;
45
46enum class OptionType
47{
48 null,
49 integer,
50 string
51};
52
53/// Customise and run a Mir server.
54class Server
55{
56public:
57 Server();
58
59/** @name Essential operations
60 * These are the commands used to run and stop.
61 * @{ */
62 /// set the command line (this must remain valid while run() is called)
63 void set_command_line(int argc, char const* argv[]);
64
65 /// Run the Mir server until it exits
66 void run();
67
68 /// Tell the Mir server to exit
69 void stop();
70
71 /// returns true if and only if server exited normally. Otherwise false.
72 bool exited_normally();
73/** @} */
74
75/** @name Configuration options
76 * @{ */
77 /// Add user configuration option(s) to Mir's option handling.
78 /// These will be resolved during initialisation from the command line,
79 /// environment variables, a config file or the supplied default.
80 void add_configuration_option(
81 std::string const& option,
82 std::string const& description,
83 int default_value);
84
85 /// Add user configuration option(s) to Mir's option handling.
86 /// These will be resolved during initialisation from the command line,
87 /// environment variables, a config file or the supplied default.
88 void add_configuration_option(
89 std::string const& option,
90 std::string const& description,
91 std::string const& default_value);
92
93 /// Add user configuration option(s) to Mir's option handling.
94 /// These will be resolved during initialisation from the command line,
95 /// environment variables, a config file or the supplied default.
96 void add_configuration_option(
97 std::string const& option,
98 std::string const& description,
99 OptionType type);
100
101 /// Set a handler for any command line options Mir does not recognise.
102 /// This will be invoked if any unrecognised options are found during initialisation.
103 /// Any unrecognised arguments are passed to this function. The pointers remain valid
104 /// for the duration of the call only.
105 /// If set_command_line_handler is not called the default action is to exit by
106 /// throwing mir::AbnormalExit (which will be handled by the exception handler prior to
107 /// exiting run().
108 void set_command_line_handler(
109 std::function<void(int argc, char const* const* argv)> const& command_line_hander);
110
111 /// Returns the configuration options.
112 /// This will be null before initialization completes. It will be available
113 /// when the init_callback has been invoked (and thereafter until the server exits).
114 auto get_options() const -> std::shared_ptr<options::Option>;
115/** @} */
116
117/** @name Using hooks into the run() logic
118 * @{ */
119 /// Add a callback to be invoked when the server has been initialized,
120 /// but before it starts. This allows client code to get access Mir objects.
121 /// If multiple callbacks are added they will be invoked in the sequence added.
122 void add_init_callback(std::function<void()> const& init_callback);
123
124 /// Set a handler for exceptions. This is invoked in a catch (...) block and
125 /// the exception can be re-thrown to retrieve type information.
126 /// The default action is to call mir::report_exception(std::cerr)
127 void set_exception_handler(std::function<void()> const& exception_handler);
128/** @} */
129
130/** @name Getting access to Mir subsystems
131 * These will throw before initialization starts or after the server exits.
132 * They may be invoked by the functors that provide alternative implementations of
133 * Mir subsystems and when the init_callback is invoked (and thereafter
134 * until the server exits).
135 * @{ */
136 /// \return the composite event filter.
137 auto the_composite_event_filter() const -> std::shared_ptr<input::CompositeEventFilter>;
138
139 /// \return the cursor listener.
140 auto the_cursor_listener() const -> std::shared_ptr<input::CursorListener>;
141
142 /// \return the graphics display.
143 auto the_display() const -> std::shared_ptr<graphics::Display>;
144
145 /// \return the graphics platform.
146 auto the_graphics_platform() const -> std::shared_ptr<graphics::Platform>;
147
148 /// \return the main loop.
149 auto the_main_loop() const -> std::shared_ptr<MainLoop>;
150
151 /// \return the prompt session listener.
152 auto the_prompt_session_listener() const -> std::shared_ptr<scene::PromptSessionListener>;
153
154 /// \return the session authorizer.
155 auto the_session_authorizer() const -> std::shared_ptr<frontend::SessionAuthorizer>;
156
157 /// \return the session listener.
158 auto the_session_listener() const -> std::shared_ptr<scene::SessionListener>;
159
160 /// \return the display layout.
161 auto the_shell_display_layout() const -> std::shared_ptr<shell::DisplayLayout>;
162
163 /// \return the surface configurator.
164 auto the_surface_configurator() const -> std::shared_ptr<scene::SurfaceConfigurator>;
165/** @} */
166
167/** @name Providing custom implementation
168 * Provide alternative implementations of Mir subsystems: the functors will be invoked during initialization
169 * (this is only useful before initialization starts).
170 * @{ */
171 /// Sets an override functor for creating the compositor.
172 void override_the_compositor(std::function<std::shared_ptr<compositor::Compositor>()> const& compositor_builder);
173
174 /// Sets an override functor for creating the cursor listener.
175 void override_the_cursor_listener(std::function<std::shared_ptr<input::CursorListener>()> const& cursor_listener_builder);
176
177 /// Sets an override functor for creating the gl config.
178 void override_the_gl_config(std::function<std::shared_ptr<graphics::GLConfig>()> const& gl_config_builder);
179
180 /// Sets an override functor for creating the input dispatcher.
181 void override_the_input_dispatcher(std::function<std::shared_ptr<input::InputDispatcher>()> const& input_dispatcher_builder);
182
183 /// Sets an override functor for creating the placement strategy.
184 void override_the_placement_strategy(std::function<std::shared_ptr<scene::PlacementStrategy>()> const& placement_strategy_builder);
185
186 /// Sets an override functor for creating the prompt session listener.
187 void override_the_prompt_session_listener(std::function<std::shared_ptr<scene::PromptSessionListener>()> const& prompt_session_listener_builder);
188
189 /// Sets an override functor for creating the status listener.
190 void override_the_server_status_listener(std::function<std::shared_ptr<ServerStatusListener>()> const& server_status_listener_builder);
191
192 /// Sets an override functor for creating the session authorizer.
193 void override_the_session_authorizer(std::function<std::shared_ptr<frontend::SessionAuthorizer>()> const& session_authorizer_builder);
194
195 /// Sets an override functor for creating the session listener.
196 void override_the_session_listener(std::function<std::shared_ptr<scene::SessionListener>()> const& session_listener_builder);
197
198 /// Sets an override functor for creating the shell focus setter.
199 void override_the_shell_focus_setter(std::function<std::shared_ptr<shell::FocusSetter>()> const& focus_setter_builder);
200
201 /// Sets an override functor for creating the surface configurator.
202 void override_the_surface_configurator(std::function<std::shared_ptr<scene::SurfaceConfigurator>()> const& surface_configurator_builder);
203
204 /// Sets a wrapper functor for creating the session coordinator.
205 void wrap_session_coordinator(std::function<std::shared_ptr<scene::SessionCoordinator>(std::shared_ptr<scene::SessionCoordinator> const& wrapped)> const& wrapper);
206
207 /// Sets a wrapper functor for creating the surface coordinator.
208 void wrap_surface_coordinator(std::function<std::shared_ptr<scene::SurfaceCoordinator>(std::shared_ptr<scene::SurfaceCoordinator> const& wrapped)> const& wrapper);
209/** @} */
210
211private:
212 struct ServerConfiguration;
213 struct Self;
214 std::shared_ptr<Self> const self;
215};
216}
217#endif /* SERVER_H_ */
0218
=== modified file 'server-ABI-sha1sums'
--- server-ABI-sha1sums 2014-10-14 17:55:14 +0000
+++ server-ABI-sha1sums 2014-10-15 09:19:21 +0000
@@ -95,6 +95,7 @@
95993e9f458ffc4288d304413f3fa0b1dcc95a093d include/server/mir/scene/surface_observer.h95993e9f458ffc4288d304413f3fa0b1dcc95a093d include/server/mir/scene/surface_observer.h
967ef3e99901168cda296d74d05a979f47bf9c3ff1 include/server/mir/server_action_queue.h967ef3e99901168cda296d74d05a979f47bf9c3ff1 include/server/mir/server_action_queue.h
978d83a51c278b8b71866d2178d9b6387c1f91a7d0 include/server/mir/server_configuration.h978d83a51c278b8b71866d2178d9b6387c1f91a7d0 include/server/mir/server_configuration.h
985d79d4a973b597d7cc1de766bd0ef3d30b389e18 include/server/mir/server.h
9886098b500339bfccd07a9bed8298f75a68b18f5c include/server/mir/server_status_listener.h9986098b500339bfccd07a9bed8298f75a68b18f5c include/server/mir/server_status_listener.h
99860c04f32b60e680140148dc9dc2295de145b9c1 include/server/mir/shell/display_layout.h100860c04f32b60e680140148dc9dc2295de145b9c1 include/server/mir/shell/display_layout.h
1006a2107b01feae13060d5c305804906e53c52e0be include/server/mir/shell/focus_controller.h1016a2107b01feae13060d5c305804906e53c52e0be include/server/mir/shell/focus_controller.h
101102
=== modified file 'src/server/CMakeLists.txt'
--- src/server/CMakeLists.txt 2014-10-10 05:44:12 +0000
+++ src/server/CMakeLists.txt 2014-10-15 09:19:21 +0000
@@ -32,6 +32,7 @@
32 default_server_configuration.cpp32 default_server_configuration.cpp
33 asio_main_loop.cpp33 asio_main_loop.cpp
34 default_emergency_cleanup.cpp34 default_emergency_cleanup.cpp
35 server.cpp
35)36)
3637
37set(MIR_SERVER_OBJECTS38set(MIR_SERVER_OBJECTS
3839
=== added file 'src/server/server.cpp'
--- src/server/server.cpp 1970-01-01 00:00:00 +0000
+++ src/server/server.cpp 2014-10-15 09:19:21 +0000
@@ -0,0 +1,373 @@
1/*
2 * Copyright © 2014 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3,
6 * as 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: Alan Griffiths <alan@octopull.co.uk>
17 */
18
19#include "mir/server.h"
20
21#include "mir/options/default_configuration.h"
22#include "mir/default_server_configuration.h"
23#include "mir/main_loop.h"
24#include "mir/report_exception.h"
25#include "mir/run_mir.h"
26
27#include <iostream>
28
29namespace mo = mir::options;
30
31#define FOREACH_WRAPPER(MACRO)\
32 MACRO(session_coordinator)\
33 MACRO(surface_coordinator)
34
35#define FOREACH_OVERRIDE(MACRO)\
36 MACRO(compositor)\
37 MACRO(cursor_listener)\
38 MACRO(gl_config)\
39 MACRO(input_dispatcher)\
40 MACRO(placement_strategy)\
41 MACRO(prompt_session_listener)\
42 MACRO(server_status_listener)\
43 MACRO(session_authorizer)\
44 MACRO(session_listener)\
45 MACRO(shell_focus_setter)\
46 MACRO(surface_configurator)
47
48#define FOREACH_ACCESSOR(MACRO)\
49 MACRO(the_composite_event_filter)\
50 MACRO(the_display)\
51 MACRO(the_graphics_platform)\
52 MACRO(the_main_loop)\
53 MACRO(the_prompt_session_listener)\
54 MACRO(the_session_authorizer)\
55 MACRO(the_session_listener)\
56 MACRO(the_shell_display_layout)\
57 MACRO(the_surface_configurator)
58
59#define MIR_SERVER_BUILDER(name)\
60 std::function<std::result_of<decltype(&mir::DefaultServerConfiguration::the_##name)(mir::DefaultServerConfiguration*)>::type()> name##_builder;
61
62#define MIR_SERVER_WRAPPER(name)\
63 std::function<std::result_of<decltype(&mir::DefaultServerConfiguration::the_##name)(mir::DefaultServerConfiguration*)>::type\
64 (std::result_of<decltype(&mir::DefaultServerConfiguration::the_##name)(mir::DefaultServerConfiguration*)>::type const&)> name##_wrapper;
65
66struct mir::Server::Self
67{
68 bool exit_status{false};
69 std::weak_ptr<options::Option> options;
70 ServerConfiguration* server_config{nullptr};
71
72 std::function<void()> init_callback{[]{}};
73 int argc{0};
74 char const** argv{nullptr};
75 std::function<void()> exception_handler{};
76
77 std::function<void(int argc, char const* const* argv)> command_line_hander{};
78
79 /// set a callback to introduce additional configuration options.
80 /// this will be invoked by run() before server initialisation starts
81 void set_add_configuration_options(
82 std::function<void(options::DefaultConfiguration& config)> const& add_configuration_options);
83
84 std::function<void(options::DefaultConfiguration& config)> add_configuration_options{
85 [](options::DefaultConfiguration&){}};
86
87 FOREACH_OVERRIDE(MIR_SERVER_BUILDER)
88
89 FOREACH_WRAPPER(MIR_SERVER_WRAPPER)
90};
91
92#undef MIR_SERVER_BUILDER
93#undef MIR_SERVER_WRAPPER
94
95#define MIR_SERVER_CONFIG_OVERRIDE(name)\
96auto the_##name()\
97-> decltype(mir::DefaultServerConfiguration::the_##name()) override\
98{\
99 if (self->name##_builder)\
100 return name(\
101 [this] { return self->name##_builder(); });\
102\
103 return mir::DefaultServerConfiguration::the_##name();\
104}
105
106#define MIR_SERVER_CONFIG_WRAP(name)\
107auto wrap_##name(decltype(Self::name##_wrapper)::result_type const& wrapped)\
108-> decltype(mir::DefaultServerConfiguration::wrap_##name({})) override\
109{\
110 if (self->name##_wrapper)\
111 return name(\
112 [&] { return self->name##_wrapper(wrapped); });\
113\
114 return mir::DefaultServerConfiguration::wrap_##name(wrapped);\
115}
116
117struct mir::Server::ServerConfiguration : mir::DefaultServerConfiguration
118{
119 ServerConfiguration(
120 std::shared_ptr<options::Configuration> const& configuration_options,
121 std::shared_ptr<Self> const self) :
122 DefaultServerConfiguration(configuration_options),
123 self(self)
124 {
125 }
126
127 using mir::DefaultServerConfiguration::the_options;
128
129 // TODO the MIR_SERVER_CONFIG_OVERRIDE macro expects a CachePtr named
130 // TODO "placement_strategy" not "shell_placement_strategy".
131 // Unfortunately, "shell_placement_strategy" is currently part of our
132 // published API and used by qtmir: we cannot just rename it to remove
133 // this ugliness. (Yet.)
134 decltype(shell_placement_strategy)& placement_strategy = shell_placement_strategy;
135
136 FOREACH_OVERRIDE(MIR_SERVER_CONFIG_OVERRIDE)
137
138 FOREACH_WRAPPER(MIR_SERVER_CONFIG_WRAP)
139
140 std::shared_ptr<Self> const self;
141};
142
143#undef MIR_SERVER_CONFIG_OVERRIDE
144#undef MIR_SERVER_CONFIG_WRAP
145
146namespace
147{
148std::shared_ptr<mo::DefaultConfiguration> configuration_options(
149 int argc,
150 char const** argv,
151 std::function<void(int argc, char const* const* argv)> const& command_line_hander)
152{
153 if (command_line_hander)
154 return std::make_shared<mo::DefaultConfiguration>(argc, argv, command_line_hander);
155 else
156 return std::make_shared<mo::DefaultConfiguration>(argc, argv);
157
158}
159}
160
161mir::Server::Server() :
162 self(std::make_shared<Self>())
163{
164}
165
166void mir::Server::Self::set_add_configuration_options(
167 std::function<void(mo::DefaultConfiguration& config)> const& add_configuration_options)
168{
169 this->add_configuration_options = add_configuration_options;
170}
171
172
173void mir::Server::set_command_line(int argc, char const* argv[])
174{
175 self->argc = argc;
176 self->argv = argv;
177}
178
179void mir::Server::add_init_callback(std::function<void()> const& init_callback)
180{
181 auto const& existing = self->init_callback;
182
183 auto const updated = [=]
184 {
185 existing();
186 init_callback();
187 };
188
189 self->init_callback = updated;
190}
191
192auto mir::Server::get_options() const -> std::shared_ptr<options::Option>
193{
194 return self->options.lock();
195}
196
197void mir::Server::set_exception_handler(std::function<void()> const& exception_handler)
198{
199 self->exception_handler = exception_handler;
200}
201
202void mir::Server::run()
203try
204{
205 auto const options = configuration_options(self->argc, self->argv, self->command_line_hander);
206
207 self->add_configuration_options(*options);
208
209 ServerConfiguration config{options, self};
210
211 self->server_config = &config;
212
213 self->options = config.the_options();
214
215 run_mir(config, [&](DisplayServer&)
216 {
217 self->init_callback();
218 });
219
220 self->exit_status = true;
221 self->server_config = nullptr;
222}
223catch (...)
224{
225 self->server_config = nullptr;
226
227 if (self->exception_handler)
228 self->exception_handler();
229 else
230 mir::report_exception(std::cerr);
231}
232
233void mir::Server::stop()
234{
235 if (auto const main_loop = the_main_loop())
236 main_loop->stop();
237}
238
239bool mir::Server::exited_normally()
240{
241 return self->exit_status;
242}
243
244namespace
245{
246auto const no_config_to_access = "Cannot access config when no config active.";
247}
248
249#define MIR_SERVER_ACCESSOR(name)\
250auto mir::Server::name() const -> decltype(self->server_config->name())\
251{\
252 if (self->server_config) return self->server_config->name();\
253 BOOST_THROW_EXCEPTION(std::logic_error(no_config_to_access));\
254}
255
256FOREACH_ACCESSOR(MIR_SERVER_ACCESSOR)
257
258#undef MIR_SERVER_ACCESSOR
259
260#define MIR_SERVER_OVERRIDE(name)\
261void mir::Server::override_the_##name(decltype(Self::name##_builder) const& value)\
262{\
263 self->name##_builder = value;\
264}
265
266FOREACH_OVERRIDE(MIR_SERVER_OVERRIDE)
267
268#undef MIR_SERVER_OVERRIDE
269
270#define MIR_SERVER_WRAP(name)\
271void mir::Server::wrap_##name(decltype(Self::name##_wrapper) const& value)\
272{\
273 self->name##_wrapper = value;\
274}
275
276FOREACH_WRAPPER(MIR_SERVER_WRAP)
277
278#undef MIR_SERVER_WRAP
279
280void mir::Server::add_configuration_option(
281 std::string const& option,
282 std::string const& description,
283 int default_)
284{
285 namespace po = boost::program_options;
286
287 auto const& existing = self->add_configuration_options;
288
289 auto const option_adder = [=](options::DefaultConfiguration& config)
290 {
291 existing(config);
292
293 config.add_options()
294 (option.c_str(), po::value<int>()->default_value(default_), description.c_str());
295 };
296
297 self->set_add_configuration_options(option_adder);
298}
299
300void mir::Server::add_configuration_option(
301 std::string const& option,
302 std::string const& description,
303 std::string const& default_)
304{
305 namespace po = boost::program_options;
306
307 auto const& existing = self->add_configuration_options;
308
309 auto const option_adder = [=](options::DefaultConfiguration& config)
310 {
311 existing(config);
312
313 config.add_options()
314 (option.c_str(), po::value<std::string>()->default_value(default_), description.c_str());
315 };
316
317 self->set_add_configuration_options(option_adder);
318}
319
320void mir::Server::add_configuration_option(
321 std::string const& option,
322 std::string const& description,
323 OptionType type)
324{
325 namespace po = boost::program_options;
326
327 auto const& existing = self->add_configuration_options;
328
329 switch (type)
330 {
331 case OptionType::null:
332 {
333 auto const option_adder = [=](options::DefaultConfiguration& config)
334 {
335 existing(config);
336
337 config.add_options()
338 (option.c_str(), description.c_str());
339 };
340
341 self->set_add_configuration_options(option_adder);
342 }
343 break;
344
345 case OptionType::integer:
346 {
347 auto const option_adder = [=](options::DefaultConfiguration& config)
348 {
349 existing(config);
350
351 config.add_options()
352 (option.c_str(), po::value<int>(), description.c_str());
353 };
354
355 self->set_add_configuration_options(option_adder);
356 }
357 break;
358
359 case OptionType::string:
360 {
361 auto const option_adder = [=](options::DefaultConfiguration& config)
362 {
363 existing(config);
364
365 config.add_options()
366 (option.c_str(), po::value<std::string>(), description.c_str());
367 };
368
369 self->set_add_configuration_options(option_adder);
370 }
371 break;
372 }
373}
0374
=== modified file 'src/server/symbols.map'
--- src/server/symbols.map 2014-10-14 17:55:14 +0000
+++ src/server/symbols.map 2014-10-15 09:19:21 +0000
@@ -375,6 +375,7 @@
375 mir::ServerActionQueue::resume_processing_for*;375 mir::ServerActionQueue::resume_processing_for*;
376 mir::ServerActionQueue::?ServerActionQueue*;376 mir::ServerActionQueue::?ServerActionQueue*;
377 mir::ServerActionQueue::ServerActionQueue*;377 mir::ServerActionQueue::ServerActionQueue*;
378 mir::Server::add_configuration_option*;
378 mir::ServerConfiguration::operator*;379 mir::ServerConfiguration::operator*;
379 mir::ServerConfiguration::?ServerConfiguration*;380 mir::ServerConfiguration::?ServerConfiguration*;
380 mir::ServerConfiguration::ServerConfiguration*;381 mir::ServerConfiguration::ServerConfiguration*;
@@ -390,12 +391,45 @@
390 mir::ServerConfiguration::the_main_loop*;391 mir::ServerConfiguration::the_main_loop*;
391 mir::ServerConfiguration::the_prompt_connector*;392 mir::ServerConfiguration::the_prompt_connector*;
392 mir::ServerConfiguration::the_server_status_listener*;393 mir::ServerConfiguration::the_server_status_listener*;
394 mir::Server::add_init_callback*;
395 mir::Server::exited_normally*;
396 mir::Server::get_options*;
397 mir::Server::override_the_compositor*;
398 mir::Server::override_the_cursor_listener*;
399 mir::Server::override_the_gl_config*;
400 mir::Server::override_the_input_dispatcher*;
401 mir::Server::override_the_placement_strategy*;
402 mir::Server::override_the_prompt_session_listener*;
403 mir::Server::override_the_server_status_listener*;
404 mir::Server::override_the_session_authorizer*;
405 mir::Server::override_the_session_listener*;
406 mir::Server::override_the_shell_focus_setter*;
407 mir::Server::override_the_surface_configurator*;
408 mir::Server::run*;
409 mir::Server::Server*;
410 mir::Server::set_command_line*;
411 mir::Server::set_command_line_hander*;
412 mir::Server::set_exception_handler*;
393 mir::ServerStatusListener::operator*;413 mir::ServerStatusListener::operator*;
394 mir::ServerStatusListener::paused*;414 mir::ServerStatusListener::paused*;
395 mir::ServerStatusListener::resumed*;415 mir::ServerStatusListener::resumed*;
396 mir::ServerStatusListener::?ServerStatusListener*;416 mir::ServerStatusListener::?ServerStatusListener*;
397 mir::ServerStatusListener::ServerStatusListener*;417 mir::ServerStatusListener::ServerStatusListener*;
398 mir::ServerStatusListener::started*;418 mir::ServerStatusListener::started*;
419 mir::Server::stop*;
420 mir::Server::the_composite_event_filter*;
421 mir::Server::the_cursor_listener*;
422 mir::Server::the_display*;
423 mir::Server::the_graphics_platform*;
424 mir::Server::the_main_loop*;
425 mir::Server::the_prompt_session_listener*;
426 mir::Server::the_server_status_listener*;
427 mir::Server::the_session_authorizer*;
428 mir::Server::the_session_listener*;
429 mir::Server::the_shell_display_layout*;
430 mir::Server::the_surface_configurator*;
431 mir::Server::wrap_session_coordinator*;
432 mir::Server::wrap_surface_coordinator*;
399 mir::shell::DisplayLayout::clip_to_output*;433 mir::shell::DisplayLayout::clip_to_output*;
400 mir::shell::DisplayLayout::?DisplayLayout*;434 mir::shell::DisplayLayout::?DisplayLayout*;
401 mir::shell::DisplayLayout::DisplayLayout*;435 mir::shell::DisplayLayout::DisplayLayout*;
@@ -592,6 +626,7 @@
592 typeinfo?for?mir::compositor::Scene;626 typeinfo?for?mir::compositor::Scene;
593 typeinfo?for?mir::compositor::SceneElement;627 typeinfo?for?mir::compositor::SceneElement;
594 typeinfo?for?mir::DefaultServerConfiguration;628 typeinfo?for?mir::DefaultServerConfiguration;
629 typeinfo?for?mir::detail::ServerAddConfigurationOptions;
595 typeinfo?for?mir::DisplayServer;630 typeinfo?for?mir::DisplayServer;
596 typeinfo?for?mir::EmergencyCleanup;631 typeinfo?for?mir::EmergencyCleanup;
597 typeinfo?for?mir::frontend::DisplayChanger;632 typeinfo?for?mir::frontend::DisplayChanger;
@@ -633,6 +668,7 @@
633 typeinfo?for?mir::scene::SurfaceCoordinator;668 typeinfo?for?mir::scene::SurfaceCoordinator;
634 typeinfo?for?mir::scene::SurfaceCreationParameters;669 typeinfo?for?mir::scene::SurfaceCreationParameters;
635 typeinfo?for?mir::scene::SurfaceObserver;670 typeinfo?for?mir::scene::SurfaceObserver;
671 typeinfo?for?mir::Server;
636 typeinfo?for?mir::ServerActionQueue;672 typeinfo?for?mir::ServerActionQueue;
637 typeinfo?for?mir::ServerConfiguration;673 typeinfo?for?mir::ServerConfiguration;
638 typeinfo?for?mir::ServerStatusListener;674 typeinfo?for?mir::ServerStatusListener;
@@ -649,6 +685,7 @@
649 vtable?for?mir::compositor::Scene;685 vtable?for?mir::compositor::Scene;
650 vtable?for?mir::compositor::SceneElement;686 vtable?for?mir::compositor::SceneElement;
651 vtable?for?mir::DefaultServerConfiguration;687 vtable?for?mir::DefaultServerConfiguration;
688 vtable?for?mir::detail::ServerAddConfigurationOptions;
652 vtable?for?mir::DisplayServer;689 vtable?for?mir::DisplayServer;
653 vtable?for?mir::EmergencyCleanup;690 vtable?for?mir::EmergencyCleanup;
654 vtable?for?mir::frontend::DisplayChanger;691 vtable?for?mir::frontend::DisplayChanger;
@@ -690,6 +727,7 @@
690 vtable?for?mir::scene::SurfaceCoordinator;727 vtable?for?mir::scene::SurfaceCoordinator;
691 vtable?for?mir::scene::SurfaceCreationParameters;728 vtable?for?mir::scene::SurfaceCreationParameters;
692 vtable?for?mir::scene::SurfaceObserver;729 vtable?for?mir::scene::SurfaceObserver;
730 vtable?for?mir::Server;
693 vtable?for?mir::ServerActionQueue;731 vtable?for?mir::ServerActionQueue;
694 vtable?for?mir::ServerConfiguration;732 vtable?for?mir::ServerConfiguration;
695 vtable?for?mir::ServerStatusListener;733 vtable?for?mir::ServerStatusListener;

Subscribers

People subscribed via source and target branches