aboutsummaryrefslogtreecommitdiff
path: root/rootston/output.c
diff options
context:
space:
mode:
Diffstat (limited to 'rootston/output.c')
-rw-r--r--rootston/output.c185
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);