diff options
Diffstat (limited to 'sway/desktop/output.c')
-rw-r--r-- | sway/desktop/output.c | 248 |
1 files changed, 192 insertions, 56 deletions
diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 2b428c30..0f00222b 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c | |||
@@ -1,9 +1,11 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | 1 | #define _POSIX_C_SOURCE 200809L |
2 | #include <assert.h> | ||
2 | #include <stdlib.h> | 3 | #include <stdlib.h> |
3 | #include <time.h> | 4 | #include <time.h> |
4 | #include <wayland-server.h> | 5 | #include <wayland-server.h> |
5 | #include <wlr/types/wlr_output.h> | 6 | #include <wlr/types/wlr_output.h> |
6 | #include <wlr/types/wlr_surface.h> | 7 | #include <wlr/types/wlr_surface.h> |
8 | #include <wlr/types/wlr_wl_shell.h> | ||
7 | #include <wlr/render.h> | 9 | #include <wlr/render.h> |
8 | #include <wlr/render/matrix.h> | 10 | #include <wlr/render/matrix.h> |
9 | #include "log.h" | 11 | #include "log.h" |
@@ -15,76 +17,198 @@ | |||
15 | #include "sway/input/input-manager.h" | 17 | #include "sway/input/input-manager.h" |
16 | #include "sway/input/seat.h" | 18 | #include "sway/input/seat.h" |
17 | 19 | ||
18 | static void output_frame_view(swayc_t *view, void *data) { | 20 | /** |
19 | struct sway_output *output = data; | 21 | * Rotate a child's position relative to a parent. The parent size is (pw, ph), |
20 | struct wlr_output *wlr_output = output->wlr_output; | 22 | * the child position is (*sx, *sy) and its size is (sw, sh). |
21 | struct sway_view *sway_view = view->sway_view; | 23 | */ |
22 | struct wlr_surface *surface = sway_view->surface; | 24 | static void rotate_child_position(double *sx, double *sy, double sw, double sh, |
25 | double pw, double ph, float rotation) { | ||
26 | if (rotation != 0.0) { | ||
27 | // Coordinates relative to the center of the subsurface | ||
28 | double ox = *sx - pw/2 + sw/2, | ||
29 | oy = *sy - ph/2 + sh/2; | ||
30 | // Rotated coordinates | ||
31 | double rx = cos(-rotation)*ox - sin(-rotation)*oy, | ||
32 | ry = cos(-rotation)*oy + sin(-rotation)*ox; | ||
33 | *sx = rx + pw/2 - sw/2; | ||
34 | *sy = ry + ph/2 - sh/2; | ||
35 | } | ||
36 | } | ||
37 | |||
38 | static void render_surface(struct wlr_surface *surface, | ||
39 | struct wlr_output *wlr_output, struct timespec *when, | ||
40 | double lx, double ly, float rotation) { | ||
23 | if (!wlr_surface_has_buffer(surface)) { | 41 | if (!wlr_surface_has_buffer(surface)) { |
24 | return; | 42 | return; |
25 | } | 43 | } |
26 | // TODO | 44 | struct wlr_output_layout *layout = root_container.sway_root->output_layout; |
27 | // - Deal with wlr_output_layout | 45 | int width = surface->current->width; |
28 | int width = sway_view->surface->current->width; | 46 | int height = surface->current->height; |
29 | int height = sway_view->surface->current->height; | ||
30 | int render_width = width * wlr_output->scale; | 47 | int render_width = width * wlr_output->scale; |
31 | int render_height = height * wlr_output->scale; | 48 | int render_height = height * wlr_output->scale; |
32 | double ox = view->x, oy = view->y; | 49 | double ox = lx, oy = ly; |
33 | // TODO | 50 | wlr_output_layout_output_coords(layout, wlr_output, &ox, &oy); |
34 | //wlr_output_layout_output_coords(desktop->layout, wlr_output, &ox, &oy); | ||
35 | ox *= wlr_output->scale; | 51 | ox *= wlr_output->scale; |
36 | oy *= wlr_output->scale; | 52 | oy *= wlr_output->scale; |
37 | // TODO | 53 | |
38 | //if (wlr_output_layout_intersects(desktop->layout, wlr_output, | 54 | struct wlr_box render_box = { |
39 | // lx, ly, lx + render_width, ly + render_height)) { | 55 | .x = lx, .y = ly, |
40 | // return; | 56 | .width = render_width, .height = render_height, |
41 | //} | 57 | }; |
42 | 58 | if (wlr_output_layout_intersects(layout, wlr_output, &render_box)) { | |
43 | // if the shell specifies window geometry, make the top left corner of the | 59 | float matrix[16]; |
44 | // window in the top left corner of the container to avoid arbitrarily | 60 | |
45 | // sized gaps based on the attached buffer size | 61 | float translate_center[16]; |
46 | int window_offset_x = 0; | 62 | wlr_matrix_translate(&translate_center, |
47 | int window_offset_y = 0; | 63 | (int)ox + render_width / 2, (int)oy + render_height / 2, 0); |
48 | 64 | ||
49 | if (view->sway_view->type == SWAY_XDG_SHELL_V6_VIEW) { | 65 | float rotate[16]; |
50 | window_offset_x = view->sway_view->wlr_xdg_surface_v6->geometry->x; | 66 | wlr_matrix_rotate(&rotate, rotation); |
51 | window_offset_y = view->sway_view->wlr_xdg_surface_v6->geometry->y; | 67 | |
68 | float translate_origin[16]; | ||
69 | wlr_matrix_translate(&translate_origin, -render_width / 2, | ||
70 | -render_height / 2, 0); | ||
71 | |||
72 | float scale[16]; | ||
73 | wlr_matrix_scale(&scale, render_width, render_height, 1); | ||
74 | |||
75 | float transform[16]; | ||
76 | wlr_matrix_mul(&translate_center, &rotate, &transform); | ||
77 | wlr_matrix_mul(&transform, &translate_origin, &transform); | ||
78 | wlr_matrix_mul(&transform, &scale, &transform); | ||
79 | |||
80 | if (surface->current->transform != WL_OUTPUT_TRANSFORM_NORMAL) { | ||
81 | float surface_translate_center[16]; | ||
82 | wlr_matrix_translate(&surface_translate_center, 0.5, 0.5, 0); | ||
83 | |||
84 | float surface_transform[16]; | ||
85 | wlr_matrix_transform(surface_transform, | ||
86 | wlr_output_transform_invert(surface->current->transform)); | ||
87 | |||
88 | float surface_translate_origin[16]; | ||
89 | wlr_matrix_translate(&surface_translate_origin, -0.5, -0.5, 0); | ||
90 | |||
91 | wlr_matrix_mul(&transform, &surface_translate_center, | ||
92 | &transform); | ||
93 | wlr_matrix_mul(&transform, &surface_transform, &transform); | ||
94 | wlr_matrix_mul(&transform, &surface_translate_origin, | ||
95 | &transform); | ||
96 | } | ||
97 | |||
98 | wlr_matrix_mul(&wlr_output->transform_matrix, &transform, &matrix); | ||
99 | |||
100 | wlr_render_with_matrix(server.renderer, surface->texture, | ||
101 | &matrix); | ||
102 | |||
103 | wlr_surface_send_frame_done(surface, when); | ||
52 | } | 104 | } |
53 | 105 | ||
54 | // TODO | 106 | struct wlr_subsurface *subsurface; |
55 | double rotation = 0; | 107 | wl_list_for_each(subsurface, &surface->subsurface_list, parent_link) { |
56 | float matrix[16]; | 108 | struct wlr_surface_state *state = subsurface->surface->current; |
109 | double sx = state->subsurface_position.x; | ||
110 | double sy = state->subsurface_position.y; | ||
111 | double sw = state->buffer_width / state->scale; | ||
112 | double sh = state->buffer_height / state->scale; | ||
113 | rotate_child_position(&sx, &sy, sw, sh, width, height, rotation); | ||
57 | 114 | ||
58 | float translate_origin[16]; | 115 | render_surface(subsurface->surface, wlr_output, when, |
59 | wlr_matrix_translate(&translate_origin, | 116 | lx + sx, |
60 | (int)ox + render_width / 2 - window_offset_x, | 117 | ly + sy, |
61 | (int)oy + render_height / 2 - window_offset_y, | 118 | rotation); |
62 | 0); | 119 | } |
120 | } | ||
63 | 121 | ||
64 | float rotate[16]; | 122 | static void render_xdg_v6_popups(struct wlr_xdg_surface_v6 *surface, |
65 | wlr_matrix_rotate(&rotate, rotation); | 123 | struct wlr_output *wlr_output, struct timespec *when, double base_x, |
124 | double base_y, float rotation) { | ||
125 | double width = surface->surface->current->width; | ||
126 | double height = surface->surface->current->height; | ||
66 | 127 | ||
67 | float translate_center[16]; | 128 | struct wlr_xdg_surface_v6 *popup; |
68 | wlr_matrix_translate(&translate_center, | 129 | wl_list_for_each(popup, &surface->popups, popup_link) { |
69 | -render_width / 2, | 130 | if (!popup->configured) { |
70 | -render_height / 2, 0); | 131 | continue; |
132 | } | ||
71 | 133 | ||
72 | float scale[16]; | 134 | double popup_width = popup->surface->current->width; |
73 | wlr_matrix_scale(&scale, render_width, render_height, 1); | 135 | double popup_height = popup->surface->current->height; |
74 | 136 | ||
75 | float transform[16]; | 137 | double popup_sx, popup_sy; |
76 | wlr_matrix_mul(&translate_origin, &rotate, &transform); | 138 | wlr_xdg_surface_v6_popup_get_position(popup, &popup_sx, &popup_sy); |
77 | wlr_matrix_mul(&transform, &translate_center, &transform); | 139 | rotate_child_position(&popup_sx, &popup_sy, popup_width, popup_height, |
78 | wlr_matrix_mul(&transform, &scale, &transform); | 140 | width, height, rotation); |
79 | wlr_matrix_mul(&wlr_output->transform_matrix, &transform, &matrix); | ||
80 | 141 | ||
81 | wlr_render_with_matrix(output->server->renderer, surface->texture, &matrix); | 142 | render_surface(popup->surface, wlr_output, when, |
143 | base_x + popup_sx, base_y + popup_sy, rotation); | ||
144 | render_xdg_v6_popups(popup, wlr_output, when, | ||
145 | base_x + popup_sx, base_y + popup_sy, rotation); | ||
146 | } | ||
147 | } | ||
82 | 148 | ||
83 | // TODO: move into wlroots | 149 | static void render_wl_shell_surface(struct wlr_wl_shell_surface *surface, |
84 | struct timespec now; | 150 | struct wlr_output *wlr_output, struct timespec *when, |
85 | clock_gettime(CLOCK_MONOTONIC, &now); | 151 | double lx, double ly, float rotation, |
152 | bool is_child) { | ||
153 | if (is_child || surface->state != WLR_WL_SHELL_SURFACE_STATE_POPUP) { | ||
154 | render_surface(surface->surface, wlr_output, when, | ||
155 | lx, ly, rotation); | ||
156 | |||
157 | double width = surface->surface->current->width; | ||
158 | double height = surface->surface->current->height; | ||
159 | |||
160 | struct wlr_wl_shell_surface *popup; | ||
161 | wl_list_for_each(popup, &surface->popups, popup_link) { | ||
162 | double popup_width = popup->surface->current->width; | ||
163 | double popup_height = popup->surface->current->height; | ||
164 | |||
165 | double popup_x = popup->transient_state->x; | ||
166 | double popup_y = popup->transient_state->y; | ||
167 | rotate_child_position(&popup_x, &popup_y, popup_width, popup_height, | ||
168 | width, height, rotation); | ||
169 | |||
170 | render_wl_shell_surface(popup, wlr_output, when, | ||
171 | lx + popup_x, ly + popup_y, rotation, true); | ||
172 | } | ||
173 | } | ||
174 | } | ||
175 | |||
176 | |||
177 | static void output_frame_view(swayc_t *view, void *data) { | ||
178 | struct sway_output *output = data; | ||
179 | struct wlr_output *wlr_output = output->wlr_output; | ||
180 | struct sway_view *sway_view = view->sway_view; | ||
181 | struct wlr_surface *surface = sway_view->surface; | ||
182 | |||
183 | if (!surface) { | ||
184 | return; | ||
185 | } | ||
86 | 186 | ||
87 | wlr_surface_send_frame_done(surface, &now); | 187 | switch (sway_view->type) { |
188 | case SWAY_XDG_SHELL_V6_VIEW: { | ||
189 | int window_offset_x = view->sway_view->wlr_xdg_surface_v6->geometry->x; | ||
190 | int window_offset_y = view->sway_view->wlr_xdg_surface_v6->geometry->y; | ||
191 | render_surface(surface, wlr_output, &output->last_frame, | ||
192 | view->x - window_offset_x, | ||
193 | view->y - window_offset_y, | ||
194 | 0); | ||
195 | render_xdg_v6_popups(sway_view->wlr_xdg_surface_v6, wlr_output, | ||
196 | &output->last_frame, | ||
197 | view->x - window_offset_x, view->y - window_offset_y, | ||
198 | 0); | ||
199 | break; | ||
200 | } | ||
201 | case SWAY_WL_SHELL_VIEW: | ||
202 | render_wl_shell_surface(sway_view->wlr_wl_shell_surface, wlr_output, | ||
203 | &output->last_frame, view->x, view->y, 0, false); | ||
204 | break; | ||
205 | case SWAY_XWAYLAND_VIEW: | ||
206 | render_surface(surface, wlr_output, &output->last_frame, view->x, | ||
207 | view->y, 0); | ||
208 | break; | ||
209 | default: | ||
210 | break; | ||
211 | } | ||
88 | } | 212 | } |
89 | 213 | ||
90 | static void output_frame_notify(struct wl_listener *listener, void *data) { | 214 | static void output_frame_notify(struct wl_listener *listener, void *data) { |
@@ -92,18 +216,30 @@ static void output_frame_notify(struct wl_listener *listener, void *data) { | |||
92 | struct wlr_output *wlr_output = data; | 216 | struct wlr_output *wlr_output = data; |
93 | struct sway_server *server = soutput->server; | 217 | struct sway_server *server = soutput->server; |
94 | 218 | ||
95 | struct timespec now; | ||
96 | clock_gettime(CLOCK_MONOTONIC, &now); | ||
97 | |||
98 | wlr_output_make_current(wlr_output); | 219 | wlr_output_make_current(wlr_output); |
99 | wlr_renderer_begin(server->renderer, wlr_output); | 220 | wlr_renderer_begin(server->renderer, wlr_output); |
100 | 221 | ||
101 | swayc_descendants_of_type( | 222 | swayc_descendants_of_type( |
102 | &root_container, C_VIEW, output_frame_view, soutput); | 223 | &root_container, C_VIEW, output_frame_view, soutput); |
103 | 224 | ||
225 | // render unmanaged views on top | ||
226 | struct sway_view *view; | ||
227 | wl_list_for_each(view, &root_container.sway_root->unmanaged_views, | ||
228 | unmanaged_view_link) { | ||
229 | if (view->type == SWAY_XWAYLAND_VIEW) { | ||
230 | // the only kind of unamanged view right now is xwayland override redirect | ||
231 | int view_x = view->wlr_xwayland_surface->x; | ||
232 | int view_y = view->wlr_xwayland_surface->y; | ||
233 | render_surface(view->surface, wlr_output, &soutput->last_frame, | ||
234 | view_x, view_y, 0); | ||
235 | } | ||
236 | } | ||
237 | |||
104 | wlr_renderer_end(server->renderer); | 238 | wlr_renderer_end(server->renderer); |
105 | wlr_output_swap_buffers(wlr_output); | 239 | wlr_output_swap_buffers(wlr_output); |
106 | 240 | ||
241 | struct timespec now; | ||
242 | clock_gettime(CLOCK_MONOTONIC, &now); | ||
107 | soutput->last_frame = now; | 243 | soutput->last_frame = now; |
108 | } | 244 | } |
109 | 245 | ||