Mir

Merge lp:~vanvugt/mir/surface-types into lp:~mir-team/mir/trunk

Proposed by Daniel van Vugt
Status: Superseded
Proposed branch: lp:~vanvugt/mir/surface-types
Merge into: lp:~mir-team/mir/trunk
Diff against target: 862 lines (+436/-1)
32 files modified
debian/control (+12/-0)
debian/mircommon-dev.install (+1/-0)
include/client/mir_toolkit/mir_client_library.h (+19/-0)
include/server/mir/frontend/application_mediator.h (+5/-0)
include/server/mir/frontend/application_mediator_report.h (+3/-0)
include/server/mir/logging/application_mediator_report.h (+2/-0)
include/server/mir/shell/application_session.h (+2/-0)
include/server/mir/shell/session.h (+3/-0)
include/server/mir/shell/surface.h (+3/-0)
include/server/mir/surfaces/surface.h (+6/-0)
include/shared/mir_toolkit/common.h (+49/-0)
include/test/mir_test_doubles/mock_session.h (+2/-0)
include/test/mir_test_doubles/mock_surface.h (+2/-0)
include/test/mir_test_doubles/stub_session.h (+4/-0)
src/client/mir_client_library.cpp (+22/-0)
src/client/mir_surface.cpp (+47/-0)
src/client/mir_surface.h (+11/-0)
src/server/frontend/application_mediator.cpp (+27/-0)
src/server/frontend/null_application_mediator_report.cpp (+4/-0)
src/server/frontend/protobuf_message_processor.cpp (+4/-0)
src/server/logging/application_mediator_report.cpp (+5/-0)
src/server/shell/application_session.cpp (+10/-0)
src/server/surfaces/proxy_surface.cpp (+31/-0)
src/server/surfaces/proxy_surface.h (+2/-0)
src/server/surfaces/surface.cpp (+22/-1)
src/shared/CMakeLists.txt (+10/-0)
src/shared/protobuf/mir_protobuf.proto (+10/-0)
tests/acceptance-tests/test_client_library.cpp (+74/-0)
tests/behavior-tests/session_management_context.cpp (+5/-0)
tests/integration-tests/cucumber/test_session_management_context.cpp (+2/-0)
tests/unit-tests/client/test_client_mir_surface.cpp (+19/-0)
tests/unit-tests/surfaces/test_surface.cpp (+18/-0)
To merge this branch: bzr merge lp:~vanvugt/mir/surface-types
Reviewer Review Type Date Requested Status
Alexandros Frantzis (community) Needs Information
PS Jenkins bot (community) continuous-integration Approve
Alan Griffiths Needs Fixing
Review via email: mp+153081@code.launchpad.net

This proposal has been superseded by a proposal from 2013-03-15.

Commit message

Add support for surface types (client API, protocol and server).

This work will also form the foundation of supporting surface states.

Description of the change

Resubmitted. This new version is much smaller, dropping about 500 lines and all mentions of "shell" which we could not agree on before.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

PASSED: Continuous integration, rev:554
http://jenkins.qa.ubuntu.com/job/mir-ci/69/
Executed test runs:
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-quantal-amd64-ci/70//console

Click here to trigger a rebuild:
http://jenkins.qa.ubuntu.com/job/mir-ci/69//rebuild/?

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

I don't think that surfaces::Surface needs configure(MirSurfaceAttrib attrib, int value) - AFICS attributes are a feature of shell::Surface. (And, as discussed elsewhere, surfaces::ProxySurface belongs in shell, possibly as shell::Window.)

~~~~

90 +

Trailing whitespace.

~~~~

216 === added file 'include/shared/mir/common.h'

This is not the place for parts of the toolkit API - this is for namespace mir

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

Is there a clear distinction between SurfaceSetting and SurfaceParameters? (And is it worth supplying SurfaceSetting to create_surface and avoiding a round-trip?)

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

the new surface type get/set for client api looks ok to me

The acceptance test takes quite a while on the galaxy nexus, perhaps it can be shortened by using less iterations in line 757?
[ RUN ] DefaultDisplayServerTestFixture.surface_types
[ OK ] DefaultDisplayServerTestFixture.surface_types (1384 ms)
(i see about 180ms on my desktop)

small nit but with
615 +int ms::Surface::configure(MirSurfaceAttrib attrib, int value)
the name 'configure' didn't make it obvious what is going on in the function.

Also with this function, (related to the comment in it) is the surface type something that mir cares about, or the shell? This is tricky to talk about without a 'shell api', but its still a bit hazy to me what our requirements for tracking the data that the shell cares about.

although the tests look good, they do have multiple testing expectations in them because they are long.

Revision history for this message
Daniel van Vugt (vanvugt) wrote :

Alan,

Extraneous "configure" methods:
I only added methods where I absolutely needed to, to make the code compile and run. However that was many revisions ago so I'll check to see if it's still required...

Trailing whitespace at line 90:
Will fix now.

216 === added file 'include/shared/mir/common.h'
"common.h" is not part of the "toolkit". It is used by the client toolkit and in the server.

SurfaceSetting vs SurfaceParameters
Yes they will always be different. SurfaceParameters are required information to create a surface. SurfaceSetting is something you might optionally change later; like type, state, hidden, width, height (most of which are not implemented yet but require this branch to land first).

Kevin,

Stress test takes too long:
I think 1.3 seconds is OK for a stress test, but I can shorten it if you really want.

"configure" is not self explanatory:
I kind of agree but have not yet thought of a better method name other than "set_attribute" (making the protocol call something like "set_surface_attribute"). I prefer "configure_surface". More suggestions?

Who cares about surface type?...
You're absolutely right that surface type is something only the shell will care about and act upon. However for consistency between different shells and avoiding duplication, it is reasonable for the server to store the type value in each server surface instance. Even though it will only be used by the shell. This will change as new attributes are added like "state" which will potentially be used by the server directly.

Test length:
Yes, I will always make code as concise as possible without hurting readability.

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 :

Minor fixes done.

