screenshooter: Add agl-screenshooter protocol 00/25300/2
authorMarius Vlad <marius.vlad@collabora.com>
Tue, 15 Sep 2020 15:12:24 +0000 (18:12 +0300)
committerJan-Simon Moeller <jsmoeller@linuxfoundation.org>
Wed, 30 Sep 2020 13:43:12 +0000 (13:43 +0000)
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

meson.build
protocol/agl-screenshooter.xml [new file with mode: 0644]
src/ivi-compositor.h
src/main.c
src/screenshooter.c [new file with mode: 0644]

index 9dd9673..4299d58 100644 (file)
@@ -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 (file)
index 0000000..6ed1457
--- /dev/null
@@ -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>
index 6969a7d..4506a5a 100644 (file)
@@ -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
index 99512d5..164b45b 100644 (file)
@@ -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 (file)
index 0000000..ef3d32e
--- /dev/null
@@ -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");
+}