diff options
Diffstat (limited to 'rootston/output.c')
-rw-r--r-- | rootston/output.c | 185 |
1 files changed, 123 insertions, 62 deletions
diff --git a/rootston/output.c b/rootston/output.c index 674cda2d..9aa7de65 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -5,9 +5,10 @@ #include <time.h> #include <wlr/backend/drm.h> #include <wlr/config.h> -#include <wlr/types/wlr_matrix.h> #include <wlr/types/wlr_compositor.h> +#include <wlr/types/wlr_matrix.h> #include <wlr/types/wlr_output_layout.h> +#include <wlr/types/wlr_presentation_time.h> #include <wlr/types/wlr_wl_shell.h> #include <wlr/types/wlr_xdg_shell_v6.h> #include <wlr/types/wlr_xdg_shell.h> @@ -22,7 +23,7 @@ * Rotate a child's position relative to a parent. The parent size is (pw, ph), * the child position is (*sx, *sy) and its size is (sw, sh). */ -static void rotate_child_position(double *sx, double *sy, double sw, double sh, +void rotate_child_position(double *sx, double *sy, double sw, double sh, double pw, double ph, float rotation) { if (rotation != 0.0) { // Coordinates relative to the center of the subsurface @@ -127,6 +128,65 @@ static void drag_icons_for_each_surface(struct roots_input *input, } } +static void layer_for_each_surface(struct wl_list *layer, + const struct wlr_box *output_layout_box, + wlr_surface_iterator_func_t iterator, struct layout_data *layout_data, + void *user_data) { + struct roots_layer_surface *roots_surface; + wl_list_for_each(roots_surface, layer, link) { + struct wlr_layer_surface_v1 *layer = roots_surface->layer_surface; + + layout_data->x = roots_surface->geo.x + output_layout_box->x; + layout_data->y = roots_surface->geo.y + output_layout_box->y; + layout_data->width = roots_surface->geo.width; + layout_data->height = roots_surface->geo.height; + layout_data->rotation = 0; + wlr_layer_surface_v1_for_each_surface(layer, iterator, user_data); + } +} + +static void output_for_each_surface(struct roots_output *output, + wlr_surface_iterator_func_t iterator, struct layout_data *layout_data, + void *user_data) { + struct wlr_output *wlr_output = output->wlr_output; + struct roots_desktop *desktop = output->desktop; + struct roots_server *server = desktop->server; + + const struct wlr_box *output_box = + wlr_output_layout_get_box(desktop->layout, wlr_output); + + if (output->fullscreen_view != NULL) { + struct roots_view *view = output->fullscreen_view; + if (wlr_output->fullscreen_surface == view->wlr_surface) { + // The surface is managed by the wlr_output + return; + } + + view_for_each_surface(view, layout_data, iterator, user_data); + +#ifdef WLR_HAS_XWAYLAND + if (view->type == ROOTS_XWAYLAND_VIEW) { + xwayland_children_for_each_surface(view->xwayland_surface, + iterator, layout_data, user_data); + } +#endif + } else { + struct roots_view *view; + wl_list_for_each_reverse(view, &desktop->views, link) { + view_for_each_surface(view, layout_data, iterator, user_data); + } + + drag_icons_for_each_surface(server->input, iterator, + layout_data, user_data); + } + + size_t len = sizeof(output->layers) / sizeof(output->layers[0]); + for (size_t i = 0; i < len; ++i) { + layer_for_each_surface(&output->layers[i], output_box, + iterator, layout_data, user_data); + } +} + struct render_data { struct layout_data layout; @@ -320,6 +380,14 @@ static void render_view(struct roots_view *view, struct render_data *data) { view_for_each_surface(view, &data->layout, render_surface, data); } +static void render_layer(struct roots_output *output, + const struct wlr_box *output_layout_box, struct render_data *data, + struct wl_list *layer) { + data->alpha = 1; + layer_for_each_surface(layer, output_layout_box, render_surface, + &data->layout, data); +} + static bool has_standalone_surface(struct roots_view *view) { if (!wl_list_empty(&view->wlr_surface->subsurfaces)) { return false; @@ -358,38 +426,6 @@ static void surface_send_frame_done(struct wlr_surface *surface, int sx, int sy, wlr_surface_send_frame_done(surface, when); } -static void render_layer(struct roots_output *output, - const struct wlr_box *output_layout_box, struct render_data *data, - struct wl_list *layer) { - struct roots_layer_surface *roots_surface; - wl_list_for_each(roots_surface, layer, link) { - struct wlr_layer_surface_v1 *layer = roots_surface->layer_surface; - - surface_for_each_surface(layer->surface, - roots_surface->geo.x + output_layout_box->x, - roots_surface->geo.y + output_layout_box->y, - 0, &data->layout, render_surface, data); - - wlr_layer_surface_v1_for_each_surface(layer, render_surface, data); - } -} - -static void layers_send_done( - struct roots_output *output, struct timespec *when) { - size_t len = sizeof(output->layers) / sizeof(output->layers[0]); - for (size_t i = 0; i < len; ++i) { - struct roots_layer_surface *roots_surface; - wl_list_for_each(roots_surface, &output->layers[i], link) { - struct wlr_layer_surface_v1 *layer = roots_surface->layer_surface; - wlr_surface_send_frame_done(layer->surface, when); - struct wlr_xdg_popup *popup; - wl_list_for_each(popup, &roots_surface->layer_surface->popups, link) { - wlr_surface_send_frame_done(popup->base->surface, when); - } - } - } -} - static void render_output(struct roots_output *output) { struct wlr_output *wlr_output = output->wlr_output; struct roots_desktop *desktop = output->desktop; @@ -423,7 +459,8 @@ static void render_output(struct roots_output *output) { output_box->y; view_move(view, view_x, view_y); - if (has_standalone_surface(view)) { + if (has_standalone_surface(view) && + wl_list_empty(&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY])) { wlr_output_set_fullscreen_surface(wlr_output, view->wlr_surface); } else { wlr_output_set_fullscreen_surface(wlr_output, NULL); @@ -537,33 +574,8 @@ damage_finish: pixman_region32_fini(&damage); // Send frame done events to all surfaces - if (output->fullscreen_view != NULL) { - struct roots_view *view = output->fullscreen_view; - if (wlr_output->fullscreen_surface == view->wlr_surface) { - // The surface is managed by the wlr_output - return; - } - - view_for_each_surface(view, &data.layout, surface_send_frame_done, - &data); - -#ifdef WLR_HAS_XWAYLAND - if (view->type == ROOTS_XWAYLAND_VIEW) { - xwayland_children_for_each_surface(view->xwayland_surface, - surface_send_frame_done, &data.layout, &data); - } -#endif - } else { - struct roots_view *view; - wl_list_for_each_reverse(view, &desktop->views, link) { - view_for_each_surface(view, &data.layout, surface_send_frame_done, - &data); - } - - drag_icons_for_each_surface(server->input, surface_send_frame_done, - &data.layout, &data); - } - layers_send_done(output, data.when); + output_for_each_surface(output, surface_send_frame_done, + &data.layout, &data); } void output_damage_whole(struct roots_output *output) { @@ -769,6 +781,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); @@ -805,6 +818,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 = (uint32_t)output_event->refresh, + .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); @@ -832,6 +891,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); |