Alan -
I can put "common.h" anywhere of course. Just remember:
  1. It's not part of the "toolkit". "toolkit" means client-only but "common.h" is also used in the server and shell.
  2. common.h has to be installed under "include/mir/..." to make it clear to external users that it's part of mir. And it is implicitly in the "mir" namespace by virtue of the "Mir" type prefixes. We can't use "namespace mir" however because it is C code, not C++.

Alan & Kevin -
I agree that "type" is not a deep server-level attribute. It only makes sense at the shell level. I could move it out of surfaces::Surface now, and into a proxy class. However I think that should be done later because the "Proxy" classes clearly need some refactoring, everyone seems to agree. I'd rather not make assumptions about what form that will take and move any members into *ProxySurface until that's done.

Also keep in mind that _most_ future configurable attributes (state, hidden, width, height etc) will be low-level and live in the server surfaces::Surface rather than the shell.

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 :

> Minor fixes done.
>
> Alan -
> I can put "common.h" anywhere of course. Just remember:
> 1. It's not part of the "toolkit". "toolkit" means client-only but
> "common.h" is also used in the server and shell.
> 2. common.h has to be installed under "include/mir/..." to make it clear to
> external users that it's part of mir. And it is implicitly in the "mir"
> namespace by virtue of the "Mir" type prefixes. We can't use "namespace mir"
> however because it is C code, not C++.

As it is included by toolkit I think it is part of toolkit. If it were really "part of mir", then there would be no reason for it to be C code. (Is it part of some hypothetical "common" that we've just identified - if so, is "common.h" isn't a good name.)

> Alan & Kevin -
> I agree that "type" is not a deep server-level attribute. It only makes sense
> at the shell level. I could move it out of surfaces::Surface now, and into a
> proxy class. However I think that should be done later because the "Proxy"
> classes clearly need some refactoring, everyone seems to agree. I'd rather not
> make assumptions about what form that will take and move any members into
> *ProxySurface until that's done.

Perhaps it is best to wait on that refactoring and reassess after that?

> Also keep in mind that _most_ future configurable attributes (state, hidden,
> width, height etc) will be low-level and live in the server surfaces::Surface
> rather than the shell.

Are you envisaging using the same mechanism?

Revision history for this message
Daniel van Vugt (vanvugt) wrote :

Absolutely, all attributes that can be changed after construction will use configure() eventually.

Please consider landing this branch before any ProxySurface refactoring. I am tired of fixing conflicts and refactoring it every day.

Revision history for this message
Daniel van Vugt (vanvugt) wrote :

Also, these arguments are blocking me from starting on two other deliverables which will depend on this work.

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

> Absolutely, all attributes that can be changed after construction will use
> configure() eventually.

Does that imply that e.g. you see resizing happening by setting the width and height in two configure calls? I'm not sure that is a good plan.

Why wouldn't there be a single resize(graphics::Size) call?

> Please consider landing this branch before any ProxySurface refactoring. I am
> tired of fixing conflicts and refactoring it every day.

I'm equally tired of reviewing it every day - there has to be a better way to communicate.

Revision history for this message
Daniel van Vugt (vanvugt) wrote :

Good point. Width/height are bad examples. But I will reuse configure() for surface states soon.

Revision history for this message
Daniel van Vugt (vanvugt) wrote :

I tried moving common.h to: include/shared/mir_toolkit/common.h
But that fails for reasons alluded to earlier. That is such common headers need to have the same relative path in the source tree as in the install tree. Because mir_client_library.h has to be able to find common.h in both situations.

Any suggestions?

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

> I tried moving common.h to: include/shared/mir_toolkit/common.h
> But that fails for reasons alluded to earlier. That is such common headers
> need to have the same relative path in the source tree as in the install tree.
> Because mir_client_library.h has to be able to find common.h in both
> situations.
>
> Any suggestions?

I guess this comes as part of the various problems with directory names.

IMO include/shared/mir_toolkit and include/client/mir_toolkit should be installed to <target>/mir_toolkit - and that would facilitate #include <mir_toolkit/common.h>

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

>
> I guess this comes as part of the various problems with directory names.
>
> IMO include/shared/mir_toolkit and include/client/mir_toolkit should be
> installed to <target>/mir_toolkit - and that would facilitate #include
> <mir_toolkit/common.h>

+1

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

== include/shared/mir vs include/shared/mir_toolkit ==

The concept is that whatever is under */mir_toolkit (and only that) will be part of the toolkit interface. Since a toolkit/client needs this, mir_toolkit is the way to go. Keep in mind that this is still under shared/.

So, this is how I see things currently:

1. server/*, client/*, shared/* => which mir components need to access the definitions in the file
2. */mir, */mir_toolkit => whether the definitions are internal to mir, or (also) exposed to the toolkit API

== surfaces::Surface::set_type(),type() ==

I agree that this doesn't belong there. I don't have a problem putting it there *temporarily* to unblock work, if the related surface refactorings aren't expected to be done soon.

== configure() ==

At the Surface level, and for the limited number of attributes I am aware of, I would prefer to have explicit calls : app_session->set_surface_state(id, ...) or app_session->surface(id)->set_state(...) (since we are already exposing the surface) etc

At the RPC level: one approach is to use configure(attrib, value), another is to have <attrib>(value) calls. A third approach (not neccessarily preferable for this use case, just mentioning it for completeness) is to have, e.g.:

message SurfaceSettings {
    optional SurfaceId surfaceid = 1;
    optional int32 type = 2;
    optional int32 state = 3;
    optional bool visible = 4;
    ...
}

The frontend could then act depending on which values are actually included in the message. This method allows the client to set and retrieve all of the settings in one go.

For the number of attributes and the use cases I am aware of, my preference would be once again to be explicit, and have separate calls <attrib>().

Marking as "Needs information" => "Needs discussion"

review: Needs Information
Revision history for this message
Daniel van Vugt (vanvugt) wrote :

I thought it was implicit that having two different top-level include directories:
  <mir/foo>
  <mir_toolkit/bar>
