Remove orbital screenshooter and gamma-control

These are undocumented, outdated protocols that have a better wlr-protocols
equivalent.
This commit is contained in:
Simon Ser 2019-06-02 13:37:34 +03:00 committed by Drew DeVault
parent abddd7b4db
commit 3dec88e455
13 changed files with 0 additions and 838 deletions

View File

@ -53,10 +53,6 @@ examples = {
'src': ['output-layout.c', 'cat.c'],
'dep': [wlroots],
},
'screenshot': {
'src': 'screenshot.c',
'dep': [wayland_client, wlr_protos, rt],
},
'idle': {
'src': 'idle.c',
'dep': [wayland_client, wlr_protos, threads],

View File

@ -1,237 +0,0 @@
/*
* Copyright © 2008 Kristian Høgsberg
*
* 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.
*/
#define _POSIX_C_SOURCE 200112L
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/param.h>
#include <sys/wait.h>
#include <unistd.h>
#include <wayland-client.h>
#include "screenshooter-client-protocol.h"
static struct wl_shm *shm = NULL;
static struct orbital_screenshooter *screenshooter = NULL;
static struct wl_list output_list;
static bool buffer_copy_done;
struct screenshooter_output {
struct wl_output *output;
int width, height;
struct wl_list link;
};
static void output_handle_geometry(void *data, struct wl_output *wl_output,
int x, int y, int physical_width, int physical_height, int subpixel,
const char *make, const char *model, int transform) {
// No-op
}
static void output_handle_mode(void *data, struct wl_output *wl_output,
uint32_t flags, int width, int height, int refresh) {
struct screenshooter_output *output = wl_output_get_user_data(wl_output);
if (wl_output == output->output && (flags & WL_OUTPUT_MODE_CURRENT)) {
output->width = width;
output->height = height;
}
}
static void output_handle_done(void *data, struct wl_output *wl_output) {
// No-op
}
static const struct wl_output_listener output_listener = {
.geometry = output_handle_geometry,
.mode = output_handle_mode,
.done = output_handle_done,
};
static void screenshot_done(void *data, struct orbital_screenshot *screenshot) {
buffer_copy_done = true;
}
static const struct orbital_screenshot_listener screenshot_listener = {
.done = screenshot_done,
};
static void handle_global(void *data, struct wl_registry *registry,
uint32_t name, const char *interface, uint32_t version) {
static struct screenshooter_output *output;
if (strcmp(interface, "wl_output") == 0) {
output = calloc(1, sizeof(*output));
output->output = wl_registry_bind(registry, name, &wl_output_interface,
1);
wl_list_insert(&output_list, &output->link);
wl_output_add_listener(output->output, &output_listener, output);
} else if (strcmp(interface, "wl_shm") == 0) {
shm = wl_registry_bind(registry, name, &wl_shm_interface, 1);
} else if (strcmp(interface, "orbital_screenshooter") == 0) {
screenshooter = wl_registry_bind(registry, name,
&orbital_screenshooter_interface, 1);
}
}
static void handle_global_remove(void *data, struct wl_registry *registry,
uint32_t name) {
// Who cares?
}
static const struct wl_registry_listener registry_listener = {
.global = handle_global,
.global_remove = handle_global_remove,
};
static struct wl_buffer *create_shm_buffer(int width, int height,
void **data_out) {
int stride = width * 4;
int size = stride * height;
const char shm_name[] = "/wlroots-screenshot";
int fd = shm_open(shm_name, O_RDWR | O_CREAT | O_EXCL, 0);
if (fd < 0) {
fprintf(stderr, "shm_open failed\n");
return NULL;
}
shm_unlink(shm_name);
int ret;
while ((ret = ftruncate(fd, size)) == EINTR) {
// No-op
}
if (ret < 0) {
close(fd);
fprintf(stderr, "ftruncate failed\n");
return NULL;
}
void *data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (data == MAP_FAILED) {
fprintf(stderr, "mmap failed: %m\n");
close(fd);
return NULL;
}
struct wl_shm_pool *pool = wl_shm_create_pool(shm, fd, size);
close(fd);
struct wl_buffer *buffer = wl_shm_pool_create_buffer(pool, 0, width, height,
stride, WL_SHM_FORMAT_XRGB8888);
wl_shm_pool_destroy(pool);
*data_out = data;
return buffer;
}
static void write_image(const char *filename, int width, int height,
void *data) {
char size[10 + 1 + 10 + 2 + 1]; // int32_t are max 10 digits
sprintf(size, "%dx%d+0", width, height);
int fd[2];
if (pipe(fd) != 0) {
fprintf(stderr, "cannot create pipe: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
pid_t child = fork();
if (child < 0) {
fprintf(stderr, "fork() failed\n");
exit(EXIT_FAILURE);
} else if (child != 0) {
close(fd[0]);
if (write(fd[1], data, 4 * width * height) < 0) {
fprintf(stderr, "write() failed: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
close(fd[1]);
waitpid(child, NULL, 0);
} else {
close(fd[1]);
if (dup2(fd[0], 0) != 0) {
fprintf(stderr, "cannot dup the pipe\n");
exit(EXIT_FAILURE);
}
close(fd[0]);
// We requested WL_SHM_FORMAT_XRGB8888 in little endian, so that's BGRA
// in big endian.
execlp("convert", "convert", "-depth", "8", "-size", size, "bgra:-",
"-alpha", "opaque", filename, NULL);
fprintf(stderr, "cannot execute convert\n");
exit(EXIT_FAILURE);
}
}
int main(int argc, char *argv[]) {
struct wl_display * display = wl_display_connect(NULL);
if (display == NULL) {
fprintf(stderr, "failed to create display: %m\n");
return -1;
}
wl_list_init(&output_list);
struct wl_registry *registry = wl_display_get_registry(display);
wl_registry_add_listener(registry, &registry_listener, NULL);
wl_display_dispatch(display);
wl_display_roundtrip(display);
if (screenshooter == NULL) {
fprintf(stderr, "display doesn't support screenshooter\n");
return -1;
}
int i = 0;
struct screenshooter_output *output;
wl_list_for_each(output, &output_list, link) {
void *data = NULL;
struct wl_buffer *buffer =
create_shm_buffer(output->width, output->height, &data);
if (buffer == NULL) {
return -1;
}
struct orbital_screenshot *screenshot = orbital_screenshooter_shoot(
screenshooter, output->output, buffer);
orbital_screenshot_add_listener(screenshot, &screenshot_listener,
screenshot);
buffer_copy_done = false;
while (!buffer_copy_done) {
wl_display_roundtrip(display);
}
char filename[24 + 10]; // int32_t are max 10 digits
snprintf(filename, sizeof(filename), "wayland-screenshot-%d.png", i);
write_image(filename, output->width, output->height, data);
wl_buffer_destroy(buffer);
++i;
}
return EXIT_SUCCESS;
}

View File

@ -6,7 +6,6 @@
#include <wlr/types/wlr_compositor.h>
#include <wlr/types/wlr_foreign_toplevel_management_v1.h>
#include <wlr/types/wlr_gamma_control_v1.h>
#include <wlr/types/wlr_gamma_control.h>
#include <wlr/types/wlr_gtk_primary_selection.h>
#include <wlr/types/wlr_idle_inhibit_v1.h>
#include <wlr/types/wlr_idle.h>
@ -21,7 +20,6 @@
#include <wlr/types/wlr_presentation_time.h>
#include <wlr/types/wlr_relative_pointer_v1.h>
#include <wlr/types/wlr_screencopy_v1.h>
#include <wlr/types/wlr_screenshooter.h>
#include <wlr/types/wlr_text_input_v3.h>
#include <wlr/types/wlr_virtual_keyboard_v1.h>
#include <wlr/types/wlr_xcursor_manager.h>
@ -47,9 +45,7 @@ struct roots_desktop {
struct wlr_compositor *compositor;
struct wlr_xdg_shell_v6 *xdg_shell_v6;
struct wlr_xdg_shell *xdg_shell;
struct wlr_gamma_control_manager *gamma_control_manager;
struct wlr_gamma_control_manager_v1 *gamma_control_manager_v1;
struct wlr_screenshooter *screenshooter;
struct wlr_export_dmabuf_manager_v1 *export_dmabuf_manager_v1;
struct wlr_server_decoration_manager *server_decoration_manager;
struct wlr_xdg_decoration_manager_v1 *xdg_decoration_manager;

View File

@ -9,7 +9,6 @@ install_headers(
'wlr_foreign_toplevel_management_v1.h',
'wlr_fullscreen_shell_v1.h',
'wlr_gamma_control_v1.h',
'wlr_gamma_control.h',
'wlr_gtk_primary_selection.h',
'wlr_idle_inhibit_v1.h',
'wlr_idle.h',
@ -34,7 +33,6 @@ install_headers(
'wlr_region.h',
'wlr_relative_pointer_v1.h',
'wlr_screencopy_v1.h',
'wlr_screenshooter.h',
'wlr_seat.h',
'wlr_server_decoration.h',
'wlr_surface.h',

View File

@ -1,46 +0,0 @@
/*
* This an unstable interface of wlroots. No guarantees are made regarding the
* future consistency of this API.
*/
#ifndef WLR_USE_UNSTABLE
#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features"
#endif
#ifndef WLR_TYPES_WLR_GAMMA_CONTROL_H
#define WLR_TYPES_WLR_GAMMA_CONTROL_H
#include <wayland-server.h>
struct wlr_gamma_control_manager {
struct wl_global *global;
struct wl_list controls; // wlr_gamma_control::link
struct wl_listener display_destroy;
struct {
struct wl_signal destroy;
} events;
void *data;
};
struct wlr_gamma_control {
struct wl_resource *resource;
struct wlr_output *output;
struct wl_list link;
struct wl_listener output_destroy_listener;
struct {
struct wl_signal destroy;
} events;
void* data;
};
struct wlr_gamma_control_manager *wlr_gamma_control_manager_create(
struct wl_display *display);
void wlr_gamma_control_manager_destroy(
struct wlr_gamma_control_manager *gamma_control_manager);
#endif

View File

@ -1,49 +0,0 @@
/*
* This protocol is obsolete and will be removed in a future version. The
* recommended replacement is wlr-screencopy.
*/
/*
* This an unstable interface of wlroots. No guarantees are made regarding the
* future consistency of this API.
*/
#ifndef WLR_USE_UNSTABLE
#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features"
#endif
#ifndef WLR_TYPES_WLR_SCREENSHOOTER_H
#define WLR_TYPES_WLR_SCREENSHOOTER_H
#include <wayland-server.h>
/**
* A very basic screenshooter interrface which implements the Orbital protocol.
*/
struct wlr_screenshooter {
struct wl_global *global;
struct wl_list screenshots; // wlr_screenshot::link
struct wl_listener display_destroy;
struct {
struct wl_signal destroy;
} events;
void *data;
};
struct wlr_screenshot {
struct wl_resource *resource;
struct wl_resource *output_resource;
struct wl_list link;
struct wlr_output *output;
struct wlr_screenshooter *screenshooter;
void* data;
};
struct wlr_screenshooter *wlr_screenshooter_create(struct wl_display *display);
void wlr_screenshooter_destroy(struct wlr_screenshooter *screenshooter);
#endif

View File

@ -1,57 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<protocol name="gamma_control">
<copyright>
Copyright © 2015 Giulio camuffo
Permission to use, copy, modify, distribute, and sell this
software and its documentation for any purpose is hereby granted
without fee, provided that the above copyright notice appear in
all copies and that both that copyright notice and this permission
notice appear in supporting documentation, and that the name of
the copyright holders not be used in advertising or publicity
pertaining to distribution of the software without specific,
written prior permission. The copyright holders make no
representations about the suitability of this software for any
purpose. It is provided "as is" without express or implied
warranty.
THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
THIS SOFTWARE.
</copyright>
<interface name="gamma_control_manager" version="1">
<request name="destroy" type="destructor"/>
<request name="get_gamma_control">
<arg name="id" type="new_id" interface="gamma_control"/>
<arg name="output" type="object" interface="wl_output"/>
</request>
</interface>
<interface name="gamma_control" version="1">
<enum name="error">
<entry name="invalid_gamma" value="0"/>
</enum>
<request name="destroy" type="destructor"/>
<request name="set_gamma">
<arg name="red" type="array"/>
<arg name="green" type="array"/>
<arg name="blue" type="array"/>
</request>
<request name="reset_gamma"/>
<event name="gamma_size">
<arg name="size" type="uint"/>
</event>
</interface>
</protocol>

View File

@ -25,11 +25,9 @@ protocols = [
[wl_protocol_dir, 'unstable/xdg-decoration/xdg-decoration-unstable-v1.xml'],
[wl_protocol_dir, 'unstable/xdg-output/xdg-output-unstable-v1.xml'],
[wl_protocol_dir, 'unstable/xdg-shell/xdg-shell-unstable-v6.xml'],
'gamma-control.xml',
'gtk-primary-selection.xml',
'idle.xml',
'input-method-unstable-v2.xml',
'screenshooter.xml',
'server-decoration.xml',
'virtual-keyboard-unstable-v1.xml',
'wlr-data-control-unstable-v1.xml',
@ -52,7 +50,6 @@ client_protocols = [
[wl_protocol_dir, 'unstable/xdg-shell/xdg-shell-unstable-v6.xml'],
'idle.xml',
'input-method-unstable-v2.xml',
'screenshooter.xml',
'wlr-export-dmabuf-unstable-v1.xml',
'wlr-foreign-toplevel-management-unstable-v1.xml',
'wlr-gamma-control-unstable-v1.xml',

View File

@ -1,16 +0,0 @@
<protocol name="orbital_screenshooter">
<interface name="orbital_screenshooter" version="1">
<request name="shoot">
<arg name="id" type="new_id" interface="orbital_screenshot"/>
<arg name="output" type="object" interface="wl_output"/>
<arg name="buffer" type="object" interface="wl_buffer"/>
</request>
</interface>
<interface name="orbital_screenshot" version="1">
<event name="done">
</event>
</interface>
</protocol>

View File

@ -10,7 +10,6 @@
#include <wlr/types/wlr_data_control_v1.h>
#include <wlr/types/wlr_export_dmabuf_v1.h>
#include <wlr/types/wlr_gamma_control_v1.h>
#include <wlr/types/wlr_gamma_control.h>
#include <wlr/types/wlr_gtk_primary_selection.h>
#include <wlr/types/wlr_idle_inhibit_v1.h>
#include <wlr/types/wlr_idle.h>
@ -379,11 +378,8 @@ struct roots_desktop *desktop_create(struct roots_server *server,
}
#endif
desktop->gamma_control_manager = wlr_gamma_control_manager_create(
server->wl_display);
desktop->gamma_control_manager_v1 = wlr_gamma_control_manager_v1_create(
server->wl_display);
desktop->screenshooter = wlr_screenshooter_create(server->wl_display);
desktop->export_dmabuf_manager_v1 =
wlr_export_dmabuf_manager_v1_create(server->wl_display);
desktop->server_decoration_manager =

View File

@ -32,7 +32,6 @@ lib_wlr_types = static_library(
'wlr_foreign_toplevel_management_v1.c',
'wlr_fullscreen_shell_v1.c',
'wlr_gamma_control_v1.c',
'wlr_gamma_control.c',
'wlr_gtk_primary_selection.c',
'wlr_idle_inhibit_v1.c',
'wlr_idle.c',
@ -57,7 +56,6 @@ lib_wlr_types = static_library(
'wlr_region.c',
'wlr_relative_pointer_v1.c',
'wlr_screencopy_v1.c',
'wlr_screenshooter.c',
'wlr_server_decoration.c',
'wlr_surface.c',
'wlr_switch.c',

View File

@ -1,197 +0,0 @@
#include <assert.h>
#include <stdlib.h>
#include <wayland-server.h>
#include <wlr/types/wlr_gamma_control.h>
#include <wlr/types/wlr_output.h>
#include <wlr/util/log.h>
#include "gamma-control-protocol.h"
#include "util/signal.h"
static void resource_destroy(struct wl_client *client,
struct wl_resource *resource) {
wl_resource_destroy(resource);
}
static void gamma_control_destroy(struct wlr_gamma_control *gamma_control) {
if (gamma_control == NULL) {
return;
}
wlr_signal_emit_safe(&gamma_control->events.destroy, gamma_control);
wl_list_remove(&gamma_control->output_destroy_listener.link);
wl_resource_set_user_data(gamma_control->resource, NULL);
wl_list_remove(&gamma_control->link);
free(gamma_control);
}
static const struct gamma_control_interface gamma_control_impl;
static struct wlr_gamma_control *gamma_control_from_resource(
struct wl_resource *resource) {
assert(wl_resource_instance_of(resource, &gamma_control_interface,
&gamma_control_impl));
return wl_resource_get_user_data(resource);
}
static void gamma_control_destroy_resource(struct wl_resource *resource) {
struct wlr_gamma_control *gamma_control =
gamma_control_from_resource(resource);
gamma_control_destroy(gamma_control);
}
static void gamma_control_handle_output_destroy(struct wl_listener *listener,
void *data) {
struct wlr_gamma_control *gamma_control =
wl_container_of(listener, gamma_control, output_destroy_listener);
gamma_control_destroy(gamma_control);
}
static void gamma_control_set_gamma(struct wl_client *client,
struct wl_resource *gamma_control_resource, struct wl_array *red,
struct wl_array *green, struct wl_array *blue) {
struct wlr_gamma_control *gamma_control =
gamma_control_from_resource(gamma_control_resource);
if (gamma_control == NULL) {
return;
}
if (red->size != green->size || red->size != blue->size) {
wl_resource_post_error(gamma_control_resource,
GAMMA_CONTROL_ERROR_INVALID_GAMMA,
"The gamma ramps don't have the same size");
return;
}
uint32_t size = red->size / sizeof(uint16_t);
uint16_t *r = (uint16_t *)red->data;
uint16_t *g = (uint16_t *)green->data;
uint16_t *b = (uint16_t *)blue->data;
wlr_output_set_gamma(gamma_control->output, size, r, g, b);
}
static void gamma_control_reset_gamma(struct wl_client *client,
struct wl_resource *gamma_control_resource) {
// TODO
}
static const struct gamma_control_interface gamma_control_impl = {
.destroy = resource_destroy,
.set_gamma = gamma_control_set_gamma,
.reset_gamma = gamma_control_reset_gamma,
};
static const struct gamma_control_manager_interface gamma_control_manager_impl;
static struct wlr_gamma_control_manager *gamma_control_manager_from_resource(
struct wl_resource *resource) {
assert(wl_resource_instance_of(resource, &gamma_control_manager_interface,
&gamma_control_manager_impl));
return wl_resource_get_user_data(resource);
}
static void gamma_control_manager_get_gamma_control(struct wl_client *client,
struct wl_resource *gamma_control_manager_resource, uint32_t id,
struct wl_resource *output_resource) {
struct wlr_gamma_control_manager *manager =
gamma_control_manager_from_resource(gamma_control_manager_resource);
struct wlr_output *output = wlr_output_from_resource(output_resource);
struct wlr_gamma_control *gamma_control =
calloc(1, sizeof(struct wlr_gamma_control));
if (gamma_control == NULL) {
wl_client_post_no_memory(client);
return;
}
gamma_control->output = output;
int version = wl_resource_get_version(gamma_control_manager_resource);
gamma_control->resource = wl_resource_create(client,
&gamma_control_interface, version, id);
if (gamma_control->resource == NULL) {
free(gamma_control);
wl_client_post_no_memory(client);
return;
}
wlr_log(WLR_DEBUG, "new gamma_control %p (res %p)", gamma_control,
gamma_control->resource);
wl_resource_set_implementation(gamma_control->resource,
&gamma_control_impl, gamma_control, gamma_control_destroy_resource);
wl_signal_init(&gamma_control->events.destroy);
wl_signal_add(&output->events.destroy,
&gamma_control->output_destroy_listener);
gamma_control->output_destroy_listener.notify =
gamma_control_handle_output_destroy;
wl_list_insert(&manager->controls, &gamma_control->link);
gamma_control_send_gamma_size(gamma_control->resource,
wlr_output_get_gamma_size(output));
}
static const struct gamma_control_manager_interface gamma_control_manager_impl = {
.get_gamma_control = gamma_control_manager_get_gamma_control,
};
static void gamma_control_manager_bind(struct wl_client *client, void *data,
uint32_t version, uint32_t id) {
struct wlr_gamma_control_manager *manager = data;
assert(client && manager);
struct wl_resource *resource = wl_resource_create(client,
&gamma_control_manager_interface, version, id);
if (resource == NULL) {
wl_client_post_no_memory(client);
return;
}
wl_resource_set_implementation(resource, &gamma_control_manager_impl,
manager, NULL);
}
void wlr_gamma_control_manager_destroy(
struct wlr_gamma_control_manager *manager) {
if (!manager) {
return;
}
struct wlr_gamma_control *gamma_control, *tmp;
wl_list_for_each_safe(gamma_control, tmp, &manager->controls, link) {
gamma_control_destroy(gamma_control);
}
wlr_signal_emit_safe(&manager->events.destroy, manager);
wl_list_remove(&manager->display_destroy.link);
wl_global_destroy(manager->global);
free(manager);
}
static void handle_display_destroy(struct wl_listener *listener, void *data) {
struct wlr_gamma_control_manager *manager =
wl_container_of(listener, manager, display_destroy);
wlr_gamma_control_manager_destroy(manager);
}
struct wlr_gamma_control_manager *wlr_gamma_control_manager_create(
struct wl_display *display) {
struct wlr_gamma_control_manager *manager =
calloc(1, sizeof(struct wlr_gamma_control_manager));
if (!manager) {
return NULL;
}
struct wl_global *global = wl_global_create(display,
&gamma_control_manager_interface, 1, manager,
gamma_control_manager_bind);
if (!global) {
free(manager);
return NULL;
}
manager->global = global;
wl_signal_init(&manager->events.destroy);
wl_list_init(&manager->controls);
manager->display_destroy.notify = handle_display_destroy;
wl_display_add_destroy_listener(display, &manager->display_destroy);
return manager;
}

View File

@ -1,217 +0,0 @@
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <wayland-server.h>
#include <wlr/backend.h>
#include <wlr/render/wlr_renderer.h>
#include <wlr/types/wlr_output.h>
#include <wlr/types/wlr_screenshooter.h>
#include <wlr/util/log.h>
#include "screenshooter-protocol.h"
#include "util/signal.h"
static struct wlr_screenshot *screenshot_from_resource(
struct wl_resource *resource) {
assert(wl_resource_instance_of(resource, &orbital_screenshot_interface,
NULL));
return wl_resource_get_user_data(resource);
}
struct screenshot_state {
struct wl_shm_buffer *shm_buffer;
struct wlr_screenshot *screenshot;
struct wl_listener frame_listener;
};
static void screenshot_destroy(struct wlr_screenshot *screenshot) {
wl_list_remove(&screenshot->link);
wl_resource_set_user_data(screenshot->resource, NULL);
free(screenshot);
}
static void handle_screenshot_resource_destroy(
struct wl_resource *screenshot_resource) {
struct wlr_screenshot *screenshot =
screenshot_from_resource(screenshot_resource);
if (screenshot != NULL) {
screenshot_destroy(screenshot);
}
}
static void output_handle_frame(struct wl_listener *listener, void *_data) {
struct screenshot_state *state = wl_container_of(listener, state,
frame_listener);
struct wlr_output *output = state->screenshot->output;
struct wlr_renderer *renderer = wlr_backend_get_renderer(output->backend);
struct wl_shm_buffer *shm_buffer = state->shm_buffer;
if (!(output->pending.committed & WLR_OUTPUT_STATE_BUFFER)) {
return;
}
enum wl_shm_format format = wl_shm_buffer_get_format(shm_buffer);
int32_t width = wl_shm_buffer_get_width(shm_buffer);
int32_t height = wl_shm_buffer_get_height(shm_buffer);
int32_t stride = wl_shm_buffer_get_stride(shm_buffer);
wl_shm_buffer_begin_access(shm_buffer);
void *data = wl_shm_buffer_get_data(shm_buffer);
bool ok = wlr_renderer_read_pixels(renderer, format, NULL, stride,
width, height, 0, 0, 0, 0, data);
wl_shm_buffer_end_access(shm_buffer);
if (!ok) {
wlr_log(WLR_ERROR, "Cannot read pixels");
goto cleanup;
}
orbital_screenshot_send_done(state->screenshot->resource);
cleanup:
wl_list_remove(&listener->link);
free(state);
}
static const struct orbital_screenshooter_interface screenshooter_impl;
static struct wlr_screenshooter *screenshooter_from_resource(
struct wl_resource *resource) {
assert(wl_resource_instance_of(resource, &orbital_screenshooter_interface,
&screenshooter_impl));
return wl_resource_get_user_data(resource);
}
static void screenshooter_shoot(struct wl_client *client,
struct wl_resource *screenshooter_resource, uint32_t id,
struct wl_resource *output_resource,
struct wl_resource *buffer_resource) {
struct wlr_screenshooter *screenshooter =
screenshooter_from_resource(screenshooter_resource);
struct wlr_output *output = wlr_output_from_resource(output_resource);
struct wlr_renderer *renderer = wlr_backend_get_renderer(output->backend);
if (renderer == NULL) {
wlr_log(WLR_ERROR, "Backend doesn't have a renderer");
return;
}
struct wl_shm_buffer *shm_buffer = wl_shm_buffer_get(buffer_resource);
if (shm_buffer == NULL) {
wlr_log(WLR_ERROR, "Invalid buffer: not a shared memory buffer");
return;
}
int32_t width = wl_shm_buffer_get_width(shm_buffer);
int32_t height = wl_shm_buffer_get_height(shm_buffer);
if (width < output->width || height < output->height) {
wlr_log(WLR_ERROR, "Invalid buffer: too small");
return;
}
uint32_t format = wl_shm_buffer_get_format(shm_buffer);
if (!wlr_renderer_format_supported(renderer, format)) {
wlr_log(WLR_ERROR, "Invalid buffer: unsupported format");
return;
}
struct wlr_screenshot *screenshot =
calloc(1, sizeof(struct wlr_screenshot));
if (!screenshot) {
wl_resource_post_no_memory(screenshooter_resource);
return;
}
screenshot->output_resource = output_resource;
screenshot->output = output;
screenshot->screenshooter = screenshooter;
screenshot->resource = wl_resource_create(client,
&orbital_screenshot_interface,
wl_resource_get_version(screenshooter_resource), id);
if (screenshot->resource == NULL) {
free(screenshot);
wl_resource_post_no_memory(screenshooter_resource);
return;
}
wl_resource_set_implementation(screenshot->resource, NULL, screenshot,
handle_screenshot_resource_destroy);
wl_list_insert(&screenshooter->screenshots, &screenshot->link);
wlr_log(WLR_DEBUG, "new screenshot %p (res %p)", screenshot,
screenshot->resource);
struct screenshot_state *state = calloc(1, sizeof(struct screenshot_state));
if (!state) {
wl_resource_destroy(screenshot->resource);
free(screenshot);
wl_resource_post_no_memory(screenshooter_resource);
return;
}
state->shm_buffer = shm_buffer;
state->screenshot = screenshot;
state->frame_listener.notify = output_handle_frame;
wl_signal_add(&output->events.precommit, &state->frame_listener);
// Schedule a buffer commit
output->needs_frame = true;
wlr_output_schedule_frame(output);
}
static const struct orbital_screenshooter_interface screenshooter_impl = {
.shoot = screenshooter_shoot,
};
static void screenshooter_bind(struct wl_client *wl_client, void *data,
uint32_t version, uint32_t id) {
struct wlr_screenshooter *screenshooter = data;
assert(wl_client && screenshooter);
struct wl_resource *wl_resource = wl_resource_create(wl_client,
&orbital_screenshooter_interface, version, id);
if (wl_resource == NULL) {
wl_client_post_no_memory(wl_client);
return;
}
wl_resource_set_implementation(wl_resource, &screenshooter_impl,
screenshooter, NULL);
}
void wlr_screenshooter_destroy(struct wlr_screenshooter *screenshooter) {
if (!screenshooter) {
return;
}
wl_list_remove(&screenshooter->display_destroy.link);
struct wlr_screenshot *screenshot, *tmp;
wl_list_for_each_safe(screenshot, tmp, &screenshooter->screenshots, link) {
screenshot_destroy(screenshot);
}
wlr_signal_emit_safe(&screenshooter->events.destroy, screenshooter);
wl_global_destroy(screenshooter->global);
free(screenshooter);
}
static void handle_display_destroy(struct wl_listener *listener, void *data) {
struct wlr_screenshooter *screenshooter =
wl_container_of(listener, screenshooter, display_destroy);
wlr_screenshooter_destroy(screenshooter);
}
struct wlr_screenshooter *wlr_screenshooter_create(struct wl_display *display) {
struct wlr_screenshooter *screenshooter =
calloc(1, sizeof(struct wlr_screenshooter));
if (!screenshooter) {
return NULL;
}
wl_list_init(&screenshooter->screenshots);
wl_signal_init(&screenshooter->events.destroy);
screenshooter->display_destroy.notify = handle_display_destroy;
wl_display_add_destroy_listener(display, &screenshooter->display_destroy);
screenshooter->global = wl_global_create(display,
&orbital_screenshooter_interface, 1, screenshooter, screenshooter_bind);
if (screenshooter->global == NULL) {
free(screenshooter);
return NULL;
}
return screenshooter;
}