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
Prerequisite: lp:~vanvugt/mir/fix-1151645
Diff against target: 864 lines (+438/-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 (+7/-0)
include/shared/mir/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 (+11/-0)
src/server/surfaces/proxy_surface.h (+2/-0)
src/server/surfaces/surface.cpp (+45/-1)
src/shared/CMakeLists.txt (+8/-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
PS Jenkins bot (community) continuous-integration Approve
Alan Griffiths Needs Fixing
Alexandros Frantzis (community) Needs Fixing
Review via email: mp+152116@code.launchpad.net

This proposal supersedes a proposal from 2013-03-01.

Commit message

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

This work will also form the foundation of supporting surface states and
necessitates a prototype shell interface.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Approve (continuous-integration)
Revision history for this message
Alan Griffiths (alan-griffiths) wrote : Posted in a previous version of this proposal

87 === modified file 'include/mir/graphics/display.h'
...
94 +#include "mir/shell/shell.h"

This feels very wrong - I don't believe that graphics::Display needs to know about shell::Shell.

Unless there is a compelling reason for something different, there should be an interface in *graphics* that determines the functionality that graphics::Display needs, and that will be implemented by shell::Shell.

~~~~

102 + void set_shell(std::shared_ptr<mir::Shell> s);
103 + bool start_shell();
104 + void stop_shell();
105 + std::shared_ptr<mir::Shell> current_shell() const;

I find it very hard to believe that these are functions that belong to graphics::Display.

In addition, graphics::Display is an interface and should not provide an implementation. (It is used in compositing - it should probably be there, but that's an existing issue.)

~~~~

252 +#include <mir/surface.h>

Don't use system includes for our files.

~~~~

298 +#ifndef __MIR_COMMON_SURFACE_H__
299 +#define __MIR_COMMON_SURFACE_H__

Does not match project naming style

~~~~

307 + MIR_SURFACE_TYPE,
308 + MirSurfaceAttrib_ARRAYSIZE

Does not match project naming style

~~~~

608 === added file 'src/display.cpp'

This is a confusing place to implement mir::graphics::Display

~~~~

633 +using namespace mir;
634 +using namespace mir::graphics;
635 +using namespace mir::shell;

This is a very different style to the rest of the codebase. I don't like it as it isn't clear where the classes mentioned in the code come from. (It can also lead to free functions being defined in global namespace and not the intended namespace.)

~~~~

735 + auto const shell = graphics_display->current_shell();
736 + if (!shell->supports(attrib))
737 + BOOST_THROW_EXCEPTION(std::logic_error("Current shell does not "
738 + "support the specified surface "
739 + "attribute"));

Application logic doesn't belong in ApplicationMediator.

~~~

814 +message SurfaceSetting {
815 + required SurfaceId surfaceid = 1;
816 + required int32 attrib = 2;
817 + optional int32 ivalue = 3;
818 + // optional string svalue = 4; // Expected for future use
819 +
820 + optional string error = 127;
821 +}

As this is returned by the RPC framework all the fields should be optional (as, in the event of an exception, it may be the only field populated).

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

Alan,

"Shell in Display"
I kind of agree. This was the last part I wrote and I later saw one or two alternative places to attach Shell other than inside Display. But from a conceptional standpoint, can we discuss why the "shell" is not a 1:1 part of a "display"?

"#include <mir/surface.h>"
Yes this is correct because it is included from a public system header (shell.h). Hence angle brackets are required.

"__MIR_COMMON_SURFACE_H__"
Yeah I can change the style no problem.

"MIR_SURFACE_TYPE"
This is C code. Not C++. What is the established convention for C-compatible enums that I should change to?

"src/display.cpp"
It's not really a confusing place because it's the same directory where other sources relating to it already reside. If I put display.cpp in a subdir then it has to be built into a static library and then bundled into the server library. Seems like an overkill for one small source file right now.

"using namespace mir"
I prefer this because it makes the code much more readable, and will argue to the very end that the convention seen in existing mir code is ugly, hard to read and more time-consuming to maintain. It is never confusing where a symbol comes from if it is only defined in one place in the project.

"Application logic doesn't belong in ApplicationMediator."
Yeah I had the same feeling. Just haven't yet found a cleaner place to put it where the logic had full access to all the objects in question.

"required vs optional"
I don't care enough to argue. Will change it.

All in all, I think that's a good initial review. Good only because I only disagree deeply with one of the points made.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

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

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

review: Approve (continuous-integration)
Revision history for this message
Alexandros Frantzis (afrantzis) wrote :

> But from a conceptional standpoint, can we discuss why the "shell" is not a 1:1 part of a "display"?

The display subsystem (at least as it stands now) offers low-level display/graphics services. Why should it have any knowledge about how those services are being used? Also, as Alan noted, if it turns out that display actually needs to have more information, this should happen through an interface that the display itself defines, and which is expressed in terms of what the display actually needs, not what the shell happens to provide.

> "MIR_SURFACE_TYPE"
> This is C code. Not C++. What is the established convention for C-compatible enums that I should change to?

See, for example, mir_client_library.h:

MirPixelFormat{ mir_pixel_format_invalid, mir_pixel_format_abgr_8888, ...}

> "src/display.cpp"
> It's not really a confusing place because it's the same directory where other sources
> relating to it already reside. If I put display.cpp in a subdir then it has to be built
> into a static library and then bundled into the server library. Seems like an overkill
> for one small source file right now.

I think the main issue is that we needed to have this file because mg::Display was not an interface anymore.

> "using namespace mir"
> I prefer this because it makes the code much more readable, and will argue to the very
> end that the convention seen in existing mir code is ugly, hard to read and more
> time-consuming to maintain. It is never confusing where a symbol comes from if it is only
> defined in one place in the project.

That's not always the case, e.g., shell::Surface vs surfaces::Surface

119 + std::shared_ptr<mir::Shell> sh = nullptr);

It would be cleaner to remove the optional parameter, and make invocations of ApplicationSession() that don't need a shell, use a NullShell.

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

Alexandros,

Yeah forget about the "Display" argument. I don't use "Display" any more. The above discussion in yellow is very out of date and should be mostly ignored.

Ok, I'll change the enum format to lower case as described. There will be a lot of string substitution today...

Yeah I know parts of Mir distinguish foo::Surface from bar::Surface. I'm familiar with that convention but don't like it. I think it's a crutch for when you can't think of a really good accurate class name. A namespace should be used as a namespace, and not used as an explicit part of the class name.

Yeah I can change the "=nullshell" into two separate constructors. I don't think that's cleaner but it's not worth arguing about.

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

> Yeah I can change the "=nullshell" into two separate constructors. I don't think that's cleaner but it's not worth
> arguing about.

Sorry, I didn't phrase my proposal very clearly. So here is take 2:

My proposal is to use a single constructor with a non-optional shell argument, and all invocations that don't need a shell should explicitly pass a NullShell. The reason is that other ways of doing this introduce (unnecessarily, IMO) two code paths in the code, any one of which could be less tested than the other. There is also the matter of desing clarity: ApplicationSession either has a shell dependency, or it doesn't. I feel that hiding that dependency by either having an optional parameter, or a second constructor, trades clarity for coding convenience, which I don't find to be a good bargain.

Thoughts?

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

That makes the test cases even more verbose and ugly. I tried it already.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

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

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

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

833 + if (!shell->supports(attrib))
834 + BOOST_THROW_EXCEPTION(std::logic_error("Current shell does not "
835 + "support the specified surface "
836 + "attribute"));
837 +
838 + if (!shell->supports(attrib, value))
839 + BOOST_THROW_EXCEPTION(std::logic_error("Current shell does not "
840 + "support the specified value "
841 + "for this attribute"));
842 +
843 + std::unique_lock<std::mutex> lock(surfaces_mutex);
844 + std::shared_ptr<msh::Surface> surf(checked_find(id)->second);
845 +
846 + return surf->configure(attrib, value);

I would expect all this precondition checking to occur inside the surf->configure() call. ApplicationSession doesn't need to know about surface attributes or "Shell".

~~~~

"Shell" is still a bad name for an interface that validates surface attributes (even if the discussion in yellow is believed to be "mostly obsolete"). But I don't really see the need for this interface at all - why doesn't Surface::configure() just implement the validation?

~~~~

195 +#include "mir/surface.h" // for MirSurfaceAttrib

use a forward declaration?

~~~~

344 === added file 'include/mir/surface.h'

I don't believe this is the correct place - this is for namespace mir {}

~~~~

Am I right in thinking that Surface attributes are meaningful to the shell, but not to the surfaces library? If that is correct, they belong on shell::Surface, but not on surfaces::Surface (and that supports my growing suspicion that ProxySurface belongs in shell).

review: Needs Fixing
Revision history for this message
Robert Carr (robertcarr) wrote :

Haven't processed the rest of the discussion but:

>> (and that supports my growing suspicion that ProxySurface belongs in shell).

Agree completely here.

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

"Shell" will in time represent a whole "shell" (i.e. everything a shell implementer needs to implement). I'm just not defining parts of the interface we don't need yet.

And yes it is correct for the Shell class to validate attributes and types, because only the shell implementer knows what attributes and types are valid for his/her shell. It would be wrong to push that functionality into 'shell::Surface' (which did not exist while I was writing this branch), because the result of supports() is invariant across surface instances. The supports() methods are simply to ask the shell author what types of surfaces/attributes their shell supports. You could argue therefore that supports() should be static to shell::Surface. However limitations in the C++ language prevent us from being able to virtualize static methods (last I checked). Calling current_shell.supports(some-surface-type) is the next best option. Consider also that we will often want to know if a surface type is supported _before_ we create the surface. So "supports()" would have to be a method of some other object that exists before the surface does, if not a static virtual method of shell::Surface (which wasn't possible last I checked).

Forward declaration or MirSurfaceAttrib:
Is there a type-safe way to forward declare an enum (from a C header) into C++11 ? That is other than using "int"? Which I was until recently... What's the syntax (that's also clang-friendly)?

'include/mir/surface.h'
I think '#include <mir/foo.h>' is the perfect place for shared headers. But of course if your header re-org branch lands first, then I'll use that proposed layout of <mir/shared/foo.h> and argue later.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

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

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

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

> "Shell" will in time represent a whole "shell" (i.e. everything a shell
> implementer needs to implement). I'm just not defining parts of the interface
> we don't need yet.

Even if this were a good idea (which needs to be argued), we shouldn't make parts of mir that only require a specific part of this functionality dependent on the whole Shell interface.

> And yes it is correct for the Shell class to validate attributes and types,
> because only the shell implementer knows what attributes and types are valid
> for his/her shell. It would be wrong to push that functionality into
> 'shell::Surface' (which did not exist while I was writing this branch),

sessions::Surface existed before "sessions" was renamed "shell".

> because the result of supports() is invariant across surface instances. The
> supports() methods are simply to ask the shell author what types of
> surfaces/attributes their shell supports. You could argue therefore that
> supports() should be static to shell::Surface. However limitations in the C++
> language prevent us from being able to virtualize static methods (last I
> checked). Calling current_shell.supports(some-surface-type) is the next best
> option. Consider also that we will often want to know if a surface type is
> supported _before_ we create the surface. So "supports()" would have to be a
> method of some other object that exists before the surface does, if not a
> static virtual method of shell::Surface (which wasn't possible last I
> checked).

It makes more sense that an implementation of shell::Surface maintains the invariant of having valid attributes (by throwing from configure()) than that it requires from co-operation by ApplicationMediator and Shell. (If you want to separate out the validation logic then make shell::SurfaceAttributeValidator a dependency of that implementation.)

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

P.S. Thank you (racarr?) for renaming sessions::Surface to shell::Surface. A single change in wording clarifies the design intention significantly, which helps.

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

Subscribers

People subscribed via source and target branches