mirror of
https://github.com/artizirk/wdisplays.git
synced 2026-10-03 12:55:42 +03:00
Merge branch 'preview-cpu'
This commit is contained in:
+27
-5
@@ -24,6 +24,7 @@ __attribute__((noreturn)) void wd_fatal_error(int status, const char *message) {
|
||||
#define MIN_ZOOM (1./1000.)
|
||||
#define MAX_ZOOM 1000.
|
||||
#define CANVAS_MARGIN 40
|
||||
#define CAPTURE_INTERVAL_MS 200
|
||||
|
||||
static const char *APP_PREFIX = "app";
|
||||
|
||||
@@ -179,6 +180,13 @@ static void cache_scroll(struct wd_state *state) {
|
||||
|
||||
static gboolean redraw_canvas(GtkWidget *widget, GdkFrameClock *frame_clock, gpointer data);
|
||||
|
||||
static gboolean capture_tick(gpointer data) {
|
||||
struct wd_state *state = data;
|
||||
state->capture_due = true;
|
||||
gtk_gl_area_queue_render(GTK_GL_AREA(state->canvas));
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
|
||||
static void update_tick_callback(struct wd_state *state) {
|
||||
bool any_animate = FALSE;
|
||||
struct wd_render_head_data *render;
|
||||
@@ -189,7 +197,7 @@ static void update_tick_callback(struct wd_state *state) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!any_animate && !state->capture) {
|
||||
if (!any_animate) {
|
||||
if (state->canvas_tick != -1) {
|
||||
gtk_widget_remove_tick_callback(state->canvas, state->canvas_tick);
|
||||
state->canvas_tick = -1;
|
||||
@@ -198,6 +206,17 @@ static void update_tick_callback(struct wd_state *state) {
|
||||
state->canvas_tick =
|
||||
gtk_widget_add_tick_callback(state->canvas, redraw_canvas, state, NULL);
|
||||
}
|
||||
if (!state->capture) {
|
||||
if (state->capture_timeout != -1) {
|
||||
g_source_remove(state->capture_timeout);
|
||||
state->capture_timeout = -1;
|
||||
wd_capture_release(state);
|
||||
}
|
||||
} else if (state->capture_timeout == -1) {
|
||||
state->capture_due = true;
|
||||
state->capture_timeout =
|
||||
g_timeout_add(CAPTURE_INTERVAL_MS, capture_tick, state);
|
||||
}
|
||||
gtk_gl_area_queue_render(GTK_GL_AREA(state->canvas));
|
||||
gtk_gl_area_set_auto_render(GTK_GL_AREA(state->canvas), state->capture);
|
||||
}
|
||||
@@ -462,6 +481,8 @@ static void cleanup(GtkWidget *window, gpointer data) {
|
||||
g_source_remove(state->reset_idle);
|
||||
if (state->apply_idle != -1)
|
||||
g_source_remove(state->apply_idle);
|
||||
if (state->capture_timeout != -1)
|
||||
g_source_remove(state->capture_timeout);
|
||||
g_object_unref(state->grab_cursor);
|
||||
g_object_unref(state->grabbing_cursor);
|
||||
g_object_unref(state->move_cursor);
|
||||
@@ -570,7 +591,10 @@ static void canvas_render(GtkGLArea *area, GdkGLContext *context, gpointer data)
|
||||
GdkFrameClock *clock = gtk_widget_get_frame_clock(state->canvas);
|
||||
uint64_t tick = gdk_frame_clock_get_frame_time(clock);
|
||||
|
||||
wd_capture_frame(state);
|
||||
if (state->capture_due) {
|
||||
state->capture_due = false;
|
||||
wd_capture_frame(state);
|
||||
}
|
||||
|
||||
struct wd_head *head;
|
||||
wl_list_for_each(head, &state->heads, link) {
|
||||
@@ -897,9 +921,6 @@ static void auto_apply_selected(GSimpleAction *action, GVariant *param, gpointer
|
||||
|
||||
static gboolean redraw_canvas(GtkWidget *widget, GdkFrameClock *frame_clock, gpointer data) {
|
||||
struct wd_state *state = data;
|
||||
if (state->capture) {
|
||||
wd_capture_frame(state);
|
||||
}
|
||||
update_tick_callback(state);
|
||||
queue_canvas_draw(state);
|
||||
return G_SOURCE_CONTINUE;
|
||||
@@ -955,6 +976,7 @@ static void activate(GtkApplication* app, gpointer user_data) {
|
||||
struct wd_state *state = wd_state_create();
|
||||
state->zoom = DEFAULT_ZOOM;
|
||||
state->canvas_tick = -1;
|
||||
state->capture_timeout = -1;
|
||||
state->apply_idle = -1;
|
||||
state->reset_idle = -1;
|
||||
|
||||
|
||||
+87
-33
@@ -139,15 +139,24 @@ void wd_apply_state(struct wd_state *state, struct wl_list *new_outputs,
|
||||
wl_display_roundtrip(display);
|
||||
}
|
||||
|
||||
static void wd_frame_destroy(struct wd_frame *frame) {
|
||||
if (frame->pixels != NULL)
|
||||
munmap(frame->pixels, frame->height * frame->stride);
|
||||
static void release_buffer(struct wd_frame *frame) {
|
||||
if (frame->data != NULL)
|
||||
munmap(frame->data, frame->height * frame->stride);
|
||||
if (frame->buffer != NULL)
|
||||
wl_buffer_destroy(frame->buffer);
|
||||
if (frame->pool != NULL)
|
||||
wl_shm_pool_destroy(frame->pool);
|
||||
if (frame->capture_fd != -1)
|
||||
close(frame->capture_fd);
|
||||
frame->data = NULL;
|
||||
frame->pixels = NULL;
|
||||
frame->buffer = NULL;
|
||||
frame->pool = NULL;
|
||||
frame->capture_fd = -1;
|
||||
}
|
||||
|
||||
static void wd_frame_destroy(struct wd_frame *frame) {
|
||||
release_buffer(frame);
|
||||
if (frame->wlr_frame != NULL)
|
||||
zwlr_screencopy_frame_v1_destroy(frame->wlr_frame);
|
||||
|
||||
@@ -197,20 +206,35 @@ static void capture_buffer(void *data,
|
||||
goto err;
|
||||
}
|
||||
|
||||
size_t size = stride * height;
|
||||
frame->capture_fd = create_shm_file(size, "/wd-%s", frame->output->name);
|
||||
if (frame->capture_fd == -1) {
|
||||
goto err;
|
||||
}
|
||||
if (frame->buffer == NULL || frame->format != format
|
||||
|| frame->width != width || frame->height != height
|
||||
|| frame->stride != stride) {
|
||||
release_buffer(frame);
|
||||
|
||||
frame->pool = wl_shm_create_pool(frame->output->state->shm,
|
||||
frame->capture_fd, size);
|
||||
frame->buffer = wl_shm_pool_create_buffer(frame->pool, 0,
|
||||
width, height, stride, format);
|
||||
size_t size = stride * height;
|
||||
frame->capture_fd = create_shm_file(size, "/wd-%s", frame->output->name);
|
||||
if (frame->capture_fd == -1) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
frame->data = mmap(NULL, size, PROT_READ, MAP_SHARED,
|
||||
frame->capture_fd, 0);
|
||||
if (frame->data == MAP_FAILED) {
|
||||
frame->data = NULL;
|
||||
fprintf(stderr, "mmap: %d: %s\n", frame->capture_fd, strerror(errno));
|
||||
goto err;
|
||||
}
|
||||
|
||||
frame->pool = wl_shm_create_pool(frame->output->state->shm,
|
||||
frame->capture_fd, size);
|
||||
frame->buffer = wl_shm_pool_create_buffer(frame->pool, 0,
|
||||
width, height, stride, format);
|
||||
frame->format = format;
|
||||
frame->stride = stride;
|
||||
frame->width = width;
|
||||
frame->height = height;
|
||||
}
|
||||
zwlr_screencopy_frame_v1_copy(copy_frame, frame->buffer);
|
||||
frame->stride = stride;
|
||||
frame->width = width;
|
||||
frame->height = height;
|
||||
frame->swap_rgb = format == WL_SHM_FORMAT_ABGR8888
|
||||
|| format == WL_SHM_FORMAT_XBGR8888;
|
||||
|
||||
@@ -226,30 +250,38 @@ static void capture_flags(void *data,
|
||||
frame->y_invert = !!(flags & ZWLR_SCREENCOPY_FRAME_V1_FLAGS_Y_INVERT);
|
||||
}
|
||||
|
||||
static void keep_as_spare(struct wd_frame *frame) {
|
||||
struct wd_output *output = frame->output;
|
||||
if (output->spare != NULL) {
|
||||
wd_frame_destroy(frame);
|
||||
return;
|
||||
}
|
||||
if (frame->wlr_frame != NULL) {
|
||||
zwlr_screencopy_frame_v1_destroy(frame->wlr_frame);
|
||||
frame->wlr_frame = NULL;
|
||||
}
|
||||
wl_list_remove(&frame->link);
|
||||
wl_list_init(&frame->link);
|
||||
output->spare = frame;
|
||||
}
|
||||
|
||||
static void capture_ready(void *data,
|
||||
struct zwlr_screencopy_frame_v1 *wlr_frame,
|
||||
uint32_t tv_sec_hi, uint32_t tv_sec_lo, uint32_t tv_nsec) {
|
||||
struct wd_frame *frame = data;
|
||||
struct wd_output *output = frame->output;
|
||||
|
||||
frame->pixels = mmap(NULL, frame->stride * frame->height,
|
||||
PROT_READ, MAP_SHARED, frame->capture_fd, 0);
|
||||
if (frame->pixels == MAP_FAILED) {
|
||||
frame->pixels = NULL;
|
||||
fprintf(stderr, "mmap: %d: %s\n", frame->capture_fd, strerror(errno));
|
||||
wd_frame_destroy(frame);
|
||||
return;
|
||||
} else {
|
||||
uint64_t tv_sec = (uint64_t) tv_sec_hi << 32 | tv_sec_lo;
|
||||
frame->tick = (tv_sec * 1000000) + (tv_nsec / 1000);
|
||||
}
|
||||
frame->pixels = frame->data;
|
||||
uint64_t tv_sec = (uint64_t) tv_sec_hi << 32 | tv_sec_lo;
|
||||
frame->tick = (tv_sec * 1000000) + (tv_nsec / 1000);
|
||||
|
||||
zwlr_screencopy_frame_v1_destroy(frame->wlr_frame);
|
||||
frame->wlr_frame = NULL;
|
||||
|
||||
struct wd_frame *frame_iter, *frame_tmp;
|
||||
wl_list_for_each_safe(frame_iter, frame_tmp, &frame->output->frames, link) {
|
||||
wl_list_for_each_safe(frame_iter, frame_tmp, &output->frames, link) {
|
||||
if (frame != frame_iter) {
|
||||
wd_frame_destroy(frame_iter);
|
||||
keep_as_spare(frame_iter);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -257,7 +289,7 @@ static void capture_ready(void *data,
|
||||
static void capture_failed(void *data,
|
||||
struct zwlr_screencopy_frame_v1 *wlr_frame) {
|
||||
struct wd_frame *frame = data;
|
||||
wd_frame_destroy(frame);
|
||||
keep_as_spare(frame);
|
||||
}
|
||||
|
||||
struct zwlr_screencopy_frame_v1_listener capture_listener = {
|
||||
@@ -288,11 +320,16 @@ void wd_capture_frame(struct wd_state *state) {
|
||||
|
||||
struct wd_output *output;
|
||||
wl_list_for_each(output, &state->outputs, link) {
|
||||
struct wd_frame *frame = calloc(1, sizeof(*frame));
|
||||
frame->output = output;
|
||||
frame->capture_fd = -1;
|
||||
struct wd_frame *frame = output->spare;
|
||||
output->spare = NULL;
|
||||
if (frame == NULL) {
|
||||
frame = calloc(1, sizeof(*frame));
|
||||
frame->output = output;
|
||||
frame->capture_fd = -1;
|
||||
}
|
||||
frame->pixels = NULL;
|
||||
frame->wlr_frame =
|
||||
zwlr_screencopy_manager_v1_capture_output(state->copy_manager, 1,
|
||||
zwlr_screencopy_manager_v1_capture_output(state->copy_manager, 0,
|
||||
output->wl_output);
|
||||
zwlr_screencopy_frame_v1_add_listener(frame->wlr_frame, &capture_listener,
|
||||
frame);
|
||||
@@ -300,11 +337,28 @@ void wd_capture_frame(struct wd_state *state) {
|
||||
}
|
||||
}
|
||||
|
||||
void wd_capture_release(struct wd_state *state) {
|
||||
struct wd_output *output;
|
||||
wl_list_for_each(output, &state->outputs, link) {
|
||||
struct wd_frame *frame, *frame_tmp;
|
||||
wl_list_for_each_safe(frame, frame_tmp, &output->frames, link) {
|
||||
wd_frame_destroy(frame);
|
||||
}
|
||||
if (output->spare != NULL) {
|
||||
wd_frame_destroy(output->spare);
|
||||
output->spare = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void wd_output_destroy(struct wd_output *output) {
|
||||
struct wd_frame *frame, *frame_tmp;
|
||||
wl_list_for_each_safe(frame, frame_tmp, &output->frames, link) {
|
||||
wd_frame_destroy(frame);
|
||||
}
|
||||
if (output->spare != NULL) {
|
||||
wd_frame_destroy(output->spare);
|
||||
}
|
||||
if (output->state->layer_shell != NULL) {
|
||||
wd_destroy_overlay(output);
|
||||
}
|
||||
|
||||
@@ -49,6 +49,7 @@ struct wd_output {
|
||||
|
||||
char *name;
|
||||
struct wl_list frames;
|
||||
struct wd_frame *spare;
|
||||
GtkWidget *overlay_window;
|
||||
struct zwlr_layer_surface_v1 *overlay_layer_surface;
|
||||
};
|
||||
@@ -62,8 +63,10 @@ struct wd_frame {
|
||||
unsigned stride;
|
||||
unsigned width;
|
||||
unsigned height;
|
||||
uint32_t format;
|
||||
struct wl_shm_pool *pool;
|
||||
struct wl_buffer *buffer;
|
||||
uint8_t *data;
|
||||
uint8_t *pixels;
|
||||
uint64_t tick;
|
||||
bool y_invert;
|
||||
@@ -223,6 +226,8 @@ struct wd_state {
|
||||
GdkCursor *move_cursor;
|
||||
|
||||
unsigned int canvas_tick;
|
||||
unsigned int capture_timeout;
|
||||
bool capture_due;
|
||||
struct wd_gl_data *gl_data;
|
||||
struct wd_render_data render;
|
||||
};
|
||||
@@ -283,6 +288,11 @@ void wd_capture_frame(struct wd_state *state);
|
||||
*/
|
||||
void wd_capture_wait(struct wd_state *state, struct wl_display *display);
|
||||
|
||||
/*
|
||||
* Frees all captured frames and their buffers.
|
||||
*/
|
||||
void wd_capture_release(struct wd_state *state);
|
||||
|
||||
/*
|
||||
* Updates the UI stack of all heads. Does not update individual head forms.
|
||||
* Useful for when a display is plugged/unplugged and we want to add/remove
|
||||
|
||||
Reference in New Issue
Block a user