mirror of
				https://github.com/swaywm/sway.git
				synced 2025-11-03 09:01:43 -05:00 
			
		
		
		
	Compare commits
	
		
			62 commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
							 | 
						dc8f5338be | ||
| 
							 | 
						d262a241cc | ||
| 
							 | 
						91be6e8a09 | ||
| 
							 | 
						63005491cf | ||
| 
							 | 
						67ecc7d2cd | ||
| 
							 | 
						0de35b3585 | ||
| 
							 | 
						703671a12d | ||
| 
							 | 
						ae75fea8ef | ||
| 
							 | 
						872cf451a1 | ||
| 
							 | 
						1311685d1c | ||
| 
							 | 
						75cfed65bb | ||
| 
							 | 
						4ea5a9cee1 | ||
| 
							 | 
						4aa71ca661 | ||
| 
							 | 
						952c428482 | ||
| 
							 | 
						0299e0412a | ||
| 
							 | 
						7f9baa05fa | ||
| 
							 | 
						5686be82c6 | ||
| 
							 | 
						a9c295fd67 | ||
| 
							 | 
						3b27392a47 | ||
| 
							 | 
						5664103902 | ||
| 
							 | 
						af86879462 | ||
| 
							 | 
						2879260f79 | ||
| 
							 | 
						b7be9de2be | ||
| 
							 | 
						c580b54b5e | ||
| 
							 | 
						6baee5cb68 | ||
| 
							 | 
						fa96c64e24 | ||
| 
							 | 
						2f1db190c6 | ||
| 
							 | 
						307ab531c0 | ||
| 
							 | 
						9d667383b4 | ||
| 
							 | 
						bb666f2ac9 | ||
| 
							 | 
						af782c17bb | ||
| 
							 | 
						5a920c48d1 | ||
| 
							 | 
						b4d550bff8 | ||
| 
							 | 
						4cca004583 | ||
| 
							 | 
						a8b6d02868 | ||
| 
							 | 
						12796fb0b3 | ||
| 
							 | 
						3264696469 | ||
| 
							 | 
						6835cbd046 | ||
| 
							 | 
						24fafa9490 | ||
| 
							 | 
						559f9eba33 | ||
| 
							 | 
						31ce4ea53d | ||
| 
							 | 
						7246bf909c | ||
| 
							 | 
						d2fceae379 | ||
| 
							 | 
						401a84bf21 | ||
| 
							 | 
						9cdd57a032 | ||
| 
							 | 
						a4927e4cb2 | ||
| 
							 | 
						b1c2155a8e | ||
| 
							 | 
						234f18d357 | ||
| 
							 | 
						d100835485 | ||
| 
							 | 
						fb0f2add19 | ||
| 
							 | 
						3fba40da50 | ||
| 
							 | 
						e6c3612b72 | ||
| 
							 | 
						04943bc6ac | ||
| 
							 | 
						fa4912b1f9 | ||
| 
							 | 
						01f5c50438 | ||
| 
							 | 
						b4ab8182b7 | ||
| 
							 | 
						8b923a3623 | ||
| 
							 | 
						53ffc1119a | ||
| 
							 | 
						100f92a189 | ||
| 
							 | 
						19ca790a9f | ||
| 
							 | 
						6320aef295 | ||
| 
							 | 
						1c992d847d | 
					 56 changed files with 919 additions and 513 deletions
				
			
		| 
						 | 
					@ -25,7 +25,7 @@ packages:
 | 
				
			||||||
  - hwdata-dev
 | 
					  - hwdata-dev
 | 
				
			||||||
sources:
 | 
					sources:
 | 
				
			||||||
  - https://github.com/swaywm/sway
 | 
					  - https://github.com/swaywm/sway
 | 
				
			||||||
  - https://gitlab.freedesktop.org/wlroots/wlroots.git
 | 
					  - https://gitlab.freedesktop.org/wlroots/wlroots.git#0.18
 | 
				
			||||||
tasks:
 | 
					tasks:
 | 
				
			||||||
  - wlroots: |
 | 
					  - wlroots: |
 | 
				
			||||||
      cd wlroots
 | 
					      cd wlroots
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -22,7 +22,7 @@ packages:
 | 
				
			||||||
  - hwdata
 | 
					  - hwdata
 | 
				
			||||||
sources:
 | 
					sources:
 | 
				
			||||||
  - https://github.com/swaywm/sway
 | 
					  - https://github.com/swaywm/sway
 | 
				
			||||||
  - https://gitlab.freedesktop.org/wlroots/wlroots.git
 | 
					  - https://gitlab.freedesktop.org/wlroots/wlroots.git#0.18
 | 
				
			||||||
tasks:
 | 
					tasks:
 | 
				
			||||||
  - wlroots: |
 | 
					  - wlroots: |
 | 
				
			||||||
      cd wlroots
 | 
					      cd wlroots
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -27,11 +27,11 @@ packages:
 | 
				
			||||||
- x11/libX11
 | 
					- x11/libX11
 | 
				
			||||||
- x11/pixman
 | 
					- x11/pixman
 | 
				
			||||||
- x11/xcb-util-wm
 | 
					- x11/xcb-util-wm
 | 
				
			||||||
- x11-servers/xwayland-devel
 | 
					- x11-servers/xwayland
 | 
				
			||||||
- misc/hwdata
 | 
					- misc/hwdata
 | 
				
			||||||
sources:
 | 
					sources:
 | 
				
			||||||
- https://github.com/swaywm/sway
 | 
					- https://github.com/swaywm/sway
 | 
				
			||||||
- https://gitlab.freedesktop.org/wlroots/wlroots.git
 | 
					- https://gitlab.freedesktop.org/wlroots/wlroots.git#0.18
 | 
				
			||||||
tasks:
 | 
					tasks:
 | 
				
			||||||
- setup: |
 | 
					- setup: |
 | 
				
			||||||
    cd sway
 | 
					    cd sway
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										11
									
								
								README.cs.md
									
										
									
									
									
								
							
							
						
						
									
										11
									
								
								README.cs.md
									
										
									
									
									
								
							| 
						 | 
					@ -1,6 +1,6 @@
 | 
				
			||||||
# sway
 | 
					# sway
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[English][en] - **[Česky][cs]** - [Deutsch][de] - [Dansk][dk] - [Español][es] - [Français][fr] - [Svenska][sv] - [Ελληνικά][gr] - [हिन्दी][hi] - [Magyar][hu] - [فارسی][ir] - [Italiano][it] - [日本語][ja] - [한국어][ko] - [Nederlands][nl] - [Polski][pl] - [Português][pt] - [Română][ro] - [Русский][ru] - [Türkçe][tr] - [Українська][uk] - [中文-简体][zh-CN] - [中文-繁體][zh-TW]
 | 
					[English][en] - [عربي][ar] - **[Česky][cs]** - [Deutsch][de] - [Dansk][dk] - [Español][es] - [Français][fr] - [ქართული][ge] - [Ελληνικά][gr] - [हिन्दी][hi] - [Magyar][hu] - [فارسی][ir] - [Italiano][it] - [日本語][ja] - [한국어][ko] - [Nederlands][nl] - [Norsk][no] - [Polski][pl] - [Português][pt] - [Română][ro] - [Русский][ru] - [Svenska][sv] - [Türkçe][tr] - [Українська][uk] - [中文-简体][zh-CN] - [中文-繁體][zh-TW]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
sway je s [i3] kompatibilní [Wayland] kompozitor. Přečtěte si [FAQ]. Připojte se na
 | 
					sway je s [i3] kompatibilní [Wayland] kompozitor. Přečtěte si [FAQ]. Připojte se na
 | 
				
			||||||
