diff options
author | Marius Vlad <marius.vlad@collabora.com> | 2020-09-15 18:12:24 +0300 |
---|---|---|
committer | Jan-Simon Moeller <jsmoeller@linuxfoundation.org> | 2020-09-30 13:43:12 +0000 |
commit | 991714fc7f92aea3d07c7225247a821e3461027e (patch) | |
tree | 9054e78451203614aaf190c1a9a30e3d2bc49be1 | |
parent | 1f888f2050ac50ec8c1750ff4f0e2c485936d7ed (diff) |
screenshooter: Add agl-screenshooter protocol
Just like weston, we add a private protocol. Underneath we make use of
the weston renderer to get a hold of the pixels and transfer them to a
user-supplied buffer. This only brings up the server side implementation
of the protocol.
Bug-AGL: SPEC-3580
Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
Change-Id: I02a07ad5eb492ef2ecad74efb34d1453ebcbedc0
-rw-r--r-- | meson.build | 5 | ||||
-rw-r--r-- | protocol/agl-screenshooter.xml | 84 | ||||
-rw-r--r-- | src/ivi-compositor.h | 2 | ||||
-rw-r--r-- | src/main.c | 1 | ||||
-rw-r--r-- | src/screenshooter.c | 137 |
5 files changed, 229 insertions, 0 deletions
diff --git a/meson.build b/meson.build index 9dd9673..4299d58 100644 --- a/meson.build +++ b/meson.build @@ -65,11 +65,13 @@ endforeach agl_shell_xml = files('protocol/agl-shell.xml') agl_shell_desktop_xml = files('protocol/agl-shell-desktop.xml') +agl_screenshooter = files('protocol/agl-screenshooter.xml') xdg_shell_xml = join_paths(dir_wp_base, 'stable', 'xdg-shell', 'xdg-shell.xml') protocols = [ { 'name': 'agl-shell', 'source': 'internal' }, { 'name': 'agl-shell-desktop', 'source': 'internal' }, + { 'name': 'agl-screenshooter', 'source': 'internal' }, { 'name': 'xdg-shell', 'source': 'wp-stable' }, ] @@ -140,12 +142,15 @@ srcs_agl_compositor = [ 'src/layout.c', 'src/policy.c', 'src/shell.c', + 'src/screenshooter.c', 'shared/option-parser.c', 'shared/os-compatibility.c', agl_shell_server_protocol_h, agl_shell_desktop_server_protocol_h, + agl_screenshooter_server_protocol_h, agl_shell_protocol_c, agl_shell_desktop_protocol_c, + agl_screenshooter_protocol_c, xdg_shell_protocol_c, ] diff --git a/protocol/agl-screenshooter.xml b/protocol/agl-screenshooter.xml new file mode 100644 index 0000000..6ed1457 --- /dev/null +++ b/protocol/agl-screenshooter.xml @@ -0,0 +1,84 @@ +<?xml version="1.0" encoding="UTF-8"?> +<protocol name="agl_screenshooter"> + + <copyright> + Copyright © 2020 Collabora. Ltd, + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice (including the next + paragraph) shall be included in all copies or substantial portions of the + Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + </copyright> + + <interface name="agl_screenshooter" version="1"> + <description summary="agl screenshooter"> + agl compositor extension that performs a screenshot of the output, which + is represented by a 'wl_output' object. + + A client would call 'take_shot' request and wait until the compositor + finishes to write the data to a wayland buffer, moment in which signals + back the client with the help of the 'done' event. Clients should wait + until the 'done' event is received, if they want to take another + screenshot, or take another screnshot of a different output. + + The client must provide a wl_shm-based wl_buffer of the correct size when + taking a shot. The compositor will write the shot into the wl_buffer and then + send the 'done' event that signals completion of writing the data. + + Once the compositor has finished to transfer the data back into the supplied + wayland buffer, the client should be able to transfer it to a popular + file format on the disk. + </description> + + <enum name="done_status"> + <entry name="success" value="0"/> + <entry name="no_memory" value="1"/> + <entry name="bad_buffer" value="2"/> + </enum> + + <request name="take_shot"> + <description summary="performs a screenshot"> + Takes a screenshot of the wayland output represented by a 'wl_output' + object. Clients should first retrieve it using global registry, as well + as the 'wl_shm' object in order to create a wayland buffer type of + object ('wl_buffer'). + + Clients can derive the stride and size from the 'wl_output' object, and + later on use those when creating shm-based 'wl_buffer', as well as supplying + the pixel format. + </description> + + <arg name="output" type="object" interface="wl_output"/> + <arg name="buffer" type="object" interface="wl_buffer"/> + </request> + + <event name="done"> + <description summary="sent when 'take_shot' finished"> + Even sent back to nofify client 'take_shot' request has completed. + </description> + <arg name="status" type="uint" enum="done_status" /> + </event> + + <request name="destroy" type="destructor"> + <description summary="destroy main object"> + Destroys the 'weston_screenshooter' interface. + </description> + </request> + + </interface> + +</protocol> diff --git a/src/ivi-compositor.h b/src/ivi-compositor.h index 6969a7d..4506a5a 100644 --- a/src/ivi-compositor.h +++ b/src/ivi-compositor.h @@ -377,5 +377,7 @@ ivi_layout_find_with_app_id(const char *app_id, struct ivi_compositor *ivi); void shell_advertise_app_state(struct ivi_compositor *ivi, const char *app_id, const char *data, uint32_t app_state); +void +ivi_screenshooter_create(struct ivi_compositor *ivi); #endif @@ -1493,6 +1493,7 @@ int main(int argc, char *argv[]) ivi_shell_create_global(&ivi); ivi_launch_shell_client(&ivi); + ivi_screenshooter_create(&ivi); ivi_agl_systemd_notify(&ivi); wl_display_run(display); diff --git a/src/screenshooter.c b/src/screenshooter.c new file mode 100644 index 0000000..ef3d32e --- /dev/null +++ b/src/screenshooter.c @@ -0,0 +1,137 @@ +/* + * Copyright © 2020 Collabora, Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "ivi-compositor.h" +#include "shared/helpers.h" + +#include <libweston/libweston.h> +#include "agl-screenshooter-server-protocol.h" +#include <libweston/weston-log.h> + +struct screenshooter { + struct ivi_compositor *ivi; + struct wl_global *global; + struct wl_client *client; + struct wl_listener destroy_listener; +}; + +static void +screenshooter_done(void *data, enum weston_screenshooter_outcome outcome) +{ + struct wl_resource *resource = data; + + if (outcome == WESTON_SCREENSHOOTER_NO_MEMORY) { + wl_resource_post_no_memory(resource); + return; + } + + agl_screenshooter_send_done(resource, outcome); +} + +static void +screenshooter_shoot(struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *output_resource, + struct wl_resource *buffer_resource) +{ + struct weston_output *output = + weston_head_from_resource(output_resource)->output; + struct weston_buffer *buffer = + weston_buffer_from_resource(buffer_resource); + + if (buffer == NULL) { + wl_resource_post_no_memory(resource); + return; + } + + weston_screenshooter_shoot(output, buffer, screenshooter_done, resource); +} + +static void +screenshooter_destructor_destroy(struct wl_client *client, + struct wl_resource *global_resource) +{ + wl_resource_destroy(global_resource); +} + +struct agl_screenshooter_interface screenshooter_implementation = { + screenshooter_shoot, + screenshooter_destructor_destroy +}; + +static void +bind_shooter(struct wl_client *client, + void *data, uint32_t version, uint32_t id) +{ + struct screenshooter *shooter = data; + struct wl_resource *resource; + bool debug_enabled = true; + + resource = wl_resource_create(client, + &agl_screenshooter_interface, 1, id); + + if (!debug_enabled && !shooter->client) { + wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT, + "screenshooter failed: permission denied. "\ + "Debug must be enabled"); + return; + } + + wl_resource_set_implementation(resource, &screenshooter_implementation, + data, NULL); +} + +static void +screenshooter_destroy(struct wl_listener *listener, void *data) +{ + struct screenshooter *shooter = + container_of(listener, struct screenshooter, destroy_listener); + + wl_list_remove(&shooter->destroy_listener.link); + + wl_global_destroy(shooter->global); + free(shooter); +} + +void +ivi_screenshooter_create(struct ivi_compositor *ivi) +{ + struct weston_compositor *ec = ivi->compositor; + struct screenshooter *shooter; + + shooter = zalloc(sizeof(*shooter)); + if (shooter == NULL) + return; + + shooter->ivi = ivi; + shooter->global = wl_global_create(ec->wl_display, + &agl_screenshooter_interface, 1, + shooter, bind_shooter); + + shooter->destroy_listener.notify = screenshooter_destroy; + wl_signal_add(&ec->destroy_signal, &shooter->destroy_listener); + + weston_log("Screenshooter interface created\n"); +} |