Merge tag '0.5.0' into debian/sid
wlroots 0.5.0
Brian Ashworth (1):
wlr_output_layout_get_box: handle empty layout
Guido Günther (4):
Unbreak build with '-Wstrict-prototypes'
rootston/view: Remove redundant declaration in the same file
wlr_xdg_shell: Remove redundant declaration in the same file
Remove glEGLImageTargetTexture2DOES
Ian Fan (1):
seat: fix remaining wlr_button_state enum rename
Ilia Bozhinov (2):
xwm: use min size as base size hint if it is missing and vice versa
xwm: fix typos in WM_NORMAL_HINTS handling
Niklas Schulze (1):
backend/session: Allow setting a custom tty via WLR_DIRECT_TTY
Scott Anderson (1):
backend/drm: Don't fail on failing to find overlay format
emersion (15):
seat: guard against button count corruption
meson: enable more compiler warnings
seat: use wlr_button_state enum instead of uint32_t
seat: only store serial if pressing a button
tinywl: send pointer frame events
backend/session: add noop session
rootston: refactor rendering
rootston: fix rotated views rendering
rootston: fix Xwayland children rendering when fullscreen
rootston: split rendering code into render.c
rootston: fix input events for rotated views
xwayland: don't set DISPLAY
seat: add debug logs when validating grab serials
backend/session: open TTY with O_CLOEXEC for direct session
xwayland: set CLOEXEC on /dev/null FD
Guido Günther
5 years ago
132 | 132 | rgb_format = fmt; |
133 | 133 | } |
134 | 134 | } |
135 | if (rgb_format == DRM_FORMAT_INVALID) { | |
135 | // Some overlays exist which don't support XRGB8888/ARGB8888 | |
136 | // We aren't even using overlay planes currently, so don't fail | |
137 | // on something unnecessary. | |
138 | if (type != DRM_PLANE_TYPE_OVERLAY && rgb_format == DRM_FORMAT_INVALID) { | |
136 | 139 | wlr_log(WLR_ERROR, "Failed to find an RGB format for plane %zu", i); |
137 | 140 | drmModeFreePlane(plane); |
138 | 141 | goto error_planes; |
22 | 22 | 'noop/backend.c', |
23 | 23 | 'noop/output.c', |
24 | 24 | 'session/direct-ipc.c', |
25 | 'session/noop.c', | |
25 | 26 | 'session/session.c', |
26 | 27 | 'wayland/backend.c', |
27 | 28 | 'wayland/output.c', |
154 | 154 | } |
155 | 155 | |
156 | 156 | static bool setup_tty(struct direct_session *session, struct wl_display *display) { |
157 | int fd = open("/dev/tty", O_RDWR); | |
157 | ||
158 | bool default_tty = false; | |
159 | ||
160 | const char *tty_path = getenv("WLR_DIRECT_TTY"); | |
161 | ||
162 | if (!tty_path) { | |
163 | tty_path = "/dev/tty"; | |
164 | default_tty = true; | |
165 | } | |
166 | ||
167 | int fd = open(tty_path, O_RDWR | O_CLOEXEC); | |
158 | 168 | if (fd == -1) { |
159 | wlr_log_errno(WLR_ERROR, "Cannot open /dev/tty"); | |
169 | wlr_log_errno(WLR_ERROR, "Cannot open %s", tty_path); | |
160 | 170 | return false; |
161 | 171 | } |
162 | 172 | |
175 | 185 | goto error; |
176 | 186 | } |
177 | 187 | |
178 | if (kd_mode != KD_TEXT) { | |
188 | if (default_tty && kd_mode != KD_TEXT) { | |
179 | 189 | wlr_log(WLR_ERROR, |
180 | 190 | "tty already in graphics mode; is another display server running?"); |
181 | 191 | goto error; |
439 | 439 | int ret; |
440 | 440 | |
441 | 441 | char str[256]; |
442 | const char *fmt = "type='signal'," | |
442 | const char fmt[] = "type='signal'," | |
443 | 443 | "sender='org.freedesktop.login1'," |
444 | 444 | "interface='org.freedesktop.login1.%s'," |
445 | 445 | "member='%s'," |
0 | #define _POSIX_C_SOURCE 200809L | |
1 | #include <fcntl.h> | |
2 | #include <stdbool.h> | |
3 | #include <stdlib.h> | |
4 | #include <unistd.h> | |
5 | #include <wayland-server.h> | |
6 | #include <wlr/backend/session/interface.h> | |
7 | #include <wlr/util/log.h> | |
8 | #include "util/signal.h" | |
9 | ||
10 | const struct session_impl session_noop; | |
11 | ||
12 | static int noop_session_open(struct wlr_session *base, const char *path) { | |
13 | return open(path, O_RDWR | O_CLOEXEC); | |
14 | } | |
15 | ||
16 | static void noop_session_close(struct wlr_session *base, int fd) { | |
17 | close(fd); | |
18 | } | |
19 | ||
20 | static bool noop_change_vt(struct wlr_session *base, unsigned vt) { | |
21 | return false; | |
22 | } | |
23 | ||
24 | static void noop_session_destroy(struct wlr_session *base) { | |
25 | free(base); | |
26 | } | |
27 | ||
28 | static struct wlr_session *noop_session_create(struct wl_display *disp) { | |
29 | struct wlr_session *session = calloc(1, sizeof(*session)); | |
30 | if (!session) { | |
31 | wlr_log_errno(WLR_ERROR, "Allocation failed"); | |
32 | return NULL; | |
33 | } | |
34 | ||
35 | session->impl = &session_noop; | |
36 | ||
37 | wlr_log(WLR_INFO, "Successfully initialized noop session"); | |
38 | return session; | |
39 | } | |
40 | ||
41 | const struct session_impl session_noop = { | |
42 | .create = noop_session_create, | |
43 | .destroy = noop_session_destroy, | |
44 | .open = noop_session_open, | |
45 | .close = noop_session_close, | |
46 | .change_vt = noop_change_vt, | |
47 | }; |
16 | 16 | |
17 | 17 | extern const struct session_impl session_logind; |
18 | 18 | extern const struct session_impl session_direct; |
19 | extern const struct session_impl session_noop; | |
19 | 20 | |
20 | 21 | static const struct session_impl *impls[] = { |
21 | 22 | #if WLR_HAS_SYSTEMD || WLR_HAS_ELOGIND |
68 | 69 | |
69 | 70 | const char *env_wlr_session = getenv("WLR_SESSION"); |
70 | 71 | if (env_wlr_session) { |
71 | if (!strcmp(env_wlr_session, "logind") || !strcmp(env_wlr_session, "systemd")) { | |
72 | #if WLR_HAS_SYSTEMD || WLR_HAS_ELOGIND | |
72 | if (strcmp(env_wlr_session, "logind") == 0 || | |
73 | strcmp(env_wlr_session, "systemd") == 0) { | |
74 | #if WLR_HAS_SYSTEMD || WLR_HAS_ELOGIND | |
73 | 75 | session = session_logind.create(disp); |
74 | #else | |
76 | #else | |
75 | 77 | wlr_log(WLR_ERROR, "wlroots is not compiled with logind support"); |
76 | #endif | |
77 | } else if (!strcmp(env_wlr_session, "direct")) { | |
78 | #endif | |
79 | } else if (strcmp(env_wlr_session, "direct") == 0) { | |
78 | 80 | session = session_direct.create(disp); |
81 | } else if (strcmp(env_wlr_session, "noop") == 0) { | |
82 | session = session_noop.create(disp); | |
79 | 83 | } else { |
80 | wlr_log(WLR_ERROR, "WLR_SESSION has an invalid value: %s", env_wlr_session); | |
84 | wlr_log(WLR_ERROR, "Unsupported WLR_SESSION: %s", | |
85 | env_wlr_session); | |
81 | 86 | } |
82 | 87 | } else { |
83 | 88 | const struct session_impl **iter; |
219 | 224 | /* Tests if 'path' is KMS compatible by trying to open it. |
220 | 225 | * It leaves the open device in *fd_out it it succeeds. |
221 | 226 | */ |
222 | static int open_if_kms(struct wlr_session *restrict session, const char *restrict path) { | |
223 | int fd; | |
224 | ||
227 | static int open_if_kms(struct wlr_session *restrict session, | |
228 | const char *restrict path) { | |
225 | 229 | if (!path) { |
226 | 230 | return -1; |
227 | 231 | } |
228 | 232 | |
229 | fd = wlr_session_open_file(session, path); | |
233 | int fd = wlr_session_open_file(session, path); | |
230 | 234 | if (fd < 0) { |
231 | 235 | return -1; |
232 | 236 | } |
233 | 237 | |
234 | drmModeRes *res = drmModeGetResources(fd); | |
235 | if (!res) { | |
238 | drmVersion *ver = drmGetVersion(fd); | |
239 | if (!ver) { | |
236 | 240 | goto out_fd; |
237 | 241 | } |
238 | 242 | |
239 | drmModeFreeResources(res); | |
243 | drmFreeVersion(ver); | |
240 | 244 | return fd; |
241 | 245 | |
242 | 246 | out_fd: |
193 | 193 | // TODO: set keymap |
194 | 194 | } |
195 | 195 | |
196 | static uint32_t get_current_time_msec() { | |
196 | static uint32_t get_current_time_msec(void) { | |
197 | 197 | struct timespec now; |
198 | 198 | clock_gettime(CLOCK_MONOTONIC, &now); |
199 | 199 | return now.tv_nsec / 1000; |
19 | 19 | hardware cursors |
20 | 20 | * *WLR_SESSION*: specifies the wlr\_session to be used (available sessions: |
21 | 21 | logind/systemd, direct) |
22 | * *WLR_DIRECT_TTY*: specifies the tty to be used (instead of using /dev/tty) | |
22 | 23 | |
23 | 24 | rootston specific |
24 | 25 | ------------------ |
175 | 175 | } |
176 | 176 | } |
177 | 177 | |
178 | static void do_updates() { | |
178 | static void do_updates(void) { | |
179 | 179 | printf("Update %d\n", update_stage); |
180 | 180 | switch (update_stage) { |
181 | 181 | case 0: |
239 | 239 | }; |
240 | 240 | } |
241 | 241 | |
242 | static void handle_timer() { | |
242 | static void handle_timer(void) { | |
243 | 243 | printf("Timer dispatched at %d\n", update_stage); |
244 | 244 | do_updates(); |
245 | 245 | } |
101 | 101 | } |
102 | 102 | |
103 | 103 | // TODO: would be nicer to have this text display inside the window |
104 | static void show_status() { | |
104 | static void show_status(void) { | |
105 | 105 | printf("State %d:", serial); |
106 | 106 | if (!enabled) { |
107 | 107 | printf(" disabled"); |
14 | 14 | #include <wlr/render/wlr_renderer.h> |
15 | 15 | #include <wlr/render/wlr_texture.h> |
16 | 16 | #include <wlr/util/log.h> |
17 | ||
18 | extern PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES; | |
19 | 17 | |
20 | 18 | struct wlr_gles2_pixel_format { |
21 | 19 | enum wl_shm_format wl_format; |
28 | 28 | struct wl_listener damage_destroy; |
29 | 29 | }; |
30 | 30 | |
31 | typedef void (*roots_surface_iterator_func_t)(struct roots_output *output, | |
32 | struct wlr_surface *surface, struct wlr_box *box, float rotation, | |
33 | void *user_data); | |
34 | ||
31 | 35 | void rotate_child_position(double *sx, double *sy, double sw, double sh, |
32 | 36 | double pw, double ph, float rotation); |
37 | ||
38 | struct roots_input; | |
39 | ||
40 | void output_surface_for_each_surface(struct roots_output *output, | |
41 | struct wlr_surface *surface, double ox, double oy, | |
42 | roots_surface_iterator_func_t iterator, void *user_data); | |
43 | void output_view_for_each_surface(struct roots_output *output, | |
44 | struct roots_view *view, roots_surface_iterator_func_t iterator, | |
45 | void *user_data); | |
46 | void output_drag_icons_for_each_surface(struct roots_output *output, | |
47 | struct roots_input *input, roots_surface_iterator_func_t iterator, | |
48 | void *user_data); | |
49 | void output_layer_for_each_surface(struct roots_output *output, | |
50 | struct wl_list *layer_surfaces, roots_surface_iterator_func_t iterator, | |
51 | void *user_data); | |
52 | #if WLR_HAS_XWAYLAND | |
53 | struct wlr_xwayland_surface; | |
54 | void output_xwayland_children_for_each_surface( | |
55 | struct roots_output *output, struct wlr_xwayland_surface *surface, | |
56 | roots_surface_iterator_func_t iterator, void *user_data); | |
57 | #endif | |
58 | void output_for_each_surface(struct roots_output *output, | |
59 | roots_surface_iterator_func_t iterator, void *user_data); | |
33 | 60 | |
34 | 61 | void handle_new_output(struct wl_listener *listener, void *data); |
35 | 62 | |
44 | 71 | void output_damage_whole_drag_icon(struct roots_output *output, |
45 | 72 | struct roots_drag_icon *icon); |
46 | 73 | void output_damage_from_local_surface(struct roots_output *output, |
47 | struct wlr_surface *surface, double ox, double oy, float rotation); | |
74 | struct wlr_surface *surface, double ox, double oy); | |
48 | 75 | void output_damage_whole_local_surface(struct roots_output *output, |
49 | struct wlr_surface *surface, double ox, double oy, float rotation); | |
76 | struct wlr_surface *surface, double ox, double oy); | |
77 | ||
78 | void output_render(struct roots_output *output); | |
79 | ||
80 | void scale_box(struct wlr_box *box, float scale); | |
81 | void get_decoration_box(struct roots_view *view, | |
82 | struct roots_output *output, struct wlr_box *box); | |
50 | 83 | |
51 | 84 | #endif |
19 | 19 | void (*maximize)(struct roots_view *view, bool maximized); |
20 | 20 | void (*set_fullscreen)(struct roots_view *view, bool fullscreen); |
21 | 21 | void (*close)(struct roots_view *view); |
22 | void (*for_each_surface)(struct roots_view *view, | |
23 | wlr_surface_iterator_func_t iterator, void *user_data); | |
22 | 24 | void (*destroy)(struct roots_view *view); |
23 | 25 | }; |
24 | 26 | |
221 | 223 | void view_init(struct roots_view *view, const struct roots_view_interface *impl, |
222 | 224 | enum roots_view_type type, struct roots_desktop *desktop); |
223 | 225 | void view_destroy(struct roots_view *view); |
224 | void view_activate(struct roots_view *view, bool activate); | |
225 | 226 | void view_apply_damage(struct roots_view *view); |
226 | 227 | void view_damage_whole(struct roots_view *view); |
227 | 228 | void view_update_position(struct roots_view *view, int x, int y); |
250 | 251 | void view_set_app_id(struct roots_view *view, const char *app_id); |
251 | 252 | void view_create_foreign_toplevel_handle(struct roots_view *view); |
252 | 253 | void view_get_deco_box(const struct roots_view *view, struct wlr_box *box); |
254 | void view_for_each_surface(struct roots_view *view, | |
255 | wlr_surface_iterator_func_t iterator, void *user_data); | |
253 | 256 | |
254 | 257 | struct roots_wl_shell_surface *roots_wl_shell_surface_from_view( |
255 | 258 | struct roots_view *view); |
72 | 72 | void *data; |
73 | 73 | }; |
74 | 74 | |
75 | struct wlr_cursor *wlr_cursor_create(); | |
75 | struct wlr_cursor *wlr_cursor_create(void); | |
76 | 76 | |
77 | 77 | void wlr_cursor_destroy(struct wlr_cursor *cur); |
78 | 78 |
46 | 46 | * physical space relative to one another, and perform various useful operations |
47 | 47 | * on that state. |
48 | 48 | */ |
49 | struct wlr_output_layout *wlr_output_layout_create(); | |
49 | struct wlr_output_layout *wlr_output_layout_create(void); | |
50 | 50 | |
51 | 51 | void wlr_output_layout_destroy(struct wlr_output_layout *layout); |
52 | 52 |
60 | 60 | struct wlr_pointer_grab_interface { |
61 | 61 | void (*enter)(struct wlr_seat_pointer_grab *grab, |
62 | 62 | struct wlr_surface *surface, double sx, double sy); |
63 | void (*motion)(struct wlr_seat_pointer_grab *grab, uint32_t time, | |
63 | void (*motion)(struct wlr_seat_pointer_grab *grab, uint32_t time_msec, | |
64 | 64 | double sx, double sy); |
65 | uint32_t (*button)(struct wlr_seat_pointer_grab *grab, uint32_t time, | |
66 | uint32_t button, uint32_t state); | |
67 | void (*axis)(struct wlr_seat_pointer_grab *grab, uint32_t time, | |
65 | uint32_t (*button)(struct wlr_seat_pointer_grab *grab, uint32_t time_msec, | |
66 | uint32_t button, enum wlr_button_state state); | |
67 | void (*axis)(struct wlr_seat_pointer_grab *grab, uint32_t time_msec, | |
68 | 68 | enum wlr_axis_orientation orientation, double value, |
69 | 69 | int32_t value_discrete, enum wlr_axis_source source); |
70 | 70 | void (*frame)(struct wlr_seat_pointer_grab *grab); |
77 | 77 | void (*enter)(struct wlr_seat_keyboard_grab *grab, |
78 | 78 | struct wlr_surface *surface, uint32_t keycodes[], |
79 | 79 | size_t num_keycodes, struct wlr_keyboard_modifiers *modifiers); |
80 | void (*key)(struct wlr_seat_keyboard_grab *grab, uint32_t time, | |
80 | void (*key)(struct wlr_seat_keyboard_grab *grab, uint32_t time_msec, | |
81 | 81 | uint32_t key, uint32_t state); |
82 | 82 | void (*modifiers)(struct wlr_seat_keyboard_grab *grab, |
83 | 83 | struct wlr_keyboard_modifiers *modifiers); |
87 | 87 | struct wlr_seat_touch_grab; |
88 | 88 | |
89 | 89 | struct wlr_touch_grab_interface { |
90 | uint32_t (*down)(struct wlr_seat_touch_grab *grab, uint32_t time, | |
90 | uint32_t (*down)(struct wlr_seat_touch_grab *grab, uint32_t time_msec, | |
91 | 91 | struct wlr_touch_point *point); |
92 | void (*up)(struct wlr_seat_touch_grab *grab, uint32_t time, | |
92 | void (*up)(struct wlr_seat_touch_grab *grab, uint32_t time_msec, | |
93 | 93 | struct wlr_touch_point *point); |
94 | void (*motion)(struct wlr_seat_touch_grab *grab, uint32_t time, | |
94 | void (*motion)(struct wlr_seat_touch_grab *grab, uint32_t time_msec, | |
95 | 95 | struct wlr_touch_point *point); |
96 | void (*enter)(struct wlr_seat_touch_grab *grab, uint32_t time, | |
96 | void (*enter)(struct wlr_seat_touch_grab *grab, uint32_t time_msec, | |
97 | 97 | struct wlr_touch_point *point); |
98 | 98 | // XXX this will conflict with the actual touch cancel which is different so |
99 | 99 | // we need to rename this |
334 | 334 | * `wlr_seat_pointer_notify_motion()` to send motion events to respect pointer |
335 | 335 | * grabs. |
336 | 336 | */ |
337 | void wlr_seat_pointer_send_motion(struct wlr_seat *wlr_seat, uint32_t time, | |
337 | void wlr_seat_pointer_send_motion(struct wlr_seat *wlr_seat, uint32_t time_msec, | |
338 | 338 | double sx, double sy); |
339 | 339 | |
340 | 340 | /** |
343 | 343 | * `wlr_seat_pointer_notify_button()` to send button events to respect pointer |
344 | 344 | * grabs. |
345 | 345 | */ |
346 | uint32_t wlr_seat_pointer_send_button(struct wlr_seat *wlr_seat, uint32_t time, | |
347 | uint32_t button, uint32_t state); | |
346 | uint32_t wlr_seat_pointer_send_button(struct wlr_seat *wlr_seat, | |
347 | uint32_t time_msec, uint32_t button, enum wlr_button_state state); | |
348 | 348 | |
349 | 349 | /** |
350 | 350 | * Send an axis event to the surface with pointer focus. Compositors should use |
351 | 351 | * `wlr_seat_pointer_notify_axis()` to send axis events to respect pointer |
352 | 352 | * grabs. |
353 | 353 | **/ |
354 | void wlr_seat_pointer_send_axis(struct wlr_seat *wlr_seat, uint32_t time, | |
354 | void wlr_seat_pointer_send_axis(struct wlr_seat *wlr_seat, uint32_t time_msec, | |
355 | 355 | enum wlr_axis_orientation orientation, double value, |
356 | 356 | int32_t value_discrete, enum wlr_axis_source source); |
357 | 357 | |
387 | 387 | * Notify the seat of motion over the given surface. Pass surface-local |
388 | 388 | * coordinates where the pointer motion occurred. |
389 | 389 | */ |
390 | void wlr_seat_pointer_notify_motion(struct wlr_seat *wlr_seat, uint32_t time, | |
391 | double sx, double sy); | |
390 | void wlr_seat_pointer_notify_motion(struct wlr_seat *wlr_seat, | |
391 | uint32_t time_msec, double sx, double sy); | |
392 | 392 | |
393 | 393 | /** |
394 | 394 | * Notify the seat that a button has been pressed. Returns the serial of the |
395 | 395 | * button press or zero if no button press was sent. |
396 | 396 | */ |
397 | 397 | uint32_t wlr_seat_pointer_notify_button(struct wlr_seat *wlr_seat, |
398 | uint32_t time, uint32_t button, uint32_t state); | |
398 | uint32_t time_msec, uint32_t button, enum wlr_button_state state); | |
399 | 399 | |
400 | 400 | /** |
401 | 401 | * Notify the seat of an axis event. |
402 | 402 | */ |
403 | void wlr_seat_pointer_notify_axis(struct wlr_seat *wlr_seat, uint32_t time, | |
403 | void wlr_seat_pointer_notify_axis(struct wlr_seat *wlr_seat, uint32_t time_msec, | |
404 | 404 | enum wlr_axis_orientation orientation, double value, |
405 | 405 | int32_t value_discrete, enum wlr_axis_source source); |
406 | 406 | |
443 | 443 | * Send the keyboard key to focused keyboard resources. Compositors should use |
444 | 444 | * `wlr_seat_notify_key()` to respect keyboard grabs. |
445 | 445 | */ |
446 | void wlr_seat_keyboard_send_key(struct wlr_seat *seat, uint32_t time, | |
446 | void wlr_seat_keyboard_send_key(struct wlr_seat *seat, uint32_t time_msec, | |
447 | 447 | uint32_t key, uint32_t state); |
448 | 448 | |
449 | 449 | /** |
450 | 450 | * Notify the seat that a key has been pressed on the keyboard. Defers to any |
451 | 451 | * keyboard grabs. |
452 | 452 | */ |
453 | void wlr_seat_keyboard_notify_key(struct wlr_seat *seat, uint32_t time, | |
453 | void wlr_seat_keyboard_notify_key(struct wlr_seat *seat, uint32_t time_msec, | |
454 | 454 | uint32_t key, uint32_t state); |
455 | 455 | |
456 | 456 | /** |
522 | 522 | * the touch device. |
523 | 523 | */ |
524 | 524 | uint32_t wlr_seat_touch_notify_down(struct wlr_seat *seat, |
525 | struct wlr_surface *surface, uint32_t time, int32_t touch_id, double sx, | |
526 | double sy); | |
525 | struct wlr_surface *surface, uint32_t time_msec, | |
526 | int32_t touch_id, double sx, double sy); | |
527 | 527 | |
528 | 528 | /** |
529 | 529 | * Notify the seat that the touch point given by `touch_id` is up. Defers to any |
530 | 530 | * grab of the touch device. |
531 | 531 | */ |
532 | void wlr_seat_touch_notify_up(struct wlr_seat *seat, uint32_t time, | |
532 | void wlr_seat_touch_notify_up(struct wlr_seat *seat, uint32_t time_msec, | |
533 | 533 | int32_t touch_id); |
534 | 534 | |
535 | 535 | /** |
538 | 538 | * even if the surface is not the owner of the touch point for processing by |
539 | 539 | * grabs. |
540 | 540 | */ |
541 | void wlr_seat_touch_notify_motion(struct wlr_seat *seat, uint32_t time, | |
541 | void wlr_seat_touch_notify_motion(struct wlr_seat *seat, uint32_t time_msec, | |
542 | 542 | int32_t touch_id, double sx, double sy); |
543 | 543 | |
544 | 544 | /** |
547 | 547 | * `wlr_seat_touch_point_clear_focus()`. |
548 | 548 | */ |
549 | 549 | void wlr_seat_touch_point_focus(struct wlr_seat *seat, |
550 | struct wlr_surface *surface, uint32_t time, int32_t touch_id, double sx, | |
551 | double sy); | |
550 | struct wlr_surface *surface, uint32_t time_msec, | |
551 | int32_t touch_id, double sx, double sy); | |
552 | 552 | |
553 | 553 | /** |
554 | 554 | * Clear the focused surface for the touch point given by `touch_id`. |
555 | 555 | */ |
556 | void wlr_seat_touch_point_clear_focus(struct wlr_seat *seat, uint32_t time, | |
556 | void wlr_seat_touch_point_clear_focus(struct wlr_seat *seat, uint32_t time_msec, | |
557 | 557 | int32_t touch_id); |
558 | 558 | |
559 | 559 | /** |
565 | 565 | * `wlr_seat_touch_notify_down()` to respect any grabs of the touch device. |
566 | 566 | */ |
567 | 567 | uint32_t wlr_seat_touch_send_down(struct wlr_seat *seat, |
568 | struct wlr_surface *surface, uint32_t time, int32_t touch_id, double sx, | |
569 | double sy); | |
568 | struct wlr_surface *surface, uint32_t time_msec, | |
569 | int32_t touch_id, double sx, double sy); | |
570 | 570 | |
571 | 571 | /** |
572 | 572 | * Send a touch up event for the touch point given by the `touch_id`. The event |
574 | 574 | * event. This will remove the touch point. Compositors should use |
575 | 575 | * `wlr_seat_touch_notify_up()` to respect any grabs of the touch device. |
576 | 576 | */ |
577 | void wlr_seat_touch_send_up(struct wlr_seat *seat, uint32_t time, | |
577 | void wlr_seat_touch_send_up(struct wlr_seat *seat, uint32_t time_msec, | |
578 | 578 | int32_t touch_id); |
579 | 579 | |
580 | 580 | /** |
583 | 583 | * down event. Compositors should use `wlr_seat_touch_notify_motion()` to |
584 | 584 | * respect any grabs of the touch device. |
585 | 585 | */ |
586 | void wlr_seat_touch_send_motion(struct wlr_seat *seat, uint32_t time, | |
586 | void wlr_seat_touch_send_motion(struct wlr_seat *seat, uint32_t time_msec, | |
587 | 587 | int32_t touch_id, double sx, double sy); |
588 | 588 | |
589 | 589 | /** |
242 | 242 | struct wlr_xdg_surface *wlr_xdg_surface_from_toplevel_resource( |
243 | 243 | struct wl_resource *resource); |
244 | 244 | |
245 | struct wlr_box wlr_xdg_positioner_get_geometry( | |
246 | struct wlr_xdg_positioner *positioner); | |
247 | ||
248 | 245 | /** |
249 | 246 | * Send a ping to the surface. If the surface does not respond in a reasonable |
250 | 247 | * amount of time, the ping_timeout event will be emitted. |
23 | 23 | pid_t pid; |
24 | 24 | struct wl_client *client; |
25 | 25 | struct wl_event_source *sigusr1_source; |
26 | struct wl_listener client_destroy; | |
27 | 26 | struct wlr_xwm *xwm; |
28 | 27 | struct wlr_xwayland_cursor *cursor; |
29 | 28 | int wm_fd[2], wl_fd[2]; |
33 | 32 | /* Anything above display is reset on Xwayland restart, rest is conserved */ |
34 | 33 | |
35 | 34 | int display; |
35 | char display_name[16]; | |
36 | 36 | int x_fd[2]; |
37 | 37 | struct wl_event_source *x_fd_read_event[2]; |
38 | struct wl_listener display_destroy; | |
39 | ||
40 | 38 | bool lazy; |
41 | 39 | |
42 | 40 | struct wl_display *wl_display; |
47 | 45 | struct wl_signal ready; |
48 | 46 | struct wl_signal new_surface; |
49 | 47 | } events; |
50 | ||
51 | struct wl_listener seat_destroy; | |
52 | 48 | |
53 | 49 | /** |
54 | 50 | * Add a custom event handler to xwayland. Return 1 if the event was |
56 | 52 | * free the event. |
57 | 53 | */ |
58 | 54 | int (*user_event_handler)(struct wlr_xwm *xwm, xcb_generic_event_t *event); |
55 | ||
56 | struct wl_listener client_destroy; | |
57 | struct wl_listener display_destroy; | |
58 | struct wl_listener seat_destroy; | |
59 | 59 | |
60 | 60 | void *data; |
61 | 61 | }; |
0 | 0 | project( |
1 | 1 | 'wlroots', |
2 | 2 | 'c', |
3 | version: '0.4.1', | |
3 | version: '0.5.0', | |
4 | 4 | license: 'MIT', |
5 | 5 | meson_version: '>=0.48.0', |
6 | 6 | default_options: [ |
13 | 13 | # Format of so_version is CURRENT, REVISION, AGE. |
14 | 14 | # See: https://autotools.io/libtool/version.html |
15 | 15 | # for a reference about clean library versioning. |
16 | so_version = ['1', '2', '0'] | |
17 | ||
18 | add_project_arguments( | |
19 | [ | |
20 | '-DWLR_SRC_DIR="@0@"'.format(meson.current_source_dir()), | |
21 | '-DWLR_USE_UNSTABLE', | |
22 | ||
23 | '-Wno-unused-parameter', | |
24 | '-Wundef', | |
25 | ], | |
26 | language: 'c', | |
27 | ) | |
16 | so_version = ['2', '3', '1'] | |
17 | ||
18 | add_project_arguments([ | |
19 | '-DWLR_SRC_DIR="@0@"'.format(meson.current_source_dir()), | |
20 | '-DWLR_USE_UNSTABLE', | |
21 | ], language: 'c') | |
22 | ||
23 | cc = meson.get_compiler('c') | |
24 | ||
25 | add_project_arguments(cc.get_supported_arguments([ | |
26 | '-Wundef', | |
27 | '-Wlogical-op', | |
28 | '-Wmissing-include-dirs', | |
29 | '-Wold-style-definition', | |
30 | '-Wpointer-arith', | |
31 | '-Winit-self', | |
32 | '-Wstrict-prototypes', | |
33 | '-Wredundant-decls', | |
34 | '-Wimplicit-fallthrough=2', | |
35 | '-Wendif-labels', | |
36 | '-Wstrict-aliasing=2', | |
37 | '-Woverflow', | |
38 | ||
39 | '-Wno-missing-braces', | |
40 | '-Wno-missing-field-initializers', | |
41 | '-Wno-unused-parameter', | |
42 | ]), language: 'c') | |
28 | 43 | |
29 | 44 | conf_data = configuration_data() |
30 | 45 | conf_data.set10('WLR_HAS_LIBCAP', false) |
36 | 51 | conf_data.set10('WLR_HAS_XCB_ICCCM', false) |
37 | 52 | |
38 | 53 | wlr_inc = include_directories('.', 'include') |
39 | ||
40 | cc = meson.get_compiler('c') | |
41 | 54 | |
42 | 55 | # Clang complains about some zeroed initializer lists (= {0}), even though they |
43 | 56 | # are valid |
311 | 311 | |
312 | 312 | glGetError(); // Clear the error flag |
313 | 313 | |
314 | unsigned char *p = data + dst_y * stride; | |
314 | unsigned char *p = (unsigned char *)data + dst_y * stride; | |
315 | 315 | uint32_t pack_stride = width * fmt->bpp / 8; |
316 | 316 | if (pack_stride == stride && dst_x == 0 && flags != NULL) { |
317 | 317 | // Under these particular conditions, we can read the pixels with only |
50 | 50 | |
51 | 51 | double view_sx = lx - view->box.x; |
52 | 52 | double view_sy = ly - view->box.y; |
53 | ||
54 | struct wlr_surface_state *state = &view->wlr_surface->current; | |
55 | struct wlr_box box = { | |
56 | .x = 0, .y = 0, | |
57 | .width = state->width, .height = state->height, | |
58 | }; | |
59 | if (view->rotation != 0.0) { | |
60 | // Coordinates relative to the center of the view | |
61 | double ox = view_sx - (double)box.width/2, | |
62 | oy = view_sy - (double)box.height/2; | |
63 | // Rotated coordinates | |
64 | double rx = cos(view->rotation)*ox + sin(view->rotation)*oy, | |
65 | ry = cos(view->rotation)*oy - sin(view->rotation)*ox; | |
66 | view_sx = rx + (double)box.width/2; | |
67 | view_sy = ry + (double)box.height/2; | |
68 | } | |
53 | rotate_child_position(&view_sx, &view_sy, 0, 0, | |
54 | view->box.width, view->box.height, -view->rotation); | |
69 | 55 | |
70 | 56 | double _sx, _sy; |
71 | 57 | struct wlr_surface *_surface = NULL; |
395 | 381 | &desktop->xwayland_surface); |
396 | 382 | desktop->xwayland_surface.notify = handle_xwayland_surface; |
397 | 383 | |
384 | setenv("DISPLAY", desktop->xwayland->display_name, true); | |
385 | ||
398 | 386 | if (wlr_xcursor_manager_load(desktop->xcursor_manager, 1)) { |
399 | 387 | wlr_log(WLR_ERROR, "Cannot load XWayland XCursor theme"); |
400 | 388 | } |
297 | 297 | |
298 | 298 | if (memcmp(&old_geo, &layer->geo, sizeof(struct wlr_box)) != 0) { |
299 | 299 | output_damage_whole_local_surface(output, layer_surface->surface, |
300 | old_geo.x, old_geo.y, 0); | |
300 | old_geo.x, old_geo.y); | |
301 | 301 | output_damage_whole_local_surface(output, layer_surface->surface, |
302 | layer->geo.x, layer->geo.y, 0); | |
302 | layer->geo.x, layer->geo.y); | |
303 | 303 | } else { |
304 | 304 | output_damage_from_local_surface(output, layer_surface->surface, |
305 | layer->geo.x, layer->geo.y, 0); | |
305 | layer->geo.x, layer->geo.y); | |
306 | 306 | } |
307 | 307 | } |
308 | 308 | } |
313 | 313 | if (wlr_output != NULL) { |
314 | 314 | struct roots_output *output = wlr_output->data; |
315 | 315 | output_damage_whole_local_surface(output, layer_surface->surface, |
316 | layer->geo.x, layer->geo.y, 0); | |
316 | layer->geo.x, layer->geo.y); | |
317 | 317 | } |
318 | 318 | } |
319 | 319 | |
341 | 341 | struct wlr_output *wlr_output = layer_surface->output; |
342 | 342 | struct roots_output *output = wlr_output->data; |
343 | 343 | output_damage_whole_local_surface(output, layer_surface->surface, |
344 | layer->geo.x, layer->geo.y, 0); | |
344 | layer->geo.x, layer->geo.y); | |
345 | 345 | wlr_surface_send_enter(layer_surface->surface, wlr_output); |
346 | 346 | } |
347 | 347 | |
362 | 362 | int ox = popup->wlr_popup->geometry.x + layer->geo.x; |
363 | 363 | int oy = popup->wlr_popup->geometry.y + layer->geo.y; |
364 | 364 | output_damage_whole_local_surface(output, popup->wlr_popup->base->surface, |
365 | ox, oy, 0); | |
365 | ox, oy); | |
366 | 366 | input_update_cursor_focus(output->desktop->server->input); |
367 | 367 | } |
368 | 368 | |
374 | 374 | int ox = popup->wlr_popup->geometry.x + layer->geo.x; |
375 | 375 | int oy = popup->wlr_popup->geometry.y + layer->geo.y; |
376 | 376 | output_damage_whole_local_surface(output, popup->wlr_popup->base->surface, |
377 | ox, oy, 0); | |
377 | ox, oy); | |
378 | 378 | } |
379 | 379 | |
380 | 380 | static void popup_handle_commit(struct wl_listener *listener, void *data) { |
385 | 385 | int ox = popup->wlr_popup->geometry.x + layer->geo.x; |
386 | 386 | int oy = popup->wlr_popup->geometry.y + layer->geo.y; |
387 | 387 | output_damage_from_local_surface(output, popup->wlr_popup->base->surface, |
388 | ox, oy, 0); | |
388 | ox, oy); | |
389 | 389 | } |
390 | 390 | |
391 | 391 | static void popup_handle_destroy(struct wl_listener *listener, void *data) { |
8 | 8 | 'layer_shell.c', |
9 | 9 | 'main.c', |
10 | 10 | 'output.c', |
11 | 'render.c', | |
11 | 12 | 'seat.c', |
12 | 13 | 'switch.c', |
13 | 14 | 'text_input.c', |
5 | 5 | #include <wlr/backend/drm.h> |
6 | 6 | #include <wlr/config.h> |
7 | 7 | #include <wlr/types/wlr_compositor.h> |
8 | #include <wlr/types/wlr_matrix.h> | |
9 | 8 | #include <wlr/types/wlr_output_layout.h> |
10 | 9 | #include <wlr/types/wlr_presentation_time.h> |
11 | 10 | #include <wlr/types/wlr_wl_shell.h> |
13 | 12 | #include <wlr/types/wlr_xdg_shell.h> |
14 | 13 | #include <wlr/util/log.h> |
15 | 14 | #include <wlr/util/region.h> |
15 | #include <wlr/xwayland.h> | |
16 | 16 | #include "rootston/config.h" |
17 | 17 | #include "rootston/layers.h" |
18 | 18 | #include "rootston/output.h" |
24 | 24 | */ |
25 | 25 | void rotate_child_position(double *sx, double *sy, double sw, double sh, |
26 | 26 | double pw, double ph, float rotation) { |
27 | if (rotation != 0.0) { | |
28 | // Coordinates relative to the center of the subsurface | |
29 | double ox = *sx - pw/2 + sw/2, | |
30 | oy = *sy - ph/2 + sh/2; | |
31 | // Rotated coordinates | |
32 | double rx = cos(rotation)*ox - sin(rotation)*oy, | |
33 | ry = cos(rotation)*oy + sin(rotation)*ox; | |
34 | *sx = rx + pw/2 - sw/2; | |
35 | *sy = ry + ph/2 - sh/2; | |
36 | } | |
37 | } | |
38 | ||
39 | struct layout_data { | |
40 | double x, y; | |
27 | if (rotation == 0.0) { | |
28 | return; | |
29 | } | |
30 | ||
31 | // Coordinates relative to the center of the subsurface | |
32 | double cx = *sx - pw/2 + sw/2, | |
33 | cy = *sy - ph/2 + sh/2; | |
34 | // Rotated coordinates | |
35 | double rx = cos(rotation)*cx - sin(rotation)*cy, | |
36 | ry = cos(rotation)*cy + sin(rotation)*cx; | |
37 | *sx = rx + pw/2 - sw/2; | |
38 | *sy = ry + ph/2 - sh/2; | |
39 | } | |
40 | ||
41 | struct surface_iterator_data { | |
42 | roots_surface_iterator_func_t user_iterator; | |
43 | void *user_data; | |
44 | ||
45 | struct roots_output *output; | |
46 | double ox, oy; | |
41 | 47 | int width, height; |
42 | 48 | float rotation; |
43 | 49 | }; |
44 | 50 | |
45 | static void get_layout_position(struct layout_data *data, | |
46 | double *lx, double *ly, const struct wlr_surface *surface, | |
47 | int sx, int sy) { | |
48 | double _sx = sx, _sy = sy; | |
49 | rotate_child_position(&_sx, &_sy, surface->current.width, | |
50 | surface->current.height, data->width, data->height, data->rotation); | |
51 | *lx = data->x + _sx; | |
52 | *ly = data->y + _sy; | |
53 | } | |
54 | ||
55 | static void surface_for_each_surface(struct wlr_surface *surface, | |
56 | double lx, double ly, float rotation, struct layout_data *layout_data, | |
57 | wlr_surface_iterator_func_t iterator, void *user_data) { | |
58 | layout_data->x = lx; | |
59 | layout_data->y = ly; | |
60 | layout_data->width = surface->current.width; | |
61 | layout_data->height = surface->current.height; | |
62 | layout_data->rotation = rotation; | |
63 | ||
64 | wlr_surface_for_each_surface(surface, iterator, user_data); | |
65 | } | |
66 | ||
67 | static void view_for_each_surface(struct roots_view *view, | |
68 | struct layout_data *layout_data, wlr_surface_iterator_func_t iterator, | |
51 | static bool get_surface_box(struct surface_iterator_data *data, | |
52 | struct wlr_surface *surface, int sx, int sy, | |
53 | struct wlr_box *surface_box) { | |
54 | struct roots_output *output = data->output; | |
55 | ||
56 | if (!wlr_surface_has_buffer(surface)) { | |
57 | return false; | |
58 | } | |
59 | ||
60 | int sw = surface->current.width; | |
61 | int sh = surface->current.height; | |
62 | ||
63 | double _sx = sx + surface->sx; | |
64 | double _sy = sy + surface->sy; | |
65 | rotate_child_position(&_sx, &_sy, sw, sh, data->width, data->height, | |
66 | data->rotation); | |
67 | ||
68 | struct wlr_box box = { | |
69 | .x = data->ox + _sx, | |
70 | .y = data->oy + _sy, | |
71 | .width = sw, | |
72 | .height = sh, | |
73 | }; | |
74 | if (surface_box != NULL) { | |
75 | *surface_box = box; | |
76 | } | |
77 | ||
78 | struct wlr_box rotated_box; | |
79 | wlr_box_rotated_bounds(&rotated_box, &box, data->rotation); | |
80 | ||
81 | struct wlr_box output_box = {0}; | |
82 | wlr_output_effective_resolution(output->wlr_output, | |
83 | &output_box.width, &output_box.height); | |
84 | ||
85 | struct wlr_box intersection; | |
86 | return wlr_box_intersection(&intersection, &output_box, &rotated_box); | |
87 | } | |
88 | ||
89 | static void output_for_each_surface_iterator(struct wlr_surface *surface, | |
90 | int sx, int sy, void *_data) { | |
91 | struct surface_iterator_data *data = _data; | |
92 | ||
93 | struct wlr_box box; | |
94 | bool intersects = get_surface_box(data, surface, sx, sy, &box); | |
95 | if (!intersects) { | |
96 | return; | |
97 | } | |
98 | ||
99 | data->user_iterator(data->output, surface, &box, data->rotation, | |
100 | data->user_data); | |
101 | } | |
102 | ||
103 | void output_surface_for_each_surface(struct roots_output *output, | |
104 | struct wlr_surface *surface, double ox, double oy, | |
105 | roots_surface_iterator_func_t iterator, void *user_data) { | |
106 | struct surface_iterator_data data = { | |
107 | .user_iterator = iterator, | |
108 | .user_data = user_data, | |
109 | .output = output, | |
110 | .ox = ox, | |
111 | .oy = oy, | |
112 | .width = surface->current.width, | |
113 | .height = surface->current.height, | |
114 | .rotation = 0, | |
115 | }; | |
116 | ||
117 | wlr_surface_for_each_surface(surface, | |
118 | output_for_each_surface_iterator, &data); | |
119 | } | |
120 | ||
121 | void output_view_for_each_surface(struct roots_output *output, | |
122 | struct roots_view *view, roots_surface_iterator_func_t iterator, | |
69 | 123 | void *user_data) { |
70 | if (!view->wlr_surface) { | |
71 | return; | |
72 | } | |
73 | ||
74 | layout_data->x = view->box.x; | |
75 | layout_data->y = view->box.y; | |
76 | layout_data->width = view->wlr_surface->current.width; | |
77 | layout_data->height = view->wlr_surface->current.height; | |
78 | layout_data->rotation = view->rotation; | |
79 | ||
80 | switch (view->type) { | |
81 | case ROOTS_XDG_SHELL_V6_VIEW:; | |
82 | struct roots_xdg_surface_v6 *xdg_surface_v6 = | |
83 | roots_xdg_surface_v6_from_view(view); | |
84 | wlr_xdg_surface_v6_for_each_surface(xdg_surface_v6->xdg_surface_v6, | |
85 | iterator, user_data); | |
86 | break; | |
87 | case ROOTS_XDG_SHELL_VIEW:; | |
88 | struct roots_xdg_surface *xdg_surface = | |
89 | roots_xdg_surface_from_view(view); | |
90 | wlr_xdg_surface_for_each_surface(xdg_surface->xdg_surface, iterator, | |
91 | user_data); | |
92 | break; | |
93 | case ROOTS_WL_SHELL_VIEW:; | |
94 | struct roots_wl_shell_surface *wl_shell_surface = | |
95 | roots_wl_shell_surface_from_view(view); | |
96 | wlr_wl_shell_surface_for_each_surface(wl_shell_surface->wl_shell_surface, | |
97 | iterator, user_data); | |
98 | break; | |
124 | struct surface_iterator_data data = { | |
125 | .user_iterator = iterator, | |
126 | .user_data = user_data, | |
127 | .output = output, | |
128 | .ox = view->box.x - output->wlr_output->lx, | |
129 | .oy = view->box.y - output->wlr_output->ly, | |
130 | .width = view->box.width, | |
131 | .height = view->box.height, | |
132 | .rotation = view->rotation, | |
133 | }; | |
134 | ||
135 | view_for_each_surface(view, output_for_each_surface_iterator, &data); | |
136 | } | |
137 | ||
99 | 138 | #if WLR_HAS_XWAYLAND |
100 | case ROOTS_XWAYLAND_VIEW: | |
101 | wlr_surface_for_each_surface(view->wlr_surface, iterator, user_data); | |
102 | break; | |
103 | #endif | |
104 | } | |
105 | } | |
106 | ||
107 | #if WLR_HAS_XWAYLAND | |
108 | static void xwayland_children_for_each_surface( | |
109 | struct wlr_xwayland_surface *surface, | |
110 | wlr_surface_iterator_func_t iterator, struct layout_data *layout_data, | |
111 | void *user_data) { | |
139 | void output_xwayland_children_for_each_surface( | |
140 | struct roots_output *output, struct wlr_xwayland_surface *surface, | |
141 | roots_surface_iterator_func_t iterator, void *user_data) { | |
112 | 142 | struct wlr_xwayland_surface *child; |
113 | 143 | wl_list_for_each(child, &surface->children, parent_link) { |
114 | 144 | if (child->mapped) { |
115 | surface_for_each_surface(child->surface, child->x, child->y, 0, | |
116 | layout_data, iterator, user_data); | |
117 | } | |
118 | xwayland_children_for_each_surface(child, iterator, layout_data, | |
145 | double ox = child->x - output->wlr_output->lx; | |
146 | double oy = child->y - output->wlr_output->ly; | |
147 | output_surface_for_each_surface(output, child->surface, | |
148 | ox, oy, iterator, user_data); | |
149 | } | |
150 | output_xwayland_children_for_each_surface(output, child, | |
151 | iterator, user_data); | |
152 | } | |
153 | } | |
154 | #endif | |
155 | ||
156 | void output_layer_for_each_surface(struct roots_output *output, | |
157 | struct wl_list *layer_surfaces, roots_surface_iterator_func_t iterator, | |
158 | void *user_data) { | |
159 | struct roots_layer_surface *layer_surface; | |
160 | wl_list_for_each(layer_surface, layer_surfaces, link) { | |
161 | struct wlr_layer_surface_v1 *wlr_layer_surface_v1 = | |
162 | layer_surface->layer_surface; | |
163 | output_surface_for_each_surface(output, wlr_layer_surface_v1->surface, | |
164 | layer_surface->geo.x, layer_surface->geo.y, iterator, | |
119 | 165 | user_data); |
120 | 166 | } |
121 | 167 | } |
122 | #endif | |
123 | ||
124 | static void drag_icons_for_each_surface(struct roots_input *input, | |
125 | wlr_surface_iterator_func_t iterator, struct layout_data *layout_data, | |
168 | ||
169 | void output_drag_icons_for_each_surface(struct roots_output *output, | |
170 | struct roots_input *input, roots_surface_iterator_func_t iterator, | |
126 | 171 | void *user_data) { |
127 | 172 | struct roots_seat *seat; |
128 | 173 | wl_list_for_each(seat, &input->seats, link) { |
129 | 174 | struct roots_drag_icon *drag_icon = seat->drag_icon; |
130 | if (drag_icon == NULL || !drag_icon->wlr_drag_icon->mapped) { | |
175 | if (!drag_icon || !drag_icon->wlr_drag_icon->mapped) { | |
131 | 176 | continue; |
132 | 177 | } |
133 | 178 | |
134 | surface_for_each_surface(drag_icon->wlr_drag_icon->surface, | |
135 | drag_icon->x, drag_icon->y, 0, layout_data, | |
136 | iterator, user_data); | |
137 | } | |
138 | } | |
139 | ||
140 | static void layer_for_each_surface(struct wl_list *layer, | |
141 | const struct wlr_box *output_layout_box, | |
142 | wlr_surface_iterator_func_t iterator, struct layout_data *layout_data, | |
143 | void *user_data) { | |
144 | struct roots_layer_surface *roots_surface; | |
145 | wl_list_for_each(roots_surface, layer, link) { | |
146 | struct wlr_layer_surface_v1 *layer = roots_surface->layer_surface; | |
147 | ||
148 | layout_data->x = roots_surface->geo.x + output_layout_box->x; | |
149 | layout_data->y = roots_surface->geo.y + output_layout_box->y; | |
150 | layout_data->width = roots_surface->geo.width; | |
151 | layout_data->height = roots_surface->geo.height; | |
152 | layout_data->rotation = 0; | |
153 | wlr_layer_surface_v1_for_each_surface(layer, iterator, user_data); | |
154 | } | |
155 | } | |
156 | ||
157 | static void output_for_each_surface(struct roots_output *output, | |
158 | wlr_surface_iterator_func_t iterator, struct layout_data *layout_data, | |
159 | void *user_data) { | |
160 | struct wlr_output *wlr_output = output->wlr_output; | |
179 | double ox = drag_icon->x - output->wlr_output->lx; | |
180 | double oy = drag_icon->y - output->wlr_output->ly; | |
181 | output_surface_for_each_surface(output, | |
182 | drag_icon->wlr_drag_icon->surface, ox, oy, iterator, user_data); | |
183 | } | |
184 | } | |
185 | ||
186 | void output_for_each_surface(struct roots_output *output, | |
187 | roots_surface_iterator_func_t iterator, void *user_data) { | |
161 | 188 | struct roots_desktop *desktop = output->desktop; |
162 | struct roots_server *server = desktop->server; | |
163 | ||
164 | const struct wlr_box *output_box = | |
165 | wlr_output_layout_get_box(desktop->layout, wlr_output); | |
166 | 189 | |
167 | 190 | if (output->fullscreen_view != NULL) { |
168 | 191 | struct roots_view *view = output->fullscreen_view; |
169 | 192 | |
170 | view_for_each_surface(view, layout_data, iterator, user_data); | |
193 | output_view_for_each_surface(output, view, iterator, user_data); | |
171 | 194 | |
172 | 195 | #if WLR_HAS_XWAYLAND |
173 | 196 | if (view->type == ROOTS_XWAYLAND_VIEW) { |
174 | 197 | struct roots_xwayland_surface *xwayland_surface = |
175 | 198 | roots_xwayland_surface_from_view(view); |
176 | xwayland_children_for_each_surface( | |
177 | xwayland_surface->xwayland_surface, | |
178 | iterator, layout_data, user_data); | |
199 | output_xwayland_children_for_each_surface(output, | |
200 | xwayland_surface->xwayland_surface, iterator, user_data); | |
179 | 201 | } |
180 | 202 | #endif |
181 | 203 | } else { |
182 | 204 | struct roots_view *view; |
183 | 205 | wl_list_for_each_reverse(view, &desktop->views, link) { |
184 | view_for_each_surface(view, layout_data, iterator, user_data); | |
185 | } | |
186 | ||
187 | drag_icons_for_each_surface(server->input, iterator, | |
188 | layout_data, user_data); | |
189 | } | |
206 | output_view_for_each_surface(output, view, iterator, user_data); | |
207 | } | |
208 | } | |
209 | ||
210 | output_drag_icons_for_each_surface(output, desktop->server->input, | |
211 | iterator, user_data); | |
190 | 212 | |
191 | 213 | size_t len = sizeof(output->layers) / sizeof(output->layers[0]); |
192 | 214 | for (size_t i = 0; i < len; ++i) { |
193 | layer_for_each_surface(&output->layers[i], output_box, | |
194 | iterator, layout_data, user_data); | |
195 | } | |
196 | } | |
197 | ||
198 | ||
199 | struct render_data { | |
200 | struct layout_data layout; | |
201 | struct roots_output *output; | |
202 | struct timespec *when; | |
203 | pixman_region32_t *damage; | |
204 | float alpha; | |
205 | }; | |
206 | ||
207 | /** | |
208 | * Checks whether a surface at (lx, ly) intersects an output. If `box` is not | |
209 | * NULL, it populates it with the surface box in the output, in output-local | |
210 | * coordinates. | |
211 | */ | |
212 | static bool surface_intersect_output(struct wlr_surface *surface, | |
213 | struct wlr_output_layout *output_layout, struct wlr_output *wlr_output, | |
214 | double lx, double ly, float rotation, struct wlr_box *box) { | |
215 | double ox = lx, oy = ly; | |
216 | wlr_output_layout_output_coords(output_layout, wlr_output, &ox, &oy); | |
217 | ||
218 | ox += surface->sx; | |
219 | oy += surface->sy; | |
220 | ||
221 | if (box != NULL) { | |
222 | box->x = ox * wlr_output->scale; | |
223 | box->y = oy * wlr_output->scale; | |
224 | box->width = surface->current.width * wlr_output->scale; | |
225 | box->height = surface->current.height * wlr_output->scale; | |
226 | } | |
227 | ||
228 | struct wlr_box layout_box = { | |
229 | .x = lx, .y = ly, | |
230 | .width = surface->current.width, .height = surface->current.height, | |
231 | }; | |
232 | wlr_box_rotated_bounds(&layout_box, &layout_box, rotation); | |
233 | return wlr_output_layout_intersects(output_layout, wlr_output, &layout_box); | |
234 | } | |
235 | ||
236 | static void scissor_output(struct roots_output *output, pixman_box32_t *rect) { | |
237 | struct wlr_output *wlr_output = output->wlr_output; | |
238 | struct wlr_renderer *renderer = wlr_backend_get_renderer(wlr_output->backend); | |
239 | assert(renderer); | |
240 | ||
241 | struct wlr_box box = { | |
242 | .x = rect->x1, | |
243 | .y = rect->y1, | |
244 | .width = rect->x2 - rect->x1, | |
245 | .height = rect->y2 - rect->y1, | |
246 | }; | |
247 | ||
248 | int ow, oh; | |
249 | wlr_output_transformed_resolution(wlr_output, &ow, &oh); | |
250 | ||
251 | enum wl_output_transform transform = | |
252 | wlr_output_transform_invert(wlr_output->transform); | |
253 | wlr_box_transform(&box, &box, transform, ow, oh); | |
254 | ||
255 | wlr_renderer_scissor(renderer, &box); | |
256 | } | |
257 | ||
258 | static void render_surface(struct wlr_surface *surface, int sx, int sy, | |
259 | void *_data) { | |
260 | struct render_data *data = _data; | |
261 | struct roots_output *output = data->output; | |
262 | float rotation = data->layout.rotation; | |
263 | ||
264 | struct wlr_texture *texture = wlr_surface_get_texture(surface); | |
265 | if (texture == NULL) { | |
266 | return; | |
267 | } | |
268 | ||
269 | struct wlr_renderer *renderer = | |
270 | wlr_backend_get_renderer(output->wlr_output->backend); | |
271 | assert(renderer); | |
272 | ||
273 | double lx, ly; | |
274 | get_layout_position(&data->layout, &lx, &ly, surface, sx, sy); | |
275 | ||
276 | struct wlr_box box; | |
277 | bool intersects = surface_intersect_output(surface, output->desktop->layout, | |
278 | output->wlr_output, lx, ly, rotation, &box); | |
279 | if (!intersects) { | |
280 | return; | |
281 | } | |
282 | ||
283 | struct wlr_box rotated; | |
284 | wlr_box_rotated_bounds(&rotated, &box, rotation); | |
285 | ||
286 | pixman_region32_t damage; | |
287 | pixman_region32_init(&damage); | |
288 | pixman_region32_union_rect(&damage, &damage, rotated.x, rotated.y, | |
289 | rotated.width, rotated.height); | |
290 | pixman_region32_intersect(&damage, &damage, data->damage); | |
291 | bool damaged = pixman_region32_not_empty(&damage); | |
292 | if (!damaged) { | |
293 | goto damage_finish; | |
294 | } | |
295 | ||
296 | float matrix[9]; | |
297 | enum wl_output_transform transform = | |
298 | wlr_output_transform_invert(surface->current.transform); | |
299 | wlr_matrix_project_box(matrix, &box, transform, rotation, | |
300 | output->wlr_output->transform_matrix); | |
301 | ||
302 | int nrects; | |
303 | pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects); | |
304 | for (int i = 0; i < nrects; ++i) { | |
305 | scissor_output(output, &rects[i]); | |
306 | wlr_render_texture_with_matrix(renderer, texture, matrix, data->alpha); | |
307 | } | |
308 | ||
309 | damage_finish: | |
310 | pixman_region32_fini(&damage); | |
311 | } | |
312 | ||
313 | static void get_decoration_box(struct roots_view *view, | |
215 | output_layer_for_each_surface(output, &output->layers[i], | |
216 | iterator, user_data); | |
217 | } | |
218 | } | |
219 | ||
220 | static int scale_length(int length, int offset, float scale) { | |
221 | return round((offset + length) * scale) - round(offset * scale); | |
222 | } | |
223 | ||
224 | void scale_box(struct wlr_box *box, float scale) { | |
225 | box->width = scale_length(box->width, box->x, scale); | |
226 | box->height = scale_length(box->height, box->y, scale); | |
227 | box->x = round(box->x * scale); | |
228 | box->y = round(box->y * scale); | |
229 | } | |
230 | ||
231 | void get_decoration_box(struct roots_view *view, | |
314 | 232 | struct roots_output *output, struct wlr_box *box) { |
315 | 233 | struct wlr_output *wlr_output = output->wlr_output; |
316 | 234 | |
330 | 248 | box->y = y * wlr_output->scale; |
331 | 249 | box->width = deco_box.width * wlr_output->scale; |
332 | 250 | box->height = deco_box.height * wlr_output->scale; |
333 | } | |
334 | ||
335 | static void render_decorations(struct roots_view *view, | |
336 | struct render_data *data) { | |
337 | if (!view->decorated || view->wlr_surface == NULL) { | |
338 | return; | |
339 | } | |
340 | ||
341 | struct roots_output *output = data->output; | |
342 | struct wlr_renderer *renderer = | |
343 | wlr_backend_get_renderer(output->wlr_output->backend); | |
344 | assert(renderer); | |
345 | ||
346 | struct wlr_box box; | |
347 | get_decoration_box(view, output, &box); | |
348 | ||
349 | struct wlr_box rotated; | |
350 | wlr_box_rotated_bounds(&rotated, &box, view->rotation); | |
351 | ||
352 | pixman_region32_t damage; | |
353 | pixman_region32_init(&damage); | |
354 | pixman_region32_union_rect(&damage, &damage, rotated.x, rotated.y, | |
355 | rotated.width, rotated.height); | |
356 | pixman_region32_intersect(&damage, &damage, data->damage); | |
357 | bool damaged = pixman_region32_not_empty(&damage); | |
358 | if (!damaged) { | |
359 | goto damage_finish; | |
360 | } | |
361 | ||
362 | float matrix[9]; | |
363 | wlr_matrix_project_box(matrix, &box, WL_OUTPUT_TRANSFORM_NORMAL, | |
364 | view->rotation, output->wlr_output->transform_matrix); | |
365 | float color[] = { 0.2, 0.2, 0.2, view->alpha }; | |
366 | ||
367 | int nrects; | |
368 | pixman_box32_t *rects = | |
369 | pixman_region32_rectangles(&damage, &nrects); | |
370 | for (int i = 0; i < nrects; ++i) { | |
371 | scissor_output(output, &rects[i]); | |
372 | wlr_render_quad_with_matrix(renderer, color, matrix); | |
373 | } | |
374 | ||
375 | damage_finish: | |
376 | pixman_region32_fini(&damage); | |
377 | } | |
378 | ||
379 | static void render_view(struct roots_view *view, struct render_data *data) { | |
380 | // Do not render views fullscreened on other outputs | |
381 | if (view->fullscreen_output != NULL && | |
382 | view->fullscreen_output != data->output) { | |
383 | return; | |
384 | } | |
385 | ||
386 | data->alpha = view->alpha; | |
387 | render_decorations(view, data); | |
388 | view_for_each_surface(view, &data->layout, render_surface, data); | |
389 | } | |
390 | ||
391 | static void render_layer(struct roots_output *output, | |
392 | const struct wlr_box *output_layout_box, struct render_data *data, | |
393 | struct wl_list *layer) { | |
394 | data->alpha = 1; | |
395 | layer_for_each_surface(layer, output_layout_box, render_surface, | |
396 | &data->layout, data); | |
397 | } | |
398 | ||
399 | static void surface_send_frame_done(struct wlr_surface *surface, int sx, int sy, | |
400 | void *_data) { | |
401 | struct render_data *data = _data; | |
402 | struct roots_output *output = data->output; | |
403 | struct timespec *when = data->when; | |
404 | float rotation = data->layout.rotation; | |
405 | ||
406 | double lx, ly; | |
407 | get_layout_position(&data->layout, &lx, &ly, surface, sx, sy); | |
408 | ||
409 | if (!surface_intersect_output(surface, output->desktop->layout, | |
410 | output->wlr_output, lx, ly, rotation, NULL)) { | |
411 | return; | |
412 | } | |
413 | ||
414 | wlr_surface_send_frame_done(surface, when); | |
415 | } | |
416 | ||
417 | static void render_output(struct roots_output *output) { | |
418 | struct wlr_output *wlr_output = output->wlr_output; | |
419 | struct roots_desktop *desktop = output->desktop; | |
420 | struct roots_server *server = desktop->server; | |
421 | struct wlr_renderer *renderer = wlr_backend_get_renderer(wlr_output->backend); | |
422 | assert(renderer); | |
423 | ||
424 | if (!wlr_output->enabled) { | |
425 | return; | |
426 | } | |
427 | ||
428 | struct timespec now; | |
429 | clock_gettime(CLOCK_MONOTONIC, &now); | |
430 | ||
431 | float clear_color[] = {0.25f, 0.25f, 0.25f, 1.0f}; | |
432 | ||
433 | const struct wlr_box *output_box = | |
434 | wlr_output_layout_get_box(desktop->layout, wlr_output); | |
435 | ||
436 | // Check if we can delegate the fullscreen surface to the output | |
437 | if (output->fullscreen_view != NULL && | |
438 | output->fullscreen_view->wlr_surface != NULL) { | |
439 | struct roots_view *view = output->fullscreen_view; | |
440 | ||
441 | // Make sure the view is centered on screen | |
442 | struct wlr_box view_box; | |
443 | view_get_box(view, &view_box); | |
444 | double view_x = (double)(output_box->width - view_box.width) / 2 + | |
445 | output_box->x; | |
446 | double view_y = (double)(output_box->height - view_box.height) / 2 + | |
447 | output_box->y; | |
448 | view_move(view, view_x, view_y); | |
449 | ||
450 | // Fullscreen views are rendered on a black background | |
451 | clear_color[0] = clear_color[1] = clear_color[2] = 0; | |
452 | } | |
453 | ||
454 | bool needs_swap; | |
455 | pixman_region32_t damage; | |
456 | pixman_region32_init(&damage); | |
457 | if (!wlr_output_damage_make_current(output->damage, &needs_swap, &damage)) { | |
458 | return; | |
459 | } | |
460 | ||
461 | struct render_data data = { | |
462 | .output = output, | |
463 | .when = &now, | |
464 | .damage = &damage, | |
465 | .alpha = 1.0, | |
466 | }; | |
467 | ||
468 | if (!needs_swap) { | |
469 | // Output doesn't need swap and isn't damaged, skip rendering completely | |
470 | goto damage_finish; | |
471 | } | |
472 | ||
473 | wlr_renderer_begin(renderer, wlr_output->width, wlr_output->height); | |
474 | ||
475 | if (!pixman_region32_not_empty(&damage)) { | |
476 | // Output isn't damaged but needs buffer swap | |
477 | goto renderer_end; | |
478 | } | |
479 | ||
480 | if (server->config->debug_damage_tracking) { | |
481 | wlr_renderer_clear(renderer, (float[]){1, 1, 0, 1}); | |
482 | } | |
483 | ||
484 | int nrects; | |
485 | pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects); | |
486 | for (int i = 0; i < nrects; ++i) { | |
487 | scissor_output(output, &rects[i]); | |
488 | wlr_renderer_clear(renderer, clear_color); | |
489 | } | |
490 | ||
491 | render_layer(output, output_box, &data, | |
492 | &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]); | |
493 | render_layer(output, output_box, &data, | |
494 | &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]); | |
495 | ||
496 | // If a view is fullscreen on this output, render it | |
497 | if (output->fullscreen_view != NULL) { | |
498 | struct roots_view *view = output->fullscreen_view; | |
499 | ||
500 | if (view->wlr_surface != NULL) { | |
501 | view_for_each_surface(view, &data.layout, render_surface, &data); | |
502 | } | |
503 | ||
504 | // During normal rendering the xwayland window tree isn't traversed | |
505 | // because all windows are rendered. Here we only want to render | |
506 | // the fullscreen window's children so we have to traverse the tree. | |
507 | #if WLR_HAS_XWAYLAND | |
508 | if (view->type == ROOTS_XWAYLAND_VIEW) { | |
509 | struct roots_xwayland_surface *xwayland_surface = | |
510 | roots_xwayland_surface_from_view(view); | |
511 | xwayland_children_for_each_surface( | |
512 | xwayland_surface->xwayland_surface, | |
513 | render_surface, &data.layout, &data); | |
514 | } | |
515 | #endif | |
516 | } else { | |
517 | // Render all views | |
518 | struct roots_view *view; | |
519 | wl_list_for_each_reverse(view, &desktop->views, link) { | |
520 | render_view(view, &data); | |
521 | } | |
522 | // Render top layer above shell views | |
523 | render_layer(output, output_box, &data, | |
524 | &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]); | |
525 | } | |
526 | ||
527 | // Render drag icons | |
528 | data.alpha = 1.0; | |
529 | drag_icons_for_each_surface(server->input, render_surface, &data.layout, | |
530 | &data); | |
531 | ||
532 | render_layer(output, output_box, &data, | |
533 | &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]); | |
534 | ||
535 | renderer_end: | |
536 | wlr_output_render_software_cursors(wlr_output, &damage); | |
537 | wlr_renderer_scissor(renderer, NULL); | |
538 | wlr_renderer_end(renderer); | |
539 | ||
540 | int width, height; | |
541 | wlr_output_transformed_resolution(wlr_output, &width, &height); | |
542 | ||
543 | if (server->config->debug_damage_tracking) { | |
544 | pixman_region32_union_rect(&damage, &damage, 0, 0, width, height); | |
545 | } | |
546 | ||
547 | enum wl_output_transform transform = | |
548 | wlr_output_transform_invert(wlr_output->transform); | |
549 | wlr_region_transform(&damage, &damage, transform, width, height); | |
550 | ||
551 | if (!wlr_output_damage_swap_buffers(output->damage, &now, &damage)) { | |
552 | goto damage_finish; | |
553 | } | |
554 | output->last_frame = desktop->last_frame = now; | |
555 | ||
556 | damage_finish: | |
557 | pixman_region32_fini(&damage); | |
558 | ||
559 | // Send frame done events to all surfaces | |
560 | output_for_each_surface(output, surface_send_frame_done, | |
561 | &data.layout, &data); | |
562 | 251 | } |
563 | 252 | |
564 | 253 | void output_damage_whole(struct roots_output *output) { |
595 | 284 | return false; |
596 | 285 | } |
597 | 286 | |
598 | struct damage_data { | |
599 | struct layout_data layout; | |
600 | struct roots_output *output; | |
601 | }; | |
602 | ||
603 | static void damage_whole_surface(struct wlr_surface *surface, int sx, int sy, | |
604 | void *_data) { | |
605 | struct damage_data *data = _data; | |
606 | struct roots_output *output = data->output; | |
607 | float rotation = data->layout.rotation; | |
608 | ||
609 | double lx, ly; | |
610 | get_layout_position(&data->layout, &lx, &ly, surface, sx, sy); | |
611 | ||
612 | if (!wlr_surface_has_buffer(surface)) { | |
613 | return; | |
614 | } | |
615 | ||
616 | int ow, oh; | |
617 | wlr_output_transformed_resolution(output->wlr_output, &ow, &oh); | |
618 | ||
619 | struct wlr_box box; | |
620 | bool intersects = surface_intersect_output(surface, output->desktop->layout, | |
621 | output->wlr_output, lx, ly, rotation, &box); | |
622 | if (!intersects) { | |
623 | return; | |
624 | } | |
625 | ||
626 | wlr_box_rotated_bounds(&box, &box, rotation); | |
627 | ||
628 | wlr_output_damage_add_box(output->damage, &box); | |
287 | static void damage_surface_iterator(struct roots_output *output, | |
288 | struct wlr_surface *surface, struct wlr_box *_box, float rotation, | |
289 | void *data) { | |
290 | bool *whole = data; | |
291 | ||
292 | struct wlr_box box = *_box; | |
293 | scale_box(&box, output->wlr_output->scale); | |
294 | ||
295 | int center_x = box.x + box.width/2; | |
296 | int center_y = box.y + box.height/2; | |
297 | ||
298 | if (pixman_region32_not_empty(&surface->buffer_damage)) { | |
299 | pixman_region32_t damage; | |
300 | pixman_region32_init(&damage); | |
301 | wlr_surface_get_effective_damage(surface, &damage); | |
302 | wlr_region_scale(&damage, &damage, output->wlr_output->scale); | |
303 | if (ceil(output->wlr_output->scale) > surface->current.scale) { | |
304 | // When scaling up a surface, it'll become blurry so we need to | |
305 | // expand the damage region | |
306 | wlr_region_expand(&damage, &damage, | |
307 | ceil(output->wlr_output->scale) - surface->current.scale); | |
308 | } | |
309 | pixman_region32_translate(&damage, box.x, box.y); | |
310 | wlr_region_rotated_bounds(&damage, &damage, rotation, | |
311 | center_x, center_y); | |
312 | wlr_output_damage_add(output->damage, &damage); | |
313 | pixman_region32_fini(&damage); | |
314 | } | |
315 | ||
316 | if (*whole) { | |
317 | wlr_box_rotated_bounds(&box, &box, rotation); | |
318 | wlr_output_damage_add_box(output->damage, &box); | |
319 | } | |
320 | ||
321 | wlr_output_schedule_frame(output->wlr_output); | |
629 | 322 | } |
630 | 323 | |
631 | 324 | void output_damage_whole_local_surface(struct roots_output *output, |
632 | struct wlr_surface *surface, double ox, double oy, float rotation) { | |
633 | struct wlr_output_layout_output *layout = wlr_output_layout_get( | |
634 | output->desktop->layout, output->wlr_output); | |
635 | struct damage_data data = { .output = output }; | |
636 | surface_for_each_surface(surface, ox + layout->x, oy + layout->y, 0, | |
637 | &data.layout, damage_whole_surface, &data); | |
325 | struct wlr_surface *surface, double ox, double oy) { | |
326 | bool whole = true; | |
327 | output_surface_for_each_surface(output, surface, ox, oy, | |
328 | damage_surface_iterator, &whole); | |
638 | 329 | } |
639 | 330 | |
640 | 331 | static void damage_whole_decoration(struct roots_view *view, |
659 | 350 | |
660 | 351 | damage_whole_decoration(view, output); |
661 | 352 | |
662 | struct damage_data data = { .output = output }; | |
663 | view_for_each_surface(view, &data.layout, damage_whole_surface, &data); | |
353 | bool whole = true; | |
354 | output_view_for_each_surface(output, view, damage_surface_iterator, &whole); | |
664 | 355 | } |
665 | 356 | |
666 | 357 | void output_damage_whole_drag_icon(struct roots_output *output, |
667 | 358 | struct roots_drag_icon *icon) { |
668 | struct damage_data data = { .output = output }; | |
669 | surface_for_each_surface(icon->wlr_drag_icon->surface, icon->x, icon->y, 0, | |
670 | &data.layout, damage_whole_surface, &data); | |
671 | } | |
672 | ||
673 | static void damage_from_surface(struct wlr_surface *surface, int sx, int sy, | |
674 | void *_data) { | |
675 | struct damage_data *data = _data; | |
676 | struct roots_output *output = data->output; | |
677 | struct wlr_output *wlr_output = output->wlr_output; | |
678 | float rotation = data->layout.rotation; | |
679 | ||
680 | double lx, ly; | |
681 | get_layout_position(&data->layout, &lx, &ly, surface, sx, sy); | |
682 | ||
683 | if (!wlr_surface_has_buffer(surface)) { | |
684 | return; | |
685 | } | |
686 | ||
687 | int ow, oh; | |
688 | wlr_output_transformed_resolution(wlr_output, &ow, &oh); | |
689 | ||
690 | struct wlr_box box; | |
691 | surface_intersect_output(surface, output->desktop->layout, | |
692 | wlr_output, lx, ly, rotation, &box); | |
693 | ||
694 | int center_x = box.x + box.width/2; | |
695 | int center_y = box.y + box.height/2; | |
696 | ||
697 | pixman_region32_t damage; | |
698 | pixman_region32_init(&damage); | |
699 | wlr_surface_get_effective_damage(surface, &damage); | |
700 | ||
701 | wlr_region_scale(&damage, &damage, wlr_output->scale); | |
702 | if (ceil(wlr_output->scale) > surface->current.scale) { | |
703 | // When scaling up a surface, it'll become blurry so we need to | |
704 | // expand the damage region | |
705 | wlr_region_expand(&damage, &damage, | |
706 | ceil(wlr_output->scale) - surface->current.scale); | |
707 | } | |
708 | pixman_region32_translate(&damage, box.x, box.y); | |
709 | wlr_region_rotated_bounds(&damage, &damage, rotation, center_x, center_y); | |
710 | wlr_output_damage_add(output->damage, &damage); | |
711 | pixman_region32_fini(&damage); | |
359 | bool whole = true; | |
360 | output_surface_for_each_surface(output, icon->wlr_drag_icon->surface, | |
361 | icon->x, icon->y, damage_surface_iterator, &whole); | |
712 | 362 | } |
713 | 363 | |
714 | 364 | void output_damage_from_local_surface(struct roots_output *output, |
715 | struct wlr_surface *surface, double ox, double oy, float rotation) { | |
716 | struct wlr_output_layout_output *layout = wlr_output_layout_get( | |
717 | output->desktop->layout, output->wlr_output); | |
718 | struct damage_data data = { .output = output }; | |
719 | surface_for_each_surface(surface, ox + layout->x, oy + layout->y, 0, | |
720 | &data.layout, damage_from_surface, &data); | |
365 | struct wlr_surface *surface, double ox, double oy) { | |
366 | bool whole = false; | |
367 | output_surface_for_each_surface(output, surface, ox, oy, | |
368 | damage_surface_iterator, &whole); | |
721 | 369 | } |
722 | 370 | |
723 | 371 | void output_damage_from_view(struct roots_output *output, |
726 | 374 | return; |
727 | 375 | } |
728 | 376 | |
729 | struct damage_data data = { .output = output }; | |
730 | view_for_each_surface(view, &data.layout, damage_from_surface, &data); | |
377 | bool whole = false; | |
378 | output_view_for_each_surface(output, view, damage_surface_iterator, &whole); | |
731 | 379 | } |
732 | 380 | |
733 | 381 | static void set_mode(struct wlr_output *output, |
782 | 430 | void *data) { |
783 | 431 | struct roots_output *output = |
784 | 432 | wl_container_of(listener, output, damage_frame); |
785 | render_output(output); | |
433 | output_render(output); | |
786 | 434 | } |
787 | 435 | |
788 | 436 | static void output_damage_handle_destroy(struct wl_listener *listener, |
804 | 452 | arrange_layers(output); |
805 | 453 | } |
806 | 454 | |
807 | struct presentation_data { | |
808 | struct layout_data layout; | |
809 | struct roots_output *output; | |
810 | struct wlr_presentation_event *event; | |
811 | }; | |
812 | ||
813 | static void surface_send_presented(struct wlr_surface *surface, int sx, int sy, | |
814 | void *_data) { | |
815 | struct presentation_data *data = _data; | |
816 | struct roots_output *output = data->output; | |
817 | float rotation = data->layout.rotation; | |
818 | ||
819 | double lx, ly; | |
820 | get_layout_position(&data->layout, &lx, &ly, surface, sx, sy); | |
821 | ||
822 | if (!surface_intersect_output(surface, output->desktop->layout, | |
823 | output->wlr_output, lx, ly, rotation, NULL)) { | |
824 | return; | |
825 | } | |
826 | ||
455 | static void surface_send_presented_iterator(struct roots_output *output, | |
456 | struct wlr_surface *surface, struct wlr_box *_box, float rotation, | |
457 | void *data) { | |
458 | struct wlr_presentation_event *event = data; | |
827 | 459 | wlr_presentation_send_surface_presented(output->desktop->presentation, |
828 | surface, data->event); | |
460 | surface, event); | |
829 | 461 | } |
830 | 462 | |
831 | 463 | static void output_handle_present(struct wl_listener *listener, void *data) { |
842 | 474 | .flags = output_event->flags, |
843 | 475 | }; |
844 | 476 | |
845 | struct presentation_data presentation_data = { | |
846 | .output = output, | |
847 | .event = &event, | |
848 | }; | |
849 | output_for_each_surface(output, surface_send_presented, | |
850 | &presentation_data.layout, &presentation_data); | |
477 | output_for_each_surface(output, | |
478 | surface_send_presented_iterator, &event); | |
851 | 479 | } |
852 | 480 | |
853 | 481 | void handle_new_output(struct wl_listener *listener, void *data) { |
0 | #define _POSIX_C_SOURCE 200809L | |
1 | #include <assert.h> | |
2 | #include <stdbool.h> | |
3 | #include <stdlib.h> | |
4 | #include <time.h> | |
5 | #include <wlr/config.h> | |
6 | #include <wlr/types/wlr_compositor.h> | |
7 | #include <wlr/types/wlr_matrix.h> | |
8 | #include <wlr/util/log.h> | |
9 | #include <wlr/util/region.h> | |
10 | #include "rootston/layers.h" | |
11 | #include "rootston/output.h" | |
12 | #include "rootston/server.h" | |
13 | ||
14 | struct render_data { | |
15 | pixman_region32_t *damage; | |
16 | float alpha; | |
17 | }; | |
18 | ||
19 | static void scissor_output(struct wlr_output *wlr_output, | |
20 | pixman_box32_t *rect) { | |
21 | struct wlr_renderer *renderer = | |
22 | wlr_backend_get_renderer(wlr_output->backend); | |
23 | assert(renderer); | |
24 | ||
25 | struct wlr_box box = { | |
26 | .x = rect->x1, | |
27 | .y = rect->y1, | |
28 | .width = rect->x2 - rect->x1, | |
29 | .height = rect->y2 - rect->y1, | |
30 | }; | |
31 | ||
32 | int ow, oh; | |
33 | wlr_output_transformed_resolution(wlr_output, &ow, &oh); | |
34 | ||
35 | enum wl_output_transform transform = | |
36 | wlr_output_transform_invert(wlr_output->transform); | |
37 | wlr_box_transform(&box, &box, transform, ow, oh); | |
38 | ||
39 | wlr_renderer_scissor(renderer, &box); | |
40 | } | |
41 | ||
42 | static void render_texture(struct wlr_output *wlr_output, | |
43 | pixman_region32_t *output_damage, struct wlr_texture *texture, | |
44 | const struct wlr_box *box, const float matrix[static 9], | |
45 | float rotation, float alpha) { | |
46 | struct wlr_renderer *renderer = | |
47 | wlr_backend_get_renderer(wlr_output->backend); | |
48 | assert(renderer); | |
49 | ||
50 | struct wlr_box rotated; | |
51 | wlr_box_rotated_bounds(&rotated, box, rotation); | |
52 | ||
53 | pixman_region32_t damage; | |
54 | pixman_region32_init(&damage); | |
55 | pixman_region32_union_rect(&damage, &damage, rotated.x, rotated.y, | |
56 | rotated.width, rotated.height); | |
57 | pixman_region32_intersect(&damage, &damage, output_damage); | |
58 | bool damaged = pixman_region32_not_empty(&damage); | |
59 | if (!damaged) { | |
60 | goto damage_finish; | |
61 | } | |
62 | ||
63 | int nrects; | |
64 | pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects); | |
65 | for (int i = 0; i < nrects; ++i) { | |
66 | scissor_output(wlr_output, &rects[i]); | |
67 | wlr_render_texture_with_matrix(renderer, texture, matrix, alpha); | |
68 | } | |
69 | ||
70 | damage_finish: | |
71 | pixman_region32_fini(&damage); | |
72 | } | |
73 | ||
74 | static void render_surface_iterator(struct roots_output *output, | |
75 | struct wlr_surface *surface, struct wlr_box *_box, float rotation, | |
76 | void *_data) { | |
77 | struct render_data *data = _data; | |
78 | struct wlr_output *wlr_output = output->wlr_output; | |
79 | pixman_region32_t *output_damage = data->damage; | |
80 | float alpha = data->alpha; | |
81 | ||
82 | struct wlr_texture *texture = wlr_surface_get_texture(surface); | |
83 | if (!texture) { | |
84 | return; | |
85 | } | |
86 | ||
87 | struct wlr_box box = *_box; | |
88 | scale_box(&box, wlr_output->scale); | |
89 | ||
90 | float matrix[9]; | |
91 | enum wl_output_transform transform = | |
92 | wlr_output_transform_invert(surface->current.transform); | |
93 | wlr_matrix_project_box(matrix, &box, transform, rotation, | |
94 | wlr_output->transform_matrix); | |
95 | ||
96 | render_texture(wlr_output, output_damage, | |
97 | texture, &box, matrix, rotation, alpha); | |
98 | } | |
99 | ||
100 | static void render_decorations(struct roots_output *output, | |
101 | struct roots_view *view, struct render_data *data) { | |
102 | if (!view->decorated || view->wlr_surface == NULL) { | |
103 | return; | |
104 | } | |
105 | ||
106 | struct wlr_renderer *renderer = | |
107 | wlr_backend_get_renderer(output->wlr_output->backend); | |
108 | assert(renderer); | |
109 | ||
110 | struct wlr_box box; | |
111 | get_decoration_box(view, output, &box); | |
112 | ||
113 | struct wlr_box rotated; | |
114 | wlr_box_rotated_bounds(&rotated, &box, view->rotation); | |
115 | ||
116 | pixman_region32_t damage; | |
117 | pixman_region32_init(&damage); | |
118 | pixman_region32_union_rect(&damage, &damage, rotated.x, rotated.y, | |
119 | rotated.width, rotated.height); | |
120 | pixman_region32_intersect(&damage, &damage, data->damage); | |
121 | bool damaged = pixman_region32_not_empty(&damage); | |
122 | if (!damaged) { | |
123 | goto damage_finish; | |
124 | } | |
125 | ||
126 | float matrix[9]; | |
127 | wlr_matrix_project_box(matrix, &box, WL_OUTPUT_TRANSFORM_NORMAL, | |
128 | view->rotation, output->wlr_output->transform_matrix); | |
129 | float color[] = { 0.2, 0.2, 0.2, view->alpha }; | |
130 | ||
131 | int nrects; | |
132 | pixman_box32_t *rects = | |
133 | pixman_region32_rectangles(&damage, &nrects); | |
134 | for (int i = 0; i < nrects; ++i) { | |
135 | scissor_output(output->wlr_output, &rects[i]); | |
136 | wlr_render_quad_with_matrix(renderer, color, matrix); | |
137 | } | |
138 | ||
139 | damage_finish: | |
140 | pixman_region32_fini(&damage); | |
141 | } | |
142 | ||
143 | static void render_view(struct roots_output *output, struct roots_view *view, | |
144 | struct render_data *data) { | |
145 | // Do not render views fullscreened on other outputs | |
146 | if (view->fullscreen_output != NULL && view->fullscreen_output != output) { | |
147 | return; | |
148 | } | |
149 | ||
150 | data->alpha = view->alpha; | |
151 | if (view->fullscreen_output == NULL) { | |
152 | render_decorations(output, view, data); | |
153 | } | |
154 | output_view_for_each_surface(output, view, render_surface_iterator, data); | |
155 | } | |
156 | ||
157 | static void render_layer(struct roots_output *output, | |
158 | pixman_region32_t *damage, struct wl_list *layer_surfaces) { | |
159 | struct render_data data = { | |
160 | .damage = damage, | |
161 | .alpha = 1.0f, | |
162 | }; | |
163 | output_layer_for_each_surface(output, layer_surfaces, | |
164 | render_surface_iterator, &data); | |
165 | } | |
166 | ||
167 | static void render_drag_icons(struct roots_output *output, | |
168 | pixman_region32_t *damage, struct roots_input *input) { | |
169 | struct render_data data = { | |
170 | .damage = damage, | |
171 | .alpha = 1.0f, | |
172 | }; | |
173 | output_drag_icons_for_each_surface(output, input, | |
174 | render_surface_iterator, &data); | |
175 | } | |
176 | ||
177 | static void surface_send_frame_done_iterator(struct roots_output *output, | |
178 | struct wlr_surface *surface, struct wlr_box *box, float rotation, | |
179 | void *data) { | |
180 | struct timespec *when = data; | |
181 | wlr_surface_send_frame_done(surface, when); | |
182 | } | |
183 | ||
184 | void output_render(struct roots_output *output) { | |
185 | struct wlr_output *wlr_output = output->wlr_output; | |
186 | struct roots_desktop *desktop = output->desktop; | |
187 | struct roots_server *server = desktop->server; | |
188 | struct wlr_renderer *renderer = | |
189 | wlr_backend_get_renderer(wlr_output->backend); | |
190 | assert(renderer); | |
191 | ||
192 | if (!wlr_output->enabled) { | |
193 | return; | |
194 | } | |
195 | ||
196 | struct timespec now; | |
197 | clock_gettime(CLOCK_MONOTONIC, &now); | |
198 | ||
199 | float clear_color[] = {0.25f, 0.25f, 0.25f, 1.0f}; | |
200 | ||
201 | const struct wlr_box *output_box = | |
202 | wlr_output_layout_get_box(desktop->layout, wlr_output); | |
203 | ||
204 | // Check if we can delegate the fullscreen surface to the output | |
205 | if (output->fullscreen_view != NULL && | |
206 | output->fullscreen_view->wlr_surface != NULL) { | |
207 | struct roots_view *view = output->fullscreen_view; | |
208 | ||
209 | // Make sure the view is centered on screen | |
210 | struct wlr_box view_box; | |
211 | view_get_box(view, &view_box); | |
212 | double view_x = (double)(output_box->width - view_box.width) / 2 + | |
213 | output_box->x; | |
214 | double view_y = (double)(output_box->height - view_box.height) / 2 + | |
215 | output_box->y; | |
216 | view_move(view, view_x, view_y); | |
217 | ||
218 | // Fullscreen views are rendered on a black background | |
219 | clear_color[0] = clear_color[1] = clear_color[2] = 0; | |
220 | } | |
221 | ||
222 | bool needs_swap; | |
223 | pixman_region32_t damage; | |
224 | pixman_region32_init(&damage); | |
225 | if (!wlr_output_damage_make_current(output->damage, &needs_swap, &damage)) { | |
226 | return; | |
227 | } | |
228 | ||
229 | struct render_data data = { | |
230 | .damage = &damage, | |
231 | .alpha = 1.0, | |
232 | }; | |
233 | ||
234 | if (!needs_swap) { | |
235 | // Output doesn't need swap and isn't damaged, skip rendering completely | |
236 | goto damage_finish; | |
237 | } | |
238 | ||
239 | wlr_renderer_begin(renderer, wlr_output->width, wlr_output->height); | |
240 | ||
241 | if (!pixman_region32_not_empty(&damage)) { | |
242 | // Output isn't damaged but needs buffer swap | |
243 | goto renderer_end; | |
244 | } | |
245 | ||
246 | if (server->config->debug_damage_tracking) { | |
247 | wlr_renderer_clear(renderer, (float[]){1, 1, 0, 1}); | |
248 | } | |
249 | ||
250 | int nrects; | |
251 | pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects); | |
252 | for (int i = 0; i < nrects; ++i) { | |
253 | scissor_output(output->wlr_output, &rects[i]); | |
254 | wlr_renderer_clear(renderer, clear_color); | |
255 | } | |
256 | ||
257 | render_layer(output, &damage, | |
258 | &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]); | |
259 | render_layer(output, &damage, | |
260 | &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]); | |
261 | ||
262 | // If a view is fullscreen on this output, render it | |
263 | if (output->fullscreen_view != NULL) { | |
264 | struct roots_view *view = output->fullscreen_view; | |
265 | ||
266 | render_view(output, view, &data); | |
267 | ||
268 | // During normal rendering the xwayland window tree isn't traversed | |
269 | // because all windows are rendered. Here we only want to render | |
270 | // the fullscreen window's children so we have to traverse the tree. | |
271 | #if WLR_HAS_XWAYLAND | |
272 | if (view->type == ROOTS_XWAYLAND_VIEW) { | |
273 | struct roots_xwayland_surface *xwayland_surface = | |
274 | roots_xwayland_surface_from_view(view); | |
275 | output_xwayland_children_for_each_surface(output, | |
276 | xwayland_surface->xwayland_surface, | |
277 | render_surface_iterator, &data); | |
278 | } | |
279 | #endif | |
280 | } else { | |
281 | // Render all views | |
282 | struct roots_view *view; | |
283 | wl_list_for_each_reverse(view, &desktop->views, link) { | |
284 | render_view(output, view, &data); | |
285 | } | |
286 | // Render top layer above shell views | |
287 | render_layer(output, &damage, | |
288 | &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]); | |
289 | } | |
290 | ||
291 | render_drag_icons(output, &damage, server->input); | |
292 | ||
293 | render_layer(output, &damage, | |
294 | &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]); | |
295 | ||
296 | renderer_end: | |
297 | wlr_output_render_software_cursors(wlr_output, &damage); | |
298 | wlr_renderer_scissor(renderer, NULL); | |
299 | wlr_renderer_end(renderer); | |
300 | ||
301 | int width, height; | |
302 | wlr_output_transformed_resolution(wlr_output, &width, &height); | |
303 | ||
304 | if (server->config->debug_damage_tracking) { | |
305 | pixman_region32_union_rect(&damage, &damage, 0, 0, width, height); | |
306 | } | |
307 | ||
308 | enum wl_output_transform transform = | |
309 | wlr_output_transform_invert(wlr_output->transform); | |
310 | wlr_region_transform(&damage, &damage, transform, width, height); | |
311 | ||
312 | if (!wlr_output_damage_swap_buffers(output->damage, &now, &damage)) { | |
313 | goto damage_finish; | |
314 | } | |
315 | output->last_frame = desktop->last_frame = now; | |
316 | ||
317 | damage_finish: | |
318 | pixman_region32_fini(&damage); | |
319 | ||
320 | // Send frame done events to all surfaces | |
321 | output_for_each_surface(output, surface_send_frame_done_iterator, | |
322 | &now); | |
323 | } |
558 | 558 | } |
559 | 559 | } |
560 | 560 | |
561 | void view_for_each_surface(struct roots_view *view, | |
562 | wlr_surface_iterator_func_t iterator, void *user_data) { | |
563 | if (view->impl->for_each_surface) { | |
564 | view->impl->for_each_surface(view, iterator, user_data); | |
565 | } else if (view->wlr_surface) { | |
566 | wlr_surface_for_each_surface(view->wlr_surface, iterator, user_data); | |
567 | } | |
568 | } | |
569 | ||
561 | 570 | void view_update_position(struct roots_view *view, int x, int y) { |
562 | 571 | if (view->box.x == x && view->box.y == y) { |
563 | 572 | return; |
79 | 79 | wl_client_destroy(surf->client); |
80 | 80 | } |
81 | 81 | |
82 | static void for_each_surface(struct roots_view *view, | |
83 | wlr_surface_iterator_func_t iterator, void *user_data) { | |
84 | struct wlr_wl_shell_surface *surf = | |
85 | roots_wl_shell_surface_from_view(view)->wl_shell_surface; | |
86 | wlr_wl_shell_surface_for_each_surface(surf, iterator, user_data); | |
87 | } | |
88 | ||
82 | 89 | static void destroy(struct roots_view *view) { |
83 | 90 | struct roots_wl_shell_surface *roots_surface = |
84 | 91 | roots_wl_shell_surface_from_view(view); |
97 | 104 | static const struct roots_view_interface view_impl = { |
98 | 105 | .resize = resize, |
99 | 106 | .close = close, |
107 | .for_each_surface = for_each_surface, | |
100 | 108 | .destroy = destroy, |
101 | 109 | }; |
102 | 110 |
253 | 253 | wlr_xdg_popup_destroy(popup->base); |
254 | 254 | } |
255 | 255 | wlr_xdg_toplevel_send_close(xdg_surface); |
256 | } | |
257 | ||
258 | static void for_each_surface(struct roots_view *view, | |
259 | wlr_surface_iterator_func_t iterator, void *user_data) { | |
260 | struct wlr_xdg_surface *xdg_surface = | |
261 | roots_xdg_surface_from_view(view)->xdg_surface; | |
262 | wlr_xdg_surface_for_each_surface(xdg_surface, iterator, user_data); | |
256 | 263 | } |
257 | 264 | |
258 | 265 | static void destroy(struct roots_view *view) { |
280 | 287 | .maximize = maximize, |
281 | 288 | .set_fullscreen = set_fullscreen, |
282 | 289 | .close = close, |
290 | .for_each_surface = for_each_surface, | |
283 | 291 | .destroy = destroy, |
284 | 292 | }; |
285 | 293 |
252 | 252 | wlr_xdg_surface_v6_send_close(popup->base); |
253 | 253 | } |
254 | 254 | wlr_xdg_surface_v6_send_close(surface); |
255 | } | |
256 | ||
257 | static void for_each_surface(struct roots_view *view, | |
258 | wlr_surface_iterator_func_t iterator, void *user_data) { | |
259 | struct wlr_xdg_surface_v6 *surface = | |
260 | roots_xdg_surface_v6_from_view(view)->xdg_surface_v6; | |
261 | wlr_xdg_surface_v6_for_each_surface(surface, iterator, user_data); | |
255 | 262 | } |
256 | 263 | |
257 | 264 | static void destroy(struct roots_view *view) { |
278 | 285 | .maximize = maximize, |
279 | 286 | .set_fullscreen = set_fullscreen, |
280 | 287 | .close = close, |
288 | .for_each_surface = for_each_surface, | |
281 | 289 | .destroy = destroy, |
282 | 290 | }; |
283 | 291 |
44 | 44 | struct wl_listener cursor_motion_absolute; |
45 | 45 | struct wl_listener cursor_button; |
46 | 46 | struct wl_listener cursor_axis; |
47 | struct wl_listener cursor_frame; | |
47 | 48 | |
48 | 49 | struct wlr_seat *seat; |
49 | 50 | struct wl_listener new_input; |
498 | 499 | event->delta_discrete, event->source); |
499 | 500 | } |
500 | 501 | |
502 | static void server_cursor_frame(struct wl_listener *listener, void *data) { | |
503 | /* This event is forwarded by the cursor when a pointer emits an frame | |
504 | * event. Frame events are sent after regular pointer events to group | |
505 | * multiple events together. For instance, two axis events may happen at the | |
506 | * same time, in which case a frame event won't be sent in between. */ | |
507 | struct tinywl_server *server = | |
508 | wl_container_of(listener, server, cursor_frame); | |
509 | /* Notify the client with pointer focus of the frame event. */ | |
510 | wlr_seat_pointer_notify_frame(server->seat); | |
511 | } | |
512 | ||
501 | 513 | /* Used to move all of the data necessary to render a surface from the top-level |
502 | 514 | * frame handler to the per-surface render function. */ |
503 | 515 | struct render_data { |
875 | 887 | wl_signal_add(&server.cursor->events.button, &server.cursor_button); |
876 | 888 | server.cursor_axis.notify = server_cursor_axis; |
877 | 889 | wl_signal_add(&server.cursor->events.axis, &server.cursor_axis); |
890 | server.cursor_frame.notify = server_cursor_frame; | |
891 | wl_signal_add(&server.cursor->events.frame, &server.cursor_frame); | |
878 | 892 | |
879 | 893 | /* |
880 | 894 | * Configures a seat, which is a single "seat" at which a user sits and |
19 | 19 | } |
20 | 20 | |
21 | 21 | static uint32_t default_pointer_button(struct wlr_seat_pointer_grab *grab, |
22 | uint32_t time, uint32_t button, uint32_t state) { | |
22 | uint32_t time, uint32_t button, enum wlr_button_state state) { | |
23 | 23 | return wlr_seat_pointer_send_button(grab->seat, time, button, state); |
24 | 24 | } |
25 | 25 | |
234 | 234 | } |
235 | 235 | |
236 | 236 | uint32_t wlr_seat_pointer_send_button(struct wlr_seat *wlr_seat, uint32_t time, |
237 | uint32_t button, uint32_t state) { | |
237 | uint32_t button, enum wlr_button_state state) { | |
238 | 238 | struct wlr_seat_client *client = wlr_seat->pointer_state.focused_client; |
239 | 239 | if (client == NULL) { |
240 | 240 | return 0; |
336 | 336 | } |
337 | 337 | |
338 | 338 | uint32_t wlr_seat_pointer_notify_button(struct wlr_seat *wlr_seat, |
339 | uint32_t time, uint32_t button, uint32_t state) { | |
339 | uint32_t time, uint32_t button, enum wlr_button_state state) { | |
340 | 340 | clock_gettime(CLOCK_MONOTONIC, &wlr_seat->last_event); |
341 | if (state == WL_POINTER_BUTTON_STATE_PRESSED) { | |
341 | if (state == WLR_BUTTON_PRESSED) { | |
342 | 342 | if (wlr_seat->pointer_state.button_count == 0) { |
343 | 343 | wlr_seat->pointer_state.grab_button = button; |
344 | 344 | wlr_seat->pointer_state.grab_time = time; |
345 | 345 | } |
346 | 346 | wlr_seat->pointer_state.button_count++; |
347 | 347 | } else { |
348 | wlr_seat->pointer_state.button_count--; | |
348 | if (wlr_seat->pointer_state.button_count == 0) { | |
349 | wlr_log(WLR_ERROR, "Corrupted seat button count"); | |
350 | } else { | |
351 | wlr_seat->pointer_state.button_count--; | |
352 | } | |
349 | 353 | } |
350 | 354 | |
351 | 355 | struct wlr_seat_pointer_grab *grab = wlr_seat->pointer_state.grab; |
352 | 356 | uint32_t serial = grab->interface->button(grab, time, button, state); |
353 | 357 | |
354 | if (serial && wlr_seat->pointer_state.button_count == 1) { | |
358 | if (serial && wlr_seat->pointer_state.button_count == 1 && | |
359 | state == WLR_BUTTON_PRESSED) { | |
355 | 360 | wlr_seat->pointer_state.grab_serial = serial; |
356 | 361 | } |
357 | 362 | |
406 | 411 | struct wlr_surface *origin, uint32_t serial) { |
407 | 412 | if (seat->pointer_state.button_count != 1 || |
408 | 413 | seat->pointer_state.grab_serial != serial) { |
414 | wlr_log(WLR_DEBUG, "Pointer grab serial validation failed: " | |
415 | "button_count=%"PRIu32" grab_serial=%"PRIu32" (got %"PRIu32")", | |
416 | seat->pointer_state.button_count, | |
417 | seat->pointer_state.grab_serial, serial); | |
409 | 418 | return false; |
410 | 419 | } |
411 | 420 | |
412 | 421 | if (origin != NULL && seat->pointer_state.focused_surface != origin) { |
422 | wlr_log(WLR_DEBUG, "Pointer grab serial validation failed: " | |
423 | "invalid origin surface"); | |
413 | 424 | return false; |
414 | 425 | } |
415 | 426 |
364 | 364 | struct wlr_touch_point **point_ptr) { |
365 | 365 | if (wlr_seat_touch_num_points(seat) != 1 || |
366 | 366 | seat->touch_state.grab_serial != serial) { |
367 | wlr_log(WLR_DEBUG, "Touch grab serial validation failed: " | |
368 | "num_points=%d grab_serial=%"PRIu32" (got %"PRIu32")", | |
369 | wlr_seat_touch_num_points(seat), | |
370 | seat->touch_state.grab_serial, serial); | |
367 | 371 | return false; |
368 | 372 | } |
369 | 373 | |
377 | 381 | } |
378 | 382 | } |
379 | 383 | |
384 | wlr_log(WLR_DEBUG, "Touch grab serial validation failed: " | |
385 | "invalid origin surface"); | |
380 | 386 | return false; |
381 | 387 | } |
379 | 379 | } |
380 | 380 | } else { |
381 | 381 | // layout extents |
382 | int min_x = INT_MAX, min_y = INT_MAX; | |
383 | int max_x = INT_MIN, max_y = INT_MIN; | |
384 | wl_list_for_each(l_output, &layout->outputs, link) { | |
385 | struct wlr_box *box = output_layout_output_get_box(l_output); | |
386 | ||
387 | if (box->x < min_x) { | |
388 | min_x = box->x; | |
389 | } | |
390 | if (box->y < min_y) { | |
391 | min_y = box->y; | |
392 | } | |
393 | if (box->x + box->width > max_x) { | |
394 | max_x = box->x + box->width; | |
395 | } | |
396 | if (box->y + box->height > max_y) { | |
397 | max_y = box->y + box->height; | |
382 | int min_x = 0, max_x = 0, min_y = 0, max_y = 0; | |
383 | if (!wl_list_empty(&layout->outputs)) { | |
384 | min_x = min_y = INT_MAX; | |
385 | max_x = max_y = INT_MIN; | |
386 | wl_list_for_each(l_output, &layout->outputs, link) { | |
387 | struct wlr_box *box = output_layout_output_get_box(l_output); | |
388 | if (box->x < min_x) { | |
389 | min_x = box->x; | |
390 | } | |
391 | if (box->y < min_y) { | |
392 | min_y = box->y; | |
393 | } | |
394 | if (box->x + box->width > max_x) { | |
395 | max_x = box->x + box->width; | |
396 | } | |
397 | if (box->y + box->height > max_y) { | |
398 | max_y = box->y + box->height; | |
399 | } | |
398 | 400 | } |
399 | 401 | } |
400 | 402 |
13 | 13 | #include <wlr/util/log.h> |
14 | 14 | #include "sockets.h" |
15 | 15 | |
16 | static const char *lock_fmt = "/tmp/.X%d-lock"; | |
17 | static const char *socket_dir = "/tmp/.X11-unix"; | |
18 | static const char *socket_fmt = "/tmp/.X11-unix/X%d"; | |
16 | static const char lock_fmt[] = "/tmp/.X%d-lock"; | |
17 | static const char socket_dir[] = "/tmp/.X11-unix"; | |
18 | static const char socket_fmt[] = "/tmp/.X11-unix/X%d"; | |
19 | 19 | #ifndef __linux__ |
20 | static const char *socket_fmt2 = "/tmp/.X11-unix/X%d_"; | |
20 | static const char socket_fmt2[] = "/tmp/.X11-unix/X%d_"; | |
21 | 21 | #endif |
22 | 22 | |
23 | 23 | bool set_cloexec(int fd, bool cloexec) { |
0 | #define _POSIX_C_SOURCE 200112L | |
0 | #define _POSIX_C_SOURCE 200809L | |
1 | 1 | #include <errno.h> |
2 | 2 | #include <fcntl.h> |
3 | 3 | #include <signal.h> |
91 | 91 | |
92 | 92 | // Closes stdout/stderr depending on log verbosity |
93 | 93 | enum wlr_log_importance verbosity = wlr_log_get_verbosity(); |
94 | int devnull = open("/dev/null", O_WRONLY | O_CREAT, 0666); | |
94 | int devnull = open("/dev/null", O_WRONLY | O_CREAT | O_CLOEXEC, 0666); | |
95 | 95 | if (devnull < 0) { |
96 | 96 | wlr_log_errno(WLR_ERROR, "XWayland: failed to open /dev/null"); |
97 | 97 | _exit(EXIT_FAILURE); |
164 | 164 | |
165 | 165 | unlink_display_sockets(wlr_xwayland->display); |
166 | 166 | wlr_xwayland->display = -1; |
167 | unsetenv("DISPLAY"); | |
168 | } | |
169 | ||
170 | static bool xwayland_start_display(struct wlr_xwayland *wlr_xwayland, | |
171 | struct wl_display *wl_display); | |
167 | wlr_xwayland->display_name[0] = '\0'; | |
168 | } | |
172 | 169 | |
173 | 170 | static bool xwayland_start_server(struct wlr_xwayland *wlr_xwayland); |
174 | 171 | static bool xwayland_start_server_lazy(struct wlr_xwayland *wlr_xwayland); |
283 | 280 | return false; |
284 | 281 | } |
285 | 282 | |
286 | char display_name[16]; | |
287 | snprintf(display_name, sizeof(display_name), ":%d", wlr_xwayland->display); | |
288 | setenv("DISPLAY", display_name, true); | |
289 | ||
283 | snprintf(wlr_xwayland->display_name, sizeof(wlr_xwayland->display_name), | |
284 | ":%d", wlr_xwayland->display); | |
290 | 285 | return true; |
291 | 286 | } |
292 | 287 |
582 | 582 | memcpy(xsurface->size_hints, &size_hints, |
583 | 583 | sizeof(struct wlr_xwayland_surface_size_hints)); |
584 | 584 | |
585 | if ((size_hints.flags & XCB_ICCCM_SIZE_HINT_P_MIN_SIZE) == 0) { | |
585 | bool has_min_size_hints = (size_hints.flags & XCB_ICCCM_SIZE_HINT_P_MIN_SIZE) != 0; | |
586 | bool has_base_size_hints = (size_hints.flags & XCB_ICCCM_SIZE_HINT_BASE_SIZE) != 0; | |
587 | /* ICCCM says that if absent, min size is equal to base size and vice versa */ | |
588 | if (!has_min_size_hints && !has_base_size_hints) { | |
586 | 589 | xsurface->size_hints->min_width = -1; |
587 | 590 | xsurface->size_hints->min_height = -1; |
588 | } | |
591 | xsurface->size_hints->base_width = -1; | |
592 | xsurface->size_hints->base_height = -1; | |
593 | } else if (!has_base_size_hints) { | |
594 | xsurface->size_hints->base_width = xsurface->size_hints->min_width; | |
595 | xsurface->size_hints->base_height = xsurface->size_hints->min_height; | |
596 | } else if (!has_min_size_hints) { | |
597 | xsurface->size_hints->min_width = xsurface->size_hints->base_width; | |
598 | xsurface->size_hints->min_height = xsurface->size_hints->base_height; | |
599 | } | |
600 | ||
589 | 601 | if ((size_hints.flags & XCB_ICCCM_SIZE_HINT_P_MAX_SIZE) == 0) { |
590 | 602 | xsurface->size_hints->max_width = -1; |
591 | 603 | xsurface->size_hints->max_height = -1; |