Mir

Merge lp:~raof/mir/input-methods-can-specify-foreign-parents into lp:mir

Proposed by Chris Halse Rogers
Status: Merged
Approved by: Daniel van Vugt
Approved revision: no longer in the source branch.
Merged at revision: 2721
Proposed branch: lp:~raof/mir/input-methods-can-specify-foreign-parents
Merge into: lp:mir
Prerequisite: lp:~raof/mir/persistent-surface-id
Diff against target: 628 lines (+331/-3)
19 files modified
include/client/mir_toolkit/mir_surface.h (+41/-0)
src/client/mir_surface.cpp (+12/-0)
src/client/mir_surface.h (+1/-0)
src/client/mir_surface_api.cpp (+30/-0)
src/client/symbols.map (+3/-0)
src/include/server/mir/frontend/shell.h (+3/-0)
src/include/server/mir/frontend/template_protobuf_message_processor.h (+4/-1)
src/protobuf/mir_protobuf.proto (+6/-0)
src/server/frontend/protobuf_message_processor.cpp (+3/-1)
src/server/frontend/session_mediator.cpp (+7/-0)
src/server/frontend/shell_wrapper.cpp (+6/-0)
src/server/frontend/shell_wrapper.h (+2/-0)
src/server/shell/default_persistent_surface_store.cpp (+10/-1)
src/server/shell/frontend_shell.cpp (+17/-0)
src/server/shell/frontend_shell.h (+2/-0)
tests/acceptance-tests/test_client_library.cpp (+45/-0)
tests/acceptance-tests/test_client_library_errors.cpp (+63/-0)
tests/acceptance-tests/test_client_surfaces.cpp (+74/-0)
tests/include/mir/test/doubles/mock_shell.h (+2/-0)
To merge this branch: bzr merge lp:~raof/mir/input-methods-can-specify-foreign-parents
Reviewer Review Type Date Requested Status
Alberto Aguirre (community) Approve
PS Jenkins bot (community) continuous-integration Approve
Alan Griffiths Needs Fixing
Kevin DuBois (community) Approve
Daniel van Vugt Abstain
Robert Carr (community) Approve
Review via email: mp+258001@code.launchpad.net

Commit message

Allow input method surfaces to specify another client's surface as its parent

Description of the change

Make persistent-surface-id actually useful by using it to let IM surfaces specify another client's surface as their parent.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Robert Carr (robertcarr) wrote :

>> + // XXX: This is ugly, but there doesn't seem to be a better way

Why not just let the exception propagate to the frontend to produce the error like we normally do? To control the error message?

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

Beyond that looking good

Revision history for this message
Alberto Aguirre (albaguirre) wrote :

Looks good.

review: Approve
Revision history for this message
Chris Halse Rogers (raof) wrote :

> >> + // XXX: This is ugly, but there doesn't seem to be a better way
>
> Why not just let the exception propagate to the frontend to produce the error
> like we normally do? To control the error message?

It's my understanding that if the frontend catches the error then the client is killed. That doesn't want to happen here - an ID no longer referring to an active surface is not a programming error, it'

Revision history for this message
Chris Halse Rogers (raof) wrote :

> >> + // XXX: This is ugly, but there doesn't seem to be a better way
>
> Why not just let the exception propagate to the frontend to produce the error
> like we normally do? To control the error message?

It's my understanding that if the frontend catches the error then the client is killed. That doesn't want to happen here - an ID no longer referring to an active surface is not a programming error, it's an unavoidable race condition. The IM will need to catch it and respond by not popping up a surface, but it shouldn't be fatal.

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

I recall mpt (or someone) designed this in some detail already. Need to find the design...

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

I can't find where surfaces which are not input methods are prevented from using this.

review: Needs Information
Revision history for this message
Chris Halse Rogers (raof) wrote :

> I can't find where surfaces which are not input methods are prevented from
> using this.

That's because there's currently nothing which enforces that. I'll update.

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
Robert Carr (robertcarr) wrote :

I think the window type validation should happen on the server side not the client

review: Needs Fixing
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Robert Carr (robertcarr) wrote :

LGTM

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

I remember in sprint discussions with tvoss/mpt at one point it was said that an input method does not operate on its parent, but some other "target" surface instead. Can't remember why.

Still need to check with mpt/tvoss if they have written down a design for it...

review: Needs Information
Revision history for this message
Chris Halse Rogers (raof) wrote :

Perhaps you're thinking of the fact that the input methods are out-of-process daemons with their own connection to Mir? They don't act on their own parents, because they don't have parents. They're parented on whatever client has the active text-box.

Which is precisely why we need this foreign-parent interface for them.

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

I don't mind. I prefer having one parent concept than two. Just keep in mind there's a risk mpt/tvoss might have specified it differently.

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

It doesnt seem quite like a parent is involved, we're just attaching the input surface to the edge of another surface. Aside from that, lgtm.

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

Meh, I guess given the current way edge attachment works, it doesn't flummox me too much to call the method "mir_surface_spec_attach_to_foreign_parent". In a vacuum (apart from the spec document) mir_surface_spec_attach_to_surface_edge would make more sense I guess. Anyways +1

review: Approve
Revision history for this message
Alberto Aguirre (albaguirre) wrote :

