diff --git a/include/rootston/desktop.h b/include/rootston/desktop.h index 90851a17f..8cee170fc 100644 --- a/include/rootston/desktop.h +++ b/include/rootston/desktop.h @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -57,6 +58,7 @@ struct roots_desktop { struct wlr_screencopy_manager_v1 *screencopy; struct wlr_tablet_manager_v2 *tablet_v2; struct wlr_pointer_constraints_v1 *pointer_constraints; + struct wlr_presentation *presentation; struct wl_listener new_output; struct wl_listener layout_change; diff --git a/include/rootston/output.h b/include/rootston/output.h index 69bc51260..3f07ab6f6 100644 --- a/include/rootston/output.h +++ b/include/rootston/output.h @@ -24,6 +24,7 @@ struct roots_output { struct wl_listener destroy; struct wl_listener mode; struct wl_listener transform; + struct wl_listener present; struct wl_listener damage_frame; struct wl_listener damage_destroy; }; diff --git a/rootston/desktop.c b/rootston/desktop.c index c180c8397..7f7490502 100644 --- a/rootston/desktop.c +++ b/rootston/desktop.c @@ -969,6 +969,9 @@ struct roots_desktop *desktop_create(struct roots_server *server, wl_signal_add(&desktop->pointer_constraints->events.new_constraint, &desktop->pointer_constraint); + desktop->presentation = + wlr_presentation_create(server->wl_display, server->backend); + return desktop; } diff --git a/rootston/output.c b/rootston/output.c index 1707be3ae..8168a0c3a 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -5,9 +5,10 @@ #include #include #include -#include #include +#include #include +#include #include #include #include @@ -784,6 +785,7 @@ static void output_destroy(struct roots_output *output) { wl_list_remove(&output->destroy.link); wl_list_remove(&output->mode.link); wl_list_remove(&output->transform.link); + wl_list_remove(&output->present.link); wl_list_remove(&output->damage_frame.link); wl_list_remove(&output->damage_destroy.link); free(output); @@ -820,6 +822,52 @@ static void output_handle_transform(struct wl_listener *listener, void *data) { arrange_layers(output); } +struct presentation_data { + struct layout_data layout; + struct roots_output *output; + struct wlr_presentation_event *event; +}; + +static void surface_send_presented(struct wlr_surface *surface, int sx, int sy, + void *_data) { + struct presentation_data *data = _data; + struct roots_output *output = data->output; + float rotation = data->layout.rotation; + + double lx, ly; + get_layout_position(&data->layout, &lx, &ly, surface, sx, sy); + + if (!surface_intersect_output(surface, output->desktop->layout, + output->wlr_output, lx, ly, rotation, NULL)) { + return; + } + + wlr_presentation_send_surface_presented(output->desktop->presentation, + surface, data->event); +} + +static void output_handle_present(struct wl_listener *listener, void *data) { + struct roots_output *output = + wl_container_of(listener, output, present); + struct wlr_output_event_present *output_event = data; + + struct wlr_presentation_event event = { + .output = output->wlr_output, + .tv_sec = (uint64_t)output_event->when->tv_sec, + .tv_nsec = (uint32_t)output_event->when->tv_nsec, + .refresh = 0, // TODO: predict next output vsync delay + .seq = (uint64_t)output_event->seq, + .flags = output_event->flags, + }; + + struct presentation_data presentation_data = { + .output = output, + .event = &event, + }; + output_for_each_surface(output, surface_send_presented, + &presentation_data.layout, &presentation_data); +} + void handle_new_output(struct wl_listener *listener, void *data) { struct roots_desktop *desktop = wl_container_of(listener, desktop, new_output); @@ -847,6 +895,8 @@ void handle_new_output(struct wl_listener *listener, void *data) { wl_signal_add(&wlr_output->events.mode, &output->mode); output->transform.notify = output_handle_transform; wl_signal_add(&wlr_output->events.transform, &output->transform); + output->present.notify = output_handle_present; + wl_signal_add(&wlr_output->events.present, &output->present); output->damage_frame.notify = output_damage_handle_frame; wl_signal_add(&output->damage->events.frame, &output->damage_frame);