Preliminary support for toplevel capture.

Note: Capture is currently untested, as no compositor has support.
Based purely on the protocol specification. Toplevel listing was tested
on Sway & wlroots (latest dev + wlroots MR #4545)
ext-image-capture
itycodes 3 weeks ago
parent 276cfd4e51
commit 50fb3d1a34

202
main.c

@ -9,6 +9,7 @@
#include "ext-image-capture-source-v1.prot.h" #include "ext-image-capture-source-v1.prot.h"
#include "ext-image-copy-capture-v1.prot.h" #include "ext-image-copy-capture-v1.prot.h"
#include "ext-foreign-toplevel-list-v1.prot.h"
#include "rif.h" #include "rif.h"
@ -34,6 +35,8 @@ struct wl_shm* wl_shm = NULL;
struct wl_buffer* frame_buffer = NULL; struct wl_buffer* frame_buffer = NULL;
struct ext_output_image_capture_source_manager_v1* output_source_manager = NULL; struct ext_output_image_capture_source_manager_v1* output_source_manager = NULL;
struct ext_image_copy_capture_manager_v1* capture_manager = NULL; struct ext_image_copy_capture_manager_v1* capture_manager = NULL;
struct ext_foreign_toplevel_list_v1* toplevel_list = NULL;
struct ext_foreign_toplevel_image_capture_source_manager_v1* toplevel_source_manager = NULL;
void* shm_data = NULL; void* shm_data = NULL;
@ -41,6 +44,7 @@ struct image_data img_data;
uint8_t is_frame_ready = 0; uint8_t is_frame_ready = 0;
uint8_t is_capture_ready = 0; uint8_t is_capture_ready = 0;
uint8_t full_screenshot = 0;
uint32_t buf_size; uint32_t buf_size;
@ -62,6 +66,12 @@ void handle_global(
if(strcmp(interface, ext_image_copy_capture_manager_v1_interface.name) == 0) { if(strcmp(interface, ext_image_copy_capture_manager_v1_interface.name) == 0) {
capture_manager = wl_registry_bind(registry, name, &ext_image_copy_capture_manager_v1_interface, version); capture_manager = wl_registry_bind(registry, name, &ext_image_copy_capture_manager_v1_interface, version);
} }
if(strcmp(interface, ext_foreign_toplevel_list_v1_interface.name) == 0) {
toplevel_list = wl_registry_bind(registry, name, &ext_foreign_toplevel_list_v1_interface, version);
}
if(strcmp(interface, ext_foreign_toplevel_image_capture_source_manager_v1_interface.name) == 0) {
toplevel_source_manager = wl_registry_bind(registry, name, &ext_foreign_toplevel_image_capture_source_manager_v1_interface, version);
}
} }
void handle_global_remove( void handle_global_remove(
@ -76,8 +86,8 @@ const struct wl_registry_listener reg_callbacks = {
.global_remove = handle_global_remove, .global_remove = handle_global_remove,
}; };
void buffer_size(void *data, void buffer_size(void* data,
struct ext_image_copy_capture_session_v1 *ext_image_copy_capture_session_v1, struct ext_image_copy_capture_session_v1* ext_image_copy_capture_session_v1,
uint32_t width, uint32_t width,
uint32_t height) { uint32_t height) {
printf("x: %d, y: %d\n", width, height); printf("x: %d, y: %d\n", width, height);
@ -85,36 +95,36 @@ void buffer_size(void *data,
img_data.height = height; img_data.height = height;
} }
void shm_format(void *data, void shm_format(void* data,
struct ext_image_copy_capture_session_v1 *ext_image_copy_capture_session_v1, struct ext_image_copy_capture_session_v1* ext_image_copy_capture_session_v1,
uint32_t format) { uint32_t format) {
img_data.shm_format = format; img_data.shm_format = format;
ASSERT(format == WL_SHM_FORMAT_XBGR8888 || format == WL_SHM_FORMAT_ABGR8888, "Unsupported buffer format."); ASSERT(format == WL_SHM_FORMAT_XBGR8888 || format == WL_SHM_FORMAT_ABGR8888, "Unsupported buffer format.");
} }
void dmabuf_device(void *data, void dmabuf_device(void* data,
struct ext_image_copy_capture_session_v1 *ext_image_copy_capture_session_v1, struct ext_image_copy_capture_session_v1* ext_image_copy_capture_session_v1,
struct wl_array *device) { struct wl_array* device) {
} }
void dmabuf_format(void *data, void dmabuf_format(void* data,
struct ext_image_copy_capture_session_v1 *ext_image_copy_capture_session_v1, struct ext_image_copy_capture_session_v1* ext_image_copy_capture_session_v1,
uint32_t format, uint32_t format,
struct wl_array *modifiers) { struct wl_array* modifiers) {
} }
void done(void *data, void capture_done(void* data,
struct ext_image_copy_capture_session_v1 *ext_image_copy_capture_session_v1) { struct ext_image_copy_capture_session_v1* ext_image_copy_capture_session_v1) {
const int shm_fd = memfd_create("wl_shm data", 0); const int shm_fd = memfd_create("wl_shm data", 0);
ASSERT(shm_fd != -1, "Failed to create memfd."); ASSERT(shm_fd != -1, "Failed to create memfd.");
// Format is hardcoded to chan width 4 // Format is hardcoded to chan width 4
const uint32_t chan_width = 4; const uint32_t chan_width = 4;
const uint32_t stride = img_data.width * chan_width; const uint32_t stride = img_data.width* chan_width;
buf_size = img_data.height * stride; buf_size = img_data.height* stride;
ASSERT(ftruncate(shm_fd, buf_size) != -1, "Failed to ftruncate the memfd."); ASSERT(ftruncate(shm_fd, buf_size) != -1, "Failed to ftruncate the memfd.");
@ -131,8 +141,8 @@ void done(void *data,
} }
void stopped(void *data, void stopped(void* data,
struct ext_image_copy_capture_session_v1 *ext_image_copy_capture_session_v1) { struct ext_image_copy_capture_session_v1* ext_image_copy_capture_session_v1) {
} }
@ -141,37 +151,37 @@ const struct ext_image_copy_capture_session_v1_listener capture_listener = {
.shm_format = shm_format, .shm_format = shm_format,
.dmabuf_device = dmabuf_device, .dmabuf_device = dmabuf_device,
.dmabuf_format = dmabuf_format, .dmabuf_format = dmabuf_format,
.done = done, .done = capture_done,
.stopped = stopped .stopped = stopped
}; };
void transform(void *data, void transform(void* data,
struct ext_image_copy_capture_frame_v1 *ext_image_copy_capture_frame_v1, struct ext_image_copy_capture_frame_v1* ext_image_copy_capture_frame_v1,
uint32_t transform) { uint32_t transform) {
} }
void damage(void *data, void damage(void* data,
struct ext_image_copy_capture_frame_v1 *ext_image_copy_capture_frame_v1, struct ext_image_copy_capture_frame_v1* ext_image_copy_capture_frame_v1,
int32_t x, int32_t x,
int32_t y, int32_t y,
int32_t width, int32_t width,
int32_t height) { int32_t height) {
} }
void presentation_time(void *data, void presentation_time(void* data,
struct ext_image_copy_capture_frame_v1 *ext_image_copy_capture_frame_v1, struct ext_image_copy_capture_frame_v1* ext_image_copy_capture_frame_v1,
uint32_t tv_sec_hi, uint32_t tv_sec_hi,
uint32_t tv_sec_lo, uint32_t tv_sec_lo,
uint32_t tv_nsec) { uint32_t tv_nsec) {
} }
void ready(void *data, void ready(void* data,
struct ext_image_copy_capture_frame_v1 *ext_image_copy_capture_frame_v1) { struct ext_image_copy_capture_frame_v1* ext_image_copy_capture_frame_v1) {
is_capture_ready = 1; is_capture_ready = 1;
} }
void failed(void *data, void failed(void* data,
struct ext_image_copy_capture_frame_v1 *ext_image_copy_capture_frame_v1, struct ext_image_copy_capture_frame_v1* ext_image_copy_capture_frame_v1,
uint32_t reason) { uint32_t reason) {
switch(reason) { switch(reason) {
case 0: case 0:
@ -194,8 +204,90 @@ const struct ext_image_copy_capture_frame_v1_listener frame_listener = {
.failed = failed .failed = failed
}; };
struct handle_data {
struct ext_foreign_toplevel_handle_v1* handle;
const char* title;
const char* app_id;
const char* identifier;
};
struct handle_data*** handles;
size_t handles_len = 0;
void closed(void *data,
struct ext_foreign_toplevel_handle_v1 *ext_foreign_toplevel_handle_v1) {
// TODO handle properly
}
void title(void *data,
struct ext_foreign_toplevel_handle_v1 *ext_foreign_toplevel_handle_v1,
const char *title) {
struct handle_data* handle_data = (struct handle_data*)data;
size_t size = strlen(title)+1;
char* title_data = malloc(size);
memcpy(title_data, title, size);
handle_data->title = title_data;
}
void app_id(void *data,
struct ext_foreign_toplevel_handle_v1 *ext_foreign_toplevel_handle_v1,
const char *app_id) {
struct handle_data* handle_data = (struct handle_data*)data;
size_t size = strlen(app_id)+1;
char* app_id_data = malloc(size);
memcpy(app_id_data, app_id, size);
handle_data->app_id = app_id_data;
}
void identifier(void *data,
struct ext_foreign_toplevel_handle_v1 *ext_foreign_toplevel_handle_v1,
const char *identifier) {
struct handle_data* handle_data = (struct handle_data*)data;
size_t size = strlen(identifier)+1;
char* identifier_data = malloc(size);
memcpy(identifier_data, identifier, size);
handle_data->identifier = identifier_data;
}
void toplevel_done(void *data,
struct ext_foreign_toplevel_handle_v1 *ext_foreign_toplevel_handle_v1) {
struct handle_data* handle_data = (struct handle_data*)data;
}
struct ext_foreign_toplevel_handle_v1_listener handle_listener = {
.closed = closed,
.done = toplevel_done,
.title = title,
.app_id = app_id,
.identifier = identifier,
};
void toplevel(void* data,
struct ext_foreign_toplevel_list_v1* ext_foreign_toplevel_list_v1,
struct ext_foreign_toplevel_handle_v1* toplevel) {
handles_len++;
*handles = realloc(*handles, handles_len*sizeof(void*));
struct handle_data* handle_data = malloc(sizeof(struct handle_data));
int main() { handle_data->handle = toplevel;
handle_data->title = NULL;
handle_data->app_id = NULL;
handle_data->identifier = NULL;
(*handles)[handles_len-1] = handle_data;
ext_foreign_toplevel_handle_v1_add_listener(toplevel, &handle_listener, handle_data);
}
void finished(void* data,
struct ext_foreign_toplevel_list_v1* ext_foreign_toplevel_list_v1) {
// TODO handle exploding properly
}
const struct ext_foreign_toplevel_list_v1_listener toplevel_listener = {
.toplevel = toplevel,
.finished = finished
};
int main(int argc, char* argv[]) {
struct wl_display* dpy = wl_display_connect(NULL); struct wl_display* dpy = wl_display_connect(NULL);
ASSERT(dpy != NULL, "Unable to connect to Wayland"); ASSERT(dpy != NULL, "Unable to connect to Wayland");
@ -208,11 +300,59 @@ int main() {
ASSERT(stream_output != NULL, "No outputs found!"); ASSERT(stream_output != NULL, "No outputs found!");
ASSERT(output_source_manager != NULL, "ext-image-capture-source-v1.ext_output_image_capture_source_manager_v1 not supported."); ASSERT(output_source_manager != NULL, "ext-image-capture-source-v1.ext_output_image_capture_source_manager_v1 not supported.");
struct handle_data* toplevel_handle = NULL;
if(argc == 2) {
ASSERT(toplevel_list != NULL, "ext-foreign-toplevel-list-v1.ext_foreign_toplevel_list_v1 not supported.");
handles = malloc(sizeof(void*));
*handles = malloc(sizeof(void*));
handles_len = 0;
ext_foreign_toplevel_list_v1_add_listener(toplevel_list, &toplevel_listener, NULL);
if(strcmp(argv[1], "?") == 0) {
wl_display_roundtrip(dpy);
for(int i = 0; i < handles_len; i++) {
struct handle_data* handle_data = (*handles)[i];
printf("title: %s, app_id: %s, identifier: %s\n", handle_data->title, handle_data->app_id, handle_data->identifier);
}
return 0;
} else {
wl_display_roundtrip(dpy);
for(int i = 0; i < handles_len; i++) {
if(strcmp((*handles)[i]->identifier, argv[1]) == 0) {
toplevel_handle = (*handles)[i];
printf("Found handle: ");
printf("title: %s, app_id: %s, identifier: %s\n", toplevel_handle->title, toplevel_handle->app_id, toplevel_handle->identifier);
}
}
}
} else if(argc == 1) {
full_screenshot = 1;
wl_display_roundtrip(dpy);
} else {
ASSERT(argc >= 1, "Invalid exec!");
printf("Usage: %s ?|<identifier>\n");
exit(-1);
}
ASSERT(capture_manager != NULL, "ext-image-copy-capture-v1.ext_image_copy_capture_manager_v1 not supported."); ASSERT(capture_manager != NULL, "ext-image-copy-capture-v1.ext_image_copy_capture_manager_v1 not supported.");
struct ext_image_capture_source_v1* capture_source = struct ext_image_capture_source_v1* capture_source;
ext_output_image_capture_source_manager_v1_create_source(output_source_manager, stream_output); if(full_screenshot) {
ASSERT(capture_source != NULL, "Failed creating a source for the default output!") ASSERT(output_source_manager != NULL, "ext-image-capture-source-v1.ext_output_image_capture_source_manager_v1 not supported.");
capture_source =
ext_output_image_capture_source_manager_v1_create_source(output_source_manager, stream_output);
ASSERT(capture_source != NULL, "Failed creating a source for the default output!")
} else {
ASSERT(toplevel_handle != NULL, "Invalid toplevel handle!");
ASSERT(toplevel_source_manager != NULL, "ext-image-capture-source-v1.ext_foreign_toplevel_image_capture_source_manager_v1 not supported.");
capture_source =
ext_foreign_toplevel_image_capture_source_manager_v1_create_source(toplevel_source_manager, toplevel_handle->handle);
ASSERT(capture_source != NULL, "Failed creating a source for the toplevel!")
}
struct ext_image_copy_capture_session_v1* capture_session = struct ext_image_copy_capture_session_v1* capture_session =
ext_image_copy_capture_manager_v1_create_session(capture_manager, capture_source, EXT_IMAGE_COPY_CAPTURE_MANAGER_V1_OPTIONS_PAINT_CURSORS); ext_image_copy_capture_manager_v1_create_session(capture_manager, capture_source, EXT_IMAGE_COPY_CAPTURE_MANAGER_V1_OPTIONS_PAINT_CURSORS);

Loading…
Cancel
Save