> It doesnt seem quite like a parent is involved, we're just attaching the input
> surface to the edge of another surface. Aside from that, lgtm.

That's how menu's work too. And I assume they have similar properties, like if the parent is not visible anymore the foreign child should go away too.

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

https://code.launchpad.net/~kdub/mir/multiple-bufferstream-api/+merge/261123 is having the same problem with glmark.... both that MP and this one add a new api function...

Revision history for this message
Alberto Aguirre (albaguirre) wrote :

^--Results in stack smashing because MirSurface::MirSurface allocates a mir::protobuf::SurfaceParameters object on the stack using the previous definition (as defined in mir 0.13.2, since glmark2-es2-mir links against libmirclient8 - i.e. no parent_persistent_id field) but the destructor invoked and the end of MirSurface::MirSurface constructor scope comes from the CI build of libmirprotobuf.so.0, which attempts to delete the parent_persistent_id_ field smashing the stack.

I think this warrants a libmirprotobuf ABI bump?

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
Alberto Aguirre (albaguirre) wrote :

Gah, I guess loading libmirprotobuf.so.0 and libmirprotobuf.so.1 in the same process is more common than I thought since the mirclientplatformmesa module links against libmirclient.

The mako test runner will install the mesa platform modules from the CI build; when glmark2-es2-mir starts up (which links against libmirclient8), it probes mirclientplatformmesa which loads libmirclient9 (and subsequently libmirprotobuf.so.1) into the same process where libmirclient8 and libmirprotobuf.so.0 are already loaded....gah.

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

*Needs Fixing*

You've tested and implemented the mir_surface_create() case, but not the mir_surface_apply_spec() case.

*Needs Discussion*

If we land 0.14 first (which means rebuilding all the downstreams to use libmirclient9) then we wouldn't need the large ugly hack. Right?

review: Needs Fixing
Revision history for this message
Chris Halse Rogers (raof) wrote :

I actually have implemented mir_surface_apply_spec, albeit negatively - any morph request into mir_surface_type_inputmethod will be denied (in FrontendShell), and you can't set a foreign parent for !mir_surface_type_inputmethod.

Now, as for the ‘can we get away without this’ question... I don't know. Once 0.14 has landed and we've rebuilt everything we own against libmirclient9 then this will pass CI without the RPC hack. I don't know whether it should or not, though.

Will *everything* definitely be rebuilt against libmirclient9? Will we need to backport any of this to vivid-overlay without rebuiling everything? Are there any third parties using libmirclient8?

Basically, do we have a requirement to not break things using libmirclient8? If yes, then we need the hack. If no, then we need to mark it as such by adding Breaks: libmirclient8 to libmirprotobuf0.

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

692 + // TODO: Fish out a policy verification object that enforces the various invariants
693 + // in the surface spec requirements (eg: regular surface has no parent,
694 + // dialog may have a parent, gloss must have a parent).

That's the WindowManager policy as already "fished out" of AbstractShell. FrontendShell is only responsible for mapping "frontend" concepts to "shell" concepts.

review: Needs Fixing
Revision history for this message
Alberto Aguirre (albaguirre) wrote :

We had a brief discussion on this - I'll make a 0.13.3 release that will include some version of this: https://code.launchpad.net/~albaguirre/mir/fix-1465883/+merge/262160
which will fix the original issue this branch had. Then no workarounds should be needed.

review: Needs Fixing
Revision history for this message
Alberto Aguirre (albaguirre) wrote :

mir 0.13.3 has landed, so you should be able to go back to r2526

Revision history for this message
Chris Halse Rogers (raof) wrote :

> 692 + // TODO: Fish out a policy verification object that enforces the
> various invariants
> 693 + // in the surface spec requirements (eg: regular surface
> has no parent,
> 694 + // dialog may have a parent, gloss must have a parent).
>
> That's the WindowManager policy as already "fished out" of AbstractShell.
> FrontendShell is only responsible for mapping "frontend" concepts to "shell"
> concepts.

Hm. I think either I'm misunderstanding the current state of the code, or you're misunderstanding my intent.

My understanding is that we want to provide the shell authors with surfaces that have some guaranteed properties - regular surfaces have no parent, gloss surfaces definitely have a parent, tooltip surfaces are not fullscreen, etc. Likewise we claim in the client library that various surface types must have certain properties.

My understanding is that the WindowManager policy is expected to be provided *by* the shell; it's therefore too late for us to guarantee that shells only see well-formed requests.

We used to provide these guarantees by making malformed requests inexpressible in the client API, but that's no longer the case. Is there anywhere else where we guarantee these invariants to the shell?

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Alberto Aguirre (albaguirre) wrote :

OK.

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

I abstain, but see we're ready for top approval now.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'include/client/mir_toolkit/mir_surface.h'
--- include/client/mir_toolkit/mir_surface.h 2015-06-17 05:20:42 +0000
+++ include/client/mir_toolkit/mir_surface.h 2015-06-29 06:21:38 +0000
@@ -416,6 +416,30 @@
416void mir_surface_spec_set_preferred_orientation(MirSurfaceSpec* spec, MirOrientationMode mode);416void mir_surface_spec_set_preferred_orientation(MirSurfaceSpec* spec, MirOrientationMode mode);
417417
418/**418/**
419 * Request that the created surface be attached to a surface of a different client.
420 *
421 * This is restricted to input methods, which need to attach their suggestion surface
422 * to text entry widgets of other processes.
423 *
424 * \param [in] spec Specification to mutate
425 * \param [in] parent A MirPersistentId reference to the parent surface
426 * \param [in] attachment_rect A rectangle specifying the region (in parent surface coordinates)
427 * that the created surface should be attached to.
428 * \param [in] edge The preferred edge direction to attach to. Use
429 * mir_edge_attachment_any for no preference.
430 * \return False if the operation is invalid for this surface type.
431 *
432 * \note If the parent surface becomes invalid before mir_surface_create() is processed,
433 * it will return an invalid surface. If the parent surface is valid at the time
434 * mir_surface_create() is called but is later closed, this surface will also receive
435 * a close event.
436 */
437bool mir_surface_spec_attach_to_foreign_parent(MirSurfaceSpec* spec,
438 MirPersistentId* parent,
439 MirRectangle* attachment_rect,
440 MirEdgeAttachment edge);
441
442/**
419 * Set the requested state.443 * Set the requested state.
420 * \param [in] spec Specification to mutate444 * \param [in] spec Specification to mutate
421 * \param [in] mode Requested state445 * \param [in] mode Requested state
@@ -694,6 +718,23 @@
694 */718 */
695void mir_persistent_id_release(MirPersistentId* id);719void mir_persistent_id_release(MirPersistentId* id);
696720
721/**
722 * \brief Get a string representation of a MirSurfaceId
723 * \param [in] id The ID to serialise
724 * \return A string representation of id. This string is owned by the MirSurfaceId,
725 * and must not be freed by the caller.
726 *
727 * \see mir_surface_id_from_string
728 */
729char const* mir_persistent_id_as_string(MirPersistentId* id);
730
731/**
732 * \brief Deserialise a string representation of a MirSurfaceId
733 * \param [in] string_representation Serialised representation of the ID
734 * \return The deserialised MirSurfaceId
735 */
736MirPersistentId* mir_persistent_id_from_string(char const* string_representation);
737
697#ifdef __cplusplus738#ifdef __cplusplus
698}739}
699/**@}*/740/**@}*/
700741
=== modified file 'src/client/mir_surface.cpp'
--- src/client/mir_surface.cpp 2015-06-17 18:24:42 +0000
+++ src/client/mir_surface.cpp 2015-06-29 06:21:38 +0000
@@ -107,6 +107,12 @@
107 if (parent.is_set() && parent.value() != nullptr)107 if (parent.is_set() && parent.value() != nullptr)
108 message->set_parent_id(parent.value()->id());108 message->set_parent_id(parent.value()->id());
109109
110 if (parent_id)
111 {
112 auto id = message->mutable_parent_persistent_id();
113 id->set_value(parent_id->as_string());
114 }
115
110 if (aux_rect.is_set())116 if (aux_rect.is_set())
111 {117 {
112 message->mutable_aux_rect()->set_left(aux_rect.value().left);118 message->mutable_aux_rect()->set_left(aux_rect.value().left);
@@ -648,6 +654,12 @@
648 if (spec.parent.is_set() && spec.parent.value())654 if (spec.parent.is_set() && spec.parent.value())
649 surface_specification->set_parent_id(spec.parent.value()->id());655 surface_specification->set_parent_id(spec.parent.value()->id());
650656
657 if (spec.parent_id)
658 {
659 auto id = surface_specification->mutable_parent_persistent_id();
660 id->set_value(spec.parent_id->as_string());
661 }
662
651 if (spec.aux_rect.is_set())663 if (spec.aux_rect.is_set())
652 {664 {
653 auto const rect = surface_specification->mutable_aux_rect();665 auto const rect = surface_specification->mutable_aux_rect();
654666
=== modified file 'src/client/mir_surface.h'
--- src/client/mir_surface.h 2015-06-17 18:24:42 +0000
+++ src/client/mir_surface.h 2015-06-29 06:21:38 +0000
@@ -86,6 +86,7 @@
86 mir::optional_value<MirOrientationMode> pref_orientation;86 mir::optional_value<MirOrientationMode> pref_orientation;
8787
88 mir::optional_value<MirSurface*> parent;88 mir::optional_value<MirSurface*> parent;
89 std::unique_ptr<MirPersistentId> parent_id;
89 mir::optional_value<MirRectangle> aux_rect;90 mir::optional_value<MirRectangle> aux_rect;
90 mir::optional_value<MirEdgeAttachment> edge_attachment;91 mir::optional_value<MirEdgeAttachment> edge_attachment;
9192
9293
=== modified file 'src/client/mir_surface_api.cpp'
--- src/client/mir_surface_api.cpp 2015-06-17 05:20:42 +0000
+++ src/client/mir_surface_api.cpp 2015-06-29 06:21:38 +0000
@@ -632,3 +632,33 @@
632{632{
633 delete id;633 delete id;
634}634}
635
636bool mir_surface_spec_attach_to_foreign_parent(MirSurfaceSpec* spec,
637 MirPersistentId* parent,
638 MirRectangle* attachment_rect,
639 MirEdgeAttachment edge)
640{
641 mir::require(mir_persistent_id_is_valid(parent));
642 mir::require(attachment_rect != nullptr);
643
644 if (!spec->type.is_set() ||
645 spec->type.value() != mir_surface_type_inputmethod)
646 {
647 return false;
648 }
649
650 spec->parent_id = std::make_unique<MirPersistentId>(*parent);
651 spec->aux_rect = *attachment_rect;
652 spec->edge_attachment = edge;
653 return true;
654}
655
656char const* mir_persistent_id_as_string(MirPersistentId *id)
657{
658 return id->as_string().c_str();
659}
660
661MirPersistentId* mir_persistent_id_from_string(char const* id_string)
662{
663 return new MirPersistentId{id_string};
664}
635665
=== modified file 'src/client/symbols.map'
--- src/client/symbols.map 2015-06-25 11:26:34 +0000
+++ src/client/symbols.map 2015-06-29 06:21:38 +0000
@@ -78,6 +78,8 @@
78 mir_omnidirectional_resize_cursor_name;78 mir_omnidirectional_resize_cursor_name;
79 mir_open_hand_cursor_name;79 mir_open_hand_cursor_name;
80 mir_orientation_event_get_direction;80 mir_orientation_event_get_direction;
81 mir_persistent_id_as_string;
82 mir_persistent_id_from_string;
81 mir_persistent_id_is_valid;83 mir_persistent_id_is_valid;
82 mir_persistent_id_release;84 mir_persistent_id_release;
83 mir_platform_message_create;85 mir_platform_message_create;
@@ -130,6 +132,7 @@
130 mir_surface_set_state;132 mir_surface_set_state;
131 mir_surface_set_swapinterval;133 mir_surface_set_swapinterval;
132 mir_surface_spec_release;134 mir_surface_spec_release;
135 mir_surface_spec_attach_to_foreign_parent;
133 mir_surface_spec_set_buffer_usage;136 mir_surface_spec_set_buffer_usage;
134 mir_surface_spec_set_fullscreen_on_output;137 mir_surface_spec_set_fullscreen_on_output;
135 mir_surface_spec_set_height;138 mir_surface_spec_set_height;
136139
=== modified file 'src/include/server/mir/frontend/shell.h'
--- src/include/server/mir/frontend/shell.h 2015-06-17 05:20:42 +0000
+++ src/include/server/mir/frontend/shell.h 2015-06-29 06:21:38 +0000
@@ -33,6 +33,7 @@
33{33{
34struct SurfaceCreationParameters;34struct SurfaceCreationParameters;
35struct PromptSessionCreationParameters;35struct PromptSessionCreationParameters;
36class Surface;
36}37}
37namespace shell { class SurfaceSpecification; }38namespace shell { class SurfaceSpecification; }
3839
@@ -63,7 +64,9 @@
63 virtual SurfaceId create_surface(std::shared_ptr<Session> const& session, scene::SurfaceCreationParameters const& params) = 0;64 virtual SurfaceId create_surface(std::shared_ptr<Session> const& session, scene::SurfaceCreationParameters const& params) = 0;
64 virtual void modify_surface(std::shared_ptr<Session> const& session, SurfaceId surface, shell::SurfaceSpecification const& modifications) = 0;65 virtual void modify_surface(std::shared_ptr<Session> const& session, SurfaceId surface, shell::SurfaceSpecification const& modifications) = 0;
65 virtual void destroy_surface(std::shared_ptr<Session> const& session, SurfaceId surface) = 0;66 virtual void destroy_surface(std::shared_ptr<Session> const& session, SurfaceId surface) = 0;
67
66 virtual std::string persistent_id_for(std::shared_ptr<Session> const& session, SurfaceId surface) = 0;68 virtual std::string persistent_id_for(std::shared_ptr<Session> const& session, SurfaceId surface) = 0;
69 virtual std::shared_ptr<scene::Surface> surface_for_id(std::string const& serialised_id) = 0;
6770
68 virtual int set_surface_attribute(71 virtual int set_surface_attribute(
69 std::shared_ptr<Session> const& session,72 std::shared_ptr<Session> const& session,
7073
=== modified file 'src/include/server/mir/frontend/template_protobuf_message_processor.h'
--- src/include/server/mir/frontend/template_protobuf_message_processor.h 2015-06-17 05:20:42 +0000
+++ src/include/server/mir/frontend/template_protobuf_message_processor.h 2015-06-29 06:21:38 +0000
@@ -27,6 +27,7 @@
27#include <boost/exception/diagnostic_information.hpp>27#include <boost/exception/diagnostic_information.hpp>
2828
29#include <memory>29#include <memory>
30#include <string>
3031
31namespace mir32namespace mir
32{33{
@@ -79,7 +80,9 @@
79 }80 }
80 catch (std::exception const& x)81 catch (std::exception const& x)
81 {82 {
82 result_message.set_error(boost::diagnostic_information(x));83 using namespace std::literals::string_literals;
84 result_message.set_error("Error processing request: "s +
85 x.what() + "\nInternal error details: " + boost::diagnostic_information(x));
83 self->send_response(invocation.id(), &result_message);86 self->send_response(invocation.id(), &result_message);
84 }87 }
85}88}
8689
=== modified file 'src/protobuf/mir_protobuf.proto'
--- src/protobuf/mir_protobuf.proto 2015-06-25 19:29:44 +0000
+++ src/protobuf/mir_protobuf.proto 2015-06-29 06:21:38 +0000
@@ -35,6 +35,8 @@
35 optional int32 height_inc = 18;35 optional int32 height_inc = 18;
36 optional SurfaceAspectRatio min_aspect = 19;36 optional SurfaceAspectRatio min_aspect = 19;
37 optional SurfaceAspectRatio max_aspect = 20;37 optional SurfaceAspectRatio max_aspect = 20;
38
39 optional PersistentSurfaceId parent_persistent_id = 21;
38}40}
3941
40message SurfaceAspectRatio42message SurfaceAspectRatio
@@ -63,11 +65,15 @@
63 optional int32 min_height = 14;65 optional int32 min_height = 14;
64 optional int32 max_width = 15;66 optional int32 max_width = 15;
65 optional int32 max_height = 16;67 optional int32 max_height = 16;
68
66 optional int32 width_inc = 17;69 optional int32 width_inc = 17;
67 optional int32 height_inc = 18;70 optional int32 height_inc = 18;
68 optional SurfaceAspectRatio min_aspect = 19;71 optional SurfaceAspectRatio min_aspect = 19;
69 optional SurfaceAspectRatio max_aspect = 20;72 optional SurfaceAspectRatio max_aspect = 20;
73
70 repeated StreamConfiguration stream = 21; 74 repeated StreamConfiguration stream = 21;
75
76 optional PersistentSurfaceId parent_persistent_id = 22;
71}77}
7278
73message StreamConfiguration {79message StreamConfiguration {
7480
=== modified file 'src/server/frontend/protobuf_message_processor.cpp'
--- src/server/frontend/protobuf_message_processor.cpp 2015-06-17 19:16:03 +0000
+++ src/server/frontend/protobuf_message_processor.cpp 2015-06-29 06:21:38 +0000
@@ -138,7 +138,9 @@
138 }138 }
139 catch (std::exception const& x)139 catch (std::exception const& x)
140 {140 {
141 result_message->set_error(boost::diagnostic_information(x));141 using namespace std::literals;
142 result_message->set_error("Error processing request: "s +
143 x.what() + "\nInternal error details: " + boost::diagnostic_information(x));
142 callback->Run();144 callback->Run();
143 }145 }
144}146}
145147
=== modified file 'src/server/frontend/session_mediator.cpp'
--- src/server/frontend/session_mediator.cpp 2015-06-19 12:35:35 +0000
+++ src/server/frontend/session_mediator.cpp 2015-06-29 06:21:38 +0000
@@ -203,6 +203,13 @@
203 if (request->has_parent_id())203 if (request->has_parent_id())
204 params.with_parent_id(SurfaceId{request->parent_id()});204 params.with_parent_id(SurfaceId{request->parent_id()});
205205
206
207 if (request->has_parent_persistent_id())
208 {
209 auto persistent_id = request->parent_persistent_id().value();
210 params.parent = shell->surface_for_id(persistent_id);
211 }
212
206 if (request->has_aux_rect())213 if (request->has_aux_rect())
207 {214 {
208 params.with_aux_rect(geom::Rectangle{215 params.with_aux_rect(geom::Rectangle{
209216
=== modified file 'src/server/frontend/shell_wrapper.cpp'
--- src/server/frontend/shell_wrapper.cpp 2015-06-17 05:20:42 +0000
+++ src/server/frontend/shell_wrapper.cpp 2015-06-29 06:21:38 +0000
@@ -19,6 +19,7 @@
19#include "shell_wrapper.h"19#include "shell_wrapper.h"
2020
21namespace mf = mir::frontend;21namespace mf = mir::frontend;
22namespace ms = mir::scene;
2223
23std::shared_ptr<mf::Session> mf::ShellWrapper::open_session(24std::shared_ptr<mf::Session> mf::ShellWrapper::open_session(
24 pid_t client_pid,25 pid_t client_pid,
@@ -73,6 +74,11 @@
73 return wrapped->persistent_id_for(session, surface);74 return wrapped->persistent_id_for(session, surface);
74}75}
7576
77std::shared_ptr<ms::Surface> mf::ShellWrapper::surface_for_id(std::string const& serialised_id)
78{
79 return wrapped->surface_for_id(serialised_id);
80}
81
76int mf::ShellWrapper::set_surface_attribute(82int mf::ShellWrapper::set_surface_attribute(
77 std::shared_ptr<Session> const& session,83 std::shared_ptr<Session> const& session,
78 SurfaceId surface_id,84 SurfaceId surface_id,
7985
=== modified file 'src/server/frontend/shell_wrapper.h'
--- src/server/frontend/shell_wrapper.h 2015-06-17 05:20:42 +0000
+++ src/server/frontend/shell_wrapper.h 2015-06-29 06:21:38 +0000
@@ -59,6 +59,8 @@
5959
60 std::string persistent_id_for(std::shared_ptr<Session> const& session, SurfaceId surface) override;60 std::string persistent_id_for(std::shared_ptr<Session> const& session, SurfaceId surface) override;
6161
62 std::shared_ptr<scene::Surface> surface_for_id(std::string const& serialised_id) override;
63
62 int set_surface_attribute(64 int set_surface_attribute(
63 std::shared_ptr<Session> const& session,65 std::shared_ptr<Session> const& session,
64 SurfaceId surface_id,66 SurfaceId surface_id,
6567
=== modified file 'src/server/shell/default_persistent_surface_store.cpp'
--- src/server/shell/default_persistent_surface_store.cpp 2015-05-29 03:30:25 +0000
+++ src/server/shell/default_persistent_surface_store.cpp 2015-06-29 06:21:38 +0000
@@ -87,5 +87,14 @@
8787
88std::shared_ptr<ms::Surface> msh::DefaultPersistentSurfaceStore::surface_for_id(Id const& id) const88std::shared_ptr<ms::Surface> msh::DefaultPersistentSurfaceStore::surface_for_id(Id const& id) const
89{89{
90 return (*store)[id];90 try
91 {
92 return (*store)[id];
93 }
94 catch (std::out_of_range& err)
95 {
96 using namespace std::literals;
97 BOOST_THROW_EXCEPTION(std::out_of_range(
98 "Lookup for surface with ID: "s + id.serialize_to_string() + " failed."));
99 }
91}100}
92101
=== modified file 'src/server/shell/frontend_shell.cpp'
--- src/server/shell/frontend_shell.cpp 2015-06-17 05:20:42 +0000
+++ src/server/shell/frontend_shell.cpp 2015-06-29 06:21:38 +0000
@@ -25,6 +25,8 @@
25#include "mir/scene/surface_creation_parameters.h"25#include "mir/scene/surface_creation_parameters.h"
26#include "mir/scene/prompt_session.h"26#include "mir/scene/prompt_session.h"
2727
28#include <boost/throw_exception.hpp>
29
28namespace mf = mir::frontend;30namespace mf = mir::frontend;
29namespace ms = mir::scene;31namespace ms = mir::scene;
30namespace msh = mir::shell::detail;32namespace msh = mir::shell::detail;
@@ -74,6 +76,15 @@
7476
75 auto populated_params = params;77 auto populated_params = params;
7678
79 // TODO: Fish out a policy verification object that enforces the various invariants
80 // in the surface spec requirements (eg: regular surface has no parent,
81 // dialog may have a parent, gloss must have a parent).
82 if (populated_params.parent.lock() &&
83 populated_params.type.value() != mir_surface_type_inputmethod)
84 {
85 BOOST_THROW_EXCEPTION(std::invalid_argument("Foreign parents may only be set on surfaces of type mir_surface_type_inputmethod"));
86 }
87
77 if (populated_params.parent_id.is_set())88 if (populated_params.parent_id.is_set())
78 populated_params.parent = scene_session->surface(populated_params.parent_id.value());89 populated_params.parent = scene_session->surface(populated_params.parent_id.value());
7990
@@ -107,6 +118,12 @@
107 return surface_store->id_for_surface(surface).serialize_to_string();118 return surface_store->id_for_surface(surface).serialize_to_string();
108}119}
109120
121std::shared_ptr<ms::Surface> msh::FrontendShell::surface_for_id(std::string const& serialized_id)
122{
123 PersistentSurfaceStore::Id const id{serialized_id};
124 return surface_store->surface_for_id(id);
125}
126
110int msh::FrontendShell::set_surface_attribute(127int msh::FrontendShell::set_surface_attribute(
111 std::shared_ptr<mf::Session> const& session,128 std::shared_ptr<mf::Session> const& session,
112 mf::SurfaceId surface_id,129 mf::SurfaceId surface_id,
113130
=== modified file 'src/server/shell/frontend_shell.h'
--- src/server/shell/frontend_shell.h 2015-06-17 05:20:42 +0000
+++ src/server/shell/frontend_shell.h 2015-06-29 06:21:38 +0000
@@ -71,6 +71,8 @@
7171
72 std::string persistent_id_for(std::shared_ptr<mf::Session> const& session, mf::SurfaceId surface) override;72 std::string persistent_id_for(std::shared_ptr<mf::Session> const& session, mf::SurfaceId surface) override;
7373
74 std::shared_ptr<ms::Surface> surface_for_id(std::string const& serialized_id) override;
75
74 int set_surface_attribute(76 int set_surface_attribute(
75 std::shared_ptr<mf::Session> const& session,77 std::shared_ptr<mf::Session> const& session,
76 mf::SurfaceId surface_id,78 mf::SurfaceId surface_id,
7779
=== modified file 'tests/acceptance-tests/test_client_library.cpp'
--- tests/acceptance-tests/test_client_library.cpp 2015-06-25 21:34:27 +0000
+++ tests/acceptance-tests/test_client_library.cpp 2015-06-29 06:21:38 +0000
@@ -913,3 +913,48 @@
913 mir_persistent_id_release(surface_id);913 mir_persistent_id_release(surface_id);
914 mir_connection_release(connection);914 mir_connection_release(connection);
915}915}
916
917TEST_F(ClientLibrary, input_method_can_specify_foreign_surface_id)
918{
919 auto first_client = mir_connect_sync(new_connection().c_str(), "Regular Client");
920
921 auto surface_spec = mir_connection_create_spec_for_normal_surface(first_client,
922 800, 600,
923 mir_pixel_format_argb_8888);
924 auto main_surface = mir_surface_create_sync(surface_spec);
925 mir_surface_spec_release(surface_spec);
926
927 ASSERT_THAT(main_surface, IsValid());
928
929 auto main_surface_id = mir_surface_request_persistent_id_sync(main_surface);
930 ASSERT_TRUE(mir_persistent_id_is_valid(main_surface_id));
931
932 // Serialise & deserialise the ID
933 auto im_parent_id = mir_persistent_id_from_string(mir_persistent_id_as_string(main_surface_id));
934
935 auto im_client = mir_connect_sync(new_connection().c_str(), "IM Client");
936 surface_spec = mir_connection_create_spec_for_input_method(im_client,
937 200, 20,
938 mir_pixel_format_argb_8888);
939 MirRectangle attachment_rect {
940 200,
941 200,
942 10,
943 10
944 };
945 mir_surface_spec_attach_to_foreign_parent(surface_spec,
946 im_parent_id,
947 &attachment_rect,
948 mir_edge_attachment_any);
949 auto im_surface = mir_surface_create_sync(surface_spec);
950
951 EXPECT_THAT(im_surface, IsValid());
952
953 mir_surface_spec_release(surface_spec);
954 mir_persistent_id_release(main_surface_id);
955 mir_persistent_id_release(im_parent_id);
956 mir_surface_release_sync(main_surface);
957 mir_surface_release_sync(im_surface);
958 mir_connection_release(first_client);
959 mir_connection_release(im_client);
960}
916961
=== modified file 'tests/acceptance-tests/test_client_library_errors.cpp'
--- tests/acceptance-tests/test_client_library_errors.cpp 2015-06-25 03:00:08 +0000
+++ tests/acceptance-tests/test_client_library_errors.cpp 2015-06-29 06:21:38 +0000
@@ -247,6 +247,38 @@
247 mir_connection_release(connection);247 mir_connection_release(connection);
248}248}
249249
250TEST_F(ClientLibraryErrors, passing_invalid_parent_id_to_surface_create)
251{
252 using namespace testing;
253
254 auto connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__);
255
256 ASSERT_THAT(connection, IsValid());
257
258 // An ID that parses as valid, but doesn't correspond to any
259 auto invalid_id = mir_persistent_id_from_string("05f223a2-39e5-48b9-9416-b0ce837351b6");
260
261 auto spec = mir_connection_create_spec_for_input_method(connection,
262 200, 200,
263 mir_pixel_format_argb_8888);
264 MirRectangle rect{
265 100,
266 100,
267 10,
268 10
269 };
270 mir_surface_spec_attach_to_foreign_parent(spec, invalid_id, &rect, mir_edge_attachment_any);
271
272 auto surface = mir_surface_create_sync(spec);
273 EXPECT_THAT(surface, Not(IsValid()));
274 EXPECT_THAT(mir_surface_get_error_message(surface), MatchesRegex(".*Lookup.*failed.*"));
275
276 mir_persistent_id_release(invalid_id);
277 mir_surface_spec_release(spec);
278 mir_surface_release_sync(surface);
279 mir_connection_release(connection);
280}
281
250using ClientLibraryErrorsDeathTest = ClientLibraryErrors;282using ClientLibraryErrorsDeathTest = ClientLibraryErrors;
251283
252284
@@ -287,3 +319,34 @@
287319
288 mir_connection_release(connection);320 mir_connection_release(connection);
289}321}
322
323TEST_F(ClientLibraryErrorsDeathTest, surface_spec_attaching_invalid_parent_id)
324{
325 auto connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__);
326
327 auto spec = mir_connection_create_spec_for_input_method(connection, 100, 100, mir_pixel_format_argb_8888);
328
329 MirRectangle rect{
330 100,
331 100,
332 10,
333 10
334 };
335 EXPECT_DEATH(mir_surface_spec_attach_to_foreign_parent(spec, nullptr, &rect, mir_edge_attachment_any), "");
336
337 mir_connection_release(connection);
338}
339
340TEST_F(ClientLibraryErrorsDeathTest, surface_spec_attaching_invalid_rectangle)
341{
342 auto connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__);
343
344 auto spec = mir_connection_create_spec_for_input_method(connection, 100, 100, mir_pixel_format_argb_8888);
345
346 auto id = mir_persistent_id_from_string("fa69b2e9-d507-4005-be61-5068f40a5aec");
347
348 EXPECT_DEATH(mir_surface_spec_attach_to_foreign_parent(spec, id, nullptr, mir_edge_attachment_any), "");
349
350 mir_persistent_id_release(id);
351 mir_connection_release(connection);
352}
290353
=== modified file 'tests/acceptance-tests/test_client_surfaces.cpp'
--- tests/acceptance-tests/test_client_surfaces.cpp 2015-06-25 03:00:08 +0000
+++ tests/acceptance-tests/test_client_surfaces.cpp 2015-06-29 06:21:38 +0000
@@ -19,9 +19,15 @@
19#include "mir_toolkit/mir_client_library.h"19#include "mir_toolkit/mir_client_library.h"
20#include "mir_toolkit/debug/surface.h"20#include "mir_toolkit/debug/surface.h"
2121
22#include "mir/test/doubles/mock_window_manager.h"
23
24#include "mir/scene/session.h"
25#include "mir/geometry/rectangle.h"
26
22#include "mir_test_framework/connected_client_headless_server.h"27#include "mir_test_framework/connected_client_headless_server.h"
23#include "mir_test_framework/any_surface.h"28#include "mir_test_framework/any_surface.h"
24#include "mir/test/validity_matchers.h"29#include "mir/test/validity_matchers.h"
30#include "mir/test/fake_shared.h"
2531
26#include <gmock/gmock.h>32#include <gmock/gmock.h>
27#include <gtest/gtest.h>33#include <gtest/gtest.h>
@@ -30,6 +36,11 @@
30#include <mutex>36#include <mutex>
3137
32namespace mtf = mir_test_framework;38namespace mtf = mir_test_framework;
39namespace mtd = mir::test::doubles;
40namespace msh = mir::shell;
41namespace ms = mir::scene;
42namespace mt = mir::test;
43namespace mg = mir::geometry;
3344
34namespace45namespace
35{46{
@@ -79,6 +90,17 @@
79 mir_buffer_usage_hardware,90 mir_buffer_usage_hardware,
80 mir_display_output_id_invalid91 mir_display_output_id_invalid
81 };92 };
93
94 void SetUp() override
95 {
96 server.override_the_window_manager_builder([this](msh::FocusController*)
97 {
98 return mt::fake_shared(window_manager);
99 });
100 ConnectedClientHeadlessServer::SetUp();
101 }
102
103 testing::NiceMock<mtd::MockWindowManager> window_manager;
82};104};
83105
84extern "C" void create_surface_callback(MirSurface* surface, void * context)106extern "C" void create_surface_callback(MirSurface* surface, void * context)
@@ -328,3 +350,55 @@
328350
329 mir_surface_release_sync(surf);351 mir_surface_release_sync(surf);
330}352}
353
354TEST_F(ClientSurfaces, input_methods_get_corret_parent_coordinates)
355{
356 using namespace testing;
357
358 mg::Rectangle const server_rect{mg::Point{100, 100}, mg::Size{10, 10}};
359 MirRectangle client_rect{ 100, 100, 10, 10 };
360
361 auto const edge_attachment = mir_edge_attachment_vertical;
362
363 std::shared_ptr<ms::Surface> parent_surface;
364 InSequence seq;
365 EXPECT_CALL(window_manager, add_surface(_,_,_)).WillOnce(Invoke([&parent_surface](auto session, auto params, auto builder)
366 {
367 auto id = builder(session, params);
368 parent_surface = session->surface(id);
369 return id;
370 }));
371 EXPECT_CALL(window_manager, add_surface(_,_,_)).WillOnce(Invoke([&parent_surface, server_rect, edge_attachment](auto session, auto params, auto builder)
372 {
373 EXPECT_THAT(params.parent.lock(), Eq(parent_surface));
374 EXPECT_TRUE(params.aux_rect.is_set());
375 EXPECT_THAT(params.aux_rect.value(), Eq(server_rect));
376 EXPECT_TRUE(params.edge_attachment.is_set());
377 EXPECT_THAT(params.edge_attachment.value(), Eq(edge_attachment));
378
379 return builder(session, params);
380 }));
381
382 auto surface = mtf::make_any_surface(connection);
383
384 auto parent_id = mir_surface_request_persistent_id_sync(surface);
385
386 auto im_connection = mir_connect_sync(new_connection().c_str(), "Mock IM connection");
387 ASSERT_THAT(im_connection, IsValid());
388
389 auto spec = mir_connection_create_spec_for_input_method(im_connection, 100, 20,
390 mir_pixel_format_abgr_8888);
391 ASSERT_THAT(spec, NotNull());
392
393 mir_surface_spec_attach_to_foreign_parent(spec, parent_id, &client_rect, edge_attachment);
394
395 mir_persistent_id_release(parent_id);
396
397 auto im = mir_surface_create_sync(spec);
398 mir_surface_spec_release(spec);
399
400 mir_surface_release_sync(im);
401 mir_surface_release_sync(surface);
402
403 mir_connection_release(im_connection);
404}
331405
=== modified file 'tests/include/mir/test/doubles/mock_shell.h'
--- tests/include/mir/test/doubles/mock_shell.h 2015-06-17 05:20:42 +0000
+++ tests/include/mir/test/doubles/mock_shell.h 2015-06-29 06:21:38 +0000
@@ -55,6 +55,8 @@
55 MOCK_METHOD3(modify_surface, void(std::shared_ptr<frontend::Session> const&, frontend::SurfaceId, shell::SurfaceSpecification const&));55 MOCK_METHOD3(modify_surface, void(std::shared_ptr<frontend::Session> const&, frontend::SurfaceId, shell::SurfaceSpecification const&));
56 MOCK_METHOD2(destroy_surface, void(std::shared_ptr<frontend::Session> const&, frontend::SurfaceId));56 MOCK_METHOD2(destroy_surface, void(std::shared_ptr<frontend::Session> const&, frontend::SurfaceId));
57 MOCK_METHOD2(persistent_id_for, std::string(std::shared_ptr<frontend::Session> const&, frontend::SurfaceId));57 MOCK_METHOD2(persistent_id_for, std::string(std::shared_ptr<frontend::Session> const&, frontend::SurfaceId));
58 MOCK_METHOD1(surface_for_id, std::shared_ptr<scene::Surface>(std::string const&));
59
5860
5961
60 MOCK_METHOD4(set_surface_attribute, int(62 MOCK_METHOD4(set_surface_attribute, int(

Subscribers

People subscribed via source and target branches