[IRC kanál][IRC channel] \(#sway na irc.libera.chat).
 | 
					[IRC kanál][IRC channel] \(#sway na irc.libera.chat).
 | 
				
			||||||
| 
						 | 
					@ -32,10 +32,11 @@ Nainstalujte závislosti:
 | 
				
			||||||
* pango
 | 
					* pango
 | 
				
			||||||
* cairo
 | 
					* cairo
 | 
				
			||||||
* gdk-pixbuf2 (volitelné: oznamovací oblast)
 | 
					* gdk-pixbuf2 (volitelné: oznamovací oblast)
 | 
				
			||||||
 | 
					* [swaybg] (volitelné: tapeta)
 | 
				
			||||||
* [scdoc] (volitelné: manuálové stránky) \*
 | 
					* [scdoc] (volitelné: manuálové stránky) \*
 | 
				
			||||||
* git (volitelné: informace o verzi) \*
 | 
					* git (volitelné: informace o verzi) \*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
_\* Závislost pouze pro sestavení_
 | 
					_\* Závislost pouze pro kompilaci_
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Spusťte tyto příkazy:
 | 
					Spusťte tyto příkazy:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -56,12 +57,13 @@ Spusťte `sway` z TTY. Některé správce zobrazení mohou fungovat, ale nejsou
 | 
				
			||||||
podporovány sway (je známo, že gdm funguje docela dobře).
 | 
					podporovány sway (je známo, že gdm funguje docela dobře).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[en]: https://github.com/swaywm/sway#readme
 | 
					[en]: https://github.com/swaywm/sway#readme
 | 
				
			||||||
 | 
					[ar]: README.ar.md
 | 
				
			||||||
[cs]: README.cs.md
 | 
					[cs]: README.cs.md
 | 
				
			||||||
[de]: README.de.md
 | 
					[de]: README.de.md
 | 
				
			||||||
[dk]: README.dk.md
 | 
					[dk]: README.dk.md
 | 
				
			||||||
[es]: README.es.md
 | 
					[es]: README.es.md
 | 
				
			||||||
[fr]: README.fr.md
 | 
					[fr]: README.fr.md
 | 
				
			||||||
[sv]: README.sv.md
 | 
					[ge]: README.ge.md
 | 
				
			||||||
[gr]: README.gr.md
 | 
					[gr]: README.gr.md
 | 
				
			||||||
[hi]: README.hi.md
 | 
					[hi]: README.hi.md
 | 
				
			||||||
[hu]: README.hu.md
 | 
					[hu]: README.hu.md
 | 
				
			||||||
| 
						 | 
					@ -70,10 +72,12 @@ podporovány sway (je známo, že gdm funguje docela dobře).
 | 
				
			||||||
[ja]: README.ja.md
 | 
					[ja]: README.ja.md
 | 
				
			||||||
[ko]: README.ko.md
 | 
					[ko]: README.ko.md
 | 
				
			||||||
[nl]: README.nl.md
 | 
					[nl]: README.nl.md
 | 
				
			||||||
 | 
					[no]: README.no.md
 | 
				
			||||||
[pl]: README.pl.md
 | 
					[pl]: README.pl.md
 | 
				
			||||||
[pt]: README.pt.md
 | 
					[pt]: README.pt.md
 | 
				
			||||||
[ro]: README.ro.md
 | 
					[ro]: README.ro.md
 | 
				
			||||||
[ru]: README.ru.md
 | 
					[ru]: README.ru.md
 | 
				
			||||||
 | 
					[sv]: README.sv.md
 | 
				
			||||||
[tr]: README.tr.md
 | 
					[tr]: README.tr.md
 | 
				
			||||||
[uk]: README.uk.md
 | 
					[uk]: README.uk.md
 | 
				
			||||||
[zh-CN]: README.zh-CN.md
 | 
					[zh-CN]: README.zh-CN.md
 | 
				
			||||||
| 
						 | 
					@ -86,4 +90,5 @@ podporovány sway (je známo, že gdm funguje docela dobře).
 | 
				
			||||||
[GitHub releases]: https://github.com/swaywm/sway/releases
 | 
					[GitHub releases]: https://github.com/swaywm/sway/releases
 | 
				
			||||||
[Development setup]: https://github.com/swaywm/sway/wiki/Development-Setup
 | 
					[Development setup]: https://github.com/swaywm/sway/wiki/Development-Setup
 | 
				
			||||||
[wlroots]: https://gitlab.freedesktop.org/wlroots/wlroots
 | 
					[wlroots]: https://gitlab.freedesktop.org/wlroots/wlroots
 | 
				
			||||||
 | 
					[swaybg]: https://github.com/swaywm/swaybg/
 | 
				
			||||||
[scdoc]: https://git.sr.ht/~sircmpwn/scdoc
 | 
					[scdoc]: https://git.sr.ht/~sircmpwn/scdoc
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										17
									
								
								config.in
									
										
									
									
									
								
							
							
						
						
									
										17
									
								
								config.in
									
										
									
									
									
								
							| 
						 | 
					@ -16,9 +16,7 @@ set $right l
 | 
				
			||||||
# Your preferred terminal emulator
 | 
					# Your preferred terminal emulator
 | 
				
			||||||
set $term foot
 | 
					set $term foot
 | 
				
			||||||
# Your preferred application launcher
 | 
					# Your preferred application launcher
 | 
				
			||||||
# Note: pass the final command to swaymsg so that the resulting window can be opened
 | 
					set $menu wmenu-run
 | 
				
			||||||
# on the original workspace that the command was run on.
 | 
					 | 
				
			||||||
set $menu dmenu_path | wmenu | xargs swaymsg exec --
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Output configuration
 | 
					### Output configuration
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
| 
						 | 
					@ -195,6 +193,19 @@ mode "resize" {
 | 
				
			||||||
    bindsym Escape mode "default"
 | 
					    bindsym Escape mode "default"
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
bindsym $mod+r mode "resize"
 | 
					bindsym $mod+r mode "resize"
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Utilities:
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					    # Special keys to adjust volume via PulseAudio
 | 
				
			||||||
 | 
					    bindsym --locked XF86AudioMute exec pactl set-sink-mute \@DEFAULT_SINK@ toggle
 | 
				
			||||||
 | 
					    bindsym --locked XF86AudioLowerVolume exec pactl set-sink-volume \@DEFAULT_SINK@ -5%
 | 
				
			||||||
 | 
					    bindsym --locked XF86AudioRaiseVolume exec pactl set-sink-volume \@DEFAULT_SINK@ +5%
 | 
				
			||||||
 | 
					    bindsym --locked XF86AudioMicMute exec pactl set-source-mute \@DEFAULT_SOURCE@ toggle
 | 
				
			||||||
 | 
					    # Special keys to adjust brightness via brightnessctl
 | 
				
			||||||
 | 
					    bindsym --locked XF86MonBrightnessDown exec brightnessctl set 5%-
 | 
				
			||||||
 | 
					    bindsym --locked XF86MonBrightnessUp exec brightnessctl set 5%+
 | 
				
			||||||
 | 
					    # Special key to take a screenshot with grim
 | 
				
			||||||
 | 
					    bindsym Print exec grim
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
# Status Bar:
 | 
					# Status Bar:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -104,6 +104,7 @@ struct sway_container *container_find_resize_parent(struct sway_container *con,
 | 
				
			||||||
sway_cmd cmd_exec_validate;
 | 
					sway_cmd cmd_exec_validate;
 | 
				
			||||||
sway_cmd cmd_exec_process;
 | 
					sway_cmd cmd_exec_process;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					sway_cmd cmd_allow_tearing;
 | 
				
			||||||
sway_cmd cmd_assign;
 | 
					sway_cmd cmd_assign;
 | 
				
			||||||
sway_cmd cmd_bar;
 | 
					sway_cmd cmd_bar;
 | 
				
			||||||
sway_cmd cmd_bindcode;
 | 
					sway_cmd cmd_bindcode;
 | 
				
			||||||
| 
						 | 
					@ -283,6 +284,7 @@ sway_cmd input_cmd_xkb_switch_layout;
 | 
				
			||||||
sway_cmd input_cmd_xkb_variant;
 | 
					sway_cmd input_cmd_xkb_variant;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
sway_cmd output_cmd_adaptive_sync;
 | 
					sway_cmd output_cmd_adaptive_sync;
 | 
				
			||||||
 | 
					sway_cmd output_cmd_allow_tearing;
 | 
				
			||||||
sway_cmd output_cmd_background;
 | 
					sway_cmd output_cmd_background;
 | 
				
			||||||
sway_cmd output_cmd_color_profile;
 | 
					sway_cmd output_cmd_color_profile;
 | 
				
			||||||
sway_cmd output_cmd_disable;
 | 
					sway_cmd output_cmd_disable;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -262,6 +262,7 @@ enum scale_filter_mode {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum render_bit_depth {
 | 
					enum render_bit_depth {
 | 
				
			||||||
	RENDER_BIT_DEPTH_DEFAULT, // the default is currently 8
 | 
						RENDER_BIT_DEPTH_DEFAULT, // the default is currently 8
 | 
				
			||||||
 | 
						RENDER_BIT_DEPTH_6,
 | 
				
			||||||
	RENDER_BIT_DEPTH_8,
 | 
						RENDER_BIT_DEPTH_8,
 | 
				
			||||||
	RENDER_BIT_DEPTH_10,
 | 
						RENDER_BIT_DEPTH_10,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					@ -289,20 +290,13 @@ struct output_config {
 | 
				
			||||||
	enum render_bit_depth render_bit_depth;
 | 
						enum render_bit_depth render_bit_depth;
 | 
				
			||||||
	bool set_color_transform;
 | 
						bool set_color_transform;
 | 
				
			||||||
	struct wlr_color_transform *color_transform;
 | 
						struct wlr_color_transform *color_transform;
 | 
				
			||||||
 | 
						int allow_tearing;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	char *background;
 | 
						char *background;
 | 
				
			||||||
	char *background_option;
 | 
						char *background_option;
 | 
				
			||||||
	char *background_fallback;
 | 
						char *background_fallback;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * An output config pre-matched to an output
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
struct matched_output_config {
 | 
					 | 
				
			||||||
	struct sway_output *output;
 | 
					 | 
				
			||||||
	struct output_config *config;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Stores size of gaps for each side
 | 
					 * Stores size of gaps for each side
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
| 
						 | 
					@ -692,13 +686,10 @@ const char *sway_output_scale_filter_to_string(enum scale_filter_mode scale_filt
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct output_config *new_output_config(const char *name);
 | 
					struct output_config *new_output_config(const char *name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool apply_output_configs(struct matched_output_config *configs,
 | 
					bool apply_output_configs(struct output_config **ocs, size_t ocs_len,
 | 
				
			||||||
		size_t configs_len, bool test_only, bool degrade_to_off);
 | 
							bool test_only, bool degrade_to_off);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void apply_all_output_configs(void);
 | 
					void apply_stored_output_configs(void);
 | 
				
			||||||
 | 
					 | 
				
			||||||
void sort_output_configs_by_priority(struct matched_output_config *configs,
 | 
					 | 
				
			||||||
		size_t configs_len);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * store_output_config stores a new output config. An output may be matched by
 | 
					 * store_output_config stores a new output config. An output may be matched by
 | 
				
			||||||
| 
						 | 
					@ -713,6 +704,8 @@ struct output_config *find_output_config(struct sway_output *output);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void free_output_config(struct output_config *oc);
 | 
					void free_output_config(struct output_config *oc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void request_modeset(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool spawn_swaybg(void);
 | 
					bool spawn_swaybg(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int workspace_output_cmp_workspace(const void *a, const void *b);
 | 
					int workspace_output_cmp_workspace(const void *a, const void *b);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -9,11 +9,14 @@ struct sway_input_popup {
 | 
				
			||||||
	struct wlr_scene_tree *scene_tree;
 | 
						struct wlr_scene_tree *scene_tree;
 | 
				
			||||||
	struct sway_popup_desc desc;
 | 
						struct sway_popup_desc desc;
 | 
				
			||||||
	struct wlr_input_popup_surface_v2 *popup_surface;
 | 
						struct wlr_input_popup_surface_v2 *popup_surface;
 | 
				
			||||||
 | 
						struct wlr_output *fixed_output;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wl_list link;
 | 
						struct wl_list link;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wl_listener popup_destroy;
 | 
						struct wl_listener popup_destroy;
 | 
				
			||||||
	struct wl_listener popup_surface_commit;
 | 
						struct wl_listener popup_surface_commit;
 | 
				
			||||||
 | 
						struct wl_listener popup_surface_map;
 | 
				
			||||||
 | 
						struct wl_listener popup_surface_unmap;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wl_listener focused_surface_unmap;
 | 
						struct wl_listener focused_surface_unmap;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										6
									
								
								include/sway/lock.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								include/sway/lock.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,6 @@
 | 
				
			||||||
 | 
					#ifndef _SWAY_LOCK_H
 | 
				
			||||||
 | 
					#define _SWAY_LOCK_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void arrange_locks(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					@ -73,6 +73,7 @@ struct sway_output {
 | 
				
			||||||
	int max_render_time; // In milliseconds
 | 
						int max_render_time; // In milliseconds
 | 
				
			||||||
	struct wl_event_source *repaint_timer;
 | 
						struct wl_event_source *repaint_timer;
 | 
				
			||||||
	bool gamma_lut_changed;
 | 
						bool gamma_lut_changed;
 | 
				
			||||||
 | 
						bool allow_tearing;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct sway_output_non_desktop {
 | 
					struct sway_output_non_desktop {
 | 
				
			||||||
| 
						 | 
					@ -135,7 +136,6 @@ enum sway_container_layout output_get_default_layout(
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum wlr_direction opposite_direction(enum wlr_direction d);
 | 
					enum wlr_direction opposite_direction(enum wlr_direction d);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void handle_output_layout_change(struct wl_listener *listener, void *data);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
void handle_gamma_control_set_gamma(struct wl_listener *listener, void *data);
 | 
					void handle_gamma_control_set_gamma(struct wl_listener *listener, void *data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -148,4 +148,6 @@ void handle_output_power_manager_set_mode(struct wl_listener *listener,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct sway_output_non_desktop *output_non_desktop_create(struct wlr_output *wlr_output);
 | 
					struct sway_output_non_desktop *output_non_desktop_create(struct wlr_output *wlr_output);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void update_output_manager_config(struct sway_server *server);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -45,7 +45,6 @@ struct sway_server {
 | 
				
			||||||
	struct sway_input_manager *input;
 | 
						struct sway_input_manager *input;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wl_listener new_output;
 | 
						struct wl_listener new_output;
 | 
				
			||||||
	struct wl_listener output_layout_change;
 | 
					 | 
				
			||||||
	struct wl_listener renderer_lost;
 | 
						struct wl_listener renderer_lost;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wlr_idle_notifier_v1 *idle_notifier_v1;
 | 
						struct wlr_idle_notifier_v1 *idle_notifier_v1;
 | 
				
			||||||
| 
						 | 
					@ -116,6 +115,10 @@ struct sway_server {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wl_listener request_set_cursor_shape;
 | 
						struct wl_listener request_set_cursor_shape;
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
 | 
						struct wlr_tearing_control_manager_v1 *tearing_control_v1;
 | 
				
			||||||
 | 
						struct wl_listener tearing_control_new_object;
 | 
				
			||||||
 | 
						struct wl_list tearing_controllers; // sway_tearing_controller::link
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wl_list pending_launcher_ctxs; // launcher_ctx::link
 | 
						struct wl_list pending_launcher_ctxs; // launcher_ctx::link
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// The timeout for transactions, after which a transaction is applied
 | 
						// The timeout for transactions, after which a transaction is applied
 | 
				
			||||||
| 
						 | 
					@ -182,4 +185,6 @@ void xdg_activation_v1_handle_new_token(struct wl_listener *listener,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void set_rr_scheduling(void);
 | 
					void set_rr_scheduling(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void handle_new_tearing_hint(struct wl_listener *listener, void *data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -103,6 +103,8 @@ struct sway_container {
 | 
				
			||||||
	char *formatted_title; // The title displayed in the title bar
 | 
						char *formatted_title; // The title displayed in the title bar
 | 
				
			||||||
	int title_width;
 | 
						int title_width;
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
 | 
						char *title_format;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	enum sway_container_layout prev_split_layout;
 | 
						enum sway_container_layout prev_split_layout;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Whether stickiness has been enabled on this container. Use
 | 
						// Whether stickiness has been enabled on this container. Use
 | 
				
			||||||
| 
						 | 
					@ -183,6 +185,8 @@ void container_update_title_bar(struct sway_container *container);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void container_update_marks(struct sway_container *container);
 | 
					void container_update_marks(struct sway_container *container);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					size_t parse_title_format(struct sway_container *container, char *buffer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
size_t container_build_representation(enum sway_container_layout layout,
 | 
					size_t container_build_representation(enum sway_container_layout layout,
 | 
				
			||||||
		list_t *children, char *buffer);
 | 
							list_t *children, char *buffer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -16,8 +16,6 @@ struct sway_root {
 | 
				
			||||||
	struct sway_node node;
 | 
						struct sway_node node;
 | 
				
			||||||
	struct wlr_output_layout *output_layout;
 | 
						struct wlr_output_layout *output_layout;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wl_listener output_layout_change;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// scene node layout:
 | 
						// scene node layout:
 | 
				
			||||||
	// - root
 | 
						// - root
 | 
				
			||||||
	// 	- staging
 | 
						// 	- staging
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,6 +4,7 @@
 | 
				
			||||||
#include <wlr/config.h>
 | 
					#include <wlr/config.h>
 | 
				
			||||||
#include <wlr/types/wlr_compositor.h>
 | 
					#include <wlr/types/wlr_compositor.h>
 | 
				
			||||||
#include <wlr/types/wlr_scene.h>
 | 
					#include <wlr/types/wlr_scene.h>
 | 
				
			||||||
 | 
					#include <wlr/types/wlr_tearing_control_v1.h>
 | 
				
			||||||
#include "sway/config.h"
 | 
					#include "sway/config.h"
 | 
				
			||||||
#if WLR_HAS_XWAYLAND
 | 
					#if WLR_HAS_XWAYLAND
 | 
				
			||||||
#include <wlr/xwayland.h>
 | 
					#include <wlr/xwayland.h>
 | 
				
			||||||
| 
						 | 
					@ -34,6 +35,12 @@ enum sway_view_prop {
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum sway_view_tearing_mode {
 | 
				
			||||||
 | 
						TEARING_OVERRIDE_FALSE,
 | 
				
			||||||
 | 
						TEARING_OVERRIDE_TRUE,
 | 
				
			||||||
 | 
						TEARING_WINDOW_HINT,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct sway_view_impl {
 | 
					struct sway_view_impl {
 | 
				
			||||||
	void (*get_constraints)(struct sway_view *view, double *min_width,
 | 
						void (*get_constraints)(struct sway_view *view, double *min_width,
 | 
				
			||||||
			double *max_width, double *min_height, double *max_height);
 | 
								double *max_width, double *min_height, double *max_height);
 | 
				
			||||||
| 
						 | 
					@ -73,8 +80,6 @@ struct sway_view {
 | 
				
			||||||
	// Used when changing a view from tiled to floating.
 | 
						// Used when changing a view from tiled to floating.
 | 
				
			||||||
	int natural_width, natural_height;
 | 
						int natural_width, natural_height;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	char *title_format;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	bool using_csd;
 | 
						bool using_csd;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct timespec urgent;
 | 
						struct timespec urgent;
 | 
				
			||||||
| 
						 | 
					@ -111,6 +116,9 @@ struct sway_view {
 | 
				
			||||||
	int max_render_time; // In milliseconds
 | 
						int max_render_time; // In milliseconds
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	enum seat_config_shortcuts_inhibit shortcuts_inhibit;
 | 
						enum seat_config_shortcuts_inhibit shortcuts_inhibit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						enum sway_view_tearing_mode tearing_mode;
 | 
				
			||||||
 | 
						enum wp_tearing_control_v1_presentation_hint tearing_hint;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct sway_xdg_shell_view {
 | 
					struct sway_xdg_shell_view {
 | 
				
			||||||
| 
						 | 
					@ -335,4 +343,6 @@ void view_assign_ctx(struct sway_view *view, struct launcher_ctx *ctx);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void view_send_frame_done(struct sway_view *view);
 | 
					void view_send_frame_done(struct sway_view *view);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool view_can_tear(struct sway_view *view);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,7 +1,7 @@
 | 
				
			||||||
project(
 | 
					project(
 | 
				
			||||||
	'sway',
 | 
						'sway',
 | 
				
			||||||
	'c',
 | 
						'c',
 | 
				
			||||||
	version: '1.10-dev',
 | 
						version: '1.10-rc3',
 | 
				
			||||||
	license: 'MIT',
 | 
						license: 'MIT',
 | 
				
			||||||
	meson_version: '>=0.60.0',
 | 
						meson_version: '>=0.60.0',
 | 
				
			||||||
	default_options: [
 | 
						default_options: [
 | 
				
			||||||
| 
						 | 
					@ -160,8 +160,8 @@ add_project_arguments('-DSYSCONFDIR="/@0@"'.format(join_paths(prefix, sysconfdir
 | 
				
			||||||
version = '"@0@"'.format(meson.project_version())
 | 
					version = '"@0@"'.format(meson.project_version())
 | 
				
			||||||
git = find_program('git', native: true, required: false)
 | 
					git = find_program('git', native: true, required: false)
 | 
				
			||||||
if git.found()
 | 
					if git.found()
 | 
				
			||||||
	git_commit = run_command([git, 'rev-parse', '--short', 'HEAD'], check: false)
 | 
						git_commit = run_command([git, '--git-dir=.git', 'rev-parse', '--short', 'HEAD'], check: false)
 | 
				
			||||||
	git_branch = run_command([git, 'rev-parse', '--abbrev-ref', 'HEAD'], check: false)
 | 
						git_branch = run_command([git, '--git-dir=.git', 'rev-parse', '--abbrev-ref', 'HEAD'], check: false)
 | 
				
			||||||
	if git_commit.returncode() == 0 and git_branch.returncode() == 0
 | 
						if git_commit.returncode() == 0 and git_branch.returncode() == 0
 | 
				
			||||||
		version = '"@0@-@1@ (" __DATE__ ", branch \'@2@\')"'.format(
 | 
							version = '"@0@-@1@ (" __DATE__ ", branch \'@2@\')"'.format(
 | 
				
			||||||
			meson.project_version(),
 | 
								meson.project_version(),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -14,6 +14,7 @@ protocols = [
 | 
				
			||||||
	wl_protocol_dir / 'unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml',
 | 
						wl_protocol_dir / 'unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml',
 | 
				
			||||||
	wl_protocol_dir / 'staging/content-type/content-type-v1.xml',
 | 
						wl_protocol_dir / 'staging/content-type/content-type-v1.xml',
 | 
				
			||||||
	wl_protocol_dir / 'staging/cursor-shape/cursor-shape-v1.xml',
 | 
						wl_protocol_dir / 'staging/cursor-shape/cursor-shape-v1.xml',
 | 
				
			||||||
 | 
						wl_protocol_dir / 'staging/tearing-control/tearing-control-v1.xml',
 | 
				
			||||||
	'wlr-layer-shell-unstable-v1.xml',
 | 
						'wlr-layer-shell-unstable-v1.xml',
 | 
				
			||||||
	'idle.xml',
 | 
						'idle.xml',
 | 
				
			||||||
	'wlr-output-power-management-unstable-v1.xml',
 | 
						'wlr-output-power-management-unstable-v1.xml',
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -28,4 +28,5 @@ archive=$prefix.tar.gz
 | 
				
			||||||
git archive --prefix="$prefix/" -o "$archive" "$next"
 | 
					git archive --prefix="$prefix/" -o "$archive" "$next"
 | 
				
			||||||
gpg --output "$archive".sig --detach-sig "$archive"
 | 
					gpg --output "$archive".sig --detach-sig "$archive"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					git push --follow-tags
 | 
				
			||||||
gh release create "sway $next" -t "$next" -n "" -d "$archive" "$archive.sig"
 | 
					gh release create "sway $next" -t "$next" -n "" -d "$archive" "$archive.sig"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -112,6 +112,7 @@ static const struct cmd_handler config_handlers[] = {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Runtime-only commands. Keep alphabetized */
 | 
					/* Runtime-only commands. Keep alphabetized */
 | 
				
			||||||
static const struct cmd_handler command_handlers[] = {
 | 
					static const struct cmd_handler command_handlers[] = {
 | 
				
			||||||
 | 
						{ "allow_tearing", cmd_allow_tearing },
 | 
				
			||||||
	{ "border", cmd_border },
 | 
						{ "border", cmd_border },
 | 
				
			||||||
	{ "create_output", cmd_create_output },
 | 
						{ "create_output", cmd_create_output },
 | 
				
			||||||
	{ "exit", cmd_exit },
 | 
						{ "exit", cmd_exit },
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										24
									
								
								sway/commands/allow_tearing.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								sway/commands/allow_tearing.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,24 @@
 | 
				
			||||||
 | 
					#include <sway/commands.h>
 | 
				
			||||||
 | 
					#include "sway/config.h"
 | 
				
			||||||
 | 
					#include "sway/tree/view.h"
 | 
				
			||||||
 | 
					#include "util.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct cmd_results *cmd_allow_tearing(int argc, char **argv) {
 | 
				
			||||||
 | 
						struct cmd_results *error = NULL;
 | 
				
			||||||
 | 
						if ((error = checkarg(argc, "allow_tearing", EXPECTED_AT_LEAST, 1))) {
 | 
				
			||||||
 | 
							return error;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct sway_container *container = config->handler_context.container;
 | 
				
			||||||
 | 
						if (!container || !container->view) {
 | 
				
			||||||
 | 
							return cmd_results_new(CMD_INVALID, "Tearing can only be allowed on views");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool wants_tearing = parse_boolean(argv[0], true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct sway_view *view = container->view;
 | 
				
			||||||
 | 
						view->tearing_mode = wants_tearing ? TEARING_OVERRIDE_TRUE :
 | 
				
			||||||
 | 
							TEARING_OVERRIDE_FALSE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return cmd_results_new(CMD_SUCCESS, NULL);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -215,15 +215,13 @@ struct cmd_results *cmd_gaps(int argc, char **argv) {
 | 
				
			||||||
		return error;
 | 
							return error;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool config_loading = !config->active || config->reloading;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (argc == 2) {
 | 
						if (argc == 2) {
 | 
				
			||||||
		return gaps_set_defaults(argc, argv);
 | 
							return gaps_set_defaults(argc, argv);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (argc == 4 && !config_loading) {
 | 
						if (argc == 4 && !config->reading) {
 | 
				
			||||||
		return gaps_set_runtime(argc, argv);
 | 
							return gaps_set_runtime(argc, argv);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (config_loading) {
 | 
						if (config->reading) {
 | 
				
			||||||
		return cmd_results_new(CMD_INVALID, "Expected %s", expected_defaults);
 | 
							return cmd_results_new(CMD_INVALID, "Expected %s", expected_defaults);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return cmd_results_new(CMD_INVALID, "Expected %s or %s",
 | 
						return cmd_results_new(CMD_INVALID, "Expected %s or %s",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -94,7 +94,7 @@ struct cmd_results *cmd_input(int argc, char **argv) {
 | 
				
			||||||
			return res;
 | 
								return res;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (!config->reloading) {
 | 
							if (!config->reading) {
 | 
				
			||||||
			input_manager_apply_input_config(ic);
 | 
								input_manager_apply_input_config(ic);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -95,10 +95,18 @@ struct cmd_results *input_cmd_xkb_switch_layout(int argc, char **argv) {
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							struct wlr_keyboard *keyboard =
 | 
				
			||||||
 | 
								wlr_keyboard_from_input_device(dev->wlr_device);
 | 
				
			||||||
 | 
							if (keyboard->keymap == NULL && dev->is_virtual) {
 | 
				
			||||||
 | 
								// The `sway_keyboard_set_layout` function is by default skipped
 | 
				
			||||||
 | 
								// when configuring virtual keyboards.
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		struct xkb_switch_layout_action *action =
 | 
							struct xkb_switch_layout_action *action =
 | 
				
			||||||
			&actions[actions_len++];
 | 
								&actions[actions_len++];
 | 
				
			||||||
 | 
							action->keyboard = keyboard;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		action->keyboard = wlr_keyboard_from_input_device(dev->wlr_device);
 | 
					 | 
				
			||||||
		if (relative) {
 | 
							if (relative) {
 | 
				
			||||||
			action->layout = get_layout_relative(action->keyboard, relative);
 | 
								action->layout = get_layout_relative(action->keyboard, relative);
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -240,7 +240,6 @@ static void container_move_to_workspace(struct sway_container *container,
 | 
				
			||||||
static void container_move_to_container(struct sway_container *container,
 | 
					static void container_move_to_container(struct sway_container *container,
 | 
				
			||||||
		struct sway_container *destination) {
 | 
							struct sway_container *destination) {
 | 
				
			||||||
	if (container == destination
 | 
						if (container == destination
 | 
				
			||||||
			|| container_has_ancestor(container, destination)
 | 
					 | 
				
			||||||
			|| container_has_ancestor(destination, container)) {
 | 
								|| container_has_ancestor(destination, container)) {
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -510,6 +509,7 @@ static struct cmd_results *cmd_move_container(bool no_auto_back_and_forth,
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			ws = workspace_create(NULL, ws_name);
 | 
								ws = workspace_create(NULL, ws_name);
 | 
				
			||||||
 | 
								arrange_workspace(ws);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		free(ws_name);
 | 
							free(ws_name);
 | 
				
			||||||
		struct sway_container *dst = seat_get_focus_inactive_tiling(seat, ws);
 | 
							struct sway_container *dst = seat_get_focus_inactive_tiling(seat, ws);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,6 +8,7 @@
 | 
				
			||||||
// must be in order for the bsearch
 | 
					// must be in order for the bsearch
 | 
				
			||||||
static const struct cmd_handler output_handlers[] = {
 | 
					static const struct cmd_handler output_handlers[] = {
 | 
				
			||||||
	{ "adaptive_sync", output_cmd_adaptive_sync },
 | 
						{ "adaptive_sync", output_cmd_adaptive_sync },
 | 
				
			||||||
 | 
						{ "allow_tearing", output_cmd_allow_tearing },
 | 
				
			||||||
	{ "background", output_cmd_background },
 | 
						{ "background", output_cmd_background },
 | 
				
			||||||
	{ "bg", output_cmd_background },
 | 
						{ "bg", output_cmd_background },
 | 
				
			||||||
	{ "color_profile", output_cmd_color_profile },
 | 
						{ "color_profile", output_cmd_color_profile },
 | 
				
			||||||
| 
						 | 
					@ -106,17 +107,16 @@ struct cmd_results *cmd_output(int argc, char **argv) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	store_output_config(output);
 | 
						store_output_config(output);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// If reloading, the output configs will be applied after reading the
 | 
						if (config->reading) {
 | 
				
			||||||
	// entire config and before the deferred commands so that an auto generated
 | 
							// When reading the config file, we wait till the end to do a single
 | 
				
			||||||
	// workspace name is not given to re-enabled outputs.
 | 
							// modeset and swaybg spawn.
 | 
				
			||||||
	if (!config->reloading && !config->validating) {
 | 
							return cmd_results_new(CMD_SUCCESS, NULL);
 | 
				
			||||||
		apply_all_output_configs();
 | 
						}
 | 
				
			||||||
		if (background) {
 | 
						request_modeset();
 | 
				
			||||||
			if (!spawn_swaybg()) {
 | 
					
 | 
				
			||||||
				return cmd_results_new(CMD_FAILURE,
 | 
						if (background && !spawn_swaybg()) {
 | 
				
			||||||
					"Failed to apply background configuration");
 | 
							return cmd_results_new(CMD_FAILURE,
 | 
				
			||||||
			}
 | 
								"Failed to apply background configuration");
 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return cmd_results_new(CMD_SUCCESS, NULL);
 | 
						return cmd_results_new(CMD_SUCCESS, NULL);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,7 @@
 | 
				
			||||||
 | 
					#include <strings.h>
 | 
				
			||||||
#include "sway/commands.h"
 | 
					#include "sway/commands.h"
 | 
				
			||||||
#include "sway/config.h"
 | 
					#include "sway/config.h"
 | 
				
			||||||
 | 
					#include "sway/output.h"
 | 
				
			||||||
#include "util.h"
 | 
					#include "util.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct cmd_results *output_cmd_adaptive_sync(int argc, char **argv) {
 | 
					struct cmd_results *output_cmd_adaptive_sync(int argc, char **argv) {
 | 
				
			||||||
| 
						 | 
					@ -10,12 +12,26 @@ struct cmd_results *output_cmd_adaptive_sync(int argc, char **argv) {
 | 
				
			||||||
		return cmd_results_new(CMD_INVALID, "Missing adaptive_sync argument");
 | 
							return cmd_results_new(CMD_INVALID, "Missing adaptive_sync argument");
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (parse_boolean(argv[0], true)) {
 | 
						bool current_value = true;
 | 
				
			||||||
		config->handler_context.output_config->adaptive_sync = 1;
 | 
						if (strcasecmp(argv[0], "toggle") == 0) {
 | 
				
			||||||
	} else {
 | 
							const char *oc_name = config->handler_context.output_config->name;
 | 
				
			||||||
		config->handler_context.output_config->adaptive_sync = 0;
 | 
							if (strcmp(oc_name, "*") == 0) {
 | 
				
			||||||
 | 
								return cmd_results_new(CMD_INVALID,
 | 
				
			||||||
 | 
									"Cannot apply toggle to all outputs");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							struct sway_output *sway_output = all_output_by_name_or_id(oc_name);
 | 
				
			||||||
 | 
							if (!sway_output || !sway_output->wlr_output) {
 | 
				
			||||||
 | 
								return cmd_results_new(CMD_FAILURE,
 | 
				
			||||||
 | 
									"Cannot apply toggle to unknown output %s", oc_name);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							current_value =
 | 
				
			||||||
 | 
								sway_output->wlr_output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						config->handler_context.output_config->adaptive_sync = parse_boolean(argv[0], current_value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	config->handler_context.leftovers.argc = argc - 1;
 | 
						config->handler_context.leftovers.argc = argc - 1;
 | 
				
			||||||
	config->handler_context.leftovers.argv = argv + 1;
 | 
						config->handler_context.leftovers.argv = argv + 1;
 | 
				
			||||||
	return NULL;
 | 
						return NULL;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										23
									
								
								sway/commands/output/allow_tearing.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								sway/commands/output/allow_tearing.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,23 @@
 | 
				
			||||||
 | 
					#include "sway/commands.h"
 | 
				
			||||||
 | 
					#include "sway/config.h"
 | 
				
			||||||
 | 
					#include "util.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct cmd_results *output_cmd_allow_tearing(int argc, char **argv) {
 | 
				
			||||||
 | 
						if (!config->handler_context.output_config) {
 | 
				
			||||||
 | 
							return cmd_results_new(CMD_FAILURE, "Missing output config");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (argc == 0) {
 | 
				
			||||||
 | 
							return cmd_results_new(CMD_INVALID, "Missing allow_tearing argument");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (parse_boolean(argv[0],
 | 
				
			||||||
 | 
								(config->handler_context.output_config->allow_tearing == 1))) {
 | 
				
			||||||
 | 
							config->handler_context.output_config->allow_tearing = 1;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							config->handler_context.output_config->allow_tearing = 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						config->handler_context.leftovers.argc = argc - 1;
 | 
				
			||||||
 | 
						config->handler_context.leftovers.argv = argv + 1;
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -5,6 +5,7 @@
 | 
				
			||||||
#include <wlr/render/color.h>
 | 
					#include <wlr/render/color.h>
 | 
				
			||||||
#include "sway/commands.h"
 | 
					#include "sway/commands.h"
 | 
				
			||||||
#include "sway/config.h"
 | 
					#include "sway/config.h"
 | 
				
			||||||
 | 
					#include "stringop.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool read_file_into_buf(const char *path, void **buf, size_t *size) {
 | 
					static bool read_file_into_buf(const char *path, void **buf, size_t *size) {
 | 
				
			||||||
	/* Why not use fopen/fread directly? glibc will succesfully open directories,
 | 
						/* Why not use fopen/fread directly? glibc will succesfully open directories,
 | 
				
			||||||
| 
						 | 
					@ -70,12 +71,23 @@ struct cmd_results *output_cmd_color_profile(int argc, char **argv) {
 | 
				
			||||||
			return cmd_results_new(CMD_INVALID,
 | 
								return cmd_results_new(CMD_INVALID,
 | 
				
			||||||
				"Invalid color profile specification: icc type requires a file");
 | 
									"Invalid color profile specification: icc type requires a file");
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							char *icc_path = strdup(argv[1]);
 | 
				
			||||||
 | 
							if (!expand_path(&icc_path)) {
 | 
				
			||||||
 | 
								struct cmd_results *cmd_res = cmd_results_new(CMD_INVALID,
 | 
				
			||||||
 | 
									"Invalid color profile specification: invalid file path");
 | 
				
			||||||
 | 
								free(icc_path);
 | 
				
			||||||
 | 
								return cmd_res;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		void *data = NULL;
 | 
							void *data = NULL;
 | 
				
			||||||
		size_t size = 0;
 | 
							size_t size = 0;
 | 
				
			||||||
		if (!read_file_into_buf(argv[1], &data, &size)) {
 | 
							if (!read_file_into_buf(icc_path, &data, &size)) {
 | 
				
			||||||
 | 
								free(icc_path);
 | 
				
			||||||
			return cmd_results_new(CMD_FAILURE,
 | 
								return cmd_results_new(CMD_FAILURE,
 | 
				
			||||||
				"Failed to load color profile: could not read ICC file");
 | 
									"Failed to load color profile: could not read ICC file");
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							free(icc_path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		struct wlr_color_transform *tmp =
 | 
							struct wlr_color_transform *tmp =
 | 
				
			||||||
			wlr_color_transform_init_linear_to_icc(data, size);
 | 
								wlr_color_transform_init_linear_to_icc(data, size);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -11,7 +11,10 @@ struct cmd_results *output_cmd_render_bit_depth(int argc, char **argv) {
 | 
				
			||||||
		return cmd_results_new(CMD_INVALID, "Missing bit depth argument.");
 | 
							return cmd_results_new(CMD_INVALID, "Missing bit depth argument.");
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (strcmp(*argv, "8") == 0) {
 | 
						if (strcmp(*argv, "6") == 0) {
 | 
				
			||||||
 | 
							config->handler_context.output_config->render_bit_depth =
 | 
				
			||||||
 | 
								RENDER_BIT_DEPTH_6;
 | 
				
			||||||
 | 
						} else if (strcmp(*argv, "8") == 0) {
 | 
				
			||||||
		config->handler_context.output_config->render_bit_depth =
 | 
							config->handler_context.output_config->render_bit_depth =
 | 
				
			||||||
			RENDER_BIT_DEPTH_8;
 | 
								RENDER_BIT_DEPTH_8;
 | 
				
			||||||
	} else if (strcmp(*argv, "10") == 0) {
 | 
						} else if (strcmp(*argv, "10") == 0) {
 | 
				
			||||||
| 
						 | 
					@ -19,7 +22,7 @@ struct cmd_results *output_cmd_render_bit_depth(int argc, char **argv) {
 | 
				
			||||||
			RENDER_BIT_DEPTH_10;
 | 
								RENDER_BIT_DEPTH_10;
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		return cmd_results_new(CMD_INVALID,
 | 
							return cmd_results_new(CMD_INVALID,
 | 
				
			||||||
			"Invalid bit depth. Must be a value in (8|10).");
 | 
								"Invalid bit depth. Must be a value in (6|8|10).");
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	config->handler_context.leftovers.argc = argc - 1;
 | 
						config->handler_context.leftovers.argc = argc - 1;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,3 +1,4 @@
 | 
				
			||||||
 | 
					#define _POSIX_C_SOURCE 200809L
 | 
				
			||||||
#include <string.h>
 | 
					#include <string.h>
 | 
				
			||||||
#include "sway/commands.h"
 | 
					#include "sway/commands.h"
 | 
				
			||||||
#include "sway/config.h"
 | 
					#include "sway/config.h"
 | 
				
			||||||
| 
						 | 
					@ -11,16 +12,19 @@ struct cmd_results *cmd_title_format(int argc, char **argv) {
 | 
				
			||||||
		return error;
 | 
							return error;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	struct sway_container *container = config->handler_context.container;
 | 
						struct sway_container *container = config->handler_context.container;
 | 
				
			||||||
	if (!container || !container->view) {
 | 
						if (!container) {
 | 
				
			||||||
		return cmd_results_new(CMD_INVALID,
 | 
							return cmd_results_new(CMD_INVALID,
 | 
				
			||||||
				"Only views can have a title_format");
 | 
											 "Only valid containers can have a title_format");
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	struct sway_view *view = container->view;
 | 
					 | 
				
			||||||
	char *format = join_args(argv, argc);
 | 
						char *format = join_args(argv, argc);
 | 
				
			||||||
	if (view->title_format) {
 | 
						if (container->title_format) {
 | 
				
			||||||
		free(view->title_format);
 | 
							free(container->title_format);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						container->title_format = format;
 | 
				
			||||||
 | 
						if (container->view) {
 | 
				
			||||||
 | 
							view_update_title(container->view, true);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							container_update_representation(container);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	view->title_format = format;
 | 
					 | 
				
			||||||
	view_update_title(view, true);
 | 
					 | 
				
			||||||
	return cmd_results_new(CMD_SUCCESS, NULL);
 | 
						return cmd_results_new(CMD_SUCCESS, NULL);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -516,7 +516,7 @@ bool load_main_config(const char *file, bool is_active, bool validating) {
 | 
				
			||||||
	// Only really necessary if not explicitly `font` is set in the config.
 | 
						// Only really necessary if not explicitly `font` is set in the config.
 | 
				
			||||||
	config_update_font_height();
 | 
						config_update_font_height();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (is_active && !validating) {
 | 
						if (!validating) {
 | 
				
			||||||
		input_manager_verify_fallback_seat();
 | 
							input_manager_verify_fallback_seat();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		for (int i = 0; i < config->input_configs->length; i++) {
 | 
							for (int i = 0; i < config->input_configs->length; i++) {
 | 
				
			||||||
| 
						 | 
					@ -533,12 +533,14 @@ bool load_main_config(const char *file, bool is_active, bool validating) {
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		sway_switch_retrigger_bindings_for_all();
 | 
							sway_switch_retrigger_bindings_for_all();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		apply_all_output_configs();
 | 
					 | 
				
			||||||
		spawn_swaybg();
 | 
							spawn_swaybg();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		config->reloading = false;
 | 
							config->reloading = false;
 | 
				
			||||||
		if (config->swaynag_config_errors.client != NULL) {
 | 
							if (is_active) {
 | 
				
			||||||
			swaynag_show(&config->swaynag_config_errors);
 | 
								request_modeset();
 | 
				
			||||||
 | 
								if (config->swaynag_config_errors.client != NULL) {
 | 
				
			||||||
 | 
									swaynag_show(&config->swaynag_config_errors);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -10,10 +10,15 @@
 | 
				
			||||||
#include <wlr/types/wlr_output_layout.h>
 | 
					#include <wlr/types/wlr_output_layout.h>
 | 
				
			||||||
#include <wlr/types/wlr_output.h>
 | 
					#include <wlr/types/wlr_output.h>
 | 
				
			||||||
#include <wlr/types/wlr_output_swapchain_manager.h>
 | 
					#include <wlr/types/wlr_output_swapchain_manager.h>
 | 
				
			||||||
 | 
					#include <xf86drm.h>
 | 
				
			||||||
#include "sway/config.h"
 | 
					#include "sway/config.h"
 | 
				
			||||||
 | 
					#include "sway/desktop/transaction.h"
 | 
				
			||||||
#include "sway/input/cursor.h"
 | 
					#include "sway/input/cursor.h"
 | 
				
			||||||
 | 
					#include "sway/layers.h"
 | 
				
			||||||
 | 
					#include "sway/lock.h"
 | 
				
			||||||
#include "sway/output.h"
 | 
					#include "sway/output.h"
 | 
				
			||||||
#include "sway/server.h"
 | 
					#include "sway/server.h"
 | 
				
			||||||
 | 
					#include "sway/tree/arrange.h"
 | 
				
			||||||
#include "sway/tree/root.h"
 | 
					#include "sway/tree/root.h"
 | 
				
			||||||
#include "log.h"
 | 
					#include "log.h"
 | 
				
			||||||
#include "util.h"
 | 
					#include "util.h"
 | 
				
			||||||
| 
						 | 
					@ -22,13 +27,6 @@
 | 
				
			||||||
#include <wlr/backend/drm.h>
 | 
					#include <wlr/backend/drm.h>
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int output_name_cmp(const void *item, const void *data) {
 | 
					 | 
				
			||||||
	const struct output_config *output = item;
 | 
					 | 
				
			||||||
	const char *name = data;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return strcmp(output->name, name);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void output_get_identifier(char *identifier, size_t len,
 | 
					void output_get_identifier(char *identifier, size_t len,
 | 
				
			||||||
		struct sway_output *output) {
 | 
							struct sway_output *output) {
 | 
				
			||||||
	struct wlr_output *wlr_output = output->wlr_output;
 | 
						struct wlr_output *wlr_output = output->wlr_output;
 | 
				
			||||||
| 
						 | 
					@ -79,6 +77,7 @@ struct output_config *new_output_config(const char *name) {
 | 
				
			||||||
	oc->set_color_transform = false;
 | 
						oc->set_color_transform = false;
 | 
				
			||||||
	oc->color_transform = NULL;
 | 
						oc->color_transform = NULL;
 | 
				
			||||||
	oc->power = -1;
 | 
						oc->power = -1;
 | 
				
			||||||
 | 
						oc->allow_tearing = -1;
 | 
				
			||||||
	return oc;
 | 
						return oc;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -216,6 +215,9 @@ static void merge_output_config(struct output_config *dst, struct output_config
 | 
				
			||||||
	if (src->power != -1) {
 | 
						if (src->power != -1) {
 | 
				
			||||||
		dst->power = src->power;
 | 
							dst->power = src->power;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if (src->allow_tearing != -1) {
 | 
				
			||||||
 | 
							dst->allow_tearing = src->allow_tearing;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void store_output_config(struct output_config *oc) {
 | 
					void store_output_config(struct output_config *oc) {
 | 
				
			||||||
| 
						 | 
					@ -258,11 +260,11 @@ void store_output_config(struct output_config *oc) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	sway_log(SWAY_DEBUG, "Config stored for output %s (enabled: %d) (%dx%d@%fHz "
 | 
						sway_log(SWAY_DEBUG, "Config stored for output %s (enabled: %d) (%dx%d@%fHz "
 | 
				
			||||||
		"position %d,%d scale %f subpixel %s transform %d) (bg %s %s) (power %d) "
 | 
							"position %d,%d scale %f subpixel %s transform %d) (bg %s %s) (power %d) "
 | 
				
			||||||
		"(max render time: %d)",
 | 
							"(max render time: %d) (allow tearing: %d)",
 | 
				
			||||||
		oc->name, oc->enabled, oc->width, oc->height, oc->refresh_rate,
 | 
							oc->name, oc->enabled, oc->width, oc->height, oc->refresh_rate,
 | 
				
			||||||
		oc->x, oc->y, oc->scale, sway_wl_output_subpixel_to_string(oc->subpixel),
 | 
							oc->x, oc->y, oc->scale, sway_wl_output_subpixel_to_string(oc->subpixel),
 | 
				
			||||||
		oc->transform, oc->background, oc->background_option, oc->power,
 | 
							oc->transform, oc->background, oc->background_option, oc->power,
 | 
				
			||||||
		oc->max_render_time);
 | 
							oc->max_render_time, oc->allow_tearing);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// If the configuration was not merged into an existing configuration, add
 | 
						// If the configuration was not merged into an existing configuration, add
 | 
				
			||||||
	// it to the list. Otherwise we're done with it and can free it.
 | 
						// it to the list. Otherwise we're done with it and can free it.
 | 
				
			||||||
| 
						 | 
					@ -397,9 +399,15 @@ static int compute_default_scale(struct wlr_output *output,
 | 
				
			||||||
	return 2;
 | 
						return 2;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool render_format_is_10bit(uint32_t render_format) {
 | 
					static enum render_bit_depth bit_depth_from_format(uint32_t render_format) {
 | 
				
			||||||
	return render_format == DRM_FORMAT_XRGB2101010 ||
 | 
						if (render_format == DRM_FORMAT_XRGB2101010 || render_format == DRM_FORMAT_XBGR2101010) {
 | 
				
			||||||
		render_format == DRM_FORMAT_XBGR2101010;
 | 
							return RENDER_BIT_DEPTH_10;
 | 
				
			||||||
 | 
						} else if (render_format == DRM_FORMAT_XRGB8888 || render_format == DRM_FORMAT_ARGB8888) {
 | 
				
			||||||
 | 
							return RENDER_BIT_DEPTH_8;
 | 
				
			||||||
 | 
						} else if (render_format == DRM_FORMAT_RGB565) {
 | 
				
			||||||
 | 
							return RENDER_BIT_DEPTH_6;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return RENDER_BIT_DEPTH_DEFAULT;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool render_format_is_bgr(uint32_t fmt) {
 | 
					static bool render_format_is_bgr(uint32_t fmt) {
 | 
				
			||||||
| 
						 | 
					@ -487,7 +495,7 @@ static void queue_output_config(struct output_config *oc,
 | 
				
			||||||
		wlr_output_state_set_scale(pending, scale);
 | 
							wlr_output_state_set_scale(pending, scale);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (oc && oc->adaptive_sync != -1) {
 | 
						if (oc && oc->adaptive_sync != -1 && wlr_output->adaptive_sync_supported) {
 | 
				
			||||||
		sway_log(SWAY_DEBUG, "Set %s adaptive sync to %d", wlr_output->name,
 | 
							sway_log(SWAY_DEBUG, "Set %s adaptive sync to %d", wlr_output->name,
 | 
				
			||||||
			oc->adaptive_sync);
 | 
								oc->adaptive_sync);
 | 
				
			||||||
		wlr_output_state_set_adaptive_sync_enabled(pending, oc->adaptive_sync == 1);
 | 
							wlr_output_state_set_adaptive_sync_enabled(pending, oc->adaptive_sync == 1);
 | 
				
			||||||
| 
						 | 
					@ -495,11 +503,13 @@ static void queue_output_config(struct output_config *oc,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (oc && oc->render_bit_depth != RENDER_BIT_DEPTH_DEFAULT) {
 | 
						if (oc && oc->render_bit_depth != RENDER_BIT_DEPTH_DEFAULT) {
 | 
				
			||||||
		if (oc->render_bit_depth == RENDER_BIT_DEPTH_10 &&
 | 
							if (oc->render_bit_depth == RENDER_BIT_DEPTH_10 &&
 | 
				
			||||||
			render_format_is_10bit(output->wlr_output->render_format)) {
 | 
								bit_depth_from_format(output->wlr_output->render_format) == oc->render_bit_depth) {
 | 
				
			||||||
			// 10-bit was set successfully before, try to save some tests by reusing the format
 | 
								// 10-bit was set successfully before, try to save some tests by reusing the format
 | 
				
			||||||
			wlr_output_state_set_render_format(pending, output->wlr_output->render_format);
 | 
								wlr_output_state_set_render_format(pending, output->wlr_output->render_format);
 | 
				
			||||||
		} else if (oc->render_bit_depth == RENDER_BIT_DEPTH_10) {
 | 
							} else if (oc->render_bit_depth == RENDER_BIT_DEPTH_10) {
 | 
				
			||||||
			wlr_output_state_set_render_format(pending, DRM_FORMAT_XRGB2101010);
 | 
								wlr_output_state_set_render_format(pending, DRM_FORMAT_XRGB2101010);
 | 
				
			||||||
 | 
							} else if (oc->render_bit_depth == RENDER_BIT_DEPTH_6){
 | 
				
			||||||
 | 
								wlr_output_state_set_render_format(pending, DRM_FORMAT_RGB565);
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			wlr_output_state_set_render_format(pending, DRM_FORMAT_XRGB8888);
 | 
								wlr_output_state_set_render_format(pending, DRM_FORMAT_XRGB8888);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -574,74 +584,65 @@ static bool finalize_output_config(struct output_config *oc, struct sway_output
 | 
				
			||||||
		wlr_color_transform_unref(output->color_transform);
 | 
							wlr_color_transform_unref(output->color_transform);
 | 
				
			||||||
		output->color_transform = oc->color_transform;
 | 
							output->color_transform = oc->color_transform;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (oc && oc->allow_tearing >= 0) {
 | 
				
			||||||
 | 
							sway_log(SWAY_DEBUG, "Set %s allow tearing to %d",
 | 
				
			||||||
 | 
								oc->name, oc->allow_tearing);
 | 
				
			||||||
 | 
							output->allow_tearing = oc->allow_tearing;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return true;
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void default_output_config(struct output_config *oc,
 | 
					// find_output_config_from_list returns a merged output_config containing all
 | 
				
			||||||
		struct wlr_output *wlr_output) {
 | 
					// stored configuration that applies to the specified output.
 | 
				
			||||||
	oc->enabled = 1;
 | 
					static struct output_config *find_output_config_from_list(
 | 
				
			||||||
	oc->power = 1;
 | 
							struct output_config **configs, size_t configs_len,
 | 
				
			||||||
	struct wlr_output_mode *mode = wlr_output_preferred_mode(wlr_output);
 | 
							struct sway_output *sway_output) {
 | 
				
			||||||
	if (mode != NULL) {
 | 
					 | 
				
			||||||
		oc->width = mode->width;
 | 
					 | 
				
			||||||
		oc->height = mode->height;
 | 
					 | 
				
			||||||
		oc->refresh_rate = mode->refresh / 1000.f;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	oc->x = oc->y = -1;
 | 
					 | 
				
			||||||
	oc->scale = 0; // auto
 | 
					 | 
				
			||||||
	oc->scale_filter = SCALE_FILTER_DEFAULT;
 | 
					 | 
				
			||||||
	struct sway_output *output = wlr_output->data;
 | 
					 | 
				
			||||||
	oc->subpixel = output->detected_subpixel;
 | 
					 | 
				
			||||||
	oc->transform = WL_OUTPUT_TRANSFORM_NORMAL;
 | 
					 | 
				
			||||||
	oc->max_render_time = 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// find_output_config returns a merged output_config containing all stored
 | 
					 | 
				
			||||||
// configuration that applies to the specified output.
 | 
					 | 
				
			||||||
struct output_config *find_output_config(struct sway_output *sway_output) {
 | 
					 | 
				
			||||||
	const char *name = sway_output->wlr_output->name;
 | 
						const char *name = sway_output->wlr_output->name;
 | 
				
			||||||
	struct output_config *oc = NULL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	struct output_config *result = new_output_config(name);
 | 
						struct output_config *result = new_output_config(name);
 | 
				
			||||||
	if (config->reloading) {
 | 
						if (result == NULL) {
 | 
				
			||||||
		default_output_config(result, sway_output->wlr_output);
 | 
							return NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Set output defaults for the "base" configuration
 | 
				
			||||||
 | 
						result->enabled = 1;
 | 
				
			||||||
 | 
						result->power = 1;
 | 
				
			||||||
 | 
						result->scale = 0; // auto
 | 
				
			||||||
 | 
						result->subpixel = sway_output->detected_subpixel;
 | 
				
			||||||
 | 
						result->transform = WL_OUTPUT_TRANSFORM_NORMAL;
 | 
				
			||||||
 | 
						result->max_render_time = 0;
 | 
				
			||||||
 | 
						result->allow_tearing = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	char id[128];
 | 
						char id[128];
 | 
				
			||||||
	output_get_identifier(id, sizeof(id), sway_output);
 | 
						output_get_identifier(id, sizeof(id), sway_output);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int i;
 | 
						// We take a new config and merge on top, in order, the wildcard config,
 | 
				
			||||||
	bool match = false;
 | 
						// output config by name, and output config by identifier to form the final
 | 
				
			||||||
	if ((i = list_seq_find(config->output_configs, output_name_cmp, "*")) >= 0) {
 | 
						// config. If there are multiple matches, they are merged in order.
 | 
				
			||||||
		match = true;
 | 
						struct output_config *oc = NULL;
 | 
				
			||||||
		oc = config->output_configs->items[i];
 | 
						const char *names[] = {"*", name, id, NULL};
 | 
				
			||||||
		merge_output_config(result, oc);
 | 
						for (const char **name = &names[0]; *name; name++) {
 | 
				
			||||||
	}
 | 
							for (size_t idx = 0; idx < configs_len; idx++) {
 | 
				
			||||||
	if ((i = list_seq_find(config->output_configs, output_name_cmp, name)) >= 0) {
 | 
								oc = configs[idx];
 | 
				
			||||||
		match = true;
 | 
								if (strcmp(oc->name, *name) == 0) {
 | 
				
			||||||
		oc = config->output_configs->items[i];
 | 
									merge_output_config(result, oc);
 | 
				
			||||||
		merge_output_config(result, oc);
 | 
								}
 | 
				
			||||||
	}
 | 
							}
 | 
				
			||||||
	if ((i = list_seq_find(config->output_configs, output_name_cmp, id)) >= 0) {
 | 
					 | 
				
			||||||
		match = true;
 | 
					 | 
				
			||||||
		oc = config->output_configs->items[i];
 | 
					 | 
				
			||||||
		merge_output_config(result, oc);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!match && !config->reloading) {
 | 
					 | 
				
			||||||
		// No name, identifier, or wildcard config. Since we are not
 | 
					 | 
				
			||||||
		// reloading with defaults, the output config will be empty, so
 | 
					 | 
				
			||||||
		// just return NULL
 | 
					 | 
				
			||||||
		free_output_config(result);
 | 
					 | 
				
			||||||
		return NULL;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return result;
 | 
						return result;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool config_has_auto_mode(struct output_config *oc) {
 | 
					struct output_config *find_output_config(struct sway_output *sway_output) {
 | 
				
			||||||
 | 
						return find_output_config_from_list(
 | 
				
			||||||
 | 
								(struct output_config **)config->output_configs->items,
 | 
				
			||||||
 | 
								config->output_configs->length, sway_output);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool config_has_manual_mode(struct output_config *oc) {
 | 
				
			||||||
	if (!oc) {
 | 
						if (!oc) {
 | 
				
			||||||
		return true;
 | 
							return false;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (oc->drm_mode.type != 0 && oc->drm_mode.type != (uint32_t)-1) {
 | 
						if (oc->drm_mode.type != 0 && oc->drm_mode.type != (uint32_t)-1) {
 | 
				
			||||||
		return true;
 | 
							return true;
 | 
				
			||||||
| 
						 | 
					@ -651,6 +652,14 @@ static bool config_has_auto_mode(struct output_config *oc) {
 | 
				
			||||||
	return false;
 | 
						return false;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * An output config pre-matched to an output
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct matched_output_config {
 | 
				
			||||||
 | 
						struct sway_output *output;
 | 
				
			||||||
 | 
						struct output_config *config;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct search_context {
 | 
					struct search_context {
 | 
				
			||||||
	struct wlr_output_swapchain_manager *swapchain_mgr;
 | 
						struct wlr_output_swapchain_manager *swapchain_mgr;
 | 
				
			||||||
	struct wlr_backend_output_state *states;
 | 
						struct wlr_backend_output_state *states;
 | 
				
			||||||
| 
						 | 
					@ -665,7 +674,9 @@ static void dump_output_state(struct wlr_output *wlr_output, struct wlr_output_s
 | 
				
			||||||
		sway_log(SWAY_DEBUG, "    enabled:       %s", state->enabled ? "yes" : "no");
 | 
							sway_log(SWAY_DEBUG, "    enabled:       %s", state->enabled ? "yes" : "no");
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (state->committed & WLR_OUTPUT_STATE_RENDER_FORMAT) {
 | 
						if (state->committed & WLR_OUTPUT_STATE_RENDER_FORMAT) {
 | 
				
			||||||
		sway_log(SWAY_DEBUG, "    render_format: %d", state->render_format);
 | 
							char *format_name = drmGetFormatName(state->render_format);
 | 
				
			||||||
 | 
							sway_log(SWAY_DEBUG, "    render_format: %s", format_name);
 | 
				
			||||||
 | 
							free(format_name);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (state->committed & WLR_OUTPUT_STATE_MODE) {
 | 
						if (state->committed & WLR_OUTPUT_STATE_MODE) {
 | 
				
			||||||
		if (state->mode_type == WLR_OUTPUT_STATE_MODE_CUSTOM) {
 | 
							if (state->mode_type == WLR_OUTPUT_STATE_MODE_CUSTOM) {
 | 
				
			||||||
| 
						 | 
					@ -742,7 +753,8 @@ static bool search_mode(struct search_context *ctx, size_t output_idx) {
 | 
				
			||||||
	struct wlr_output_state *state = &backend_state->base;
 | 
						struct wlr_output_state *state = &backend_state->base;
 | 
				
			||||||
	struct wlr_output *wlr_output = backend_state->output;
 | 
						struct wlr_output *wlr_output = backend_state->output;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!config_has_auto_mode(cfg->config)) {
 | 
						// We only search for mode if one is not explicitly specified in the config
 | 
				
			||||||
 | 
						if (config_has_manual_mode(cfg->config)) {
 | 
				
			||||||
		return search_adaptive_sync(ctx, output_idx);
 | 
							return search_adaptive_sync(ctx, output_idx);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -783,6 +795,8 @@ static bool search_render_format(struct search_context *ctx, size_t output_idx)
 | 
				
			||||||
		DRM_FORMAT_XRGB2101010,
 | 
							DRM_FORMAT_XRGB2101010,
 | 
				
			||||||
		DRM_FORMAT_XBGR2101010,
 | 
							DRM_FORMAT_XBGR2101010,
 | 
				
			||||||
		DRM_FORMAT_XRGB8888,
 | 
							DRM_FORMAT_XRGB8888,
 | 
				
			||||||
 | 
							DRM_FORMAT_ARGB8888,
 | 
				
			||||||
 | 
							DRM_FORMAT_RGB565,
 | 
				
			||||||
		DRM_FORMAT_INVALID,
 | 
							DRM_FORMAT_INVALID,
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
	if (render_format_is_bgr(wlr_output->render_format)) {
 | 
						if (render_format_is_bgr(wlr_output->render_format)) {
 | 
				
			||||||
| 
						 | 
					@ -793,9 +807,13 @@ static bool search_render_format(struct search_context *ctx, size_t output_idx)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	const struct wlr_drm_format_set *primary_formats =
 | 
						const struct wlr_drm_format_set *primary_formats =
 | 
				
			||||||
		wlr_output_get_primary_formats(wlr_output, WLR_BUFFER_CAP_DMABUF);
 | 
							wlr_output_get_primary_formats(wlr_output, WLR_BUFFER_CAP_DMABUF);
 | 
				
			||||||
	bool need_10bit = cfg->config && cfg->config->render_bit_depth == RENDER_BIT_DEPTH_10;
 | 
						enum render_bit_depth needed_bits = RENDER_BIT_DEPTH_8;
 | 
				
			||||||
 | 
						if (cfg->config && cfg->config->render_bit_depth != RENDER_BIT_DEPTH_DEFAULT) {
 | 
				
			||||||
 | 
							needed_bits = cfg->config->render_bit_depth;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	for (size_t idx = 0; fmts[idx] != DRM_FORMAT_INVALID; idx++) {
 | 
						for (size_t idx = 0; fmts[idx] != DRM_FORMAT_INVALID; idx++) {
 | 
				
			||||||
		if (!need_10bit && render_format_is_10bit(fmts[idx])) {
 | 
							enum render_bit_depth format_bits = bit_depth_from_format(fmts[idx]);
 | 
				
			||||||
 | 
							if (needed_bits < format_bits) {
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if (!wlr_drm_format_set_get(primary_formats, fmts[idx])) {
 | 
							if (!wlr_drm_format_set_get(primary_formats, fmts[idx])) {
 | 
				
			||||||
| 
						 | 
					@ -868,12 +886,12 @@ static int compare_matched_output_config_priority(const void *a, const void *b)
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void sort_output_configs_by_priority(struct matched_output_config *configs,
 | 
					static void sort_output_configs_by_priority(
 | 
				
			||||||
		size_t configs_len) {
 | 
							struct matched_output_config *configs, size_t configs_len) {
 | 
				
			||||||
	qsort(configs, configs_len, sizeof(*configs), compare_matched_output_config_priority);
 | 
						qsort(configs, configs_len, sizeof(*configs), compare_matched_output_config_priority);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool apply_output_configs(struct matched_output_config *configs,
 | 
					static bool apply_resolved_output_configs(struct matched_output_config *configs,
 | 
				
			||||||
		size_t configs_len, bool test_only, bool degrade_to_off) {
 | 
							size_t configs_len, bool test_only, bool degrade_to_off) {
 | 
				
			||||||
	struct wlr_backend_output_state *states = calloc(configs_len, sizeof(*states));
 | 
						struct wlr_backend_output_state *states = calloc(configs_len, sizeof(*states));
 | 
				
			||||||
	if (!states) {
 | 
						if (!states) {
 | 
				
			||||||
| 
						 | 
					@ -950,8 +968,14 @@ bool apply_output_configs(struct matched_output_config *configs,
 | 
				
			||||||
		sway_log(SWAY_DEBUG, "Finalizing config for %s",
 | 
							sway_log(SWAY_DEBUG, "Finalizing config for %s",
 | 
				
			||||||
			cfg->output->wlr_output->name);
 | 
								cfg->output->wlr_output->name);
 | 
				
			||||||
		finalize_output_config(cfg->config, cfg->output);
 | 
							finalize_output_config(cfg->config, cfg->output);
 | 
				
			||||||
 | 
							arrange_layers(cfg->output);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						arrange_root();
 | 
				
			||||||
 | 
						arrange_locks();
 | 
				
			||||||
 | 
						update_output_manager_config(&server);
 | 
				
			||||||
 | 
						transaction_commit_dirty();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
out:
 | 
					out:
 | 
				
			||||||
	wlr_output_swapchain_manager_finish(&swapchain_mgr);
 | 
						wlr_output_swapchain_manager_finish(&swapchain_mgr);
 | 
				
			||||||
	for (size_t idx = 0; idx < configs_len; idx++) {
 | 
						for (size_t idx = 0; idx < configs_len; idx++) {
 | 
				
			||||||
| 
						 | 
					@ -976,11 +1000,12 @@ out:
 | 
				
			||||||
	return ok;
 | 
						return ok;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void apply_all_output_configs(void) {
 | 
					bool apply_output_configs(struct output_config **ocs, size_t ocs_len,
 | 
				
			||||||
 | 
							bool test_only, bool degrade_to_off) {
 | 
				
			||||||
	size_t configs_len = wl_list_length(&root->all_outputs);
 | 
						size_t configs_len = wl_list_length(&root->all_outputs);
 | 
				
			||||||
	struct matched_output_config *configs = calloc(configs_len, sizeof(*configs));
 | 
						struct matched_output_config *configs = calloc(configs_len, sizeof(*configs));
 | 
				
			||||||
	if (!configs) {
 | 
						if (!configs) {
 | 
				
			||||||
		return;
 | 
							return false;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int config_idx = 0;
 | 
						int config_idx = 0;
 | 
				
			||||||
| 
						 | 
					@ -993,16 +1018,22 @@ void apply_all_output_configs(void) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		struct matched_output_config *config = &configs[config_idx++];
 | 
							struct matched_output_config *config = &configs[config_idx++];
 | 
				
			||||||
		config->output = sway_output;
 | 
							config->output = sway_output;
 | 
				
			||||||
		config->config = find_output_config(sway_output);
 | 
							config->config = find_output_config_from_list(ocs, ocs_len, sway_output);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	sort_output_configs_by_priority(configs, configs_len);
 | 
						sort_output_configs_by_priority(configs, configs_len);
 | 
				
			||||||
	apply_output_configs(configs, configs_len, false, true);
 | 
						bool ok = apply_resolved_output_configs(configs, configs_len, test_only, degrade_to_off);
 | 
				
			||||||
	for (size_t idx = 0; idx < configs_len; idx++) {
 | 
						for (size_t idx = 0; idx < configs_len; idx++) {
 | 
				
			||||||
		struct matched_output_config *cfg = &configs[idx];
 | 
							struct matched_output_config *cfg = &configs[idx];
 | 
				
			||||||
		free_output_config(cfg->config);
 | 
							free_output_config(cfg->config);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	free(configs);
 | 
						free(configs);
 | 
				
			||||||
 | 
						return ok;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void apply_stored_output_configs(void) {
 | 
				
			||||||
 | 
						apply_output_configs((struct output_config **)config->output_configs->items,
 | 
				
			||||||
 | 
								config->output_configs->length, false, true);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void free_output_config(struct output_config *oc) {
 | 
					void free_output_config(struct output_config *oc) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -90,6 +90,43 @@ void arrange_layers(struct sway_output *output) {
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		arrange_popups(root->layers.popup);
 | 
							arrange_popups(root->layers.popup);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Find topmost keyboard interactive layer, if such a layer exists
 | 
				
			||||||
 | 
						struct wlr_scene_tree *layers_above_shell[] = {
 | 
				
			||||||
 | 
							output->layers.shell_overlay,
 | 
				
			||||||
 | 
							output->layers.shell_top,
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
						size_t nlayers = sizeof(layers_above_shell) / sizeof(layers_above_shell[0]);
 | 
				
			||||||
 | 
						struct wlr_scene_node *node;
 | 
				
			||||||
 | 
						struct sway_layer_surface *topmost = NULL;
 | 
				
			||||||
 | 
						for (size_t i = 0; i < nlayers; ++i) {
 | 
				
			||||||
 | 
							wl_list_for_each_reverse(node,
 | 
				
			||||||
 | 
									&layers_above_shell[i]->children, link) {
 | 
				
			||||||
 | 
								struct sway_layer_surface *surface = scene_descriptor_try_get(node,
 | 
				
			||||||
 | 
									SWAY_SCENE_DESC_LAYER_SHELL);
 | 
				
			||||||
 | 
								if (surface && surface->layer_surface->current.keyboard_interactive
 | 
				
			||||||
 | 
										== ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE &&
 | 
				
			||||||
 | 
										surface->layer_surface->surface->mapped) {
 | 
				
			||||||
 | 
									topmost = surface;
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (topmost != NULL) {
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct sway_seat *seat;
 | 
				
			||||||
 | 
						wl_list_for_each(seat, &server.input->seats, link) {
 | 
				
			||||||
 | 
							seat->has_exclusive_layer = false;
 | 
				
			||||||
 | 
							if (topmost != NULL) {
 | 
				
			||||||
 | 
								seat_set_focus_layer(seat, topmost->layer_surface);
 | 
				
			||||||
 | 
							} else if (seat->focused_layer &&
 | 
				
			||||||
 | 
									seat->focused_layer->current.keyboard_interactive
 | 
				
			||||||
 | 
										!= ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE) {
 | 
				
			||||||
 | 
								seat_set_focus_layer(seat, NULL);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct wlr_scene_tree *sway_layer_get_scene(struct sway_output *output,
 | 
					static struct wlr_scene_tree *sway_layer_get_scene(struct sway_output *output,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,6 +8,7 @@
 | 
				
			||||||
#include <wlr/render/swapchain.h>
 | 
					#include <wlr/render/swapchain.h>
 | 
				
			||||||
#include <wlr/render/wlr_renderer.h>
 | 
					#include <wlr/render/wlr_renderer.h>
 | 
				
			||||||
#include <wlr/types/wlr_buffer.h>
 | 
					#include <wlr/types/wlr_buffer.h>
 | 
				
			||||||
 | 
					#include <wlr/types/wlr_alpha_modifier_v1.h>
 | 
				
			||||||
#include <wlr/types/wlr_gamma_control_v1.h>
 | 
					#include <wlr/types/wlr_gamma_control_v1.h>
 | 
				
			||||||
#include <wlr/types/wlr_matrix.h>
 | 
					#include <wlr/types/wlr_matrix.h>
 | 
				
			||||||
#include <wlr/types/wlr_output_layout.h>
 | 
					#include <wlr/types/wlr_output_layout.h>
 | 
				
			||||||
| 
						 | 
					@ -216,6 +217,15 @@ static void output_configure_scene(struct sway_output *output,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (node->type == WLR_SCENE_NODE_BUFFER) {
 | 
						if (node->type == WLR_SCENE_NODE_BUFFER) {
 | 
				
			||||||
		struct wlr_scene_buffer *buffer = wlr_scene_buffer_from_node(node);
 | 
							struct wlr_scene_buffer *buffer = wlr_scene_buffer_from_node(node);
 | 
				
			||||||
 | 
							struct wlr_scene_surface *surface = wlr_scene_surface_try_from_buffer(buffer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (surface) {
 | 
				
			||||||
 | 
								const struct wlr_alpha_modifier_surface_v1_state *alpha_modifier_state =
 | 
				
			||||||
 | 
									wlr_alpha_modifier_v1_get_surface_state(surface->surface);
 | 
				
			||||||
 | 
								if (alpha_modifier_state != NULL) {
 | 
				
			||||||
 | 
									opacity *= (float)alpha_modifier_state->multiplier;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// hack: don't call the scene setter because that will damage all outputs
 | 
							// hack: don't call the scene setter because that will damage all outputs
 | 
				
			||||||
		// We don't want to damage outputs that aren't our current output that
 | 
							// We don't want to damage outputs that aren't our current output that
 | 
				
			||||||
| 
						 | 
					@ -232,6 +242,23 @@ static void output_configure_scene(struct sway_output *output,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool output_can_tear(struct sway_output *output) {
 | 
				
			||||||
 | 
						struct sway_workspace *workspace = output->current.active_workspace;
 | 
				
			||||||
 | 
						if (!workspace) {
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct sway_container *fullscreen_con = root->fullscreen_global;
 | 
				
			||||||
 | 
						if (!fullscreen_con) {
 | 
				
			||||||
 | 
							fullscreen_con = workspace->current.fullscreen;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (fullscreen_con && fullscreen_con->view) {
 | 
				
			||||||
 | 
							return (output->allow_tearing && view_can_tear(fullscreen_con->view));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int output_repaint_timer_handler(void *data) {
 | 
					static int output_repaint_timer_handler(void *data) {
 | 
				
			||||||
	struct sway_output *output = data;
 | 
						struct sway_output *output = data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -247,6 +274,13 @@ static int output_repaint_timer_handler(void *data) {
 | 
				
			||||||
		.color_transform = output->color_transform,
 | 
							.color_transform = output->color_transform,
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct wlr_output *wlr_output = output->wlr_output;
 | 
				
			||||||
 | 
						struct wlr_scene_output *scene_output = output->scene_output;
 | 
				
			||||||
 | 
						if (!wlr_output->needs_frame && !output->gamma_lut_changed &&
 | 
				
			||||||
 | 
								!pixman_region32_not_empty(&scene_output->pending_commit_damage)) {
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wlr_output_state pending;
 | 
						struct wlr_output_state pending;
 | 
				
			||||||
	wlr_output_state_init(&pending);
 | 
						wlr_output_state_init(&pending);
 | 
				
			||||||
	if (!wlr_scene_output_build_state(output->scene_output, &pending, &opts)) {
 | 
						if (!wlr_scene_output_build_state(output->scene_output, &pending, &opts)) {
 | 
				
			||||||
| 
						 | 
					@ -269,6 +303,16 @@ static int output_repaint_timer_handler(void *data) {
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (output_can_tear(output)) {
 | 
				
			||||||
 | 
							pending.tearing_page_flip = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (!wlr_output_test_state(output->wlr_output, &pending)) {
 | 
				
			||||||
 | 
								sway_log(SWAY_DEBUG, "Output test failed on '%s', retrying without tearing page-flip",
 | 
				
			||||||
 | 
									output->wlr_output->name);
 | 
				
			||||||
 | 
								pending.tearing_page_flip = false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!wlr_output_commit_state(output->wlr_output, &pending)) {
 | 
						if (!wlr_output_commit_state(output->wlr_output, &pending)) {
 | 
				
			||||||
		sway_log(SWAY_ERROR, "Page-flip failed on output %s", output->wlr_output->name);
 | 
							sway_log(SWAY_ERROR, "Page-flip failed on output %s", output->wlr_output->name);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -340,7 +384,7 @@ static void handle_frame(struct wl_listener *listener, void *user_data) {
 | 
				
			||||||
	wlr_scene_output_for_each_buffer(output->scene_output, send_frame_done_iterator, &data);
 | 
						wlr_scene_output_for_each_buffer(output->scene_output, send_frame_done_iterator, &data);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void update_output_manager_config(struct sway_server *server) {
 | 
					void update_output_manager_config(struct sway_server *server) {
 | 
				
			||||||
	struct wlr_output_configuration_v1 *config =
 | 
						struct wlr_output_configuration_v1 *config =
 | 
				
			||||||
		wlr_output_configuration_v1_create();
 | 
							wlr_output_configuration_v1_create();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -370,24 +414,19 @@ static int timer_modeset_handle(void *data) {
 | 
				
			||||||
	wl_event_source_remove(server->delayed_modeset);
 | 
						wl_event_source_remove(server->delayed_modeset);
 | 
				
			||||||
	server->delayed_modeset = NULL;
 | 
						server->delayed_modeset = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	apply_all_output_configs();
 | 
						apply_stored_output_configs();
 | 
				
			||||||
	transaction_commit_dirty();
 | 
					 | 
				
			||||||
	update_output_manager_config(server);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void request_modeset(struct sway_server *server) {
 | 
					void request_modeset(void) {
 | 
				
			||||||
	if (server->delayed_modeset == NULL) {
 | 
						if (server.delayed_modeset == NULL) {
 | 
				
			||||||
		server->delayed_modeset = wl_event_loop_add_timer(server->wl_event_loop,
 | 
							server.delayed_modeset = wl_event_loop_add_timer(server.wl_event_loop,
 | 
				
			||||||
			timer_modeset_handle, server);
 | 
								timer_modeset_handle, &server);
 | 
				
			||||||
		wl_event_source_timer_update(server->delayed_modeset, 10);
 | 
							wl_event_source_timer_update(server.delayed_modeset, 10);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void begin_destroy(struct sway_output *output) {
 | 
					static void begin_destroy(struct sway_output *output) {
 | 
				
			||||||
	struct sway_server *server = output->server;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (output->enabled) {
 | 
						if (output->enabled) {
 | 
				
			||||||
		output_disable(output);
 | 
							output_disable(output);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -408,7 +447,7 @@ static void begin_destroy(struct sway_output *output) {
 | 
				
			||||||
	output->wlr_output->data = NULL;
 | 
						output->wlr_output->data = NULL;
 | 
				
			||||||
	output->wlr_output = NULL;
 | 
						output->wlr_output = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	request_modeset(server);
 | 
						request_modeset();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void handle_destroy(struct wl_listener *listener, void *data) {
 | 
					static void handle_destroy(struct wl_listener *listener, void *data) {
 | 
				
			||||||
| 
						 | 
					@ -429,17 +468,6 @@ static void handle_commit(struct wl_listener *listener, void *data) {
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (event->state->committed & (
 | 
					 | 
				
			||||||
			WLR_OUTPUT_STATE_MODE |
 | 
					 | 
				
			||||||
			WLR_OUTPUT_STATE_TRANSFORM |
 | 
					 | 
				
			||||||
			WLR_OUTPUT_STATE_SCALE)) {
 | 
					 | 
				
			||||||
		arrange_layers(output);
 | 
					 | 
				
			||||||
		arrange_output(output);
 | 
					 | 
				
			||||||
		transaction_commit_dirty();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		update_output_manager_config(output->server);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Next time the output is enabled, try to re-apply the gamma LUT
 | 
						// Next time the output is enabled, try to re-apply the gamma LUT
 | 
				
			||||||
	if ((event->state->committed & WLR_OUTPUT_STATE_ENABLED) && !output->wlr_output->enabled) {
 | 
						if ((event->state->committed & WLR_OUTPUT_STATE_ENABLED) && !output->wlr_output->enabled) {
 | 
				
			||||||
		output->gamma_lut_changed = true;
 | 
							output->gamma_lut_changed = true;
 | 
				
			||||||
| 
						 | 
					@ -462,7 +490,20 @@ static void handle_request_state(struct wl_listener *listener, void *data) {
 | 
				
			||||||
	struct sway_output *output =
 | 
						struct sway_output *output =
 | 
				
			||||||
		wl_container_of(listener, output, request_state);
 | 
							wl_container_of(listener, output, request_state);
 | 
				
			||||||
	const struct wlr_output_event_request_state *event = data;
 | 
						const struct wlr_output_event_request_state *event = data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						uint32_t committed = event->state->committed;
 | 
				
			||||||
	wlr_output_commit_state(output->wlr_output, event->state);
 | 
						wlr_output_commit_state(output->wlr_output, event->state);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (committed & (
 | 
				
			||||||
 | 
								WLR_OUTPUT_STATE_MODE |
 | 
				
			||||||
 | 
								WLR_OUTPUT_STATE_TRANSFORM |
 | 
				
			||||||
 | 
								WLR_OUTPUT_STATE_SCALE)) {
 | 
				
			||||||
 | 
							arrange_layers(output);
 | 
				
			||||||
 | 
							arrange_output(output);
 | 
				
			||||||
 | 
							transaction_commit_dirty();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							update_output_manager_config(output->server);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static unsigned int last_headless_num = 0;
 | 
					static unsigned int last_headless_num = 0;
 | 
				
			||||||
| 
						 | 
					@ -542,14 +583,7 @@ void handle_new_output(struct wl_listener *listener, void *data) {
 | 
				
			||||||
		sway_session_lock_add_output(server->session_lock.lock, output);
 | 
							sway_session_lock_add_output(server->session_lock.lock, output);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	request_modeset(server);
 | 
						request_modeset();
 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void handle_output_layout_change(struct wl_listener *listener,
 | 
					 | 
				
			||||||
		void *data) {
 | 
					 | 
				
			||||||
	struct sway_server *server =
 | 
					 | 
				
			||||||
		wl_container_of(listener, server, output_layout_change);
 | 
					 | 
				
			||||||
	update_output_manager_config(server);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void handle_gamma_control_set_gamma(struct wl_listener *listener, void *data) {
 | 
					void handle_gamma_control_set_gamma(struct wl_listener *listener, void *data) {
 | 
				
			||||||
| 
						 | 
					@ -568,9 +602,8 @@ void handle_gamma_control_set_gamma(struct wl_listener *listener, void *data) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct output_config *output_config_for_config_head(
 | 
					static struct output_config *output_config_for_config_head(
 | 
				
			||||||
		struct wlr_output_configuration_head_v1 *config_head,
 | 
							struct wlr_output_configuration_head_v1 *config_head) {
 | 
				
			||||||
		struct sway_output *output) {
 | 
						struct output_config *oc = new_output_config(config_head->state.output->name);
 | 
				
			||||||
	struct output_config *oc = new_output_config(output->wlr_output->name);
 | 
					 | 
				
			||||||
	oc->enabled = config_head->state.enabled;
 | 
						oc->enabled = config_head->state.enabled;
 | 
				
			||||||
	if (!oc->enabled) {
 | 
						if (!oc->enabled) {
 | 
				
			||||||
		return oc;
 | 
							return oc;
 | 
				
			||||||
| 
						 | 
					@ -596,71 +629,52 @@ static struct output_config *output_config_for_config_head(
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void output_manager_apply(struct sway_server *server,
 | 
					static void output_manager_apply(struct sway_server *server,
 | 
				
			||||||
		struct wlr_output_configuration_v1 *config, bool test_only) {
 | 
							struct wlr_output_configuration_v1 *cfg, bool test_only) {
 | 
				
			||||||
	size_t configs_len = wl_list_length(&root->all_outputs);
 | 
						bool ok = false;
 | 
				
			||||||
	struct matched_output_config *configs = calloc(configs_len, sizeof(*configs));
 | 
						size_t configs_len = config->output_configs->length + wl_list_length(&cfg->heads);
 | 
				
			||||||
 | 
						struct output_config **configs = calloc(configs_len, sizeof(*configs));
 | 
				
			||||||
	if (!configs) {
 | 
						if (!configs) {
 | 
				
			||||||
		return;
 | 
							goto done;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						size_t start_new_configs = config->output_configs->length;
 | 
				
			||||||
 | 
						for (size_t idx = 0; idx < start_new_configs; idx++) {
 | 
				
			||||||
 | 
							configs[idx] = config->output_configs->items[idx];
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int config_idx = 0;
 | 
						size_t config_idx = start_new_configs;
 | 
				
			||||||
	struct sway_output *sway_output;
 | 
						struct wlr_output_configuration_head_v1 *config_head;
 | 
				
			||||||
	wl_list_for_each(sway_output, &root->all_outputs, link) {
 | 
						wl_list_for_each(config_head, &cfg->heads, link) {
 | 
				
			||||||
		if (sway_output == root->fallback_output) {
 | 
							// Generate the configuration and store it as a temporary
 | 
				
			||||||
			configs_len--;
 | 
							// config. We keep a record of it so we can remove it later.
 | 
				
			||||||
			continue;
 | 
							struct output_config *oc = output_config_for_config_head(config_head);
 | 
				
			||||||
		}
 | 
							configs[config_idx++] = oc;
 | 
				
			||||||
 | 
					 | 
				
			||||||
		struct matched_output_config *cfg = &configs[config_idx++];
 | 
					 | 
				
			||||||
		cfg->output = sway_output;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		struct wlr_output_configuration_head_v1 *config_head;
 | 
					 | 
				
			||||||
		wl_list_for_each(config_head, &config->heads, link) {
 | 
					 | 
				
			||||||
			if (config_head->state.output == sway_output->wlr_output) {
 | 
					 | 
				
			||||||
				cfg->config = output_config_for_config_head(config_head, sway_output);
 | 
					 | 
				
			||||||
				break;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if (!cfg->config) {
 | 
					 | 
				
			||||||
			cfg->config = find_output_config(sway_output);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	sort_output_configs_by_priority(configs, configs_len);
 | 
						// Try to commit without degrade to off enabled. Note that this will fail
 | 
				
			||||||
	bool ok = apply_output_configs(configs, configs_len, test_only, false);
 | 
						// if any output configured for enablement fails to be enabled, even if it
 | 
				
			||||||
	for (size_t idx = 0; idx < configs_len; idx++) {
 | 
						// was not part of the config heads we were asked to configure.
 | 
				
			||||||
		struct matched_output_config *cfg = &configs[idx];
 | 
						ok = apply_output_configs(configs, configs_len, test_only, false);
 | 
				
			||||||
 | 
						for (size_t idx = start_new_configs; idx < configs_len; idx++) {
 | 
				
			||||||
		// Only store new configs for successful non-test commits. Old configs,
 | 
							struct output_config *cfg = configs[idx];
 | 
				
			||||||
		// test-only and failed commits just get freed.
 | 
					 | 
				
			||||||
		bool store_config = false;
 | 
					 | 
				
			||||||
		if (!test_only && ok) {
 | 
							if (!test_only && ok) {
 | 
				
			||||||
			struct wlr_output_configuration_head_v1 *config_head;
 | 
								store_output_config(cfg);
 | 
				
			||||||
			wl_list_for_each(config_head, &config->heads, link) {
 | 
					 | 
				
			||||||
				if (config_head->state.output == cfg->output->wlr_output) {
 | 
					 | 
				
			||||||
					store_config = true;
 | 
					 | 
				
			||||||
					break;
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if (store_config) {
 | 
					 | 
				
			||||||
			store_output_config(cfg->config);
 | 
					 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			free_output_config(cfg->config);
 | 
								free_output_config(cfg);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	free(configs);
 | 
						free(configs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					done:
 | 
				
			||||||
	if (ok) {
 | 
						if (ok) {
 | 
				
			||||||
		wlr_output_configuration_v1_send_succeeded(config);
 | 
							wlr_output_configuration_v1_send_succeeded(cfg);
 | 
				
			||||||
 | 
							if (server->delayed_modeset != NULL) {
 | 
				
			||||||
 | 
								wl_event_source_remove(server->delayed_modeset);
 | 
				
			||||||
 | 
								server->delayed_modeset = NULL;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		wlr_output_configuration_v1_send_failed(config);
 | 
							wlr_output_configuration_v1_send_failed(cfg);
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	wlr_output_configuration_v1_destroy(config);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!test_only) {
 | 
					 | 
				
			||||||
		update_output_manager_config(server);
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						wlr_output_configuration_v1_destroy(cfg);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void handle_output_manager_apply(struct wl_listener *listener, void *data) {
 | 
					void handle_output_manager_apply(struct wl_listener *listener, void *data) {
 | 
				
			||||||
| 
						 | 
					@ -694,5 +708,5 @@ void handle_output_power_manager_set_mode(struct wl_listener *listener,
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	store_output_config(oc);
 | 
						store_output_config(oc);
 | 
				
			||||||
	request_modeset(output->server);
 | 
						request_modeset();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										64
									
								
								sway/desktop/tearing.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								sway/desktop/tearing.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,64 @@
 | 
				
			||||||
 | 
					#include <wayland-server-core.h>
 | 
				
			||||||
 | 
					#include <wlr/types/wlr_tearing_control_v1.h>
 | 
				
			||||||
 | 
					#include "sway/server.h"
 | 
				
			||||||
 | 
					#include "sway/tree/view.h"
 | 
				
			||||||
 | 
					#include "sway/output.h"
 | 
				
			||||||
 | 
					#include "log.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct sway_tearing_controller {
 | 
				
			||||||
 | 
						struct wlr_tearing_control_v1 *tearing_control;
 | 
				
			||||||
 | 
						struct wl_listener set_hint;
 | 
				
			||||||
 | 
						struct wl_listener destroy;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct wl_list link; // sway_server::tearing_controllers
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void handle_tearing_controller_set_hint(struct wl_listener *listener,
 | 
				
			||||||
 | 
							void *data) {
 | 
				
			||||||
 | 
						struct sway_tearing_controller *controller =
 | 
				
			||||||
 | 
							wl_container_of(listener, controller, set_hint);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct sway_view *view = view_from_wlr_surface(
 | 
				
			||||||
 | 
							controller->tearing_control->surface);
 | 
				
			||||||
 | 
						if (view) {
 | 
				
			||||||
 | 
							view->tearing_hint = controller->tearing_control->current;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void handle_tearing_controller_destroy(struct wl_listener *listener,
 | 
				
			||||||
 | 
							void *data) {
 | 
				
			||||||
 | 
						struct sway_tearing_controller *controller =
 | 
				
			||||||
 | 
							wl_container_of(listener, controller, destroy);
 | 
				
			||||||
 | 
						wl_list_remove(&controller->set_hint.link);
 | 
				
			||||||
 | 
						wl_list_remove(&controller->destroy.link);
 | 
				
			||||||
 | 
						wl_list_remove(&controller->link);
 | 
				
			||||||
 | 
						free(controller);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void handle_new_tearing_hint(struct wl_listener *listener,
 | 
				
			||||||
 | 
							void *data) {
 | 
				
			||||||
 | 
						struct sway_server *server =
 | 
				
			||||||
 | 
							wl_container_of(listener, server, tearing_control_new_object);
 | 
				
			||||||
 | 
						struct wlr_tearing_control_v1 *tearing_control = data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						enum wp_tearing_control_v1_presentation_hint hint =
 | 
				
			||||||
 | 
							wlr_tearing_control_manager_v1_surface_hint_from_surface(
 | 
				
			||||||
 | 
								server->tearing_control_v1, tearing_control->surface);
 | 
				
			||||||
 | 
						sway_log(SWAY_DEBUG, "New presentation hint %d received for surface %p",
 | 
				
			||||||
 | 
							hint, tearing_control->surface);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct sway_tearing_controller *controller =
 | 
				
			||||||
 | 
							calloc(1, sizeof(struct sway_tearing_controller));
 | 
				
			||||||
 | 
						if (!controller) {
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						controller->tearing_control = tearing_control;
 | 
				
			||||||
 | 
						controller->set_hint.notify = handle_tearing_controller_set_hint;
 | 
				
			||||||
 | 
						wl_signal_add(&tearing_control->events.set_hint, &controller->set_hint);
 | 
				
			||||||
 | 
						controller->destroy.notify = handle_tearing_controller_destroy;
 | 
				
			||||||
 | 
						wl_signal_add(&tearing_control->events.destroy, &controller->destroy);
 | 
				
			||||||
 | 
						wl_list_init(&controller->link);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wl_list_insert(&server->tearing_controllers, &controller->link);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -559,7 +559,7 @@ static void arrange_output(struct sway_output *output, int width, int height) {
 | 
				
			||||||
	for (int i = 0; i < output->current.workspaces->length; i++) {
 | 
						for (int i = 0; i < output->current.workspaces->length; i++) {
 | 
				
			||||||
		struct sway_workspace *child = output->current.workspaces->items[i];
 | 
							struct sway_workspace *child = output->current.workspaces->items[i];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		bool activated = output->current.active_workspace == child;
 | 
							bool activated = output->current.active_workspace == child && output->wlr_output->enabled;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		wlr_scene_node_reparent(&child->layers.tiling->node, output->layers.tiling);
 | 
							wlr_scene_node_reparent(&child->layers.tiling->node, output->layers.tiling);
 | 
				
			||||||
		wlr_scene_node_reparent(&child->layers.fullscreen->node, output->layers.fullscreen);
 | 
							wlr_scene_node_reparent(&child->layers.fullscreen->node, output->layers.fullscreen);
 | 
				
			||||||
| 
						 | 
					@ -612,9 +612,11 @@ void arrange_popups(struct wlr_scene_tree *popups) {
 | 
				
			||||||
		struct sway_popup_desc *popup = scene_descriptor_try_get(node,
 | 
							struct sway_popup_desc *popup = scene_descriptor_try_get(node,
 | 
				
			||||||
			SWAY_SCENE_DESC_POPUP);
 | 
								SWAY_SCENE_DESC_POPUP);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		int lx, ly;
 | 
							if (popup) {
 | 
				
			||||||
		wlr_scene_node_coords(popup->relative, &lx, &ly);
 | 
								int lx, ly;
 | 
				
			||||||
		wlr_scene_node_set_position(node, lx, ly);
 | 
								wlr_scene_node_coords(popup->relative, &lx, &ly);
 | 
				
			||||||
 | 
								wlr_scene_node_set_position(node, lx, ly);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -632,6 +634,15 @@ static void arrange_root(struct sway_root *root) {
 | 
				
			||||||
	for (int i = 0; i < root->scratchpad->length; i++) {
 | 
						for (int i = 0; i < root->scratchpad->length; i++) {
 | 
				
			||||||
		struct sway_container *con = root->scratchpad->items[i];
 | 
							struct sway_container *con = root->scratchpad->items[i];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// When a container is moved to a scratchpad, it's possible that it
 | 
				
			||||||
 | 
							// was moved into a floating container as part of the same transaction.
 | 
				
			||||||
 | 
							// In this case, we need to make sure we reparent all the container's
 | 
				
			||||||
 | 
							// children so that disabling the container will disable all descendants.
 | 
				
			||||||
 | 
							if (!con->view) for (int ii = 0; ii < con->current.children->length; ii++) {
 | 
				
			||||||
 | 
								struct sway_container *child = con->current.children->items[ii];
 | 
				
			||||||
 | 
								wlr_scene_node_reparent(&child->scene_tree->node, con->content_tree);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		wlr_scene_node_set_enabled(&con->scene_tree->node, false);
 | 
							wlr_scene_node_set_enabled(&con->scene_tree->node, false);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -289,7 +289,9 @@ static void set_activated(struct sway_view *view, bool activated) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wlr_xwayland_surface_activate(surface, activated);
 | 
						wlr_xwayland_surface_activate(surface, activated);
 | 
				
			||||||
	wlr_xwayland_surface_restack(surface, NULL, XCB_STACK_MODE_ABOVE);
 | 
						if (activated) {
 | 
				
			||||||
 | 
							wlr_xwayland_surface_restack(surface, NULL, XCB_STACK_MODE_ABOVE);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void set_tiled(struct sway_view *view, bool tiled) {
 | 
					static void set_tiled(struct sway_view *view, bool tiled) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,7 +4,6 @@
 | 
				
			||||||
#include <math.h>
 | 
					#include <math.h>
 | 
				
			||||||
#include <assert.h>
 | 
					#include <assert.h>
 | 
				
			||||||
#include <wlr/config.h>
 | 
					#include <wlr/config.h>
 | 
				
			||||||
#include <wlr/backend/libinput.h>
 | 
					 | 
				
			||||||
#include <wlr/types/wlr_cursor.h>
 | 
					#include <wlr/types/wlr_cursor.h>
 | 
				
			||||||
#include <wlr/types/wlr_keyboard_group.h>
 | 
					#include <wlr/types/wlr_keyboard_group.h>
 | 
				
			||||||
#include <wlr/types/wlr_virtual_keyboard_v1.h>
 | 
					#include <wlr/types/wlr_virtual_keyboard_v1.h>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1028,13 +1028,6 @@ static void sway_keyboard_set_layout(struct sway_keyboard *keyboard,
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// If the seat has no active keyboard, set this one
 | 
					 | 
				
			||||||
	struct wlr_seat *seat = keyboard->seat_device->sway_seat->wlr_seat;
 | 
					 | 
				
			||||||
	struct wlr_keyboard *current_keyboard = seat->keyboard_state.keyboard;
 | 
					 | 
				
			||||||
	if (current_keyboard == NULL) {
 | 
					 | 
				
			||||||
		wlr_seat_set_keyboard(seat, keyboard->wlr);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (keymap_changed) {
 | 
						if (keymap_changed) {
 | 
				
			||||||
		ipc_event_input("xkb_keymap",
 | 
							ipc_event_input("xkb_keymap",
 | 
				
			||||||
				  keyboard->seat_device->input_device);
 | 
									  keyboard->seat_device->input_device);
 | 
				
			||||||
| 
						 | 
					@ -1078,6 +1071,13 @@ void sway_keyboard_configure(struct sway_keyboard *keyboard) {
 | 
				
			||||||
		sway_keyboard_set_layout(keyboard, input_config);
 | 
							sway_keyboard_set_layout(keyboard, input_config);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// If the seat has no active keyboard, set this one
 | 
				
			||||||
 | 
						struct wlr_seat *seat = keyboard->seat_device->sway_seat->wlr_seat;
 | 
				
			||||||
 | 
						struct wlr_keyboard *current_keyboard = seat->keyboard_state.keyboard;
 | 
				
			||||||
 | 
						if (current_keyboard == NULL) {
 | 
				
			||||||
 | 
							wlr_seat_set_keyboard(seat, keyboard->wlr);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wl_list_remove(&keyboard->keyboard_key.link);
 | 
						wl_list_remove(&keyboard->keyboard_key.link);
 | 
				
			||||||
	wl_signal_add(&keyboard->wlr->events.key, &keyboard->keyboard_key);
 | 
						wl_signal_add(&keyboard->wlr->events.key, &keyboard->keyboard_key);
 | 
				
			||||||
	keyboard->keyboard_key.notify = handle_keyboard_key;
 | 
						keyboard->keyboard_key.notify = handle_keyboard_key;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -491,7 +491,9 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec,
 | 
				
			||||||
	// Handle moving a tiling container
 | 
						// Handle moving a tiling container
 | 
				
			||||||
	if (config->tiling_drag && (mod_pressed || on_titlebar) &&
 | 
						if (config->tiling_drag && (mod_pressed || on_titlebar) &&
 | 
				
			||||||
			state == WL_POINTER_BUTTON_STATE_PRESSED && !is_floating_or_child &&
 | 
								state == WL_POINTER_BUTTON_STATE_PRESSED && !is_floating_or_child &&
 | 
				
			||||||
			cont && cont->pending.fullscreen_mode == FULLSCREEN_NONE) {
 | 
								cont && cont->pending.fullscreen_mode == FULLSCREEN_NONE &&
 | 
				
			||||||
 | 
								button == (config->floating_mod_inverse ? BTN_RIGHT : BTN_LEFT)) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// If moving a container by its title bar, use a threshold for the drag
 | 
							// If moving a container by its title bar, use a threshold for the drag
 | 
				
			||||||
		if (!mod_pressed && config->tiling_drag_threshold > 0) {
 | 
							if (!mod_pressed && config->tiling_drag_threshold > 0) {
 | 
				
			||||||
			seatop_begin_move_tiling_threshold(seat, cont);
 | 
								seatop_begin_move_tiling_threshold(seat, cont);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -11,8 +11,6 @@
 | 
				
			||||||
#include "sway/layers.h"
 | 
					#include "sway/layers.h"
 | 
				
			||||||
#include "sway/server.h"
 | 
					#include "sway/server.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void input_popup_update(struct sway_input_popup *popup);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static struct sway_text_input *relay_get_focusable_text_input(
 | 
					static struct sway_text_input *relay_get_focusable_text_input(
 | 
				
			||||||
		struct sway_input_method_relay *relay) {
 | 
							struct sway_input_method_relay *relay) {
 | 
				
			||||||
	struct sway_text_input *text_input = NULL;
 | 
						struct sway_text_input *text_input = NULL;
 | 
				
			||||||
| 
						 | 
					@ -128,6 +126,89 @@ static void handle_im_destroy(struct wl_listener *listener, void *data) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void constrain_popup(struct sway_input_popup *popup) {
 | 
				
			||||||
 | 
						struct sway_text_input *text_input =
 | 
				
			||||||
 | 
							relay_get_focused_text_input(popup->relay);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!popup->desc.relative) {
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct wlr_box parent = {0};
 | 
				
			||||||
 | 
						wlr_scene_node_coords(&popup->desc.relative->parent->node, &parent.x, &parent.y);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct wlr_box geo = {0};
 | 
				
			||||||
 | 
						struct wlr_output *output;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (popup->desc.view) {
 | 
				
			||||||
 | 
							struct sway_view *view = popup->desc.view;
 | 
				
			||||||
 | 
							output = wlr_output_layout_output_at(root->output_layout,
 | 
				
			||||||
 | 
								view->container->pending.content_x + view->geometry.x,
 | 
				
			||||||
 | 
								view->container->pending.content_y + view->geometry.y);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							parent.width = view->geometry.width;
 | 
				
			||||||
 | 
							parent.height = view->geometry.height;
 | 
				
			||||||
 | 
							geo = view->geometry;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							output = popup->fixed_output;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct wlr_box output_box;
 | 
				
			||||||
 | 
						wlr_output_layout_get_box(root->output_layout, output, &output_box);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool cursor_rect = text_input->input->current.features &
 | 
				
			||||||
 | 
							WLR_TEXT_INPUT_V3_FEATURE_CURSOR_RECTANGLE;
 | 
				
			||||||
 | 
						struct wlr_box cursor_area;
 | 
				
			||||||
 | 
						if (cursor_rect) {
 | 
				
			||||||
 | 
							cursor_area = text_input->input->current.cursor_rectangle;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							cursor_area = (struct wlr_box) {
 | 
				
			||||||
 | 
								.width = parent.width,
 | 
				
			||||||
 | 
								.height = parent.height,
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int popup_width = popup->popup_surface->surface->current.width;
 | 
				
			||||||
 | 
						int popup_height = popup->popup_surface->surface->current.height;
 | 
				
			||||||
 | 
						int x1 = parent.x + cursor_area.x;
 | 
				
			||||||
 | 
						int x2 = parent.x + cursor_area.x + cursor_area.width;
 | 
				
			||||||
 | 
						int y1 = parent.y + cursor_area.y;
 | 
				
			||||||
 | 
						int y2 = parent.y + cursor_area.y + cursor_area.height;
 | 
				
			||||||
 | 
						int x = x1;
 | 
				
			||||||
 | 
						int y = y2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int available_right = output_box.x + output_box.width - x1;
 | 
				
			||||||
 | 
						int available_left = x2 - output_box.x;
 | 
				
			||||||
 | 
						if (available_right < popup_width && available_left > available_right) {
 | 
				
			||||||
 | 
							x = x2 - popup_width;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int available_down = output_box.y + output_box.height - y2;
 | 
				
			||||||
 | 
						int available_up = y1 - output_box.y;
 | 
				
			||||||
 | 
						if (available_down < popup_height && available_up > available_down) {
 | 
				
			||||||
 | 
							y = y1 - popup_height;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wlr_scene_node_set_position(popup->desc.relative, x - parent.x - geo.x, y - parent.y - geo.y);
 | 
				
			||||||
 | 
						if (cursor_rect) {
 | 
				
			||||||
 | 
							struct wlr_box box = {
 | 
				
			||||||
 | 
								.x = x1 - x,
 | 
				
			||||||
 | 
								.y = y1 - y,
 | 
				
			||||||
 | 
								.width = cursor_area.width,
 | 
				
			||||||
 | 
								.height = cursor_area.height,
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
							wlr_input_popup_surface_v2_send_text_input_rectangle(
 | 
				
			||||||
 | 
								popup->popup_surface, &box);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (popup->scene_tree) {
 | 
				
			||||||
 | 
							wlr_scene_node_set_position(&popup->scene_tree->node, x - geo.x, y - geo.y);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void input_popup_set_focus(struct sway_input_popup *popup,
 | 
				
			||||||
 | 
							struct wlr_surface *surface);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void relay_send_im_state(struct sway_input_method_relay *relay,
 | 
					static void relay_send_im_state(struct sway_input_method_relay *relay,
 | 
				
			||||||
		struct wlr_text_input_v3 *input) {
 | 
							struct wlr_text_input_v3 *input) {
 | 
				
			||||||
	struct wlr_input_method_v2 *input_method = relay->input_method;
 | 
						struct wlr_input_method_v2 *input_method = relay->input_method;
 | 
				
			||||||
| 
						 | 
					@ -148,10 +229,16 @@ static void relay_send_im_state(struct sway_input_method_relay *relay,
 | 
				
			||||||
			input->current.content_type.hint,
 | 
								input->current.content_type.hint,
 | 
				
			||||||
			input->current.content_type.purpose);
 | 
								input->current.content_type.purpose);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct sway_text_input *text_input = relay_get_focused_text_input(relay);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct sway_input_popup *popup;
 | 
						struct sway_input_popup *popup;
 | 
				
			||||||
	wl_list_for_each(popup, &relay->input_popups, link) {
 | 
						wl_list_for_each(popup, &relay->input_popups, link) {
 | 
				
			||||||
		// send_text_input_rectangle is called in this function
 | 
							if (text_input != NULL) {
 | 
				
			||||||
		input_popup_update(popup);
 | 
								input_popup_set_focus(popup, text_input->input->focused_surface);
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								input_popup_set_focus(popup, NULL);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	wlr_input_method_v2_send_done(input_method);
 | 
						wlr_input_method_v2_send_done(input_method);
 | 
				
			||||||
	// TODO: pass intent, display popup size
 | 
						// TODO: pass intent, display popup size
 | 
				
			||||||
| 
						 | 
					@ -275,72 +362,52 @@ static void relay_handle_text_input(struct wl_listener *listener,
 | 
				
			||||||
	sway_text_input_create(relay, wlr_text_input);
 | 
						sway_text_input_create(relay, wlr_text_input);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void input_popup_update(struct sway_input_popup *popup) {
 | 
					static void input_popup_set_focus(struct sway_input_popup *popup,
 | 
				
			||||||
	struct sway_text_input *text_input =
 | 
							struct wlr_surface *surface) {
 | 
				
			||||||
		relay_get_focused_text_input(popup->relay);
 | 
						wl_list_remove(&popup->focused_surface_unmap.link);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (text_input == NULL || text_input->input->focused_surface == NULL) {
 | 
						if (!popup->scene_tree) {
 | 
				
			||||||
 | 
							wl_list_init(&popup->focused_surface_unmap.link);
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (popup->scene_tree != NULL) {
 | 
						if (popup->desc.relative) {
 | 
				
			||||||
		wlr_scene_node_destroy(&popup->scene_tree->node);
 | 
							scene_descriptor_destroy(&popup->scene_tree->node, SWAY_SCENE_DESC_POPUP);
 | 
				
			||||||
		popup->scene_tree = NULL;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if (popup->desc.relative != NULL) {
 | 
					 | 
				
			||||||
		wlr_scene_node_destroy(popup->desc.relative);
 | 
							wlr_scene_node_destroy(popup->desc.relative);
 | 
				
			||||||
		popup->desc.relative = NULL;
 | 
							popup->desc.relative = NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	popup->desc.view = NULL;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!popup->popup_surface->surface->mapped) {
 | 
						if (surface == NULL) {
 | 
				
			||||||
 | 
							wl_list_init(&popup->focused_surface_unmap.link);
 | 
				
			||||||
 | 
							wlr_scene_node_set_enabled(&popup->scene_tree->node, false);
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool cursor_rect = text_input->input->current.features
 | 
					 | 
				
			||||||
		& WLR_TEXT_INPUT_V3_FEATURE_CURSOR_RECTANGLE;
 | 
					 | 
				
			||||||
	struct wlr_surface *focused_surface = text_input->input->focused_surface;
 | 
					 | 
				
			||||||
	struct wlr_box cursor_area = text_input->input->current.cursor_rectangle;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	struct wlr_box output_box;
 | 
					 | 
				
			||||||
	struct wlr_box parent = {0};
 | 
					 | 
				
			||||||
	struct wlr_layer_surface_v1 *layer_surface =
 | 
						struct wlr_layer_surface_v1 *layer_surface =
 | 
				
			||||||
		wlr_layer_surface_v1_try_from_wlr_surface(focused_surface);
 | 
							wlr_layer_surface_v1_try_from_wlr_surface(surface);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wlr_scene_tree *relative_parent;
 | 
						struct wlr_scene_tree *relative_parent;
 | 
				
			||||||
 | 
						if (layer_surface) {
 | 
				
			||||||
 | 
							wl_signal_add(&layer_surface->surface->events.unmap,
 | 
				
			||||||
 | 
								&popup->focused_surface_unmap);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wlr_box geo = {0};
 | 
							struct sway_layer_surface *layer = layer_surface->data;
 | 
				
			||||||
 | 
					 | 
				
			||||||
	popup->scene_tree = wlr_scene_subsurface_tree_create(root->layers.popup, popup->popup_surface->surface);
 | 
					 | 
				
			||||||
	if (layer_surface != NULL) {
 | 
					 | 
				
			||||||
		struct sway_layer_surface *layer =
 | 
					 | 
				
			||||||
			layer_surface->data;
 | 
					 | 
				
			||||||
		if (layer == NULL) {
 | 
							if (layer == NULL) {
 | 
				
			||||||
			return;
 | 
								return;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		relative_parent = layer->scene->tree;
 | 
							relative_parent = layer->scene->tree;
 | 
				
			||||||
		struct wlr_output *output = layer->layer_surface->output;
 | 
					 | 
				
			||||||
		wlr_output_layout_get_box(root->output_layout, output, &output_box);
 | 
					 | 
				
			||||||
		int lx, ly;
 | 
					 | 
				
			||||||
		wlr_scene_node_coords(&layer->tree->node, &lx, &ly);
 | 
					 | 
				
			||||||
		parent.x = lx;
 | 
					 | 
				
			||||||
		parent.y = ly;
 | 
					 | 
				
			||||||
		popup->desc.view = NULL;
 | 
							popup->desc.view = NULL;
 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		struct sway_view *view = view_from_wlr_surface(focused_surface);
 | 
					 | 
				
			||||||
		relative_parent = view->scene_tree;
 | 
					 | 
				
			||||||
		geo = view->geometry;
 | 
					 | 
				
			||||||
		int lx, ly;
 | 
					 | 
				
			||||||
		wlr_scene_node_coords(&view->scene_tree->node, &lx, &ly);
 | 
					 | 
				
			||||||
		struct wlr_output *output = wlr_output_layout_output_at(root->output_layout,
 | 
					 | 
				
			||||||
			view->container->pending.content_x + view->geometry.x,
 | 
					 | 
				
			||||||
			view->container->pending.content_y + view->geometry.y);
 | 
					 | 
				
			||||||
		wlr_output_layout_get_box(root->output_layout, output, &output_box);
 | 
					 | 
				
			||||||
		parent.x = lx;
 | 
					 | 
				
			||||||
		parent.y = ly;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		parent.width = view->geometry.width;
 | 
							// we don't need to add an event here to NULL out this field because
 | 
				
			||||||
		parent.height = view->geometry.height;
 | 
							// this field will only be initialized if the popup is part of a layer
 | 
				
			||||||
 | 
							// surface. Layer surfaces get destroyed as part of the output being
 | 
				
			||||||
 | 
							// destroyed, thus also trickling down to popups.
 | 
				
			||||||
 | 
							popup->fixed_output = layer->layer_surface->output;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							struct sway_view *view = view_from_wlr_surface(surface);
 | 
				
			||||||
 | 
							wl_signal_add(&view->events.unmap, &popup->focused_surface_unmap);
 | 
				
			||||||
 | 
							relative_parent = view->scene_tree;
 | 
				
			||||||
		popup->desc.view = view;
 | 
							popup->desc.view = view;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -354,93 +421,59 @@ static void input_popup_update(struct sway_input_popup *popup) {
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!cursor_rect) {
 | 
						constrain_popup(popup);
 | 
				
			||||||
		cursor_area.x = 0;
 | 
						wlr_scene_node_set_enabled(&popup->scene_tree->node, true);
 | 
				
			||||||
		cursor_area.y = 0;
 | 
					 | 
				
			||||||
		cursor_area.width = parent.width;
 | 
					 | 
				
			||||||
		cursor_area.height = parent.height;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	int popup_width = popup->popup_surface->surface->current.width;
 | 
					 | 
				
			||||||
	int popup_height = popup->popup_surface->surface->current.height;
 | 
					 | 
				
			||||||
	int x1 = parent.x + cursor_area.x;
 | 
					 | 
				
			||||||
	int x2 = parent.x + cursor_area.x + cursor_area.width;
 | 
					 | 
				
			||||||
	int y1 = parent.y + cursor_area.y;
 | 
					 | 
				
			||||||
	int y2 = parent.y + cursor_area.y + cursor_area.height;
 | 
					 | 
				
			||||||
	int x = x1;
 | 
					 | 
				
			||||||
	int y = y2;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	int available_right = output_box.x + output_box.width - x1;
 | 
					 | 
				
			||||||
	int available_left = x2 - output_box.x;
 | 
					 | 
				
			||||||
	if (available_right < popup_width && available_left > available_right) {
 | 
					 | 
				
			||||||
		x = x2 - popup_width;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	int available_down = output_box.y + output_box.height - y2;
 | 
					 | 
				
			||||||
	int available_up = y1 - output_box.y;
 | 
					 | 
				
			||||||
	if (available_down < popup_height && available_up > available_down) {
 | 
					 | 
				
			||||||
		y = y1 - popup_height;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	wlr_scene_node_set_position(&relative->node, x - parent.x - geo.x, y - parent.y - geo.y);
 | 
					 | 
				
			||||||
	if (cursor_rect) {
 | 
					 | 
				
			||||||
		struct wlr_box box = {
 | 
					 | 
				
			||||||
			.x = x1 - x,
 | 
					 | 
				
			||||||
			.y = y1 - y,
 | 
					 | 
				
			||||||
			.width = cursor_area.width,
 | 
					 | 
				
			||||||
			.height = cursor_area.height,
 | 
					 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
		wlr_input_popup_surface_v2_send_text_input_rectangle(
 | 
					 | 
				
			||||||
			popup->popup_surface, &box);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	wlr_scene_node_set_position(&popup->scene_tree->node, x - geo.x, y - geo.y);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void input_popup_set_focus(struct sway_input_popup *popup,
 | 
					 | 
				
			||||||
		struct wlr_surface *surface) {
 | 
					 | 
				
			||||||
	wl_list_remove(&popup->focused_surface_unmap.link);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (surface == NULL) {
 | 
					 | 
				
			||||||
		wl_list_init(&popup->focused_surface_unmap.link);
 | 
					 | 
				
			||||||
		input_popup_update(popup);
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	struct wlr_layer_surface_v1 *layer_surface =
 | 
					 | 
				
			||||||
		wlr_layer_surface_v1_try_from_wlr_surface(surface);
 | 
					 | 
				
			||||||
	if (layer_surface != NULL) {
 | 
					 | 
				
			||||||
		wl_signal_add(
 | 
					 | 
				
			||||||
			&layer_surface->surface->events.unmap, &popup->focused_surface_unmap);
 | 
					 | 
				
			||||||
		input_popup_update(popup);
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	struct sway_view *view = view_from_wlr_surface(surface);
 | 
					 | 
				
			||||||
	wl_signal_add(&view->events.unmap, &popup->focused_surface_unmap);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void handle_im_popup_destroy(struct wl_listener *listener, void *data) {
 | 
					static void handle_im_popup_destroy(struct wl_listener *listener, void *data) {
 | 
				
			||||||
	struct sway_input_popup *popup =
 | 
						struct sway_input_popup *popup =
 | 
				
			||||||
		wl_container_of(listener, popup, popup_destroy);
 | 
							wl_container_of(listener, popup, popup_destroy);
 | 
				
			||||||
 | 
						wlr_scene_node_destroy(&popup->scene_tree->node);
 | 
				
			||||||
	wl_list_remove(&popup->focused_surface_unmap.link);
 | 
						wl_list_remove(&popup->focused_surface_unmap.link);
 | 
				
			||||||
	wl_list_remove(&popup->popup_surface_commit.link);
 | 
						wl_list_remove(&popup->popup_surface_commit.link);
 | 
				
			||||||
 | 
						wl_list_remove(&popup->popup_surface_map.link);
 | 
				
			||||||
 | 
						wl_list_remove(&popup->popup_surface_unmap.link);
 | 
				
			||||||
	wl_list_remove(&popup->popup_destroy.link);
 | 
						wl_list_remove(&popup->popup_destroy.link);
 | 
				
			||||||
	wl_list_remove(&popup->link);
 | 
						wl_list_remove(&popup->link);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	free(popup);
 | 
						free(popup);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void handle_im_popup_surface_commit(struct wl_listener *listener,
 | 
					static void handle_im_popup_surface_map(struct wl_listener *listener, void *data) {
 | 
				
			||||||
		void *data) {
 | 
						struct sway_input_popup *popup =
 | 
				
			||||||
 | 
							wl_container_of(listener, popup, popup_surface_map);
 | 
				
			||||||
 | 
						struct sway_text_input *text_input = relay_get_focused_text_input(popup->relay);
 | 
				
			||||||
 | 
						if (text_input != NULL) {
 | 
				
			||||||
 | 
							input_popup_set_focus(popup, text_input->input->focused_surface);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							input_popup_set_focus(popup, NULL);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void handle_im_popup_surface_unmap(struct wl_listener *listener, void *data) {
 | 
				
			||||||
 | 
						struct sway_input_popup *popup =
 | 
				
			||||||
 | 
							wl_container_of(listener, popup, popup_surface_unmap);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						scene_descriptor_destroy(&popup->scene_tree->node, SWAY_SCENE_DESC_POPUP);
 | 
				
			||||||
 | 
						// relative should already be freed as it should be a child of the just unmapped scene
 | 
				
			||||||
 | 
						popup->desc.relative = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						input_popup_set_focus(popup, NULL);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void handle_im_popup_surface_commit(struct wl_listener *listener, void *data) {
 | 
				
			||||||
	struct sway_input_popup *popup =
 | 
						struct sway_input_popup *popup =
 | 
				
			||||||
		wl_container_of(listener, popup, popup_surface_commit);
 | 
							wl_container_of(listener, popup, popup_surface_commit);
 | 
				
			||||||
	input_popup_update(popup);
 | 
					
 | 
				
			||||||
 | 
						constrain_popup(popup);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void handle_im_focused_surface_unmap(
 | 
					static void handle_im_focused_surface_unmap(
 | 
				
			||||||
		struct wl_listener *listener, void *data) {
 | 
							struct wl_listener *listener, void *data) {
 | 
				
			||||||
	struct sway_input_popup *popup =
 | 
						struct sway_input_popup *popup =
 | 
				
			||||||
		wl_container_of(listener, popup, focused_surface_unmap);
 | 
							wl_container_of(listener, popup, focused_surface_unmap);
 | 
				
			||||||
	input_popup_update(popup);
 | 
					
 | 
				
			||||||
 | 
						input_popup_set_focus(popup, NULL);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void handle_im_new_popup_surface(struct wl_listener *listener,
 | 
					static void handle_im_new_popup_surface(struct wl_listener *listener,
 | 
				
			||||||
| 
						 | 
					@ -448,16 +481,38 @@ static void handle_im_new_popup_surface(struct wl_listener *listener,
 | 
				
			||||||
	struct sway_input_method_relay *relay = wl_container_of(listener, relay,
 | 
						struct sway_input_method_relay *relay = wl_container_of(listener, relay,
 | 
				
			||||||
		input_method_new_popup_surface);
 | 
							input_method_new_popup_surface);
 | 
				
			||||||
	struct sway_input_popup *popup = calloc(1, sizeof(*popup));
 | 
						struct sway_input_popup *popup = calloc(1, sizeof(*popup));
 | 
				
			||||||
 | 
						if (!popup) {
 | 
				
			||||||
 | 
							sway_log(SWAY_ERROR, "Failed to allocate an input method popup");
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	popup->relay = relay;
 | 
						popup->relay = relay;
 | 
				
			||||||
	popup->popup_surface = data;
 | 
						popup->popup_surface = data;
 | 
				
			||||||
	popup->popup_surface->data = popup;
 | 
						popup->popup_surface->data = popup;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wl_signal_add(
 | 
						popup->scene_tree = wlr_scene_tree_create(root->layers.popup);
 | 
				
			||||||
		&popup->popup_surface->events.destroy, &popup->popup_destroy);
 | 
						if (!popup->scene_tree) {
 | 
				
			||||||
 | 
							sway_log(SWAY_ERROR, "Failed to allocate scene tree");
 | 
				
			||||||
 | 
							free(popup);
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!wlr_scene_subsurface_tree_create(popup->scene_tree,
 | 
				
			||||||
 | 
								popup->popup_surface->surface)) {
 | 
				
			||||||
 | 
							sway_log(SWAY_ERROR, "Failed to allocate subsurface tree");
 | 
				
			||||||
 | 
							wlr_scene_node_destroy(&popup->scene_tree->node);
 | 
				
			||||||
 | 
							free(popup);
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wl_signal_add(&popup->popup_surface->events.destroy, &popup->popup_destroy);
 | 
				
			||||||
	popup->popup_destroy.notify = handle_im_popup_destroy;
 | 
						popup->popup_destroy.notify = handle_im_popup_destroy;
 | 
				
			||||||
	wl_signal_add(&popup->popup_surface->surface->events.commit,
 | 
						wl_signal_add(&popup->popup_surface->surface->events.commit, &popup->popup_surface_commit);
 | 
				
			||||||
		&popup->popup_surface_commit);
 | 
					 | 
				
			||||||
	popup->popup_surface_commit.notify = handle_im_popup_surface_commit;
 | 
						popup->popup_surface_commit.notify = handle_im_popup_surface_commit;
 | 
				
			||||||
 | 
						wl_signal_add(&popup->popup_surface->surface->events.map, &popup->popup_surface_map);
 | 
				
			||||||
 | 
						popup->popup_surface_map.notify = handle_im_popup_surface_map;
 | 
				
			||||||
 | 
						wl_signal_add(&popup->popup_surface->surface->events.unmap, &popup->popup_surface_unmap);
 | 
				
			||||||
 | 
						popup->popup_surface_unmap.notify = handle_im_popup_surface_unmap;
 | 
				
			||||||
	wl_list_init(&popup->focused_surface_unmap.link);
 | 
						wl_list_init(&popup->focused_surface_unmap.link);
 | 
				
			||||||
	popup->focused_surface_unmap.notify = handle_im_focused_surface_unmap;
 | 
						popup->focused_surface_unmap.notify = handle_im_focused_surface_unmap;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -399,6 +399,8 @@ static void ipc_json_describe_enabled_output(struct sway_output *output,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	json_object_object_add(object, "max_render_time", json_object_new_int(output->max_render_time));
 | 
						json_object_object_add(object, "max_render_time", json_object_new_int(output->max_render_time));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						json_object_object_add(object, "allow_tearing", json_object_new_boolean(output->allow_tearing));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
json_object *ipc_json_describe_disabled_output(struct sway_output *output) {
 | 
					json_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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	json_object_object_add(object, "max_render_time", json_object_new_int(c->view->max_render_time));
 | 
						json_object_object_add(object, "max_render_time", json_object_new_int(c->view->max_render_time));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						json_object_object_add(object, "allow_tearing", json_object_new_boolean(view_can_tear(c->view)));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	json_object_object_add(object, "shell", json_object_new_string(view_get_shell(c->view)));
 | 
						json_object_object_add(object, "shell", json_object_new_string(view_get_shell(c->view)));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	json_object_object_add(object, "inhibit_idle",
 | 
						json_object_object_add(object, "inhibit_idle",
 | 
				
			||||||
| 
						 | 
					@ -1129,7 +1133,9 @@ json_object *ipc_json_describe_input(struct sway_input_device *device) {
 | 
				
			||||||
		json_object *layouts_arr = json_object_new_array();
 | 
							json_object *layouts_arr = json_object_new_array();
 | 
				
			||||||
		json_object_object_add(object, "xkb_layout_names", layouts_arr);
 | 
							json_object_object_add(object, "xkb_layout_names", layouts_arr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		xkb_layout_index_t num_layouts = xkb_keymap_num_layouts(keymap);
 | 
							xkb_layout_index_t num_layouts =
 | 
				
			||||||
 | 
								keymap ? xkb_keymap_num_layouts(keymap) : 0;
 | 
				
			||||||
 | 
							// Virtual keyboards might have null keymap
 | 
				
			||||||
		xkb_layout_index_t layout_idx;
 | 
							xkb_layout_index_t layout_idx;
 | 
				
			||||||
		for (layout_idx = 0; layout_idx < num_layouts; layout_idx++) {
 | 
							for (layout_idx = 0; layout_idx < num_layouts; layout_idx++) {
 | 
				
			||||||
			const char *layout = xkb_keymap_layout_get_name(keymap, layout_idx);
 | 
								const char *layout = xkb_keymap_layout_get_name(keymap, layout_idx);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										29
									
								
								sway/lock.c
									
										
									
									
									
								
							
							
						
						
									
										29
									
								
								sway/lock.c
									
										
									
									
									
								
							| 
						 | 
					@ -8,6 +8,7 @@
 | 
				
			||||||
#include "sway/layers.h"
 | 
					#include "sway/layers.h"
 | 
				
			||||||
#include "sway/output.h"
 | 
					#include "sway/output.h"
 | 
				
			||||||
#include "sway/server.h"
 | 
					#include "sway/server.h"
 | 
				
			||||||
 | 
					#include "sway/lock.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct sway_session_lock_output {
 | 
					struct sway_session_lock_output {
 | 
				
			||||||
	struct wlr_scene_tree *tree;
 | 
						struct wlr_scene_tree *tree;
 | 
				
			||||||
| 
						 | 
					@ -19,7 +20,6 @@ struct sway_session_lock_output {
 | 
				
			||||||
	struct wl_list link; // sway_session_lock::outputs
 | 
						struct wl_list link; // sway_session_lock::outputs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wl_listener destroy;
 | 
						struct wl_listener destroy;
 | 
				
			||||||
	struct wl_listener commit;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wlr_session_lock_surface_v1 *surface;
 | 
						struct wlr_session_lock_surface_v1 *surface;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -89,6 +89,17 @@ static void lock_output_reconfigure(struct sway_session_lock_output *output) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void arrange_locks(void) {
 | 
				
			||||||
 | 
						if (server.session_lock.lock == NULL) {
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct sway_session_lock_output *lock_output;
 | 
				
			||||||
 | 
						wl_list_for_each(lock_output, &server.session_lock.lock->outputs, link) {
 | 
				
			||||||
 | 
							lock_output_reconfigure(lock_output);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void handle_new_surface(struct wl_listener *listener, void *data) {
 | 
					static void handle_new_surface(struct wl_listener *listener, void *data) {
 | 
				
			||||||
	struct sway_session_lock *lock = wl_container_of(listener, lock, new_surface);
 | 
						struct sway_session_lock *lock = wl_container_of(listener, lock, new_surface);
 | 
				
			||||||
	struct wlr_session_lock_surface_v1 *lock_surface = data;
 | 
						struct wlr_session_lock_surface_v1 *lock_surface = data;
 | 
				
			||||||
| 
						 | 
					@ -125,7 +136,6 @@ static void sway_session_lock_output_destroy(struct sway_session_lock_output *ou
 | 
				
			||||||
		wl_list_remove(&output->surface_map.link);
 | 
							wl_list_remove(&output->surface_map.link);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wl_list_remove(&output->commit.link);
 | 
					 | 
				
			||||||
	wl_list_remove(&output->destroy.link);
 | 
						wl_list_remove(&output->destroy.link);
 | 
				
			||||||
	wl_list_remove(&output->link);
 | 
						wl_list_remove(&output->link);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -138,18 +148,6 @@ static void lock_node_handle_destroy(struct wl_listener *listener, void *data) {
 | 
				
			||||||
	sway_session_lock_output_destroy(output);
 | 
						sway_session_lock_output_destroy(output);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void lock_output_handle_commit(struct wl_listener *listener, void *data) {
 | 
					 | 
				
			||||||
	struct wlr_output_event_commit *event = data;
 | 
					 | 
				
			||||||
	struct sway_session_lock_output *output =
 | 
					 | 
				
			||||||
		wl_container_of(listener, output, commit);
 | 
					 | 
				
			||||||
	if (event->state->committed & (
 | 
					 | 
				
			||||||
			WLR_OUTPUT_STATE_MODE |
 | 
					 | 
				
			||||||
			WLR_OUTPUT_STATE_SCALE |
 | 
					 | 
				
			||||||
			WLR_OUTPUT_STATE_TRANSFORM)) {
 | 
					 | 
				
			||||||
		lock_output_reconfigure(output);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static struct sway_session_lock_output *session_lock_output_create(
 | 
					static struct sway_session_lock_output *session_lock_output_create(
 | 
				
			||||||
		struct sway_session_lock *lock, struct sway_output *output) {
 | 
							struct sway_session_lock *lock, struct sway_output *output) {
 | 
				
			||||||
	struct sway_session_lock_output *lock_output = calloc(1, sizeof(*lock_output));
 | 
						struct sway_session_lock_output *lock_output = calloc(1, sizeof(*lock_output));
 | 
				
			||||||
| 
						 | 
					@ -186,9 +184,6 @@ static struct sway_session_lock_output *session_lock_output_create(
 | 
				
			||||||
	lock_output->destroy.notify = lock_node_handle_destroy;
 | 
						lock_output->destroy.notify = lock_node_handle_destroy;
 | 
				
			||||||
	wl_signal_add(&tree->node.events.destroy, &lock_output->destroy);
 | 
						wl_signal_add(&tree->node.events.destroy, &lock_output->destroy);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	lock_output->commit.notify = lock_output_handle_commit;
 | 
					 | 
				
			||||||
	wl_signal_add(&output->wlr_output->events.commit, &lock_output->commit);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	lock_output_reconfigure(lock_output);
 | 
						lock_output_reconfigure(lock_output);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wl_list_insert(&lock->outputs, &lock_output->link);
 | 
						wl_list_insert(&lock->outputs, &lock_output->link);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -18,6 +18,7 @@ sway_sources = files(
 | 
				
			||||||
	'desktop/idle_inhibit_v1.c',
 | 
						'desktop/idle_inhibit_v1.c',
 | 
				
			||||||
	'desktop/layer_shell.c',
 | 
						'desktop/layer_shell.c',
 | 
				
			||||||
	'desktop/output.c',
 | 
						'desktop/output.c',
 | 
				
			||||||
 | 
						'desktop/tearing.c',
 | 
				
			||||||
	'desktop/transaction.c',
 | 
						'desktop/transaction.c',
 | 
				
			||||||
	'desktop/xdg_shell.c',
 | 
						'desktop/xdg_shell.c',
 | 
				
			||||||
	'desktop/launcher.c',
 | 
						'desktop/launcher.c',
 | 
				
			||||||
| 
						 | 
					@ -41,6 +42,7 @@ sway_sources = files(
 | 
				
			||||||
	'config/seat.c',
 | 
						'config/seat.c',
 | 
				
			||||||
	'config/input.c',
 | 
						'config/input.c',
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						'commands/allow_tearing.c',
 | 
				
			||||||
	'commands/assign.c',
 | 
						'commands/assign.c',
 | 
				
			||||||
	'commands/bar.c',
 | 
						'commands/bar.c',
 | 
				
			||||||
	'commands/bind.c',
 | 
						'commands/bind.c',
 | 
				
			||||||
| 
						 | 
					@ -188,6 +190,7 @@ sway_sources = files(
 | 
				
			||||||
	'commands/input/xkb_variant.c',
 | 
						'commands/input/xkb_variant.c',
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	'commands/output/adaptive_sync.c',
 | 
						'commands/output/adaptive_sync.c',
 | 
				
			||||||
 | 
						'commands/output/allow_tearing.c',
 | 
				
			||||||
	'commands/output/background.c',
 | 
						'commands/output/background.c',
 | 
				
			||||||
	'commands/output/disable.c',
 | 
						'commands/output/disable.c',
 | 
				
			||||||
	'commands/output/dpms.c',
 | 
						'commands/output/dpms.c',
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -39,6 +39,9 @@ void *scene_descriptor_try_get(struct wlr_scene_node *node,
 | 
				
			||||||
void scene_descriptor_destroy(struct wlr_scene_node *node,
 | 
					void scene_descriptor_destroy(struct wlr_scene_node *node,
 | 
				
			||||||
		enum sway_scene_descriptor_type type) {
 | 
							enum sway_scene_descriptor_type type) {
 | 
				
			||||||
	struct scene_descriptor *desc = scene_node_get_descriptor(node, type);
 | 
						struct scene_descriptor *desc = scene_node_get_descriptor(node, type);
 | 
				
			||||||
 | 
						if (!desc) {
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	descriptor_destroy(desc);
 | 
						descriptor_destroy(desc);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -9,6 +9,7 @@
 | 
				
			||||||
#include <wlr/config.h>
 | 
					#include <wlr/config.h>
 | 
				
			||||||
#include <wlr/render/allocator.h>
 | 
					#include <wlr/render/allocator.h>
 | 
				
			||||||
#include <wlr/render/wlr_renderer.h>
 | 
					#include <wlr/render/wlr_renderer.h>
 | 
				
			||||||
 | 
					#include <wlr/types/wlr_alpha_modifier_v1.h>
 | 
				
			||||||
#include <wlr/types/wlr_compositor.h>
 | 
					#include <wlr/types/wlr_compositor.h>
 | 
				
			||||||
#include <wlr/types/wlr_content_type_v1.h>
 | 
					#include <wlr/types/wlr_content_type_v1.h>
 | 
				
			||||||
#include <wlr/types/wlr_cursor_shape_v1.h>
 | 
					#include <wlr/types/wlr_cursor_shape_v1.h>
 | 
				
			||||||
| 
						 | 
					@ -203,8 +204,8 @@ static void handle_renderer_lost(struct wl_listener *listener, void *data) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wlr_compositor_set_renderer(server->compositor, renderer);
 | 
						wlr_compositor_set_renderer(server->compositor, renderer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (int i = 0; i < root->outputs->length; ++i) {
 | 
						struct sway_output *output;
 | 
				
			||||||
		struct sway_output *output = root->outputs->items[i];
 | 
						wl_list_for_each(output, &root->all_outputs, link) {
 | 
				
			||||||
		wlr_output_init_render(output->wlr_output,
 | 
							wlr_output_init_render(output->wlr_output,
 | 
				
			||||||
			server->allocator, server->renderer);
 | 
								server->allocator, server->renderer);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -272,9 +273,6 @@ bool server_init(struct sway_server *server) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	server->new_output.notify = handle_new_output;
 | 
						server->new_output.notify = handle_new_output;
 | 
				
			||||||
	wl_signal_add(&server->backend->events.new_output, &server->new_output);
 | 
						wl_signal_add(&server->backend->events.new_output, &server->new_output);
 | 
				
			||||||
	server->output_layout_change.notify = handle_output_layout_change;
 | 
					 | 
				
			||||||
	wl_signal_add(&root->output_layout->events.change,
 | 
					 | 
				
			||||||
		&server->output_layout_change);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	server->xdg_output_manager_v1 =
 | 
						server->xdg_output_manager_v1 =
 | 
				
			||||||
		wlr_xdg_output_manager_v1_create(server->wl_display, root->output_layout);
 | 
							wlr_xdg_output_manager_v1_create(server->wl_display, root->output_layout);
 | 
				
			||||||
| 
						 | 
					@ -324,6 +322,7 @@ bool server_init(struct sway_server *server) {
 | 
				
			||||||
		&server->pointer_constraint);
 | 
							&server->pointer_constraint);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wlr_presentation_create(server->wl_display, server->backend);
 | 
						wlr_presentation_create(server->wl_display, server->backend);
 | 
				
			||||||
 | 
						wlr_alpha_modifier_v1_create(server->wl_display);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	server->output_manager_v1 =
 | 
						server->output_manager_v1 =
 | 
				
			||||||
		wlr_output_manager_v1_create(server->wl_display);
 | 
							wlr_output_manager_v1_create(server->wl_display);
 | 
				
			||||||
| 
						 | 
					@ -372,6 +371,13 @@ bool server_init(struct sway_server *server) {
 | 
				
			||||||
		wlr_content_type_manager_v1_create(server->wl_display, 1);
 | 
							wlr_content_type_manager_v1_create(server->wl_display, 1);
 | 
				
			||||||
	wlr_fractional_scale_manager_v1_create(server->wl_display, 1);
 | 
						wlr_fractional_scale_manager_v1_create(server->wl_display, 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						server->tearing_control_v1 =
 | 
				
			||||||
 | 
							wlr_tearing_control_manager_v1_create(server->wl_display, 1);
 | 
				
			||||||
 | 
						server->tearing_control_new_object.notify = handle_new_tearing_hint;
 | 
				
			||||||
 | 
						wl_signal_add(&server->tearing_control_v1->events.new_object,
 | 
				
			||||||
 | 
							&server->tearing_control_new_object);
 | 
				
			||||||
 | 
						wl_list_init(&server->tearing_controllers);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wlr_xdg_foreign_registry *foreign_registry =
 | 
						struct wlr_xdg_foreign_registry *foreign_registry =
 | 
				
			||||||
		wlr_xdg_foreign_registry_create(server->wl_display);
 | 
							wlr_xdg_foreign_registry_create(server->wl_display);
 | 
				
			||||||
	wlr_xdg_foreign_v1_create(server->wl_display, foreign_registry);
 | 
						wlr_xdg_foreign_v1_create(server->wl_display, foreign_registry);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -154,7 +154,7 @@ must be separated by one space. For example:
 | 
				
			||||||
	This setting only has an effect on Wayland and DRM backends, as support for
 | 
						This setting only has an effect on Wayland and DRM backends, as support for
 | 
				
			||||||
	presentation timestamps and predicted output refresh rate is required.
 | 
						presentation timestamps and predicted output refresh rate is required.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
*output* <name> adaptive_sync on|off
 | 
					*output* <name> adaptive_sync on|off|toggle
 | 
				
			||||||
	Enables or disables adaptive synchronization (often referred to as Variable
 | 
						Enables or disables adaptive synchronization (often referred to as Variable
 | 
				
			||||||
	Refresh Rate, or by the vendor-specific names FreeSync/G-Sync).
 | 
						Refresh Rate, or by the vendor-specific names FreeSync/G-Sync).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -163,9 +163,9 @@ must be separated by one space. For example:
 | 
				
			||||||
	adaptive sync can improve latency, but can cause flickering on some
 | 
						adaptive sync can improve latency, but can cause flickering on some
 | 
				
			||||||
	hardware.
 | 
						hardware.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
*output* <name> render_bit_depth 8|10
 | 
					*output* <name> render_bit_depth 6|8|10
 | 
				
			||||||
	Controls the color channel bit depth at which frames are rendered; the
 | 
						Controls the maximum color channel bit depth at which frames are
 | 
				
			||||||
	default is currently 8 bits per channel.
 | 
						rendered; the default is currently 8 bits per channel.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Setting higher values will not have an effect if hardware and software lack
 | 
						Setting higher values will not have an effect if hardware and software lack
 | 
				
			||||||
	support for such bit depths. Successfully increasing the render bit depth
 | 
						support for such bit depths. Successfully increasing the render bit depth
 | 
				
			||||||
| 
						 | 
					@ -190,6 +190,26 @@ must be separated by one space. For example:
 | 
				
			||||||
	may have no effect or produce unexpected output when used together with future
 | 
						may have no effect or produce unexpected output when used together with future
 | 
				
			||||||
	HDR support features.
 | 
						HDR support features.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*output* <name> allow_tearing yes|no
 | 
				
			||||||
 | 
						Allows or disallows screen tearing as a result of immediate page flips,
 | 
				
			||||||
 | 
						and an immediate presentation mode from a client. The default is that no
 | 
				
			||||||
 | 
						screen tearing is allowed.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						With immediate page flips, frames from the client are presented as soon
 | 
				
			||||||
 | 
						as possible instead of synchronizing with the monitor's vblank interval 
 | 
				
			||||||
 | 
						(VSync). 
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						It is recommended to set *max_render_time* to *off*. In that case a page flip
 | 
				
			||||||
 | 
						happens as soon as a client updates. Otherwise, tearing will only happen if
 | 
				
			||||||
 | 
						rendering takes longer than the configured milliseconds before the next
 | 
				
			||||||
 | 
						display refresh.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						To adjust whether tearing is allowed for specific applications, see
 | 
				
			||||||
 | 
						*allow_tearing* in *sway*(5). Note that tearing will only be enabled
 | 
				
			||||||
 | 
						when it's allowed for both the output and the application.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						This setting only has effect when a window is fullscreen on the output.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# SEE ALSO
 | 
					# SEE ALSO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
*sway*(5) *sway-input*(5)
 | 
					*sway*(5) *sway-input*(5)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -57,6 +57,7 @@ which you may only select one. *[...]* is used for optional arguments, and
 | 
				
			||||||
This section only lists general commands. For input and output commands, refer
 | 
					This section only lists general commands. For input and output commands, refer
 | 
				
			||||||
to *sway-input*(5) and *sway-output*(5).
 | 
					to *sway-input*(5) and *sway-output*(5).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Config only commands
 | 
				
			||||||
The following commands may only be used in the configuration file.
 | 
					The following commands may only be used in the configuration file.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
*bar* [<bar-id>] <bar-subcommands...>
 | 
					*bar* [<bar-id>] <bar-subcommands...>
 | 
				
			||||||
| 
						 | 
					@ -98,6 +99,7 @@ The following commands may only be used in the configuration file.
 | 
				
			||||||
	machines, it may be desirable to have Xwayland started immediately by
 | 
						machines, it may be desirable to have Xwayland started immediately by
 | 
				
			||||||
	using _force_ instead of _enable_.
 | 
						using _force_ instead of _enable_.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Runtime only commands
 | 
				
			||||||
The following commands cannot be used directly in the configuration file.
 | 
					The following commands cannot be used directly in the configuration file.
 | 
				
			||||||
They are expected to be used with *bindsym* or at runtime through *swaymsg*(1).
 | 
					They are expected to be used with *bindsym* or at runtime through *swaymsg*(1).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -215,6 +217,20 @@ set|plus|minus|toggle <amount>
 | 
				
			||||||
	effect on the output the window is currently on. See *sway-output*(5) for
 | 
						effect on the output the window is currently on. See *sway-output*(5) for
 | 
				
			||||||
	further details.
 | 
						further details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*allow_tearing* yes|no
 | 
				
			||||||
 | 
						Allows or disallows screen tearing as a result of immediate page flips
 | 
				
			||||||
 | 
						for a fullscreen application.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						When this option is not set, the tearing hints provided by the application
 | 
				
			||||||
 | 
						determine whether tearing is allowed. When _yes_ is specified,
 | 
				
			||||||
 | 
						the application allows tearing regardless of the tearing hints.
 | 
				
			||||||
 | 
						When _no_ is specified, tearing will never be allowed on the application,
 | 
				
			||||||
 | 
						regardless of the tearing hints.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						This setting only has an effect if tearing is allowed on the output through
 | 
				
			||||||
 | 
						the per-output *allow_tearing* setting. See *sway-output*(5) 
 | 
				
			||||||
 | 
						for further details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
*move* left|right|up|down [<px> px]
 | 
					*move* left|right|up|down [<px> px]
 | 
				
			||||||
	Moves the focused container in the direction specified. The optional _px_
 | 
						Moves the focused container in the direction specified. The optional _px_
 | 
				
			||||||
	argument specifies how many pixels to move the container. If unspecified,
 | 
						argument specifies how many pixels to move the container. If unspecified,
 | 
				
			||||||
| 
						 | 
					@ -371,6 +387,7 @@ set|plus|minus|toggle <amount>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	The default format is "%title".
 | 
						The default format is "%title".
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Config or runtime commands
 | 
				
			||||||
The following commands may be used either in the configuration file or at
 | 
					The following commands may be used either in the configuration file or at
 | 
				
			||||||
runtime.
 | 
					runtime.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -314,14 +314,9 @@ void arrange_output(struct sway_output *output) {
 | 
				
			||||||
	if (config->reloading) {
 | 
						if (config->reloading) {
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	struct wlr_box output_box;
 | 
						if (!output->wlr_output->enabled) {
 | 
				
			||||||
	wlr_output_layout_get_box(root->output_layout,
 | 
							return;
 | 
				
			||||||
		output->wlr_output, &output_box);
 | 
						}
 | 
				
			||||||
	output->lx = output_box.x;
 | 
					 | 
				
			||||||
	output->ly = output_box.y;
 | 
					 | 
				
			||||||
	output->width = output_box.width;
 | 
					 | 
				
			||||||
	output->height = output_box.height;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for (int i = 0; i < output->workspaces->length; ++i) {
 | 
						for (int i = 0; i < output->workspaces->length; ++i) {
 | 
				
			||||||
		struct sway_workspace *workspace = output->workspaces->items[i];
 | 
							struct sway_workspace *workspace = output->workspaces->items[i];
 | 
				
			||||||
		arrange_workspace(workspace);
 | 
							arrange_workspace(workspace);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -22,6 +22,7 @@
 | 
				
			||||||
#include "sway/tree/workspace.h"
 | 
					#include "sway/tree/workspace.h"
 | 
				
			||||||
#include "sway/xdg_decoration.h"
 | 
					#include "sway/xdg_decoration.h"
 | 
				
			||||||
#include "list.h"
 | 
					#include "list.h"
 | 
				
			||||||
 | 
					#include "pango.h"
 | 
				
			||||||
#include "log.h"
 | 
					#include "log.h"
 | 
				
			||||||
#include "stringop.h"
 | 
					#include "stringop.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -499,6 +500,7 @@ void container_destroy(struct sway_container *con) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	free(con->title);
 | 
						free(con->title);
 | 
				
			||||||
	free(con->formatted_title);
 | 
						free(con->formatted_title);
 | 
				
			||||||
 | 
						free(con->title_format);
 | 
				
			||||||
	list_free(con->pending.children);
 | 
						list_free(con->pending.children);
 | 
				
			||||||
	list_free(con->current.children);
 | 
						list_free(con->current.children);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -645,6 +647,91 @@ bool container_has_ancestor(struct sway_container *descendant,
 | 
				
			||||||
	return false;
 | 
						return false;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static char *escape_pango_markup(const char *buffer) {
 | 
				
			||||||
 | 
						size_t length = escape_markup_text(buffer, NULL);
 | 
				
			||||||
 | 
						char *escaped_title = calloc(length + 1, sizeof(char));
 | 
				
			||||||
 | 
						escape_markup_text(buffer, escaped_title);
 | 
				
			||||||
 | 
						return escaped_title;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static size_t append_prop(char *buffer, const char *value) {
 | 
				
			||||||
 | 
						if (!value) {
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						// If using pango_markup in font, we need to escape all markup chars
 | 
				
			||||||
 | 
						// from values to make sure tags are not inserted by clients
 | 
				
			||||||
 | 
						if (config->pango_markup) {
 | 
				
			||||||
 | 
							char *escaped_value = escape_pango_markup(value);
 | 
				
			||||||
 | 
							lenient_strcat(buffer, escaped_value);
 | 
				
			||||||
 | 
							size_t len = strlen(escaped_value);
 | 
				
			||||||
 | 
							free(escaped_value);
 | 
				
			||||||
 | 
							return len;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							lenient_strcat(buffer, value);
 | 
				
			||||||
 | 
							return strlen(value);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Calculate and return the length of the formatted title.
 | 
				
			||||||
 | 
					 * If buffer is not NULL, also populate the buffer with the formatted title.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					size_t parse_title_format(struct sway_container *container, char *buffer) {
 | 
				
			||||||
 | 
						if (!container->title_format || strcmp(container->title_format, "%title") == 0) {
 | 
				
			||||||
 | 
							if (container->view) {
 | 
				
			||||||
 | 
								return append_prop(buffer, view_get_title(container->view));
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								return container_build_representation(container->pending.layout, container->pending.children, buffer);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						size_t len = 0;
 | 
				
			||||||
 | 
						char *format = container->title_format;
 | 
				
			||||||
 | 
						char *next = strchr(format, '%');
 | 
				
			||||||
 | 
						while (next) {
 | 
				
			||||||
 | 
							// Copy everything up to the %
 | 
				
			||||||
 | 
							lenient_strncat(buffer, format, next - format);
 | 
				
			||||||
 | 
							len += next - format;
 | 
				
			||||||
 | 
							format = next;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (strncmp(next, "%title", 6) == 0) {
 | 
				
			||||||
 | 
								if (container->view) {
 | 
				
			||||||
 | 
									len += append_prop(buffer, view_get_title(container->view));
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									len += container_build_representation(container->pending.layout, container->pending.children, buffer);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								format += 6;
 | 
				
			||||||
 | 
							} else if (container->view) {
 | 
				
			||||||
 | 
								if (strncmp(next, "%app_id", 7) == 0) {
 | 
				
			||||||
 | 
									len += append_prop(buffer, view_get_app_id(container->view));
 | 
				
			||||||
 | 
									format += 7;
 | 
				
			||||||
 | 
								} else if (strncmp(next, "%class", 6) == 0) {
 | 
				
			||||||
 | 
									len += append_prop(buffer, view_get_class(container->view));
 | 
				
			||||||
 | 
									format += 6;
 | 
				
			||||||
 | 
								} else if (strncmp(next, "%instance", 9) == 0) {
 | 
				
			||||||
 | 
									len += append_prop(buffer, view_get_instance(container->view));
 | 
				
			||||||
 | 
									format += 9;
 | 
				
			||||||
 | 
								} else if (strncmp(next, "%shell", 6) == 0) {
 | 
				
			||||||
 | 
									len += append_prop(buffer, view_get_shell(container->view));
 | 
				
			||||||
 | 
									format += 6;
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									lenient_strcat(buffer, "%");
 | 
				
			||||||
 | 
									++format;
 | 
				
			||||||
 | 
									++len;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								lenient_strcat(buffer, "%");
 | 
				
			||||||
 | 
								++format;
 | 
				
			||||||
 | 
								++len;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							next = strchr(format, '%');
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						lenient_strcat(buffer, format);
 | 
				
			||||||
 | 
						len += strlen(format);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return len;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Calculate and return the length of the tree representation.
 | 
					 * Calculate and return the length of the tree representation.
 | 
				
			||||||
 * An example tree representation is: V[Terminal, Firefox]
 | 
					 * An example tree representation is: V[Terminal, Firefox]
 | 
				
			||||||
| 
						 | 
					@ -700,16 +787,14 @@ size_t container_build_representation(enum sway_container_layout layout,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void container_update_representation(struct sway_container *con) {
 | 
					void container_update_representation(struct sway_container *con) {
 | 
				
			||||||
	if (!con->view) {
 | 
						if (!con->view) {
 | 
				
			||||||
		size_t len = container_build_representation(con->pending.layout,
 | 
							size_t len = parse_title_format(con, NULL);
 | 
				
			||||||
				con->pending.children, NULL);
 | 
					 | 
				
			||||||
		free(con->formatted_title);
 | 
							free(con->formatted_title);
 | 
				
			||||||
		con->formatted_title = calloc(len + 1, sizeof(char));
 | 
							con->formatted_title = calloc(len + 1, sizeof(char));
 | 
				
			||||||
		if (!sway_assert(con->formatted_title,
 | 
							if (!sway_assert(con->formatted_title,
 | 
				
			||||||
					"Unable to allocate title string")) {
 | 
										"Unable to allocate title string")) {
 | 
				
			||||||
			return;
 | 
								return;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		container_build_representation(con->pending.layout, con->pending.children,
 | 
							parse_title_format(con, con->formatted_title);
 | 
				
			||||||
				con->formatted_title);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (con->title_bar.title_text) {
 | 
							if (con->title_bar.title_text) {
 | 
				
			||||||
			sway_text_node_set_text(con->title_bar.title_text, con->formatted_title);
 | 
								sway_text_node_set_text(con->title_bar.title_text, con->formatted_title);
 | 
				
			||||||
| 
						 | 
					@ -773,11 +858,11 @@ void floating_fix_coordinates(struct sway_container *con, struct wlr_box *old, s
 | 
				
			||||||
		// Fall back to centering on the workspace.
 | 
							// Fall back to centering on the workspace.
 | 
				
			||||||
		container_floating_move_to_center(con);
 | 
							container_floating_move_to_center(con);
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		int rel_x = con->pending.x - old->x + (con->pending.width / 2);
 | 
							double rel_x = con->pending.x - old->x + (con->pending.width / 2);
 | 
				
			||||||
		int rel_y = con->pending.y - old->y + (con->pending.height / 2);
 | 
							double rel_y = con->pending.y - old->y + (con->pending.height / 2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		con->pending.x = new->x + (double)(rel_x * new->width) / old->width - (con->pending.width / 2);
 | 
							con->pending.x = new->x + (rel_x * new->width) / old->width - (con->pending.width / 2);
 | 
				
			||||||
		con->pending.y = new->y + (double)(rel_y * new->height) / old->height - (con->pending.height / 2);
 | 
							con->pending.y = new->y + (rel_y * new->height) / old->height - (con->pending.height / 2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		sway_log(SWAY_DEBUG, "Transformed container %p to coords (%f, %f)", con, con->pending.x, con->pending.y);
 | 
							sway_log(SWAY_DEBUG, "Transformed container %p to coords (%f, %f)", con, con->pending.x, con->pending.y);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -180,12 +180,7 @@ void output_enable(struct sway_output *output) {
 | 
				
			||||||
		ws->layout = output_get_default_layout(output);
 | 
							ws->layout = output_get_default_layout(output);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	input_manager_configure_xcursor();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	wl_signal_emit_mutable(&root->events.new_node, &output->node);
 | 
						wl_signal_emit_mutable(&root->events.new_node, &output->node);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	arrange_layers(output);
 | 
					 | 
				
			||||||
	arrange_root();
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void evacuate_sticky(struct sway_workspace *old_ws,
 | 
					static void evacuate_sticky(struct sway_workspace *old_ws,
 | 
				
			||||||
| 
						 | 
					@ -300,13 +295,6 @@ void output_disable(struct sway_output *output) {
 | 
				
			||||||
	list_del(root->outputs, index);
 | 
						list_del(root->outputs, index);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	output->enabled = false;
 | 
						output->enabled = false;
 | 
				
			||||||
 | 
					 | 
				
			||||||
	arrange_root();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Reconfigure all devices, since devices with map_to_output directives for
 | 
					 | 
				
			||||||
	// an output that goes offline should stop sending events as long as the
 | 
					 | 
				
			||||||
	// output remains offline.
 | 
					 | 
				
			||||||
	input_manager_configure_all_input_mappings();
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void output_begin_destroy(struct sway_output *output) {
 | 
					void output_begin_destroy(struct sway_output *output) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -19,12 +19,6 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct sway_root *root;
 | 
					struct sway_root *root;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void output_layout_handle_change(struct wl_listener *listener,
 | 
					 | 
				
			||||||
		void *data) {
 | 
					 | 
				
			||||||
	arrange_root();
 | 
					 | 
				
			||||||
	transaction_commit_dirty();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct sway_root *root_create(struct wl_display *wl_display) {
 | 
					struct sway_root *root_create(struct wl_display *wl_display) {
 | 
				
			||||||
	struct sway_root *root = calloc(1, sizeof(struct sway_root));
 | 
						struct sway_root *root = calloc(1, sizeof(struct sway_root));
 | 
				
			||||||
	if (!root) {
 | 
						if (!root) {
 | 
				
			||||||
| 
						 | 
					@ -81,14 +75,10 @@ struct sway_root *root_create(struct wl_display *wl_display) {
 | 
				
			||||||
	root->non_desktop_outputs = create_list();
 | 
						root->non_desktop_outputs = create_list();
 | 
				
			||||||
	root->scratchpad = create_list();
 | 
						root->scratchpad = create_list();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	root->output_layout_change.notify = output_layout_handle_change;
 | 
					 | 
				
			||||||
	wl_signal_add(&root->output_layout->events.change,
 | 
					 | 
				
			||||||
		&root->output_layout_change);
 | 
					 | 
				
			||||||
	return root;
 | 
						return root;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void root_destroy(struct sway_root *root) {
 | 
					void root_destroy(struct sway_root *root) {
 | 
				
			||||||
	wl_list_remove(&root->output_layout_change.link);
 | 
					 | 
				
			||||||
	list_free(root->scratchpad);
 | 
						list_free(root->scratchpad);
 | 
				
			||||||
	list_free(root->non_desktop_outputs);
 | 
						list_free(root->non_desktop_outputs);
 | 
				
			||||||
	list_free(root->outputs);
 | 
						list_free(root->outputs);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -34,7 +34,6 @@
 | 
				
			||||||
#include "sway/tree/workspace.h"
 | 
					#include "sway/tree/workspace.h"
 | 
				
			||||||
#include "sway/config.h"
 | 
					#include "sway/config.h"
 | 
				
			||||||
#include "sway/xdg_decoration.h"
 | 
					#include "sway/xdg_decoration.h"
 | 
				
			||||||
#include "pango.h"
 | 
					 | 
				
			||||||
#include "stringop.h"
 | 
					#include "stringop.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool view_init(struct sway_view *view, enum sway_view_type type,
 | 
					bool view_init(struct sway_view *view, enum sway_view_type type,
 | 
				
			||||||
| 
						 | 
					@ -58,6 +57,7 @@ bool view_init(struct sway_view *view, enum sway_view_type type,
 | 
				
			||||||
	view->executed_criteria = create_list();
 | 
						view->executed_criteria = create_list();
 | 
				
			||||||
	view->allow_request_urgent = true;
 | 
						view->allow_request_urgent = true;
 | 
				
			||||||
	view->shortcuts_inhibit = SHORTCUTS_INHIBIT_DEFAULT;
 | 
						view->shortcuts_inhibit = SHORTCUTS_INHIBIT_DEFAULT;
 | 
				
			||||||
 | 
						view->tearing_mode = TEARING_WINDOW_HINT;
 | 
				
			||||||
	wl_signal_init(&view->events.unmap);
 | 
						wl_signal_init(&view->events.unmap);
 | 
				
			||||||
	return true;
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -80,8 +80,6 @@ void view_destroy(struct sway_view *view) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	view_assign_ctx(view, NULL);
 | 
						view_assign_ctx(view, NULL);
 | 
				
			||||||
	wlr_scene_node_destroy(&view->scene_tree->node);
 | 
						wlr_scene_node_destroy(&view->scene_tree->node);
 | 
				
			||||||
	free(view->title_format);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (view->impl->destroy) {
 | 
						if (view->impl->destroy) {
 | 
				
			||||||
		view->impl->destroy(view);
 | 
							view->impl->destroy(view);
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
| 
						 | 
					@ -990,77 +988,6 @@ struct sway_view *view_from_wlr_surface(struct wlr_surface *wlr_surface) {
 | 
				
			||||||
	return NULL;
 | 
						return NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static char *escape_pango_markup(const char *buffer) {
 | 
					 | 
				
			||||||
	size_t length = escape_markup_text(buffer, NULL);
 | 
					 | 
				
			||||||
	char *escaped_title = calloc(length + 1, sizeof(char));
 | 
					 | 
				
			||||||
	escape_markup_text(buffer, escaped_title);
 | 
					 | 
				
			||||||
	return escaped_title;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static size_t append_prop(char *buffer, const char *value) {
 | 
					 | 
				
			||||||
	if (!value) {
 | 
					 | 
				
			||||||
		return 0;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	// If using pango_markup in font, we need to escape all markup chars
 | 
					 | 
				
			||||||
	// from values to make sure tags are not inserted by clients
 | 
					 | 
				
			||||||
	if (config->pango_markup) {
 | 
					 | 
				
			||||||
		char *escaped_value = escape_pango_markup(value);
 | 
					 | 
				
			||||||
		lenient_strcat(buffer, escaped_value);
 | 
					 | 
				
			||||||
		size_t len = strlen(escaped_value);
 | 
					 | 
				
			||||||
		free(escaped_value);
 | 
					 | 
				
			||||||
		return len;
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		lenient_strcat(buffer, value);
 | 
					 | 
				
			||||||
		return strlen(value);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Calculate and return the length of the formatted title.
 | 
					 | 
				
			||||||
 * If buffer is not NULL, also populate the buffer with the formatted title.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
static size_t parse_title_format(struct sway_view *view, char *buffer) {
 | 
					 | 
				
			||||||
	if (!view->title_format || strcmp(view->title_format, "%title") == 0) {
 | 
					 | 
				
			||||||
		return append_prop(buffer, view_get_title(view));
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	size_t len = 0;
 | 
					 | 
				
			||||||
	char *format = view->title_format;
 | 
					 | 
				
			||||||
	char *next = strchr(format, '%');
 | 
					 | 
				
			||||||
	while (next) {
 | 
					 | 
				
			||||||
		// Copy everything up to the %
 | 
					 | 
				
			||||||
		lenient_strncat(buffer, format, next - format);
 | 
					 | 
				
			||||||
		len += next - format;
 | 
					 | 
				
			||||||
		format = next;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (strncmp(next, "%title", 6) == 0) {
 | 
					 | 
				
			||||||
			len += append_prop(buffer, view_get_title(view));
 | 
					 | 
				
			||||||
			format += 6;
 | 
					 | 
				
			||||||
		} else if (strncmp(next, "%app_id", 7) == 0) {
 | 
					 | 
				
			||||||
			len += append_prop(buffer, view_get_app_id(view));
 | 
					 | 
				
			||||||
			format += 7;
 | 
					 | 
				
			||||||
		} else if (strncmp(next, "%class", 6) == 0) {
 | 
					 | 
				
			||||||
			len += append_prop(buffer, view_get_class(view));
 | 
					 | 
				
			||||||
			format += 6;
 | 
					 | 
				
			||||||
		} else if (strncmp(next, "%instance", 9) == 0) {
 | 
					 | 
				
			||||||
			len += append_prop(buffer, view_get_instance(view));
 | 
					 | 
				
			||||||
			format += 9;
 | 
					 | 
				
			||||||
		} else if (strncmp(next, "%shell", 6) == 0) {
 | 
					 | 
				
			||||||
			len += append_prop(buffer, view_get_shell(view));
 | 
					 | 
				
			||||||
			format += 6;
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			lenient_strcat(buffer, "%");
 | 
					 | 
				
			||||||
			++format;
 | 
					 | 
				
			||||||
			++len;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		next = strchr(format, '%');
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	lenient_strcat(buffer, format);
 | 
					 | 
				
			||||||
	len += strlen(format);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return len;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void view_update_app_id(struct sway_view *view) {
 | 
					void view_update_app_id(struct sway_view *view) {
 | 
				
			||||||
	const char *app_id = view_get_app_id(view);
 | 
						const char *app_id = view_get_app_id(view);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1089,7 +1016,7 @@ void view_update_title(struct sway_view *view, bool force) {
 | 
				
			||||||
	free(view->container->title);
 | 
						free(view->container->title);
 | 
				
			||||||
	free(view->container->formatted_title);
 | 
						free(view->container->formatted_title);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	size_t len = parse_title_format(view, NULL);
 | 
						size_t len = parse_title_format(view->container, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (len) {
 | 
						if (len) {
 | 
				
			||||||
		char *buffer = calloc(len + 1, sizeof(char));
 | 
							char *buffer = calloc(len + 1, sizeof(char));
 | 
				
			||||||
| 
						 | 
					@ -1097,7 +1024,7 @@ void view_update_title(struct sway_view *view, bool force) {
 | 
				
			||||||
			return;
 | 
								return;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		parse_title_format(view, buffer);
 | 
							parse_title_format(view->container, buffer);
 | 
				
			||||||
		view->container->formatted_title = buffer;
 | 
							view->container->formatted_title = buffer;
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		view->container->formatted_title = NULL;
 | 
							view->container->formatted_title = NULL;
 | 
				
			||||||
| 
						 | 
					@ -1260,6 +1187,19 @@ bool view_is_transient_for(struct sway_view *child,
 | 
				
			||||||
		child->impl->is_transient_for(child, ancestor);
 | 
							child->impl->is_transient_for(child, ancestor);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool view_can_tear(struct sway_view *view) {
 | 
				
			||||||
 | 
						switch (view->tearing_mode) {
 | 
				
			||||||
 | 
						case TEARING_OVERRIDE_FALSE:
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						case TEARING_OVERRIDE_TRUE:
 | 
				
			||||||
 | 
							return true;
 | 
				
			||||||
 | 
						case TEARING_WINDOW_HINT:
 | 
				
			||||||
 | 
							return view->tearing_hint ==
 | 
				
			||||||
 | 
								WP_TEARING_CONTROL_V1_PRESENTATION_HINT_ASYNC;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void send_frame_done_iterator(struct wlr_scene_buffer *scene_buffer,
 | 
					static void send_frame_done_iterator(struct wlr_scene_buffer *scene_buffer,
 | 
				
			||||||
		int x, int y, void *data) {
 | 
							int x, int y, void *data) {
 | 
				
			||||||
	struct timespec *when = data;
 | 
						struct timespec *when = data;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -508,7 +508,7 @@ void bar_run(struct swaybar *bar) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
#if HAVE_TRAY
 | 
					#if HAVE_TRAY
 | 
				
			||||||
	if (bar->tray) {
 | 
						if (bar->tray) {
 | 
				
			||||||
		loop_add_fd(bar->eventloop, bar->tray->fd, POLLIN, tray_in, bar->tray->bus);
 | 
							loop_add_fd(bar->eventloop, bar->tray->fd, POLLIN, tray_in, bar);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
	while (bar->running) {
 | 
						while (bar->running) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -518,8 +518,7 @@ static bool handle_barconfig_update(struct swaybar *bar, const char *payload,
 | 
				
			||||||
#if HAVE_TRAY
 | 
					#if HAVE_TRAY
 | 
				
			||||||
	if (oldcfg->tray_hidden && !newcfg->tray_hidden) {
 | 
						if (oldcfg->tray_hidden && !newcfg->tray_hidden) {
 | 
				
			||||||
		bar->tray = create_tray(bar);
 | 
							bar->tray = create_tray(bar);
 | 
				
			||||||
		loop_add_fd(bar->eventloop, bar->tray->fd, POLLIN, tray_in,
 | 
							loop_add_fd(bar->eventloop, bar->tray->fd, POLLIN, tray_in, bar);
 | 
				
			||||||
				bar->tray->bus);
 | 
					 | 
				
			||||||
	} else if (bar->tray && newcfg->tray_hidden) {
 | 
						} else if (bar->tray && newcfg->tray_hidden) {
 | 
				
			||||||
		loop_remove_fd(bar->eventloop, bar->tray->fd);
 | 
							loop_remove_fd(bar->eventloop, bar->tray->fd);
 | 
				
			||||||
		destroy_tray(bar->tray);
 | 
							destroy_tray(bar->tray);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,5 @@
 | 
				
			||||||
#include <cairo.h>
 | 
					#include <cairo.h>
 | 
				
			||||||
 | 
					#include <poll.h>
 | 
				
			||||||
#include <stdint.h>
 | 
					#include <stdint.h>
 | 
				
			||||||
#include <stdlib.h>
 | 
					#include <stdlib.h>
 | 
				
			||||||
#include <string.h>
 | 
					#include <string.h>
 | 
				
			||||||
| 
						 | 
					@ -90,9 +91,16 @@ void destroy_tray(struct swaybar_tray *tray) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void tray_in(int fd, short mask, void *data) {
 | 
					void tray_in(int fd, short mask, void *data) {
 | 
				
			||||||
	sd_bus *bus = data;
 | 
						struct swaybar *bar = data;
 | 
				
			||||||
	int ret;
 | 
						int ret;
 | 
				
			||||||
	while ((ret = sd_bus_process(bus, NULL)) > 0) {
 | 
					
 | 
				
			||||||
 | 
						if (mask & (POLLHUP | POLLERR)) {
 | 
				
			||||||
 | 
					        sway_log(SWAY_ERROR, "D-Bus connection closed unexpectedly");
 | 
				
			||||||
 | 
							bar->running = false;
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						while ((ret = sd_bus_process(bar->tray->bus, NULL)) > 0) {
 | 
				
			||||||
		// This space intentionally left blank
 | 
							// This space intentionally left blank
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (ret < 0) {
 | 
						if (ret < 0) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -193,7 +193,7 @@ static void pretty_print_output(json_object *o) {
 | 
				
			||||||
	json_object_object_get_ex(o, "current_workspace", &ws);
 | 
						json_object_object_get_ex(o, "current_workspace", &ws);
 | 
				
			||||||
	json_object_object_get_ex(o, "non_desktop", &non_desktop);
 | 
						json_object_object_get_ex(o, "non_desktop", &non_desktop);
 | 
				
			||||||
	json_object *make, *model, *serial, *scale, *scale_filter, *subpixel,
 | 
						json_object *make, *model, *serial, *scale, *scale_filter, *subpixel,
 | 
				
			||||||
		*transform, *max_render_time, *adaptive_sync_status;
 | 
							*transform, *max_render_time, *adaptive_sync_status, *allow_tearing;
 | 
				
			||||||
	json_object_object_get_ex(o, "make", &make);
 | 
						json_object_object_get_ex(o, "make", &make);
 | 
				
			||||||
	json_object_object_get_ex(o, "model", &model);
 | 
						json_object_object_get_ex(o, "model", &model);
 | 
				
			||||||
	json_object_object_get_ex(o, "serial", &serial);
 | 
						json_object_object_get_ex(o, "serial", &serial);
 | 
				
			||||||
| 
						 | 
					@ -203,6 +203,7 @@ static void pretty_print_output(json_object *o) {
 | 
				
			||||||
	json_object_object_get_ex(o, "transform", &transform);
 | 
						json_object_object_get_ex(o, "transform", &transform);
 | 
				
			||||||
	json_object_object_get_ex(o, "max_render_time", &max_render_time);
 | 
						json_object_object_get_ex(o, "max_render_time", &max_render_time);
 | 
				
			||||||
	json_object_object_get_ex(o, "adaptive_sync_status", &adaptive_sync_status);
 | 
						json_object_object_get_ex(o, "adaptive_sync_status", &adaptive_sync_status);
 | 
				
			||||||
 | 
						json_object_object_get_ex(o, "allow_tearing", &allow_tearing);
 | 
				
			||||||
	json_object *x, *y;
 | 
						json_object *x, *y;
 | 
				
			||||||
	json_object_object_get_ex(rect, "x", &x);
 | 
						json_object_object_get_ex(rect, "x", &x);
 | 
				
			||||||
	json_object_object_get_ex(rect, "y", &y);
 | 
						json_object_object_get_ex(rect, "y", &y);
 | 
				
			||||||
| 
						 | 
					@ -256,6 +257,9 @@ static void pretty_print_output(json_object *o) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		printf("  Adaptive sync: %s\n",
 | 
							printf("  Adaptive sync: %s\n",
 | 
				
			||||||
			json_object_get_string(adaptive_sync_status));
 | 
								json_object_get_string(adaptive_sync_status));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							printf("  Allow tearing: %s\n",
 | 
				
			||||||
 | 
								json_object_get_boolean(allow_tearing) ? "yes" : "no");
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		printf(
 | 
							printf(
 | 
				
			||||||
			"Output %s '%s %s %s' (disabled)\n",
 | 
								"Output %s '%s %s %s' (disabled)\n",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue