diff options
-rw-r--r-- | protocol/agl-shell.xml | 49 | ||||
-rw-r--r-- | src/desktop.c | 24 | ||||
-rw-r--r-- | src/ivi-compositor.h | 6 | ||||
-rw-r--r-- | src/shell.c | 75 |
4 files changed, 142 insertions, 12 deletions
diff --git a/protocol/agl-shell.xml b/protocol/agl-shell.xml index 11a65a1..4ab71af 100644 --- a/protocol/agl-shell.xml +++ b/protocol/agl-shell.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <protocol name="agl_shell"> <copyright> - Copyright © 2019 Collabora, Ltd. + Copyright © 2019, 2022 Collabora, Ltd. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -22,8 +22,29 @@ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. </copyright> - <interface name="agl_shell" version="1"> - <description summary="user interface for weston-ivi"> + <interface name="agl_shell" version="2"> + <description summary="user interface for Automotive Grade Linux platform"> + Starting with version 2 of the protocol, the client is required to wait + for the 'bound_ok' or 'bound_fail' events in order to proceed further. + + In case the client gets a 'bound_fail' event then it should consider that + there's another client already bound to the agl_shell protocol. + A client that receives a 'bound_ok' event should consider that there's + no other client already bound to the interface and can proceed further. + + If the client uses an older version of the protocol it will receive + automatically an error and the compositor will terminate the connection, + if there's another client already bound the interface. + + If the client receives the 'bound_fail' event and attempts to use the + interface further it will receive an error and the compositor will + terminate the connection. After the 'bound_fail' event was received the + client should call the destructor, which has been added with version 2 + of the protocol. The client is free to try at a later point in time to + see if it will receive the 'bound_ok' event, but there's no explicit way + of finding out when that event will be delivered. + It is assumed that it can infer that information through other + means/other channels. </description> <enum name="error"> @@ -113,5 +134,27 @@ <arg name="app_id" type="string"/> <arg name="output" type="object" interface="wl_output"/> </request> + + <event name="bound_ok" since="2"> + <description summary="event sent if binding was ok"> + Informs the client that it was able to bind the agl_shell + interface succesfully. Clients are required to wait for this + event before continuing further. + </description> + </event> + + <event name="bound_fail" since="2"> + <description summary="event sent if binding was nok"> + Informs the client that binding to the agl_shell interface was + unsuccesfull. Clients are required to wait for this event for + continuing further. + </description> + </event> + + <request name="destroy" type="destructor" since="2"> + <description summary="destroys the factory object"> + </description> + </request> + </interface> </protocol> diff --git a/src/desktop.c b/src/desktop.c index b2907fe..1351508 100644 --- a/src/desktop.c +++ b/src/desktop.c @@ -164,6 +164,14 @@ desktop_surface_added(struct weston_desktop_surface *dsurface, void *userdata) dclient = weston_desktop_surface_get_client(dsurface); client = weston_desktop_client_get_client(dclient); + if (ivi->shell_client.resource && + ivi->shell_client.status == BOUND_FAILED) { + wl_client_post_implementation_error(client, + "agl_shell has already been bound. " + "Check out bound_fail event"); + return; + } + surface = zalloc(sizeof *surface); if (!surface) { wl_client_post_no_memory(client); @@ -250,10 +258,20 @@ desktop_surface_removed(struct weston_desktop_surface *dsurface, void *userdata) struct weston_surface *wsurface = weston_desktop_surface_get_surface(dsurface); const char *app_id = NULL; - struct weston_seat *wseat = get_ivi_shell_weston_first_seat(surface->ivi); - struct ivi_shell_seat *ivi_seat = get_ivi_shell_seat(wseat); + struct weston_seat *wseat = NULL; + struct ivi_shell_seat *ivi_seat = NULL; + struct ivi_output *output = NULL; + + /* we might not have a valid ivi_surface if _added failed due to + * protocol errors */ + if (!surface) + return; + + wseat = get_ivi_shell_weston_first_seat(surface->ivi); + if (wseat) + ivi_seat = get_ivi_shell_seat(wseat); - struct ivi_output *output = ivi_layout_get_output_from_surface(surface); + output = ivi_layout_get_output_from_surface(surface); wl_list_remove(&surface->listener_advertise_app.link); surface->listener_advertise_app.notify = NULL; diff --git a/src/ivi-compositor.h b/src/ivi-compositor.h index 78d1acd..dff11b9 100644 --- a/src/ivi-compositor.h +++ b/src/ivi-compositor.h @@ -46,6 +46,11 @@ struct desktop_client { struct wl_list link; /* ivi_compositor::desktop_clients */ }; +enum agl_shell_bound_status { + BOUND_OK, + BOUND_FAILED, +}; + struct ivi_compositor { struct weston_compositor *compositor; struct weston_config *config; @@ -81,6 +86,7 @@ struct ivi_compositor { struct wl_client *client; struct wl_resource *resource; bool ready; + enum agl_shell_bound_status status; } shell_client; struct wl_list desktop_clients; /* desktop_client::link */ diff --git a/src/shell.c b/src/shell.c index dc07c26..28c1117 100644 --- a/src/shell.c +++ b/src/shell.c @@ -1017,10 +1017,20 @@ shell_ready(struct wl_client *client, struct wl_resource *shell_res) struct ivi_output *output; struct ivi_surface *surface, *tmp; + if (ivi->shell_client.resource && + ivi->shell_client.status == BOUND_FAILED) { + wl_resource_post_error(shell_res, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "agl_shell has already been bound. " + "Check out bound_fail event"); + return; + } + /* Init already finished. Do nothing */ if (ivi->shell_client.ready) return; + ivi->shell_client.ready = true; wl_list_for_each(output, &ivi->outputs, link) { @@ -1047,9 +1057,19 @@ shell_set_background(struct wl_client *client, struct weston_output *woutput = weston_head_get_output(head); struct ivi_output *output = to_ivi_output(woutput); struct weston_surface *wsurface = wl_resource_get_user_data(surface_res); + struct ivi_compositor *ivi = wl_resource_get_user_data(shell_res); struct weston_desktop_surface *dsurface; struct ivi_surface *surface; + if (ivi->shell_client.resource && + ivi->shell_client.status == BOUND_FAILED) { + wl_resource_post_error(shell_res, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "agl_shell has already been bound. " + "Check out bound_fail event"); + return; + } + dsurface = weston_surface_get_desktop_surface(wsurface); if (!dsurface) { wl_resource_post_error(shell_res, @@ -1098,11 +1118,21 @@ shell_set_panel(struct wl_client *client, struct weston_output *woutput = weston_head_get_output(head); struct ivi_output *output = to_ivi_output(woutput); struct weston_surface *wsurface = wl_resource_get_user_data(surface_res); + struct ivi_compositor *ivi = wl_resource_get_user_data(shell_res); struct weston_desktop_surface *dsurface; struct ivi_surface *surface; struct ivi_surface **member; int32_t width = 0, height = 0; + if (ivi->shell_client.resource && + ivi->shell_client.status == BOUND_FAILED) { + wl_resource_post_error(shell_res, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "agl_shell has already been bound. " + "Check out bound_fail event"); + return; + } + dsurface = weston_surface_get_desktop_surface(wsurface); if (!dsurface) { wl_resource_post_error(shell_res, @@ -1208,8 +1238,18 @@ shell_activate_app(struct wl_client *client, { struct weston_head *head = weston_head_from_resource(output_res); struct weston_output *woutput = weston_head_get_output(head); + struct ivi_compositor *ivi = wl_resource_get_user_data(shell_res); struct ivi_output *output = to_ivi_output(woutput); + if (ivi->shell_client.resource && + ivi->shell_client.status == BOUND_FAILED) { + wl_resource_post_error(shell_res, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "agl_shell has already been bound. " + "Check out bound_fail event"); + return; + } + ivi_layout_activate(output, app_id); } @@ -1241,7 +1281,14 @@ shell_deactivate_app(struct wl_client *client, NULL, AGL_SHELL_DESKTOP_APP_STATE_DEACTIVATED); } +/* stub, no usage for the time being */ +static void +shell_destroy(struct wl_client *client, struct wl_resource *res) +{ +} + static const struct agl_shell_interface agl_shell_implementation = { + .destroy = shell_destroy, .ready = shell_ready, .set_background = shell_set_background, .set_panel = shell_set_panel, @@ -1334,6 +1381,14 @@ unbind_agl_shell(struct wl_resource *resource) struct ivi_surface *surf, *surf_tmp; ivi = wl_resource_get_user_data(resource); + + /* reset status to allow other clients issue legit requests */ + if (ivi->shell_client.resource && + ivi->shell_client.status == BOUND_FAILED) { + ivi->shell_client.status = BOUND_OK; + return; + } + wl_list_for_each(output, &ivi->outputs, link) { /* reset the active surf if there's one present */ if (output->active) { @@ -1383,22 +1438,30 @@ bind_agl_shell(struct wl_client *client, return; } - resource = wl_resource_create(client, &agl_shell_interface, - 1, id); + resource = wl_resource_create(client, &agl_shell_interface, version, id); if (!resource) { wl_client_post_no_memory(client); return; } if (ivi->shell_client.resource) { - wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT, - "agl_shell has already been bound"); - return; + if (wl_resource_get_version(resource) == 1) { + wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT, + "agl_shell has already been bound"); + return; + } + + agl_shell_send_bound_fail(resource); + ivi->shell_client.status = BOUND_FAILED; } wl_resource_set_implementation(resource, &agl_shell_implementation, ivi, unbind_agl_shell); ivi->shell_client.resource = resource; + + if (ivi->shell_client.status == BOUND_OK && + wl_resource_get_version(resource) >= AGL_SHELL_BOUND_OK_SINCE_VERSION) + agl_shell_send_bound_ok(ivi->shell_client.resource); } static void @@ -1457,7 +1520,7 @@ int ivi_shell_create_global(struct ivi_compositor *ivi) { ivi->agl_shell = wl_global_create(ivi->compositor->wl_display, - &agl_shell_interface, 1, + &agl_shell_interface, 2, ivi, bind_agl_shell); if (!ivi->agl_shell) { weston_log("Failed to create wayland global.\n"); |