aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/sway/commands.h2
-rw-r--r--include/sway/config.h1
-rw-r--r--include/sway/output.h1
-rw-r--r--include/sway/server.h6
-rw-r--r--include/sway/tree/view.h12
-rw-r--r--protocols/meson.build1
-rw-r--r--sway/commands.c1
-rw-r--r--sway/commands/allow_tearing.c24
-rw-r--r--sway/commands/output.c1
-rw-r--r--sway/commands/output/allow_tearing.c23
-rw-r--r--sway/config/output.c16
-rw-r--r--sway/desktop/output.c28
-rw-r--r--sway/desktop/tearing.c62
-rw-r--r--sway/ipc-json.c4
-rw-r--r--sway/meson.build3
-rw-r--r--sway/server.c7
-rw-r--r--sway/sway-output.5.scd20
-rw-r--r--sway/sway.5.scd14
-rw-r--r--sway/tree/view.c14
-rw-r--r--swaymsg/main.c6
20 files changed, 243 insertions, 3 deletions
diff --git a/include/sway/commands.h b/include/sway/commands.h
index 15cd8698..5210d3ba 100644
--- a/include/sway/commands.h
+++ b/include/sway/commands.h
@@ -104,6 +104,7 @@ struct sway_container *container_find_resize_parent(struct sway_container *con,
104sway_cmd cmd_exec_validate; 104sway_cmd cmd_exec_validate;
105sway_cmd cmd_exec_process; 105sway_cmd cmd_exec_process;
106 106
107sway_cmd cmd_allow_tearing;
107sway_cmd cmd_assign; 108sway_cmd cmd_assign;
108sway_cmd cmd_bar; 109sway_cmd cmd_bar;
109sway_cmd cmd_bindcode; 110sway_cmd cmd_bindcode;
@@ -283,6 +284,7 @@ sway_cmd input_cmd_xkb_switch_layout;
283sway_cmd input_cmd_xkb_variant; 284sway_cmd input_cmd_xkb_variant;
284 285
285sway_cmd output_cmd_adaptive_sync; 286sway_cmd output_cmd_adaptive_sync;
287sway_cmd output_cmd_allow_tearing;
286sway_cmd output_cmd_background; 288sway_cmd output_cmd_background;
287sway_cmd output_cmd_color_profile; 289sway_cmd output_cmd_color_profile;
288sway_cmd output_cmd_disable; 290sway_cmd output_cmd_disable;
diff --git a/include/sway/config.h b/include/sway/config.h
index dfa3c1b7..d9f56157 100644
--- a/include/sway/config.h
+++ b/include/sway/config.h
@@ -289,6 +289,7 @@ struct output_config {
289 enum render_bit_depth render_bit_depth; 289 enum render_bit_depth render_bit_depth;
290 bool set_color_transform; 290 bool set_color_transform;
291 struct wlr_color_transform *color_transform; 291 struct wlr_color_transform *color_transform;
292 int allow_tearing;
292 293
293 char *background; 294 char *background;
294 char *background_option; 295 char *background_option;
diff --git a/include/sway/output.h b/include/sway/output.h
index 2189c6e8..7e2d5892 100644
--- a/include/sway/output.h
+++ b/include/sway/output.h
@@ -73,6 +73,7 @@ struct sway_output {
73 int max_render_time; // In milliseconds 73 int max_render_time; // In milliseconds
74 struct wl_event_source *repaint_timer; 74 struct wl_event_source *repaint_timer;
75 bool gamma_lut_changed; 75 bool gamma_lut_changed;
76 bool allow_tearing;
76}; 77};
77 78
78struct sway_output_non_desktop { 79struct sway_output_non_desktop {
diff --git a/include/sway/server.h b/include/sway/server.h
index abf1b6b4..460f9e17 100644
--- a/include/sway/server.h
+++ b/include/sway/server.h
@@ -115,6 +115,10 @@ struct sway_server {
115 struct wl_listener xdg_activation_v1_new_token; 115 struct wl_listener xdg_activation_v1_new_token;
116 116
117 struct wl_listener request_set_cursor_shape; 117 struct wl_listener request_set_cursor_shape;
118
119 struct wlr_tearing_control_manager_v1 *tearing_control_v1;
120 struct wl_listener tearing_control_new_object;
121 struct wl_list tearing_controllers; // sway_tearing_controller::link
118 122
119 struct wl_list pending_launcher_ctxs; // launcher_ctx::link 123 struct wl_list pending_launcher_ctxs; // launcher_ctx::link
120 124
@@ -182,4 +186,6 @@ void xdg_activation_v1_handle_new_token(struct wl_listener *listener,
182 186
183void set_rr_scheduling(void); 187void set_rr_scheduling(void);
184 188
189void handle_new_tearing_hint(struct wl_listener *listener, void *data);
190
185#endif 191#endif
diff --git a/include/sway/tree/view.h b/include/sway/tree/view.h
index 3ae8cf22..14aad1a1 100644
--- a/include/sway/tree/view.h
+++ b/include/sway/tree/view.h
@@ -4,6 +4,7 @@
4#include <wlr/config.h> 4#include <wlr/config.h>
5#include <wlr/types/wlr_compositor.h> 5#include <wlr/types/wlr_compositor.h>
6#include <wlr/types/wlr_scene.h> 6#include <wlr/types/wlr_scene.h>
7#include <wlr/types/wlr_tearing_control_v1.h>
7#include "sway/config.h" 8#include "sway/config.h"
8#if WLR_HAS_XWAYLAND 9#if WLR_HAS_XWAYLAND
9#include <wlr/xwayland.h> 10#include <wlr/xwayland.h>
@@ -34,6 +35,12 @@ enum sway_view_prop {
34#endif 35#endif
35}; 36};
36 37
38enum sway_view_tearing_mode {
39 TEARING_OVERRIDE_FALSE,
40 TEARING_OVERRIDE_TRUE,
41 TEARING_WINDOW_HINT,
42};
43
37struct sway_view_impl { 44struct sway_view_impl {
38 void (*get_constraints)(struct sway_view *view, double *min_width, 45 void (*get_constraints)(struct sway_view *view, double *min_width,
39 double *max_width, double *min_height, double *max_height); 46 double *max_width, double *min_height, double *max_height);
@@ -111,6 +118,9 @@ struct sway_view {
111 int max_render_time; // In milliseconds 118 int max_render_time; // In milliseconds
112 119
113 enum seat_config_shortcuts_inhibit shortcuts_inhibit; 120 enum seat_config_shortcuts_inhibit shortcuts_inhibit;
121
122 enum sway_view_tearing_mode tearing_mode;
123 enum wp_tearing_control_v1_presentation_hint tearing_hint;
114}; 124};
115 125
116struct sway_xdg_shell_view { 126struct sway_xdg_shell_view {
@@ -335,4 +345,6 @@ void view_assign_ctx(struct sway_view *view, struct launcher_ctx *ctx);
335 345
336void view_send_frame_done(struct sway_view *view); 346void view_send_frame_done(struct sway_view *view);
337 347
348bool view_can_tear(struct sway_view *view);
349
338#endif 350#endif
diff --git a/protocols/meson.build b/protocols/meson.build
index 6eac8542..d96f8757 100644
--- a/protocols/meson.build
+++ b/protocols/meson.build
@@ -14,6 +14,7 @@ protocols = [
14 wl_protocol_dir / 'unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml', 14 wl_protocol_dir / 'unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml',
15 wl_protocol_dir / 'staging/content-type/content-type-v1.xml', 15 wl_protocol_dir / 'staging/content-type/content-type-v1.xml',
16 wl_protocol_dir / 'staging/cursor-shape/cursor-shape-v1.xml', 16 wl_protocol_dir / 'staging/cursor-shape/cursor-shape-v1.xml',
17 wl_protocol_dir / 'staging/tearing-control/tearing-control-v1.xml',
17 'wlr-layer-shell-unstable-v1.xml', 18 'wlr-layer-shell-unstable-v1.xml',
18 'idle.xml', 19 'idle.xml',
19 'wlr-output-power-management-unstable-v1.xml', 20 'wlr-output-power-management-unstable-v1.xml',
diff --git a/sway/commands.c b/sway/commands.c
index 8d003dfa..c2c12ee6 100644
--- a/sway/commands.c
+++ b/sway/commands.c
@@ -112,6 +112,7 @@ static const struct cmd_handler config_handlers[] = {
112 112
113/* Runtime-only commands. Keep alphabetized */ 113/* Runtime-only commands. Keep alphabetized */
114static const struct cmd_handler command_handlers[] = { 114static const struct cmd_handler command_handlers[] = {
115 { "allow_tearing", cmd_allow_tearing },
115 { "border", cmd_border }, 116 { "border", cmd_border },
116 { "create_output", cmd_create_output }, 117 { "create_output", cmd_create_output },
117 { "exit", cmd_exit }, 118 { "exit", cmd_exit },
diff --git a/sway/commands/allow_tearing.c b/sway/commands/allow_tearing.c
new file mode 100644
index 00000000..ee594138
--- /dev/null
+++ b/sway/commands/allow_tearing.c
@@ -0,0 +1,24 @@
1#include <sway/commands.h>
2#include "sway/config.h"
3#include "sway/tree/view.h"
4#include "util.h"
5
6struct cmd_results *cmd_allow_tearing(int argc, char **argv) {
7 struct cmd_results *error = NULL;
8 if ((error = checkarg(argc, "allow_tearing", EXPECTED_AT_LEAST, 1))) {
9 return error;
10 }
11
12 struct sway_container *container = config->handler_context.container;
13 if (!container || !container->view) {
14 return cmd_results_new(CMD_INVALID, "Tearing can only be allowed on views");
15 }
16
17 bool wants_tearing = parse_boolean(argv[0], true);
18
19 struct sway_view *view = container->view;
20 view->tearing_mode = wants_tearing ? TEARING_OVERRIDE_TRUE :
21 TEARING_OVERRIDE_FALSE;
22
23 return cmd_results_new(CMD_SUCCESS, NULL);
24}
diff --git a/sway/commands/output.c b/sway/commands/output.c
index b822e770..9478e0ba 100644
--- a/sway/commands/output.c
+++ b/sway/commands/output.c
@@ -8,6 +8,7 @@
8// must be in order for the bsearch 8// must be in order for the bsearch
9static const struct cmd_handler output_handlers[] = { 9static const struct cmd_handler output_handlers[] = {
10 { "adaptive_sync", output_cmd_adaptive_sync }, 10 { "adaptive_sync", output_cmd_adaptive_sync },
11 { "allow_tearing", output_cmd_allow_tearing },
11 { "background", output_cmd_background }, 12 { "background", output_cmd_background },
12 { "bg", output_cmd_background }, 13 { "bg", output_cmd_background },
13 { "color_profile", output_cmd_color_profile }, 14 { "color_profile", output_cmd_color_profile },
diff --git a/sway/commands/output/allow_tearing.c b/sway/commands/output/allow_tearing.c
new file mode 100644
index 00000000..9a183b96
--- /dev/null
+++ b/sway/commands/output/allow_tearing.c
@@ -0,0 +1,23 @@
1#include "sway/commands.h"
2#include "sway/config.h"
3#include "util.h"
4
5struct cmd_results *output_cmd_allow_tearing(int argc, char **argv) {
6 if (!config->handler_context.output_config) {
7 return cmd_results_new(CMD_FAILURE, "Missing output config");
8 }
9 if (argc == 0) {
10 return cmd_results_new(CMD_INVALID, "Missing allow_tearing argument");
11 }
12
13 if (parse_boolean(argv[0],
14 (config->handler_context.output_config->allow_tearing == 1))) {
15 config->handler_context.output_config->allow_tearing = 1;
16 } else {
17 config->handler_context.output_config->allow_tearing = 0;
18 }
19
20 config->handler_context.leftovers.argc = argc - 1;
21 config->handler_context.leftovers.argv = argv + 1;
22 return NULL;
23}
diff --git a/sway/config/output.c b/sway/config/output.c
index e64efb7f..940c75fe 100644
--- a/sway/config/output.c
+++ b/sway/config/output.c
@@ -79,6 +79,7 @@ struct output_config *new_output_config(const char *name) {
79 oc->set_color_transform = false; 79 oc->set_color_transform = false;
80 oc->color_transform = NULL; 80 oc->color_transform = NULL;
81 oc->power = -1; 81 oc->power = -1;
82 oc->allow_tearing = -1;
82 return oc; 83 return oc;
83} 84}
84 85
@@ -216,6 +217,9 @@ static void merge_output_config(struct output_config *dst, struct output_config
216 if (src->power != -1) { 217 if (src->power != -1) {
217 dst->power = src->power; 218 dst->power = src->power;
218 } 219 }
220 if (src->allow_tearing != -1) {
221 dst->allow_tearing = src->allow_tearing;
222 }
219} 223}
220 224
221void store_output_config(struct output_config *oc) { 225void store_output_config(struct output_config *oc) {
@@ -258,11 +262,11 @@ void store_output_config(struct output_config *oc) {
258 262
259 sway_log(SWAY_DEBUG, "Config stored for output %s (enabled: %d) (%dx%d@%fHz " 263 sway_log(SWAY_DEBUG, "Config stored for output %s (enabled: %d) (%dx%d@%fHz "
260 "position %d,%d scale %f subpixel %s transform %d) (bg %s %s) (power %d) " 264 "position %d,%d scale %f subpixel %s transform %d) (bg %s %s) (power %d) "
261 "(max render time: %d)", 265 "(max render time: %d) (allow tearing: %d)",
262 oc->name, oc->enabled, oc->width, oc->height, oc->refresh_rate, 266 oc->name, oc->enabled, oc->width, oc->height, oc->refresh_rate,
263 oc->x, oc->y, oc->scale, sway_wl_output_subpixel_to_string(oc->subpixel), 267 oc->x, oc->y, oc->scale, sway_wl_output_subpixel_to_string(oc->subpixel),
264 oc->transform, oc->background, oc->background_option, oc->power, 268 oc->transform, oc->background, oc->background_option, oc->power,
265 oc->max_render_time); 269 oc->max_render_time, oc->allow_tearing);
266 270
267 // If the configuration was not merged into an existing configuration, add 271 // If the configuration was not merged into an existing configuration, add
268 // it to the list. Otherwise we're done with it and can free it. 272 // it to the list. Otherwise we're done with it and can free it.
@@ -574,6 +578,13 @@ static bool finalize_output_config(struct output_config *oc, struct sway_output
574 wlr_color_transform_unref(output->color_transform); 578 wlr_color_transform_unref(output->color_transform);
575 output->color_transform = oc->color_transform; 579 output->color_transform = oc->color_transform;
576 } 580 }
581
582 if (oc && oc->allow_tearing >= 0) {
583 sway_log(SWAY_DEBUG, "Set %s allow tearing to %d",
584 oc->name, oc->allow_tearing);
585 output->allow_tearing = oc->allow_tearing;
586 }
587
577 return true; 588 return true;
578} 589}
579 590
@@ -594,6 +605,7 @@ static void default_output_config(struct output_config *oc,
594 oc->subpixel = output->detected_subpixel; 605 oc->subpixel = output->detected_subpixel;
595 oc->transform = WL_OUTPUT_TRANSFORM_NORMAL; 606 oc->transform = WL_OUTPUT_TRANSFORM_NORMAL;
596 oc->max_render_time = 0; 607 oc->max_render_time = 0;
608 oc->allow_tearing = 0;
597} 609}
598 610
599// find_output_config returns a merged output_config containing all stored 611// find_output_config returns a merged output_config containing all stored
diff --git a/sway/desktop/output.c b/sway/desktop/output.c
index 27ede68e..f1e08eff 100644
--- a/sway/desktop/output.c
+++ b/sway/desktop/output.c
@@ -232,6 +232,23 @@ static void output_configure_scene(struct sway_output *output,
232 } 232 }
233} 233}
234 234
235static bool output_can_tear(struct sway_output *output) {
236 struct sway_workspace *workspace = output->current.active_workspace;
237 if (!workspace) {
238 return false;
239 }
240
241 struct sway_container *fullscreen_con = root->fullscreen_global;
242 if (!fullscreen_con) {
243 fullscreen_con = workspace->current.fullscreen;
244 }
245 if (fullscreen_con && fullscreen_con->view) {
246 return (output->allow_tearing && view_can_tear(fullscreen_con->view));
247 }
248
249 return false;
250}
251
235static int output_repaint_timer_handler(void *data) { 252static int output_repaint_timer_handler(void *data) {
236 struct sway_output *output = data; 253 struct sway_output *output = data;
237 254
@@ -275,6 +292,17 @@ static int output_repaint_timer_handler(void *data) {
275 wlr_output_state_set_gamma_lut(&pending, 0, NULL, NULL, NULL); 292 wlr_output_state_set_gamma_lut(&pending, 0, NULL, NULL, NULL);
276 } 293 }
277 } 294 }
295
296 if (output_can_tear(output)) {
297 pending.tearing_page_flip = true;
298
299 if (!wlr_output_test_state(output->wlr_output, &pending)) {
300 sway_log(SWAY_DEBUG, "Output test failed on '%s', retrying without tearing page-flip",
301 output->wlr_output->name);
302
303 pending.tearing_page_flip = false;
304 }
305 }
278 306
279 if (!wlr_output_commit_state(output->wlr_output, &pending)) { 307 if (!wlr_output_commit_state(output->wlr_output, &pending)) {
280 sway_log(SWAY_ERROR, "Page-flip failed on output %s", output->wlr_output->name); 308 sway_log(SWAY_ERROR, "Page-flip failed on output %s", output->wlr_output->name);
diff --git a/sway/desktop/tearing.c b/sway/desktop/tearing.c
new file mode 100644
index 00000000..36cc48bf
--- /dev/null
+++ b/sway/desktop/tearing.c
@@ -0,0 +1,62 @@
1#include <wayland-server-core.h>
2#include <wlr/types/wlr_tearing_control_v1.h>
3#include "sway/server.h"
4#include "sway/tree/view.h"
5#include "sway/output.h"
6#include "log.h"
7
8struct sway_tearing_controller {
9 struct wlr_tearing_control_v1 *tearing_control;
10 struct wl_listener set_hint;
11 struct wl_listener destroy;
12
13 struct wl_list link; // sway_server::tearing_controllers
14};
15
16static void handle_tearing_controller_set_hint(struct wl_listener *listener,
17 void *data) {
18 struct sway_tearing_controller *controller =
19 wl_container_of(listener, controller, set_hint);
20
21 struct sway_view *view = view_from_wlr_surface(
22 controller->tearing_control->surface);
23 if (view) {
24 view->tearing_hint = controller->tearing_control->current;
25 }
26}
27
28static void handle_tearing_controller_destroy(struct wl_listener *listener,
29 void *data) {
30 struct sway_tearing_controller *controller =
31 wl_container_of(listener, controller, destroy);
32 wl_list_remove(&controller->link);
33 free(controller);
34}
35
36void handle_new_tearing_hint(struct wl_listener *listener,
37 void *data) {
38 struct sway_server *server =
39 wl_container_of(listener, server, tearing_control_new_object);
40 struct wlr_tearing_control_v1 *tearing_control = data;
41
42 enum wp_tearing_control_v1_presentation_hint hint =
43 wlr_tearing_control_manager_v1_surface_hint_from_surface(
44 server->tearing_control_v1, tearing_control->surface);
45 sway_log(SWAY_DEBUG, "New presentation hint %d received for surface %p",
46 hint, tearing_control->surface);
47
48 struct sway_tearing_controller *controller =
49 calloc(1, sizeof(struct sway_tearing_controller));
50 if (!controller) {
51 return;
52 }
53
54 controller->tearing_control = tearing_control;
55 controller->set_hint.notify = handle_tearing_controller_set_hint;
56 wl_signal_add(&tearing_control->events.set_hint, &controller->set_hint);
57 controller->destroy.notify = handle_tearing_controller_destroy;
58 wl_signal_add(&tearing_control->events.destroy, &controller->destroy);
59 wl_list_init(&controller->link);
60
61 wl_list_insert(&server->tearing_controllers, &controller->link);
62}
diff --git a/sway/ipc-json.c b/sway/ipc-json.c
index e512a223..8eaa8324 100644
--- a/sway/ipc-json.c
+++ b/sway/ipc-json.c
@@ -399,6 +399,8 @@ static void ipc_json_describe_enabled_output(struct sway_output *output,
399 } 399 }
400 400
401 json_object_object_add(object, "max_render_time", json_object_new_int(output->max_render_time)); 401 json_object_object_add(object, "max_render_time", json_object_new_int(output->max_render_time));
402
403 json_object_object_add(object, "allow_tearing", json_object_new_boolean(output->allow_tearing));
402} 404}
403 405
404json_object *ipc_json_describe_disabled_output(struct sway_output *output) { 406json_object *ipc_json_describe_disabled_output(struct sway_output *output) {
@@ -593,6 +595,8 @@ static void ipc_json_describe_view(struct sway_container *c, json_object *object
593 595
594 json_object_object_add(object, "max_render_time", json_object_new_int(c->view->max_render_time)); 596 json_object_object_add(object, "max_render_time", json_object_new_int(c->view->max_render_time));
595 597
598 json_object_object_add(object, "allow_tearing", json_object_new_boolean(view_can_tear(c->view)));
599
596 json_object_object_add(object, "shell", json_object_new_string(view_get_shell(c->view))); 600 json_object_object_add(object, "shell", json_object_new_string(view_get_shell(c->view)));
597 601
598 json_object_object_add(object, "inhibit_idle", 602 json_object_object_add(object, "inhibit_idle",
diff --git a/sway/meson.build b/sway/meson.build
index 2f4406ab..8042c89b 100644
--- a/sway/meson.build
+++ b/sway/meson.build
@@ -18,6 +18,7 @@ sway_sources = files(
18 'desktop/idle_inhibit_v1.c', 18 'desktop/idle_inhibit_v1.c',
19 'desktop/layer_shell.c', 19 'desktop/layer_shell.c',
20 'desktop/output.c', 20 'desktop/output.c',
21 'desktop/tearing.c',
21 'desktop/transaction.c', 22 'desktop/transaction.c',
22 'desktop/xdg_shell.c', 23 'desktop/xdg_shell.c',
23 'desktop/launcher.c', 24 'desktop/launcher.c',
@@ -41,6 +42,7 @@ sway_sources = files(
41 'config/seat.c', 42 'config/seat.c',
42 'config/input.c', 43 'config/input.c',
43 44
45 'commands/allow_tearing.c',
44 'commands/assign.c', 46 'commands/assign.c',
45 'commands/bar.c', 47 'commands/bar.c',
46 'commands/bind.c', 48 'commands/bind.c',
@@ -188,6 +190,7 @@ sway_sources = files(
188 'commands/input/xkb_variant.c', 190 'commands/input/xkb_variant.c',
189 191
190 'commands/output/adaptive_sync.c', 192 'commands/output/adaptive_sync.c',
193 'commands/output/allow_tearing.c',
191 'commands/output/background.c', 194 'commands/output/background.c',
192 'commands/output/disable.c', 195 'commands/output/disable.c',
193 'commands/output/dpms.c', 196 'commands/output/dpms.c',
diff --git a/sway/server.c b/sway/server.c
index edbc1a4b..bb895377 100644
--- a/sway/server.c
+++ b/sway/server.c
@@ -371,6 +371,13 @@ bool server_init(struct sway_server *server) {
371 server->content_type_manager_v1 = 371 server->content_type_manager_v1 =
372 wlr_content_type_manager_v1_create(server->wl_display, 1); 372 wlr_content_type_manager_v1_create(server->wl_display, 1);
373 wlr_fractional_scale_manager_v1_create(server->wl_display, 1); 373 wlr_fractional_scale_manager_v1_create(server->wl_display, 1);
374
375 server->tearing_control_v1 =
376 wlr_tearing_control_manager_v1_create(server->wl_display, 1);
377 server->tearing_control_new_object.notify = handle_new_tearing_hint;
378 wl_signal_add(&server->tearing_control_v1->events.new_object,
379 &server->tearing_control_new_object);
380 wl_list_init(&server->tearing_controllers);
374 381
375 struct wlr_xdg_foreign_registry *foreign_registry = 382 struct wlr_xdg_foreign_registry *foreign_registry =
376 wlr_xdg_foreign_registry_create(server->wl_display); 383 wlr_xdg_foreign_registry_create(server->wl_display);
diff --git a/sway/sway-output.5.scd b/sway/sway-output.5.scd
index 6d7c0860..d9a28807 100644
--- a/sway/sway-output.5.scd
+++ b/sway/sway-output.5.scd
@@ -190,6 +190,26 @@ must be separated by one space. For example:
190 may have no effect or produce unexpected output when used together with future 190 may have no effect or produce unexpected output when used together with future
191 HDR support features. 191 HDR support features.
192 192
193*output* <name> allow_tearing yes|no
194 Allows or disallows screen tearing as a result of immediate page flips,
195 and an immediate presentation mode from a client. The default is that no
196 screen tearing is allowed.
197
198 With immediate page flips, frames from the client are presented as soon
199 as possible instead of synchronizing with the monitor's vblank interval
200 (VSync).
201
202 It is recommended to set *max_render_time* to *off*. In that case a page flip
203 happens as soon as a client updates. Otherwise, tearing will only happen if
204 rendering takes longer than the configured milliseconds before the next
205 display refresh.
206
207 To adjust whether tearing is allowed for specific applications, see
208 *allow_tearing* in *sway*(5). Note that tearing will only be enabled
209 when it's allowed for both the output and the application.
210
211 This setting only has effect when a window is fullscreen on the output.
212
193# SEE ALSO 213# SEE ALSO
194 214
195*sway*(5) *sway-input*(5) 215*sway*(5) *sway-input*(5)
diff --git a/sway/sway.5.scd b/sway/sway.5.scd
index 9f823947..0b36a757 100644
--- a/sway/sway.5.scd
+++ b/sway/sway.5.scd
@@ -215,6 +215,20 @@ set|plus|minus|toggle <amount>
215 effect on the output the window is currently on. See *sway-output*(5) for 215 effect on the output the window is currently on. See *sway-output*(5) for
216 further details. 216 further details.
217 217
218*allow_tearing* yes|no
219 Allows or disallows screen tearing as a result of immediate page flips
220 for a fullscreen application.
221
222 When this option is not set, the tearing hints provided by the application
223 determine whether tearing is allowed. When _yes_ is specified,
224 the application allows tearing regardless of the tearing hints.
225 When _no_ is specified, tearing will never be allowed on the application,
226 regardless of the tearing hints.
227
228 This setting only has an effect if tearing is allowed on the output through
229 the per-output *allow_tearing* setting. See *sway-output*(5)
230 for further details.
231
218*move* left|right|up|down [<px> px] 232*move* left|right|up|down [<px> px]
219 Moves the focused container in the direction specified. The optional _px_ 233 Moves the focused container in the direction specified. The optional _px_
220 argument specifies how many pixels to move the container. If unspecified, 234 argument specifies how many pixels to move the container. If unspecified,
diff --git a/sway/tree/view.c b/sway/tree/view.c
index 4f757acf..84a25f9c 100644
--- a/sway/tree/view.c
+++ b/sway/tree/view.c
@@ -58,6 +58,7 @@ bool view_init(struct sway_view *view, enum sway_view_type type,
58 view->executed_criteria = create_list(); 58 view->executed_criteria = create_list();
59 view->allow_request_urgent = true; 59 view->allow_request_urgent = true;
60 view->shortcuts_inhibit = SHORTCUTS_INHIBIT_DEFAULT; 60 view->shortcuts_inhibit = SHORTCUTS_INHIBIT_DEFAULT;
61 view->tearing_mode = TEARING_WINDOW_HINT;
61 wl_signal_init(&view->events.unmap); 62 wl_signal_init(&view->events.unmap);
62 return true; 63 return true;
63} 64}
@@ -1260,6 +1261,19 @@ bool view_is_transient_for(struct sway_view *child,
1260 child->impl->is_transient_for(child, ancestor); 1261 child->impl->is_transient_for(child, ancestor);
1261} 1262}
1262 1263
1264bool view_can_tear(struct sway_view *view) {
1265 switch (view->tearing_mode) {
1266 case TEARING_OVERRIDE_FALSE:
1267 return false;
1268 case TEARING_OVERRIDE_TRUE:
1269 return true;
1270 case TEARING_WINDOW_HINT:
1271 return view->tearing_hint ==
1272 WP_TEARING_CONTROL_V1_PRESENTATION_HINT_ASYNC;
1273 }
1274 return false;
1275}
1276
1263static void send_frame_done_iterator(struct wlr_scene_buffer *scene_buffer, 1277static void send_frame_done_iterator(struct wlr_scene_buffer *scene_buffer,
1264 int x, int y, void *data) { 1278 int x, int y, void *data) {
1265 struct timespec *when = data; 1279 struct timespec *when = data;
diff --git a/swaymsg/main.c b/swaymsg/main.c
index 573a7b16..5c57171e 100644
--- a/swaymsg/main.c
+++ b/swaymsg/main.c
@@ -193,7 +193,7 @@ static void pretty_print_output(json_object *o) {
193 json_object_object_get_ex(o, "current_workspace", &ws); 193 json_object_object_get_ex(o, "current_workspace", &ws);
194 json_object_object_get_ex(o, "non_desktop", &non_desktop); 194 json_object_object_get_ex(o, "non_desktop", &non_desktop);
195 json_object *make, *model, *serial, *scale, *scale_filter, *subpixel, 195 json_object *make, *model, *serial, *scale, *scale_filter, *subpixel,
196 *transform, *max_render_time, *adaptive_sync_status; 196 *transform, *max_render_time, *adaptive_sync_status, *allow_tearing;
197 json_object_object_get_ex(o, "make", &make); 197 json_object_object_get_ex(o, "make", &make);
198 json_object_object_get_ex(o, "model", &model); 198 json_object_object_get_ex(o, "model", &model);
199 json_object_object_get_ex(o, "serial", &serial); 199 json_object_object_get_ex(o, "serial", &serial);
@@ -203,6 +203,7 @@ static void pretty_print_output(json_object *o) {
203 json_object_object_get_ex(o, "transform", &transform); 203 json_object_object_get_ex(o, "transform", &transform);
204 json_object_object_get_ex(o, "max_render_time", &max_render_time); 204 json_object_object_get_ex(o, "max_render_time", &max_render_time);
205 json_object_object_get_ex(o, "adaptive_sync_status", &adaptive_sync_status); 205 json_object_object_get_ex(o, "adaptive_sync_status", &adaptive_sync_status);
206 json_object_object_get_ex(o, "allow_tearing", &allow_tearing);
206 json_object *x, *y; 207 json_object *x, *y;
207 json_object_object_get_ex(rect, "x", &x); 208 json_object_object_get_ex(rect, "x", &x);
208 json_object_object_get_ex(rect, "y", &y); 209 json_object_object_get_ex(rect, "y", &y);
@@ -256,6 +257,9 @@ static void pretty_print_output(json_object *o) {
256 257
257 printf(" Adaptive sync: %s\n", 258 printf(" Adaptive sync: %s\n",
258 json_object_get_string(adaptive_sync_status)); 259 json_object_get_string(adaptive_sync_status));
260
261 printf(" Allow tearing: %s\n",
262 json_object_get_boolean(allow_tearing) ? "yes" : "no");
259 } else { 263 } else {
260 printf( 264 printf(
261 "Output %s '%s %s %s' (disabled)\n", 265 "Output %s '%s %s %s' (disabled)\n",