was obviously a bad idea. I thought that was obvious but clearly it's just my opinion now. I think eventually everything should be under "mir/" for consistency:
  <mir/foo>
  <mir/toolkit/bar>
But that's a cleanup for a another day and a different proposal.

Alexandros:
configure() needs to be generic because there are so many layers of classes in the Mir code, it does not scale to add a new function for every attribute at every layer. When I added configure() I was surprised at how many classes I had to modify. It becomes unmaintainable and excessively over-complicated if you have to do that again and again for each new attribute. Consider also reporting -- we don't want to change every type of report to add new methods to those every time a new attribute is added.
Also, we should not assume to have designed all the required attributes any time soon. New attributes will be added and some even removed over time. We don't want to go changing the protocol and half a dozen foundational classes each time.

Revision history for this message
Daniel van Vugt (vanvugt) wrote :

I've now been working on this branch for a month and it's been under review for two weeks. It has worked perfectly without bugs for the entire duration. Remember we're only arguing about style issues that can be fixed later.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'debian/control'
2--- debian/control 2013-03-12 03:50:42 +0000
3+++ debian/control 2013-03-15 03:39:20 +0000
4@@ -58,11 +58,22 @@
5 .
6 Contains the shared library needed by server applications for Mir.
7
8+Package: mircommon-dev
9+Section: libdevel
10+Architecture: any
11+Depends: ${misc:Depends},
12+Description: Display server for Ubuntu - development headers
13+ Mir is a display server running on linux systems, with a focus on efficiency,
14+ robust operation and a well-defined driver model.
15+ .
16+ Contains header files required for server and/or client development.
17+
18 Package: libmirserver-dev
19 Section: libdevel
20 Architecture: any
21 Depends: libmirserver0 (= ${binary:Version}),
22 libmirprotobuf-dev (= ${source:Version}),
23+ mircommon-dev (= ${source:Version}),
24 ${misc:Depends},
25 Description: Display server for Ubuntu - development headers
26 Mir is a display server running on linux systems, with a focus on efficiency,
27@@ -86,6 +97,7 @@
28 Architecture: any
29 Depends: libmirclient0 (= ${binary:Version}),
30 libmirprotobuf-dev (= ${source:Version}),
31+ mircommon-dev (= ${source:Version}),
32 ${misc:Depends},
33 Description: Display server for Ubuntu - development headers
34 Mir is a display server running on linux systems, with a focus on efficiency,
35
36=== added file 'debian/mircommon-dev.install'
37--- debian/mircommon-dev.install 1970-01-01 00:00:00 +0000
38+++ debian/mircommon-dev.install 2013-03-15 03:39:20 +0000
39@@ -0,0 +1,1 @@
40+usr/include/mir_toolkit/*.h
41
42=== modified file 'include/client/mir_toolkit/mir_client_library.h'
43--- include/client/mir_toolkit/mir_client_library.h 2013-03-07 08:04:05 +0000
44+++ include/client/mir_toolkit/mir_client_library.h 2013-03-15 03:39:20 +0000
45@@ -18,6 +18,8 @@
46 #ifndef MIR_CLIENT_LIBRARY_H
47 #define MIR_CLIENT_LIBRARY_H
48
49+#include <mir_toolkit/common.h>
50+
51 #ifdef __cplusplus
52 /** The C client API
53 */
54@@ -322,6 +324,23 @@
55 */
56 int mir_debug_surface_id(MirSurface *surface);
57
58+/**
59+ * Set the type (purpose) of a surface. This is not guaranteed to always work
60+ * with some shell types (e.g. phone/tablet UIs). As such, you may have to
61+ * wait on the function and check the result using mir_surface_get_type.
62+ * \param [in] surface The surface to operate on
63+ * \param [in] type The new type of the surface
64+ * \return A wait handle that can be passed to mir_wait_for
65+ */
66+MirWaitHandle* mir_surface_set_type(MirSurface *surface, MirSurfaceType type);
67+
68+/**
69+ * Get the type (purpose) of a surface.
70+ * \param [in] surface The surface to query
71+ * \return The type of the surface
72+ */
73+MirSurfaceType mir_surface_get_type(MirSurface *surface);
74+
75 #ifdef __cplusplus
76 }
77 }
78
79=== modified file 'include/server/mir/frontend/application_mediator.h'
80--- include/server/mir/frontend/application_mediator.h 2013-03-07 08:04:05 +0000
81+++ include/server/mir/frontend/application_mediator.h 2013-03-15 03:39:20 +0000
82@@ -103,6 +103,11 @@
83 mir::protobuf::DRMAuthMagicStatus* response,
84 google::protobuf::Closure* done);
85
86+ void configure_surface(google::protobuf::RpcController* controller,
87+ const mir::protobuf::SurfaceSetting*,
88+ mir::protobuf::SurfaceSetting*,
89+ google::protobuf::Closure* done);
90+
91 private:
92 std::shared_ptr<shell::SessionStore> const session_store;
93 std::shared_ptr<graphics::Platform> const graphics_platform;
94
95=== modified file 'include/server/mir/frontend/application_mediator_report.h'
96--- include/server/mir/frontend/application_mediator_report.h 2013-03-07 08:04:05 +0000
97+++ include/server/mir/frontend/application_mediator_report.h 2013-03-15 03:39:20 +0000
98@@ -41,6 +41,7 @@
99 virtual void application_disconnect_called(std::string const& app_name) = 0;
100
101 virtual void application_drm_auth_magic_called(std::string const& app_name) = 0;
102+ virtual void application_configure_surface_called(std::string const& app_name) = 0;
103
104 virtual void application_error(
105 std::string const& app_name,
106@@ -63,6 +64,8 @@
107
108 virtual void application_drm_auth_magic_called(std::string const& app_name);
109
110+ virtual void application_configure_surface_called(std::string const& app_name);
111+
112 virtual void application_error(
113 std::string const& app_name,
114 char const* method,
115
116=== modified file 'include/server/mir/logging/application_mediator_report.h'
117--- include/server/mir/logging/application_mediator_report.h 2013-03-04 16:02:02 +0000
118+++ include/server/mir/logging/application_mediator_report.h 2013-03-15 03:39:20 +0000
119@@ -47,6 +47,8 @@
120
121 virtual void application_drm_auth_magic_called(std::string const& app_name);
122
123+ virtual void application_configure_surface_called(std::string const& app_name);
124+
125 virtual void application_error(
126 std::string const& app_name,
127 char const* method,
128
129=== modified file 'include/server/mir/shell/application_session.h'
130--- include/server/mir/shell/application_session.h 2013-03-07 08:04:05 +0000
131+++ include/server/mir/shell/application_session.h 2013-03-15 03:39:20 +0000
132@@ -46,6 +46,8 @@
133 void hide();
134 void show();
135
136+ int configure_surface(SurfaceId id, MirSurfaceAttrib attrib, int value);
137+
138 protected:
139 ApplicationSession(ApplicationSession const&) = delete;
140 ApplicationSession& operator=(ApplicationSession const&) = delete;
141
142=== modified file 'include/server/mir/shell/session.h'
143--- include/server/mir/shell/session.h 2013-03-07 08:04:05 +0000
144+++ include/server/mir/shell/session.h 2013-03-15 03:39:20 +0000
145@@ -19,6 +19,7 @@
146 #ifndef MIR_SHELL_SESSION_H_
147 #define MIR_SHELL_SESSION_H_
148
149+#include "mir_toolkit/common.h"
150 #include "mir/shell/surface_id.h"
151
152 #include <mutex>
153@@ -50,6 +51,8 @@
154 virtual void hide() = 0;
155 virtual void show() = 0;
156
157+ virtual int configure_surface(SurfaceId id, MirSurfaceAttrib attrib, int value) = 0;
158+
159 protected:
160 Session() = default;
161 Session(Session const&) = delete;
162
163=== modified file 'include/server/mir/shell/surface.h'
164--- include/server/mir/shell/surface.h 2013-03-07 08:04:05 +0000
165+++ include/server/mir/shell/surface.h 2013-03-15 03:39:20 +0000
166@@ -23,6 +23,7 @@
167 #include "mir/geometry/pixel_format.h"
168 #include "mir/geometry/point.h"
169 #include "mir/geometry/size.h"
170+#include "mir_toolkit/common.h"
171
172 #include <memory>
173
174@@ -55,6 +56,8 @@
175 virtual void advance_client_buffer() = 0;
176 virtual std::shared_ptr<compositor::Buffer> client_buffer() const = 0;
177
178+ virtual int configure(MirSurfaceAttrib attrib, int value) = 0;
179+
180 protected:
181 Surface() = default;
182 Surface(Surface const&) = delete;
183
184=== modified file 'include/server/mir/surfaces/surface.h'
185--- include/server/mir/surfaces/surface.h 2013-03-07 08:04:05 +0000
186+++ include/server/mir/surfaces/surface.h 2013-03-15 03:39:20 +0000
187@@ -22,6 +22,7 @@
188 #include "mir/geometry/pixel_format.h"
189 #include "mir/graphics/renderable.h"
190 #include "mir/compositor/buffer_properties.h"
191+#include "mir_toolkit/common.h"
192
193 #include <memory>
194 #include <string>
195@@ -71,6 +72,9 @@
196 std::shared_ptr<compositor::Buffer> client_buffer() const;
197 void shutdown();
198
199+ MirSurfaceType type() const;
200+ bool set_type(MirSurfaceType t);
201+
202 private:
203 std::string surface_name;
204 std::shared_ptr<BufferBundle> buffer_bundle;
205@@ -81,6 +85,8 @@
206 float alpha_value;
207
208 bool is_hidden;
209+
210+ MirSurfaceType type_value;
211 };
212
213 }
214
215=== added file 'include/shared/mir_toolkit/common.h'
216--- include/shared/mir_toolkit/common.h 1970-01-01 00:00:00 +0000
217+++ include/shared/mir_toolkit/common.h 2013-03-15 03:39:20 +0000
218@@ -0,0 +1,49 @@
219+/*
220+ * Simple definitions common to client and server.
221+ *
222+ * Copyright © 2013 Canonical Ltd.
223+ *
224+ * This program is free software: you can redistribute it and/or modify
225+ * it under the terms of the GNU Lesser General Public License version 3 as
226+ * published by the Free Software Foundation.
227+ *
228+ * This program is distributed in the hope that it will be useful,
229+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
230+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
231+ * GNU Lesser General Public License for more details.
232+ *
233+ * You should have received a copy of the GNU Lesser General Public License
234+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
235+ *
236+ * Author: Daniel van Vugt <daniel.van.vugt@canonical.com>
237+ */
238+
239+#ifndef MIR_COMMON_H_
240+#define MIR_COMMON_H_
241+
242+/* This is C code. Not C++. */
243+
244+/*
245+ * Attributes of a surface that the client and server/shell may wish to
246+ * get or set over the wire.
247+ */
248+typedef enum MirSurfaceAttrib
249+{
250+ mir_surface_attrib_type,
251+ mir_surface_attrib_arraysize_
252+} MirSurfaceAttrib;
253+
254+typedef enum MirSurfaceType
255+{
256+ mir_surface_type_normal,
257+ mir_surface_type_utility,
258+ mir_surface_type_dialog,
259+ mir_surface_type_overlay,
260+ mir_surface_type_freestyle,
261+ mir_surface_type_popover,
262+ mir_surface_type_arraysize_
263+} MirSurfaceType;
264+
265+/* TODO: Surface states here */
266+
267+#endif
268
269=== modified file 'include/test/mir_test_doubles/mock_session.h'
270--- include/test/mir_test_doubles/mock_session.h 2013-03-11 20:18:11 +0000
271+++ include/test/mir_test_doubles/mock_session.h 2013-03-15 03:39:20 +0000
272@@ -41,6 +41,8 @@
273
274 MOCK_METHOD0(hide, void());
275 MOCK_METHOD0(show, void());
276+
277+ MOCK_METHOD3(configure_surface, int(shell::SurfaceId, MirSurfaceAttrib, int));
278 };
279
280 }
281
282=== modified file 'include/test/mir_test_doubles/mock_surface.h'
283--- include/test/mir_test_doubles/mock_surface.h 2013-03-11 20:18:11 +0000
284+++ include/test/mir_test_doubles/mock_surface.h 2013-03-15 03:39:20 +0000
285@@ -41,6 +41,8 @@
286 MOCK_CONST_METHOD0(size, geometry::Size ());
287 MOCK_CONST_METHOD0(pixel_format, geometry::PixelFormat ());
288 MOCK_CONST_METHOD0(client_buffer, std::shared_ptr<compositor::Buffer> ());
289+
290+ MOCK_METHOD2(configure, int(MirSurfaceAttrib, int));
291 };
292
293 }
294
295=== modified file 'include/test/mir_test_doubles/stub_session.h'
296--- include/test/mir_test_doubles/stub_session.h 2013-03-11 20:12:42 +0000
297+++ include/test/mir_test_doubles/stub_session.h 2013-03-15 03:39:20 +0000
298@@ -54,6 +54,10 @@
299 void show()
300 {
301 }
302+ int configure_surface(shell::SurfaceId, MirSurfaceAttrib, int)
303+ {
304+ return 0;
305+ }
306 };
307
308 }
309
310=== modified file 'src/client/mir_client_library.cpp'
311--- src/client/mir_client_library.cpp 2013-03-07 08:04:05 +0000
312+++ src/client/mir_client_library.cpp 2013-03-15 03:39:20 +0000
313@@ -227,3 +227,25 @@
314 {
315 // Ignore
316 }
317+
318+mir_toolkit::MirWaitHandle* mir_toolkit::mir_surface_set_type(MirSurface *surf,
319+ MirSurfaceType type)
320+{
321+ return surf ? surf->configure(mir_surface_attrib_type, type) : NULL;
322+}
323+
324+MirSurfaceType mir_toolkit::mir_surface_get_type(MirSurface *surf)
325+{
326+ MirSurfaceType type = mir_surface_type_normal;
327+
328+ if (surf)
329+ {
330+ // I assume the type can only change from the client side. Otherwise
331+ // we would have to send off a message to retrieve the latest...
332+
333+ int t = surf->attrib(mir_surface_attrib_type);
334+ type = static_cast<MirSurfaceType>(t);
335+ }
336+
337+ return type;
338+}
339
340=== modified file 'src/client/mir_surface.cpp'
341--- src/client/mir_surface.cpp 2013-03-07 08:04:05 +0000
342+++ src/client/mir_surface.cpp 2013-03-15 03:39:20 +0000
343@@ -50,6 +50,10 @@
344 message.set_buffer_usage(params.buffer_usage);
345
346 server.create_surface(0, &message, &surface, gp::NewCallback(this, &MirSurface::created, callback, context));
347+
348+ for (int i = 0; i < mir_surface_attrib_arraysize_; i++)
349+ attrib_cache[i] = -1;
350+ attrib_cache[mir_surface_attrib_type] = mir_surface_type_normal;
351 }
352
353 mir_toolkit::MirSurface::~MirSurface()
354@@ -226,3 +230,46 @@
355 {
356 return *accelerated_window;
357 }
358+
359+MirWaitHandle* MirSurface::configure(MirSurfaceAttrib at, int value)
360+{
361+ mp::SurfaceSetting setting;
362+ setting.mutable_surfaceid()->CopyFrom(surface.id());
363+ setting.set_attrib(at);
364+ setting.set_ivalue(value);
365+
366+ configure_wait_handle.expect_result();
367+ server.configure_surface(0, &setting, &configure_result,
368+ google::protobuf::NewCallback(this, &MirSurface::on_configured));
369+
370+ return &configure_wait_handle;
371+}
372+
373+void MirSurface::on_configured()
374+{
375+ if (configure_result.has_surfaceid() &&
376+ configure_result.surfaceid().value() == surface.id().value() &&
377+ configure_result.has_attrib())
378+ {
379+ switch (configure_result.attrib())
380+ {
381+ case mir_surface_attrib_type:
382+ if (configure_result.has_ivalue())
383+ {
384+ int t = configure_result.ivalue();
385+ attrib_cache[mir_surface_attrib_type] = t;
386+ } // else error is probably set due to an unsupported attrib/value
387+ break;
388+ default:
389+ assert(false);
390+ break;
391+ }
392+
393+ configure_wait_handle.result_received();
394+ }
395+}
396+
397+int MirSurface::attrib(MirSurfaceAttrib at) const
398+{
399+ return attrib_cache[at];
400+}
401
402=== modified file 'src/client/mir_surface.h'
403--- src/client/mir_surface.h 2013-03-07 08:04:05 +0000
404+++ src/client/mir_surface.h 2013-03-15 03:39:20 +0000
405@@ -23,6 +23,7 @@
406 #include "mir/geometry/pixel_format.h"
407 #include "mir/geometry/dimensions.h"
408 #include "mir_toolkit/mir_client_library.h"
409+#include "mir_toolkit/common.h"
410 #include "client_buffer_depository.h"
411 #include "mir_wait_handle.h"
412 #include "mir_client_surface.h"
413@@ -72,7 +73,11 @@
414 void release_cpu_region();
415 EGLNativeWindowType generate_native_window();
416
417+ MirWaitHandle* configure(MirSurfaceAttrib a, int value);
418+ int attrib(MirSurfaceAttrib a) const;
419+
420 private:
421+ void on_configured();
422 void process_incoming_buffer();
423 void populate(MirBufferPackage& buffer_package);
424 void created(mir_surface_lifecycle_callback callback, void * context);
425@@ -88,6 +93,7 @@
426 MirConnection *connection;
427 MirWaitHandle create_wait_handle;
428 MirWaitHandle next_buffer_wait_handle;
429+ MirWaitHandle configure_wait_handle;
430
431 int last_buffer_id;
432
433@@ -96,6 +102,11 @@
434
435 std::shared_ptr<mir::client::Logger> logger;
436 std::shared_ptr<EGLNativeWindowType> accelerated_window;
437+
438+ mir::protobuf::SurfaceSetting configure_result;
439+
440+ // Cache of latest SurfaceSettings returned from the server
441+ int attrib_cache[mir_surface_attrib_arraysize_];
442 };
443
444 #endif /* MIR_CLIENT_PRIVATE_MIR_WAIT_HANDLE_H_ */
445
446=== modified file 'src/server/frontend/application_mediator.cpp'
447--- src/server/frontend/application_mediator.cpp 2013-03-07 08:04:05 +0000
448+++ src/server/frontend/application_mediator.cpp 2013-03-15 03:39:20 +0000
449@@ -24,6 +24,7 @@
450 #include "mir/shell/surface_creation_parameters.h"
451 #include "mir/frontend/resource_cache.h"
452
453+#include "mir_toolkit/common.h"
454 #include "mir/compositor/buffer_ipc_package.h"
455 #include "mir/compositor/buffer_id.h"
456 #include "mir/compositor/buffer.h"
457@@ -220,3 +221,29 @@
458 done->Run();
459 }
460
461+void mir::frontend::ApplicationMediator::configure_surface(
462+ google::protobuf::RpcController*, // controller,
463+ const mir::protobuf::SurfaceSetting* request,
464+ mir::protobuf::SurfaceSetting* response,
465+ google::protobuf::Closure* done)
466+{
467+ MirSurfaceAttrib attrib = static_cast<MirSurfaceAttrib>(request->attrib());
468+
469+ // Required response fields:
470+ response->mutable_surfaceid()->CopyFrom(request->surfaceid());
471+ response->set_attrib(attrib);
472+
473+ if (application_session.get() == nullptr)
474+ BOOST_THROW_EXCEPTION(std::logic_error("Invalid application session"));
475+
476+ report->application_configure_surface_called(application_session->name());
477+
478+ auto const id = shell::SurfaceId(request->surfaceid().value());
479+ int value = request->ivalue();
480+ int newvalue = application_session->configure_surface(id, attrib, value);
481+
482+ response->set_ivalue(newvalue);
483+
484+ done->Run();
485+}
486+
487
488=== modified file 'src/server/frontend/null_application_mediator_report.cpp'
489--- src/server/frontend/null_application_mediator_report.cpp 2013-03-07 08:04:05 +0000
490+++ src/server/frontend/null_application_mediator_report.cpp 2013-03-15 03:39:20 +0000
491@@ -42,6 +42,10 @@
492 {
493 }
494
495+void mir::frontend::NullApplicationMediatorReport::application_configure_surface_called(std::string const&)
496+{
497+}
498+
499 void mir::frontend::NullApplicationMediatorReport::application_error(
500 std::string const&,
501 char const* ,
502
503=== modified file 'src/server/frontend/protobuf_message_processor.cpp'
504--- src/server/frontend/protobuf_message_processor.cpp 2013-03-07 08:04:05 +0000
505+++ src/server/frontend/protobuf_message_processor.cpp 2013-03-15 03:39:20 +0000
506@@ -176,6 +176,10 @@
507 {
508 invoke(&protobuf::DisplayServer::select_focus_by_lightdm_id, invocation);
509 }
510+ else if ("configure_surface" == invocation.method_name())
511+ {
512+ invoke(&protobuf::DisplayServer::configure_surface, invocation);
513+ }
514 else if ("disconnect" == invocation.method_name())
515 {
516 invoke(&protobuf::DisplayServer::disconnect, invocation);
517
518=== modified file 'src/server/logging/application_mediator_report.cpp'
519--- src/server/logging/application_mediator_report.cpp 2013-03-04 16:02:02 +0000
520+++ src/server/logging/application_mediator_report.cpp 2013-03-15 03:39:20 +0000
521@@ -63,6 +63,11 @@
522 log->log<Logger::informational>("application_drm_auth_magic_called(\"" + app_name + "\")", component);
523 }
524
525+void ml::ApplicationMediatorReport::application_configure_surface_called(std::string const& app_name)
526+{
527+ log->log<Logger::informational>("application_configure_surface_called(\"" + app_name + "\")", component);
528+}
529+
530 void ml::ApplicationMediatorReport::application_error(
531 std::string const& app_name,
532 char const* method,
533
534=== modified file 'src/server/shell/application_session.cpp'
535--- src/server/shell/application_session.cpp 2013-03-07 08:04:05 +0000
536+++ src/server/shell/application_session.cpp 2013-03-15 03:39:20 +0000
537@@ -122,3 +122,13 @@
538 id_s.second->show();
539 }
540 }
541+
542+int msh::ApplicationSession::configure_surface(msh::SurfaceId id,
543+ MirSurfaceAttrib attrib,
544+ int value)
545+{
546+ std::unique_lock<std::mutex> lock(surfaces_mutex);
547+ std::shared_ptr<msh::Surface> surf(checked_find(id)->second);
548+
549+ return surf->configure(attrib, value);
550+}
551
552=== modified file 'src/server/surfaces/proxy_surface.cpp'
553--- src/server/surfaces/proxy_surface.cpp 2013-03-07 08:04:05 +0000
554+++ src/server/surfaces/proxy_surface.cpp 2013-03-15 03:39:20 +0000
555@@ -109,6 +109,37 @@
556 surface_stack->destroy_surface(surface);
557 }
558
559+int ms::BasicProxySurface::configure(MirSurfaceAttrib attrib, int value)
560+{
561+ if (auto const& s = surface.lock())
562+ {
563+ int result = 0;
564+
565+ /*
566+ * TODO: In future, query the shell implementation for the subset of
567+ * attributes/types it implements.
568+ */
569+ switch (attrib)
570+ {
571+ case mir_surface_attrib_type:
572+ if (!s->set_type(static_cast<MirSurfaceType>(value)))
573+ BOOST_THROW_EXCEPTION(std::logic_error("Invalid surface "
574+ "type."));
575+ result = s->type();
576+ break;
577+ default:
578+ BOOST_THROW_EXCEPTION(std::logic_error("Invalid surface "
579+ "attribute."));
580+ break;
581+ }
582+
583+ return result;
584+ }
585+ else
586+ {
587+ BOOST_THROW_EXCEPTION(std::runtime_error("Invalid surface"));
588+ }
589+}
590
591 ms::ProxySurface::ProxySurface(
592 SurfaceStackModel* const surface_stack_,
593
594=== modified file 'src/server/surfaces/proxy_surface.h'
595--- src/server/surfaces/proxy_surface.h 2013-03-07 08:04:05 +0000
596+++ src/server/surfaces/proxy_surface.h 2013-03-15 03:39:20 +0000
597@@ -56,6 +56,8 @@
598
599 std::shared_ptr<compositor::Buffer> client_buffer() const;
600
601+ int configure(MirSurfaceAttrib attrib, int value);
602+
603 protected:
604 void destroy_surface(SurfaceStackModel* const surface_stack) const;
605
606
607=== modified file 'src/server/surfaces/surface.cpp'
608--- src/server/surfaces/surface.cpp 2013-03-07 08:04:05 +0000
609+++ src/server/surfaces/surface.cpp 2013-03-15 03:39:20 +0000
610@@ -22,6 +22,8 @@
611 #include "mir/compositor/buffer_ipc_package.h"
612 #include "mir/surfaces/buffer_bundle.h"
613
614+#include <stdexcept>
615+#include <boost/throw_exception.hpp>
616 #include <cassert>
617 #include <glm/gtc/matrix_transform.hpp>
618
619@@ -36,7 +38,8 @@
620 surface_name(name),
621 buffer_bundle(buffer_bundle),
622 alpha_value(1.0f),
623- is_hidden(false)
624+ is_hidden(false),
625+ type_value(mir_surface_type_normal)
626 {
627 // TODO(tvoss,kdub): Does a surface without a buffer_bundle make sense?
628 assert(buffer_bundle);
629@@ -128,3 +131,21 @@
630 {
631 return client_buffer_resource;
632 }
633+
634+MirSurfaceType ms::Surface::type() const
635+{
636+ return type_value;
637+}
638+
639+bool ms::Surface::set_type(MirSurfaceType t)
640+{
641+ bool valid = false;
642+
643+ if (t >= 0 && t < mir_surface_type_arraysize_)
644+ {
645+ type_value = t;
646+ valid = true;
647+ }
648+
649+ return valid;
650+}
651
652=== modified file 'src/shared/CMakeLists.txt'
653--- src/shared/CMakeLists.txt 2013-03-13 17:54:59 +0000
654+++ src/shared/CMakeLists.txt 2013-03-15 03:39:20 +0000
655@@ -5,3 +5,13 @@
656 MIR_GENERATED_INCLUDE_DIRECTORIES
657 ${MIR_GENERATED_INCLUDE_DIRECTORIES}
658 PARENT_SCOPE)
659+
660+# Some headers contain common definitions required for both client and
661+# server development...
662+set (MIR_COMMON_HEADERS
663+ ${CMAKE_SOURCE_DIR}/include/shared/mir_toolkit/common.h
664+)
665+
666+# TODO: Find a more elegant include/ structure. Ideally one in which everything
667+# lives under "include/mir/".
668+install (FILES ${MIR_COMMON_HEADERS} DESTINATION "include/mir_toolkit/")
669
670=== modified file 'src/shared/protobuf/mir_protobuf.proto'
671--- src/shared/protobuf/mir_protobuf.proto 2013-01-10 16:58:01 +0000
672+++ src/shared/protobuf/mir_protobuf.proto 2013-03-15 03:39:20 +0000
673@@ -111,6 +111,14 @@
674 optional string error = 127;
675 }
676
677+message SurfaceSetting {
678+ optional SurfaceId surfaceid = 1;
679+ optional int32 attrib = 2;
680+ optional int32 ivalue = 3;
681+ // optional string svalue = 4; // Expected for future use
682+ optional string error = 127;
683+}
684+
685 service DisplayServer {
686 // Platform independent requests
687 rpc connect(ConnectParameters) returns (Connection);
688@@ -124,5 +132,7 @@
689 rpc drm_auth_magic(DRMMagic) returns (DRMAuthMagicStatus);
690
691 rpc test_file_descriptors(Void) returns (Buffer);
692+
693+ rpc configure_surface(SurfaceSetting) returns (SurfaceSetting);
694 }
695
696
697=== modified file 'tests/acceptance-tests/test_client_library.cpp'
698--- tests/acceptance-tests/test_client_library.cpp 2013-03-07 08:04:05 +0000
699+++ tests/acceptance-tests/test_client_library.cpp 2013-03-15 03:39:20 +0000
700@@ -168,6 +168,80 @@
701 launch_client_process(client_config);
702 }
703
704+TEST_F(DefaultDisplayServerTestFixture, surface_types)
705+{
706+ struct ClientConfig : ClientConfigCommon
707+ {
708+ void exec()
709+ {
710+
711+ mir_wait_for(mir_connect(mir_test_socket, __PRETTY_FUNCTION__, connection_callback, this));
712+
713+ ASSERT_TRUE(connection != NULL);
714+ EXPECT_TRUE(mir_connection_is_valid(connection));
715+ EXPECT_STREQ(mir_connection_get_error_message(connection), "");
716+
717+ MirSurfaceParameters const request_params =
718+ {
719+ __PRETTY_FUNCTION__,
720+ 640, 480,
721+ mir_pixel_format_abgr_8888,
722+ mir_buffer_usage_hardware
723+ };
724+
725+ mir_wait_for(mir_surface_create(connection, &request_params, create_surface_callback, this));
726+
727+ ASSERT_TRUE(surface != NULL);
728+ EXPECT_TRUE(mir_surface_is_valid(surface));
729+ EXPECT_STREQ(mir_surface_get_error_message(surface), "");
730+
731+ EXPECT_EQ(mir_surface_get_type(surface),
732+ mir_surface_type_normal);
733+
734+ mir_wait_for(mir_surface_set_type(surface,
735+ mir_surface_type_freestyle));
736+ EXPECT_EQ(mir_surface_get_type(surface),
737+ mir_surface_type_freestyle);
738+
739+ mir_wait_for(mir_surface_set_type(surface,
740+ static_cast<MirSurfaceType>(999)));
741+ EXPECT_EQ(mir_surface_get_type(surface),
742+ mir_surface_type_freestyle);
743+
744+ mir_wait_for(mir_surface_set_type(surface,
745+ mir_surface_type_dialog));
746+ EXPECT_EQ(mir_surface_get_type(surface),
747+ mir_surface_type_dialog);
748+
749+ mir_wait_for(mir_surface_set_type(surface,
750+ static_cast<MirSurfaceType>(888)));
751+ EXPECT_EQ(mir_surface_get_type(surface),
752+ mir_surface_type_dialog);
753+
754+ // Stress-test synchronization logic with some flooding
755+ for (int i = 0; i < 100; i++)
756+ {
757+ mir_surface_set_type(surface, mir_surface_type_normal);
758+ mir_surface_set_type(surface, mir_surface_type_utility);
759+ mir_surface_set_type(surface, mir_surface_type_dialog);
760+ mir_surface_set_type(surface, mir_surface_type_overlay);
761+ mir_surface_set_type(surface, mir_surface_type_freestyle);
762+ mir_wait_for(mir_surface_set_type(surface,
763+ mir_surface_type_popover));
764+ ASSERT_EQ(mir_surface_get_type(surface),
765+ mir_surface_type_popover);
766+ }
767+
768+ mir_wait_for(mir_surface_release(surface, release_surface_callback,
769+ this));
770+
771+ mir_connection_release(connection);
772+ }
773+ } client_config;
774+
775+ launch_client_process(client_config);
776+}
777+
778 TEST_F(DefaultDisplayServerTestFixture, client_library_creates_multiple_surfaces)
779 {
780 int const n_surfaces = 13;
781
782=== modified file 'tests/behavior-tests/session_management_context.cpp'
783--- tests/behavior-tests/session_management_context.cpp 2013-03-13 07:41:46 +0000
784+++ tests/behavior-tests/session_management_context.cpp 2013-03-15 03:39:20 +0000
785@@ -75,6 +75,11 @@
786 {
787 return std::shared_ptr<mc::Buffer>();
788 }
789+
790+ virtual int configure(MirSurfaceAttrib, int)
791+ {
792+ return 0;
793+ }
794 };
795
796 struct SizedDummySurface : public DummySurface
797
798=== modified file 'tests/integration-tests/cucumber/test_session_management_context.cpp'
799--- tests/integration-tests/cucumber/test_session_management_context.cpp 2013-03-13 07:41:46 +0000
800+++ tests/integration-tests/cucumber/test_session_management_context.cpp 2013-03-15 03:39:20 +0000
801@@ -64,6 +64,8 @@
802 MOCK_CONST_METHOD0(size, mir::geometry::Size ());
803 MOCK_CONST_METHOD0(pixel_format, mir::geometry::PixelFormat ());
804 MOCK_CONST_METHOD0(client_buffer, std::shared_ptr<mc::Buffer> ());
805+
806+ MOCK_METHOD2(configure, int(MirSurfaceAttrib, int));
807 };
808
809 MATCHER_P(NamedWindowWithNoGeometry, name, "")
810
811=== modified file 'tests/unit-tests/client/test_client_mir_surface.cpp'
812--- tests/unit-tests/client/test_client_mir_surface.cpp 2013-03-07 08:04:05 +0000
813+++ tests/unit-tests/client/test_client_mir_surface.cpp 2013-03-15 03:39:20 +0000
814@@ -376,3 +376,22 @@
815 EXPECT_EQ(pf, geom::PixelFormat::abgr_8888);
816 }
817
818+TEST_F(MirClientSurfaceTest, default_surface_type)
819+{
820+ using namespace testing;
821+ using namespace mir::protobuf;
822+
823+ EXPECT_CALL(*mock_depository, deposit_package_rv(_,_,_,_))
824+ .Times(1);
825+
826+ auto surface = std::make_shared<MirSurface> (connection.get(),
827+ *client_comm_channel,
828+ logger,
829+ mock_depository,
830+ params,
831+ &empty_callback,
832+ (void*) NULL);
833+ surface->get_create_wait_handle()->wait_for_result();
834+
835+ EXPECT_EQ(surface->attrib(mir_surface_attrib_type), mir_surface_type_normal);
836+}
837
838=== modified file 'tests/unit-tests/surfaces/test_surface.cpp'
839--- tests/unit-tests/surfaces/test_surface.cpp 2013-03-07 08:04:05 +0000
840+++ tests/unit-tests/surfaces/test_surface.cpp 2013-03-15 03:39:20 +0000
841@@ -306,3 +306,21 @@
842
843 EXPECT_EQ(alpha, ret_alpha);
844 }
845+
846+TEST_F(SurfaceCreation, types)
847+{
848+ using namespace testing;
849+
850+ ms::Surface surf{surface_name, mock_buffer_bundle};
851+
852+ EXPECT_EQ(mir_surface_type_normal, surf.type());
853+
854+ EXPECT_TRUE(surf.set_type(mir_surface_type_utility));
855+ EXPECT_EQ(surf.type(), mir_surface_type_utility);
856+
857+ EXPECT_FALSE(surf.set_type(static_cast<MirSurfaceType>(999)));
858+ EXPECT_EQ(surf.type(), mir_surface_type_utility);
859+
860+ EXPECT_TRUE(surf.set_type(mir_surface_type_dialog));
861+ EXPECT_EQ(surf.type(), mir_surface_type_dialog);
862+}

Subscribers

People subscribed via source and target branches