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
1=== added file 'include/server/mir/server.h'
2--- include/server/mir/server.h 1970-01-01 00:00:00 +0000
3+++ include/server/mir/server.h 2014-10-15 09:19:21 +0000
4@@ -0,0 +1,217 @@
5+/*
6+ * Copyright © 2014 Canonical Ltd.
7+ *
8+ * This program is free software: you can redistribute it and/or modify it
9+ * under the terms of the GNU General Public License version 3,
10+ * as published by the Free Software Foundation.
11+ *
12+ * This program is distributed in the hope that it will be useful,
13+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
14+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+ * GNU General Public License for more details.
16+ *
17+ * You should have received a copy of the GNU General Public License
18+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
19+ *
20+ * Authored By: Alan Griffiths <alan@octopull.co.uk>
21+ */
22+
23+#ifndef MIR_SERVER_H_
24+#define MIR_SERVER_H_
25+
26+#include <functional>
27+#include <memory>
28+
29+namespace mir
30+{
31+namespace compositor { class Compositor; }
32+namespace frontend { class SessionAuthorizer; }
33+namespace graphics { class Platform; class Display; class GLConfig; }
34+namespace input { class CompositeEventFilter; class InputDispatcher; class CursorListener; }
35+namespace options { class Option; }
36+namespace shell { class FocusSetter; class DisplayLayout; }
37+namespace scene
38+{
39+class PlacementStrategy;
40+class SessionListener;
41+class PromptSessionListener;
42+class SurfaceConfigurator;
43+class SessionCoordinator;
44+class SurfaceCoordinator;
45+}
46+
47+class MainLoop;
48+class ServerStatusListener;
49+
50+enum class OptionType
51+{
52+ null,
53+ integer,
54+ string
55+};
56+
57+/// Customise and run a Mir server.
58+class Server
59+{
60+public:
61+ Server();
62+
63+/** @name Essential operations
64+ * These are the commands used to run and stop.
65+ * @{ */
66+ /// set the command line (this must remain valid while run() is called)
67+ void set_command_line(int argc, char const* argv[]);
68+
69+ /// Run the Mir server until it exits
70+ void run();
71+
72+ /// Tell the Mir server to exit
73+ void stop();
74+
75+ /// returns true if and only if server exited normally. Otherwise false.
76+ bool exited_normally();
77+/** @} */
78+
79+/** @name Configuration options
80+ * @{ */
81+ /// Add user configuration option(s) to Mir's option handling.
82+ /// These will be resolved during initialisation from the command line,
83+ /// environment variables, a config file or the supplied default.
84+ void add_configuration_option(
85+ std::string const& option,
86+ std::string const& description,
87+ int default_value);
88+
89+ /// Add user configuration option(s) to Mir's option handling.
90+ /// These will be resolved during initialisation from the command line,
91+ /// environment variables, a config file or the supplied default.
92+ void add_configuration_option(
93+ std::string const& option,
94+ std::string const& description,
95+ std::string const& default_value);
96+
97+ /// Add user configuration option(s) to Mir's option handling.
98+ /// These will be resolved during initialisation from the command line,
99+ /// environment variables, a config file or the supplied default.
100+ void add_configuration_option(
101+ std::string const& option,
102+ std::string const& description,
103+ OptionType type);
104+
105+ /// Set a handler for any command line options Mir does not recognise.
106+ /// This will be invoked if any unrecognised options are found during initialisation.
107+ /// Any unrecognised arguments are passed to this function. The pointers remain valid
108+ /// for the duration of the call only.
109+ /// If set_command_line_handler is not called the default action is to exit by
110+ /// throwing mir::AbnormalExit (which will be handled by the exception handler prior to
111+ /// exiting run().
112+ void set_command_line_handler(
113+ std::function<void(int argc, char const* const* argv)> const& command_line_hander);
114+
115+ /// Returns the configuration options.
116+ /// This will be null before initialization completes. It will be available
117+ /// when the init_callback has been invoked (and thereafter until the server exits).
118+ auto get_options() const -> std::shared_ptr<options::Option>;
119+/** @} */
120+
121+/** @name Using hooks into the run() logic
122+ * @{ */
123+ /// Add a callback to be invoked when the server has been initialized,
124+ /// but before it starts. This allows client code to get access Mir objects.
125+ /// If multiple callbacks are added they will be invoked in the sequence added.
126+ void add_init_callback(std::function<void()> const& init_callback);
127+
128+ /// Set a handler for exceptions. This is invoked in a catch (...) block and
129+ /// the exception can be re-thrown to retrieve type information.
130+ /// The default action is to call mir::report_exception(std::cerr)
131+ void set_exception_handler(std::function<void()> const& exception_handler);
132+/** @} */
133+
134+/** @name Getting access to Mir subsystems
135+ * These will throw before initialization starts or after the server exits.
136+ * They may be invoked by the functors that provide alternative implementations of
137+ * Mir subsystems and when the init_callback is invoked (and thereafter
138+ * until the server exits).
139+ * @{ */
140+ /// \return the composite event filter.
141+ auto the_composite_event_filter() const -> std::shared_ptr<input::CompositeEventFilter>;
142+
143+ /// \return the cursor listener.
144+ auto the_cursor_listener() const -> std::shared_ptr<input::CursorListener>;
145+
146+ /// \return the graphics display.
147+ auto the_display() const -> std::shared_ptr<graphics::Display>;
148+
149+ /// \return the graphics platform.
150+ auto the_graphics_platform() const -> std::shared_ptr<graphics::Platform>;
151+
152+ /// \return the main loop.
153+ auto the_main_loop() const -> std::shared_ptr<MainLoop>;
154+
155+ /// \return the prompt session listener.
156+ auto the_prompt_session_listener() const -> std::shared_ptr<scene::PromptSessionListener>;
157+
158+ /// \return the session authorizer.
159+ auto the_session_authorizer() const -> std::shared_ptr<frontend::SessionAuthorizer>;
160+
161+ /// \return the session listener.
162+ auto the_session_listener() const -> std::shared_ptr<scene::SessionListener>;
163+
164+ /// \return the display layout.
165+ auto the_shell_display_layout() const -> std::shared_ptr<shell::DisplayLayout>;
166+
167+ /// \return the surface configurator.
168+ auto the_surface_configurator() const -> std::shared_ptr<scene::SurfaceConfigurator>;
169+/** @} */
170+
171+/** @name Providing custom implementation
172+ * Provide alternative implementations of Mir subsystems: the functors will be invoked during initialization
173+ * (this is only useful before initialization starts).
174+ * @{ */
175+ /// Sets an override functor for creating the compositor.
176+ void override_the_compositor(std::function<std::shared_ptr<compositor::Compositor>()> const& compositor_builder);
177+
178+ /// Sets an override functor for creating the cursor listener.
179+ void override_the_cursor_listener(std::function<std::shared_ptr<input::CursorListener>()> const& cursor_listener_builder);
180+
181+ /// Sets an override functor for creating the gl config.
182+ void override_the_gl_config(std::function<std::shared_ptr<graphics::GLConfig>()> const& gl_config_builder);
183+
184+ /// Sets an override functor for creating the input dispatcher.
185+ void override_the_input_dispatcher(std::function<std::shared_ptr<input::InputDispatcher>()> const& input_dispatcher_builder);
186+
187+ /// Sets an override functor for creating the placement strategy.
188+ void override_the_placement_strategy(std::function<std::shared_ptr<scene::PlacementStrategy>()> const& placement_strategy_builder);
189+
190+ /// Sets an override functor for creating the prompt session listener.
191+ void override_the_prompt_session_listener(std::function<std::shared_ptr<scene::PromptSessionListener>()> const& prompt_session_listener_builder);
192+
193+ /// Sets an override functor for creating the status listener.
194+ void override_the_server_status_listener(std::function<std::shared_ptr<ServerStatusListener>()> const& server_status_listener_builder);
195+
196+ /// Sets an override functor for creating the session authorizer.
197+ void override_the_session_authorizer(std::function<std::shared_ptr<frontend::SessionAuthorizer>()> const& session_authorizer_builder);
198+
199+ /// Sets an override functor for creating the session listener.
200+ void override_the_session_listener(std::function<std::shared_ptr<scene::SessionListener>()> const& session_listener_builder);
201+
202+ /// Sets an override functor for creating the shell focus setter.
203+ void override_the_shell_focus_setter(std::function<std::shared_ptr<shell::FocusSetter>()> const& focus_setter_builder);
204+
205+ /// Sets an override functor for creating the surface configurator.
206+ void override_the_surface_configurator(std::function<std::shared_ptr<scene::SurfaceConfigurator>()> const& surface_configurator_builder);
207+
208+ /// Sets a wrapper functor for creating the session coordinator.
209+ void wrap_session_coordinator(std::function<std::shared_ptr<scene::SessionCoordinator>(std::shared_ptr<scene::SessionCoordinator> const& wrapped)> const& wrapper);
210+
211+ /// Sets a wrapper functor for creating the surface coordinator.
212+ void wrap_surface_coordinator(std::function<std::shared_ptr<scene::SurfaceCoordinator>(std::shared_ptr<scene::SurfaceCoordinator> const& wrapped)> const& wrapper);
213+/** @} */
214+
215+private:
216+ struct ServerConfiguration;
217+ struct Self;
218+ std::shared_ptr<Self> const self;
219+};
220+}
221+#endif /* SERVER_H_ */
222
223=== modified file 'server-ABI-sha1sums'
224--- server-ABI-sha1sums 2014-10-14 17:55:14 +0000
225+++ server-ABI-sha1sums 2014-10-15 09:19:21 +0000
226@@ -95,6 +95,7 @@
227 993e9f458ffc4288d304413f3fa0b1dcc95a093d include/server/mir/scene/surface_observer.h
228 7ef3e99901168cda296d74d05a979f47bf9c3ff1 include/server/mir/server_action_queue.h
229 8d83a51c278b8b71866d2178d9b6387c1f91a7d0 include/server/mir/server_configuration.h
230+5d79d4a973b597d7cc1de766bd0ef3d30b389e18 include/server/mir/server.h
231 86098b500339bfccd07a9bed8298f75a68b18f5c include/server/mir/server_status_listener.h
232 860c04f32b60e680140148dc9dc2295de145b9c1 include/server/mir/shell/display_layout.h
233 6a2107b01feae13060d5c305804906e53c52e0be include/server/mir/shell/focus_controller.h
234
235=== modified file 'src/server/CMakeLists.txt'
236--- src/server/CMakeLists.txt 2014-10-10 05:44:12 +0000
237+++ src/server/CMakeLists.txt 2014-10-15 09:19:21 +0000
238@@ -32,6 +32,7 @@
239 default_server_configuration.cpp
240 asio_main_loop.cpp
241 default_emergency_cleanup.cpp
242+ server.cpp
243 )
244
245 set(MIR_SERVER_OBJECTS
246
247=== added file 'src/server/server.cpp'
248--- src/server/server.cpp 1970-01-01 00:00:00 +0000
249+++ src/server/server.cpp 2014-10-15 09:19:21 +0000
250@@ -0,0 +1,373 @@
251+/*
252+ * Copyright © 2014 Canonical Ltd.
253+ *
254+ * This program is free software: you can redistribute it and/or modify it
255+ * under the terms of the GNU General Public License version 3,
256+ * as published by the Free Software Foundation.
257+ *
258+ * This program is distributed in the hope that it will be useful,
259+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
260+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
261+ * GNU General Public License for more details.
262+ *
263+ * You should have received a copy of the GNU General Public License
264+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
265+ *
266+ * Authored By: Alan Griffiths <alan@octopull.co.uk>
267+ */
268+
269+#include "mir/server.h"
270+
271+#include "mir/options/default_configuration.h"
272+#include "mir/default_server_configuration.h"
273+#include "mir/main_loop.h"
274+#include "mir/report_exception.h"
275+#include "mir/run_mir.h"
276+
277+#include <iostream>
278+
279+namespace mo = mir::options;
280+
281+#define FOREACH_WRAPPER(MACRO)\
282+ MACRO(session_coordinator)\
283+ MACRO(surface_coordinator)
284+
285+#define FOREACH_OVERRIDE(MACRO)\
286+ MACRO(compositor)\
287+ MACRO(cursor_listener)\
288+ MACRO(gl_config)\
289+ MACRO(input_dispatcher)\
290+ MACRO(placement_strategy)\
291+ MACRO(prompt_session_listener)\
292+ MACRO(server_status_listener)\
293+ MACRO(session_authorizer)\
294+ MACRO(session_listener)\
295+ MACRO(shell_focus_setter)\
296+ MACRO(surface_configurator)
297+
298+#define FOREACH_ACCESSOR(MACRO)\
299+ MACRO(the_composite_event_filter)\
300+ MACRO(the_display)\
301+ MACRO(the_graphics_platform)\
302+ MACRO(the_main_loop)\
303+ MACRO(the_prompt_session_listener)\
304+ MACRO(the_session_authorizer)\
305+ MACRO(the_session_listener)\
306+ MACRO(the_shell_display_layout)\
307+ MACRO(the_surface_configurator)
308+
309+#define MIR_SERVER_BUILDER(name)\
310+ std::function<std::result_of<decltype(&mir::DefaultServerConfiguration::the_##name)(mir::DefaultServerConfiguration*)>::type()> name##_builder;
311+
312+#define MIR_SERVER_WRAPPER(name)\
313+ std::function<std::result_of<decltype(&mir::DefaultServerConfiguration::the_##name)(mir::DefaultServerConfiguration*)>::type\
314+ (std::result_of<decltype(&mir::DefaultServerConfiguration::the_##name)(mir::DefaultServerConfiguration*)>::type const&)> name##_wrapper;
315+
316+struct mir::Server::Self
317+{
318+ bool exit_status{false};
319+ std::weak_ptr<options::Option> options;
320+ ServerConfiguration* server_config{nullptr};
321+
322+ std::function<void()> init_callback{[]{}};
323+ int argc{0};
324+ char const** argv{nullptr};
325+ std::function<void()> exception_handler{};
326+
327+ std::function<void(int argc, char const* const* argv)> command_line_hander{};
328+
329+ /// set a callback to introduce additional configuration options.
330+ /// this will be invoked by run() before server initialisation starts
331+ void set_add_configuration_options(
332+ std::function<void(options::DefaultConfiguration& config)> const& add_configuration_options);
333+
334+ std::function<void(options::DefaultConfiguration& config)> add_configuration_options{
335+ [](options::DefaultConfiguration&){}};
336+
337+ FOREACH_OVERRIDE(MIR_SERVER_BUILDER)
338+
339+ FOREACH_WRAPPER(MIR_SERVER_WRAPPER)
340+};
341+
342+#undef MIR_SERVER_BUILDER
343+#undef MIR_SERVER_WRAPPER
344+
345+#define MIR_SERVER_CONFIG_OVERRIDE(name)\
346+auto the_##name()\
347+-> decltype(mir::DefaultServerConfiguration::the_##name()) override\
348+{\
349+ if (self->name##_builder)\
350+ return name(\
351+ [this] { return self->name##_builder(); });\
352+\
353+ return mir::DefaultServerConfiguration::the_##name();\
354+}
355+
356+#define MIR_SERVER_CONFIG_WRAP(name)\
357+auto wrap_##name(decltype(Self::name##_wrapper)::result_type const& wrapped)\
358+-> decltype(mir::DefaultServerConfiguration::wrap_##name({})) override\
359+{\
360+ if (self->name##_wrapper)\
361+ return name(\
362+ [&] { return self->name##_wrapper(wrapped); });\
363+\
364+ return mir::DefaultServerConfiguration::wrap_##name(wrapped);\
365+}
366+
367+struct mir::Server::ServerConfiguration : mir::DefaultServerConfiguration
368+{
369+ ServerConfiguration(
370+ std::shared_ptr<options::Configuration> const& configuration_options,
371+ std::shared_ptr<Self> const self) :
372+ DefaultServerConfiguration(configuration_options),
373+ self(self)
374+ {
375+ }
376+
377+ using mir::DefaultServerConfiguration::the_options;
378+
379+ // TODO the MIR_SERVER_CONFIG_OVERRIDE macro expects a CachePtr named
380+ // TODO "placement_strategy" not "shell_placement_strategy".
381+ // Unfortunately, "shell_placement_strategy" is currently part of our
382+ // published API and used by qtmir: we cannot just rename it to remove
383+ // this ugliness. (Yet.)
384+ decltype(shell_placement_strategy)& placement_strategy = shell_placement_strategy;
385+
386+ FOREACH_OVERRIDE(MIR_SERVER_CONFIG_OVERRIDE)
387+
388+ FOREACH_WRAPPER(MIR_SERVER_CONFIG_WRAP)
389+
390+ std::shared_ptr<Self> const self;
391+};
392+
393+#undef MIR_SERVER_CONFIG_OVERRIDE
394+#undef MIR_SERVER_CONFIG_WRAP
395+
396+namespace
397+{
398+std::shared_ptr<mo::DefaultConfiguration> configuration_options(
399+ int argc,
400+ char const** argv,
401+ std::function<void(int argc, char const* const* argv)> const& command_line_hander)
402+{
403+ if (command_line_hander)
404+ return std::make_shared<mo::DefaultConfiguration>(argc, argv, command_line_hander);
405+ else
406+ return std::make_shared<mo::DefaultConfiguration>(argc, argv);
407+
408+}
409+}
410+
411+mir::Server::Server() :
412+ self(std::make_shared<Self>())
413+{
414+}
415+
416+void mir::Server::Self::set_add_configuration_options(
417+ std::function<void(mo::DefaultConfiguration& config)> const& add_configuration_options)
418+{
419+ this->add_configuration_options = add_configuration_options;
420+}
421+
422+
423+void mir::Server::set_command_line(int argc, char const* argv[])
424+{
425+ self->argc = argc;
426+ self->argv = argv;
427+}
428+
429+void mir::Server::add_init_callback(std::function<void()> const& init_callback)
430+{
431+ auto const& existing = self->init_callback;
432+
433+ auto const updated = [=]
434+ {
435+ existing();
436+ init_callback();
437+ };
438+
439+ self->init_callback = updated;
440+}
441+
442+auto mir::Server::get_options() const -> std::shared_ptr<options::Option>
443+{
444+ return self->options.lock();
445+}
446+
447+void mir::Server::set_exception_handler(std::function<void()> const& exception_handler)
448+{
449+ self->exception_handler = exception_handler;
450+}
451+
452+void mir::Server::run()
453+try
454+{
455+ auto const options = configuration_options(self->argc, self->argv, self->command_line_hander);
456+
457+ self->add_configuration_options(*options);
458+
459+ ServerConfiguration config{options, self};
460+
461+ self->server_config = &config;
462+
463+ self->options = config.the_options();
464+
465+ run_mir(config, [&](DisplayServer&)
466+ {
467+ self->init_callback();
468+ });
469+
470+ self->exit_status = true;
471+ self->server_config = nullptr;
472+}
473+catch (...)
474+{
475+ self->server_config = nullptr;
476+
477+ if (self->exception_handler)
478+ self->exception_handler();
479+ else
480+ mir::report_exception(std::cerr);
481+}
482+
483+void mir::Server::stop()
484+{
485+ if (auto const main_loop = the_main_loop())
486+ main_loop->stop();
487+}
488+
489+bool mir::Server::exited_normally()
490+{
491+ return self->exit_status;
492+}
493+
494+namespace
495+{
496+auto const no_config_to_access = "Cannot access config when no config active.";
497+}
498+
499+#define MIR_SERVER_ACCESSOR(name)\
500+auto mir::Server::name() const -> decltype(self->server_config->name())\
501+{\
502+ if (self->server_config) return self->server_config->name();\
503+ BOOST_THROW_EXCEPTION(std::logic_error(no_config_to_access));\
504+}
505+
506+FOREACH_ACCESSOR(MIR_SERVER_ACCESSOR)
507+
508+#undef MIR_SERVER_ACCESSOR
509+
510+#define MIR_SERVER_OVERRIDE(name)\
511+void mir::Server::override_the_##name(decltype(Self::name##_builder) const& value)\
512+{\
513+ self->name##_builder = value;\
514+}
515+
516+FOREACH_OVERRIDE(MIR_SERVER_OVERRIDE)
517+
518+#undef MIR_SERVER_OVERRIDE
519+
520+#define MIR_SERVER_WRAP(name)\
521+void mir::Server::wrap_##name(decltype(Self::name##_wrapper) const& value)\
522+{\
523+ self->name##_wrapper = value;\
524+}
525+
526+FOREACH_WRAPPER(MIR_SERVER_WRAP)
527+
528+#undef MIR_SERVER_WRAP
529+
530+void mir::Server::add_configuration_option(
531+ std::string const& option,
532+ std::string const& description,
533+ int default_)
534+{
535+ namespace po = boost::program_options;
536+
537+ auto const& existing = self->add_configuration_options;
538+
539+ auto const option_adder = [=](options::DefaultConfiguration& config)
540+ {
541+ existing(config);
542+
543+ config.add_options()
544+ (option.c_str(), po::value<int>()->default_value(default_), description.c_str());
545+ };
546+
547+ self->set_add_configuration_options(option_adder);
548+}
549+
550+void mir::Server::add_configuration_option(
551+ std::string const& option,
552+ std::string const& description,
553+ std::string const& default_)
554+{
555+ namespace po = boost::program_options;
556+
557+ auto const& existing = self->add_configuration_options;
558+
559+ auto const option_adder = [=](options::DefaultConfiguration& config)
560+ {
561+ existing(config);
562+
563+ config.add_options()
564+ (option.c_str(), po::value<std::string>()->default_value(default_), description.c_str());
565+ };
566+
567+ self->set_add_configuration_options(option_adder);
568+}
569+
570+void mir::Server::add_configuration_option(
571+ std::string const& option,
572+ std::string const& description,
573+ OptionType type)
574+{
575+ namespace po = boost::program_options;
576+
577+ auto const& existing = self->add_configuration_options;
578+
579+ switch (type)
580+ {
581+ case OptionType::null:
582+ {
583+ auto const option_adder = [=](options::DefaultConfiguration& config)
584+ {
585+ existing(config);
586+
587+ config.add_options()
588+ (option.c_str(), description.c_str());
589+ };
590+
591+ self->set_add_configuration_options(option_adder);
592+ }
593+ break;
594+
595+ case OptionType::integer:
596+ {
597+ auto const option_adder = [=](options::DefaultConfiguration& config)
598+ {
599+ existing(config);
600+
601+ config.add_options()
602+ (option.c_str(), po::value<int>(), description.c_str());
603+ };
604+
605+ self->set_add_configuration_options(option_adder);
606+ }
607+ break;
608+
609+ case OptionType::string:
610+ {
611+ auto const option_adder = [=](options::DefaultConfiguration& config)
612+ {
613+ existing(config);
614+
615+ config.add_options()
616+ (option.c_str(), po::value<std::string>(), description.c_str());
617+ };
618+
619+ self->set_add_configuration_options(option_adder);
620+ }
621+ break;
622+ }
623+}
624
625=== modified file 'src/server/symbols.map'
626--- src/server/symbols.map 2014-10-14 17:55:14 +0000
627+++ src/server/symbols.map 2014-10-15 09:19:21 +0000
628@@ -375,6 +375,7 @@
629 mir::ServerActionQueue::resume_processing_for*;
630 mir::ServerActionQueue::?ServerActionQueue*;
631 mir::ServerActionQueue::ServerActionQueue*;
632+ mir::Server::add_configuration_option*;
633 mir::ServerConfiguration::operator*;
634 mir::ServerConfiguration::?ServerConfiguration*;
635 mir::ServerConfiguration::ServerConfiguration*;
636@@ -390,12 +391,45 @@
637 mir::ServerConfiguration::the_main_loop*;
638 mir::ServerConfiguration::the_prompt_connector*;
639 mir::ServerConfiguration::the_server_status_listener*;
640+ mir::Server::add_init_callback*;
641+ mir::Server::exited_normally*;
642+ mir::Server::get_options*;
643+ mir::Server::override_the_compositor*;
644+ mir::Server::override_the_cursor_listener*;
645+ mir::Server::override_the_gl_config*;
646+ mir::Server::override_the_input_dispatcher*;
647+ mir::Server::override_the_placement_strategy*;
648+ mir::Server::override_the_prompt_session_listener*;
649+ mir::Server::override_the_server_status_listener*;
650+ mir::Server::override_the_session_authorizer*;
651+ mir::Server::override_the_session_listener*;
652+ mir::Server::override_the_shell_focus_setter*;
653+ mir::Server::override_the_surface_configurator*;
654+ mir::Server::run*;
655+ mir::Server::Server*;
656+ mir::Server::set_command_line*;
657+ mir::Server::set_command_line_hander*;
658+ mir::Server::set_exception_handler*;
659 mir::ServerStatusListener::operator*;
660 mir::ServerStatusListener::paused*;
661 mir::ServerStatusListener::resumed*;
662 mir::ServerStatusListener::?ServerStatusListener*;
663 mir::ServerStatusListener::ServerStatusListener*;
664 mir::ServerStatusListener::started*;
665+ mir::Server::stop*;
666+ mir::Server::the_composite_event_filter*;
667+ mir::Server::the_cursor_listener*;
668+ mir::Server::the_display*;
669+ mir::Server::the_graphics_platform*;
670+ mir::Server::the_main_loop*;
671+ mir::Server::the_prompt_session_listener*;
672+ mir::Server::the_server_status_listener*;
673+ mir::Server::the_session_authorizer*;
674+ mir::Server::the_session_listener*;
675+ mir::Server::the_shell_display_layout*;
676+ mir::Server::the_surface_configurator*;
677+ mir::Server::wrap_session_coordinator*;
678+ mir::Server::wrap_surface_coordinator*;
679 mir::shell::DisplayLayout::clip_to_output*;
680 mir::shell::DisplayLayout::?DisplayLayout*;
681 mir::shell::DisplayLayout::DisplayLayout*;
682@@ -592,6 +626,7 @@
683 typeinfo?for?mir::compositor::Scene;
684 typeinfo?for?mir::compositor::SceneElement;
685 typeinfo?for?mir::DefaultServerConfiguration;
686+ typeinfo?for?mir::detail::ServerAddConfigurationOptions;
687 typeinfo?for?mir::DisplayServer;
688 typeinfo?for?mir::EmergencyCleanup;
689 typeinfo?for?mir::frontend::DisplayChanger;
690@@ -633,6 +668,7 @@
691 typeinfo?for?mir::scene::SurfaceCoordinator;
692 typeinfo?for?mir::scene::SurfaceCreationParameters;
693 typeinfo?for?mir::scene::SurfaceObserver;
694+ typeinfo?for?mir::Server;
695 typeinfo?for?mir::ServerActionQueue;
696 typeinfo?for?mir::ServerConfiguration;
697 typeinfo?for?mir::ServerStatusListener;
698@@ -649,6 +685,7 @@
699 vtable?for?mir::compositor::Scene;
700 vtable?for?mir::compositor::SceneElement;
701 vtable?for?mir::DefaultServerConfiguration;
702+ vtable?for?mir::detail::ServerAddConfigurationOptions;
703 vtable?for?mir::DisplayServer;
704 vtable?for?mir::EmergencyCleanup;
705 vtable?for?mir::frontend::DisplayChanger;
706@@ -690,6 +727,7 @@
707 vtable?for?mir::scene::SurfaceCoordinator;
708 vtable?for?mir::scene::SurfaceCreationParameters;
709 vtable?for?mir::scene::SurfaceObserver;
710+ vtable?for?mir::Server;
711 vtable?for?mir::ServerActionQueue;
712 vtable?for?mir::ServerConfiguration;
713 vtable?for?mir::ServerStatusListener;

Subscribers

People subscribed via source and target branches