mirror of
				https://github.com/swaywm/sway.git
				synced 2025-11-03 09:01:43 -05:00 
			
		
		
		
	Merge branch 'master' into wlr-gamma-control
This commit is contained in:
		
						commit
						3a54e2291c
					
				
					 113 changed files with 5196 additions and 1035 deletions
				
			
		| 
						 | 
					@ -64,8 +64,6 @@ Abhängigkeiten:
 | 
				
			||||||
* cairo
 | 
					* cairo
 | 
				
			||||||
* gdk-pixbuf2 *
 | 
					* gdk-pixbuf2 *
 | 
				
			||||||
* pam **
 | 
					* pam **
 | 
				
			||||||
* imagemagick (erforderlich für Bildaufnahme mit swaygrab)
 | 
					 | 
				
			||||||
* ffmpeg (erforderlich für Videoaufnahme swaygrab)
 | 
					 | 
				
			||||||
* [scdoc](https://git.sr.ht/~sircmpwn/scdoc) (erforderlich für man pages)
 | 
					* [scdoc](https://git.sr.ht/~sircmpwn/scdoc) (erforderlich für man pages)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
_\*Nur erforderlich für swaybar, swaybg, und swaylock_
 | 
					_\*Nur erforderlich für swaybar, swaybg, und swaylock_
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -57,8 +57,6 @@ To username μου στο Freenode είναι kon14 και θα με βρείτ
 | 
				
			||||||
* cairo
 | 
					* cairo
 | 
				
			||||||
* gdk-pixbuf2 *
 | 
					* gdk-pixbuf2 *
 | 
				
			||||||
* pam **
 | 
					* pam **
 | 
				
			||||||
* imagemagick (αναγκαίο για καταγραφή εικόνας μέσω του swaygrab)
 | 
					 | 
				
			||||||
* ffmpeg (αναγκαίο για καταγραφή video μέσω του swaygrab)
 | 
					 | 
				
			||||||
* [scdoc](https://git.sr.ht/~sircmpwn/scdoc) (required for man pages)
 | 
					* [scdoc](https://git.sr.ht/~sircmpwn/scdoc) (required for man pages)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
_\*Απαιτείται μόνο για swaybar, swaybg, and swaylock_
 | 
					_\*Απαιτείται μόνο για swaybar, swaybg, and swaylock_
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -59,8 +59,6 @@ Installez les dépendances :
 | 
				
			||||||
* cairo
 | 
					* cairo
 | 
				
			||||||
* gdk-pixbuf2 *
 | 
					* gdk-pixbuf2 *
 | 
				
			||||||
* pam **
 | 
					* pam **
 | 
				
			||||||
* imagemagick (requis pour la capture d'image avec swaygrab)
 | 
					 | 
				
			||||||
* ffmpeg (requis pour la capture vidéo avec swaygrab)
 | 
					 | 
				
			||||||
* [scdoc](https://git.sr.ht/~sircmpwn/scdoc) (requis pour les pages man)
 | 
					* [scdoc](https://git.sr.ht/~sircmpwn/scdoc) (requis pour les pages man)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
_\*Uniquement requis pour swaybar, swaybg, and swaylock_
 | 
					_\*Uniquement requis pour swaybar, swaybg, and swaylock_
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -60,8 +60,6 @@ Installa queste dipendenze:
 | 
				
			||||||
* cairo
 | 
					* cairo
 | 
				
			||||||
* gdk-pixbuf2 *
 | 
					* gdk-pixbuf2 *
 | 
				
			||||||
* pam **
 | 
					* pam **
 | 
				
			||||||
* imagemagick (richiesto per catturare immagini con swaygrab)
 | 
					 | 
				
			||||||
* ffmpeg (rrichiesto per catturare video con swaygrab)
 | 
					 | 
				
			||||||
* [scdoc](https://git.sr.ht/~sircmpwn/scdoc) (rrichiesto per man pages)
 | 
					* [scdoc](https://git.sr.ht/~sircmpwn/scdoc) (rrichiesto per man pages)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
_\*Richiesto solo per swaybar, swaybg, e swaylock_
 | 
					_\*Richiesto solo per swaybar, swaybg, e swaylock_
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -50,8 +50,6 @@ Swayは沢山のディストリビューションで提供されています。"
 | 
				
			||||||
* cairo
 | 
					* cairo
 | 
				
			||||||
* gdk-pixbuf2 *
 | 
					* gdk-pixbuf2 *
 | 
				
			||||||
* pam **
 | 
					* pam **
 | 
				
			||||||
* imagemagick (swaygrabでスクリーンショットを撮るのに必要です)
 | 
					 | 
				
			||||||
* ffmpeg (swaygrabで画面を録画するのに必要です)
 | 
					 | 
				
			||||||
* [scdoc](https://git.sr.ht/~sircmpwn/scdoc) (manで必要です)
 | 
					* [scdoc](https://git.sr.ht/~sircmpwn/scdoc) (manで必要です)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
_\*swaybar,swaybg,swaylockでのみ必要です_
 | 
					_\*swaybar,swaybg,swaylockでのみ必要です_
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -58,8 +58,6 @@ Install dependencies:
 | 
				
			||||||
* gdk-pixbuf2 *
 | 
					* gdk-pixbuf2 *
 | 
				
			||||||
* pam **
 | 
					* pam **
 | 
				
			||||||
* dbus >= 1.10 ***
 | 
					* dbus >= 1.10 ***
 | 
				
			||||||
* imagemagick (required for image capture with swaygrab)
 | 
					 | 
				
			||||||
* ffmpeg (required for video capture with swaygrab)
 | 
					 | 
				
			||||||
* [scdoc](https://git.sr.ht/~sircmpwn/scdoc) (required for man pages)
 | 
					* [scdoc](https://git.sr.ht/~sircmpwn/scdoc) (required for man pages)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
_\*Only required for swaybar, swaybg, and swaylock_
 | 
					_\*Only required for swaybar, swaybg, and swaylock_
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -66,8 +66,6 @@ Antes de iniciar a compilação, instale as dependências:
 | 
				
			||||||
* cairo
 | 
					* cairo
 | 
				
			||||||
* gdk-pixbuf2 *
 | 
					* gdk-pixbuf2 *
 | 
				
			||||||
* pam **
 | 
					* pam **
 | 
				
			||||||
* imagemagick (capturar imagem com o swaygrab)
 | 
					 | 
				
			||||||
* ffmpeg (capturar vídeo com o swaygrab)
 | 
					 | 
				
			||||||
* [scdoc](https://git.sr.ht/~sircmpwn/scdoc) (man pages)
 | 
					* [scdoc](https://git.sr.ht/~sircmpwn/scdoc) (man pages)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
_\*Dependência apenas de swaybar, swaybg, e swaylock_
 | 
					_\*Dependência apenas de swaybar, swaybg, e swaylock_
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -62,8 +62,6 @@ Sway доступен во многих дистрибутивах и наход
 | 
				
			||||||
* gdk-pixbuf2 *
 | 
					* gdk-pixbuf2 *
 | 
				
			||||||
* pam **
 | 
					* pam **
 | 
				
			||||||
* dbus >= 1.10 ***
 | 
					* dbus >= 1.10 ***
 | 
				
			||||||
* imagemagick (требуется для захвата изображений через swaygrab)
 | 
					 | 
				
			||||||
* ffmpeg (требуется для захвата видео через swaygrab)
 | 
					 | 
				
			||||||
* [scdoc](https://git.sr.ht/~sircmpwn/scdoc) (required for man pages)
 | 
					* [scdoc](https://git.sr.ht/~sircmpwn/scdoc) (required for man pages)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
_\*Требуется только для swaybar, swaybg и swaylock_
 | 
					_\*Требуется только для swaybar, swaybg и swaylock_
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -66,8 +66,6 @@ Sway доступний у багатьох дистрибутивах Linux (а
 | 
				
			||||||
* cairo
 | 
					* cairo
 | 
				
			||||||
* gdk-pixbuf2 *
 | 
					* gdk-pixbuf2 *
 | 
				
			||||||
* pam **
 | 
					* pam **
 | 
				
			||||||
* imagemagick (для захоплення зображень за допомогою swaygrab)
 | 
					 | 
				
			||||||
* ffmpeg (для захоплення відео за допомогою swaygrab)
 | 
					 | 
				
			||||||
* [scdoc](https://git.sr.ht/~sircmpwn/scdoc) (required for man pages)
 | 
					* [scdoc](https://git.sr.ht/~sircmpwn/scdoc) (required for man pages)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
_\*Лише для swaybar, swaybg та swaylock_
 | 
					_\*Лише для swaybar, swaybg та swaylock_
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -123,6 +123,22 @@ uint32_t parse_color(const char *color) {
 | 
				
			||||||
	return res;
 | 
						return res;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool parse_boolean(const char *boolean, bool current) {
 | 
				
			||||||
 | 
						if (strcasecmp(boolean, "1") == 0
 | 
				
			||||||
 | 
								|| strcasecmp(boolean, "yes") == 0
 | 
				
			||||||
 | 
								|| strcasecmp(boolean, "on") == 0
 | 
				
			||||||
 | 
								|| strcasecmp(boolean, "true") == 0
 | 
				
			||||||
 | 
								|| strcasecmp(boolean, "enable") == 0
 | 
				
			||||||
 | 
								|| strcasecmp(boolean, "enabled") == 0
 | 
				
			||||||
 | 
								|| strcasecmp(boolean, "active") == 0) {
 | 
				
			||||||
 | 
							return true;
 | 
				
			||||||
 | 
						} else if (strcasecmp(boolean, "toggle") == 0) {
 | 
				
			||||||
 | 
							return !current;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						// All other values are false to match i3
 | 
				
			||||||
 | 
						return false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
char* resolve_path(const char* path) {
 | 
					char* resolve_path(const char* path) {
 | 
				
			||||||
	struct stat sb;
 | 
						struct stat sb;
 | 
				
			||||||
	ssize_t r;
 | 
						ssize_t r;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										46
									
								
								completions/bash/sway
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								completions/bash/sway
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,46 @@
 | 
				
			||||||
 | 
					# sway(1) completion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					_sway()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  local cur prev
 | 
				
			||||||
 | 
					  _get_comp_words_by_ref cur prev
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  short=(
 | 
				
			||||||
 | 
					    -h
 | 
				
			||||||
 | 
					    -c
 | 
				
			||||||
 | 
					    -C
 | 
				
			||||||
 | 
					    -d
 | 
				
			||||||
 | 
					    -v
 | 
				
			||||||
 | 
					    -V
 | 
				
			||||||
 | 
					  )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  long=(
 | 
				
			||||||
 | 
					    --help
 | 
				
			||||||
 | 
					    --config
 | 
				
			||||||
 | 
					    --validate
 | 
				
			||||||
 | 
					    --debug
 | 
				
			||||||
 | 
					    --version
 | 
				
			||||||
 | 
					    --verbose
 | 
				
			||||||
 | 
					    --get-socketpath
 | 
				
			||||||
 | 
					  )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  case $prev in
 | 
				
			||||||
 | 
					    -c|--config)
 | 
				
			||||||
 | 
					      _filedir
 | 
				
			||||||
 | 
					      return
 | 
				
			||||||
 | 
					      ;;
 | 
				
			||||||
 | 
					  esac
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if [[ $cur == --* ]]; then
 | 
				
			||||||
 | 
					    COMPREPLY=($(compgen -W "${long[*]}" -- "$cur"))
 | 
				
			||||||
 | 
					  elif [[ $cur == -* ]]; then
 | 
				
			||||||
 | 
					    COMPREPLY=($(compgen -W "${short[*]}" -- "$cur"))
 | 
				
			||||||
 | 
					    COMPREPLY+=($(compgen -W "${long[*]}" -- "$cur"))
 | 
				
			||||||
 | 
					  else
 | 
				
			||||||
 | 
					    COMPREPLY=($(compgen -W "${short[*]}" -- "$cur"))
 | 
				
			||||||
 | 
					    COMPREPLY+=($(compgen -W "${long[*]}" -- "$cur"))
 | 
				
			||||||
 | 
					    COMPREPLY+=($(compgen -c -- "$cur"))
 | 
				
			||||||
 | 
					  fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} &&
 | 
				
			||||||
 | 
					complete -F _sway sway
 | 
				
			||||||
							
								
								
									
										48
									
								
								completions/bash/swayidle
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								completions/bash/swayidle
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,48 @@
 | 
				
			||||||
 | 
					# swaymsg(1) completion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					_swayidle()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  local cur prev
 | 
				
			||||||
 | 
					  _get_comp_words_by_ref -n : cur prev
 | 
				
			||||||
 | 
					  local prev2=${COMP_WORDS[COMP_CWORD-2]}
 | 
				
			||||||
 | 
					  local prev3=${COMP_WORDS[COMP_CWORD-3]}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  events=(
 | 
				
			||||||
 | 
					    'timeout'
 | 
				
			||||||
 | 
					    'before-sleep'
 | 
				
			||||||
 | 
					  )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  short=(
 | 
				
			||||||
 | 
					    -h
 | 
				
			||||||
 | 
					    -d
 | 
				
			||||||
 | 
					  )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if [ "$prev" = timeout ]; then
 | 
				
			||||||
 | 
					    # timeout <timeout>
 | 
				
			||||||
 | 
					    return
 | 
				
			||||||
 | 
					  elif [ "$prev2" = timeout ]; then
 | 
				
			||||||
 | 
					    # timeout <timeout> <timeout command>
 | 
				
			||||||
 | 
					    COMPREPLY=($(compgen -c -- "$cur"))
 | 
				
			||||||
 | 
					    return
 | 
				
			||||||
 | 
					  elif [ "$prev3" = timeout ]; then
 | 
				
			||||||
 | 
					    # timeout <timeout> <timeout command> [resume <resume command>]
 | 
				
			||||||
 | 
					    COMPREPLY=(resume)
 | 
				
			||||||
 | 
					    # optional argument; no return here as user may skip 'resume'
 | 
				
			||||||
 | 
					  fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  case "$prev" in
 | 
				
			||||||
 | 
					    resume)
 | 
				
			||||||
 | 
					      COMPREPLY=($(compgen -c -- "$cur"))
 | 
				
			||||||
 | 
					      return
 | 
				
			||||||
 | 
					      ;;
 | 
				
			||||||
 | 
					    before-sleep)
 | 
				
			||||||
 | 
					      COMPREPLY=($(compgen -c -- "$cur"))
 | 
				
			||||||
 | 
					      return
 | 
				
			||||||
 | 
					      ;;
 | 
				
			||||||
 | 
					  esac
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  COMPREPLY+=($(compgen -W "${events[*]}" -- "$cur"))
 | 
				
			||||||
 | 
					  COMPREPLY+=($(compgen -W "${short[*]}" -- "$cur"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} &&
 | 
				
			||||||
 | 
					complete -F _swayidle swayidle
 | 
				
			||||||
							
								
								
									
										66
									
								
								completions/bash/swaylock
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								completions/bash/swaylock
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,66 @@
 | 
				
			||||||
 | 
					# swaylock(1) completion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					_swaylock()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  local cur prev
 | 
				
			||||||
 | 
					  _get_comp_words_by_ref -n : cur prev
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  short=(
 | 
				
			||||||
 | 
					    -h
 | 
				
			||||||
 | 
					    -c
 | 
				
			||||||
 | 
					    -s
 | 
				
			||||||
 | 
					    -t
 | 
				
			||||||
 | 
					    -v
 | 
				
			||||||
 | 
					    -i
 | 
				
			||||||
 | 
					    -u
 | 
				
			||||||
 | 
					    -f
 | 
				
			||||||
 | 
					  )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  long=(
 | 
				
			||||||
 | 
					    --help
 | 
				
			||||||
 | 
					    --color
 | 
				
			||||||
 | 
					    --scaling
 | 
				
			||||||
 | 
					    --tiling
 | 
				
			||||||
 | 
					    --version
 | 
				
			||||||
 | 
					    --image
 | 
				
			||||||
 | 
					    --no-unlock-indicator
 | 
				
			||||||
 | 
					    --daemonize
 | 
				
			||||||
 | 
					  )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  scaling=(
 | 
				
			||||||
 | 
					    'stretch'
 | 
				
			||||||
 | 
					    'fill'
 | 
				
			||||||
 | 
					    'fit'
 | 
				
			||||||
 | 
					    'center'
 | 
				
			||||||
 | 
					    'tile'
 | 
				
			||||||
 | 
					  )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  case $prev in
 | 
				
			||||||
 | 
					    -c|--color)
 | 
				
			||||||
 | 
					      return
 | 
				
			||||||
 | 
					      ;;
 | 
				
			||||||
 | 
					    --scaling)
 | 
				
			||||||
 | 
					      COMPREPLY=($(compgen -W "${scaling[*]}" -- "$cur"))
 | 
				
			||||||
 | 
					      return
 | 
				
			||||||
 | 
					      ;;
 | 
				
			||||||
 | 
					    -i|--image)
 | 
				
			||||||
 | 
					      if grep -q : <<< "$cur"; then
 | 
				
			||||||
 | 
					        output="${cur%%:*}:"
 | 
				
			||||||
 | 
					        cur="${cur#*:}"
 | 
				
			||||||
 | 
					      else
 | 
				
			||||||
 | 
					        output=
 | 
				
			||||||
 | 
					      fi
 | 
				
			||||||
 | 
					      COMPREPLY=($(compgen -f -- "$cur"))
 | 
				
			||||||
 | 
					      return
 | 
				
			||||||
 | 
					      ;;
 | 
				
			||||||
 | 
					  esac
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if [[ $cur == --* ]]; then
 | 
				
			||||||
 | 
					    COMPREPLY=($(compgen -W "${long[*]}" -- "$cur"))
 | 
				
			||||||
 | 
					  else
 | 
				
			||||||
 | 
					    COMPREPLY=($(compgen -W "${short[*]}" -- "$cur"))
 | 
				
			||||||
 | 
					    COMPREPLY+=($(compgen -W "${long[*]}" -- "$cur"))
 | 
				
			||||||
 | 
					  fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} &&
 | 
				
			||||||
 | 
					complete -F _swaylock swaylock
 | 
				
			||||||
							
								
								
									
										59
									
								
								completions/bash/swaymsg
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								completions/bash/swaymsg
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,59 @@
 | 
				
			||||||
 | 
					# swaymsg(1) completion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					_swaymsg()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  local cur prev
 | 
				
			||||||
 | 
					  _get_comp_words_by_ref cur prev
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  types=(
 | 
				
			||||||
 | 
					    'get_workspaces'
 | 
				
			||||||
 | 
					    'get_seats'
 | 
				
			||||||
 | 
					    'get_inputs'
 | 
				
			||||||
 | 
					    'get_outputs'
 | 
				
			||||||
 | 
					    'get_tree'
 | 
				
			||||||
 | 
					    'get_marks'
 | 
				
			||||||
 | 
					    'get_bar_config'
 | 
				
			||||||
 | 
					    'get_version'
 | 
				
			||||||
 | 
					    'get_binding_modes'
 | 
				
			||||||
 | 
					    'get_config'
 | 
				
			||||||
 | 
					    'send_tick'
 | 
				
			||||||
 | 
					  )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  short=(
 | 
				
			||||||
 | 
					    -h
 | 
				
			||||||
 | 
					    -q
 | 
				
			||||||
 | 
					    -r
 | 
				
			||||||
 | 
					    -s
 | 
				
			||||||
 | 
					    -t
 | 
				
			||||||
 | 
					    -v
 | 
				
			||||||
 | 
					  )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  long=(
 | 
				
			||||||
 | 
					    --help
 | 
				
			||||||
 | 
					    --quiet
 | 
				
			||||||
 | 
					    --raw
 | 
				
			||||||
 | 
					    --socket
 | 
				
			||||||
 | 
					    --type
 | 
				
			||||||
 | 
					    --verbose
 | 
				
			||||||
 | 
					  )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  case $prev in
 | 
				
			||||||
 | 
					    -s|--socket)
 | 
				
			||||||
 | 
					      _filedir
 | 
				
			||||||
 | 
					      return
 | 
				
			||||||
 | 
					      ;;
 | 
				
			||||||
 | 
					    -t|--type)
 | 
				
			||||||
 | 
					      COMPREPLY=($(compgen -W "${types[*]}" -- "$cur"))
 | 
				
			||||||
 | 
					      return
 | 
				
			||||||
 | 
					      ;;
 | 
				
			||||||
 | 
					  esac
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if [[ $cur == --* ]]; then
 | 
				
			||||||
 | 
					    COMPREPLY=($(compgen -W "${long[*]}" -- "$cur"))
 | 
				
			||||||
 | 
					  else
 | 
				
			||||||
 | 
					    COMPREPLY=($(compgen -W "${short[*]}" -- "$cur"))
 | 
				
			||||||
 | 
					    COMPREPLY+=($(compgen -W "${long[*]}" -- "$cur"))
 | 
				
			||||||
 | 
					  fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} &&
 | 
				
			||||||
 | 
					complete -F _swaymsg swaymsg
 | 
				
			||||||
| 
						 | 
					@ -18,5 +18,5 @@ _arguments -s \
 | 
				
			||||||
	'(-c --config)'{-c,--config}'[Specify a config file]:files:_files' \
 | 
						'(-c --config)'{-c,--config}'[Specify a config file]:files:_files' \
 | 
				
			||||||
	'(-C --validate)'{-C,--validate}'[Check validity of the config file, then exit]' \
 | 
						'(-C --validate)'{-C,--validate}'[Check validity of the config file, then exit]' \
 | 
				
			||||||
	'(-d --debug)'{-d,--debug}'[Enables full logging, including debug information]' \
 | 
						'(-d --debug)'{-d,--debug}'[Enables full logging, including debug information]' \
 | 
				
			||||||
	'(-v --verbose)'{-v,--verbose}'[Enables more verbose logging]' \
 | 
						'(-V --verbose)'{-V,--verbose}'[Enables more verbose logging]' \
 | 
				
			||||||
	'(--get-socketpath)'--get-socketpath'[Gets the IPC socket path and prints it, then exits]'
 | 
						'(--get-socketpath)'--get-socketpath'[Gets the IPC socket path and prints it, then exits]'
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,23 +0,0 @@
 | 
				
			||||||
#compdef swaygrab
 | 
					 | 
				
			||||||
#-----------------
 | 
					 | 
				
			||||||
# Description
 | 
					 | 
				
			||||||
# -----------
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# Completion script for swaygrab in sway wm (http://swaywm.org)
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# -----------------------------------------------------
 | 
					 | 
				
			||||||
# Author
 | 
					 | 
				
			||||||
# ------
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# * Seth Barberee <seth.barberee@gmail.com>
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# ------------------------------------------
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
_arguments -s \
 | 
					 | 
				
			||||||
	'(-h --help)'{-h,--help}'[Shows help message]' \
 | 
					 | 
				
			||||||
	'(-c --capture)'{-c,--capture}'[Captures multiple frames as video and passes them to ffmpeg]' \
 | 
					 | 
				
			||||||
	'(-o --output)'{-o,--output}'[Use the specified output. If not specified then current focused output will be used]' \
 | 
					 | 
				
			||||||
	'(-v --version)'{-v,--version}'[Print the version (of swaymsg) and quit]' \
 | 
					 | 
				
			||||||
	'(-s --socket)'{-s,--socket}'[Use the specified socket path.]:files:_files' \
 | 
					 | 
				
			||||||
	'(-r --rate)'{-r,--rate}'[Specify a framerate (in fps). Used in combination with -c. Default is 30 and must be an integer]' \
 | 
					 | 
				
			||||||
	'(--raw)--raw[Instead of ImageMagick or ffmpeg, dump raw rgba data to stdout]'
 | 
					 | 
				
			||||||
| 
						 | 
					@ -22,6 +22,9 @@ types=(
 | 
				
			||||||
'get_marks'
 | 
					'get_marks'
 | 
				
			||||||
'get_bar_config'
 | 
					'get_bar_config'
 | 
				
			||||||
'get_version'
 | 
					'get_version'
 | 
				
			||||||
 | 
					'get_binding_modes'
 | 
				
			||||||
 | 
					'get_config'
 | 
				
			||||||
 | 
					'send_tick'
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
_arguments -s \
 | 
					_arguments -s \
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -16,7 +16,8 @@ set $right l
 | 
				
			||||||
# Your preferred terminal emulator
 | 
					# Your preferred terminal emulator
 | 
				
			||||||
set $term urxvt
 | 
					set $term urxvt
 | 
				
			||||||
# Your preferred application launcher
 | 
					# Your preferred application launcher
 | 
				
			||||||
set $menu dmenu_run
 | 
					# Note: it's recommended that you pass the final command to sway
 | 
				
			||||||
 | 
					set $menu dmenu_path | dmenu | xargs swaymsg exec
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Output configuration
 | 
					### Output configuration
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -15,6 +15,7 @@ enum ipc_command_type {
 | 
				
			||||||
	IPC_GET_VERSION = 7,
 | 
						IPC_GET_VERSION = 7,
 | 
				
			||||||
	IPC_GET_BINDING_MODES = 8,
 | 
						IPC_GET_BINDING_MODES = 8,
 | 
				
			||||||
	IPC_GET_CONFIG = 9,
 | 
						IPC_GET_CONFIG = 9,
 | 
				
			||||||
 | 
						IPC_SEND_TICK = 10,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// sway-specific command types
 | 
						// sway-specific command types
 | 
				
			||||||
	IPC_GET_INPUTS = 100,
 | 
						IPC_GET_INPUTS = 100,
 | 
				
			||||||
| 
						 | 
					@ -27,8 +28,8 @@ enum ipc_command_type {
 | 
				
			||||||
	IPC_EVENT_WINDOW = ((1<<31) | 3),
 | 
						IPC_EVENT_WINDOW = ((1<<31) | 3),
 | 
				
			||||||
	IPC_EVENT_BARCONFIG_UPDATE = ((1<<31) | 4),
 | 
						IPC_EVENT_BARCONFIG_UPDATE = ((1<<31) | 4),
 | 
				
			||||||
	IPC_EVENT_BINDING = ((1<<31) | 5),
 | 
						IPC_EVENT_BINDING = ((1<<31) | 5),
 | 
				
			||||||
	IPC_EVENT_MODIFIER = ((1<<31) | 6),
 | 
						IPC_EVENT_SHUTDOWN = ((1<<31) | 6),
 | 
				
			||||||
	IPC_EVENT_INPUT = ((1<<31) | 7),
 | 
						IPC_EVENT_TICK = ((1<<31) | 7),
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -106,7 +106,7 @@ sway_cmd cmd_exit;
 | 
				
			||||||
sway_cmd cmd_floating;
 | 
					sway_cmd cmd_floating;
 | 
				
			||||||
sway_cmd cmd_floating_maximum_size;
 | 
					sway_cmd cmd_floating_maximum_size;
 | 
				
			||||||
sway_cmd cmd_floating_minimum_size;
 | 
					sway_cmd cmd_floating_minimum_size;
 | 
				
			||||||
sway_cmd cmd_floating_mod;
 | 
					sway_cmd cmd_floating_modifier;
 | 
				
			||||||
sway_cmd cmd_floating_scroll;
 | 
					sway_cmd cmd_floating_scroll;
 | 
				
			||||||
sway_cmd cmd_focus;
 | 
					sway_cmd cmd_focus;
 | 
				
			||||||
sway_cmd cmd_focus_follows_mouse;
 | 
					sway_cmd cmd_focus_follows_mouse;
 | 
				
			||||||
| 
						 | 
					@ -213,8 +213,10 @@ sway_cmd input_cmd_scroll_button;
 | 
				
			||||||
sway_cmd input_cmd_scroll_method;
 | 
					sway_cmd input_cmd_scroll_method;
 | 
				
			||||||
sway_cmd input_cmd_tap;
 | 
					sway_cmd input_cmd_tap;
 | 
				
			||||||
sway_cmd input_cmd_tap_button_map;
 | 
					sway_cmd input_cmd_tap_button_map;
 | 
				
			||||||
 | 
					sway_cmd input_cmd_xkb_capslock;
 | 
				
			||||||
sway_cmd input_cmd_xkb_layout;
 | 
					sway_cmd input_cmd_xkb_layout;
 | 
				
			||||||
sway_cmd input_cmd_xkb_model;
 | 
					sway_cmd input_cmd_xkb_model;
 | 
				
			||||||
 | 
					sway_cmd input_cmd_xkb_numlock;
 | 
				
			||||||
sway_cmd input_cmd_xkb_options;
 | 
					sway_cmd input_cmd_xkb_options;
 | 
				
			||||||
sway_cmd input_cmd_xkb_rules;
 | 
					sway_cmd input_cmd_xkb_rules;
 | 
				
			||||||
sway_cmd input_cmd_xkb_variant;
 | 
					sway_cmd input_cmd_xkb_variant;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,5 @@
 | 
				
			||||||
#ifndef _SWAY_CONFIG_H
 | 
					#ifndef _SWAY_CONFIG_H
 | 
				
			||||||
#define _SWAY_CONFIG_H
 | 
					#define _SWAY_CONFIG_H
 | 
				
			||||||
#define PID_WORKSPACE_TIMEOUT 60
 | 
					 | 
				
			||||||
#include <libinput.h>
 | 
					#include <libinput.h>
 | 
				
			||||||
#include <stdint.h>
 | 
					#include <stdint.h>
 | 
				
			||||||
#include <string.h>
 | 
					#include <string.h>
 | 
				
			||||||
| 
						 | 
					@ -22,14 +21,28 @@ struct sway_variable {
 | 
				
			||||||
	char *value;
 | 
						char *value;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum binding_input_type {
 | 
				
			||||||
 | 
						BINDING_KEYCODE,
 | 
				
			||||||
 | 
						BINDING_KEYSYM,
 | 
				
			||||||
 | 
						BINDING_MOUSE,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum binding_flags {
 | 
				
			||||||
 | 
						BINDING_RELEASE=1,
 | 
				
			||||||
 | 
						BINDING_LOCKED=2, // keyboard only
 | 
				
			||||||
 | 
						BINDING_BORDER=4, // mouse only; trigger on container border
 | 
				
			||||||
 | 
						BINDING_CONTENTS=8, // mouse only; trigger on container contents
 | 
				
			||||||
 | 
						BINDING_TITLEBAR=16 // mouse only; trigger on container titlebar
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * A key binding and an associated command.
 | 
					 * A key binding and an associated command.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
struct sway_binding {
 | 
					struct sway_binding {
 | 
				
			||||||
 | 
						enum binding_input_type type;
 | 
				
			||||||
	int order;
 | 
						int order;
 | 
				
			||||||
	bool release;
 | 
						uint32_t flags;
 | 
				
			||||||
	bool locked;
 | 
					 | 
				
			||||||
	bool bindcode;
 | 
					 | 
				
			||||||
	list_t *keys; // sorted in ascending order
 | 
						list_t *keys; // sorted in ascending order
 | 
				
			||||||
	uint32_t modifiers;
 | 
						uint32_t modifiers;
 | 
				
			||||||
	char *command;
 | 
						char *command;
 | 
				
			||||||
| 
						 | 
					@ -50,6 +63,7 @@ struct sway_mode {
 | 
				
			||||||
	char *name;
 | 
						char *name;
 | 
				
			||||||
	list_t *keysym_bindings;
 | 
						list_t *keysym_bindings;
 | 
				
			||||||
	list_t *keycode_bindings;
 | 
						list_t *keycode_bindings;
 | 
				
			||||||
 | 
						list_t *mouse_bindings;
 | 
				
			||||||
	bool pango;
 | 
						bool pango;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -87,6 +101,9 @@ struct input_config {
 | 
				
			||||||
	char *xkb_rules;
 | 
						char *xkb_rules;
 | 
				
			||||||
	char *xkb_variant;
 | 
						char *xkb_variant;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int xkb_numlock;
 | 
				
			||||||
 | 
						int xkb_capslock;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct input_config_mapped_from_region *mapped_from_region;
 | 
						struct input_config_mapped_from_region *mapped_from_region;
 | 
				
			||||||
	char *mapped_to_output;
 | 
						char *mapped_to_output;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -146,12 +163,6 @@ struct workspace_output {
 | 
				
			||||||
	char *workspace;
 | 
						char *workspace;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct pid_workspace {
 | 
					 | 
				
			||||||
	pid_t *pid;
 | 
					 | 
				
			||||||
	char *workspace;
 | 
					 | 
				
			||||||
	time_t *time_added;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct bar_config {
 | 
					struct bar_config {
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * One of "dock", "hide", "invisible"
 | 
						 * One of "dock", "hide", "invisible"
 | 
				
			||||||
| 
						 | 
					@ -302,7 +313,6 @@ struct sway_config {
 | 
				
			||||||
	list_t *bars;
 | 
						list_t *bars;
 | 
				
			||||||
	list_t *cmd_queue;
 | 
						list_t *cmd_queue;
 | 
				
			||||||
	list_t *workspace_outputs;
 | 
						list_t *workspace_outputs;
 | 
				
			||||||
	list_t *pid_workspaces;
 | 
					 | 
				
			||||||
	list_t *output_configs;
 | 
						list_t *output_configs;
 | 
				
			||||||
	list_t *input_configs;
 | 
						list_t *input_configs;
 | 
				
			||||||
	list_t *seat_configs;
 | 
						list_t *seat_configs;
 | 
				
			||||||
| 
						 | 
					@ -313,6 +323,7 @@ struct sway_config {
 | 
				
			||||||
	struct bar_config *current_bar;
 | 
						struct bar_config *current_bar;
 | 
				
			||||||
	char *swaybg_command;
 | 
						char *swaybg_command;
 | 
				
			||||||
	uint32_t floating_mod;
 | 
						uint32_t floating_mod;
 | 
				
			||||||
 | 
						bool floating_mod_inverse;
 | 
				
			||||||
	uint32_t dragging_key;
 | 
						uint32_t dragging_key;
 | 
				
			||||||
	uint32_t resizing_key;
 | 
						uint32_t resizing_key;
 | 
				
			||||||
	char *floating_scroll_up_cmd;
 | 
						char *floating_scroll_up_cmd;
 | 
				
			||||||
| 
						 | 
					@ -388,9 +399,6 @@ struct sway_config {
 | 
				
			||||||
	} handler_context;
 | 
						} handler_context;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void pid_workspace_add(struct pid_workspace *pw);
 | 
					 | 
				
			||||||
void free_pid_workspace(struct pid_workspace *pw);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Loads the main config from the given path. is_active should be true when
 | 
					 * Loads the main config from the given path. is_active should be true when
 | 
				
			||||||
 * reloading the config.
 | 
					 * reloading the config.
 | 
				
			||||||
| 
						 | 
					@ -480,7 +488,7 @@ int sway_binding_cmp_keys(const void *a, const void *b);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void free_sway_binding(struct sway_binding *sb);
 | 
					void free_sway_binding(struct sway_binding *sb);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct sway_binding *sway_binding_dup(struct sway_binding *sb);
 | 
					void seat_execute_command(struct sway_seat *seat, struct sway_binding *binding);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void load_swaybars();
 | 
					void load_swaybars();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,6 +2,7 @@
 | 
				
			||||||
#define _SWAY_CRITERIA_H
 | 
					#define _SWAY_CRITERIA_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <pcre.h>
 | 
					#include <pcre.h>
 | 
				
			||||||
 | 
					#include "config.h"
 | 
				
			||||||
#include "list.h"
 | 
					#include "list.h"
 | 
				
			||||||
#include "tree/view.h"
 | 
					#include "tree/view.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -25,7 +26,9 @@ struct criteria {
 | 
				
			||||||
	pcre *instance;
 | 
						pcre *instance;
 | 
				
			||||||
	pcre *con_mark;
 | 
						pcre *con_mark;
 | 
				
			||||||
	uint32_t con_id; // internal ID
 | 
						uint32_t con_id; // internal ID
 | 
				
			||||||
 | 
					#ifdef HAVE_XWAYLAND
 | 
				
			||||||
	uint32_t id; // X11 window ID
 | 
						uint32_t id; // X11 window ID
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
	pcre *window_role;
 | 
						pcre *window_role;
 | 
				
			||||||
	uint32_t window_type;
 | 
						uint32_t window_type;
 | 
				
			||||||
	bool floating;
 | 
						bool floating;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -42,17 +42,4 @@ void transaction_notify_view_ready(struct sway_view *view, uint32_t serial);
 | 
				
			||||||
void transaction_notify_view_ready_by_size(struct sway_view *view,
 | 
					void transaction_notify_view_ready_by_size(struct sway_view *view,
 | 
				
			||||||
		int width, int height);
 | 
							int width, int height);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Get the saved texture that should be rendered for a view.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * The addresses pointed at by the width and height pointers will be populated
 | 
					 | 
				
			||||||
 * with the surface's dimensions, which may be different to the texture's
 | 
					 | 
				
			||||||
 * dimensions if output scaling is used.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * This function should only be called if it is known that the view has
 | 
					 | 
				
			||||||
 * instructions.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
struct wlr_texture *transaction_get_saved_texture(struct sway_view *view,
 | 
					 | 
				
			||||||
		int *width, int *height);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,6 +3,8 @@
 | 
				
			||||||
#include <stdint.h>
 | 
					#include <stdint.h>
 | 
				
			||||||
#include "sway/input/seat.h"
 | 
					#include "sway/input/seat.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define SWAY_CURSOR_PRESSED_BUTTONS_CAP 32
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct sway_cursor {
 | 
					struct sway_cursor {
 | 
				
			||||||
	struct sway_seat *seat;
 | 
						struct sway_seat *seat;
 | 
				
			||||||
	struct wlr_cursor *cursor;
 | 
						struct wlr_cursor *cursor;
 | 
				
			||||||
| 
						 | 
					@ -11,6 +13,7 @@ struct sway_cursor {
 | 
				
			||||||
	} previous;
 | 
						} previous;
 | 
				
			||||||
	struct wlr_xcursor_manager *xcursor_manager;
 | 
						struct wlr_xcursor_manager *xcursor_manager;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						const char *image;
 | 
				
			||||||
	struct wl_client *image_client;
 | 
						struct wl_client *image_client;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wl_listener motion;
 | 
						struct wl_listener motion;
 | 
				
			||||||
| 
						 | 
					@ -28,6 +31,10 @@ struct sway_cursor {
 | 
				
			||||||
	uint32_t tool_buttons;
 | 
						uint32_t tool_buttons;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wl_listener request_set_cursor;
 | 
						struct wl_listener request_set_cursor;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Mouse binding state
 | 
				
			||||||
 | 
						uint32_t pressed_buttons[SWAY_CURSOR_PRESSED_BUTTONS_CAP];
 | 
				
			||||||
 | 
						size_t pressed_button_count;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void sway_cursor_destroy(struct sway_cursor *cursor);
 | 
					void sway_cursor_destroy(struct sway_cursor *cursor);
 | 
				
			||||||
| 
						 | 
					@ -37,4 +44,7 @@ void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec,
 | 
				
			||||||
void dispatch_cursor_button(struct sway_cursor *cursor, uint32_t time_msec,
 | 
					void dispatch_cursor_button(struct sway_cursor *cursor, uint32_t time_msec,
 | 
				
			||||||
	uint32_t button, enum wlr_button_state state);
 | 
						uint32_t button, enum wlr_button_state state);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void cursor_set_image(struct sway_cursor *cursor, const char *image,
 | 
				
			||||||
 | 
							struct wl_client *client);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,6 +2,7 @@
 | 
				
			||||||
#define _SWAY_INPUT_INPUT_MANAGER_H
 | 
					#define _SWAY_INPUT_INPUT_MANAGER_H
 | 
				
			||||||
#include <libinput.h>
 | 
					#include <libinput.h>
 | 
				
			||||||
#include <wlr/types/wlr_input_inhibitor.h>
 | 
					#include <wlr/types/wlr_input_inhibitor.h>
 | 
				
			||||||
 | 
					#include <wlr/types/wlr_virtual_keyboard_v1.h>
 | 
				
			||||||
#include "sway/server.h"
 | 
					#include "sway/server.h"
 | 
				
			||||||
#include "sway/config.h"
 | 
					#include "sway/config.h"
 | 
				
			||||||
#include "list.h"
 | 
					#include "list.h"
 | 
				
			||||||
| 
						 | 
					@ -25,10 +26,12 @@ struct sway_input_manager {
 | 
				
			||||||
	struct wl_list seats;
 | 
						struct wl_list seats;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wlr_input_inhibit_manager *inhibit;
 | 
						struct wlr_input_inhibit_manager *inhibit;
 | 
				
			||||||
 | 
						struct wlr_virtual_keyboard_manager_v1 *virtual_keyboard;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wl_listener new_input;
 | 
						struct wl_listener new_input;
 | 
				
			||||||
	struct wl_listener inhibit_activate;
 | 
						struct wl_listener inhibit_activate;
 | 
				
			||||||
	struct wl_listener inhibit_deactivate;
 | 
						struct wl_listener inhibit_deactivate;
 | 
				
			||||||
 | 
						struct wl_listener virtual_keyboard_new;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct sway_input_manager *input_manager_create(struct sway_server *server);
 | 
					struct sway_input_manager *input_manager_create(struct sway_server *server);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -38,6 +38,9 @@ struct sway_keyboard {
 | 
				
			||||||
	struct sway_shortcut_state state_keysyms_raw;
 | 
						struct sway_shortcut_state state_keysyms_raw;
 | 
				
			||||||
	struct sway_shortcut_state state_keycodes;
 | 
						struct sway_shortcut_state state_keycodes;
 | 
				
			||||||
	struct sway_binding *held_binding;
 | 
						struct sway_binding *held_binding;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct wl_event_source *key_repeat_source;
 | 
				
			||||||
 | 
						struct sway_binding *repeat_binding;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct sway_keyboard *sway_keyboard_create(struct sway_seat *seat,
 | 
					struct sway_keyboard *sway_keyboard_create(struct sway_seat *seat,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,6 +3,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <wlr/types/wlr_layer_shell.h>
 | 
					#include <wlr/types/wlr_layer_shell.h>
 | 
				
			||||||
#include <wlr/types/wlr_seat.h>
 | 
					#include <wlr/types/wlr_seat.h>
 | 
				
			||||||
 | 
					#include <wlr/util/edges.h>
 | 
				
			||||||
#include "sway/input/input-manager.h"
 | 
					#include "sway/input/input-manager.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct sway_seat_device {
 | 
					struct sway_seat_device {
 | 
				
			||||||
| 
						 | 
					@ -52,6 +53,24 @@ struct sway_seat {
 | 
				
			||||||
	int32_t touch_id;
 | 
						int32_t touch_id;
 | 
				
			||||||
	double touch_x, touch_y;
 | 
						double touch_x, touch_y;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Operations (drag and resize)
 | 
				
			||||||
 | 
						enum {
 | 
				
			||||||
 | 
							OP_NONE,
 | 
				
			||||||
 | 
							OP_MOVE,
 | 
				
			||||||
 | 
							OP_RESIZE,
 | 
				
			||||||
 | 
						} operation;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct sway_container *op_container;
 | 
				
			||||||
 | 
						enum wlr_edges op_resize_edge;
 | 
				
			||||||
 | 
						uint32_t op_button;
 | 
				
			||||||
 | 
						bool op_resize_preserve_ratio;
 | 
				
			||||||
 | 
						double op_ref_lx, op_ref_ly;         // cursor's x/y at start of op
 | 
				
			||||||
 | 
						double op_ref_width, op_ref_height;  // container's size at start of op
 | 
				
			||||||
 | 
						double op_ref_con_lx, op_ref_con_ly; // container's x/y at start of op
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						uint32_t last_button;
 | 
				
			||||||
 | 
						uint32_t last_button_serial;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wl_listener focus_destroy;
 | 
						struct wl_listener focus_destroy;
 | 
				
			||||||
	struct wl_listener new_container;
 | 
						struct wl_listener new_container;
 | 
				
			||||||
	struct wl_listener new_drag_icon;
 | 
						struct wl_listener new_drag_icon;
 | 
				
			||||||
| 
						 | 
					@ -80,7 +99,7 @@ void seat_configure_xcursor(struct sway_seat *seat);
 | 
				
			||||||
void seat_set_focus(struct sway_seat *seat, struct sway_container *container);
 | 
					void seat_set_focus(struct sway_seat *seat, struct sway_container *container);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void seat_set_focus_warp(struct sway_seat *seat,
 | 
					void seat_set_focus_warp(struct sway_seat *seat,
 | 
				
			||||||
		struct sway_container *container, bool warp);
 | 
							struct sway_container *container, bool warp, bool notify);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void seat_set_focus_surface(struct sway_seat *seat,
 | 
					void seat_set_focus_surface(struct sway_seat *seat,
 | 
				
			||||||
		struct wlr_surface *surface, bool unfocus);
 | 
							struct wlr_surface *surface, bool unfocus);
 | 
				
			||||||
| 
						 | 
					@ -105,6 +124,9 @@ struct sway_container *seat_get_focus(struct sway_seat *seat);
 | 
				
			||||||
struct sway_container *seat_get_focus_inactive(struct sway_seat *seat,
 | 
					struct sway_container *seat_get_focus_inactive(struct sway_seat *seat,
 | 
				
			||||||
		struct sway_container *container);
 | 
							struct sway_container *container);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct sway_container *seat_get_focus_inactive_tiling(struct sway_seat *seat,
 | 
				
			||||||
 | 
							struct sway_container *container);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Descend into the focus stack to find the focus-inactive view. Useful for
 | 
					 * Descend into the focus stack to find the focus-inactive view. Useful for
 | 
				
			||||||
 * container placement when they change position in the tree.
 | 
					 * container placement when they change position in the tree.
 | 
				
			||||||
| 
						 | 
					@ -134,4 +156,15 @@ bool seat_is_input_allowed(struct sway_seat *seat, struct wlr_surface *surface);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void drag_icon_update_position(struct sway_drag_icon *icon);
 | 
					void drag_icon_update_position(struct sway_drag_icon *icon);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void seat_begin_move(struct sway_seat *seat, struct sway_container *con,
 | 
				
			||||||
 | 
							uint32_t button);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void seat_begin_resize(struct sway_seat *seat, struct sway_container *con,
 | 
				
			||||||
 | 
							uint32_t button, enum wlr_edges edge);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void seat_end_mouse_operation(struct sway_seat *seat);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void seat_pointer_notify_button(struct sway_seat *seat, uint32_t time_msec,
 | 
				
			||||||
 | 
							uint32_t button, enum wlr_button_state state);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -16,5 +16,7 @@ void ipc_event_workspace(struct sway_container *old,
 | 
				
			||||||
void ipc_event_window(struct sway_container *window, const char *change);
 | 
					void ipc_event_window(struct sway_container *window, const char *change);
 | 
				
			||||||
void ipc_event_barconfig_update(struct bar_config *bar);
 | 
					void ipc_event_barconfig_update(struct bar_config *bar);
 | 
				
			||||||
void ipc_event_mode(const char *mode, bool pango);
 | 
					void ipc_event_mode(const char *mode, bool pango);
 | 
				
			||||||
 | 
					void ipc_event_shutdown(const char *reason);
 | 
				
			||||||
 | 
					void ipc_event_binding(struct sway_binding *binding);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,6 +5,7 @@
 | 
				
			||||||
#include <wayland-server.h>
 | 
					#include <wayland-server.h>
 | 
				
			||||||
#include <wlr/types/wlr_box.h>
 | 
					#include <wlr/types/wlr_box.h>
 | 
				
			||||||
#include <wlr/types/wlr_output.h>
 | 
					#include <wlr/types/wlr_output.h>
 | 
				
			||||||
 | 
					#include "config.h"
 | 
				
			||||||
#include "sway/tree/view.h"
 | 
					#include "sway/tree/view.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct sway_server;
 | 
					struct sway_server;
 | 
				
			||||||
| 
						 | 
					@ -38,15 +39,9 @@ struct sway_output {
 | 
				
			||||||
	} events;
 | 
						} events;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					typedef void (*sway_surface_iterator_func_t)(struct sway_output *output,
 | 
				
			||||||
 * Contains a surface's root geometry information. For instance, when rendering
 | 
						struct wlr_surface *surface, struct wlr_box *box, float rotation,
 | 
				
			||||||
 * a popup, this will contain the parent view's position and size.
 | 
						void *user_data);
 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
struct root_geometry {
 | 
					 | 
				
			||||||
	double x, y;
 | 
					 | 
				
			||||||
	int width, height;
 | 
					 | 
				
			||||||
	float rotation;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
void output_damage_whole(struct sway_output *output);
 | 
					void output_damage_whole(struct sway_output *output);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -65,36 +60,37 @@ struct sway_container *output_by_name(const char *name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void output_enable(struct sway_output *output);
 | 
					void output_enable(struct sway_output *output);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool output_has_opaque_lockscreen(struct sway_output *output,
 | 
					bool output_has_opaque_overlay_layer_surface(struct sway_output *output);
 | 
				
			||||||
	struct sway_seat *seat);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct sway_container *output_get_active_workspace(struct sway_output *output);
 | 
					struct sway_container *output_get_active_workspace(struct sway_output *output);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void output_render(struct sway_output *output, struct timespec *when,
 | 
					void output_render(struct sway_output *output, struct timespec *when,
 | 
				
			||||||
	pixman_region32_t *damage);
 | 
						pixman_region32_t *damage);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool output_get_surface_box(struct root_geometry *geo,
 | 
					void output_surface_for_each_surface(struct sway_output *output,
 | 
				
			||||||
	struct sway_output *output, struct wlr_surface *surface, int sx, int sy,
 | 
							struct wlr_surface *surface, double ox, double oy,
 | 
				
			||||||
	struct wlr_box *surface_box);
 | 
							sway_surface_iterator_func_t iterator, void *user_data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void output_surface_for_each_surface(struct wlr_surface *surface,
 | 
					void output_view_for_each_surface(struct sway_output *output,
 | 
				
			||||||
	double ox, double oy, struct root_geometry *geo,
 | 
						struct sway_view *view, sway_surface_iterator_func_t iterator,
 | 
				
			||||||
	wlr_surface_iterator_func_t iterator, void *user_data);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void output_view_for_each_surface(struct sway_view *view,
 | 
					 | 
				
			||||||
	struct sway_output *output, struct root_geometry *geo,
 | 
					 | 
				
			||||||
	wlr_surface_iterator_func_t iterator, void *user_data);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void output_layer_for_each_surface(struct wl_list *layer_surfaces,
 | 
					 | 
				
			||||||
	struct root_geometry *geo, wlr_surface_iterator_func_t iterator,
 | 
					 | 
				
			||||||
	void *user_data);
 | 
						void *user_data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void output_unmanaged_for_each_surface(struct wl_list *unmanaged,
 | 
					void output_view_for_each_popup(struct sway_output *output,
 | 
				
			||||||
	struct sway_output *output, struct root_geometry *geo,
 | 
							struct sway_view *view, sway_surface_iterator_func_t iterator,
 | 
				
			||||||
	wlr_surface_iterator_func_t iterator, void *user_data);
 | 
							void *user_data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void output_drag_icons_for_each_surface(struct wl_list *drag_icons,
 | 
					void output_layer_for_each_surface(struct sway_output *output,
 | 
				
			||||||
	struct sway_output *output, struct root_geometry *geo,
 | 
						struct wl_list *layer_surfaces, sway_surface_iterator_func_t iterator,
 | 
				
			||||||
	wlr_surface_iterator_func_t iterator, void *user_data);
 | 
						void *user_data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef HAVE_XWAYLAND
 | 
				
			||||||
 | 
					void output_unmanaged_for_each_surface(struct sway_output *output,
 | 
				
			||||||
 | 
						struct wl_list *unmanaged, sway_surface_iterator_func_t iterator,
 | 
				
			||||||
 | 
						void *user_data);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void output_drag_icons_for_each_surface(struct sway_output *output,
 | 
				
			||||||
 | 
						struct wl_list *drag_icons, sway_surface_iterator_func_t iterator,
 | 
				
			||||||
 | 
						void *user_data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										26
									
								
								include/sway/scratchpad.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								include/sway/scratchpad.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,26 @@
 | 
				
			||||||
 | 
					#ifndef _SWAY_SCRATCHPAD_H
 | 
				
			||||||
 | 
					#define _SWAY_SCRATCHPAD_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "tree/container.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Move a container to the scratchpad.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void scratchpad_add_container(struct sway_container *con);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Remove a container from the scratchpad.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void scratchpad_remove_container(struct sway_container *con);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Show or hide the next container on the scratchpad.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void scratchpad_toggle_auto(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Show or hide a specific container on the scratchpad.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void scratchpad_toggle_container(struct sway_container *con);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					@ -12,7 +12,10 @@
 | 
				
			||||||
#include <wlr/render/wlr_renderer.h>
 | 
					#include <wlr/render/wlr_renderer.h>
 | 
				
			||||||
// TODO WLR: make Xwayland optional
 | 
					// TODO WLR: make Xwayland optional
 | 
				
			||||||
#include "list.h"
 | 
					#include "list.h"
 | 
				
			||||||
 | 
					#include "config.h"
 | 
				
			||||||
 | 
					#ifdef HAVE_XWAYLAND
 | 
				
			||||||
#include "sway/xwayland.h"
 | 
					#include "sway/xwayland.h"
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct sway_server {
 | 
					struct sway_server {
 | 
				
			||||||
	struct wl_display *wl_display;
 | 
						struct wl_display *wl_display;
 | 
				
			||||||
| 
						 | 
					@ -39,11 +42,11 @@ struct sway_server {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wlr_xdg_shell *xdg_shell;
 | 
						struct wlr_xdg_shell *xdg_shell;
 | 
				
			||||||
	struct wl_listener xdg_shell_surface;
 | 
						struct wl_listener xdg_shell_surface;
 | 
				
			||||||
 | 
					#ifdef HAVE_XWAYLAND
 | 
				
			||||||
	struct sway_xwayland xwayland;
 | 
						struct sway_xwayland xwayland;
 | 
				
			||||||
	struct wl_listener xwayland_surface;
 | 
						struct wl_listener xwayland_surface;
 | 
				
			||||||
	struct wl_listener xwayland_ready;
 | 
						struct wl_listener xwayland_ready;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
	bool debug_txn_timings;
 | 
						bool debug_txn_timings;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	list_t *transactions;
 | 
						list_t *transactions;
 | 
				
			||||||
| 
						 | 
					@ -65,6 +68,7 @@ void handle_idle_inhibitor_v1(struct wl_listener *listener, void *data);
 | 
				
			||||||
void handle_layer_shell_surface(struct wl_listener *listener, void *data);
 | 
					void handle_layer_shell_surface(struct wl_listener *listener, void *data);
 | 
				
			||||||
void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data);
 | 
					void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data);
 | 
				
			||||||
void handle_xdg_shell_surface(struct wl_listener *listener, void *data);
 | 
					void handle_xdg_shell_surface(struct wl_listener *listener, void *data);
 | 
				
			||||||
 | 
					#ifdef HAVE_XWAYLAND
 | 
				
			||||||
void handle_xwayland_surface(struct wl_listener *listener, void *data);
 | 
					void handle_xwayland_surface(struct wl_listener *listener, void *data);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -60,6 +60,8 @@ struct sway_container_state {
 | 
				
			||||||
	double swayc_x, swayc_y;
 | 
						double swayc_x, swayc_y;
 | 
				
			||||||
	double swayc_width, swayc_height;
 | 
						double swayc_width, swayc_height;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool is_fullscreen;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool has_gaps;
 | 
						bool has_gaps;
 | 
				
			||||||
	double current_gaps;
 | 
						double current_gaps;
 | 
				
			||||||
	double gaps_inner;
 | 
						double gaps_inner;
 | 
				
			||||||
| 
						 | 
					@ -74,7 +76,6 @@ struct sway_container_state {
 | 
				
			||||||
	// View properties
 | 
						// View properties
 | 
				
			||||||
	double view_x, view_y;
 | 
						double view_x, view_y;
 | 
				
			||||||
	double view_width, view_height;
 | 
						double view_width, view_height;
 | 
				
			||||||
	bool is_fullscreen;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	enum sway_container_border border;
 | 
						enum sway_container_border border;
 | 
				
			||||||
	int border_thickness;
 | 
						int border_thickness;
 | 
				
			||||||
| 
						 | 
					@ -84,7 +85,7 @@ struct sway_container_state {
 | 
				
			||||||
	bool border_right;
 | 
						bool border_right;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Workspace properties
 | 
						// Workspace properties
 | 
				
			||||||
	struct sway_view *ws_fullscreen;
 | 
						struct sway_container *ws_fullscreen;
 | 
				
			||||||
	struct sway_container *ws_floating;
 | 
						struct sway_container *ws_floating;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -124,6 +125,8 @@ struct sway_container {
 | 
				
			||||||
	double saved_x, saved_y;
 | 
						double saved_x, saved_y;
 | 
				
			||||||
	double saved_width, saved_height;
 | 
						double saved_width, saved_height;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool is_fullscreen;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// The gaps currently applied to the container.
 | 
						// The gaps currently applied to the container.
 | 
				
			||||||
	double current_gaps;
 | 
						double current_gaps;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -135,6 +138,11 @@ struct sway_container {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct sway_container *parent;
 | 
						struct sway_container *parent;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Indicates that the container is a scratchpad container.
 | 
				
			||||||
 | 
						// Both hidden and visible scratchpad containers have scratchpad=true.
 | 
				
			||||||
 | 
						// Hidden scratchpad containers have a NULL parent.
 | 
				
			||||||
 | 
						bool scratchpad;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	float alpha;
 | 
						float alpha;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wlr_texture *title_focused;
 | 
						struct wlr_texture *title_focused;
 | 
				
			||||||
| 
						 | 
					@ -222,16 +230,13 @@ struct sway_container *container_parent(struct sway_container *container,
 | 
				
			||||||
 * surface-local coordinates of the given layout coordinates if the container
 | 
					 * surface-local coordinates of the given layout coordinates if the container
 | 
				
			||||||
 * is a view and the view contains a surface at those coordinates.
 | 
					 * is a view and the view contains a surface at those coordinates.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
struct sway_container *container_at(struct sway_container *container,
 | 
					struct sway_container *container_at(struct sway_container *workspace,
 | 
				
			||||||
		double ox, double oy, struct wlr_surface **surface,
 | 
							double lx, double ly, struct wlr_surface **surface,
 | 
				
			||||||
		double *sx, double *sy);
 | 
							double *sx, double *sy);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					struct sway_container *container_at_view(struct sway_container *view,
 | 
				
			||||||
 * Same as container_at, but only checks floating views and expects coordinates
 | 
							double lx, double ly, struct wlr_surface **surface,
 | 
				
			||||||
 * to be layout coordinates, as that's what floating views use.
 | 
							double *sx, double *sy);
 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
struct sway_container *floating_container_at(double lx, double ly,
 | 
					 | 
				
			||||||
		struct wlr_surface **surface, double *sx, double *sy);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Apply the function for each descendant of the container breadth first.
 | 
					 * Apply the function for each descendant of the container breadth first.
 | 
				
			||||||
| 
						 | 
					@ -262,6 +267,8 @@ int container_count_descendants_of_type(struct sway_container *con,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void container_create_notify(struct sway_container *container);
 | 
					void container_create_notify(struct sway_container *container);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void container_update_textures_recursive(struct sway_container *con);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void container_damage_whole(struct sway_container *container);
 | 
					void container_damage_whole(struct sway_container *container);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool container_reap_empty(struct sway_container *con);
 | 
					bool container_reap_empty(struct sway_container *con);
 | 
				
			||||||
| 
						 | 
					@ -289,6 +296,11 @@ void container_notify_subtree_changed(struct sway_container *container);
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
size_t container_titlebar_height(void);
 | 
					size_t container_titlebar_height(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Resize and center the container in its workspace.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void container_init_floating(struct sway_container *container);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void container_set_floating(struct sway_container *container, bool enable);
 | 
					void container_set_floating(struct sway_container *container, bool enable);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void container_set_geometry_from_floating_view(struct sway_container *con);
 | 
					void container_set_geometry_from_floating_view(struct sway_container *con);
 | 
				
			||||||
| 
						 | 
					@ -304,6 +316,12 @@ bool container_is_floating(struct sway_container *container);
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
void container_get_box(struct sway_container *container, struct wlr_box *box);
 | 
					void container_get_box(struct sway_container *container, struct wlr_box *box);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Move a floating container by the specified amount.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void container_floating_translate(struct sway_container *con,
 | 
				
			||||||
 | 
							double x_amount, double y_amount);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Move a floating container to a new layout-local position.
 | 
					 * Move a floating container to a new layout-local position.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
| 
						 | 
					@ -318,4 +336,32 @@ void container_set_dirty(struct sway_container *container);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool container_has_urgent_child(struct sway_container *container);
 | 
					bool container_has_urgent_child(struct sway_container *container);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * If the container is involved in a drag or resize operation via a mouse, this
 | 
				
			||||||
 | 
					 * ends the operation.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void container_end_mouse_operation(struct sway_container *container);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void container_set_fullscreen(struct sway_container *container, bool enable);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Return true if the container is floating, or a child of a floating split
 | 
				
			||||||
 | 
					 * container.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					bool container_is_floating_or_child(struct sway_container *container);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Return true if the container is fullscreen, or a child of a fullscreen split
 | 
				
			||||||
 | 
					 * container.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					bool container_is_fullscreen_or_child(struct sway_container *container);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Wrap the children of parent in a new container. The new container will be the
 | 
				
			||||||
 | 
					 * only child of parent.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The new container is returned.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct sway_container *container_wrap_children(struct sway_container *parent);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,6 +3,7 @@
 | 
				
			||||||
#include <wlr/types/wlr_output_layout.h>
 | 
					#include <wlr/types/wlr_output_layout.h>
 | 
				
			||||||
#include <wlr/render/wlr_texture.h>
 | 
					#include <wlr/render/wlr_texture.h>
 | 
				
			||||||
#include "sway/tree/container.h"
 | 
					#include "sway/tree/container.h"
 | 
				
			||||||
 | 
					#include "config.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum movement_direction {
 | 
					enum movement_direction {
 | 
				
			||||||
	MOVE_LEFT,
 | 
						MOVE_LEFT,
 | 
				
			||||||
| 
						 | 
					@ -14,10 +15,11 @@ enum movement_direction {
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum resize_edge {
 | 
					enum resize_edge {
 | 
				
			||||||
	RESIZE_EDGE_LEFT,
 | 
						RESIZE_EDGE_NONE   = 0,
 | 
				
			||||||
	RESIZE_EDGE_RIGHT,
 | 
						RESIZE_EDGE_LEFT   = 1,
 | 
				
			||||||
	RESIZE_EDGE_TOP,
 | 
						RESIZE_EDGE_RIGHT  = 2,
 | 
				
			||||||
	RESIZE_EDGE_BOTTOM,
 | 
						RESIZE_EDGE_TOP    = 4,
 | 
				
			||||||
 | 
						RESIZE_EDGE_BOTTOM = 8,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct sway_container;
 | 
					struct sway_container;
 | 
				
			||||||
| 
						 | 
					@ -26,14 +28,17 @@ struct sway_root {
 | 
				
			||||||
	struct wlr_output_layout *output_layout;
 | 
						struct wlr_output_layout *output_layout;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wl_listener output_layout_change;
 | 
						struct wl_listener output_layout_change;
 | 
				
			||||||
 | 
					#ifdef HAVE_XWAYLAND
 | 
				
			||||||
	struct wl_list xwayland_unmanaged; // sway_xwayland_unmanaged::link
 | 
						struct wl_list xwayland_unmanaged; // sway_xwayland_unmanaged::link
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
	struct wl_list drag_icons; // sway_drag_icon::link
 | 
						struct wl_list drag_icons; // sway_drag_icon::link
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wlr_texture *debug_tree;
 | 
						struct wlr_texture *debug_tree;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wl_list outputs; // sway_output::link
 | 
						struct wl_list outputs; // sway_output::link
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						list_t *scratchpad; // struct sway_container
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct {
 | 
						struct {
 | 
				
			||||||
		struct wl_signal new_container;
 | 
							struct wl_signal new_container;
 | 
				
			||||||
	} events;
 | 
						} events;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,7 +3,10 @@
 | 
				
			||||||
#include <wayland-server.h>
 | 
					#include <wayland-server.h>
 | 
				
			||||||
#include <wlr/types/wlr_surface.h>
 | 
					#include <wlr/types/wlr_surface.h>
 | 
				
			||||||
#include <wlr/types/wlr_xdg_shell_v6.h>
 | 
					#include <wlr/types/wlr_xdg_shell_v6.h>
 | 
				
			||||||
 | 
					#include "config.h"
 | 
				
			||||||
 | 
					#ifdef HAVE_XWAYLAND
 | 
				
			||||||
#include <wlr/xwayland.h>
 | 
					#include <wlr/xwayland.h>
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
#include "sway/input/input-manager.h"
 | 
					#include "sway/input/input-manager.h"
 | 
				
			||||||
#include "sway/input/seat.h"
 | 
					#include "sway/input/seat.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -12,7 +15,9 @@ struct sway_container;
 | 
				
			||||||
enum sway_view_type {
 | 
					enum sway_view_type {
 | 
				
			||||||
	SWAY_VIEW_XDG_SHELL_V6,
 | 
						SWAY_VIEW_XDG_SHELL_V6,
 | 
				
			||||||
	SWAY_VIEW_XDG_SHELL,
 | 
						SWAY_VIEW_XDG_SHELL,
 | 
				
			||||||
 | 
					#ifdef HAVE_XWAYLAND
 | 
				
			||||||
	SWAY_VIEW_XWAYLAND,
 | 
						SWAY_VIEW_XWAYLAND,
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum sway_view_prop {
 | 
					enum sway_view_prop {
 | 
				
			||||||
| 
						 | 
					@ -22,10 +27,14 @@ enum sway_view_prop {
 | 
				
			||||||
	VIEW_PROP_INSTANCE,
 | 
						VIEW_PROP_INSTANCE,
 | 
				
			||||||
	VIEW_PROP_WINDOW_TYPE,
 | 
						VIEW_PROP_WINDOW_TYPE,
 | 
				
			||||||
	VIEW_PROP_WINDOW_ROLE,
 | 
						VIEW_PROP_WINDOW_ROLE,
 | 
				
			||||||
 | 
					#ifdef HAVE_XWAYLAND
 | 
				
			||||||
	VIEW_PROP_X11_WINDOW_ID,
 | 
						VIEW_PROP_X11_WINDOW_ID,
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct sway_view_impl {
 | 
					struct sway_view_impl {
 | 
				
			||||||
 | 
						void (*get_constraints)(struct sway_view *view, double *min_width,
 | 
				
			||||||
 | 
								double *max_width, double *min_height, double *max_height);
 | 
				
			||||||
	const char *(*get_string_prop)(struct sway_view *view,
 | 
						const char *(*get_string_prop)(struct sway_view *view,
 | 
				
			||||||
			enum sway_view_prop prop);
 | 
								enum sway_view_prop prop);
 | 
				
			||||||
	uint32_t (*get_int_prop)(struct sway_view *view, enum sway_view_prop prop);
 | 
						uint32_t (*get_int_prop)(struct sway_view *view, enum sway_view_prop prop);
 | 
				
			||||||
| 
						 | 
					@ -38,7 +47,10 @@ struct sway_view_impl {
 | 
				
			||||||
	bool (*has_client_side_decorations)(struct sway_view *view);
 | 
						bool (*has_client_side_decorations)(struct sway_view *view);
 | 
				
			||||||
	void (*for_each_surface)(struct sway_view *view,
 | 
						void (*for_each_surface)(struct sway_view *view,
 | 
				
			||||||
		wlr_surface_iterator_func_t iterator, void *user_data);
 | 
							wlr_surface_iterator_func_t iterator, void *user_data);
 | 
				
			||||||
 | 
						void (*for_each_popup)(struct sway_view *view,
 | 
				
			||||||
 | 
							wlr_surface_iterator_func_t iterator, void *user_data);
 | 
				
			||||||
	void (*close)(struct sway_view *view);
 | 
						void (*close)(struct sway_view *view);
 | 
				
			||||||
 | 
						void (*close_popups)(struct sway_view *view);
 | 
				
			||||||
	void (*destroy)(struct sway_view *view);
 | 
						void (*destroy)(struct sway_view *view);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -60,8 +72,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;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool is_fullscreen;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	char *title_format;
 | 
						char *title_format;
 | 
				
			||||||
	enum sway_container_border border;
 | 
						enum sway_container_border border;
 | 
				
			||||||
	int border_thickness;
 | 
						int border_thickness;
 | 
				
			||||||
| 
						 | 
					@ -75,6 +85,9 @@ struct sway_view {
 | 
				
			||||||
	bool allow_request_urgent;
 | 
						bool allow_request_urgent;
 | 
				
			||||||
	struct wl_event_source *urgent_timer;
 | 
						struct wl_event_source *urgent_timer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct wlr_buffer *saved_buffer;
 | 
				
			||||||
 | 
						int saved_buffer_width, saved_buffer_height;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool destroying;
 | 
						bool destroying;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	list_t *executed_criteria; // struct criteria *
 | 
						list_t *executed_criteria; // struct criteria *
 | 
				
			||||||
| 
						 | 
					@ -88,7 +101,9 @@ struct sway_view {
 | 
				
			||||||
	union {
 | 
						union {
 | 
				
			||||||
		struct wlr_xdg_surface_v6 *wlr_xdg_surface_v6;
 | 
							struct wlr_xdg_surface_v6 *wlr_xdg_surface_v6;
 | 
				
			||||||
		struct wlr_xdg_surface *wlr_xdg_surface;
 | 
							struct wlr_xdg_surface *wlr_xdg_surface;
 | 
				
			||||||
 | 
					#ifdef HAVE_XWAYLAND
 | 
				
			||||||
		struct wlr_xwayland_surface *wlr_xwayland_surface;
 | 
							struct wlr_xwayland_surface *wlr_xwayland_surface;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
		struct wlr_wl_shell_surface *wlr_wl_shell_surface;
 | 
							struct wlr_wl_shell_surface *wlr_wl_shell_surface;
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -108,6 +123,8 @@ struct sway_xdg_shell_v6_view {
 | 
				
			||||||
	struct wl_listener request_resize;
 | 
						struct wl_listener request_resize;
 | 
				
			||||||
	struct wl_listener request_maximize;
 | 
						struct wl_listener request_maximize;
 | 
				
			||||||
	struct wl_listener request_fullscreen;
 | 
						struct wl_listener request_fullscreen;
 | 
				
			||||||
 | 
						struct wl_listener set_title;
 | 
				
			||||||
 | 
						struct wl_listener set_app_id;
 | 
				
			||||||
	struct wl_listener new_popup;
 | 
						struct wl_listener new_popup;
 | 
				
			||||||
	struct wl_listener map;
 | 
						struct wl_listener map;
 | 
				
			||||||
	struct wl_listener unmap;
 | 
						struct wl_listener unmap;
 | 
				
			||||||
| 
						 | 
					@ -122,12 +139,14 @@ struct sway_xdg_shell_view {
 | 
				
			||||||
	struct wl_listener request_resize;
 | 
						struct wl_listener request_resize;
 | 
				
			||||||
	struct wl_listener request_maximize;
 | 
						struct wl_listener request_maximize;
 | 
				
			||||||
	struct wl_listener request_fullscreen;
 | 
						struct wl_listener request_fullscreen;
 | 
				
			||||||
 | 
						struct wl_listener set_title;
 | 
				
			||||||
 | 
						struct wl_listener set_app_id;
 | 
				
			||||||
	struct wl_listener new_popup;
 | 
						struct wl_listener new_popup;
 | 
				
			||||||
	struct wl_listener map;
 | 
						struct wl_listener map;
 | 
				
			||||||
	struct wl_listener unmap;
 | 
						struct wl_listener unmap;
 | 
				
			||||||
	struct wl_listener destroy;
 | 
						struct wl_listener destroy;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					#ifdef HAVE_XWAYLAND
 | 
				
			||||||
struct sway_xwayland_view {
 | 
					struct sway_xwayland_view {
 | 
				
			||||||
	struct sway_view view;
 | 
						struct sway_view view;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -159,7 +178,7 @@ struct sway_xwayland_unmanaged {
 | 
				
			||||||
	struct wl_listener unmap;
 | 
						struct wl_listener unmap;
 | 
				
			||||||
	struct wl_listener destroy;
 | 
						struct wl_listener destroy;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
struct sway_view_child;
 | 
					struct sway_view_child;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct sway_view_child_impl {
 | 
					struct sway_view_child_impl {
 | 
				
			||||||
| 
						 | 
					@ -215,14 +234,12 @@ uint32_t view_get_window_type(struct sway_view *view);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const char *view_get_shell(struct sway_view *view);
 | 
					const char *view_get_shell(struct sway_view *view);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void view_get_constraints(struct sway_view *view, double *min_width,
 | 
				
			||||||
 | 
							double *max_width, double *min_height, double *max_height);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
uint32_t view_configure(struct sway_view *view, double lx, double ly, int width,
 | 
					uint32_t view_configure(struct sway_view *view, double lx, double ly, int width,
 | 
				
			||||||
	int height);
 | 
						int height);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Center the view in its workspace and build the swayc decorations around it.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
void view_init_floating(struct sway_view *view);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Configure the view's position and size based on the swayc's position and
 | 
					 * Configure the view's position and size based on the swayc's position and
 | 
				
			||||||
 * size, taking borders into consideration.
 | 
					 * size, taking borders into consideration.
 | 
				
			||||||
| 
						 | 
					@ -233,17 +250,24 @@ void view_set_activated(struct sway_view *view, bool activated);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void view_set_tiled(struct sway_view *view, bool tiled);
 | 
					void view_set_tiled(struct sway_view *view, bool tiled);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void view_set_fullscreen_raw(struct sway_view *view, bool fullscreen);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void view_set_fullscreen(struct sway_view *view, bool fullscreen);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void view_close(struct sway_view *view);
 | 
					void view_close(struct sway_view *view);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void view_close_popups(struct sway_view *view);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void view_damage_from(struct sway_view *view);
 | 
					void view_damage_from(struct sway_view *view);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Iterate all surfaces of a view (toplevels + popups).
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
void view_for_each_surface(struct sway_view *view,
 | 
					void view_for_each_surface(struct sway_view *view,
 | 
				
			||||||
	wlr_surface_iterator_func_t iterator, void *user_data);
 | 
						wlr_surface_iterator_func_t iterator, void *user_data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Iterate all popups recursively.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void view_for_each_popup(struct sway_view *view,
 | 
				
			||||||
 | 
						wlr_surface_iterator_func_t iterator, void *user_data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// view implementation
 | 
					// view implementation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void view_init(struct sway_view *view, enum sway_view_type type,
 | 
					void view_init(struct sway_view *view, enum sway_view_type type,
 | 
				
			||||||
| 
						 | 
					@ -272,9 +296,10 @@ struct sway_view *view_from_wlr_xdg_surface(
 | 
				
			||||||
	struct wlr_xdg_surface *xdg_surface);
 | 
						struct wlr_xdg_surface *xdg_surface);
 | 
				
			||||||
struct sway_view *view_from_wlr_xdg_surface_v6(
 | 
					struct sway_view *view_from_wlr_xdg_surface_v6(
 | 
				
			||||||
	struct wlr_xdg_surface_v6 *xdg_surface_v6);
 | 
						struct wlr_xdg_surface_v6 *xdg_surface_v6);
 | 
				
			||||||
 | 
					#ifdef HAVE_XWAYLAND
 | 
				
			||||||
struct sway_view *view_from_wlr_xwayland_surface(
 | 
					struct sway_view *view_from_wlr_xwayland_surface(
 | 
				
			||||||
	struct wlr_xwayland_surface *xsurface);
 | 
						struct wlr_xwayland_surface *xsurface);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
struct sway_view *view_from_wlr_surface(struct wlr_surface *surface);
 | 
					struct sway_view *view_from_wlr_surface(struct wlr_surface *surface);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
| 
						 | 
					@ -303,6 +328,8 @@ void view_clear_marks(struct sway_view *view);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool view_has_mark(struct sway_view *view, char *mark);
 | 
					bool view_has_mark(struct sway_view *view, char *mark);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void view_add_mark(struct sway_view *view, char *mark);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void view_update_marks_textures(struct sway_view *view);
 | 
					void view_update_marks_textures(struct sway_view *view);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
| 
						 | 
					@ -315,4 +342,8 @@ void view_set_urgent(struct sway_view *view, bool enable);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool view_is_urgent(struct sway_view *view);
 | 
					bool view_is_urgent(struct sway_view *view);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void view_remove_saved_buffer(struct sway_view *view);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void view_save_buffer(struct sway_view *view);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,7 +7,7 @@ struct sway_view;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct sway_workspace {
 | 
					struct sway_workspace {
 | 
				
			||||||
	struct sway_container *swayc;
 | 
						struct sway_container *swayc;
 | 
				
			||||||
	struct sway_view *fullscreen;
 | 
						struct sway_container *fullscreen;
 | 
				
			||||||
	struct sway_container *floating;
 | 
						struct sway_container *floating;
 | 
				
			||||||
	list_t *output_priority;
 | 
						list_t *output_priority;
 | 
				
			||||||
	bool urgent;
 | 
						bool urgent;
 | 
				
			||||||
| 
						 | 
					@ -44,6 +44,10 @@ void workspace_output_add_priority(struct sway_container *workspace,
 | 
				
			||||||
struct sway_container *workspace_output_get_highest_available(
 | 
					struct sway_container *workspace_output_get_highest_available(
 | 
				
			||||||
		struct sway_container *ws, struct sway_container *exclude);
 | 
							struct sway_container *ws, struct sway_container *exclude);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct sway_container *workspace_for_pid(pid_t pid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void workspace_record_pid(pid_t pid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void workspace_detect_urgent(struct sway_container *workspace);
 | 
					void workspace_detect_urgent(struct sway_container *workspace);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,10 +0,0 @@
 | 
				
			||||||
#include <json-c/json.h>
 | 
					 | 
				
			||||||
#include "wlc/wlc.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void init_json_tree(int socketfd);
 | 
					 | 
				
			||||||
void free_json_tree();
 | 
					 | 
				
			||||||
char *get_focused_output();
 | 
					 | 
				
			||||||
char *create_payload(const char *output, struct wlc_geometry *g);
 | 
					 | 
				
			||||||
struct wlc_geometry *get_container_geometry(json_object *container);
 | 
					 | 
				
			||||||
json_object *get_focused_container();
 | 
					 | 
				
			||||||
json_object *get_output_container(const char *output);
 | 
					 | 
				
			||||||
							
								
								
									
										13
									
								
								include/swaynag/config.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								include/swaynag/config.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,13 @@
 | 
				
			||||||
 | 
					#ifndef _SWAYNAG_CONFIG_H
 | 
				
			||||||
 | 
					#define _SWAYNAG_CONFIG_H
 | 
				
			||||||
 | 
					#include "swaynag/swaynag.h"
 | 
				
			||||||
 | 
					#include "list.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int swaynag_parse_options(int argc, char **argv, struct swaynag *swaynag,
 | 
				
			||||||
 | 
							list_t *types, struct swaynag_type *type, char **config, bool *debug);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					char *swaynag_get_config_path(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int swaynag_load_config(char *path, struct swaynag *swaynag, list_t *types);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
							
								
								
									
										7
									
								
								include/swaynag/render.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								include/swaynag/render.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,7 @@
 | 
				
			||||||
 | 
					#ifndef _SWAYNAG_RENDER_H
 | 
				
			||||||
 | 
					#define _SWAYNAG_RENDER_H
 | 
				
			||||||
 | 
					#include "swaynag/swaynag.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void render_frame(struct swaynag *swaynag);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
							
								
								
									
										100
									
								
								include/swaynag/swaynag.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								include/swaynag/swaynag.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,100 @@
 | 
				
			||||||
 | 
					#ifndef _SWAYNAG_SWAYNAG_H
 | 
				
			||||||
 | 
					#define _SWAYNAG_SWAYNAG_H
 | 
				
			||||||
 | 
					#include <stdint.h>
 | 
				
			||||||
 | 
					#include <strings.h>
 | 
				
			||||||
 | 
					#include "list.h"
 | 
				
			||||||
 | 
					#include "pool-buffer.h"
 | 
				
			||||||
 | 
					#include "swaynag/types.h"
 | 
				
			||||||
 | 
					#include "xdg-output-unstable-v1-client-protocol.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define SWAYNAG_MAX_HEIGHT 500
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct swaynag;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum swaynag_action_type {
 | 
				
			||||||
 | 
						SWAYNAG_ACTION_DISMISS,
 | 
				
			||||||
 | 
						SWAYNAG_ACTION_EXPAND,
 | 
				
			||||||
 | 
						SWAYNAG_ACTION_COMMAND,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct swaynag_pointer {
 | 
				
			||||||
 | 
						struct wl_pointer *pointer;
 | 
				
			||||||
 | 
						uint32_t serial;
 | 
				
			||||||
 | 
						struct wl_cursor_theme *cursor_theme;
 | 
				
			||||||
 | 
						struct wl_cursor_image *cursor_image;
 | 
				
			||||||
 | 
						struct wl_surface *cursor_surface;
 | 
				
			||||||
 | 
						int x;
 | 
				
			||||||
 | 
						int y;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct swaynag_output {
 | 
				
			||||||
 | 
						char *name;
 | 
				
			||||||
 | 
						struct wl_output *wl_output;
 | 
				
			||||||
 | 
						uint32_t wl_name;
 | 
				
			||||||
 | 
						uint32_t scale;
 | 
				
			||||||
 | 
						struct swaynag *swaynag;
 | 
				
			||||||
 | 
						struct wl_list link;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct swaynag_button {
 | 
				
			||||||
 | 
						char *text;
 | 
				
			||||||
 | 
						enum swaynag_action_type type;
 | 
				
			||||||
 | 
						char *action;
 | 
				
			||||||
 | 
						int x;
 | 
				
			||||||
 | 
						int y;
 | 
				
			||||||
 | 
						int width;
 | 
				
			||||||
 | 
						int height;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct swaynag_details {
 | 
				
			||||||
 | 
						bool visible;
 | 
				
			||||||
 | 
						char *message;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int x;
 | 
				
			||||||
 | 
						int y;
 | 
				
			||||||
 | 
						int width;
 | 
				
			||||||
 | 
						int height;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int offset;
 | 
				
			||||||
 | 
						int visible_lines;
 | 
				
			||||||
 | 
						int total_lines;
 | 
				
			||||||
 | 
						struct swaynag_button button_details;
 | 
				
			||||||
 | 
						struct swaynag_button button_up;
 | 
				
			||||||
 | 
						struct swaynag_button button_down;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct swaynag {
 | 
				
			||||||
 | 
						bool run_display;
 | 
				
			||||||
 | 
						int querying_outputs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct wl_display *display;
 | 
				
			||||||
 | 
						struct wl_compositor *compositor;
 | 
				
			||||||
 | 
						struct wl_seat *seat;
 | 
				
			||||||
 | 
						struct wl_shm *shm;
 | 
				
			||||||
 | 
						struct swaynag_pointer pointer;
 | 
				
			||||||
 | 
						struct zxdg_output_manager_v1 *xdg_output_manager;
 | 
				
			||||||
 | 
						struct wl_list outputs;  // swaynag_output::link
 | 
				
			||||||
 | 
						struct swaynag_output *output;
 | 
				
			||||||
 | 
						struct zwlr_layer_shell_v1 *layer_shell;
 | 
				
			||||||
 | 
						struct zwlr_layer_surface_v1 *layer_surface;
 | 
				
			||||||
 | 
						struct wl_surface *surface;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						uint32_t width;
 | 
				
			||||||
 | 
						uint32_t height;
 | 
				
			||||||
 | 
						int32_t scale;
 | 
				
			||||||
 | 
						struct pool_buffer buffers[2];
 | 
				
			||||||
 | 
						struct pool_buffer *current_buffer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct swaynag_type *type;
 | 
				
			||||||
 | 
						char *message;
 | 
				
			||||||
 | 
						list_t *buttons;
 | 
				
			||||||
 | 
						struct swaynag_details details;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void swaynag_setup(struct swaynag *swaynag);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void swaynag_run(struct swaynag *swaynag);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void swaynag_destroy(struct swaynag *swaynag);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
							
								
								
									
										39
									
								
								include/swaynag/types.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								include/swaynag/types.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,39 @@
 | 
				
			||||||
 | 
					#ifndef _SWAYNAG_TYPES_H
 | 
				
			||||||
 | 
					#define _SWAYNAG_TYPES_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct swaynag_type {
 | 
				
			||||||
 | 
						char *name;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						char *font;
 | 
				
			||||||
 | 
						char *output;
 | 
				
			||||||
 | 
						uint32_t anchors;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						uint32_t button_background;
 | 
				
			||||||
 | 
						uint32_t background;
 | 
				
			||||||
 | 
						uint32_t text;
 | 
				
			||||||
 | 
						uint32_t border;
 | 
				
			||||||
 | 
						uint32_t border_bottom;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						uint32_t bar_border_thickness;
 | 
				
			||||||
 | 
						uint32_t message_padding;
 | 
				
			||||||
 | 
						uint32_t details_border_thickness;
 | 
				
			||||||
 | 
						uint32_t button_border_thickness;
 | 
				
			||||||
 | 
						uint32_t button_gap;
 | 
				
			||||||
 | 
						uint32_t button_gap_close;
 | 
				
			||||||
 | 
						uint32_t button_margin_right;
 | 
				
			||||||
 | 
						uint32_t button_padding;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void swaynag_types_add_default(list_t *types);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct swaynag_type *swaynag_type_get(list_t *types, char *name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct swaynag_type *swaynag_type_clone(struct swaynag_type *type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void swaynag_type_merge(struct swaynag_type *dest, struct swaynag_type *src);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void swaynag_type_free(struct swaynag_type *type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void swaynag_types_free(list_t *types);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					@ -2,6 +2,7 @@
 | 
				
			||||||
#define _SWAY_UTIL_H
 | 
					#define _SWAY_UTIL_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <stdint.h>
 | 
					#include <stdint.h>
 | 
				
			||||||
 | 
					#include <stdbool.h>
 | 
				
			||||||
#include <unistd.h>
 | 
					#include <unistd.h>
 | 
				
			||||||
#include <sys/types.h> 
 | 
					#include <sys/types.h> 
 | 
				
			||||||
#include <xkbcommon/xkbcommon.h>
 | 
					#include <xkbcommon/xkbcommon.h>
 | 
				
			||||||
| 
						 | 
					@ -50,6 +51,14 @@ pid_t get_parent_pid(pid_t pid);
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
uint32_t parse_color(const char *color);
 | 
					uint32_t parse_color(const char *color);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Given a string that represents a boolean, return the boolean value. This
 | 
				
			||||||
 | 
					 * function also takes in the current boolean value to support toggling. If
 | 
				
			||||||
 | 
					 * toggling is not desired, pass in true for current so that toggling values
 | 
				
			||||||
 | 
					 * get parsed as not true.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					bool parse_boolean(const char *boolean, bool current);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Given a path string, recurseively resolves any symlinks to their targets
 | 
					 * Given a path string, recurseively resolves any symlinks to their targets
 | 
				
			||||||
 * (which may be a file, directory) and returns the result.
 | 
					 * (which may be a file, directory) and returns the result.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										25
									
								
								meson.build
									
										
									
									
									
								
							
							
						
						
									
										25
									
								
								meson.build
									
										
									
									
									
								
							| 
						 | 
					@ -12,6 +12,7 @@ project(
 | 
				
			||||||
add_project_arguments('-Wno-unused-parameter', language: 'c')
 | 
					add_project_arguments('-Wno-unused-parameter', language: 'c')
 | 
				
			||||||
add_project_arguments('-Wno-unused-function', language: 'c')
 | 
					add_project_arguments('-Wno-unused-function', language: 'c')
 | 
				
			||||||
add_project_arguments('-Wno-unused-result', language: 'c')
 | 
					add_project_arguments('-Wno-unused-result', language: 'c')
 | 
				
			||||||
 | 
					add_project_arguments('-DWLR_USE_UNSTABLE', language: 'c')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
cc = meson.get_compiler('c')
 | 
					cc = meson.get_compiler('c')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -43,11 +44,17 @@ systemd        = dependency('libsystemd', required: false)
 | 
				
			||||||
elogind        = dependency('libelogind', required: false)
 | 
					elogind        = dependency('libelogind', required: false)
 | 
				
			||||||
math           = cc.find_library('m')
 | 
					math           = cc.find_library('m')
 | 
				
			||||||
rt             = cc.find_library('rt')
 | 
					rt             = cc.find_library('rt')
 | 
				
			||||||
xcb            = dependency('xcb')
 | 
					 | 
				
			||||||
git            = find_program('git', required: false)
 | 
					git            = find_program('git', required: false)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
conf_data = configuration_data()
 | 
					conf_data = configuration_data()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if get_option('enable-xwayland')
 | 
				
			||||||
 | 
						conf_data.set('HAVE_XWAYLAND', true)
 | 
				
			||||||
 | 
						xcb = dependency('xcb')
 | 
				
			||||||
 | 
					else
 | 
				
			||||||
 | 
						conf_data.set('HAVE_XWAYLAND', false)
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if gdk_pixbuf.found()
 | 
					if gdk_pixbuf.found()
 | 
				
			||||||
	conf_data.set('HAVE_GDK_PIXBUF', true)
 | 
						conf_data.set('HAVE_GDK_PIXBUF', true)
 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
| 
						 | 
					@ -75,6 +82,8 @@ if scdoc.found()
 | 
				
			||||||
		'swaylock/swaylock.1.scd',
 | 
							'swaylock/swaylock.1.scd',
 | 
				
			||||||
		'swaymsg/swaymsg.1.scd',
 | 
							'swaymsg/swaymsg.1.scd',
 | 
				
			||||||
		'swayidle/swayidle.1.scd',
 | 
							'swayidle/swayidle.1.scd',
 | 
				
			||||||
 | 
							'swaynag/swaynag.1.scd',
 | 
				
			||||||
 | 
							'swaynag/swaynag.5.scd',
 | 
				
			||||||
	]
 | 
						]
 | 
				
			||||||
	foreach filename : man_files
 | 
						foreach filename : man_files
 | 
				
			||||||
		topic = filename.split('.')[-3].split('/')[-1]
 | 
							topic = filename.split('.')[-3].split('/')[-1]
 | 
				
			||||||
| 
						 | 
					@ -123,6 +132,7 @@ subdir('swaybg')
 | 
				
			||||||
subdir('swaybar')
 | 
					subdir('swaybar')
 | 
				
			||||||
subdir('swaylock')
 | 
					subdir('swaylock')
 | 
				
			||||||
subdir('swayidle')
 | 
					subdir('swayidle')
 | 
				
			||||||
 | 
					subdir('swaynag')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
config = configuration_data()
 | 
					config = configuration_data()
 | 
				
			||||||
config.set('sysconfdir', join_paths(prefix, sysconfdir))
 | 
					config.set('sysconfdir', join_paths(prefix, sysconfdir))
 | 
				
			||||||
| 
						 | 
					@ -176,7 +186,6 @@ endif
 | 
				
			||||||
if (get_option('zsh_completions'))
 | 
					if (get_option('zsh_completions'))
 | 
				
			||||||
	zsh_files = files(
 | 
						zsh_files = files(
 | 
				
			||||||
		'completions/zsh/_sway',
 | 
							'completions/zsh/_sway',
 | 
				
			||||||
		'completions/zsh/_swaygrab',
 | 
					 | 
				
			||||||
		'completions/zsh/_swaylock',
 | 
							'completions/zsh/_swaylock',
 | 
				
			||||||
		'completions/zsh/_swaymsg',
 | 
							'completions/zsh/_swaymsg',
 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
| 
						 | 
					@ -184,3 +193,15 @@ if (get_option('zsh_completions'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	install_data(zsh_files, install_dir: zsh_install_dir)
 | 
						install_data(zsh_files, install_dir: zsh_install_dir)
 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if (get_option('bash_completions'))
 | 
				
			||||||
 | 
						bash_files = files(
 | 
				
			||||||
 | 
							'completions/bash/sway',
 | 
				
			||||||
 | 
							'completions/bash/swayidle',
 | 
				
			||||||
 | 
							'completions/bash/swaylock',
 | 
				
			||||||
 | 
							'completions/bash/swaymsg',
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
						bash_install_dir = datadir + '/bash-completion/completions'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						install_data(bash_files, install_dir: bash_install_dir)
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,3 +1,5 @@
 | 
				
			||||||
option('sway_version', type : 'string', description: 'The version string reported in `sway --version`.')
 | 
					option('sway_version', type : 'string', description: 'The version string reported in `sway --version`.')
 | 
				
			||||||
option('default_wallpaper', type: 'boolean', value: true, description: 'Install the default wallpaper.')
 | 
					option('default_wallpaper', type: 'boolean', value: true, description: 'Install the default wallpaper.')
 | 
				
			||||||
option('zsh_completions', type: 'boolean', value: true, description: 'Install zsh shell completions.')
 | 
					option('zsh_completions', type: 'boolean', value: true, description: 'Install zsh shell completions.')
 | 
				
			||||||
 | 
					option('bash_completions', type: 'boolean', value: true, description: 'Install bash shell completions.')
 | 
				
			||||||
 | 
					option('enable-xwayland', type: 'boolean', value: true, description: 'Enable support for X11 applications')
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -12,7 +12,6 @@
 | 
				
			||||||
permit * fullscreen keyboard mouse
 | 
					permit * fullscreen keyboard mouse
 | 
				
			||||||
permit @prefix@/bin/swaylock lock
 | 
					permit @prefix@/bin/swaylock lock
 | 
				
			||||||
permit @prefix@/bin/swaybg background
 | 
					permit @prefix@/bin/swaybg background
 | 
				
			||||||
permit @prefix@/bin/swaygrab screenshot
 | 
					 | 
				
			||||||
permit @prefix@/bin/swaybar panel
 | 
					permit @prefix@/bin/swaybar panel
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Configures enabled IPC features for specific programs
 | 
					# Configures enabled IPC features for specific programs
 | 
				
			||||||
| 
						 | 
					@ -36,11 +35,6 @@ ipc @prefix@/bin/swaybar {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ipc @prefix@/bin/swaygrab {
 | 
					 | 
				
			||||||
    outputs enabled
 | 
					 | 
				
			||||||
    tree enabled
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
ipc @prefix@/bin/swaylock {
 | 
					ipc @prefix@/bin/swaylock {
 | 
				
			||||||
    outputs enabled
 | 
					    outputs enabled
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -103,6 +103,7 @@ static struct cmd_handler handlers[] = {
 | 
				
			||||||
	{ "exec_always", cmd_exec_always },
 | 
						{ "exec_always", cmd_exec_always },
 | 
				
			||||||
	{ "floating_maximum_size", cmd_floating_maximum_size },
 | 
						{ "floating_maximum_size", cmd_floating_maximum_size },
 | 
				
			||||||
	{ "floating_minimum_size", cmd_floating_minimum_size },
 | 
						{ "floating_minimum_size", cmd_floating_minimum_size },
 | 
				
			||||||
 | 
						{ "floating_modifier", cmd_floating_modifier },
 | 
				
			||||||
	{ "focus", cmd_focus },
 | 
						{ "focus", cmd_focus },
 | 
				
			||||||
	{ "focus_follows_mouse", cmd_focus_follows_mouse },
 | 
						{ "focus_follows_mouse", cmd_focus_follows_mouse },
 | 
				
			||||||
	{ "focus_wrapping", cmd_focus_wrapping },
 | 
						{ "focus_wrapping", cmd_focus_wrapping },
 | 
				
			||||||
| 
						 | 
					@ -148,6 +149,7 @@ static struct cmd_handler command_handlers[] = {
 | 
				
			||||||
	{ "reload", cmd_reload },
 | 
						{ "reload", cmd_reload },
 | 
				
			||||||
	{ "rename", cmd_rename },
 | 
						{ "rename", cmd_rename },
 | 
				
			||||||
	{ "resize", cmd_resize },
 | 
						{ "resize", cmd_resize },
 | 
				
			||||||
 | 
						{ "scratchpad", cmd_scratchpad },
 | 
				
			||||||
	{ "split", cmd_split },
 | 
						{ "split", cmd_split },
 | 
				
			||||||
	{ "splith", cmd_splith },
 | 
						{ "splith", cmd_splith },
 | 
				
			||||||
	{ "splitt", cmd_splitt },
 | 
						{ "splitt", cmd_splitt },
 | 
				
			||||||
| 
						 | 
					@ -325,7 +327,7 @@ struct cmd_results *execute_command(char *_exec, struct sway_seat *seat) {
 | 
				
			||||||
	} while(head);
 | 
						} while(head);
 | 
				
			||||||
cleanup:
 | 
					cleanup:
 | 
				
			||||||
	free(exec);
 | 
						free(exec);
 | 
				
			||||||
	free(views);
 | 
						list_free(views);
 | 
				
			||||||
	if (!results) {
 | 
						if (!results) {
 | 
				
			||||||
		results = cmd_results_new(CMD_SUCCESS, NULL, NULL);
 | 
							results = cmd_results_new(CMD_SUCCESS, NULL, NULL);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,3 +1,4 @@
 | 
				
			||||||
 | 
					#define _XOPEN_SOURCE 500
 | 
				
			||||||
#ifdef __linux__
 | 
					#ifdef __linux__
 | 
				
			||||||
#include <linux/input-event-codes.h>
 | 
					#include <linux/input-event-codes.h>
 | 
				
			||||||
#elif __FreeBSD__
 | 
					#elif __FreeBSD__
 | 
				
			||||||
| 
						 | 
					@ -5,9 +6,11 @@
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
#include <xkbcommon/xkbcommon.h>
 | 
					#include <xkbcommon/xkbcommon.h>
 | 
				
			||||||
#include <xkbcommon/xkbcommon-names.h>
 | 
					#include <xkbcommon/xkbcommon-names.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
#include <strings.h>
 | 
					#include <strings.h>
 | 
				
			||||||
#include "sway/commands.h"
 | 
					#include "sway/commands.h"
 | 
				
			||||||
#include "sway/config.h"
 | 
					#include "sway/config.h"
 | 
				
			||||||
 | 
					#include "sway/ipc-server.h"
 | 
				
			||||||
#include "list.h"
 | 
					#include "list.h"
 | 
				
			||||||
#include "log.h"
 | 
					#include "log.h"
 | 
				
			||||||
#include "stringop.h"
 | 
					#include "stringop.h"
 | 
				
			||||||
| 
						 | 
					@ -27,6 +30,33 @@ void free_sway_binding(struct sway_binding *binding) {
 | 
				
			||||||
	free(binding);
 | 
						free(binding);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct sway_binding *sway_binding_dup(struct sway_binding *sb) {
 | 
				
			||||||
 | 
						struct sway_binding *new_sb = calloc(1, sizeof(struct sway_binding));
 | 
				
			||||||
 | 
						if (!new_sb) {
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						new_sb->type = sb->type;
 | 
				
			||||||
 | 
						new_sb->order = sb->order;
 | 
				
			||||||
 | 
						new_sb->flags = sb->flags;
 | 
				
			||||||
 | 
						new_sb->modifiers = sb->modifiers;
 | 
				
			||||||
 | 
						new_sb->command = strdup(sb->command);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						new_sb->keys = create_list();
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
						for (i = 0; i < sb->keys->length; ++i) {
 | 
				
			||||||
 | 
							xkb_keysym_t *key = malloc(sizeof(xkb_keysym_t));
 | 
				
			||||||
 | 
							if (!key) {
 | 
				
			||||||
 | 
								free_sway_binding(new_sb);
 | 
				
			||||||
 | 
								return NULL;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							*key = *(xkb_keysym_t *)sb->keys->items[i];
 | 
				
			||||||
 | 
							list_add(new_sb->keys, key);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return new_sb;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Returns true if the bindings have the same key and modifier combinations.
 | 
					 * Returns true if the bindings have the same key and modifier combinations.
 | 
				
			||||||
 * Note that keyboard layout is not considered, so the bindings might actually
 | 
					 * Note that keyboard layout is not considered, so the bindings might actually
 | 
				
			||||||
| 
						 | 
					@ -34,11 +64,14 @@ void free_sway_binding(struct sway_binding *binding) {
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static bool binding_key_compare(struct sway_binding *binding_a,
 | 
					static bool binding_key_compare(struct sway_binding *binding_a,
 | 
				
			||||||
		struct sway_binding *binding_b) {
 | 
							struct sway_binding *binding_b) {
 | 
				
			||||||
	if (binding_a->release != binding_b->release) {
 | 
						if (binding_a->type != binding_b->type) {
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (binding_a->bindcode != binding_b->bindcode) {
 | 
						uint32_t conflict_generating_flags = BINDING_RELEASE | BINDING_BORDER
 | 
				
			||||||
 | 
								| BINDING_CONTENTS | BINDING_TITLEBAR;
 | 
				
			||||||
 | 
						if ((binding_a->flags & conflict_generating_flags) !=
 | 
				
			||||||
 | 
								(binding_b->flags & conflict_generating_flags)) {
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -69,6 +102,66 @@ static int key_qsort_cmp(const void *keyp_a, const void *keyp_b) {
 | 
				
			||||||
	return (key_a < key_b) ? -1 : ((key_a > key_b) ? 1 : 0);
 | 
						return (key_a < key_b) ? -1 : ((key_a > key_b) ? 1 : 0);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * From a keycode, bindcode, or bindsym name and the most likely binding type,
 | 
				
			||||||
 | 
					 * identify the appropriate numeric value corresponding to the key. Return NULL
 | 
				
			||||||
 | 
					 * and set *key_val if successful, otherwise return a specific error. Change
 | 
				
			||||||
 | 
					 * the value of *type if the initial type guess was incorrect and if this
 | 
				
			||||||
 | 
					 * was the first identified key.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static struct cmd_results *identify_key(const char* name, bool first_key,
 | 
				
			||||||
 | 
							uint32_t* key_val, enum binding_input_type* type) {
 | 
				
			||||||
 | 
						if (*type == BINDING_KEYCODE) {
 | 
				
			||||||
 | 
							// check for keycode
 | 
				
			||||||
 | 
							xkb_keycode_t keycode = strtol(name, NULL, 10);
 | 
				
			||||||
 | 
							if (!xkb_keycode_is_legal_ext(keycode)) {
 | 
				
			||||||
 | 
								return cmd_results_new(CMD_INVALID, "bindcode",
 | 
				
			||||||
 | 
										"Invalid keycode '%s'", name);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							*key_val = keycode;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							// check for keysym
 | 
				
			||||||
 | 
							xkb_keysym_t keysym = xkb_keysym_from_name(name,
 | 
				
			||||||
 | 
									XKB_KEYSYM_CASE_INSENSITIVE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Check for mouse binding
 | 
				
			||||||
 | 
							uint32_t button = 0;
 | 
				
			||||||
 | 
							if (strncasecmp(name, "button", strlen("button")) == 0 &&
 | 
				
			||||||
 | 
									strlen(name) == strlen("button0")) {
 | 
				
			||||||
 | 
								button = name[strlen("button")] - '1' + BTN_LEFT;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (*type == BINDING_KEYSYM) {
 | 
				
			||||||
 | 
								if (button) {
 | 
				
			||||||
 | 
									if (first_key) {
 | 
				
			||||||
 | 
										*type = BINDING_MOUSE;
 | 
				
			||||||
 | 
										*key_val = button;
 | 
				
			||||||
 | 
									} else {
 | 
				
			||||||
 | 
										return cmd_results_new(CMD_INVALID, "bindsym",
 | 
				
			||||||
 | 
												"Mixed button '%s' into key sequence", name);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								} else if (keysym) {
 | 
				
			||||||
 | 
									*key_val = keysym;
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									return cmd_results_new(CMD_INVALID, "bindsym",
 | 
				
			||||||
 | 
											"Unknown key '%s'", name);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								if (button) {
 | 
				
			||||||
 | 
									*key_val = button;
 | 
				
			||||||
 | 
								} else if (keysym) {
 | 
				
			||||||
 | 
									return cmd_results_new(CMD_INVALID, "bindsym",
 | 
				
			||||||
 | 
											"Mixed keysym '%s' into button sequence", name);
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									return cmd_results_new(CMD_INVALID, "bindsym",
 | 
				
			||||||
 | 
											"Unknown button '%s'", name);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct cmd_results *cmd_bindsym_or_bindcode(int argc, char **argv,
 | 
					static struct cmd_results *cmd_bindsym_or_bindcode(int argc, char **argv,
 | 
				
			||||||
		bool bindcode) {
 | 
							bool bindcode) {
 | 
				
			||||||
	const char *bindtype = bindcode ? "bindcode" : "bindsym";
 | 
						const char *bindtype = bindcode ? "bindcode" : "bindsym";
 | 
				
			||||||
| 
						 | 
					@ -85,22 +178,34 @@ static struct cmd_results *cmd_bindsym_or_bindcode(int argc, char **argv,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	binding->keys = create_list();
 | 
						binding->keys = create_list();
 | 
				
			||||||
	binding->modifiers = 0;
 | 
						binding->modifiers = 0;
 | 
				
			||||||
	binding->release = false;
 | 
						binding->flags = 0;
 | 
				
			||||||
	binding->locked = false;
 | 
						binding->type = bindcode ? BINDING_KEYCODE : BINDING_KEYSYM;
 | 
				
			||||||
	binding->bindcode = bindcode;
 | 
					
 | 
				
			||||||
 | 
						bool exclude_titlebar = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Handle --release and --locked
 | 
						// Handle --release and --locked
 | 
				
			||||||
	while (argc > 0) {
 | 
						while (argc > 0) {
 | 
				
			||||||
		if (strcmp("--release", argv[0]) == 0) {
 | 
							if (strcmp("--release", argv[0]) == 0) {
 | 
				
			||||||
			binding->release = true;
 | 
								binding->flags |= BINDING_RELEASE;
 | 
				
			||||||
		} else if (strcmp("--locked", argv[0]) == 0) {
 | 
							} else if (strcmp("--locked", argv[0]) == 0) {
 | 
				
			||||||
			binding->locked = true;
 | 
								binding->flags |= BINDING_LOCKED;
 | 
				
			||||||
 | 
							} else if (strcmp("--whole-window", argv[0]) == 0) {
 | 
				
			||||||
 | 
								binding->flags |= BINDING_BORDER | BINDING_CONTENTS | BINDING_TITLEBAR;
 | 
				
			||||||
 | 
							} else if (strcmp("--border", argv[0]) == 0) {
 | 
				
			||||||
 | 
								binding->flags |= BINDING_BORDER;
 | 
				
			||||||
 | 
							} else if (strcmp("--exclude-titlebar", argv[0]) == 0) {
 | 
				
			||||||
 | 
								exclude_titlebar = true;
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		argv++;
 | 
							argv++;
 | 
				
			||||||
		argc--;
 | 
							argc--;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if (binding->flags & (BINDING_BORDER | BINDING_CONTENTS | BINDING_TITLEBAR)
 | 
				
			||||||
 | 
								|| exclude_titlebar) {
 | 
				
			||||||
 | 
							binding->type = BINDING_MOUSE;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (argc < 2) {
 | 
						if (argc < 2) {
 | 
				
			||||||
		free_sway_binding(binding);
 | 
							free_sway_binding(binding);
 | 
				
			||||||
		return cmd_results_new(CMD_FAILURE, bindtype,
 | 
							return cmd_results_new(CMD_FAILURE, bindtype,
 | 
				
			||||||
| 
						 | 
					@ -119,64 +224,47 @@ static struct cmd_results *cmd_bindsym_or_bindcode(int argc, char **argv,
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		xkb_keycode_t keycode;
 | 
							// Identify the key and possibly change binding->type
 | 
				
			||||||
		xkb_keysym_t keysym;
 | 
							uint32_t key_val = 0;
 | 
				
			||||||
		if (bindcode) {
 | 
							error = identify_key(split->items[i], binding->keys->length == 0,
 | 
				
			||||||
			// parse keycode
 | 
									     &key_val, &binding->type);
 | 
				
			||||||
			keycode = (int)strtol(split->items[i], NULL, 10);
 | 
							if (error) {
 | 
				
			||||||
			if (!xkb_keycode_is_legal_ext(keycode)) {
 | 
					 | 
				
			||||||
				error =
 | 
					 | 
				
			||||||
					cmd_results_new(CMD_INVALID, "bindcode",
 | 
					 | 
				
			||||||
						"Invalid keycode '%s'", (char *)split->items[i]);
 | 
					 | 
				
			||||||
			free_sway_binding(binding);
 | 
								free_sway_binding(binding);
 | 
				
			||||||
			list_free(split);
 | 
								list_free(split);
 | 
				
			||||||
			return error;
 | 
								return error;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			// Check for xkb key
 | 
					 | 
				
			||||||
			 keysym = xkb_keysym_from_name(split->items[i],
 | 
					 | 
				
			||||||
					XKB_KEYSYM_CASE_INSENSITIVE);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// Check for mouse binding
 | 
					 | 
				
			||||||
			if (strncasecmp(split->items[i], "button", strlen("button")) == 0 &&
 | 
					 | 
				
			||||||
					strlen(split->items[i]) == strlen("button0")) {
 | 
					 | 
				
			||||||
				keysym = ((char *)split->items[i])[strlen("button")] - '1' + BTN_LEFT;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			if (!keysym) {
 | 
					 | 
				
			||||||
				struct cmd_results *ret = cmd_results_new(CMD_INVALID, "bindsym",
 | 
					 | 
				
			||||||
						"Unknown key '%s'", (char *)split->items[i]);
 | 
					 | 
				
			||||||
				free_sway_binding(binding);
 | 
					 | 
				
			||||||
				free_flat_list(split);
 | 
					 | 
				
			||||||
				return ret;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		uint32_t *key = calloc(1, sizeof(uint32_t));
 | 
							uint32_t *key = calloc(1, sizeof(uint32_t));
 | 
				
			||||||
		if (!key) {
 | 
							if (!key) {
 | 
				
			||||||
			free_sway_binding(binding);
 | 
								free_sway_binding(binding);
 | 
				
			||||||
			free_flat_list(split);
 | 
								free_flat_list(split);
 | 
				
			||||||
			return cmd_results_new(CMD_FAILURE, bindtype,
 | 
								return cmd_results_new(CMD_FAILURE, bindtype,
 | 
				
			||||||
					"Unable to allocate binding");
 | 
										"Unable to allocate binding key");
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							*key = key_val;
 | 
				
			||||||
		if (bindcode) {
 | 
					 | 
				
			||||||
			*key = (uint32_t)keycode;
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			*key = (uint32_t)keysym;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		list_add(binding->keys, key);
 | 
							list_add(binding->keys, key);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	free_flat_list(split);
 | 
						free_flat_list(split);
 | 
				
			||||||
	binding->order = binding_order++;
 | 
						binding->order = binding_order++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// refine region of interest for mouse binding once we are certain
 | 
				
			||||||
 | 
						// that this is one
 | 
				
			||||||
 | 
						if (exclude_titlebar) {
 | 
				
			||||||
 | 
							binding->flags &= ~BINDING_TITLEBAR;
 | 
				
			||||||
 | 
						} else if (binding->type == BINDING_MOUSE) {
 | 
				
			||||||
 | 
							binding->flags |= BINDING_TITLEBAR;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// sort ascending
 | 
						// sort ascending
 | 
				
			||||||
	list_qsort(binding->keys, key_qsort_cmp);
 | 
						list_qsort(binding->keys, key_qsort_cmp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	list_t *mode_bindings;
 | 
						list_t *mode_bindings;
 | 
				
			||||||
	if (bindcode) {
 | 
						if (binding->type == BINDING_KEYCODE) {
 | 
				
			||||||
		mode_bindings = config->current_mode->keycode_bindings;
 | 
							mode_bindings = config->current_mode->keycode_bindings;
 | 
				
			||||||
	} else {
 | 
						} else if (binding->type == BINDING_KEYSYM) {
 | 
				
			||||||
		mode_bindings = config->current_mode->keysym_bindings;
 | 
							mode_bindings = config->current_mode->keysym_bindings;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							mode_bindings = config->current_mode->mouse_bindings;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// overwrite the binding if it already exists
 | 
						// overwrite the binding if it already exists
 | 
				
			||||||
| 
						 | 
					@ -209,3 +297,39 @@ struct cmd_results *cmd_bindsym(int argc, char **argv) {
 | 
				
			||||||
struct cmd_results *cmd_bindcode(int argc, char **argv) {
 | 
					struct cmd_results *cmd_bindcode(int argc, char **argv) {
 | 
				
			||||||
	return cmd_bindsym_or_bindcode(argc, argv, true);
 | 
						return cmd_bindsym_or_bindcode(argc, argv, true);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Execute the command associated to a binding
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void seat_execute_command(struct sway_seat *seat, struct sway_binding *binding) {
 | 
				
			||||||
 | 
						wlr_log(WLR_DEBUG, "running command for binding: %s",
 | 
				
			||||||
 | 
							binding->command);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct sway_binding *binding_copy = binding;
 | 
				
			||||||
 | 
						bool reload = false;
 | 
				
			||||||
 | 
						// if this is a reload command we need to make a duplicate of the
 | 
				
			||||||
 | 
						// binding since it will be gone after the reload has completed.
 | 
				
			||||||
 | 
						if (strcasecmp(binding->command, "reload") == 0) {
 | 
				
			||||||
 | 
							reload = true;
 | 
				
			||||||
 | 
							binding_copy = sway_binding_dup(binding);
 | 
				
			||||||
 | 
							if (!binding_copy) {
 | 
				
			||||||
 | 
								wlr_log(WLR_ERROR, "Failed to duplicate binding during reload");
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						config->handler_context.seat = seat;
 | 
				
			||||||
 | 
						struct cmd_results *results = execute_command(binding->command, NULL);
 | 
				
			||||||
 | 
						if (results->status == CMD_SUCCESS) {
 | 
				
			||||||
 | 
							ipc_event_binding(binding_copy);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							wlr_log(WLR_DEBUG, "could not run command for binding: %s (%s)",
 | 
				
			||||||
 | 
								binding->command, results->error);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (reload) { // free the binding if we made a copy
 | 
				
			||||||
 | 
							free_sway_binding(binding_copy);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						free_cmd_results(results);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,6 +4,7 @@
 | 
				
			||||||
#include <string.h>
 | 
					#include <string.h>
 | 
				
			||||||
#include <sys/wait.h>
 | 
					#include <sys/wait.h>
 | 
				
			||||||
#include <unistd.h>
 | 
					#include <unistd.h>
 | 
				
			||||||
 | 
					#include <signal.h>
 | 
				
			||||||
#include "sway/commands.h"
 | 
					#include "sway/commands.h"
 | 
				
			||||||
#include "sway/config.h"
 | 
					#include "sway/config.h"
 | 
				
			||||||
#include "sway/tree/container.h"
 | 
					#include "sway/tree/container.h"
 | 
				
			||||||
| 
						 | 
					@ -47,6 +48,9 @@ struct cmd_results *cmd_exec_always(int argc, char **argv) {
 | 
				
			||||||
	if ((pid = fork()) == 0) {
 | 
						if ((pid = fork()) == 0) {
 | 
				
			||||||
		// Fork child process again
 | 
							// Fork child process again
 | 
				
			||||||
		setsid();
 | 
							setsid();
 | 
				
			||||||
 | 
							sigset_t set;
 | 
				
			||||||
 | 
							sigemptyset(&set);
 | 
				
			||||||
 | 
							sigprocmask(SIG_SETMASK, &set, NULL);
 | 
				
			||||||
		close(fd[0]);
 | 
							close(fd[0]);
 | 
				
			||||||
		if ((child = fork()) == 0) {
 | 
							if ((child = fork()) == 0) {
 | 
				
			||||||
			close(fd[1]);
 | 
								close(fd[1]);
 | 
				
			||||||
| 
						 | 
					@ -74,7 +78,7 @@ struct cmd_results *cmd_exec_always(int argc, char **argv) {
 | 
				
			||||||
	waitpid(pid, NULL, 0);
 | 
						waitpid(pid, NULL, 0);
 | 
				
			||||||
	if (child > 0) {
 | 
						if (child > 0) {
 | 
				
			||||||
		wlr_log(WLR_DEBUG, "Child process created with pid %d", child);
 | 
							wlr_log(WLR_DEBUG, "Child process created with pid %d", child);
 | 
				
			||||||
		// TODO: add PID to active workspace
 | 
							workspace_record_pid(child);
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		return cmd_results_new(CMD_FAILURE, "exec_always",
 | 
							return cmd_results_new(CMD_FAILURE, "exec_always",
 | 
				
			||||||
			"Second fork() failed");
 | 
								"Second fork() failed");
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -17,9 +17,24 @@ struct cmd_results *cmd_floating(int argc, char **argv) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	struct sway_container *container =
 | 
						struct sway_container *container =
 | 
				
			||||||
		config->handler_context.current_container;
 | 
							config->handler_context.current_container;
 | 
				
			||||||
	if (container->type != C_VIEW) {
 | 
						if (container->type == C_WORKSPACE && container->children->length == 0) {
 | 
				
			||||||
		// TODO: This doesn't strictly speaking have to be true
 | 
							return cmd_results_new(CMD_INVALID, "floating",
 | 
				
			||||||
		return cmd_results_new(CMD_INVALID, "float", "Only views can float");
 | 
									"Can't float an empty workspace");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (container->type == C_WORKSPACE) {
 | 
				
			||||||
 | 
							// Wrap the workspace's children in a container so we can float it
 | 
				
			||||||
 | 
							struct sway_container *workspace = container;
 | 
				
			||||||
 | 
							container = container_wrap_children(container);
 | 
				
			||||||
 | 
							workspace->layout = L_HORIZ;
 | 
				
			||||||
 | 
							seat_set_focus(config->handler_context.seat, container);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// If the container is in a floating split container,
 | 
				
			||||||
 | 
						// operate on the split container instead of the child.
 | 
				
			||||||
 | 
						if (container_is_floating_or_child(container)) {
 | 
				
			||||||
 | 
							while (container->parent->layout != L_FLOATING) {
 | 
				
			||||||
 | 
								container = container->parent;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool wants_floating;
 | 
						bool wants_floating;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										30
									
								
								sway/commands/floating_modifier.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								sway/commands/floating_modifier.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,30 @@
 | 
				
			||||||
 | 
					#include "strings.h"
 | 
				
			||||||
 | 
					#include "sway/commands.h"
 | 
				
			||||||
 | 
					#include "sway/config.h"
 | 
				
			||||||
 | 
					#include "util.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct cmd_results *cmd_floating_modifier(int argc, char **argv) {
 | 
				
			||||||
 | 
						struct cmd_results *error = NULL;
 | 
				
			||||||
 | 
						if ((error = checkarg(argc, "floating_modifier", EXPECTED_AT_LEAST, 1))) {
 | 
				
			||||||
 | 
							return error;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						uint32_t mod = get_modifier_mask_by_name(argv[0]);
 | 
				
			||||||
 | 
						if (!mod) {
 | 
				
			||||||
 | 
							return cmd_results_new(CMD_INVALID, "floating_modifier",
 | 
				
			||||||
 | 
									"Invalid modifier");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (argc == 1 || strcasecmp(argv[1], "normal") == 0) {
 | 
				
			||||||
 | 
							config->floating_mod_inverse = false;
 | 
				
			||||||
 | 
						} else if (strcasecmp(argv[1], "inverse") == 0) {
 | 
				
			||||||
 | 
							config->floating_mod_inverse = true;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							return cmd_results_new(CMD_INVALID, "floating_modifier",
 | 
				
			||||||
 | 
									"Usage: floating_modifier <mod> [inverse|normal]");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						config->floating_mod = mod;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -35,14 +35,25 @@ static struct cmd_results *focus_mode(struct sway_container *con,
 | 
				
			||||||
		struct sway_seat *seat, bool floating) {
 | 
							struct sway_seat *seat, bool floating) {
 | 
				
			||||||
	struct sway_container *ws = con->type == C_WORKSPACE ?
 | 
						struct sway_container *ws = con->type == C_WORKSPACE ?
 | 
				
			||||||
		con : container_parent(con, C_WORKSPACE);
 | 
							con : container_parent(con, C_WORKSPACE);
 | 
				
			||||||
	struct sway_container *new_focus = ws;
 | 
					
 | 
				
			||||||
 | 
						// If the container is in a floating split container,
 | 
				
			||||||
 | 
						// operate on the split container instead of the child.
 | 
				
			||||||
 | 
						if (container_is_floating_or_child(con)) {
 | 
				
			||||||
 | 
							while (con->parent->layout != L_FLOATING) {
 | 
				
			||||||
 | 
								con = con->parent;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct sway_container *new_focus = NULL;
 | 
				
			||||||
	if (floating) {
 | 
						if (floating) {
 | 
				
			||||||
		new_focus = ws->sway_workspace->floating;
 | 
							new_focus = seat_get_focus_inactive(seat, ws->sway_workspace->floating);
 | 
				
			||||||
		if (new_focus->children->length == 0) {
 | 
						} else {
 | 
				
			||||||
			return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 | 
							new_focus = seat_get_focus_inactive_tiling(seat, ws);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if (!new_focus) {
 | 
				
			||||||
 | 
							new_focus = ws;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	seat_set_focus(seat, seat_get_active_child(seat, new_focus));
 | 
						seat_set_focus(seat, new_focus);
 | 
				
			||||||
	return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 | 
						return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -97,7 +108,7 @@ struct cmd_results *cmd_focus(int argc, char **argv) {
 | 
				
			||||||
	} else if (strcmp(argv[0], "tiling") == 0) {
 | 
						} else if (strcmp(argv[0], "tiling") == 0) {
 | 
				
			||||||
		return focus_mode(con, seat, false);
 | 
							return focus_mode(con, seat, false);
 | 
				
			||||||
	} else if (strcmp(argv[0], "mode_toggle") == 0) {
 | 
						} else if (strcmp(argv[0], "mode_toggle") == 0) {
 | 
				
			||||||
		return focus_mode(con, seat, !container_is_floating(con));
 | 
							return focus_mode(con, seat, !container_is_floating_or_child(con));
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (strcmp(argv[0], "output") == 0) {
 | 
						if (strcmp(argv[0], "output") == 0) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,12 +1,14 @@
 | 
				
			||||||
#include <string.h>
 | 
					#include <string.h>
 | 
				
			||||||
#include <strings.h>
 | 
					#include <strings.h>
 | 
				
			||||||
#include "sway/commands.h"
 | 
					#include "sway/commands.h"
 | 
				
			||||||
 | 
					#include "util.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct cmd_results *cmd_focus_follows_mouse(int argc, char **argv) {
 | 
					struct cmd_results *cmd_focus_follows_mouse(int argc, char **argv) {
 | 
				
			||||||
	struct cmd_results *error = NULL;
 | 
						struct cmd_results *error = NULL;
 | 
				
			||||||
	if ((error = checkarg(argc, "focus_follows_mouse", EXPECTED_EQUAL_TO, 1))) {
 | 
						if ((error = checkarg(argc, "focus_follows_mouse", EXPECTED_EQUAL_TO, 1))) {
 | 
				
			||||||
		return error;
 | 
							return error;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	config->focus_follows_mouse = !strcasecmp(argv[0], "yes");
 | 
						config->focus_follows_mouse =
 | 
				
			||||||
 | 
							parse_boolean(argv[0], config->focus_follows_mouse);
 | 
				
			||||||
	return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 | 
						return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,7 @@
 | 
				
			||||||
#include <strings.h>
 | 
					#include <strings.h>
 | 
				
			||||||
#include "sway/commands.h"
 | 
					#include "sway/commands.h"
 | 
				
			||||||
#include "sway/config.h"
 | 
					#include "sway/config.h"
 | 
				
			||||||
 | 
					#include "util.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct cmd_results *cmd_focus_wrapping(int argc, char **argv) {
 | 
					struct cmd_results *cmd_focus_wrapping(int argc, char **argv) {
 | 
				
			||||||
	struct cmd_results *error = NULL;
 | 
						struct cmd_results *error = NULL;
 | 
				
			||||||
| 
						 | 
					@ -8,15 +9,12 @@ struct cmd_results *cmd_focus_wrapping(int argc, char **argv) {
 | 
				
			||||||
		return error;
 | 
							return error;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (strcasecmp(argv[0], "no") == 0) {
 | 
						if (strcasecmp(argv[0], "force") == 0) {
 | 
				
			||||||
		config->focus_wrapping = WRAP_NO;
 | 
					 | 
				
			||||||
	} else if (strcasecmp(argv[0], "yes") == 0) {
 | 
					 | 
				
			||||||
		config->focus_wrapping = WRAP_YES;
 | 
					 | 
				
			||||||
	} else if (strcasecmp(argv[0], "force") == 0) {
 | 
					 | 
				
			||||||
		config->focus_wrapping = WRAP_FORCE;
 | 
							config->focus_wrapping = WRAP_FORCE;
 | 
				
			||||||
 | 
						} else if (parse_boolean(argv[0], config->focus_wrapping == WRAP_YES)) {
 | 
				
			||||||
 | 
							config->focus_wrapping = WRAP_YES;
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		return cmd_results_new(CMD_INVALID, "focus_wrapping",
 | 
							config->focus_wrapping = WRAP_NO;
 | 
				
			||||||
				"Expected 'focus_wrapping yes|no|force'");
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 | 
						return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,7 @@
 | 
				
			||||||
#include <strings.h>
 | 
					#include <strings.h>
 | 
				
			||||||
#include "sway/commands.h"
 | 
					#include "sway/commands.h"
 | 
				
			||||||
#include "sway/config.h"
 | 
					#include "sway/config.h"
 | 
				
			||||||
 | 
					#include "util.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct cmd_results *cmd_force_focus_wrapping(int argc, char **argv) {
 | 
					struct cmd_results *cmd_force_focus_wrapping(int argc, char **argv) {
 | 
				
			||||||
	struct cmd_results *error =
 | 
						struct cmd_results *error =
 | 
				
			||||||
| 
						 | 
					@ -9,13 +10,10 @@ struct cmd_results *cmd_force_focus_wrapping(int argc, char **argv) {
 | 
				
			||||||
		return error;
 | 
							return error;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (strcasecmp(argv[0], "no") == 0) {
 | 
						if (parse_boolean(argv[0], config->focus_wrapping == WRAP_FORCE)) {
 | 
				
			||||||
		config->focus_wrapping = WRAP_YES;
 | 
					 | 
				
			||||||
	} else if (strcasecmp(argv[0], "yes") == 0) {
 | 
					 | 
				
			||||||
		config->focus_wrapping = WRAP_FORCE;
 | 
							config->focus_wrapping = WRAP_FORCE;
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		return cmd_results_new(CMD_INVALID, "force_focus_wrapping",
 | 
							config->focus_wrapping = WRAP_YES;
 | 
				
			||||||
				"Expected 'force_focus_wrapping yes|no'");
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 | 
						return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,6 +5,7 @@
 | 
				
			||||||
#include "sway/tree/container.h"
 | 
					#include "sway/tree/container.h"
 | 
				
			||||||
#include "sway/tree/view.h"
 | 
					#include "sway/tree/view.h"
 | 
				
			||||||
#include "sway/tree/layout.h"
 | 
					#include "sway/tree/layout.h"
 | 
				
			||||||
 | 
					#include "util.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct cmd_results *cmd_fullscreen(int argc, char **argv) {
 | 
					struct cmd_results *cmd_fullscreen(int argc, char **argv) {
 | 
				
			||||||
	struct cmd_results *error = NULL;
 | 
						struct cmd_results *error = NULL;
 | 
				
			||||||
| 
						 | 
					@ -13,25 +14,24 @@ struct cmd_results *cmd_fullscreen(int argc, char **argv) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	struct sway_container *container =
 | 
						struct sway_container *container =
 | 
				
			||||||
		config->handler_context.current_container;
 | 
							config->handler_context.current_container;
 | 
				
			||||||
	if (container->type != C_VIEW) {
 | 
						if (container->type == C_WORKSPACE && container->children->length == 0) {
 | 
				
			||||||
		return cmd_results_new(CMD_INVALID, "fullscreen",
 | 
							return cmd_results_new(CMD_INVALID, "fullscreen",
 | 
				
			||||||
				"Only views can fullscreen");
 | 
									"Can't fullscreen an empty workspace");
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	struct sway_view *view = container->sway_view;
 | 
						if (container->type == C_WORKSPACE) {
 | 
				
			||||||
	bool wants_fullscreen;
 | 
							// Wrap the workspace's children in a container so we can fullscreen it
 | 
				
			||||||
 | 
							struct sway_container *workspace = container;
 | 
				
			||||||
 | 
							container = container_wrap_children(container);
 | 
				
			||||||
 | 
							workspace->layout = L_HORIZ;
 | 
				
			||||||
 | 
							seat_set_focus(config->handler_context.seat, container);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						bool enable = !container->is_fullscreen;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (argc == 0 || strcmp(argv[0], "toggle") == 0) {
 | 
						if (argc) {
 | 
				
			||||||
		wants_fullscreen = !view->is_fullscreen;
 | 
							enable = parse_boolean(argv[0], container->is_fullscreen);
 | 
				
			||||||
	} else if (strcmp(argv[0], "enable") == 0) {
 | 
					 | 
				
			||||||
		wants_fullscreen = true;
 | 
					 | 
				
			||||||
	} else if (strcmp(argv[0], "disable") == 0) {
 | 
					 | 
				
			||||||
		wants_fullscreen = false;
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		return cmd_results_new(CMD_INVALID, "fullscreen",
 | 
					 | 
				
			||||||
				"Expected 'fullscreen' or 'fullscreen <enable|disable|toggle>'");
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	view_set_fullscreen(view, wants_fullscreen);
 | 
						container_set_fullscreen(container, enable);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct sway_container *workspace = container_parent(container, C_WORKSPACE);
 | 
						struct sway_container *workspace = container_parent(container, C_WORKSPACE);
 | 
				
			||||||
	arrange_windows(workspace->parent);
 | 
						arrange_windows(workspace->parent);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -31,6 +31,12 @@ static struct cmd_handler input_handlers[] = {
 | 
				
			||||||
	{ "xkb_variant", input_cmd_xkb_variant },
 | 
						{ "xkb_variant", input_cmd_xkb_variant },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// must be in order for the bsearch
 | 
				
			||||||
 | 
					static struct cmd_handler input_config_handlers[] = {
 | 
				
			||||||
 | 
						{ "xkb_capslock", input_cmd_xkb_capslock },
 | 
				
			||||||
 | 
						{ "xkb_numlock", input_cmd_xkb_numlock },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct cmd_results *cmd_input(int argc, char **argv) {
 | 
					struct cmd_results *cmd_input(int argc, char **argv) {
 | 
				
			||||||
	struct cmd_results *error = NULL;
 | 
						struct cmd_results *error = NULL;
 | 
				
			||||||
	if ((error = checkarg(argc, "input", EXPECTED_AT_LEAST, 2))) {
 | 
						if ((error = checkarg(argc, "input", EXPECTED_AT_LEAST, 2))) {
 | 
				
			||||||
| 
						 | 
					@ -44,8 +50,21 @@ struct cmd_results *cmd_input(int argc, char **argv) {
 | 
				
			||||||
		return cmd_results_new(CMD_FAILURE, NULL, "Couldn't allocate config");
 | 
							return cmd_results_new(CMD_FAILURE, NULL, "Couldn't allocate config");
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct cmd_results *res = config_subcommand(argv + 1, argc - 1,
 | 
						struct cmd_results *res;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (find_handler(argv[1], input_config_handlers,
 | 
				
			||||||
 | 
								sizeof(input_config_handlers))) {
 | 
				
			||||||
 | 
							if (config->reading) {
 | 
				
			||||||
 | 
								res = config_subcommand(argv + 1, argc - 1,
 | 
				
			||||||
 | 
									input_config_handlers, sizeof(input_config_handlers));
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								res = cmd_results_new(CMD_FAILURE, "input",
 | 
				
			||||||
 | 
									"Can only be used in config file.");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							res = config_subcommand(argv + 1, argc - 1,
 | 
				
			||||||
			input_handlers, sizeof(input_handlers));
 | 
								input_handlers, sizeof(input_handlers));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	free_input_config(config->handler_context.input_config);
 | 
						free_input_config(config->handler_context.input_config);
 | 
				
			||||||
	config->handler_context.input_config = NULL;
 | 
						config->handler_context.input_config = NULL;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,6 +3,7 @@
 | 
				
			||||||
#include "sway/config.h"
 | 
					#include "sway/config.h"
 | 
				
			||||||
#include "sway/commands.h"
 | 
					#include "sway/commands.h"
 | 
				
			||||||
#include "sway/input/input-manager.h"
 | 
					#include "sway/input/input-manager.h"
 | 
				
			||||||
 | 
					#include "util.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct cmd_results *input_cmd_drag_lock(int argc, char **argv) {
 | 
					struct cmd_results *input_cmd_drag_lock(int argc, char **argv) {
 | 
				
			||||||
	struct cmd_results *error = NULL;
 | 
						struct cmd_results *error = NULL;
 | 
				
			||||||
| 
						 | 
					@ -18,14 +19,10 @@ struct cmd_results *input_cmd_drag_lock(int argc, char **argv) {
 | 
				
			||||||
	struct input_config *new_config =
 | 
						struct input_config *new_config =
 | 
				
			||||||
		new_input_config(current_input_config->identifier);
 | 
							new_input_config(current_input_config->identifier);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (strcasecmp(argv[0], "enabled") == 0) {
 | 
						if (parse_boolean(argv[0], true)) {
 | 
				
			||||||
		new_config->drag_lock = LIBINPUT_CONFIG_DRAG_LOCK_ENABLED;
 | 
							new_config->drag_lock = LIBINPUT_CONFIG_DRAG_LOCK_ENABLED;
 | 
				
			||||||
	} else if (strcasecmp(argv[0], "disabled") == 0) {
 | 
					 | 
				
			||||||
		new_config->drag_lock = LIBINPUT_CONFIG_DRAG_LOCK_DISABLED;
 | 
					 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		free_input_config(new_config);
 | 
							new_config->drag_lock = LIBINPUT_CONFIG_DRAG_LOCK_DISABLED;
 | 
				
			||||||
		return cmd_results_new(CMD_INVALID, "drag_lock",
 | 
					 | 
				
			||||||
			"Expected 'drag_lock <enabled|disabled>'");
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	apply_input_config(new_config);
 | 
						apply_input_config(new_config);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,6 +3,7 @@
 | 
				
			||||||
#include "sway/config.h"
 | 
					#include "sway/config.h"
 | 
				
			||||||
#include "sway/commands.h"
 | 
					#include "sway/commands.h"
 | 
				
			||||||
#include "sway/input/input-manager.h"
 | 
					#include "sway/input/input-manager.h"
 | 
				
			||||||
 | 
					#include "util.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct cmd_results *input_cmd_dwt(int argc, char **argv) {
 | 
					struct cmd_results *input_cmd_dwt(int argc, char **argv) {
 | 
				
			||||||
	struct cmd_results *error = NULL;
 | 
						struct cmd_results *error = NULL;
 | 
				
			||||||
| 
						 | 
					@ -17,14 +18,10 @@ struct cmd_results *input_cmd_dwt(int argc, char **argv) {
 | 
				
			||||||
	struct input_config *new_config =
 | 
						struct input_config *new_config =
 | 
				
			||||||
		new_input_config(current_input_config->identifier);
 | 
							new_input_config(current_input_config->identifier);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (strcasecmp(argv[0], "enabled") == 0) {
 | 
						if (parse_boolean(argv[0], true)) {
 | 
				
			||||||
		new_config->dwt = LIBINPUT_CONFIG_DWT_ENABLED;
 | 
							new_config->dwt = LIBINPUT_CONFIG_DWT_ENABLED;
 | 
				
			||||||
	} else if (strcasecmp(argv[0], "disabled") == 0) {
 | 
					 | 
				
			||||||
		new_config->dwt = LIBINPUT_CONFIG_DWT_DISABLED;
 | 
					 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		free_input_config(new_config);
 | 
							new_config->dwt = LIBINPUT_CONFIG_DWT_DISABLED;
 | 
				
			||||||
		return cmd_results_new(CMD_INVALID, "dwt",
 | 
					 | 
				
			||||||
			"Expected 'dwt <enabled|disabled>'");
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	apply_input_config(new_config);
 | 
						apply_input_config(new_config);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,6 +3,7 @@
 | 
				
			||||||
#include "sway/config.h"
 | 
					#include "sway/config.h"
 | 
				
			||||||
#include "sway/commands.h"
 | 
					#include "sway/commands.h"
 | 
				
			||||||
#include "sway/input/input-manager.h"
 | 
					#include "sway/input/input-manager.h"
 | 
				
			||||||
 | 
					#include "util.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct cmd_results *input_cmd_left_handed(int argc, char **argv) {
 | 
					struct cmd_results *input_cmd_left_handed(int argc, char **argv) {
 | 
				
			||||||
	struct cmd_results *error = NULL;
 | 
						struct cmd_results *error = NULL;
 | 
				
			||||||
| 
						 | 
					@ -18,15 +19,7 @@ struct cmd_results *input_cmd_left_handed(int argc, char **argv) {
 | 
				
			||||||
	struct input_config *new_config =
 | 
						struct input_config *new_config =
 | 
				
			||||||
		new_input_config(current_input_config->identifier);
 | 
							new_input_config(current_input_config->identifier);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (strcasecmp(argv[0], "enabled") == 0) {
 | 
						new_config->left_handed = parse_boolean(argv[0], true);
 | 
				
			||||||
		new_config->left_handed = 1;
 | 
					 | 
				
			||||||
	} else if (strcasecmp(argv[0], "disabled") == 0) {
 | 
					 | 
				
			||||||
		new_config->left_handed = 0;
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		free_input_config(new_config);
 | 
					 | 
				
			||||||
		return cmd_results_new(CMD_INVALID, "left_handed",
 | 
					 | 
				
			||||||
			"Expected 'left_handed <enabled|disabled>'");
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	apply_input_config(new_config);
 | 
						apply_input_config(new_config);
 | 
				
			||||||
	return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 | 
						return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,6 +3,7 @@
 | 
				
			||||||
#include "sway/config.h"
 | 
					#include "sway/config.h"
 | 
				
			||||||
#include "sway/commands.h"
 | 
					#include "sway/commands.h"
 | 
				
			||||||
#include "sway/input/input-manager.h"
 | 
					#include "sway/input/input-manager.h"
 | 
				
			||||||
 | 
					#include "util.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct cmd_results *input_cmd_middle_emulation(int argc, char **argv) {
 | 
					struct cmd_results *input_cmd_middle_emulation(int argc, char **argv) {
 | 
				
			||||||
	struct cmd_results *error = NULL;
 | 
						struct cmd_results *error = NULL;
 | 
				
			||||||
| 
						 | 
					@ -18,15 +19,11 @@ struct cmd_results *input_cmd_middle_emulation(int argc, char **argv) {
 | 
				
			||||||
	struct input_config *new_config =
 | 
						struct input_config *new_config =
 | 
				
			||||||
		new_input_config(current_input_config->identifier);
 | 
							new_input_config(current_input_config->identifier);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (strcasecmp(argv[0], "enabled") == 0) {
 | 
						if (parse_boolean(argv[0], true)) {
 | 
				
			||||||
		new_config->middle_emulation = LIBINPUT_CONFIG_MIDDLE_EMULATION_ENABLED;
 | 
							new_config->middle_emulation = LIBINPUT_CONFIG_MIDDLE_EMULATION_ENABLED;
 | 
				
			||||||
	} else if (strcasecmp(argv[0], "disabled") == 0) {
 | 
						} else {
 | 
				
			||||||
		new_config->middle_emulation =
 | 
							new_config->middle_emulation =
 | 
				
			||||||
			LIBINPUT_CONFIG_MIDDLE_EMULATION_DISABLED;
 | 
								LIBINPUT_CONFIG_MIDDLE_EMULATION_DISABLED;
 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		free_input_config(new_config);
 | 
					 | 
				
			||||||
		return cmd_results_new(CMD_INVALID, "middle_emulation",
 | 
					 | 
				
			||||||
			"Expected 'middle_emulation <enabled|disabled>'");
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	apply_input_config(new_config);
 | 
						apply_input_config(new_config);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,6 +3,7 @@
 | 
				
			||||||
#include "sway/config.h"
 | 
					#include "sway/config.h"
 | 
				
			||||||
#include "sway/commands.h"
 | 
					#include "sway/commands.h"
 | 
				
			||||||
#include "sway/input/input-manager.h"
 | 
					#include "sway/input/input-manager.h"
 | 
				
			||||||
 | 
					#include "util.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct cmd_results *input_cmd_natural_scroll(int argc, char **argv) {
 | 
					struct cmd_results *input_cmd_natural_scroll(int argc, char **argv) {
 | 
				
			||||||
	struct cmd_results *error = NULL;
 | 
						struct cmd_results *error = NULL;
 | 
				
			||||||
| 
						 | 
					@ -18,15 +19,7 @@ struct cmd_results *input_cmd_natural_scroll(int argc, char **argv) {
 | 
				
			||||||
	struct input_config *new_config =
 | 
						struct input_config *new_config =
 | 
				
			||||||
		new_input_config(current_input_config->identifier);
 | 
							new_input_config(current_input_config->identifier);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (strcasecmp(argv[0], "enabled") == 0) {
 | 
						new_config->natural_scroll = parse_boolean(argv[0], true);
 | 
				
			||||||
		new_config->natural_scroll = 1;
 | 
					 | 
				
			||||||
	} else if (strcasecmp(argv[0], "disabled") == 0) {
 | 
					 | 
				
			||||||
		new_config->natural_scroll = 0;
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		free_input_config(new_config);
 | 
					 | 
				
			||||||
		return cmd_results_new(CMD_INVALID, "natural_scroll",
 | 
					 | 
				
			||||||
			"Expected 'natural_scroll <enabled|disabled>'");
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	apply_input_config(new_config);
 | 
						apply_input_config(new_config);
 | 
				
			||||||
	return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 | 
						return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,6 +4,7 @@
 | 
				
			||||||
#include "sway/commands.h"
 | 
					#include "sway/commands.h"
 | 
				
			||||||
#include "sway/input/input-manager.h"
 | 
					#include "sway/input/input-manager.h"
 | 
				
			||||||
#include "log.h"
 | 
					#include "log.h"
 | 
				
			||||||
 | 
					#include "util.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct cmd_results *input_cmd_tap(int argc, char **argv) {
 | 
					struct cmd_results *input_cmd_tap(int argc, char **argv) {
 | 
				
			||||||
	struct cmd_results *error = NULL;
 | 
						struct cmd_results *error = NULL;
 | 
				
			||||||
| 
						 | 
					@ -18,14 +19,10 @@ struct cmd_results *input_cmd_tap(int argc, char **argv) {
 | 
				
			||||||
	struct input_config *new_config =
 | 
						struct input_config *new_config =
 | 
				
			||||||
		new_input_config(current_input_config->identifier);
 | 
							new_input_config(current_input_config->identifier);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (strcasecmp(argv[0], "enabled") == 0) {
 | 
						if (parse_boolean(argv[0], true)) {
 | 
				
			||||||
		new_config->tap = LIBINPUT_CONFIG_TAP_ENABLED;
 | 
							new_config->tap = LIBINPUT_CONFIG_TAP_ENABLED;
 | 
				
			||||||
	} else if (strcasecmp(argv[0], "disabled") == 0) {
 | 
					 | 
				
			||||||
		new_config->tap = LIBINPUT_CONFIG_TAP_DISABLED;
 | 
					 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		free_input_config(new_config);
 | 
							new_config->tap = LIBINPUT_CONFIG_TAP_DISABLED;
 | 
				
			||||||
		return cmd_results_new(CMD_INVALID, "tap",
 | 
					 | 
				
			||||||
			"Expected 'tap <enabled|disabled>'");
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wlr_log(WLR_DEBUG, "apply-tap for device: %s",
 | 
						wlr_log(WLR_DEBUG, "apply-tap for device: %s",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										33
									
								
								sway/commands/input/xkb_capslock.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								sway/commands/input/xkb_capslock.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,33 @@
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <strings.h>
 | 
				
			||||||
 | 
					#include "sway/config.h"
 | 
				
			||||||
 | 
					#include "sway/commands.h"
 | 
				
			||||||
 | 
					#include "sway/input/input-manager.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct cmd_results *input_cmd_xkb_capslock(int argc, char **argv) {
 | 
				
			||||||
 | 
						struct cmd_results *error = NULL;
 | 
				
			||||||
 | 
						if ((error = checkarg(argc, "xkb_capslock", EXPECTED_AT_LEAST, 1))) {
 | 
				
			||||||
 | 
							return error;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						struct input_config *current_input_config =
 | 
				
			||||||
 | 
							config->handler_context.input_config;
 | 
				
			||||||
 | 
						if (!current_input_config) {
 | 
				
			||||||
 | 
							return cmd_results_new(CMD_FAILURE, "xkb_capslock", 
 | 
				
			||||||
 | 
								"No input device defined.");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						struct input_config *new_config =
 | 
				
			||||||
 | 
							new_input_config(current_input_config->identifier);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (strcasecmp(argv[0], "enabled") == 0) {
 | 
				
			||||||
 | 
							new_config->xkb_capslock = 1;
 | 
				
			||||||
 | 
						} else if (strcasecmp(argv[0], "disabled") == 0) {
 | 
				
			||||||
 | 
							new_config->xkb_capslock = 0; 
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							free_input_config(new_config);
 | 
				
			||||||
 | 
							return cmd_results_new(CMD_INVALID, "xkb_capslock",
 | 
				
			||||||
 | 
								"Expected 'xkb_capslock <enabled|disabled>'");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						apply_input_config(new_config);
 | 
				
			||||||
 | 
						return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										33
									
								
								sway/commands/input/xkb_numlock.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								sway/commands/input/xkb_numlock.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,33 @@
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <strings.h>
 | 
				
			||||||
 | 
					#include "sway/config.h"
 | 
				
			||||||
 | 
					#include "sway/commands.h"
 | 
				
			||||||
 | 
					#include "sway/input/input-manager.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct cmd_results *input_cmd_xkb_numlock(int argc, char **argv) {
 | 
				
			||||||
 | 
						struct cmd_results *error = NULL;
 | 
				
			||||||
 | 
						if ((error = checkarg(argc, "xkb_numlock", EXPECTED_AT_LEAST, 1))) {
 | 
				
			||||||
 | 
							return error;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						struct input_config *current_input_config =
 | 
				
			||||||
 | 
							config->handler_context.input_config;
 | 
				
			||||||
 | 
						if (!current_input_config) {
 | 
				
			||||||
 | 
							return cmd_results_new(CMD_FAILURE, "xkb_numlock", 
 | 
				
			||||||
 | 
								"No input device defined.");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						struct input_config *new_config =
 | 
				
			||||||
 | 
							new_input_config(current_input_config->identifier);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (strcasecmp(argv[0], "enabled") == 0) {
 | 
				
			||||||
 | 
							new_config->xkb_numlock = 1;
 | 
				
			||||||
 | 
						} else if (strcasecmp(argv[0], "disabled") == 0) {
 | 
				
			||||||
 | 
							new_config->xkb_numlock = 0; 
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							free_input_config(new_config);
 | 
				
			||||||
 | 
							return cmd_results_new(CMD_INVALID, "xkb_numlock",
 | 
				
			||||||
 | 
								"Expected 'xkb_numlock <enabled|disabled>'");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						apply_input_config(new_config);
 | 
				
			||||||
 | 
						return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -58,7 +58,7 @@ struct cmd_results *cmd_mark(int argc, char **argv) {
 | 
				
			||||||
	view_find_and_unmark(mark);
 | 
						view_find_and_unmark(mark);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!toggle || !had_mark) {
 | 
						if (!toggle || !had_mark) {
 | 
				
			||||||
		list_add(view->marks, strdup(mark));
 | 
							view_add_mark(view, mark);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	free(mark);
 | 
						free(mark);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -56,6 +56,7 @@ struct cmd_results *cmd_mode(int argc, char **argv) {
 | 
				
			||||||
		mode->name = strdup(mode_name);
 | 
							mode->name = strdup(mode_name);
 | 
				
			||||||
		mode->keysym_bindings = create_list();
 | 
							mode->keysym_bindings = create_list();
 | 
				
			||||||
		mode->keycode_bindings = create_list();
 | 
							mode->keycode_bindings = create_list();
 | 
				
			||||||
 | 
							mode->mouse_bindings = create_list();
 | 
				
			||||||
		mode->pango = pango;
 | 
							mode->pango = pango;
 | 
				
			||||||
		list_add(config->modes, mode);
 | 
							list_add(config->modes, mode);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -9,6 +9,7 @@
 | 
				
			||||||
#include "sway/input/cursor.h"
 | 
					#include "sway/input/cursor.h"
 | 
				
			||||||
#include "sway/input/seat.h"
 | 
					#include "sway/input/seat.h"
 | 
				
			||||||
#include "sway/output.h"
 | 
					#include "sway/output.h"
 | 
				
			||||||
 | 
					#include "sway/scratchpad.h"
 | 
				
			||||||
#include "sway/tree/arrange.h"
 | 
					#include "sway/tree/arrange.h"
 | 
				
			||||||
#include "sway/tree/container.h"
 | 
					#include "sway/tree/container.h"
 | 
				
			||||||
#include "sway/tree/layout.h"
 | 
					#include "sway/tree/layout.h"
 | 
				
			||||||
| 
						 | 
					@ -58,8 +59,7 @@ static struct cmd_results *cmd_move_container(struct sway_container *current,
 | 
				
			||||||
			&& strcasecmp(argv[2], "workspace") == 0) {
 | 
								&& strcasecmp(argv[2], "workspace") == 0) {
 | 
				
			||||||
		// move container to workspace x
 | 
							// move container to workspace x
 | 
				
			||||||
		if (current->type == C_WORKSPACE) {
 | 
							if (current->type == C_WORKSPACE) {
 | 
				
			||||||
			// TODO: Wrap children in a container and move that
 | 
								current = container_wrap_children(current);
 | 
				
			||||||
			return cmd_results_new(CMD_FAILURE, "move", "Unimplemented");
 | 
					 | 
				
			||||||
		} else if (current->type != C_CONTAINER && current->type != C_VIEW) {
 | 
							} else if (current->type != C_CONTAINER && current->type != C_VIEW) {
 | 
				
			||||||
			return cmd_results_new(CMD_FAILURE, "move",
 | 
								return cmd_results_new(CMD_FAILURE, "move",
 | 
				
			||||||
					"Can only move containers and views.");
 | 
										"Can only move containers and views.");
 | 
				
			||||||
| 
						 | 
					@ -97,7 +97,7 @@ static struct cmd_results *cmd_move_container(struct sway_container *current,
 | 
				
			||||||
		container_move_to(current, destination);
 | 
							container_move_to(current, destination);
 | 
				
			||||||
		struct sway_container *focus = seat_get_focus_inactive(
 | 
							struct sway_container *focus = seat_get_focus_inactive(
 | 
				
			||||||
				config->handler_context.seat, old_parent);
 | 
									config->handler_context.seat, old_parent);
 | 
				
			||||||
		seat_set_focus(config->handler_context.seat, focus);
 | 
							seat_set_focus_warp(config->handler_context.seat, focus, true, false);
 | 
				
			||||||
		container_reap_empty(old_parent);
 | 
							container_reap_empty(old_parent);
 | 
				
			||||||
		container_reap_empty(destination->parent);
 | 
							container_reap_empty(destination->parent);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -134,7 +134,7 @@ static struct cmd_results *cmd_move_container(struct sway_container *current,
 | 
				
			||||||
		struct sway_container *old_parent = current->parent;
 | 
							struct sway_container *old_parent = current->parent;
 | 
				
			||||||
		struct sway_container *old_ws = container_parent(current, C_WORKSPACE);
 | 
							struct sway_container *old_ws = container_parent(current, C_WORKSPACE);
 | 
				
			||||||
		container_move_to(current, focus);
 | 
							container_move_to(current, focus);
 | 
				
			||||||
		seat_set_focus(config->handler_context.seat, old_parent);
 | 
							seat_set_focus_warp(config->handler_context.seat, old_parent, true, false);
 | 
				
			||||||
		container_reap_empty(old_parent);
 | 
							container_reap_empty(old_parent);
 | 
				
			||||||
		container_reap_empty(focus->parent);
 | 
							container_reap_empty(focus->parent);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -195,7 +195,7 @@ static struct cmd_results *move_in_direction(struct sway_container *container,
 | 
				
			||||||
				"Cannot move workspaces in a direction");
 | 
									"Cannot move workspaces in a direction");
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (container_is_floating(container)) {
 | 
						if (container_is_floating(container)) {
 | 
				
			||||||
		if (container->type == C_VIEW && container->sway_view->is_fullscreen) {
 | 
							if (container->is_fullscreen) {
 | 
				
			||||||
			return cmd_results_new(CMD_FAILURE, "move",
 | 
								return cmd_results_new(CMD_FAILURE, "move",
 | 
				
			||||||
					"Cannot move fullscreen floating container");
 | 
										"Cannot move fullscreen floating container");
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -296,6 +296,34 @@ static struct cmd_results *move_to_position(struct sway_container *container,
 | 
				
			||||||
	return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 | 
						return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct cmd_results *move_to_scratchpad(struct sway_container *con) {
 | 
				
			||||||
 | 
						if (con->type == C_WORKSPACE && con->children->length == 0) {
 | 
				
			||||||
 | 
							return cmd_results_new(CMD_INVALID, "move",
 | 
				
			||||||
 | 
									"Can't move an empty workspace to the scratchpad");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (con->type == C_WORKSPACE) {
 | 
				
			||||||
 | 
							// Wrap the workspace's children in a container
 | 
				
			||||||
 | 
							struct sway_container *workspace = con;
 | 
				
			||||||
 | 
							con = container_wrap_children(con);
 | 
				
			||||||
 | 
							workspace->layout = L_HORIZ;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// If the container is in a floating split container,
 | 
				
			||||||
 | 
						// operate on the split container instead of the child.
 | 
				
			||||||
 | 
						if (container_is_floating_or_child(con)) {
 | 
				
			||||||
 | 
							while (con->parent->layout != L_FLOATING) {
 | 
				
			||||||
 | 
								con = con->parent;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (con->scratchpad) {
 | 
				
			||||||
 | 
							return cmd_results_new(CMD_INVALID, "move",
 | 
				
			||||||
 | 
									"Container is already in the scratchpad");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						scratchpad_add_container(con);
 | 
				
			||||||
 | 
						return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct cmd_results *cmd_move(int argc, char **argv) {
 | 
					struct cmd_results *cmd_move(int argc, char **argv) {
 | 
				
			||||||
	struct cmd_results *error = NULL;
 | 
						struct cmd_results *error = NULL;
 | 
				
			||||||
	if ((error = checkarg(argc, "move", EXPECTED_AT_LEAST, 1))) {
 | 
						if ((error = checkarg(argc, "move", EXPECTED_AT_LEAST, 1))) {
 | 
				
			||||||
| 
						 | 
					@ -317,10 +345,9 @@ struct cmd_results *cmd_move(int argc, char **argv) {
 | 
				
			||||||
	} else if (strcasecmp(argv[0], "workspace") == 0) {
 | 
						} else if (strcasecmp(argv[0], "workspace") == 0) {
 | 
				
			||||||
		return cmd_move_workspace(current, argc, argv);
 | 
							return cmd_move_workspace(current, argc, argv);
 | 
				
			||||||
	} else if (strcasecmp(argv[0], "scratchpad") == 0
 | 
						} else if (strcasecmp(argv[0], "scratchpad") == 0
 | 
				
			||||||
			|| (strcasecmp(argv[0], "to") == 0
 | 
								|| (strcasecmp(argv[0], "to") == 0 && argc == 2
 | 
				
			||||||
				&& strcasecmp(argv[1], "scratchpad") == 0)) {
 | 
									&& strcasecmp(argv[1], "scratchpad") == 0)) {
 | 
				
			||||||
		// TODO: scratchpad
 | 
							return move_to_scratchpad(current);
 | 
				
			||||||
		return cmd_results_new(CMD_FAILURE, "move", "Unimplemented");
 | 
					 | 
				
			||||||
	} else if (strcasecmp(argv[0], "position") == 0) {
 | 
						} else if (strcasecmp(argv[0], "position") == 0) {
 | 
				
			||||||
		return move_to_position(current, argc, argv);
 | 
							return move_to_position(current, argc, argv);
 | 
				
			||||||
	} else if (strcasecmp(argv[0], "absolute") == 0) {
 | 
						} else if (strcasecmp(argv[0], "absolute") == 0) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,6 @@
 | 
				
			||||||
#include "sway/commands.h"
 | 
					#include "sway/commands.h"
 | 
				
			||||||
#include "sway/config.h"
 | 
					#include "sway/config.h"
 | 
				
			||||||
 | 
					#include "util.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct cmd_results *output_cmd_dpms(int argc, char **argv) {
 | 
					struct cmd_results *output_cmd_dpms(int argc, char **argv) {
 | 
				
			||||||
	if (!config->handler_context.output_config) {
 | 
						if (!config->handler_context.output_config) {
 | 
				
			||||||
| 
						 | 
					@ -9,13 +10,10 @@ struct cmd_results *output_cmd_dpms(int argc, char **argv) {
 | 
				
			||||||
		return cmd_results_new(CMD_INVALID, "output", "Missing dpms argument.");
 | 
							return cmd_results_new(CMD_INVALID, "output", "Missing dpms argument.");
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (strcmp(*argv, "on") == 0) {
 | 
						if (parse_boolean(argv[0], true)) {
 | 
				
			||||||
		config->handler_context.output_config->dpms_state = DPMS_ON;
 | 
							config->handler_context.output_config->dpms_state = DPMS_ON;
 | 
				
			||||||
	} else if (strcmp(*argv, "off") == 0) {
 | 
					 | 
				
			||||||
		config->handler_context.output_config->dpms_state = DPMS_OFF;
 | 
					 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		return cmd_results_new(CMD_INVALID, "output",
 | 
							config->handler_context.output_config->dpms_state = DPMS_OFF;
 | 
				
			||||||
				"Invalid dpms state, valid states are on/off.");
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	config->handler_context.leftovers.argc = argc - 1;
 | 
						config->handler_context.leftovers.argc = argc - 1;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,17 +1,46 @@
 | 
				
			||||||
 | 
					#define _XOPEN_SOURCE 500
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
#include "sway/commands.h"
 | 
					#include "sway/commands.h"
 | 
				
			||||||
#include "sway/config.h"
 | 
					#include "sway/config.h"
 | 
				
			||||||
 | 
					#include "sway/ipc-server.h"
 | 
				
			||||||
#include "sway/tree/arrange.h"
 | 
					#include "sway/tree/arrange.h"
 | 
				
			||||||
 | 
					#include "list.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct cmd_results *cmd_reload(int argc, char **argv) {
 | 
					struct cmd_results *cmd_reload(int argc, char **argv) {
 | 
				
			||||||
	struct cmd_results *error = NULL;
 | 
						struct cmd_results *error = NULL;
 | 
				
			||||||
	if ((error = checkarg(argc, "reload", EXPECTED_EQUAL_TO, 0))) {
 | 
						if ((error = checkarg(argc, "reload", EXPECTED_EQUAL_TO, 0))) {
 | 
				
			||||||
		return error;
 | 
							return error;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// store bar ids to check against new bars for barconfig_update events
 | 
				
			||||||
 | 
						list_t *bar_ids = create_list();
 | 
				
			||||||
 | 
						for (int i = 0; i < config->bars->length; ++i) {
 | 
				
			||||||
 | 
							struct bar_config *bar = config->bars->items[i];
 | 
				
			||||||
 | 
							list_add(bar_ids, strdup(bar->id));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!load_main_config(config->current_config_path, true)) {
 | 
						if (!load_main_config(config->current_config_path, true)) {
 | 
				
			||||||
		return cmd_results_new(CMD_FAILURE, "reload", "Error(s) reloading config.");
 | 
							return cmd_results_new(CMD_FAILURE, "reload", "Error(s) reloading config.");
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						ipc_event_workspace(NULL, NULL, "reload");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	load_swaybars();
 | 
						load_swaybars();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (int i = 0; i < config->bars->length; ++i) {
 | 
				
			||||||
 | 
							struct bar_config *bar = config->bars->items[i];
 | 
				
			||||||
 | 
							for (int j = 0; j < bar_ids->length; ++j) {
 | 
				
			||||||
 | 
								if (strcmp(bar->id, bar_ids->items[j]) == 0) {
 | 
				
			||||||
 | 
									ipc_event_barconfig_update(bar);
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (int i = 0; i < bar_ids->length; ++i) {
 | 
				
			||||||
 | 
							free(bar_ids->items[i]);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						list_free(bar_ids);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	arrange_windows(&root_container);
 | 
						arrange_windows(&root_container);
 | 
				
			||||||
	return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 | 
						return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										44
									
								
								sway/commands/scratchpad.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								sway/commands/scratchpad.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,44 @@
 | 
				
			||||||
 | 
					#include "log.h"
 | 
				
			||||||
 | 
					#include "sway/commands.h"
 | 
				
			||||||
 | 
					#include "sway/config.h"
 | 
				
			||||||
 | 
					#include "sway/scratchpad.h"
 | 
				
			||||||
 | 
					#include "sway/tree/container.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct cmd_results *cmd_scratchpad(int argc, char **argv) {
 | 
				
			||||||
 | 
						struct cmd_results *error = NULL;
 | 
				
			||||||
 | 
						if ((error = checkarg(argc, "scratchpad", EXPECTED_EQUAL_TO, 1))) {
 | 
				
			||||||
 | 
							return error;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (strcmp(argv[0], "show") != 0) {
 | 
				
			||||||
 | 
							return cmd_results_new(CMD_INVALID, "scratchpad",
 | 
				
			||||||
 | 
									"Expected 'scratchpad show'");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (!root_container.sway_root->scratchpad->length) {
 | 
				
			||||||
 | 
							return cmd_results_new(CMD_INVALID, "scratchpad",
 | 
				
			||||||
 | 
									"Scratchpad is empty");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (config->handler_context.using_criteria) {
 | 
				
			||||||
 | 
							struct sway_container *con = config->handler_context.current_container;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// If the container is in a floating split container,
 | 
				
			||||||
 | 
							// operate on the split container instead of the child.
 | 
				
			||||||
 | 
							if (container_is_floating_or_child(con)) {
 | 
				
			||||||
 | 
								while (con->parent->layout != L_FLOATING) {
 | 
				
			||||||
 | 
									con = con->parent;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// If using criteria, this command is executed for every container which
 | 
				
			||||||
 | 
							// matches the criteria. If this container isn't in the scratchpad,
 | 
				
			||||||
 | 
							// we'll just silently return a success.
 | 
				
			||||||
 | 
							if (!con->scratchpad) {
 | 
				
			||||||
 | 
								return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							scratchpad_toggle_container(con);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							scratchpad_toggle_auto();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -7,6 +7,7 @@
 | 
				
			||||||
#include "list.h"
 | 
					#include "list.h"
 | 
				
			||||||
#include "log.h"
 | 
					#include "log.h"
 | 
				
			||||||
#include "stringop.h"
 | 
					#include "stringop.h"
 | 
				
			||||||
 | 
					#include "util.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void rebuild_marks_iterator(struct sway_container *con, void *data) {
 | 
					static void rebuild_marks_iterator(struct sway_container *con, void *data) {
 | 
				
			||||||
	if (con->type == C_VIEW) {
 | 
						if (con->type == C_VIEW) {
 | 
				
			||||||
| 
						 | 
					@ -20,14 +21,7 @@ struct cmd_results *cmd_show_marks(int argc, char **argv) {
 | 
				
			||||||
		return error;
 | 
							return error;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (strcmp(*argv, "yes") == 0) {
 | 
						config->show_marks = parse_boolean(argv[0], config->show_marks);
 | 
				
			||||||
		config->show_marks = true;
 | 
					 | 
				
			||||||
	} else if (strcmp(*argv, "no") == 0) {
 | 
					 | 
				
			||||||
		config->show_marks = false;
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		return cmd_results_new(CMD_INVALID, "show_marks",
 | 
					 | 
				
			||||||
				"Expected 'show_marks <yes|no>'");
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (config->show_marks) {
 | 
						if (config->show_marks) {
 | 
				
			||||||
		container_for_each_descendant_dfs(&root_container,
 | 
							container_for_each_descendant_dfs(&root_container,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -10,10 +10,6 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct cmd_results *do_split(int layout) {
 | 
					static struct cmd_results *do_split(int layout) {
 | 
				
			||||||
	struct sway_container *con = config->handler_context.current_container;
 | 
						struct sway_container *con = config->handler_context.current_container;
 | 
				
			||||||
	if (container_is_floating(con)) {
 | 
					 | 
				
			||||||
		return cmd_results_new(CMD_FAILURE, "split",
 | 
					 | 
				
			||||||
			"Can't split a floating view");
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	struct sway_container *parent = container_split(con, layout);
 | 
						struct sway_container *parent = container_split(con, layout);
 | 
				
			||||||
	container_create_notify(parent);
 | 
						container_create_notify(parent);
 | 
				
			||||||
	arrange_windows(parent->parent);
 | 
						arrange_windows(parent->parent);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,6 @@
 | 
				
			||||||
#include <strings.h>
 | 
					#include <strings.h>
 | 
				
			||||||
#include <wlr/util/log.h>
 | 
					#include <wlr/util/log.h>
 | 
				
			||||||
 | 
					#include "config.h"
 | 
				
			||||||
#include "sway/commands.h"
 | 
					#include "sway/commands.h"
 | 
				
			||||||
#include "sway/tree/arrange.h"
 | 
					#include "sway/tree/arrange.h"
 | 
				
			||||||
#include "sway/tree/layout.h"
 | 
					#include "sway/tree/layout.h"
 | 
				
			||||||
| 
						 | 
					@ -14,10 +15,14 @@ static bool test_con_id(struct sway_container *container, void *con_id) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool test_id(struct sway_container *container, void *id) {
 | 
					static bool test_id(struct sway_container *container, void *id) {
 | 
				
			||||||
 | 
					#ifdef HAVE_XWAYLAND
 | 
				
			||||||
	xcb_window_t *wid = id;
 | 
						xcb_window_t *wid = id;
 | 
				
			||||||
	return (container->type == C_VIEW
 | 
						return (container->type == C_VIEW
 | 
				
			||||||
			&& container->sway_view->type == SWAY_VIEW_XWAYLAND
 | 
								&& container->sway_view->type == SWAY_VIEW_XWAYLAND
 | 
				
			||||||
			&& container->sway_view->wlr_xwayland_surface->window_id == *wid);
 | 
								&& container->sway_view->wlr_xwayland_surface->window_id == *wid);
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
						return false;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool test_mark(struct sway_container *container, void *mark) {
 | 
					static bool test_mark(struct sway_container *container, void *mark) {
 | 
				
			||||||
| 
						 | 
					@ -43,8 +48,10 @@ struct cmd_results *cmd_swap(int argc, char **argv) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	char *value = join_args(argv + 3, argc - 3);
 | 
						char *value = join_args(argv + 3, argc - 3);
 | 
				
			||||||
	if (strcasecmp(argv[2], "id") == 0) {
 | 
						if (strcasecmp(argv[2], "id") == 0) {
 | 
				
			||||||
 | 
					#ifdef HAVE_XWAYLAND
 | 
				
			||||||
		xcb_window_t id = strtol(value, NULL, 0);
 | 
							xcb_window_t id = strtol(value, NULL, 0);
 | 
				
			||||||
		other = container_find(&root_container, test_id, (void *)&id);
 | 
							other = container_find(&root_container, test_id, (void *)&id);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
	} else if (strcasecmp(argv[2], "con_id") == 0) {
 | 
						} else if (strcasecmp(argv[2], "con_id") == 0) {
 | 
				
			||||||
		size_t con_id = atoi(value);
 | 
							size_t con_id = atoi(value);
 | 
				
			||||||
		other = container_find(&root_container, test_con_id, (void *)con_id);
 | 
							other = container_find(&root_container, test_con_id, (void *)con_id);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,6 +5,7 @@
 | 
				
			||||||
#include "sway/tree/container.h"
 | 
					#include "sway/tree/container.h"
 | 
				
			||||||
#include "sway/tree/view.h"
 | 
					#include "sway/tree/view.h"
 | 
				
			||||||
#include "sway/tree/layout.h"
 | 
					#include "sway/tree/layout.h"
 | 
				
			||||||
 | 
					#include "util.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct cmd_results *cmd_urgent(int argc, char **argv) {
 | 
					struct cmd_results *cmd_urgent(int argc, char **argv) {
 | 
				
			||||||
	struct cmd_results *error = NULL;
 | 
						struct cmd_results *error = NULL;
 | 
				
			||||||
| 
						 | 
					@ -19,17 +20,12 @@ struct cmd_results *cmd_urgent(int argc, char **argv) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	struct sway_view *view = container->sway_view;
 | 
						struct sway_view *view = container->sway_view;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (strcmp(argv[0], "enable") == 0) {
 | 
						if (strcmp(argv[0], "allow") == 0) {
 | 
				
			||||||
		view_set_urgent(view, true);
 | 
					 | 
				
			||||||
	} else if (strcmp(argv[0], "disable") == 0) {
 | 
					 | 
				
			||||||
		view_set_urgent(view, false);
 | 
					 | 
				
			||||||
	} else if (strcmp(argv[0], "allow") == 0) {
 | 
					 | 
				
			||||||
		view->allow_request_urgent = true;
 | 
							view->allow_request_urgent = true;
 | 
				
			||||||
	} else if (strcmp(argv[0], "deny") == 0) {
 | 
						} else if (strcmp(argv[0], "deny") == 0) {
 | 
				
			||||||
		view->allow_request_urgent = false;
 | 
							view->allow_request_urgent = false;
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		return cmd_results_new(CMD_INVALID, "urgent",
 | 
							view_set_urgent(view, parse_boolean(argv[0], view_is_urgent(view)));
 | 
				
			||||||
				"Expected 'urgent <enable|disable|allow|deny>'");
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 | 
						return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -56,6 +56,12 @@ static void free_mode(struct sway_mode *mode) {
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		list_free(mode->keycode_bindings);
 | 
							list_free(mode->keycode_bindings);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if (mode->mouse_bindings) {
 | 
				
			||||||
 | 
							for (i = 0; i < mode->mouse_bindings->length; i++) {
 | 
				
			||||||
 | 
								free_sway_binding(mode->mouse_bindings->items[i]);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							list_free(mode->mouse_bindings);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	free(mode);
 | 
						free(mode);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -87,7 +93,6 @@ void free_config(struct sway_config *config) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	list_free(config->cmd_queue);
 | 
						list_free(config->cmd_queue);
 | 
				
			||||||
	list_free(config->workspace_outputs);
 | 
						list_free(config->workspace_outputs);
 | 
				
			||||||
	list_free(config->pid_workspaces);
 | 
					 | 
				
			||||||
	if (config->output_configs) {
 | 
						if (config->output_configs) {
 | 
				
			||||||
		for (int i = 0; i < config->output_configs->length; i++) {
 | 
							for (int i = 0; i < config->output_configs->length; i++) {
 | 
				
			||||||
			free_output_config(config->output_configs->items[i]);
 | 
								free_output_config(config->output_configs->items[i]);
 | 
				
			||||||
| 
						 | 
					@ -157,7 +162,6 @@ static void config_defaults(struct sway_config *config) {
 | 
				
			||||||
	if (!(config->modes = create_list())) goto cleanup;
 | 
						if (!(config->modes = create_list())) goto cleanup;
 | 
				
			||||||
	if (!(config->bars = create_list())) goto cleanup;
 | 
						if (!(config->bars = create_list())) goto cleanup;
 | 
				
			||||||
	if (!(config->workspace_outputs = create_list())) goto cleanup;
 | 
						if (!(config->workspace_outputs = create_list())) goto cleanup;
 | 
				
			||||||
	if (!(config->pid_workspaces = create_list())) goto cleanup;
 | 
					 | 
				
			||||||
	if (!(config->criteria = create_list())) goto cleanup;
 | 
						if (!(config->criteria = create_list())) goto cleanup;
 | 
				
			||||||
	if (!(config->no_focus = create_list())) goto cleanup;
 | 
						if (!(config->no_focus = create_list())) goto cleanup;
 | 
				
			||||||
	if (!(config->input_configs = create_list())) goto cleanup;
 | 
						if (!(config->input_configs = create_list())) goto cleanup;
 | 
				
			||||||
| 
						 | 
					@ -172,9 +176,11 @@ static void config_defaults(struct sway_config *config) {
 | 
				
			||||||
	strcpy(config->current_mode->name, "default");
 | 
						strcpy(config->current_mode->name, "default");
 | 
				
			||||||
	if (!(config->current_mode->keysym_bindings = create_list())) goto cleanup;
 | 
						if (!(config->current_mode->keysym_bindings = create_list())) goto cleanup;
 | 
				
			||||||
	if (!(config->current_mode->keycode_bindings = create_list())) goto cleanup;
 | 
						if (!(config->current_mode->keycode_bindings = create_list())) goto cleanup;
 | 
				
			||||||
 | 
						if (!(config->current_mode->mouse_bindings = create_list())) goto cleanup;
 | 
				
			||||||
	list_add(config->modes, config->current_mode);
 | 
						list_add(config->modes, config->current_mode);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	config->floating_mod = 0;
 | 
						config->floating_mod = 0;
 | 
				
			||||||
 | 
						config->floating_mod_inverse = false;
 | 
				
			||||||
	config->dragging_key = BTN_LEFT;
 | 
						config->dragging_key = BTN_LEFT;
 | 
				
			||||||
	config->resizing_key = BTN_RIGHT;
 | 
						config->resizing_key = BTN_RIGHT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -10,6 +10,7 @@
 | 
				
			||||||
#include <sys/stat.h>
 | 
					#include <sys/stat.h>
 | 
				
			||||||
#include <signal.h>
 | 
					#include <signal.h>
 | 
				
			||||||
#include <strings.h>
 | 
					#include <strings.h>
 | 
				
			||||||
 | 
					#include <signal.h>
 | 
				
			||||||
#include "sway/config.h"
 | 
					#include "sway/config.h"
 | 
				
			||||||
#include "stringop.h"
 | 
					#include "stringop.h"
 | 
				
			||||||
#include "list.h"
 | 
					#include "list.h"
 | 
				
			||||||
| 
						 | 
					@ -175,6 +176,9 @@ void invoke_swaybar(struct bar_config *bar) {
 | 
				
			||||||
	if (bar->pid == 0) {
 | 
						if (bar->pid == 0) {
 | 
				
			||||||
		setpgid(0, 0);
 | 
							setpgid(0, 0);
 | 
				
			||||||
		close(filedes[0]);
 | 
							close(filedes[0]);
 | 
				
			||||||
 | 
							sigset_t set;
 | 
				
			||||||
 | 
							sigemptyset(&set);
 | 
				
			||||||
 | 
							sigprocmask(SIG_SETMASK, &set, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// run custom swaybar
 | 
							// run custom swaybar
 | 
				
			||||||
		size_t len = snprintf(NULL, 0, "%s -b %s",
 | 
							size_t len = snprintf(NULL, 0, "%s -b %s",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -33,6 +33,8 @@ struct input_config *new_input_config(const char* identifier) {
 | 
				
			||||||
	input->left_handed = INT_MIN;
 | 
						input->left_handed = INT_MIN;
 | 
				
			||||||
	input->repeat_delay = INT_MIN;
 | 
						input->repeat_delay = INT_MIN;
 | 
				
			||||||
	input->repeat_rate = INT_MIN;
 | 
						input->repeat_rate = INT_MIN;
 | 
				
			||||||
 | 
						input->xkb_numlock = INT_MIN;
 | 
				
			||||||
 | 
						input->xkb_capslock = INT_MIN;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return input;
 | 
						return input;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -104,6 +106,12 @@ void merge_input_config(struct input_config *dst, struct input_config *src) {
 | 
				
			||||||
		free(dst->xkb_variant);
 | 
							free(dst->xkb_variant);
 | 
				
			||||||
		dst->xkb_variant = strdup(src->xkb_variant);
 | 
							dst->xkb_variant = strdup(src->xkb_variant);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if (src->xkb_numlock != INT_MIN) {
 | 
				
			||||||
 | 
							dst->xkb_numlock = src->xkb_numlock;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (src->xkb_capslock != INT_MIN) {
 | 
				
			||||||
 | 
							dst->xkb_capslock = src->xkb_capslock;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	if (src->mapped_from_region) {
 | 
						if (src->mapped_from_region) {
 | 
				
			||||||
		free(dst->mapped_from_region);
 | 
							free(dst->mapped_from_region);
 | 
				
			||||||
		dst->mapped_from_region =
 | 
							dst->mapped_from_region =
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -10,6 +10,7 @@
 | 
				
			||||||
#include "stringop.h"
 | 
					#include "stringop.h"
 | 
				
			||||||
#include "list.h"
 | 
					#include "list.h"
 | 
				
			||||||
#include "log.h"
 | 
					#include "log.h"
 | 
				
			||||||
 | 
					#include "config.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool criteria_is_empty(struct criteria *criteria) {
 | 
					bool criteria_is_empty(struct criteria *criteria) {
 | 
				
			||||||
	return !criteria->title
 | 
						return !criteria->title
 | 
				
			||||||
| 
						 | 
					@ -19,7 +20,9 @@ bool criteria_is_empty(struct criteria *criteria) {
 | 
				
			||||||
		&& !criteria->instance
 | 
							&& !criteria->instance
 | 
				
			||||||
		&& !criteria->con_mark
 | 
							&& !criteria->con_mark
 | 
				
			||||||
		&& !criteria->con_id
 | 
							&& !criteria->con_id
 | 
				
			||||||
 | 
					#ifdef HAVE_XWAYLAND
 | 
				
			||||||
		&& !criteria->id
 | 
							&& !criteria->id
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
		&& !criteria->window_role
 | 
							&& !criteria->window_role
 | 
				
			||||||
		&& !criteria->window_type
 | 
							&& !criteria->window_type
 | 
				
			||||||
		&& !criteria->floating
 | 
							&& !criteria->floating
 | 
				
			||||||
| 
						 | 
					@ -127,12 +130,14 @@ static bool criteria_matches_view(struct criteria *criteria,
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef HAVE_XWAYLAND
 | 
				
			||||||
	if (criteria->id) { // X11 window ID
 | 
						if (criteria->id) { // X11 window ID
 | 
				
			||||||
		uint32_t x11_window_id = view_get_x11_window_id(view);
 | 
							uint32_t x11_window_id = view_get_x11_window_id(view);
 | 
				
			||||||
		if (!x11_window_id || x11_window_id != criteria->id) {
 | 
							if (!x11_window_id || x11_window_id != criteria->id) {
 | 
				
			||||||
			return false;
 | 
								return false;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (criteria->window_role) {
 | 
						if (criteria->window_role) {
 | 
				
			||||||
		// TODO
 | 
							// TODO
 | 
				
			||||||
| 
						 | 
					@ -225,6 +230,15 @@ list_t *criteria_get_views(struct criteria *criteria) {
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
	container_for_each_descendant_dfs(&root_container,
 | 
						container_for_each_descendant_dfs(&root_container,
 | 
				
			||||||
		criteria_get_views_iterator, &data);
 | 
							criteria_get_views_iterator, &data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Scratchpad items which are hidden are not in the tree.
 | 
				
			||||||
 | 
						for (int i = 0; i < root_container.sway_root->scratchpad->length; ++i) {
 | 
				
			||||||
 | 
							struct sway_container *con =
 | 
				
			||||||
 | 
								root_container.sway_root->scratchpad->items[i];
 | 
				
			||||||
 | 
							if (!con->parent) {
 | 
				
			||||||
 | 
								criteria_get_views_iterator(con, &data);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	return matches;
 | 
						return matches;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -256,7 +270,9 @@ enum criteria_token {
 | 
				
			||||||
	T_CON_ID,
 | 
						T_CON_ID,
 | 
				
			||||||
	T_CON_MARK,
 | 
						T_CON_MARK,
 | 
				
			||||||
	T_FLOATING,
 | 
						T_FLOATING,
 | 
				
			||||||
 | 
					#ifdef HAVE_XWAYLAND
 | 
				
			||||||
	T_ID,
 | 
						T_ID,
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
	T_INSTANCE,
 | 
						T_INSTANCE,
 | 
				
			||||||
	T_SHELL,
 | 
						T_SHELL,
 | 
				
			||||||
	T_TILING,
 | 
						T_TILING,
 | 
				
			||||||
| 
						 | 
					@ -278,8 +294,10 @@ static enum criteria_token token_from_name(char *name) {
 | 
				
			||||||
		return T_CON_ID;
 | 
							return T_CON_ID;
 | 
				
			||||||
	} else if (strcmp(name, "con_mark") == 0) {
 | 
						} else if (strcmp(name, "con_mark") == 0) {
 | 
				
			||||||
		return T_CON_MARK;
 | 
							return T_CON_MARK;
 | 
				
			||||||
 | 
					#ifdef HAVE_XWAYLAND
 | 
				
			||||||
	} else if (strcmp(name, "id") == 0) {
 | 
						} else if (strcmp(name, "id") == 0) {
 | 
				
			||||||
		return T_ID;
 | 
							return T_ID;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
	} else if (strcmp(name, "instance") == 0) {
 | 
						} else if (strcmp(name, "instance") == 0) {
 | 
				
			||||||
		return T_INSTANCE;
 | 
							return T_INSTANCE;
 | 
				
			||||||
	} else if (strcmp(name, "shell") == 0) {
 | 
						} else if (strcmp(name, "shell") == 0) {
 | 
				
			||||||
| 
						 | 
					@ -346,7 +364,9 @@ static char *get_focused_prop(enum criteria_token token) {
 | 
				
			||||||
	case T_CON_ID: // These do not support __focused__
 | 
						case T_CON_ID: // These do not support __focused__
 | 
				
			||||||
	case T_CON_MARK:
 | 
						case T_CON_MARK:
 | 
				
			||||||
	case T_FLOATING:
 | 
						case T_FLOATING:
 | 
				
			||||||
 | 
					#ifdef HAVE_XWAYLAND
 | 
				
			||||||
	case T_ID:
 | 
						case T_ID:
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
	case T_TILING:
 | 
						case T_TILING:
 | 
				
			||||||
	case T_URGENT:
 | 
						case T_URGENT:
 | 
				
			||||||
	case T_WINDOW_TYPE:
 | 
						case T_WINDOW_TYPE:
 | 
				
			||||||
| 
						 | 
					@ -417,12 +437,14 @@ static bool parse_token(struct criteria *criteria, char *name, char *value) {
 | 
				
			||||||
	case T_WINDOW_TYPE:
 | 
						case T_WINDOW_TYPE:
 | 
				
			||||||
		// TODO: This is a string but will be stored as an enum or integer
 | 
							// TODO: This is a string but will be stored as an enum or integer
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
					#ifdef HAVE_XWAYLAND
 | 
				
			||||||
	case T_ID:
 | 
						case T_ID:
 | 
				
			||||||
		criteria->id = strtoul(effective_value, &endptr, 10);
 | 
							criteria->id = strtoul(effective_value, &endptr, 10);
 | 
				
			||||||
		if (*endptr != 0) {
 | 
							if (*endptr != 0) {
 | 
				
			||||||
			error = strdup("The value for 'id' should be numeric");
 | 
								error = strdup("The value for 'id' should be numeric");
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
	case T_FLOATING:
 | 
						case T_FLOATING:
 | 
				
			||||||
		criteria->floating = true;
 | 
							criteria->floating = true;
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,11 +7,13 @@
 | 
				
			||||||
#include <wlr/types/wlr_output_damage.h>
 | 
					#include <wlr/types/wlr_output_damage.h>
 | 
				
			||||||
#include <wlr/types/wlr_output.h>
 | 
					#include <wlr/types/wlr_output.h>
 | 
				
			||||||
#include <wlr/util/log.h>
 | 
					#include <wlr/util/log.h>
 | 
				
			||||||
 | 
					#include "sway/desktop/transaction.h"
 | 
				
			||||||
#include "sway/input/input-manager.h"
 | 
					#include "sway/input/input-manager.h"
 | 
				
			||||||
#include "sway/input/seat.h"
 | 
					#include "sway/input/seat.h"
 | 
				
			||||||
#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/tree/arrange.h"
 | 
				
			||||||
#include "sway/tree/layout.h"
 | 
					#include "sway/tree/layout.h"
 | 
				
			||||||
#include "log.h"
 | 
					#include "log.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -245,6 +247,9 @@ static void handle_surface_commit(struct wl_listener *listener, void *data) {
 | 
				
			||||||
		output_damage_surface(output, layer->geo.x, layer->geo.y,
 | 
							output_damage_surface(output, layer->geo.x, layer->geo.y,
 | 
				
			||||||
			layer_surface->surface, false);
 | 
								layer_surface->surface, false);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						arrange_windows(output->swayc);
 | 
				
			||||||
 | 
						transaction_commit_dirty();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void unmap(struct sway_layer_surface *sway_layer) {
 | 
					static void unmap(struct sway_layer_surface *sway_layer) {
 | 
				
			||||||
| 
						 | 
					@ -282,6 +287,8 @@ static void handle_destroy(struct wl_listener *listener, void *data) {
 | 
				
			||||||
		struct sway_output *output = sway_layer->layer_surface->output->data;
 | 
							struct sway_output *output = sway_layer->layer_surface->output->data;
 | 
				
			||||||
		if (output != NULL && output->swayc != NULL) {
 | 
							if (output != NULL && output->swayc != NULL) {
 | 
				
			||||||
			arrange_layers(output);
 | 
								arrange_layers(output);
 | 
				
			||||||
 | 
								arrange_windows(output->swayc);
 | 
				
			||||||
 | 
								transaction_commit_dirty();
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		wl_list_remove(&sway_layer->output_destroy.link);
 | 
							wl_list_remove(&sway_layer->output_destroy.link);
 | 
				
			||||||
		sway_layer->layer_surface->output = NULL;
 | 
							sway_layer->layer_surface->output = NULL;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -14,6 +14,7 @@
 | 
				
			||||||
#include <wlr/types/wlr_surface.h>
 | 
					#include <wlr/types/wlr_surface.h>
 | 
				
			||||||
#include <wlr/util/region.h>
 | 
					#include <wlr/util/region.h>
 | 
				
			||||||
#include "log.h"
 | 
					#include "log.h"
 | 
				
			||||||
 | 
					#include "config.h"
 | 
				
			||||||
#include "sway/config.h"
 | 
					#include "sway/config.h"
 | 
				
			||||||
#include "sway/input/input-manager.h"
 | 
					#include "sway/input/input-manager.h"
 | 
				
			||||||
#include "sway/input/seat.h"
 | 
					#include "sway/input/seat.h"
 | 
				
			||||||
| 
						 | 
					@ -56,9 +57,21 @@ static void rotate_child_position(double *sx, double *sy, double sw, double sh,
 | 
				
			||||||
	*sy = ry + ph/2 - sh/2;
 | 
						*sy = ry + ph/2 - sh/2;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool output_get_surface_box(struct root_geometry *geo,
 | 
					struct surface_iterator_data {
 | 
				
			||||||
		struct sway_output *output, struct wlr_surface *surface, int sx, int sy,
 | 
						sway_surface_iterator_func_t user_iterator;
 | 
				
			||||||
 | 
						void *user_data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct sway_output *output;
 | 
				
			||||||
 | 
						double ox, oy;
 | 
				
			||||||
 | 
						int width, height;
 | 
				
			||||||
 | 
						float rotation;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool get_surface_box(struct surface_iterator_data *data,
 | 
				
			||||||
 | 
							struct wlr_surface *surface, int sx, int sy,
 | 
				
			||||||
		struct wlr_box *surface_box) {
 | 
							struct wlr_box *surface_box) {
 | 
				
			||||||
 | 
						struct sway_output *output = data->output;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!wlr_surface_has_buffer(surface)) {
 | 
						if (!wlr_surface_has_buffer(surface)) {
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -67,12 +80,12 @@ bool output_get_surface_box(struct root_geometry *geo,
 | 
				
			||||||
	int sh = surface->current.height;
 | 
						int sh = surface->current.height;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	double _sx = sx, _sy = sy;
 | 
						double _sx = sx, _sy = sy;
 | 
				
			||||||
	rotate_child_position(&_sx, &_sy, sw, sh, geo->width, geo->height,
 | 
						rotate_child_position(&_sx, &_sy, sw, sh, data->width, data->height,
 | 
				
			||||||
		geo->rotation);
 | 
							data->rotation);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wlr_box box = {
 | 
						struct wlr_box box = {
 | 
				
			||||||
		.x = geo->x + _sx,
 | 
							.x = data->ox + _sx,
 | 
				
			||||||
		.y = geo->y + _sy,
 | 
							.y = data->oy + _sy,
 | 
				
			||||||
		.width = sw,
 | 
							.width = sw,
 | 
				
			||||||
		.height = sh,
 | 
							.height = sh,
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
| 
						 | 
					@ -81,7 +94,7 @@ bool output_get_surface_box(struct root_geometry *geo,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wlr_box rotated_box;
 | 
						struct wlr_box rotated_box;
 | 
				
			||||||
	wlr_box_rotated_bounds(&box, geo->rotation, &rotated_box);
 | 
						wlr_box_rotated_bounds(&box, data->rotation, &rotated_box);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wlr_box output_box = {
 | 
						struct wlr_box output_box = {
 | 
				
			||||||
		.width = output->swayc->current.swayc_width,
 | 
							.width = output->swayc->current.swayc_width,
 | 
				
			||||||
| 
						 | 
					@ -92,46 +105,90 @@ bool output_get_surface_box(struct root_geometry *geo,
 | 
				
			||||||
	return wlr_box_intersection(&output_box, &rotated_box, &intersection);
 | 
						return wlr_box_intersection(&output_box, &rotated_box, &intersection);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void output_surface_for_each_surface(struct wlr_surface *surface,
 | 
					static void output_for_each_surface_iterator(struct wlr_surface *surface,
 | 
				
			||||||
		double ox, double oy, struct root_geometry *geo,
 | 
							int sx, int sy, void *_data) {
 | 
				
			||||||
		wlr_surface_iterator_func_t iterator, void *user_data) {
 | 
						struct surface_iterator_data *data = _data;
 | 
				
			||||||
	geo->x = ox;
 | 
					 | 
				
			||||||
	geo->y = oy;
 | 
					 | 
				
			||||||
	geo->width = surface->current.width;
 | 
					 | 
				
			||||||
	geo->height = surface->current.height;
 | 
					 | 
				
			||||||
	geo->rotation = 0;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wlr_surface_for_each_surface(surface, iterator, user_data);
 | 
						struct wlr_box box;
 | 
				
			||||||
 | 
						bool intersects = get_surface_box(data, surface, sx, sy, &box);
 | 
				
			||||||
 | 
						if (!intersects) {
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void output_view_for_each_surface(struct sway_view *view,
 | 
						data->user_iterator(data->output, surface, &box, data->rotation,
 | 
				
			||||||
		struct sway_output *output, struct root_geometry *geo,
 | 
							data->user_data);
 | 
				
			||||||
		wlr_surface_iterator_func_t iterator, void *user_data) {
 | 
					 | 
				
			||||||
	geo->x = view->swayc->current.view_x - output->swayc->current.swayc_x;
 | 
					 | 
				
			||||||
	geo->y = view->swayc->current.view_y - output->swayc->current.swayc_y;
 | 
					 | 
				
			||||||
	geo->width = view->swayc->current.view_width;
 | 
					 | 
				
			||||||
	geo->height = view->swayc->current.view_height;
 | 
					 | 
				
			||||||
	geo->rotation = 0; // TODO
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	view_for_each_surface(view, iterator, user_data);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void output_layer_for_each_surface(struct wl_list *layer_surfaces,
 | 
					void output_surface_for_each_surface(struct sway_output *output,
 | 
				
			||||||
		struct root_geometry *geo, wlr_surface_iterator_func_t iterator,
 | 
							struct wlr_surface *surface, double ox, double oy,
 | 
				
			||||||
 | 
							sway_surface_iterator_func_t iterator, void *user_data) {
 | 
				
			||||||
 | 
						struct surface_iterator_data data = {
 | 
				
			||||||
 | 
							.user_iterator = iterator,
 | 
				
			||||||
 | 
							.user_data = user_data,
 | 
				
			||||||
 | 
							.output = output,
 | 
				
			||||||
 | 
							.ox = ox,
 | 
				
			||||||
 | 
							.oy = oy,
 | 
				
			||||||
 | 
							.width = surface->current.width,
 | 
				
			||||||
 | 
							.height = surface->current.height,
 | 
				
			||||||
 | 
							.rotation = 0,
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wlr_surface_for_each_surface(surface,
 | 
				
			||||||
 | 
							output_for_each_surface_iterator, &data);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void output_view_for_each_surface(struct sway_output *output,
 | 
				
			||||||
 | 
							struct sway_view *view, sway_surface_iterator_func_t iterator,
 | 
				
			||||||
 | 
							void *user_data) {
 | 
				
			||||||
 | 
						struct surface_iterator_data data = {
 | 
				
			||||||
 | 
							.user_iterator = iterator,
 | 
				
			||||||
 | 
							.user_data = user_data,
 | 
				
			||||||
 | 
							.output = output,
 | 
				
			||||||
 | 
							.ox = view->swayc->current.view_x - output->swayc->current.swayc_x,
 | 
				
			||||||
 | 
							.oy = view->swayc->current.view_y - output->swayc->current.swayc_y,
 | 
				
			||||||
 | 
							.width = view->swayc->current.view_width,
 | 
				
			||||||
 | 
							.height = view->swayc->current.view_height,
 | 
				
			||||||
 | 
							.rotation = 0, // TODO
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						view_for_each_surface(view,
 | 
				
			||||||
 | 
							output_for_each_surface_iterator, &data);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void output_view_for_each_popup(struct sway_output *output,
 | 
				
			||||||
 | 
							struct sway_view *view, sway_surface_iterator_func_t iterator,
 | 
				
			||||||
 | 
							void *user_data) {
 | 
				
			||||||
 | 
						struct surface_iterator_data data = {
 | 
				
			||||||
 | 
							.user_iterator = iterator,
 | 
				
			||||||
 | 
							.user_data = user_data,
 | 
				
			||||||
 | 
							.output = output,
 | 
				
			||||||
 | 
							.ox = view->swayc->current.view_x - output->swayc->current.swayc_x,
 | 
				
			||||||
 | 
							.oy = view->swayc->current.view_y - output->swayc->current.swayc_y,
 | 
				
			||||||
 | 
							.width = view->swayc->current.view_width,
 | 
				
			||||||
 | 
							.height = view->swayc->current.view_height,
 | 
				
			||||||
 | 
							.rotation = 0, // TODO
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						view_for_each_popup(view, output_for_each_surface_iterator, &data);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void output_layer_for_each_surface(struct sway_output *output,
 | 
				
			||||||
 | 
							struct wl_list *layer_surfaces, sway_surface_iterator_func_t iterator,
 | 
				
			||||||
		void *user_data) {
 | 
							void *user_data) {
 | 
				
			||||||
	struct sway_layer_surface *layer_surface;
 | 
						struct sway_layer_surface *layer_surface;
 | 
				
			||||||
	wl_list_for_each(layer_surface, layer_surfaces, link) {
 | 
						wl_list_for_each(layer_surface, layer_surfaces, link) {
 | 
				
			||||||
		struct wlr_layer_surface *wlr_layer_surface =
 | 
							struct wlr_layer_surface *wlr_layer_surface =
 | 
				
			||||||
			layer_surface->layer_surface;
 | 
								layer_surface->layer_surface;
 | 
				
			||||||
		output_surface_for_each_surface(wlr_layer_surface->surface,
 | 
							output_surface_for_each_surface(output, wlr_layer_surface->surface,
 | 
				
			||||||
			layer_surface->geo.x, layer_surface->geo.y, geo, iterator,
 | 
								layer_surface->geo.x, layer_surface->geo.y, iterator,
 | 
				
			||||||
			user_data);
 | 
								user_data);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void output_unmanaged_for_each_surface(struct wl_list *unmanaged,
 | 
					#ifdef HAVE_XWAYLAND
 | 
				
			||||||
		struct sway_output *output, struct root_geometry *geo,
 | 
					void output_unmanaged_for_each_surface(struct sway_output *output,
 | 
				
			||||||
		wlr_surface_iterator_func_t iterator, void *user_data) {
 | 
							struct wl_list *unmanaged, sway_surface_iterator_func_t iterator,
 | 
				
			||||||
 | 
							void *user_data) {
 | 
				
			||||||
	struct sway_xwayland_unmanaged *unmanaged_surface;
 | 
						struct sway_xwayland_unmanaged *unmanaged_surface;
 | 
				
			||||||
	wl_list_for_each(unmanaged_surface, unmanaged, link) {
 | 
						wl_list_for_each(unmanaged_surface, unmanaged, link) {
 | 
				
			||||||
		struct wlr_xwayland_surface *xsurface =
 | 
							struct wlr_xwayland_surface *xsurface =
 | 
				
			||||||
| 
						 | 
					@ -139,22 +196,24 @@ void output_unmanaged_for_each_surface(struct wl_list *unmanaged,
 | 
				
			||||||
		double ox = unmanaged_surface->lx - output->swayc->current.swayc_x;
 | 
							double ox = unmanaged_surface->lx - output->swayc->current.swayc_x;
 | 
				
			||||||
		double oy = unmanaged_surface->ly - output->swayc->current.swayc_y;
 | 
							double oy = unmanaged_surface->ly - output->swayc->current.swayc_y;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		output_surface_for_each_surface(xsurface->surface, ox, oy, geo,
 | 
							output_surface_for_each_surface(output, xsurface->surface, ox, oy,
 | 
				
			||||||
			iterator, user_data);
 | 
								iterator, user_data);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void output_drag_icons_for_each_surface(struct wl_list *drag_icons,
 | 
					void output_drag_icons_for_each_surface(struct sway_output *output,
 | 
				
			||||||
		struct sway_output *output, struct root_geometry *geo,
 | 
							struct wl_list *drag_icons, sway_surface_iterator_func_t iterator,
 | 
				
			||||||
		wlr_surface_iterator_func_t iterator, void *user_data) {
 | 
							void *user_data) {
 | 
				
			||||||
	struct sway_drag_icon *drag_icon;
 | 
						struct sway_drag_icon *drag_icon;
 | 
				
			||||||
	wl_list_for_each(drag_icon, drag_icons, link) {
 | 
						wl_list_for_each(drag_icon, drag_icons, link) {
 | 
				
			||||||
		double ox = drag_icon->x - output->swayc->x;
 | 
							double ox = drag_icon->x - output->swayc->x;
 | 
				
			||||||
		double oy = drag_icon->y - output->swayc->y;
 | 
							double oy = drag_icon->y - output->swayc->y;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (drag_icon->wlr_drag_icon->mapped) {
 | 
							if (drag_icon->wlr_drag_icon->mapped) {
 | 
				
			||||||
			output_surface_for_each_surface(drag_icon->wlr_drag_icon->surface,
 | 
								output_surface_for_each_surface(output,
 | 
				
			||||||
				ox, oy, geo, iterator, user_data);
 | 
									drag_icon->wlr_drag_icon->surface, ox, oy,
 | 
				
			||||||
 | 
									iterator, user_data);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -181,21 +240,14 @@ struct sway_container *output_get_active_workspace(struct sway_output *output) {
 | 
				
			||||||
	return workspace;
 | 
						return workspace;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool output_has_opaque_lockscreen(struct sway_output *output,
 | 
					bool output_has_opaque_overlay_layer_surface(struct sway_output *output) {
 | 
				
			||||||
		struct sway_seat *seat) {
 | 
					 | 
				
			||||||
	if (!seat->exclusive_client) {
 | 
					 | 
				
			||||||
		return false;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	struct wlr_layer_surface *wlr_layer_surface;
 | 
						struct wlr_layer_surface *wlr_layer_surface;
 | 
				
			||||||
	wl_list_for_each(wlr_layer_surface, &server.layer_shell->surfaces, link) {
 | 
						wl_list_for_each(wlr_layer_surface, &server.layer_shell->surfaces, link) {
 | 
				
			||||||
		if (wlr_layer_surface->output != output->wlr_output) {
 | 
							if (wlr_layer_surface->output != output->wlr_output ||
 | 
				
			||||||
 | 
									wlr_layer_surface->layer != ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY) {
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		struct wlr_surface *wlr_surface = wlr_layer_surface->surface;
 | 
							struct wlr_surface *wlr_surface = wlr_layer_surface->surface;
 | 
				
			||||||
		if (wlr_surface->resource->client != seat->exclusive_client) {
 | 
					 | 
				
			||||||
			continue;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		struct sway_layer_surface *sway_layer_surface =
 | 
							struct sway_layer_surface *sway_layer_surface =
 | 
				
			||||||
			layer_from_wlr_layer_surface(wlr_layer_surface);
 | 
								layer_from_wlr_layer_surface(wlr_layer_surface);
 | 
				
			||||||
		pixman_box32_t output_box = {
 | 
							pixman_box32_t output_box = {
 | 
				
			||||||
| 
						 | 
					@ -217,46 +269,38 @@ bool output_has_opaque_lockscreen(struct sway_output *output,
 | 
				
			||||||
	return false;
 | 
						return false;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void send_frame_done_iterator(struct sway_output *output,
 | 
				
			||||||
 | 
							struct wlr_surface *surface, struct wlr_box *box, float rotation,
 | 
				
			||||||
 | 
							void *_data) {
 | 
				
			||||||
 | 
						struct timespec *when = _data;
 | 
				
			||||||
 | 
						wlr_surface_send_frame_done(surface, when);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void send_frame_done_layer(struct sway_output *output,
 | 
				
			||||||
 | 
							struct wl_list *layer_surfaces, struct timespec *when) {
 | 
				
			||||||
 | 
						output_layer_for_each_surface(output, layer_surfaces,
 | 
				
			||||||
 | 
							send_frame_done_iterator, when);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef HAVE_XWAYLAND
 | 
				
			||||||
 | 
					static void send_frame_done_unmanaged(struct sway_output *output,
 | 
				
			||||||
 | 
							struct wl_list *unmanaged, struct timespec *when) {
 | 
				
			||||||
 | 
						output_unmanaged_for_each_surface(output, unmanaged,
 | 
				
			||||||
 | 
							send_frame_done_iterator, when);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void send_frame_done_drag_icons(struct sway_output *output,
 | 
				
			||||||
 | 
							struct wl_list *drag_icons, struct timespec *when) {
 | 
				
			||||||
 | 
						output_drag_icons_for_each_surface(output, drag_icons,
 | 
				
			||||||
 | 
							send_frame_done_iterator, when);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct send_frame_done_data {
 | 
					struct send_frame_done_data {
 | 
				
			||||||
	struct root_geometry root_geo;
 | 
					 | 
				
			||||||
	struct sway_output *output;
 | 
						struct sway_output *output;
 | 
				
			||||||
	struct timespec *when;
 | 
						struct timespec *when;
 | 
				
			||||||
	struct wl_client *exclusive_client;
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void send_frame_done_iterator(struct wlr_surface *surface,
 | 
					 | 
				
			||||||
		int sx, int sy, void *_data) {
 | 
					 | 
				
			||||||
	struct send_frame_done_data *data = _data;
 | 
					 | 
				
			||||||
	if (data->exclusive_client &&
 | 
					 | 
				
			||||||
			data->exclusive_client != surface->resource->client) {
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	bool intersects = output_get_surface_box(&data->root_geo, data->output, surface,
 | 
					 | 
				
			||||||
		sx, sy, NULL);
 | 
					 | 
				
			||||||
	if (intersects) {
 | 
					 | 
				
			||||||
		wlr_surface_send_frame_done(surface, data->when);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void send_frame_done_layer(struct send_frame_done_data *data,
 | 
					 | 
				
			||||||
		struct wl_list *layer_surfaces) {
 | 
					 | 
				
			||||||
	output_layer_for_each_surface(layer_surfaces, &data->root_geo,
 | 
					 | 
				
			||||||
		send_frame_done_iterator, data);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void send_frame_done_unmanaged(struct send_frame_done_data *data,
 | 
					 | 
				
			||||||
		struct wl_list *unmanaged) {
 | 
					 | 
				
			||||||
	output_unmanaged_for_each_surface(unmanaged, data->output, &data->root_geo,
 | 
					 | 
				
			||||||
		send_frame_done_iterator, data);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void send_frame_done_drag_icons(struct send_frame_done_data *data,
 | 
					 | 
				
			||||||
		struct wl_list *drag_icons) {
 | 
					 | 
				
			||||||
	output_drag_icons_for_each_surface(drag_icons, data->output, &data->root_geo,
 | 
					 | 
				
			||||||
		send_frame_done_iterator, data);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void send_frame_done_container_iterator(struct sway_container *con,
 | 
					static void send_frame_done_container_iterator(struct sway_container *con,
 | 
				
			||||||
		void *_data) {
 | 
							void *_data) {
 | 
				
			||||||
	struct send_frame_done_data *data = _data;
 | 
						struct send_frame_done_data *data = _data;
 | 
				
			||||||
| 
						 | 
					@ -268,52 +312,62 @@ static void send_frame_done_container_iterator(struct sway_container *con,
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	output_view_for_each_surface(con->sway_view, data->output, &data->root_geo,
 | 
						output_view_for_each_surface(data->output, con->sway_view,
 | 
				
			||||||
		send_frame_done_iterator, data);
 | 
							send_frame_done_iterator, data->when);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void send_frame_done_container(struct send_frame_done_data *data,
 | 
					static void send_frame_done_container(struct sway_output *output,
 | 
				
			||||||
		struct sway_container *con) {
 | 
							struct sway_container *con, struct timespec *when) {
 | 
				
			||||||
	container_descendants(con, C_VIEW,
 | 
					 | 
				
			||||||
		send_frame_done_container_iterator, data);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void send_frame_done(struct sway_output *output, struct timespec *when) {
 | 
					 | 
				
			||||||
	struct sway_seat *seat = input_manager_current_seat(input_manager);
 | 
					 | 
				
			||||||
	struct send_frame_done_data data = {
 | 
						struct send_frame_done_data data = {
 | 
				
			||||||
		.output = output,
 | 
							.output = output,
 | 
				
			||||||
		.when = when,
 | 
							.when = when,
 | 
				
			||||||
		.exclusive_client = output_has_opaque_lockscreen(output, seat) ?
 | 
					 | 
				
			||||||
			seat->exclusive_client : NULL,
 | 
					 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
						container_descendants(con, C_VIEW,
 | 
				
			||||||
 | 
							send_frame_done_container_iterator, &data);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void send_frame_done(struct sway_output *output, struct timespec *when) {
 | 
				
			||||||
 | 
						if (output_has_opaque_overlay_layer_surface(output)) {
 | 
				
			||||||
 | 
							goto send_frame_overlay;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct sway_container *workspace = output_get_active_workspace(output);
 | 
						struct sway_container *workspace = output_get_active_workspace(output);
 | 
				
			||||||
	if (workspace->current.ws_fullscreen) {
 | 
						if (workspace->current.ws_fullscreen) {
 | 
				
			||||||
		send_frame_done_container_iterator(
 | 
							if (workspace->current.ws_fullscreen->type == C_VIEW) {
 | 
				
			||||||
			workspace->current.ws_fullscreen->swayc, &data);
 | 
								output_view_for_each_surface(output,
 | 
				
			||||||
 | 
									workspace->current.ws_fullscreen->sway_view,
 | 
				
			||||||
		if (workspace->current.ws_fullscreen->type == SWAY_VIEW_XWAYLAND) {
 | 
									send_frame_done_iterator, when);
 | 
				
			||||||
			send_frame_done_unmanaged(&data,
 | 
					 | 
				
			||||||
				&root_container.sway_root->xwayland_unmanaged);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
		send_frame_done_layer(&data,
 | 
								send_frame_done_container(output, workspace->current.ws_fullscreen,
 | 
				
			||||||
			&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]);
 | 
									when);
 | 
				
			||||||
		send_frame_done_layer(&data,
 | 
							}
 | 
				
			||||||
			&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]);
 | 
					#ifdef HAVE_XWAYLAND
 | 
				
			||||||
 | 
							send_frame_done_unmanaged(output,
 | 
				
			||||||
 | 
								&root_container.sway_root->xwayland_unmanaged, when);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							send_frame_done_layer(output,
 | 
				
			||||||
 | 
								&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], when);
 | 
				
			||||||
 | 
							send_frame_done_layer(output,
 | 
				
			||||||
 | 
								&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM], when);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		send_frame_done_container(&data, workspace);
 | 
							send_frame_done_container(output, workspace, when);
 | 
				
			||||||
		send_frame_done_container(&data, workspace->sway_workspace->floating);
 | 
							send_frame_done_container(output, workspace->sway_workspace->floating,
 | 
				
			||||||
 | 
								when);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		send_frame_done_unmanaged(&data,
 | 
					#ifdef HAVE_XWAYLAND
 | 
				
			||||||
			&root_container.sway_root->xwayland_unmanaged);
 | 
							send_frame_done_unmanaged(output,
 | 
				
			||||||
		send_frame_done_layer(&data,
 | 
								&root_container.sway_root->xwayland_unmanaged, when);
 | 
				
			||||||
			&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]);
 | 
					#endif
 | 
				
			||||||
 | 
							send_frame_done_layer(output,
 | 
				
			||||||
 | 
								&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], when);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	send_frame_done_layer(&data,
 | 
					send_frame_overlay:
 | 
				
			||||||
		&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]);
 | 
						send_frame_done_layer(output,
 | 
				
			||||||
	send_frame_done_drag_icons(&data, &root_container.sway_root->drag_icons);
 | 
							&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], when);
 | 
				
			||||||
 | 
						send_frame_done_drag_icons(output, &root_container.sway_root->drag_icons,
 | 
				
			||||||
 | 
							when);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void damage_handle_frame(struct wl_listener *listener, void *data) {
 | 
					static void damage_handle_frame(struct wl_listener *listener, void *data) {
 | 
				
			||||||
| 
						 | 
					@ -348,26 +402,13 @@ void output_damage_whole(struct sway_output *output) {
 | 
				
			||||||
	wlr_output_damage_add_whole(output->damage);
 | 
						wlr_output_damage_add_whole(output->damage);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct damage_data {
 | 
					static void damage_surface_iterator(struct sway_output *output,
 | 
				
			||||||
	struct root_geometry root_geo;
 | 
							struct wlr_surface *surface, struct wlr_box *_box, float rotation,
 | 
				
			||||||
	struct sway_output *output;
 | 
					 | 
				
			||||||
	bool whole;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void damage_surface_iterator(struct wlr_surface *surface, int sx, int sy,
 | 
					 | 
				
			||||||
		void *_data) {
 | 
							void *_data) {
 | 
				
			||||||
	struct damage_data *data = _data;
 | 
						bool *data = _data;
 | 
				
			||||||
	struct sway_output *output = data->output;
 | 
						bool whole = *data;
 | 
				
			||||||
	float rotation = data->root_geo.rotation;
 | 
					 | 
				
			||||||
	bool whole = data->whole;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	struct wlr_box box;
 | 
					 | 
				
			||||||
	bool intersects = output_get_surface_box(&data->root_geo, data->output, surface,
 | 
					 | 
				
			||||||
		sx, sy, &box);
 | 
					 | 
				
			||||||
	if (!intersects) {
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct wlr_box box = *_box;
 | 
				
			||||||
	scale_box(&box, output->wlr_output->scale);
 | 
						scale_box(&box, output->wlr_output->scale);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int center_x = box.x + box.width/2;
 | 
						int center_x = box.x + box.width/2;
 | 
				
			||||||
| 
						 | 
					@ -407,13 +448,8 @@ static void damage_surface_iterator(struct wlr_surface *surface, int sx, int sy,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void output_damage_surface(struct sway_output *output, double ox, double oy,
 | 
					void output_damage_surface(struct sway_output *output, double ox, double oy,
 | 
				
			||||||
		struct wlr_surface *surface, bool whole) {
 | 
							struct wlr_surface *surface, bool whole) {
 | 
				
			||||||
	struct damage_data data = {
 | 
						output_surface_for_each_surface(output, surface, ox, oy,
 | 
				
			||||||
		.output = output,
 | 
							damage_surface_iterator, &whole);
 | 
				
			||||||
		.whole = whole,
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	output_surface_for_each_surface(surface, ox, oy, &data.root_geo,
 | 
					 | 
				
			||||||
		damage_surface_iterator, &data);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void output_damage_view(struct sway_output *output,
 | 
					static void output_damage_view(struct sway_output *output,
 | 
				
			||||||
| 
						 | 
					@ -426,13 +462,7 @@ static void output_damage_view(struct sway_output *output,
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct damage_data data = {
 | 
						output_view_for_each_surface(output, view, damage_surface_iterator, &whole);
 | 
				
			||||||
		.output = output,
 | 
					 | 
				
			||||||
		.whole = whole,
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	output_view_for_each_surface(view, output, &data.root_geo,
 | 
					 | 
				
			||||||
		damage_surface_iterator, &data);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void output_damage_from_view(struct sway_output *output,
 | 
					void output_damage_from_view(struct sway_output *output,
 | 
				
			||||||
| 
						 | 
					@ -463,11 +493,12 @@ static void output_damage_whole_container_iterator(struct sway_container *con,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void output_damage_whole_container(struct sway_output *output,
 | 
					void output_damage_whole_container(struct sway_output *output,
 | 
				
			||||||
		struct sway_container *con) {
 | 
							struct sway_container *con) {
 | 
				
			||||||
 | 
						// Pad the box by 1px, because the width is a double and might be a fraction
 | 
				
			||||||
	struct wlr_box box = {
 | 
						struct wlr_box box = {
 | 
				
			||||||
		.x = con->current.swayc_x - output->wlr_output->lx,
 | 
							.x = con->current.swayc_x - output->wlr_output->lx - 1,
 | 
				
			||||||
		.y = con->current.swayc_y - output->wlr_output->ly,
 | 
							.y = con->current.swayc_y - output->wlr_output->ly - 1,
 | 
				
			||||||
		.width = con->current.swayc_width,
 | 
							.width = con->current.swayc_width + 2,
 | 
				
			||||||
		.height = con->current.swayc_height,
 | 
							.height = con->current.swayc_height + 2,
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
	scale_box(&box, output->wlr_output->scale);
 | 
						scale_box(&box, output->wlr_output->scale);
 | 
				
			||||||
	wlr_output_damage_add_box(output->damage, &box);
 | 
						wlr_output_damage_add_box(output->damage, &box);
 | 
				
			||||||
| 
						 | 
					@ -509,22 +540,14 @@ static void handle_transform(struct wl_listener *listener, void *data) {
 | 
				
			||||||
	transaction_commit_dirty();
 | 
						transaction_commit_dirty();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void handle_scale_iterator(struct sway_container *view, void *data) {
 | 
					 | 
				
			||||||
	view_update_marks_textures(view->sway_view);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void handle_scale(struct wl_listener *listener, void *data) {
 | 
					static void handle_scale(struct wl_listener *listener, void *data) {
 | 
				
			||||||
	struct sway_output *output = wl_container_of(listener, output, scale);
 | 
						struct sway_output *output = wl_container_of(listener, output, scale);
 | 
				
			||||||
	arrange_layers(output);
 | 
						arrange_layers(output);
 | 
				
			||||||
	container_descendants(output->swayc, C_VIEW, handle_scale_iterator, NULL);
 | 
						container_update_textures_recursive(output->swayc);
 | 
				
			||||||
	arrange_windows(output->swayc);
 | 
						arrange_windows(output->swayc);
 | 
				
			||||||
	transaction_commit_dirty();
 | 
						transaction_commit_dirty();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct sway_output *output_from_wlr_output(struct wlr_output *wlr_output) {
 | 
					 | 
				
			||||||
	return wlr_output->data;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void handle_new_output(struct wl_listener *listener, void *data) {
 | 
					void handle_new_output(struct wl_listener *listener, void *data) {
 | 
				
			||||||
	struct sway_server *server = wl_container_of(listener, server, new_output);
 | 
						struct sway_server *server = wl_container_of(listener, server, new_output);
 | 
				
			||||||
	struct wlr_output *wlr_output = data;
 | 
						struct wlr_output *wlr_output = data;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -14,6 +14,7 @@
 | 
				
			||||||
#include <wlr/types/wlr_surface.h>
 | 
					#include <wlr/types/wlr_surface.h>
 | 
				
			||||||
#include <wlr/util/region.h>
 | 
					#include <wlr/util/region.h>
 | 
				
			||||||
#include "log.h"
 | 
					#include "log.h"
 | 
				
			||||||
 | 
					#include "config.h"
 | 
				
			||||||
#include "sway/config.h"
 | 
					#include "sway/config.h"
 | 
				
			||||||
#include "sway/debug.h"
 | 
					#include "sway/debug.h"
 | 
				
			||||||
#include "sway/input/input-manager.h"
 | 
					#include "sway/input/input-manager.h"
 | 
				
			||||||
| 
						 | 
					@ -28,10 +29,7 @@
 | 
				
			||||||
#include "sway/tree/workspace.h"
 | 
					#include "sway/tree/workspace.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct render_data {
 | 
					struct render_data {
 | 
				
			||||||
	struct root_geometry root_geo;
 | 
					 | 
				
			||||||
	struct sway_output *output;
 | 
					 | 
				
			||||||
	pixman_region32_t *damage;
 | 
						pixman_region32_t *damage;
 | 
				
			||||||
	struct sway_view *view;
 | 
					 | 
				
			||||||
	float alpha;
 | 
						float alpha;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -91,11 +89,11 @@ damage_finish:
 | 
				
			||||||
	pixman_region32_fini(&damage);
 | 
						pixman_region32_fini(&damage);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void render_surface_iterator(struct wlr_surface *surface, int sx, int sy,
 | 
					static void render_surface_iterator(struct sway_output *output,
 | 
				
			||||||
 | 
							struct wlr_surface *surface, struct wlr_box *_box, float rotation,
 | 
				
			||||||
		void *_data) {
 | 
							void *_data) {
 | 
				
			||||||
	struct render_data *data = _data;
 | 
						struct render_data *data = _data;
 | 
				
			||||||
	struct wlr_output *wlr_output = data->output->wlr_output;
 | 
						struct wlr_output *wlr_output = output->wlr_output;
 | 
				
			||||||
	float rotation = data->root_geo.rotation;
 | 
					 | 
				
			||||||
	pixman_region32_t *output_damage = data->damage;
 | 
						pixman_region32_t *output_damage = data->damage;
 | 
				
			||||||
	float alpha = data->alpha;
 | 
						float alpha = data->alpha;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -104,13 +102,7 @@ static void render_surface_iterator(struct wlr_surface *surface, int sx, int sy,
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wlr_box box;
 | 
						struct wlr_box box = *_box;
 | 
				
			||||||
	bool intersects = output_get_surface_box(&data->root_geo, data->output,
 | 
					 | 
				
			||||||
		surface, sx, sy, &box);
 | 
					 | 
				
			||||||
	if (!intersects) {
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	scale_box(&box, wlr_output->scale);
 | 
						scale_box(&box, wlr_output->scale);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	float matrix[9];
 | 
						float matrix[9];
 | 
				
			||||||
| 
						 | 
					@ -125,33 +117,32 @@ static void render_surface_iterator(struct wlr_surface *surface, int sx, int sy,
 | 
				
			||||||
static void render_layer(struct sway_output *output,
 | 
					static void render_layer(struct sway_output *output,
 | 
				
			||||||
		pixman_region32_t *damage, struct wl_list *layer_surfaces) {
 | 
							pixman_region32_t *damage, struct wl_list *layer_surfaces) {
 | 
				
			||||||
	struct render_data data = {
 | 
						struct render_data data = {
 | 
				
			||||||
		.output = output,
 | 
					 | 
				
			||||||
		.damage = damage,
 | 
							.damage = damage,
 | 
				
			||||||
		.alpha = 1.0f,
 | 
							.alpha = 1.0f,
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
	output_layer_for_each_surface(layer_surfaces, &data.root_geo,
 | 
						output_layer_for_each_surface(output, layer_surfaces,
 | 
				
			||||||
		render_surface_iterator, &data);
 | 
							render_surface_iterator, &data);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef HAVE_XWAYLAND
 | 
				
			||||||
static void render_unmanaged(struct sway_output *output,
 | 
					static void render_unmanaged(struct sway_output *output,
 | 
				
			||||||
		pixman_region32_t *damage, struct wl_list *unmanaged) {
 | 
							pixman_region32_t *damage, struct wl_list *unmanaged) {
 | 
				
			||||||
	struct render_data data = {
 | 
						struct render_data data = {
 | 
				
			||||||
		.output = output,
 | 
					 | 
				
			||||||
		.damage = damage,
 | 
							.damage = damage,
 | 
				
			||||||
		.alpha = 1.0f,
 | 
							.alpha = 1.0f,
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
	output_unmanaged_for_each_surface(unmanaged, output, &data.root_geo,
 | 
						output_unmanaged_for_each_surface(output, unmanaged,
 | 
				
			||||||
		render_surface_iterator, &data);
 | 
							render_surface_iterator, &data);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void render_drag_icons(struct sway_output *output,
 | 
					static void render_drag_icons(struct sway_output *output,
 | 
				
			||||||
		pixman_region32_t *damage, struct wl_list *drag_icons) {
 | 
							pixman_region32_t *damage, struct wl_list *drag_icons) {
 | 
				
			||||||
	struct render_data data = {
 | 
						struct render_data data = {
 | 
				
			||||||
		.output = output,
 | 
					 | 
				
			||||||
		.damage = damage,
 | 
							.damage = damage,
 | 
				
			||||||
		.alpha = 1.0f,
 | 
							.alpha = 1.0f,
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
	output_drag_icons_for_each_surface(drag_icons, output, &data.root_geo,
 | 
						output_drag_icons_for_each_surface(output, drag_icons,
 | 
				
			||||||
		render_surface_iterator, &data);
 | 
							render_surface_iterator, &data);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -195,33 +186,51 @@ static void premultiply_alpha(float color[4], float opacity) {
 | 
				
			||||||
	color[2] *= color[3];
 | 
						color[2] *= color[3];
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void render_view_surfaces(struct sway_view *view,
 | 
					static void render_view_toplevels(struct sway_view *view,
 | 
				
			||||||
		struct sway_output *output, pixman_region32_t *damage, float alpha) {
 | 
							struct sway_output *output, pixman_region32_t *damage, float alpha) {
 | 
				
			||||||
	struct render_data data = {
 | 
						struct render_data data = {
 | 
				
			||||||
		.output = output,
 | 
					 | 
				
			||||||
		.damage = damage,
 | 
							.damage = damage,
 | 
				
			||||||
		.view = view,
 | 
					 | 
				
			||||||
		.alpha = alpha,
 | 
							.alpha = alpha,
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
	output_view_for_each_surface(view, output, &data.root_geo,
 | 
						// Render all toplevels without descending into popups
 | 
				
			||||||
 | 
						output_surface_for_each_surface(output, view->surface,
 | 
				
			||||||
 | 
								view->swayc->current.view_x - output->wlr_output->lx,
 | 
				
			||||||
 | 
								view->swayc->current.view_y - output->wlr_output->ly,
 | 
				
			||||||
			render_surface_iterator, &data);
 | 
								render_surface_iterator, &data);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void render_popup_iterator(struct sway_output *output,
 | 
				
			||||||
 | 
							struct wlr_surface *surface, struct wlr_box *box, float rotation,
 | 
				
			||||||
 | 
							void *data) {
 | 
				
			||||||
 | 
						// Render this popup's surface
 | 
				
			||||||
 | 
						render_surface_iterator(output, surface, box, rotation, data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Render this popup's child toplevels
 | 
				
			||||||
 | 
						output_surface_for_each_surface(output, surface, box->x, box->y,
 | 
				
			||||||
 | 
								render_surface_iterator, data);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void render_view_popups(struct sway_view *view,
 | 
				
			||||||
 | 
							struct sway_output *output, pixman_region32_t *damage, float alpha) {
 | 
				
			||||||
 | 
						struct render_data data = {
 | 
				
			||||||
 | 
							.damage = damage,
 | 
				
			||||||
 | 
							.alpha = alpha,
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
						output_view_for_each_popup(output, view, render_popup_iterator, &data);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void render_saved_view(struct sway_view *view,
 | 
					static void render_saved_view(struct sway_view *view,
 | 
				
			||||||
		struct sway_output *output, pixman_region32_t *damage, float alpha) {
 | 
							struct sway_output *output, pixman_region32_t *damage, float alpha) {
 | 
				
			||||||
	struct wlr_output *wlr_output = output->wlr_output;
 | 
						struct wlr_output *wlr_output = output->wlr_output;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int width, height;
 | 
						if (!view->saved_buffer || !view->saved_buffer->texture) {
 | 
				
			||||||
	struct wlr_texture *texture =
 | 
					 | 
				
			||||||
		transaction_get_saved_texture(view, &width, &height);
 | 
					 | 
				
			||||||
	if (!texture) {
 | 
					 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	struct wlr_box box = {
 | 
						struct wlr_box box = {
 | 
				
			||||||
		.x = view->swayc->current.view_x - output->swayc->current.swayc_x,
 | 
							.x = view->swayc->current.view_x - output->swayc->current.swayc_x,
 | 
				
			||||||
		.y = view->swayc->current.view_y - output->swayc->current.swayc_y,
 | 
							.y = view->swayc->current.view_y - output->swayc->current.swayc_y,
 | 
				
			||||||
		.width = width,
 | 
							.width = view->saved_buffer_width,
 | 
				
			||||||
		.height = height,
 | 
							.height = view->saved_buffer_height,
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wlr_box output_box = {
 | 
						struct wlr_box output_box = {
 | 
				
			||||||
| 
						 | 
					@ -241,7 +250,8 @@ static void render_saved_view(struct sway_view *view,
 | 
				
			||||||
	wlr_matrix_project_box(matrix, &box, WL_OUTPUT_TRANSFORM_NORMAL, 0,
 | 
						wlr_matrix_project_box(matrix, &box, WL_OUTPUT_TRANSFORM_NORMAL, 0,
 | 
				
			||||||
		wlr_output->transform_matrix);
 | 
							wlr_output->transform_matrix);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	render_texture(wlr_output, damage, texture, &box, matrix, alpha);
 | 
						render_texture(wlr_output, damage, view->saved_buffer->texture,
 | 
				
			||||||
 | 
								&box, matrix, alpha);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
| 
						 | 
					@ -250,10 +260,10 @@ static void render_saved_view(struct sway_view *view,
 | 
				
			||||||
static void render_view(struct sway_output *output, pixman_region32_t *damage,
 | 
					static void render_view(struct sway_output *output, pixman_region32_t *damage,
 | 
				
			||||||
		struct sway_container *con, struct border_colors *colors) {
 | 
							struct sway_container *con, struct border_colors *colors) {
 | 
				
			||||||
	struct sway_view *view = con->sway_view;
 | 
						struct sway_view *view = con->sway_view;
 | 
				
			||||||
	if (view->swayc->instructions->length) {
 | 
						if (view->saved_buffer) {
 | 
				
			||||||
		render_saved_view(view, output, damage, view->swayc->alpha);
 | 
							render_saved_view(view, output, damage, view->swayc->alpha);
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		render_view_surfaces(view, output, damage, view->swayc->alpha);
 | 
							render_view_toplevels(view, output, damage, view->swayc->alpha);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (view->using_csd) {
 | 
						if (view->using_csd) {
 | 
				
			||||||
| 
						 | 
					@ -778,7 +788,7 @@ static void render_floating_container(struct sway_output *soutput,
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		render_view(soutput, damage, con, colors);
 | 
							render_view(soutput, damage, con, colors);
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		render_container(soutput, damage, con, false);
 | 
							render_container(soutput, damage, con, con->current.focused);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -835,22 +845,13 @@ void output_render(struct sway_output *output, struct timespec *when,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct sway_container *workspace = output_get_active_workspace(output);
 | 
						struct sway_container *workspace = output_get_active_workspace(output);
 | 
				
			||||||
	struct sway_view *fullscreen_view = workspace->current.ws_fullscreen;
 | 
						struct sway_container *fullscreen_con = workspace->current.ws_fullscreen;
 | 
				
			||||||
	struct sway_seat *seat = input_manager_current_seat(input_manager);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (output_has_opaque_lockscreen(output, seat)) {
 | 
						if (output_has_opaque_overlay_layer_surface(output)) {
 | 
				
			||||||
		struct wlr_layer_surface *wlr_layer_surface = seat->focused_layer;
 | 
							goto render_overlay;
 | 
				
			||||||
		struct sway_layer_surface *sway_layer_surface =
 | 
						}
 | 
				
			||||||
			layer_from_wlr_layer_surface(seat->focused_layer);
 | 
					
 | 
				
			||||||
		struct render_data data = {
 | 
						if (fullscreen_con) {
 | 
				
			||||||
			.output = output,
 | 
					 | 
				
			||||||
			.damage = damage,
 | 
					 | 
				
			||||||
			.alpha = 1.0f,
 | 
					 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
		output_surface_for_each_surface(wlr_layer_surface->surface,
 | 
					 | 
				
			||||||
			sway_layer_surface->geo.x, sway_layer_surface->geo.y,
 | 
					 | 
				
			||||||
			&data.root_geo, render_surface_iterator, &data);
 | 
					 | 
				
			||||||
	} else if (fullscreen_view) {
 | 
					 | 
				
			||||||
		float clear_color[] = {0.0f, 0.0f, 0.0f, 1.0f};
 | 
							float clear_color[] = {0.0f, 0.0f, 0.0f, 1.0f};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		int nrects;
 | 
							int nrects;
 | 
				
			||||||
| 
						 | 
					@ -861,16 +862,22 @@ void output_render(struct sway_output *output, struct timespec *when,
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// TODO: handle views smaller than the output
 | 
							// TODO: handle views smaller than the output
 | 
				
			||||||
		if (fullscreen_view->swayc->instructions->length) {
 | 
							if (fullscreen_con->type == C_VIEW) {
 | 
				
			||||||
			render_saved_view(fullscreen_view, output, damage, 1.0f);
 | 
								if (fullscreen_con->sway_view->saved_buffer) {
 | 
				
			||||||
 | 
									render_saved_view(fullscreen_con->sway_view,
 | 
				
			||||||
 | 
											output, damage, 1.0f);
 | 
				
			||||||
			} else {
 | 
								} else {
 | 
				
			||||||
			render_view_surfaces(fullscreen_view, output, damage, 1.0f);
 | 
									render_view_toplevels(fullscreen_con->sway_view,
 | 
				
			||||||
 | 
											output, damage, 1.0f);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
		if (fullscreen_view->type == SWAY_VIEW_XWAYLAND) {
 | 
								render_container(output, damage, fullscreen_con,
 | 
				
			||||||
 | 
										fullscreen_con->current.focused);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					#ifdef HAVE_XWAYLAND
 | 
				
			||||||
		render_unmanaged(output, damage,
 | 
							render_unmanaged(output, damage,
 | 
				
			||||||
			&root_container.sway_root->xwayland_unmanaged);
 | 
								&root_container.sway_root->xwayland_unmanaged);
 | 
				
			||||||
		}
 | 
					#endif
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		float clear_color[] = {0.25f, 0.25f, 0.25f, 1.0f};
 | 
							float clear_color[] = {0.25f, 0.25f, 0.25f, 1.0f};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -888,12 +895,21 @@ void output_render(struct sway_output *output, struct timespec *when,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		render_container(output, damage, workspace, workspace->current.focused);
 | 
							render_container(output, damage, workspace, workspace->current.focused);
 | 
				
			||||||
		render_floating(output, damage);
 | 
							render_floating(output, damage);
 | 
				
			||||||
 | 
					#ifdef HAVE_XWAYLAND
 | 
				
			||||||
		render_unmanaged(output, damage,
 | 
							render_unmanaged(output, damage,
 | 
				
			||||||
			&root_container.sway_root->xwayland_unmanaged);
 | 
								&root_container.sway_root->xwayland_unmanaged);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
		render_layer(output, damage,
 | 
							render_layer(output, damage,
 | 
				
			||||||
			&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]);
 | 
								&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct sway_seat *seat = input_manager_current_seat(input_manager);
 | 
				
			||||||
 | 
						struct sway_container *focus = seat_get_focus(seat);
 | 
				
			||||||
 | 
						if (focus && focus->type == C_VIEW) {
 | 
				
			||||||
 | 
							render_view_popups(focus->sway_view, output, damage, focus->alpha);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					render_overlay:
 | 
				
			||||||
	render_layer(output, damage,
 | 
						render_layer(output, damage,
 | 
				
			||||||
		&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]);
 | 
							&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]);
 | 
				
			||||||
	render_drag_icons(output, damage, &root_container.sway_root->drag_icons);
 | 
						render_drag_icons(output, damage, &root_container.sway_root->drag_icons);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,5 @@
 | 
				
			||||||
#define _POSIX_C_SOURCE 200809L
 | 
					#define _POSIX_C_SOURCE 200809L
 | 
				
			||||||
 | 
					#include <errno.h>
 | 
				
			||||||
#include <stdbool.h>
 | 
					#include <stdbool.h>
 | 
				
			||||||
#include <stdlib.h>
 | 
					#include <stdlib.h>
 | 
				
			||||||
#include <string.h>
 | 
					#include <string.h>
 | 
				
			||||||
| 
						 | 
					@ -40,8 +41,6 @@ struct sway_transaction_instruction {
 | 
				
			||||||
	struct sway_transaction *transaction;
 | 
						struct sway_transaction *transaction;
 | 
				
			||||||
	struct sway_container *container;
 | 
						struct sway_container *container;
 | 
				
			||||||
	struct sway_container_state state;
 | 
						struct sway_container_state state;
 | 
				
			||||||
	struct wlr_buffer *saved_buffer;
 | 
					 | 
				
			||||||
	int saved_buffer_width, saved_buffer_height;
 | 
					 | 
				
			||||||
	uint32_t serial;
 | 
						uint32_t serial;
 | 
				
			||||||
	bool ready;
 | 
						bool ready;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					@ -56,27 +55,6 @@ static struct sway_transaction *transaction_create() {
 | 
				
			||||||
	return transaction;
 | 
						return transaction;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void remove_saved_view_buffer(
 | 
					 | 
				
			||||||
		struct sway_transaction_instruction *instruction) {
 | 
					 | 
				
			||||||
	if (instruction->saved_buffer) {
 | 
					 | 
				
			||||||
		wlr_buffer_unref(instruction->saved_buffer);
 | 
					 | 
				
			||||||
		instruction->saved_buffer = NULL;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void save_view_buffer(struct sway_view *view,
 | 
					 | 
				
			||||||
		struct sway_transaction_instruction *instruction) {
 | 
					 | 
				
			||||||
	if (!sway_assert(instruction->saved_buffer == NULL,
 | 
					 | 
				
			||||||
				"Didn't expect instruction to have a saved buffer already")) {
 | 
					 | 
				
			||||||
		remove_saved_view_buffer(instruction);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if (view->surface && wlr_surface_has_buffer(view->surface)) {
 | 
					 | 
				
			||||||
		instruction->saved_buffer = wlr_buffer_ref(view->surface->buffer);
 | 
					 | 
				
			||||||
		instruction->saved_buffer_width = view->surface->current.width;
 | 
					 | 
				
			||||||
		instruction->saved_buffer_height = view->surface->current.height;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void transaction_destroy(struct sway_transaction *transaction) {
 | 
					static void transaction_destroy(struct sway_transaction *transaction) {
 | 
				
			||||||
	// Free instructions
 | 
						// Free instructions
 | 
				
			||||||
	for (int i = 0; i < transaction->instructions->length; ++i) {
 | 
						for (int i = 0; i < transaction->instructions->length; ++i) {
 | 
				
			||||||
| 
						 | 
					@ -92,7 +70,6 @@ static void transaction_destroy(struct sway_transaction *transaction) {
 | 
				
			||||||
		if (con->destroying && !con->instructions->length) {
 | 
							if (con->destroying && !con->instructions->length) {
 | 
				
			||||||
			container_free(con);
 | 
								container_free(con);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		remove_saved_view_buffer(instruction);
 | 
					 | 
				
			||||||
		free(instruction);
 | 
							free(instruction);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	list_free(transaction->instructions);
 | 
						list_free(transaction->instructions);
 | 
				
			||||||
| 
						 | 
					@ -110,6 +87,7 @@ static void copy_pending_state(struct sway_container *container,
 | 
				
			||||||
	state->swayc_y = container->y;
 | 
						state->swayc_y = container->y;
 | 
				
			||||||
	state->swayc_width = container->width;
 | 
						state->swayc_width = container->width;
 | 
				
			||||||
	state->swayc_height = container->height;
 | 
						state->swayc_height = container->height;
 | 
				
			||||||
 | 
						state->is_fullscreen = container->is_fullscreen;
 | 
				
			||||||
	state->has_gaps = container->has_gaps;
 | 
						state->has_gaps = container->has_gaps;
 | 
				
			||||||
	state->current_gaps = container->current_gaps;
 | 
						state->current_gaps = container->current_gaps;
 | 
				
			||||||
	state->gaps_inner = container->gaps_inner;
 | 
						state->gaps_inner = container->gaps_inner;
 | 
				
			||||||
| 
						 | 
					@ -122,7 +100,6 @@ static void copy_pending_state(struct sway_container *container,
 | 
				
			||||||
		state->view_y = view->y;
 | 
							state->view_y = view->y;
 | 
				
			||||||
		state->view_width = view->width;
 | 
							state->view_width = view->width;
 | 
				
			||||||
		state->view_height = view->height;
 | 
							state->view_height = view->height;
 | 
				
			||||||
		state->is_fullscreen = view->is_fullscreen;
 | 
					 | 
				
			||||||
		state->border = view->border;
 | 
							state->border = view->border;
 | 
				
			||||||
		state->border_thickness = view->border_thickness;
 | 
							state->border_thickness = view->border_thickness;
 | 
				
			||||||
		state->border_top = view->border_top;
 | 
							state->border_top = view->border_top;
 | 
				
			||||||
| 
						 | 
					@ -157,9 +134,6 @@ static void transaction_add_container(struct sway_transaction *transaction,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	copy_pending_state(container, &instruction->state);
 | 
						copy_pending_state(container, &instruction->state);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (container->type == C_VIEW) {
 | 
					 | 
				
			||||||
		save_view_buffer(container->sway_view, instruction);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	list_add(transaction->instructions, instruction);
 | 
						list_add(transaction->instructions, instruction);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -219,27 +193,35 @@ static void transaction_apply(struct sway_transaction *transaction) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		memcpy(&container->current, &instruction->state,
 | 
							memcpy(&container->current, &instruction->state,
 | 
				
			||||||
				sizeof(struct sway_container_state));
 | 
									sizeof(struct sway_container_state));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (container->type == C_VIEW) {
 | 
				
			||||||
 | 
								if (container->destroying) {
 | 
				
			||||||
 | 
									if (container->instructions->length == 1 &&
 | 
				
			||||||
 | 
											container->sway_view->saved_buffer) {
 | 
				
			||||||
 | 
										view_remove_saved_buffer(container->sway_view);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									if (container->sway_view->saved_buffer) {
 | 
				
			||||||
 | 
										view_remove_saved_buffer(container->sway_view);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									if (container->instructions->length > 1) {
 | 
				
			||||||
 | 
										view_save_buffer(container->sway_view);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * For simplicity, we only progress the queue if it can be completely flushed.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
static void transaction_progress_queue() {
 | 
					static void transaction_progress_queue() {
 | 
				
			||||||
	// We iterate this list in reverse because we're more likely to find a
 | 
						while (server.transactions->length) {
 | 
				
			||||||
	// waiting transactions at the end of the list.
 | 
							struct sway_transaction *transaction = server.transactions->items[0];
 | 
				
			||||||
	for (int i = server.transactions->length - 1; i >= 0; --i) {
 | 
					 | 
				
			||||||
		struct sway_transaction *transaction = server.transactions->items[i];
 | 
					 | 
				
			||||||
		if (transaction->num_waiting) {
 | 
							if (transaction->num_waiting) {
 | 
				
			||||||
			return;
 | 
								return;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	for (int i = 0; i < server.transactions->length; ++i) {
 | 
					 | 
				
			||||||
		struct sway_transaction *transaction = server.transactions->items[i];
 | 
					 | 
				
			||||||
		transaction_apply(transaction);
 | 
							transaction_apply(transaction);
 | 
				
			||||||
		transaction_destroy(transaction);
 | 
							transaction_destroy(transaction);
 | 
				
			||||||
 | 
							list_del(server.transactions, 0);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	server.transactions->length = 0;
 | 
					 | 
				
			||||||
	idle_inhibit_v1_check_active(server.idle_inhibit_manager_v1);
 | 
						idle_inhibit_v1_check_active(server.idle_inhibit_manager_v1);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -302,6 +284,9 @@ static void transaction_commit(struct sway_transaction *transaction) {
 | 
				
			||||||
			struct timespec when;
 | 
								struct timespec when;
 | 
				
			||||||
			wlr_surface_send_frame_done(con->sway_view->surface, &when);
 | 
								wlr_surface_send_frame_done(con->sway_view->surface, &when);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							if (con->type == C_VIEW && !con->sway_view->saved_buffer) {
 | 
				
			||||||
 | 
								view_save_buffer(con->sway_view);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		list_add(con->instructions, instruction);
 | 
							list_add(con->instructions, instruction);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	transaction->num_configures = transaction->num_waiting;
 | 
						transaction->num_configures = transaction->num_waiting;
 | 
				
			||||||
| 
						 | 
					@ -324,7 +309,14 @@ static void transaction_commit(struct sway_transaction *transaction) {
 | 
				
			||||||
		// Set up a timer which the views must respond within
 | 
							// Set up a timer which the views must respond within
 | 
				
			||||||
		transaction->timer = wl_event_loop_add_timer(server.wl_event_loop,
 | 
							transaction->timer = wl_event_loop_add_timer(server.wl_event_loop,
 | 
				
			||||||
				handle_timeout, transaction);
 | 
									handle_timeout, transaction);
 | 
				
			||||||
 | 
							if (transaction->timer) {
 | 
				
			||||||
			wl_event_source_timer_update(transaction->timer, txn_timeout_ms);
 | 
								wl_event_source_timer_update(transaction->timer, txn_timeout_ms);
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								wlr_log(WLR_ERROR, "Unable to create transaction timer (%s). "
 | 
				
			||||||
 | 
										"Some imperfect frames might be rendered.",
 | 
				
			||||||
 | 
										strerror(errno));
 | 
				
			||||||
 | 
								handle_timeout(transaction);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// The debug tree shows the pending/live tree. Here is a good place to
 | 
						// The debug tree shows the pending/live tree. Here is a good place to
 | 
				
			||||||
| 
						 | 
					@ -352,13 +344,11 @@ static void set_instruction_ready(
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// If all views are ready, apply the transaction.
 | 
					 | 
				
			||||||
	// If the transaction has timed out then its num_waiting will be 0 already.
 | 
						// If the transaction has timed out then its num_waiting will be 0 already.
 | 
				
			||||||
	if (transaction->num_waiting > 0 && --transaction->num_waiting == 0) {
 | 
						if (transaction->num_waiting > 0 && --transaction->num_waiting == 0) {
 | 
				
			||||||
		if (!txn_debug) {
 | 
							if (!txn_debug) {
 | 
				
			||||||
			wlr_log(WLR_DEBUG, "Transaction %p is ready", transaction);
 | 
								wlr_log(WLR_DEBUG, "Transaction %p is ready", transaction);
 | 
				
			||||||
			wl_event_source_timer_update(transaction->timer, 0);
 | 
								wl_event_source_timer_update(transaction->timer, 0);
 | 
				
			||||||
			transaction_progress_queue();
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -375,6 +365,7 @@ static void set_instructions_ready(struct sway_view *view, int index) {
 | 
				
			||||||
			set_instruction_ready(instruction);
 | 
								set_instruction_ready(instruction);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						transaction_progress_queue();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void transaction_notify_view_ready(struct sway_view *view, uint32_t serial) {
 | 
					void transaction_notify_view_ready(struct sway_view *view, uint32_t serial) {
 | 
				
			||||||
| 
						 | 
					@ -401,18 +392,6 @@ void transaction_notify_view_ready_by_size(struct sway_view *view,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wlr_texture *transaction_get_saved_texture(struct sway_view *view,
 | 
					 | 
				
			||||||
		int *width, int *height) {
 | 
					 | 
				
			||||||
	struct sway_transaction_instruction *instruction =
 | 
					 | 
				
			||||||
		view->swayc->instructions->items[0];
 | 
					 | 
				
			||||||
	if (!instruction->saved_buffer) {
 | 
					 | 
				
			||||||
		return NULL;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	*width = instruction->saved_buffer_width;
 | 
					 | 
				
			||||||
	*height = instruction->saved_buffer_height;
 | 
					 | 
				
			||||||
	return instruction->saved_buffer->texture;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void transaction_commit_dirty(void) {
 | 
					void transaction_commit_dirty(void) {
 | 
				
			||||||
	if (!server.dirty_containers->length) {
 | 
						if (!server.dirty_containers->length) {
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,5 @@
 | 
				
			||||||
#define _POSIX_C_SOURCE 199309L
 | 
					#define _POSIX_C_SOURCE 199309L
 | 
				
			||||||
 | 
					#include <float.h>
 | 
				
			||||||
#include <stdbool.h>
 | 
					#include <stdbool.h>
 | 
				
			||||||
#include <stdlib.h>
 | 
					#include <stdlib.h>
 | 
				
			||||||
#include <wayland-server.h>
 | 
					#include <wayland-server.h>
 | 
				
			||||||
| 
						 | 
					@ -95,6 +96,16 @@ static struct sway_xdg_shell_view *xdg_shell_view_from_view(
 | 
				
			||||||
	return (struct sway_xdg_shell_view *)view;
 | 
						return (struct sway_xdg_shell_view *)view;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void get_constraints(struct sway_view *view, double *min_width,
 | 
				
			||||||
 | 
							double *max_width, double *min_height, double *max_height) {
 | 
				
			||||||
 | 
						struct wlr_xdg_toplevel_state *state =
 | 
				
			||||||
 | 
							&view->wlr_xdg_surface->toplevel->current;
 | 
				
			||||||
 | 
						*min_width = state->min_width > 0 ? state->min_width : DBL_MIN;
 | 
				
			||||||
 | 
						*max_width = state->max_width > 0 ? state->max_width : DBL_MAX;
 | 
				
			||||||
 | 
						*min_height = state->min_height > 0 ? state->min_height : DBL_MIN;
 | 
				
			||||||
 | 
						*max_height = state->max_height > 0 ? state->max_height : DBL_MAX;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const char *get_string_prop(struct sway_view *view, enum sway_view_prop prop) {
 | 
					static const char *get_string_prop(struct sway_view *view, enum sway_view_prop prop) {
 | 
				
			||||||
	if (xdg_shell_view_from_view(view) == NULL) {
 | 
						if (xdg_shell_view_from_view(view) == NULL) {
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
| 
						 | 
					@ -168,6 +179,14 @@ static void for_each_surface(struct sway_view *view,
 | 
				
			||||||
		user_data);
 | 
							user_data);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void for_each_popup(struct sway_view *view,
 | 
				
			||||||
 | 
							wlr_surface_iterator_func_t iterator, void *user_data) {
 | 
				
			||||||
 | 
						if (xdg_shell_view_from_view(view) == NULL) {
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						wlr_xdg_surface_for_each_popup(view->wlr_xdg_surface, iterator, user_data);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void _close(struct sway_view *view) {
 | 
					static void _close(struct sway_view *view) {
 | 
				
			||||||
	if (xdg_shell_view_from_view(view) == NULL) {
 | 
						if (xdg_shell_view_from_view(view) == NULL) {
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
| 
						 | 
					@ -178,6 +197,18 @@ static void _close(struct sway_view *view) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void close_popups_iterator(struct wlr_surface *surface,
 | 
				
			||||||
 | 
							int sx, int sy, void *data) {
 | 
				
			||||||
 | 
						struct wlr_xdg_surface *xdg_surface =
 | 
				
			||||||
 | 
							wlr_xdg_surface_from_wlr_surface(surface);
 | 
				
			||||||
 | 
						wlr_xdg_surface_send_close(xdg_surface);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void close_popups(struct sway_view *view) {
 | 
				
			||||||
 | 
						wlr_xdg_surface_for_each_popup(view->wlr_xdg_surface,
 | 
				
			||||||
 | 
								close_popups_iterator, NULL);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void destroy(struct sway_view *view) {
 | 
					static void destroy(struct sway_view *view) {
 | 
				
			||||||
	struct sway_xdg_shell_view *xdg_shell_view =
 | 
						struct sway_xdg_shell_view *xdg_shell_view =
 | 
				
			||||||
		xdg_shell_view_from_view(view);
 | 
							xdg_shell_view_from_view(view);
 | 
				
			||||||
| 
						 | 
					@ -188,6 +219,7 @@ static void destroy(struct sway_view *view) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct sway_view_impl view_impl = {
 | 
					static const struct sway_view_impl view_impl = {
 | 
				
			||||||
 | 
						.get_constraints = get_constraints,
 | 
				
			||||||
	.get_string_prop = get_string_prop,
 | 
						.get_string_prop = get_string_prop,
 | 
				
			||||||
	.configure = configure,
 | 
						.configure = configure,
 | 
				
			||||||
	.set_activated = set_activated,
 | 
						.set_activated = set_activated,
 | 
				
			||||||
| 
						 | 
					@ -195,7 +227,9 @@ static const struct sway_view_impl view_impl = {
 | 
				
			||||||
	.set_fullscreen = set_fullscreen,
 | 
						.set_fullscreen = set_fullscreen,
 | 
				
			||||||
	.wants_floating = wants_floating,
 | 
						.wants_floating = wants_floating,
 | 
				
			||||||
	.for_each_surface = for_each_surface,
 | 
						.for_each_surface = for_each_surface,
 | 
				
			||||||
 | 
						.for_each_popup = for_each_popup,
 | 
				
			||||||
	.close = _close,
 | 
						.close = _close,
 | 
				
			||||||
 | 
						.close_popups = close_popups,
 | 
				
			||||||
	.destroy = destroy,
 | 
						.destroy = destroy,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -213,10 +247,24 @@ static void handle_commit(struct wl_listener *listener, void *data) {
 | 
				
			||||||
		transaction_notify_view_ready(view, xdg_surface->configure_serial);
 | 
							transaction_notify_view_ready(view, xdg_surface->configure_serial);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	view_update_title(view, false);
 | 
					 | 
				
			||||||
	view_damage_from(view);
 | 
						view_damage_from(view);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void handle_set_title(struct wl_listener *listener, void *data) {
 | 
				
			||||||
 | 
						struct sway_xdg_shell_view *xdg_shell_view =
 | 
				
			||||||
 | 
							wl_container_of(listener, xdg_shell_view, set_title);
 | 
				
			||||||
 | 
						struct sway_view *view = &xdg_shell_view->view;
 | 
				
			||||||
 | 
						view_update_title(view, false);
 | 
				
			||||||
 | 
						view_execute_criteria(view);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void handle_set_app_id(struct wl_listener *listener, void *data) {
 | 
				
			||||||
 | 
						struct sway_xdg_shell_view *xdg_shell_view =
 | 
				
			||||||
 | 
							wl_container_of(listener, xdg_shell_view, set_app_id);
 | 
				
			||||||
 | 
						struct sway_view *view = &xdg_shell_view->view;
 | 
				
			||||||
 | 
						view_execute_criteria(view);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void handle_new_popup(struct wl_listener *listener, void *data) {
 | 
					static void handle_new_popup(struct wl_listener *listener, void *data) {
 | 
				
			||||||
	struct sway_xdg_shell_view *xdg_shell_view =
 | 
						struct sway_xdg_shell_view *xdg_shell_view =
 | 
				
			||||||
		wl_container_of(listener, xdg_shell_view, new_popup);
 | 
							wl_container_of(listener, xdg_shell_view, new_popup);
 | 
				
			||||||
| 
						 | 
					@ -241,13 +289,41 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	view_set_fullscreen(view, e->fullscreen);
 | 
						container_set_fullscreen(view->swayc, e->fullscreen);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct sway_container *output = container_parent(view->swayc, C_OUTPUT);
 | 
						struct sway_container *output = container_parent(view->swayc, C_OUTPUT);
 | 
				
			||||||
	arrange_windows(output);
 | 
						arrange_windows(output);
 | 
				
			||||||
	transaction_commit_dirty();
 | 
						transaction_commit_dirty();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void handle_request_move(struct wl_listener *listener, void *data) {
 | 
				
			||||||
 | 
						struct sway_xdg_shell_view *xdg_shell_view =
 | 
				
			||||||
 | 
							wl_container_of(listener, xdg_shell_view, request_move);
 | 
				
			||||||
 | 
						struct sway_view *view = &xdg_shell_view->view;
 | 
				
			||||||
 | 
						if (!container_is_floating(view->swayc)) {
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						struct wlr_xdg_toplevel_move_event *e = data;
 | 
				
			||||||
 | 
						struct sway_seat *seat = e->seat->seat->data;
 | 
				
			||||||
 | 
						if (e->serial == seat->last_button_serial) {
 | 
				
			||||||
 | 
							seat_begin_move(seat, view->swayc, seat->last_button);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void handle_request_resize(struct wl_listener *listener, void *data) {
 | 
				
			||||||
 | 
						struct sway_xdg_shell_view *xdg_shell_view =
 | 
				
			||||||
 | 
							wl_container_of(listener, xdg_shell_view, request_resize);
 | 
				
			||||||
 | 
						struct sway_view *view = &xdg_shell_view->view;
 | 
				
			||||||
 | 
						if (!container_is_floating(view->swayc)) {
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						struct wlr_xdg_toplevel_resize_event *e = data;
 | 
				
			||||||
 | 
						struct sway_seat *seat = e->seat->seat->data;
 | 
				
			||||||
 | 
						if (e->serial == seat->last_button_serial) {
 | 
				
			||||||
 | 
							seat_begin_resize(seat, view->swayc, seat->last_button, e->edges);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void handle_unmap(struct wl_listener *listener, void *data) {
 | 
					static void handle_unmap(struct wl_listener *listener, void *data) {
 | 
				
			||||||
	struct sway_xdg_shell_view *xdg_shell_view =
 | 
						struct sway_xdg_shell_view *xdg_shell_view =
 | 
				
			||||||
		wl_container_of(listener, xdg_shell_view, unmap);
 | 
							wl_container_of(listener, xdg_shell_view, unmap);
 | 
				
			||||||
| 
						 | 
					@ -262,6 +338,10 @@ static void handle_unmap(struct wl_listener *listener, void *data) {
 | 
				
			||||||
	wl_list_remove(&xdg_shell_view->commit.link);
 | 
						wl_list_remove(&xdg_shell_view->commit.link);
 | 
				
			||||||
	wl_list_remove(&xdg_shell_view->new_popup.link);
 | 
						wl_list_remove(&xdg_shell_view->new_popup.link);
 | 
				
			||||||
	wl_list_remove(&xdg_shell_view->request_fullscreen.link);
 | 
						wl_list_remove(&xdg_shell_view->request_fullscreen.link);
 | 
				
			||||||
 | 
						wl_list_remove(&xdg_shell_view->request_move.link);
 | 
				
			||||||
 | 
						wl_list_remove(&xdg_shell_view->request_resize.link);
 | 
				
			||||||
 | 
						wl_list_remove(&xdg_shell_view->set_title.link);
 | 
				
			||||||
 | 
						wl_list_remove(&xdg_shell_view->set_app_id.link);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void handle_map(struct wl_listener *listener, void *data) {
 | 
					static void handle_map(struct wl_listener *listener, void *data) {
 | 
				
			||||||
| 
						 | 
					@ -280,7 +360,7 @@ static void handle_map(struct wl_listener *listener, void *data) {
 | 
				
			||||||
	view_map(view, view->wlr_xdg_surface->surface);
 | 
						view_map(view, view->wlr_xdg_surface->surface);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (xdg_surface->toplevel->client_pending.fullscreen) {
 | 
						if (xdg_surface->toplevel->client_pending.fullscreen) {
 | 
				
			||||||
		view_set_fullscreen(view, true);
 | 
							container_set_fullscreen(view->swayc, true);
 | 
				
			||||||
		struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE);
 | 
							struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE);
 | 
				
			||||||
		arrange_windows(ws);
 | 
							arrange_windows(ws);
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
| 
						 | 
					@ -299,6 +379,22 @@ static void handle_map(struct wl_listener *listener, void *data) {
 | 
				
			||||||
	xdg_shell_view->request_fullscreen.notify = handle_request_fullscreen;
 | 
						xdg_shell_view->request_fullscreen.notify = handle_request_fullscreen;
 | 
				
			||||||
	wl_signal_add(&xdg_surface->toplevel->events.request_fullscreen,
 | 
						wl_signal_add(&xdg_surface->toplevel->events.request_fullscreen,
 | 
				
			||||||
			&xdg_shell_view->request_fullscreen);
 | 
								&xdg_shell_view->request_fullscreen);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						xdg_shell_view->request_move.notify = handle_request_move;
 | 
				
			||||||
 | 
						wl_signal_add(&xdg_surface->toplevel->events.request_move,
 | 
				
			||||||
 | 
								&xdg_shell_view->request_move);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						xdg_shell_view->request_resize.notify = handle_request_resize;
 | 
				
			||||||
 | 
						wl_signal_add(&xdg_surface->toplevel->events.request_resize,
 | 
				
			||||||
 | 
								&xdg_shell_view->request_resize);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						xdg_shell_view->set_title.notify = handle_set_title;
 | 
				
			||||||
 | 
						wl_signal_add(&xdg_surface->toplevel->events.set_title,
 | 
				
			||||||
 | 
								&xdg_shell_view->set_title);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						xdg_shell_view->set_app_id.notify = handle_set_app_id;
 | 
				
			||||||
 | 
						wl_signal_add(&xdg_surface->toplevel->events.set_app_id,
 | 
				
			||||||
 | 
								&xdg_shell_view->set_app_id);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void handle_destroy(struct wl_listener *listener, void *data) {
 | 
					static void handle_destroy(struct wl_listener *listener, void *data) {
 | 
				
			||||||
| 
						 | 
					@ -344,9 +440,6 @@ void handle_xdg_shell_surface(struct wl_listener *listener, void *data) {
 | 
				
			||||||
	view_init(&xdg_shell_view->view, SWAY_VIEW_XDG_SHELL, &view_impl);
 | 
						view_init(&xdg_shell_view->view, SWAY_VIEW_XDG_SHELL, &view_impl);
 | 
				
			||||||
	xdg_shell_view->view.wlr_xdg_surface = xdg_surface;
 | 
						xdg_shell_view->view.wlr_xdg_surface = xdg_surface;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// TODO:
 | 
					 | 
				
			||||||
	// - Look up pid and open on appropriate workspace
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	xdg_shell_view->map.notify = handle_map;
 | 
						xdg_shell_view->map.notify = handle_map;
 | 
				
			||||||
	wl_signal_add(&xdg_surface->events.map, &xdg_shell_view->map);
 | 
						wl_signal_add(&xdg_surface->events.map, &xdg_shell_view->map);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,5 @@
 | 
				
			||||||
#define _POSIX_C_SOURCE 199309L
 | 
					#define _POSIX_C_SOURCE 199309L
 | 
				
			||||||
 | 
					#include <float.h>
 | 
				
			||||||
#include <stdbool.h>
 | 
					#include <stdbool.h>
 | 
				
			||||||
#include <stdlib.h>
 | 
					#include <stdlib.h>
 | 
				
			||||||
#include <wayland-server.h>
 | 
					#include <wayland-server.h>
 | 
				
			||||||
| 
						 | 
					@ -94,6 +95,16 @@ static struct sway_xdg_shell_v6_view *xdg_shell_v6_view_from_view(
 | 
				
			||||||
	return (struct sway_xdg_shell_v6_view *)view;
 | 
						return (struct sway_xdg_shell_v6_view *)view;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void get_constraints(struct sway_view *view, double *min_width,
 | 
				
			||||||
 | 
							double *max_width, double *min_height, double *max_height) {
 | 
				
			||||||
 | 
						struct wlr_xdg_toplevel_v6_state *state =
 | 
				
			||||||
 | 
							&view->wlr_xdg_surface_v6->toplevel->current;
 | 
				
			||||||
 | 
						*min_width = state->min_width > 0 ? state->min_width : DBL_MIN;
 | 
				
			||||||
 | 
						*max_width = state->max_width > 0 ? state->max_width : DBL_MAX;
 | 
				
			||||||
 | 
						*min_height = state->min_height > 0 ? state->min_height : DBL_MIN;
 | 
				
			||||||
 | 
						*max_height = state->max_height > 0 ? state->max_height : DBL_MAX;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const char *get_string_prop(struct sway_view *view, enum sway_view_prop prop) {
 | 
					static const char *get_string_prop(struct sway_view *view, enum sway_view_prop prop) {
 | 
				
			||||||
	if (xdg_shell_v6_view_from_view(view) == NULL) {
 | 
						if (xdg_shell_v6_view_from_view(view) == NULL) {
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
| 
						 | 
					@ -164,6 +175,15 @@ static void for_each_surface(struct sway_view *view,
 | 
				
			||||||
		user_data);
 | 
							user_data);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void for_each_popup(struct sway_view *view,
 | 
				
			||||||
 | 
							wlr_surface_iterator_func_t iterator, void *user_data) {
 | 
				
			||||||
 | 
						if (xdg_shell_v6_view_from_view(view) == NULL) {
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						wlr_xdg_surface_v6_for_each_popup(view->wlr_xdg_surface_v6, iterator,
 | 
				
			||||||
 | 
							user_data);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void _close(struct sway_view *view) {
 | 
					static void _close(struct sway_view *view) {
 | 
				
			||||||
	if (xdg_shell_v6_view_from_view(view) == NULL) {
 | 
						if (xdg_shell_v6_view_from_view(view) == NULL) {
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
| 
						 | 
					@ -174,6 +194,18 @@ static void _close(struct sway_view *view) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void close_popups_iterator(struct wlr_surface *surface,
 | 
				
			||||||
 | 
							int sx, int sy, void *data) {
 | 
				
			||||||
 | 
						struct wlr_xdg_surface_v6 *xdg_surface_v6 =
 | 
				
			||||||
 | 
							wlr_xdg_surface_v6_from_wlr_surface(surface);
 | 
				
			||||||
 | 
						wlr_xdg_surface_v6_send_close(xdg_surface_v6);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void close_popups(struct sway_view *view) {
 | 
				
			||||||
 | 
						wlr_xdg_surface_v6_for_each_popup(view->wlr_xdg_surface_v6,
 | 
				
			||||||
 | 
								close_popups_iterator, NULL);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void destroy(struct sway_view *view) {
 | 
					static void destroy(struct sway_view *view) {
 | 
				
			||||||
	struct sway_xdg_shell_v6_view *xdg_shell_v6_view =
 | 
						struct sway_xdg_shell_v6_view *xdg_shell_v6_view =
 | 
				
			||||||
		xdg_shell_v6_view_from_view(view);
 | 
							xdg_shell_v6_view_from_view(view);
 | 
				
			||||||
| 
						 | 
					@ -184,6 +216,7 @@ static void destroy(struct sway_view *view) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct sway_view_impl view_impl = {
 | 
					static const struct sway_view_impl view_impl = {
 | 
				
			||||||
 | 
						.get_constraints = get_constraints,
 | 
				
			||||||
	.get_string_prop = get_string_prop,
 | 
						.get_string_prop = get_string_prop,
 | 
				
			||||||
	.configure = configure,
 | 
						.configure = configure,
 | 
				
			||||||
	.set_activated = set_activated,
 | 
						.set_activated = set_activated,
 | 
				
			||||||
| 
						 | 
					@ -191,7 +224,9 @@ static const struct sway_view_impl view_impl = {
 | 
				
			||||||
	.set_fullscreen = set_fullscreen,
 | 
						.set_fullscreen = set_fullscreen,
 | 
				
			||||||
	.wants_floating = wants_floating,
 | 
						.wants_floating = wants_floating,
 | 
				
			||||||
	.for_each_surface = for_each_surface,
 | 
						.for_each_surface = for_each_surface,
 | 
				
			||||||
 | 
						.for_each_popup = for_each_popup,
 | 
				
			||||||
	.close = _close,
 | 
						.close = _close,
 | 
				
			||||||
 | 
						.close_popups = close_popups,
 | 
				
			||||||
	.destroy = destroy,
 | 
						.destroy = destroy,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -208,10 +243,24 @@ static void handle_commit(struct wl_listener *listener, void *data) {
 | 
				
			||||||
		transaction_notify_view_ready(view, xdg_surface_v6->configure_serial);
 | 
							transaction_notify_view_ready(view, xdg_surface_v6->configure_serial);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	view_update_title(view, false);
 | 
					 | 
				
			||||||
	view_damage_from(view);
 | 
						view_damage_from(view);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void handle_set_title(struct wl_listener *listener, void *data) {
 | 
				
			||||||
 | 
						struct sway_xdg_shell_v6_view *xdg_shell_v6_view =
 | 
				
			||||||
 | 
							wl_container_of(listener, xdg_shell_v6_view, set_title);
 | 
				
			||||||
 | 
						struct sway_view *view = &xdg_shell_v6_view->view;
 | 
				
			||||||
 | 
						view_update_title(view, false);
 | 
				
			||||||
 | 
						view_execute_criteria(view);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void handle_set_app_id(struct wl_listener *listener, void *data) {
 | 
				
			||||||
 | 
						struct sway_xdg_shell_v6_view *xdg_shell_v6_view =
 | 
				
			||||||
 | 
							wl_container_of(listener, xdg_shell_v6_view, set_app_id);
 | 
				
			||||||
 | 
						struct sway_view *view = &xdg_shell_v6_view->view;
 | 
				
			||||||
 | 
						view_execute_criteria(view);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void handle_new_popup(struct wl_listener *listener, void *data) {
 | 
					static void handle_new_popup(struct wl_listener *listener, void *data) {
 | 
				
			||||||
	struct sway_xdg_shell_v6_view *xdg_shell_v6_view =
 | 
						struct sway_xdg_shell_v6_view *xdg_shell_v6_view =
 | 
				
			||||||
		wl_container_of(listener, xdg_shell_v6_view, new_popup);
 | 
							wl_container_of(listener, xdg_shell_v6_view, new_popup);
 | 
				
			||||||
| 
						 | 
					@ -236,13 +285,41 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	view_set_fullscreen(view, e->fullscreen);
 | 
						container_set_fullscreen(view->swayc, e->fullscreen);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct sway_container *output = container_parent(view->swayc, C_OUTPUT);
 | 
						struct sway_container *output = container_parent(view->swayc, C_OUTPUT);
 | 
				
			||||||
	arrange_windows(output);
 | 
						arrange_windows(output);
 | 
				
			||||||
	transaction_commit_dirty();
 | 
						transaction_commit_dirty();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void handle_request_move(struct wl_listener *listener, void *data) {
 | 
				
			||||||
 | 
						struct sway_xdg_shell_v6_view *xdg_shell_v6_view =
 | 
				
			||||||
 | 
							wl_container_of(listener, xdg_shell_v6_view, request_move);
 | 
				
			||||||
 | 
						struct sway_view *view = &xdg_shell_v6_view->view;
 | 
				
			||||||
 | 
						if (!container_is_floating(view->swayc)) {
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						struct wlr_xdg_toplevel_v6_move_event *e = data;
 | 
				
			||||||
 | 
						struct sway_seat *seat = e->seat->seat->data;
 | 
				
			||||||
 | 
						if (e->serial == seat->last_button_serial) {
 | 
				
			||||||
 | 
							seat_begin_move(seat, view->swayc, seat->last_button);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void handle_request_resize(struct wl_listener *listener, void *data) {
 | 
				
			||||||
 | 
						struct sway_xdg_shell_v6_view *xdg_shell_v6_view =
 | 
				
			||||||
 | 
							wl_container_of(listener, xdg_shell_v6_view, request_resize);
 | 
				
			||||||
 | 
						struct sway_view *view = &xdg_shell_v6_view->view;
 | 
				
			||||||
 | 
						if (!container_is_floating(view->swayc)) {
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						struct wlr_xdg_toplevel_v6_resize_event *e = data;
 | 
				
			||||||
 | 
						struct sway_seat *seat = e->seat->seat->data;
 | 
				
			||||||
 | 
						if (e->serial == seat->last_button_serial) {
 | 
				
			||||||
 | 
							seat_begin_resize(seat, view->swayc, seat->last_button, e->edges);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void handle_unmap(struct wl_listener *listener, void *data) {
 | 
					static void handle_unmap(struct wl_listener *listener, void *data) {
 | 
				
			||||||
	struct sway_xdg_shell_v6_view *xdg_shell_v6_view =
 | 
						struct sway_xdg_shell_v6_view *xdg_shell_v6_view =
 | 
				
			||||||
		wl_container_of(listener, xdg_shell_v6_view, unmap);
 | 
							wl_container_of(listener, xdg_shell_v6_view, unmap);
 | 
				
			||||||
| 
						 | 
					@ -257,6 +334,10 @@ static void handle_unmap(struct wl_listener *listener, void *data) {
 | 
				
			||||||
	wl_list_remove(&xdg_shell_v6_view->commit.link);
 | 
						wl_list_remove(&xdg_shell_v6_view->commit.link);
 | 
				
			||||||
	wl_list_remove(&xdg_shell_v6_view->new_popup.link);
 | 
						wl_list_remove(&xdg_shell_v6_view->new_popup.link);
 | 
				
			||||||
	wl_list_remove(&xdg_shell_v6_view->request_fullscreen.link);
 | 
						wl_list_remove(&xdg_shell_v6_view->request_fullscreen.link);
 | 
				
			||||||
 | 
						wl_list_remove(&xdg_shell_v6_view->request_move.link);
 | 
				
			||||||
 | 
						wl_list_remove(&xdg_shell_v6_view->request_resize.link);
 | 
				
			||||||
 | 
						wl_list_remove(&xdg_shell_v6_view->set_title.link);
 | 
				
			||||||
 | 
						wl_list_remove(&xdg_shell_v6_view->set_app_id.link);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void handle_map(struct wl_listener *listener, void *data) {
 | 
					static void handle_map(struct wl_listener *listener, void *data) {
 | 
				
			||||||
| 
						 | 
					@ -275,7 +356,7 @@ static void handle_map(struct wl_listener *listener, void *data) {
 | 
				
			||||||
	view_map(view, view->wlr_xdg_surface_v6->surface);
 | 
						view_map(view, view->wlr_xdg_surface_v6->surface);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (xdg_surface->toplevel->client_pending.fullscreen) {
 | 
						if (xdg_surface->toplevel->client_pending.fullscreen) {
 | 
				
			||||||
		view_set_fullscreen(view, true);
 | 
							container_set_fullscreen(view->swayc, true);
 | 
				
			||||||
		struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE);
 | 
							struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE);
 | 
				
			||||||
		arrange_windows(ws);
 | 
							arrange_windows(ws);
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
| 
						 | 
					@ -294,6 +375,22 @@ static void handle_map(struct wl_listener *listener, void *data) {
 | 
				
			||||||
	xdg_shell_v6_view->request_fullscreen.notify = handle_request_fullscreen;
 | 
						xdg_shell_v6_view->request_fullscreen.notify = handle_request_fullscreen;
 | 
				
			||||||
	wl_signal_add(&xdg_surface->toplevel->events.request_fullscreen,
 | 
						wl_signal_add(&xdg_surface->toplevel->events.request_fullscreen,
 | 
				
			||||||
			&xdg_shell_v6_view->request_fullscreen);
 | 
								&xdg_shell_v6_view->request_fullscreen);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						xdg_shell_v6_view->request_move.notify = handle_request_move;
 | 
				
			||||||
 | 
						wl_signal_add(&xdg_surface->toplevel->events.request_move,
 | 
				
			||||||
 | 
								&xdg_shell_v6_view->request_move);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						xdg_shell_v6_view->request_resize.notify = handle_request_resize;
 | 
				
			||||||
 | 
						wl_signal_add(&xdg_surface->toplevel->events.request_resize,
 | 
				
			||||||
 | 
								&xdg_shell_v6_view->request_resize);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						xdg_shell_v6_view->set_title.notify = handle_set_title;
 | 
				
			||||||
 | 
						wl_signal_add(&xdg_surface->toplevel->events.set_title,
 | 
				
			||||||
 | 
								&xdg_shell_v6_view->set_title);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						xdg_shell_v6_view->set_app_id.notify = handle_set_app_id;
 | 
				
			||||||
 | 
						wl_signal_add(&xdg_surface->toplevel->events.set_app_id,
 | 
				
			||||||
 | 
								&xdg_shell_v6_view->set_app_id);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void handle_destroy(struct wl_listener *listener, void *data) {
 | 
					static void handle_destroy(struct wl_listener *listener, void *data) {
 | 
				
			||||||
| 
						 | 
					@ -335,9 +432,6 @@ void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) {
 | 
				
			||||||
	view_init(&xdg_shell_v6_view->view, SWAY_VIEW_XDG_SHELL_V6, &view_impl);
 | 
						view_init(&xdg_shell_v6_view->view, SWAY_VIEW_XDG_SHELL_V6, &view_impl);
 | 
				
			||||||
	xdg_shell_v6_view->view.wlr_xdg_surface_v6 = xdg_surface;
 | 
						xdg_shell_v6_view->view.wlr_xdg_surface_v6 = xdg_surface;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// TODO:
 | 
					 | 
				
			||||||
	// - Look up pid and open on appropriate workspace
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	xdg_shell_v6_view->map.notify = handle_map;
 | 
						xdg_shell_v6_view->map.notify = handle_map;
 | 
				
			||||||
	wl_signal_add(&xdg_surface->events.map, &xdg_shell_v6_view->map);
 | 
						wl_signal_add(&xdg_surface->events.map, &xdg_shell_v6_view->map);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -69,12 +69,14 @@ static void unmanaged_handle_map(struct wl_listener *listener, void *data) {
 | 
				
			||||||
	surface->ly = xsurface->y;
 | 
						surface->ly = xsurface->y;
 | 
				
			||||||
	desktop_damage_surface(xsurface->surface, surface->lx, surface->ly, true);
 | 
						desktop_damage_surface(xsurface->surface, surface->lx, surface->ly, true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (wlr_xwayland_or_surface_wants_focus(xsurface)) {
 | 
				
			||||||
		struct sway_seat *seat = input_manager_current_seat(input_manager);
 | 
							struct sway_seat *seat = input_manager_current_seat(input_manager);
 | 
				
			||||||
		struct wlr_xwayland *xwayland =
 | 
							struct wlr_xwayland *xwayland =
 | 
				
			||||||
			seat->input->server->xwayland.wlr_xwayland;
 | 
								seat->input->server->xwayland.wlr_xwayland;
 | 
				
			||||||
		wlr_xwayland_set_seat(xwayland, seat->wlr_seat);
 | 
							wlr_xwayland_set_seat(xwayland, seat->wlr_seat);
 | 
				
			||||||
		seat_set_focus_surface(seat, xsurface->surface, false);
 | 
							seat_set_focus_surface(seat, xsurface->surface, false);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void unmanaged_handle_unmap(struct wl_listener *listener, void *data) {
 | 
					static void unmanaged_handle_unmap(struct wl_listener *listener, void *data) {
 | 
				
			||||||
	struct sway_xwayland_unmanaged *surface =
 | 
						struct sway_xwayland_unmanaged *surface =
 | 
				
			||||||
| 
						 | 
					@ -305,6 +307,8 @@ static void handle_destroy(struct wl_listener *listener, void *data) {
 | 
				
			||||||
	wl_list_remove(&xwayland_view->destroy.link);
 | 
						wl_list_remove(&xwayland_view->destroy.link);
 | 
				
			||||||
	wl_list_remove(&xwayland_view->request_configure.link);
 | 
						wl_list_remove(&xwayland_view->request_configure.link);
 | 
				
			||||||
	wl_list_remove(&xwayland_view->request_fullscreen.link);
 | 
						wl_list_remove(&xwayland_view->request_fullscreen.link);
 | 
				
			||||||
 | 
						wl_list_remove(&xwayland_view->request_move.link);
 | 
				
			||||||
 | 
						wl_list_remove(&xwayland_view->request_resize.link);
 | 
				
			||||||
	wl_list_remove(&xwayland_view->set_title.link);
 | 
						wl_list_remove(&xwayland_view->set_title.link);
 | 
				
			||||||
	wl_list_remove(&xwayland_view->set_class.link);
 | 
						wl_list_remove(&xwayland_view->set_class.link);
 | 
				
			||||||
	wl_list_remove(&xwayland_view->set_window_type.link);
 | 
						wl_list_remove(&xwayland_view->set_window_type.link);
 | 
				
			||||||
| 
						 | 
					@ -355,7 +359,7 @@ static void handle_map(struct wl_listener *listener, void *data) {
 | 
				
			||||||
	view_map(view, xsurface->surface);
 | 
						view_map(view, xsurface->surface);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (xsurface->fullscreen) {
 | 
						if (xsurface->fullscreen) {
 | 
				
			||||||
		view_set_fullscreen(view, true);
 | 
							container_set_fullscreen(view->swayc, true);
 | 
				
			||||||
		struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE);
 | 
							struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE);
 | 
				
			||||||
		arrange_windows(ws);
 | 
							arrange_windows(ws);
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
| 
						 | 
					@ -393,13 +397,44 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data)
 | 
				
			||||||
	if (!xsurface->mapped) {
 | 
						if (!xsurface->mapped) {
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	view_set_fullscreen(view, xsurface->fullscreen);
 | 
						container_set_fullscreen(view->swayc, xsurface->fullscreen);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct sway_container *output = container_parent(view->swayc, C_OUTPUT);
 | 
						struct sway_container *output = container_parent(view->swayc, C_OUTPUT);
 | 
				
			||||||
	arrange_windows(output);
 | 
						arrange_windows(output);
 | 
				
			||||||
	transaction_commit_dirty();
 | 
						transaction_commit_dirty();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void handle_request_move(struct wl_listener *listener, void *data) {
 | 
				
			||||||
 | 
						struct sway_xwayland_view *xwayland_view =
 | 
				
			||||||
 | 
							wl_container_of(listener, xwayland_view, request_move);
 | 
				
			||||||
 | 
						struct sway_view *view = &xwayland_view->view;
 | 
				
			||||||
 | 
						struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface;
 | 
				
			||||||
 | 
						if (!xsurface->mapped) {
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (!container_is_floating(view->swayc)) {
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						struct sway_seat *seat = input_manager_current_seat(input_manager);
 | 
				
			||||||
 | 
						seat_begin_move(seat, view->swayc, seat->last_button);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void handle_request_resize(struct wl_listener *listener, void *data) {
 | 
				
			||||||
 | 
						struct sway_xwayland_view *xwayland_view =
 | 
				
			||||||
 | 
							wl_container_of(listener, xwayland_view, request_resize);
 | 
				
			||||||
 | 
						struct sway_view *view = &xwayland_view->view;
 | 
				
			||||||
 | 
						struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface;
 | 
				
			||||||
 | 
						if (!xsurface->mapped) {
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (!container_is_floating(view->swayc)) {
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						struct wlr_xwayland_resize_event *e = data;
 | 
				
			||||||
 | 
						struct sway_seat *seat = input_manager_current_seat(input_manager);
 | 
				
			||||||
 | 
						seat_begin_resize(seat, view->swayc, seat->last_button, e->edges);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void handle_set_title(struct wl_listener *listener, void *data) {
 | 
					static void handle_set_title(struct wl_listener *listener, void *data) {
 | 
				
			||||||
	struct sway_xwayland_view *xwayland_view =
 | 
						struct sway_xwayland_view *xwayland_view =
 | 
				
			||||||
		wl_container_of(listener, xwayland_view, set_title);
 | 
							wl_container_of(listener, xwayland_view, set_title);
 | 
				
			||||||
| 
						 | 
					@ -481,9 +516,6 @@ void handle_xwayland_surface(struct wl_listener *listener, void *data) {
 | 
				
			||||||
	view_init(&xwayland_view->view, SWAY_VIEW_XWAYLAND, &view_impl);
 | 
						view_init(&xwayland_view->view, SWAY_VIEW_XWAYLAND, &view_impl);
 | 
				
			||||||
	xwayland_view->view.wlr_xwayland_surface = xsurface;
 | 
						xwayland_view->view.wlr_xwayland_surface = xsurface;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// TODO:
 | 
					 | 
				
			||||||
	// - Look up pid and open on appropriate workspace
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	wl_signal_add(&xsurface->events.destroy, &xwayland_view->destroy);
 | 
						wl_signal_add(&xsurface->events.destroy, &xwayland_view->destroy);
 | 
				
			||||||
	xwayland_view->destroy.notify = handle_destroy;
 | 
						xwayland_view->destroy.notify = handle_destroy;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -495,6 +527,14 @@ void handle_xwayland_surface(struct wl_listener *listener, void *data) {
 | 
				
			||||||
		&xwayland_view->request_fullscreen);
 | 
							&xwayland_view->request_fullscreen);
 | 
				
			||||||
	xwayland_view->request_fullscreen.notify = handle_request_fullscreen;
 | 
						xwayland_view->request_fullscreen.notify = handle_request_fullscreen;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wl_signal_add(&xsurface->events.request_move,
 | 
				
			||||||
 | 
							&xwayland_view->request_move);
 | 
				
			||||||
 | 
						xwayland_view->request_move.notify = handle_request_move;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wl_signal_add(&xsurface->events.request_resize,
 | 
				
			||||||
 | 
							&xwayland_view->request_resize);
 | 
				
			||||||
 | 
						xwayland_view->request_resize.notify = handle_request_resize;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wl_signal_add(&xsurface->events.set_title, &xwayland_view->set_title);
 | 
						wl_signal_add(&xsurface->events.set_title, &xwayland_view->set_title);
 | 
				
			||||||
	xwayland_view->set_title.notify = handle_set_title;
 | 
						xwayland_view->set_title.notify = handle_set_title;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,15 +5,20 @@
 | 
				
			||||||
#elif __FreeBSD__
 | 
					#elif __FreeBSD__
 | 
				
			||||||
#include <dev/evdev/input-event-codes.h>
 | 
					#include <dev/evdev/input-event-codes.h>
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					#include <limits.h>
 | 
				
			||||||
#include <wlr/types/wlr_cursor.h>
 | 
					#include <wlr/types/wlr_cursor.h>
 | 
				
			||||||
#include <wlr/types/wlr_xcursor_manager.h>
 | 
					#include <wlr/types/wlr_xcursor_manager.h>
 | 
				
			||||||
#include <wlr/types/wlr_idle.h>
 | 
					#include <wlr/types/wlr_idle.h>
 | 
				
			||||||
#include "list.h"
 | 
					#include "list.h"
 | 
				
			||||||
#include "log.h"
 | 
					#include "log.h"
 | 
				
			||||||
 | 
					#include "config.h"
 | 
				
			||||||
 | 
					#include "sway/desktop.h"
 | 
				
			||||||
#include "sway/desktop/transaction.h"
 | 
					#include "sway/desktop/transaction.h"
 | 
				
			||||||
#include "sway/input/cursor.h"
 | 
					#include "sway/input/cursor.h"
 | 
				
			||||||
 | 
					#include "sway/input/keyboard.h"
 | 
				
			||||||
#include "sway/layers.h"
 | 
					#include "sway/layers.h"
 | 
				
			||||||
#include "sway/output.h"
 | 
					#include "sway/output.h"
 | 
				
			||||||
 | 
					#include "sway/tree/arrange.h"
 | 
				
			||||||
#include "sway/tree/view.h"
 | 
					#include "sway/tree/view.h"
 | 
				
			||||||
#include "sway/tree/workspace.h"
 | 
					#include "sway/tree/workspace.h"
 | 
				
			||||||
#include "wlr-layer-shell-unstable-v1-protocol.h"
 | 
					#include "wlr-layer-shell-unstable-v1-protocol.h"
 | 
				
			||||||
| 
						 | 
					@ -50,6 +55,7 @@ static struct sway_container *container_at_coords(
 | 
				
			||||||
		struct sway_seat *seat, double lx, double ly,
 | 
							struct sway_seat *seat, double lx, double ly,
 | 
				
			||||||
		struct wlr_surface **surface, double *sx, double *sy) {
 | 
							struct wlr_surface **surface, double *sx, double *sy) {
 | 
				
			||||||
	// check for unmanaged views first
 | 
						// check for unmanaged views first
 | 
				
			||||||
 | 
					#ifdef HAVE_XWAYLAND
 | 
				
			||||||
	struct wl_list *unmanaged = &root_container.sway_root->xwayland_unmanaged;
 | 
						struct wl_list *unmanaged = &root_container.sway_root->xwayland_unmanaged;
 | 
				
			||||||
	struct sway_xwayland_unmanaged *unmanaged_surface;
 | 
						struct sway_xwayland_unmanaged *unmanaged_surface;
 | 
				
			||||||
	wl_list_for_each_reverse(unmanaged_surface, unmanaged, link) {
 | 
						wl_list_for_each_reverse(unmanaged_surface, unmanaged, link) {
 | 
				
			||||||
| 
						 | 
					@ -65,7 +71,7 @@ static struct sway_container *container_at_coords(
 | 
				
			||||||
			return NULL;
 | 
								return NULL;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
	// find the output the cursor is on
 | 
						// find the output the cursor is on
 | 
				
			||||||
	struct wlr_output_layout *output_layout =
 | 
						struct wlr_output_layout *output_layout =
 | 
				
			||||||
		root_container.sway_root->output_layout;
 | 
							root_container.sway_root->output_layout;
 | 
				
			||||||
| 
						 | 
					@ -93,14 +99,8 @@ static struct sway_container *container_at_coords(
 | 
				
			||||||
		return ws;
 | 
							return ws;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (ws->sway_workspace->fullscreen) {
 | 
						if (ws->sway_workspace->fullscreen) {
 | 
				
			||||||
		struct wlr_surface *wlr_surface = ws->sway_workspace->fullscreen->surface;
 | 
							return container_at_view(ws->sway_workspace->fullscreen, lx, ly,
 | 
				
			||||||
		if (wlr_surface_point_accepts_input(wlr_surface, ox, oy)) {
 | 
									surface, sx, sy);
 | 
				
			||||||
			*sx = ox;
 | 
					 | 
				
			||||||
			*sy = oy;
 | 
					 | 
				
			||||||
			*surface = wlr_surface;
 | 
					 | 
				
			||||||
			return ws->sway_workspace->fullscreen->swayc;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		return NULL;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if ((*surface = layer_surface_at(output,
 | 
						if ((*surface = layer_surface_at(output,
 | 
				
			||||||
				&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP],
 | 
									&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP],
 | 
				
			||||||
| 
						 | 
					@ -109,9 +109,6 @@ static struct sway_container *container_at_coords(
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct sway_container *c;
 | 
						struct sway_container *c;
 | 
				
			||||||
	if ((c = floating_container_at(lx, ly, surface, sx, sy))) {
 | 
					 | 
				
			||||||
		return c;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if ((c = container_at(ws, lx, ly, surface, sx, sy))) {
 | 
						if ((c = container_at(ws, lx, ly, surface, sx, sy))) {
 | 
				
			||||||
		return c;
 | 
							return c;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -127,7 +124,7 @@ static struct sway_container *container_at_coords(
 | 
				
			||||||
		return ws;
 | 
							return ws;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	c = seat_get_focus_inactive(seat, output->swayc);
 | 
						c = seat_get_active_child(seat, output->swayc);
 | 
				
			||||||
	if (c) {
 | 
						if (c) {
 | 
				
			||||||
		return c;
 | 
							return c;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -139,6 +136,171 @@ static struct sway_container *container_at_coords(
 | 
				
			||||||
	return output->swayc;
 | 
						return output->swayc;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static enum wlr_edges find_resize_edge(struct sway_container *cont,
 | 
				
			||||||
 | 
							struct sway_cursor *cursor) {
 | 
				
			||||||
 | 
						if (cont->type != C_VIEW) {
 | 
				
			||||||
 | 
							return WLR_EDGE_NONE;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						struct sway_view *view = cont->sway_view;
 | 
				
			||||||
 | 
						if (view->border == B_NONE || !view->border_thickness || view->using_csd) {
 | 
				
			||||||
 | 
							return WLR_EDGE_NONE;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						enum wlr_edges edge = 0;
 | 
				
			||||||
 | 
						if (cursor->cursor->x < cont->x + view->border_thickness) {
 | 
				
			||||||
 | 
							edge |= WLR_EDGE_LEFT;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (cursor->cursor->y < cont->y + view->border_thickness) {
 | 
				
			||||||
 | 
							edge |= WLR_EDGE_TOP;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (cursor->cursor->x >= cont->x + cont->width - view->border_thickness) {
 | 
				
			||||||
 | 
							edge |= WLR_EDGE_RIGHT;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (cursor->cursor->y >= cont->y + cont->height - view->border_thickness) {
 | 
				
			||||||
 | 
							edge |= WLR_EDGE_BOTTOM;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return edge;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void handle_move_motion(struct sway_seat *seat,
 | 
				
			||||||
 | 
							struct sway_cursor *cursor) {
 | 
				
			||||||
 | 
						struct sway_container *con = seat->op_container;
 | 
				
			||||||
 | 
						desktop_damage_whole_container(con);
 | 
				
			||||||
 | 
						container_floating_translate(con,
 | 
				
			||||||
 | 
								cursor->cursor->x - cursor->previous.x,
 | 
				
			||||||
 | 
								cursor->cursor->y - cursor->previous.y);
 | 
				
			||||||
 | 
						desktop_damage_whole_container(con);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void calculate_floating_constraints(struct sway_container *con,
 | 
				
			||||||
 | 
							int *min_width, int *max_width, int *min_height, int *max_height) {
 | 
				
			||||||
 | 
						if (config->floating_minimum_width == -1) { // no minimum
 | 
				
			||||||
 | 
							*min_width = 0;
 | 
				
			||||||
 | 
						} else if (config->floating_minimum_width == 0) { // automatic
 | 
				
			||||||
 | 
							*min_width = 75;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							*min_width = config->floating_minimum_width;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (config->floating_minimum_height == -1) { // no minimum
 | 
				
			||||||
 | 
							*min_height = 0;
 | 
				
			||||||
 | 
						} else if (config->floating_minimum_height == 0) { // automatic
 | 
				
			||||||
 | 
							*min_height = 50;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							*min_height = config->floating_minimum_height;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (config->floating_maximum_width == -1) { // no maximum
 | 
				
			||||||
 | 
							*max_width = INT_MAX;
 | 
				
			||||||
 | 
						} else if (config->floating_maximum_width == 0) { // automatic
 | 
				
			||||||
 | 
							struct sway_container *ws = container_parent(con, C_WORKSPACE);
 | 
				
			||||||
 | 
							*max_width = ws->width;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							*max_width = config->floating_maximum_width;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (config->floating_maximum_height == -1) { // no maximum
 | 
				
			||||||
 | 
							*max_height = INT_MAX;
 | 
				
			||||||
 | 
						} else if (config->floating_maximum_height == 0) { // automatic
 | 
				
			||||||
 | 
							struct sway_container *ws = container_parent(con, C_WORKSPACE);
 | 
				
			||||||
 | 
							*max_height = ws->height;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							*max_height = config->floating_maximum_height;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void handle_resize_motion(struct sway_seat *seat,
 | 
				
			||||||
 | 
							struct sway_cursor *cursor) {
 | 
				
			||||||
 | 
						struct sway_container *con = seat->op_container;
 | 
				
			||||||
 | 
						enum wlr_edges edge = seat->op_resize_edge;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// The amount the mouse has moved since the start of the resize operation
 | 
				
			||||||
 | 
						// Positive is down/right
 | 
				
			||||||
 | 
						double mouse_move_x = cursor->cursor->x - seat->op_ref_lx;
 | 
				
			||||||
 | 
						double mouse_move_y = cursor->cursor->y - seat->op_ref_ly;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (edge == WLR_EDGE_TOP || edge == WLR_EDGE_BOTTOM) {
 | 
				
			||||||
 | 
							mouse_move_x = 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (edge == WLR_EDGE_LEFT || edge == WLR_EDGE_RIGHT) {
 | 
				
			||||||
 | 
							mouse_move_y = 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						double grow_width = edge & WLR_EDGE_LEFT ? -mouse_move_x : mouse_move_x;
 | 
				
			||||||
 | 
						double grow_height = edge & WLR_EDGE_TOP ? -mouse_move_y : mouse_move_y;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (seat->op_resize_preserve_ratio) {
 | 
				
			||||||
 | 
							double x_multiplier = grow_width / seat->op_ref_width;
 | 
				
			||||||
 | 
							double y_multiplier = grow_height / seat->op_ref_height;
 | 
				
			||||||
 | 
							double max_multiplier = fmax(x_multiplier, y_multiplier);
 | 
				
			||||||
 | 
							grow_width = seat->op_ref_width * max_multiplier;
 | 
				
			||||||
 | 
							grow_height = seat->op_ref_height * max_multiplier;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Determine new width/height, and accommodate for floating min/max values
 | 
				
			||||||
 | 
						double width = seat->op_ref_width + grow_width;
 | 
				
			||||||
 | 
						double height = seat->op_ref_height + grow_height;
 | 
				
			||||||
 | 
						int min_width, max_width, min_height, max_height;
 | 
				
			||||||
 | 
						calculate_floating_constraints(con, &min_width, &max_width,
 | 
				
			||||||
 | 
								&min_height, &max_height);
 | 
				
			||||||
 | 
						width = fmax(min_width, fmin(width, max_width));
 | 
				
			||||||
 | 
						height = fmax(min_height, fmin(height, max_height));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Apply the view's min/max size
 | 
				
			||||||
 | 
						if (con->type == C_VIEW) {
 | 
				
			||||||
 | 
							double view_min_width, view_max_width, view_min_height, view_max_height;
 | 
				
			||||||
 | 
							view_get_constraints(con->sway_view, &view_min_width, &view_max_width,
 | 
				
			||||||
 | 
									&view_min_height, &view_max_height);
 | 
				
			||||||
 | 
							width = fmax(view_min_width, fmin(width, view_max_width));
 | 
				
			||||||
 | 
							height = fmax(view_min_height, fmin(height, view_max_height));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Recalculate these, in case we hit a min/max limit
 | 
				
			||||||
 | 
						grow_width = width - seat->op_ref_width;
 | 
				
			||||||
 | 
						grow_height = height - seat->op_ref_height;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Determine grow x/y values - these are relative to the container's x/y at
 | 
				
			||||||
 | 
						// the start of the resize operation.
 | 
				
			||||||
 | 
						double grow_x = 0, grow_y = 0;
 | 
				
			||||||
 | 
						if (edge & WLR_EDGE_LEFT) {
 | 
				
			||||||
 | 
							grow_x = -grow_width;
 | 
				
			||||||
 | 
						} else if (edge & WLR_EDGE_RIGHT) {
 | 
				
			||||||
 | 
							grow_x = 0;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							grow_x = -grow_width / 2;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (edge & WLR_EDGE_TOP) {
 | 
				
			||||||
 | 
							grow_y = -grow_height;
 | 
				
			||||||
 | 
						} else if (edge & WLR_EDGE_BOTTOM) {
 | 
				
			||||||
 | 
							grow_y = 0;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							grow_y = -grow_height / 2;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Determine the amounts we need to bump everything relative to the current
 | 
				
			||||||
 | 
						// size.
 | 
				
			||||||
 | 
						int relative_grow_width = width - con->width;
 | 
				
			||||||
 | 
						int relative_grow_height = height - con->height;
 | 
				
			||||||
 | 
						int relative_grow_x = (seat->op_ref_con_lx + grow_x) - con->x;
 | 
				
			||||||
 | 
						int relative_grow_y = (seat->op_ref_con_ly + grow_y) - con->y;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Actually resize stuff
 | 
				
			||||||
 | 
						con->x += relative_grow_x;
 | 
				
			||||||
 | 
						con->y += relative_grow_y;
 | 
				
			||||||
 | 
						con->width += relative_grow_width;
 | 
				
			||||||
 | 
						con->height += relative_grow_height;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (con->type == C_VIEW) {
 | 
				
			||||||
 | 
							struct sway_view *view = con->sway_view;
 | 
				
			||||||
 | 
							view->x += relative_grow_x;
 | 
				
			||||||
 | 
							view->y += relative_grow_y;
 | 
				
			||||||
 | 
							view->width += relative_grow_width;
 | 
				
			||||||
 | 
							view->height += relative_grow_height;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						arrange_windows(con);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec,
 | 
					void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec,
 | 
				
			||||||
		bool allow_refocusing) {
 | 
							bool allow_refocusing) {
 | 
				
			||||||
	if (time_msec == 0) {
 | 
						if (time_msec == 0) {
 | 
				
			||||||
| 
						 | 
					@ -146,6 +308,18 @@ void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct sway_seat *seat = cursor->seat;
 | 
						struct sway_seat *seat = cursor->seat;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (seat->operation != OP_NONE) {
 | 
				
			||||||
 | 
							if (seat->operation == OP_MOVE) {
 | 
				
			||||||
 | 
								handle_move_motion(seat, cursor);
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								handle_resize_motion(seat, cursor);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							cursor->previous.x = cursor->cursor->x;
 | 
				
			||||||
 | 
							cursor->previous.y = cursor->cursor->y;
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wlr_seat *wlr_seat = seat->wlr_seat;
 | 
						struct wlr_seat *wlr_seat = seat->wlr_seat;
 | 
				
			||||||
	struct wlr_surface *surface = NULL;
 | 
						struct wlr_surface *surface = NULL;
 | 
				
			||||||
	double sx, sy;
 | 
						double sx, sy;
 | 
				
			||||||
| 
						 | 
					@ -172,7 +346,7 @@ void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec,
 | 
				
			||||||
				output = container_parent(c, C_OUTPUT);
 | 
									output = container_parent(c, C_OUTPUT);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			if (output != focus) {
 | 
								if (output != focus) {
 | 
				
			||||||
				seat_set_focus_warp(seat, c, false);
 | 
									seat_set_focus_warp(seat, c, false, true);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		} else if (c->type == C_VIEW) {
 | 
							} else if (c->type == C_VIEW) {
 | 
				
			||||||
			// Focus c if the following are true:
 | 
								// Focus c if the following are true:
 | 
				
			||||||
| 
						 | 
					@ -182,27 +356,33 @@ void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec,
 | 
				
			||||||
			if (!wlr_seat_keyboard_has_grab(cursor->seat->wlr_seat) &&
 | 
								if (!wlr_seat_keyboard_has_grab(cursor->seat->wlr_seat) &&
 | 
				
			||||||
					c != prev_c &&
 | 
										c != prev_c &&
 | 
				
			||||||
					view_is_visible(c->sway_view)) {
 | 
										view_is_visible(c->sway_view)) {
 | 
				
			||||||
				seat_set_focus_warp(seat, c, false);
 | 
									seat_set_focus_warp(seat, c, false, true);
 | 
				
			||||||
			} else {
 | 
								} else {
 | 
				
			||||||
				struct sway_container *next_focus =
 | 
									struct sway_container *next_focus =
 | 
				
			||||||
					seat_get_focus_inactive(seat, &root_container);
 | 
										seat_get_focus_inactive(seat, &root_container);
 | 
				
			||||||
				if (next_focus && next_focus->type == C_VIEW &&
 | 
									if (next_focus && next_focus->type == C_VIEW &&
 | 
				
			||||||
						view_is_visible(next_focus->sway_view)) {
 | 
											view_is_visible(next_focus->sway_view)) {
 | 
				
			||||||
					seat_set_focus_warp(seat, next_focus, false);
 | 
										seat_set_focus_warp(seat, next_focus, false, true);
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// reset cursor if switching between clients
 | 
						// Handle cursor image
 | 
				
			||||||
	struct wl_client *client = NULL;
 | 
						if (surface) {
 | 
				
			||||||
	if (surface != NULL) {
 | 
							// Reset cursor if switching between clients
 | 
				
			||||||
		client = wl_resource_get_client(surface->resource);
 | 
							struct wl_client *client = wl_resource_get_client(surface->resource);
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
		if (client != cursor->image_client) {
 | 
							if (client != cursor->image_client) {
 | 
				
			||||||
		wlr_xcursor_manager_set_cursor_image(cursor->xcursor_manager,
 | 
								cursor_set_image(cursor, "left_ptr", client);
 | 
				
			||||||
			"left_ptr", cursor->cursor);
 | 
							}
 | 
				
			||||||
		cursor->image_client = client;
 | 
						} else if (c && container_is_floating(c)) {
 | 
				
			||||||
 | 
							// Try a floating container's resize edge
 | 
				
			||||||
 | 
							enum wlr_edges edge = find_resize_edge(c, cursor);
 | 
				
			||||||
 | 
							const char *image = edge == WLR_EDGE_NONE ?
 | 
				
			||||||
 | 
								"left_ptr" : wlr_xcursor_get_resize_name(edge);
 | 
				
			||||||
 | 
							cursor_set_image(cursor, image, NULL);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							cursor_set_image(cursor, "left_ptr", NULL);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// send pointer enter/leave
 | 
						// send pointer enter/leave
 | 
				
			||||||
| 
						 | 
					@ -243,8 +423,142 @@ static void handle_cursor_motion_absolute(
 | 
				
			||||||
	transaction_commit_dirty();
 | 
						transaction_commit_dirty();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void dispatch_cursor_button_floating(struct sway_cursor *cursor,
 | 
				
			||||||
 | 
							uint32_t time_msec, uint32_t button, enum wlr_button_state state,
 | 
				
			||||||
 | 
							struct wlr_surface *surface, double sx, double sy,
 | 
				
			||||||
 | 
							struct sway_container *cont) {
 | 
				
			||||||
 | 
						struct sway_seat *seat = cursor->seat;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Deny moving or resizing a fullscreen container
 | 
				
			||||||
 | 
						if (container_is_fullscreen_or_child(cont)) {
 | 
				
			||||||
 | 
							seat_pointer_notify_button(seat, time_msec, button, state);
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						struct sway_container *floater = cont;
 | 
				
			||||||
 | 
						while (floater->parent->layout != L_FLOATING) {
 | 
				
			||||||
 | 
							floater = floater->parent;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat->wlr_seat);
 | 
				
			||||||
 | 
						bool mod_pressed = keyboard &&
 | 
				
			||||||
 | 
							(wlr_keyboard_get_modifiers(keyboard) & config->floating_mod);
 | 
				
			||||||
 | 
						enum wlr_edges edge = find_resize_edge(floater, cursor);
 | 
				
			||||||
 | 
						bool over_title = edge == WLR_EDGE_NONE && !surface;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Check for beginning move
 | 
				
			||||||
 | 
						uint32_t btn_move = config->floating_mod_inverse ? BTN_RIGHT : BTN_LEFT;
 | 
				
			||||||
 | 
						if (button == btn_move && state == WLR_BUTTON_PRESSED &&
 | 
				
			||||||
 | 
								(mod_pressed || over_title)) {
 | 
				
			||||||
 | 
							seat_begin_move(seat, floater, button);
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Check for beginning resize
 | 
				
			||||||
 | 
						bool resizing_via_border = button == BTN_LEFT && edge != WLR_EDGE_NONE;
 | 
				
			||||||
 | 
						uint32_t btn_resize = config->floating_mod_inverse ? BTN_LEFT : BTN_RIGHT;
 | 
				
			||||||
 | 
						bool resizing_via_mod = button == btn_resize && mod_pressed;
 | 
				
			||||||
 | 
						if ((resizing_via_border || resizing_via_mod) &&
 | 
				
			||||||
 | 
								state == WLR_BUTTON_PRESSED) {
 | 
				
			||||||
 | 
							if (edge == WLR_EDGE_NONE) {
 | 
				
			||||||
 | 
								edge |= cursor->cursor->x > floater->x + floater->width / 2 ?
 | 
				
			||||||
 | 
									WLR_EDGE_RIGHT : WLR_EDGE_LEFT;
 | 
				
			||||||
 | 
								edge |= cursor->cursor->y > floater->y + floater->height / 2 ?
 | 
				
			||||||
 | 
									WLR_EDGE_BOTTOM : WLR_EDGE_TOP;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							seat_begin_resize(seat, floater, button, edge);
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Send event to surface
 | 
				
			||||||
 | 
						seat_set_focus(seat, cont);
 | 
				
			||||||
 | 
						seat_pointer_notify_button(seat, time_msec, button, state);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Remove a button (and duplicates) to the sorted list of currently pressed buttons
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static void state_erase_button(struct sway_cursor *cursor, uint32_t button) {
 | 
				
			||||||
 | 
						size_t j = 0;
 | 
				
			||||||
 | 
						for (size_t i = 0; i < cursor->pressed_button_count; ++i) {
 | 
				
			||||||
 | 
							if (i > j) {
 | 
				
			||||||
 | 
								cursor->pressed_buttons[j] = cursor->pressed_buttons[i];
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (cursor->pressed_buttons[i] != button) {
 | 
				
			||||||
 | 
								++j;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						while (cursor->pressed_button_count > j) {
 | 
				
			||||||
 | 
							--cursor->pressed_button_count;
 | 
				
			||||||
 | 
							cursor->pressed_buttons[cursor->pressed_button_count] = 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Add a button to the sorted list of currently pressed buttons, if there
 | 
				
			||||||
 | 
					 * is space.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static void state_add_button(struct sway_cursor *cursor, uint32_t button) {
 | 
				
			||||||
 | 
						if (cursor->pressed_button_count >= SWAY_CURSOR_PRESSED_BUTTONS_CAP) {
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						size_t i = 0;
 | 
				
			||||||
 | 
						while (i < cursor->pressed_button_count && cursor->pressed_buttons[i] < button) {
 | 
				
			||||||
 | 
							++i;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						size_t j = cursor->pressed_button_count;
 | 
				
			||||||
 | 
						while (j > i) {
 | 
				
			||||||
 | 
							cursor->pressed_buttons[j] = cursor->pressed_buttons[j - 1];
 | 
				
			||||||
 | 
							--j;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						cursor->pressed_buttons[i] = button;
 | 
				
			||||||
 | 
						cursor->pressed_button_count++;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Return the mouse binding which matches modifier, click location, release,
 | 
				
			||||||
 | 
					 * and pressed button state, otherwise return null.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static struct sway_binding* get_active_mouse_binding(const struct sway_cursor *cursor,
 | 
				
			||||||
 | 
							list_t *bindings, uint32_t modifiers, bool release, bool on_titlebar,
 | 
				
			||||||
 | 
									     bool on_border, bool on_content) {
 | 
				
			||||||
 | 
						uint32_t click_region = (on_titlebar ? BINDING_TITLEBAR : 0) |
 | 
				
			||||||
 | 
								(on_border ? BINDING_BORDER : 0) |
 | 
				
			||||||
 | 
								(on_content ? BINDING_CONTENTS : 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (int i = 0; i < bindings->length; ++i) {
 | 
				
			||||||
 | 
							struct sway_binding *binding = bindings->items[i];
 | 
				
			||||||
 | 
							if (modifiers ^ binding->modifiers ||
 | 
				
			||||||
 | 
									cursor->pressed_button_count != (size_t)binding->keys->length ||
 | 
				
			||||||
 | 
									release != (binding->flags & BINDING_RELEASE) ||
 | 
				
			||||||
 | 
									!(click_region & binding->flags)) {
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							bool match = true;
 | 
				
			||||||
 | 
							for (size_t j = 0; j < cursor->pressed_button_count; j++) {
 | 
				
			||||||
 | 
								uint32_t key = *(uint32_t *)binding->keys->items[j];
 | 
				
			||||||
 | 
								if (key != cursor->pressed_buttons[j]) {
 | 
				
			||||||
 | 
									match = false;
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (!match) {
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return binding;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void dispatch_cursor_button(struct sway_cursor *cursor,
 | 
					void dispatch_cursor_button(struct sway_cursor *cursor,
 | 
				
			||||||
		uint32_t time_msec, uint32_t button, enum wlr_button_state state) {
 | 
							uint32_t time_msec, uint32_t button, enum wlr_button_state state) {
 | 
				
			||||||
 | 
						if (cursor->seat->operation != OP_NONE &&
 | 
				
			||||||
 | 
								button == cursor->seat->op_button && state == WLR_BUTTON_RELEASED) {
 | 
				
			||||||
 | 
							seat_end_mouse_operation(cursor->seat);
 | 
				
			||||||
 | 
							seat_pointer_notify_button(cursor->seat, time_msec, button, state);
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	if (time_msec == 0) {
 | 
						if (time_msec == 0) {
 | 
				
			||||||
		time_msec = get_current_time_msec();
 | 
							time_msec = get_current_time_msec();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -253,12 +567,41 @@ void dispatch_cursor_button(struct sway_cursor *cursor,
 | 
				
			||||||
	double sx, sy;
 | 
						double sx, sy;
 | 
				
			||||||
	struct sway_container *cont = container_at_coords(cursor->seat,
 | 
						struct sway_container *cont = container_at_coords(cursor->seat,
 | 
				
			||||||
			cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy);
 | 
								cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Handle mouse bindings
 | 
				
			||||||
 | 
						bool on_border = cont && (find_resize_edge(cont, cursor) != WLR_EDGE_NONE);
 | 
				
			||||||
 | 
						bool on_contents = !on_border && surface;
 | 
				
			||||||
 | 
						bool on_titlebar = !on_border && !surface;
 | 
				
			||||||
 | 
						struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(cursor->seat->wlr_seat);
 | 
				
			||||||
 | 
						uint32_t modifiers = keyboard ? wlr_keyboard_get_modifiers(keyboard) : 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct sway_binding *binding = NULL;
 | 
				
			||||||
 | 
						if (state == WLR_BUTTON_PRESSED) {
 | 
				
			||||||
 | 
							state_add_button(cursor, button);
 | 
				
			||||||
 | 
							binding = get_active_mouse_binding(cursor,
 | 
				
			||||||
 | 
								config->current_mode->mouse_bindings, modifiers, false,
 | 
				
			||||||
 | 
								on_titlebar, on_border, on_contents);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							binding = get_active_mouse_binding(cursor,
 | 
				
			||||||
 | 
								config->current_mode->mouse_bindings, modifiers, true,
 | 
				
			||||||
 | 
								on_titlebar, on_border, on_contents);
 | 
				
			||||||
 | 
							state_erase_button(cursor, button);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (binding) {
 | 
				
			||||||
 | 
							seat_execute_command(cursor->seat, binding);
 | 
				
			||||||
 | 
							// TODO: do we want to pass on the event?
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (surface && wlr_surface_is_layer_surface(surface)) {
 | 
						if (surface && wlr_surface_is_layer_surface(surface)) {
 | 
				
			||||||
		struct wlr_layer_surface *layer =
 | 
							struct wlr_layer_surface *layer =
 | 
				
			||||||
			wlr_layer_surface_from_wlr_surface(surface);
 | 
								wlr_layer_surface_from_wlr_surface(surface);
 | 
				
			||||||
		if (layer->current.keyboard_interactive) {
 | 
							if (layer->current.keyboard_interactive) {
 | 
				
			||||||
			seat_set_focus_layer(cursor->seat, layer);
 | 
								seat_set_focus_layer(cursor->seat, layer);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							seat_pointer_notify_button(cursor->seat, time_msec, button, state);
 | 
				
			||||||
 | 
						} else if (cont && container_is_floating_or_child(cont)) {
 | 
				
			||||||
 | 
							dispatch_cursor_button_floating(cursor, time_msec, button, state,
 | 
				
			||||||
 | 
									surface, sx, sy, cont);
 | 
				
			||||||
	} else if (surface && cont && cont->type != C_VIEW) {
 | 
						} else if (surface && cont && cont->type != C_VIEW) {
 | 
				
			||||||
		// Avoid moving keyboard focus from a surface that accepts it to one
 | 
							// Avoid moving keyboard focus from a surface that accepts it to one
 | 
				
			||||||
		// that does not unless the change would move us to a new workspace.
 | 
							// that does not unless the change would move us to a new workspace.
 | 
				
			||||||
| 
						 | 
					@ -275,12 +618,14 @@ void dispatch_cursor_button(struct sway_cursor *cursor,
 | 
				
			||||||
		if (new_ws != old_ws) {
 | 
							if (new_ws != old_ws) {
 | 
				
			||||||
			seat_set_focus(cursor->seat, cont);
 | 
								seat_set_focus(cursor->seat, cont);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							seat_pointer_notify_button(cursor->seat, time_msec, button, state);
 | 
				
			||||||
	} else if (cont) {
 | 
						} else if (cont) {
 | 
				
			||||||
		seat_set_focus(cursor->seat, cont);
 | 
							seat_set_focus(cursor->seat, cont);
 | 
				
			||||||
 | 
							seat_pointer_notify_button(cursor->seat, time_msec, button, state);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							seat_pointer_notify_button(cursor->seat, time_msec, button, state);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wlr_seat_pointer_notify_button(cursor->seat->wlr_seat,
 | 
					 | 
				
			||||||
			time_msec, button, state);
 | 
					 | 
				
			||||||
	transaction_commit_dirty();
 | 
						transaction_commit_dirty();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -467,6 +812,9 @@ static void handle_request_set_cursor(struct wl_listener *listener,
 | 
				
			||||||
		void *data) {
 | 
							void *data) {
 | 
				
			||||||
	struct sway_cursor *cursor =
 | 
						struct sway_cursor *cursor =
 | 
				
			||||||
		wl_container_of(listener, cursor, request_set_cursor);
 | 
							wl_container_of(listener, cursor, request_set_cursor);
 | 
				
			||||||
 | 
						if (cursor->seat->operation != OP_NONE) {
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	struct wlr_seat_pointer_request_set_cursor_event *event = data;
 | 
						struct wlr_seat_pointer_request_set_cursor_event *event = data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wl_client *focused_client = NULL;
 | 
						struct wl_client *focused_client = NULL;
 | 
				
			||||||
| 
						 | 
					@ -485,9 +833,20 @@ static void handle_request_set_cursor(struct wl_listener *listener,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wlr_cursor_set_surface(cursor->cursor, event->surface, event->hotspot_x,
 | 
						wlr_cursor_set_surface(cursor->cursor, event->surface, event->hotspot_x,
 | 
				
			||||||
		event->hotspot_y);
 | 
							event->hotspot_y);
 | 
				
			||||||
 | 
						cursor->image = NULL;
 | 
				
			||||||
	cursor->image_client = focused_client;
 | 
						cursor->image_client = focused_client;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void cursor_set_image(struct sway_cursor *cursor, const char *image,
 | 
				
			||||||
 | 
							struct wl_client *client) {
 | 
				
			||||||
 | 
						if (!cursor->image || strcmp(cursor->image, image) != 0) {
 | 
				
			||||||
 | 
							wlr_xcursor_manager_set_cursor_image(cursor->xcursor_manager, image,
 | 
				
			||||||
 | 
									cursor->cursor);
 | 
				
			||||||
 | 
							cursor->image = image;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						cursor->image_client = client;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void sway_cursor_destroy(struct sway_cursor *cursor) {
 | 
					void sway_cursor_destroy(struct sway_cursor *cursor) {
 | 
				
			||||||
	if (!cursor) {
 | 
						if (!cursor) {
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,6 +8,7 @@
 | 
				
			||||||
#include <math.h>
 | 
					#include <math.h>
 | 
				
			||||||
#include <wlr/backend/libinput.h>
 | 
					#include <wlr/backend/libinput.h>
 | 
				
			||||||
#include <wlr/types/wlr_input_inhibitor.h>
 | 
					#include <wlr/types/wlr_input_inhibitor.h>
 | 
				
			||||||
 | 
					#include <wlr/types/wlr_virtual_keyboard_v1.h>
 | 
				
			||||||
#include "sway/config.h"
 | 
					#include "sway/config.h"
 | 
				
			||||||
#include "sway/input/input-manager.h"
 | 
					#include "sway/input/input-manager.h"
 | 
				
			||||||
#include "sway/input/seat.h"
 | 
					#include "sway/input/seat.h"
 | 
				
			||||||
| 
						 | 
					@ -303,6 +304,35 @@ static void handle_inhibit_deactivate(struct wl_listener *listener, void *data)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void handle_virtual_keyboard(struct wl_listener *listener, void *data) {
 | 
				
			||||||
 | 
						struct sway_input_manager *input_manager =
 | 
				
			||||||
 | 
							wl_container_of(listener, input_manager, virtual_keyboard_new);
 | 
				
			||||||
 | 
						struct wlr_virtual_keyboard_v1 *keyboard = data;
 | 
				
			||||||
 | 
						struct wlr_input_device *device = &keyboard->input_device;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct sway_seat *seat = input_manager_get_default_seat(input_manager);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// TODO: The user might want this on a different seat
 | 
				
			||||||
 | 
						struct sway_input_device *input_device =
 | 
				
			||||||
 | 
							calloc(1, sizeof(struct sway_input_device));
 | 
				
			||||||
 | 
						if (!sway_assert(input_device, "could not allocate input device")) {
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						device->data = input_device;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						input_device->wlr_device = device;
 | 
				
			||||||
 | 
						input_device->identifier = get_device_identifier(device);
 | 
				
			||||||
 | 
						wl_list_insert(&input_manager->devices, &input_device->link);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wlr_log(WLR_DEBUG, "adding virtual keyboard: '%s'",
 | 
				
			||||||
 | 
							input_device->identifier);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wl_signal_add(&device->events.destroy, &input_device->device_destroy);
 | 
				
			||||||
 | 
						input_device->device_destroy.notify = handle_device_destroy;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						seat_add_device(seat, input_device);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct sway_input_manager *input_manager_create(
 | 
					struct sway_input_manager *input_manager_create(
 | 
				
			||||||
		struct sway_server *server) {
 | 
							struct sway_server *server) {
 | 
				
			||||||
	struct sway_input_manager *input =
 | 
						struct sway_input_manager *input =
 | 
				
			||||||
| 
						 | 
					@ -321,6 +351,12 @@ struct sway_input_manager *input_manager_create(
 | 
				
			||||||
	input->new_input.notify = handle_new_input;
 | 
						input->new_input.notify = handle_new_input;
 | 
				
			||||||
	wl_signal_add(&server->backend->events.new_input, &input->new_input);
 | 
						wl_signal_add(&server->backend->events.new_input, &input->new_input);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						input->virtual_keyboard = wlr_virtual_keyboard_manager_v1_create(
 | 
				
			||||||
 | 
							server->wl_display);
 | 
				
			||||||
 | 
						wl_signal_add(&input->virtual_keyboard->events.new_virtual_keyboard,
 | 
				
			||||||
 | 
							&input->virtual_keyboard_new);
 | 
				
			||||||
 | 
						input->virtual_keyboard_new.notify = handle_virtual_keyboard;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	input->inhibit = wlr_input_inhibit_manager_create(server->wl_display);
 | 
						input->inhibit = wlr_input_inhibit_manager_create(server->wl_display);
 | 
				
			||||||
	input->inhibit_activate.notify = handle_inhibit_activate;
 | 
						input->inhibit_activate.notify = handle_inhibit_activate;
 | 
				
			||||||
	wl_signal_add(&input->inhibit->events.activate,
 | 
						wl_signal_add(&input->inhibit->events.activate,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,11 +3,12 @@
 | 
				
			||||||
#include <wlr/backend/multi.h>
 | 
					#include <wlr/backend/multi.h>
 | 
				
			||||||
#include <wlr/backend/session.h>
 | 
					#include <wlr/backend/session.h>
 | 
				
			||||||
#include <wlr/types/wlr_idle.h>
 | 
					#include <wlr/types/wlr_idle.h>
 | 
				
			||||||
#include "sway/desktop/transaction.h"
 | 
					#include <wlr/interfaces/wlr_keyboard.h>
 | 
				
			||||||
#include "sway/input/seat.h"
 | 
					 | 
				
			||||||
#include "sway/input/keyboard.h"
 | 
					 | 
				
			||||||
#include "sway/input/input-manager.h"
 | 
					 | 
				
			||||||
#include "sway/commands.h"
 | 
					#include "sway/commands.h"
 | 
				
			||||||
 | 
					#include "sway/desktop/transaction.h"
 | 
				
			||||||
 | 
					#include "sway/input/input-manager.h"
 | 
				
			||||||
 | 
					#include "sway/input/keyboard.h"
 | 
				
			||||||
 | 
					#include "sway/input/seat.h"
 | 
				
			||||||
#include "log.h"
 | 
					#include "log.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
| 
						 | 
					@ -88,11 +89,13 @@ static void get_active_binding(const struct sway_shortcut_state *state,
 | 
				
			||||||
		uint32_t modifiers, bool release, bool locked) {
 | 
							uint32_t modifiers, bool release, bool locked) {
 | 
				
			||||||
	for (int i = 0; i < bindings->length; ++i) {
 | 
						for (int i = 0; i < bindings->length; ++i) {
 | 
				
			||||||
		struct sway_binding *binding = bindings->items[i];
 | 
							struct sway_binding *binding = bindings->items[i];
 | 
				
			||||||
 | 
							bool binding_locked = binding->flags & BINDING_LOCKED;
 | 
				
			||||||
 | 
							bool binding_release = binding->flags & BINDING_RELEASE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (modifiers ^ binding->modifiers ||
 | 
							if (modifiers ^ binding->modifiers ||
 | 
				
			||||||
				state->npressed != (size_t)binding->keys->length ||
 | 
									state->npressed != (size_t)binding->keys->length ||
 | 
				
			||||||
				locked > binding->locked ||
 | 
									release != binding_release ||
 | 
				
			||||||
				release != binding->release) {
 | 
									locked > binding_locked) {
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -118,23 +121,6 @@ static void get_active_binding(const struct sway_shortcut_state *state,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Execute the command associated to a binding
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
static void keyboard_execute_command(struct sway_keyboard *keyboard,
 | 
					 | 
				
			||||||
		struct sway_binding *binding) {
 | 
					 | 
				
			||||||
	wlr_log(WLR_DEBUG, "running command for binding: %s",
 | 
					 | 
				
			||||||
		binding->command);
 | 
					 | 
				
			||||||
	config->handler_context.seat = keyboard->seat_device->sway_seat;
 | 
					 | 
				
			||||||
	struct cmd_results *results = execute_command(binding->command, NULL);
 | 
					 | 
				
			||||||
	transaction_commit_dirty();
 | 
					 | 
				
			||||||
	if (results->status != CMD_SUCCESS) {
 | 
					 | 
				
			||||||
		wlr_log(WLR_DEBUG, "could not run command for binding: %s (%s)",
 | 
					 | 
				
			||||||
			binding->command, results->error);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	free_cmd_results(results);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Execute a built-in, hardcoded compositor binding. These are triggered from a
 | 
					 * Execute a built-in, hardcoded compositor binding. These are triggered from a
 | 
				
			||||||
 * single keysym.
 | 
					 * single keysym.
 | 
				
			||||||
| 
						 | 
					@ -211,12 +197,13 @@ static size_t keyboard_keysyms_raw(struct sway_keyboard *keyboard,
 | 
				
			||||||
static void handle_keyboard_key(struct wl_listener *listener, void *data) {
 | 
					static void handle_keyboard_key(struct wl_listener *listener, void *data) {
 | 
				
			||||||
	struct sway_keyboard *keyboard =
 | 
						struct sway_keyboard *keyboard =
 | 
				
			||||||
		wl_container_of(listener, keyboard, keyboard_key);
 | 
							wl_container_of(listener, keyboard, keyboard_key);
 | 
				
			||||||
	struct wlr_seat *wlr_seat = keyboard->seat_device->sway_seat->wlr_seat;
 | 
						struct sway_seat* seat = keyboard->seat_device->sway_seat;
 | 
				
			||||||
 | 
						struct wlr_seat *wlr_seat = seat->wlr_seat;
 | 
				
			||||||
	struct wlr_input_device *wlr_device =
 | 
						struct wlr_input_device *wlr_device =
 | 
				
			||||||
		keyboard->seat_device->input_device->wlr_device;
 | 
							keyboard->seat_device->input_device->wlr_device;
 | 
				
			||||||
	wlr_idle_notify_activity(keyboard->seat_device->sway_seat->input->server->idle, wlr_seat);
 | 
						wlr_idle_notify_activity(seat->input->server->idle, wlr_seat);
 | 
				
			||||||
	struct wlr_event_keyboard_key *event = data;
 | 
						struct wlr_event_keyboard_key *event = data;
 | 
				
			||||||
	bool input_inhibited = keyboard->seat_device->sway_seat->exclusive_client != NULL;
 | 
						bool input_inhibited = seat->exclusive_client != NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Identify new keycode, raw keysym(s), and translated keysym(s)
 | 
						// Identify new keycode, raw keysym(s), and translated keysym(s)
 | 
				
			||||||
	xkb_keycode_t keycode = event->keycode + 8;
 | 
						xkb_keycode_t keycode = event->keycode + 8;
 | 
				
			||||||
| 
						 | 
					@ -266,7 +253,7 @@ static void handle_keyboard_key(struct wl_listener *listener, void *data) {
 | 
				
			||||||
	// Execute stored release binding once no longer active
 | 
						// Execute stored release binding once no longer active
 | 
				
			||||||
	if (keyboard->held_binding && binding_released != keyboard->held_binding &&
 | 
						if (keyboard->held_binding && binding_released != keyboard->held_binding &&
 | 
				
			||||||
			event->state == WLR_KEY_RELEASED) {
 | 
								event->state == WLR_KEY_RELEASED) {
 | 
				
			||||||
		keyboard_execute_command(keyboard, keyboard->held_binding);
 | 
							seat_execute_command(seat, keyboard->held_binding);
 | 
				
			||||||
		handled = true;
 | 
							handled = true;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (binding_released != keyboard->held_binding) {
 | 
						if (binding_released != keyboard->held_binding) {
 | 
				
			||||||
| 
						 | 
					@ -277,6 +264,7 @@ static void handle_keyboard_key(struct wl_listener *listener, void *data) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Identify and execute active pressed binding
 | 
						// Identify and execute active pressed binding
 | 
				
			||||||
 | 
						struct sway_binding *next_repeat_binding = NULL;
 | 
				
			||||||
	if (event->state == WLR_KEY_PRESSED) {
 | 
						if (event->state == WLR_KEY_PRESSED) {
 | 
				
			||||||
		struct sway_binding *binding_pressed = NULL;
 | 
							struct sway_binding *binding_pressed = NULL;
 | 
				
			||||||
		get_active_binding(&keyboard->state_keycodes,
 | 
							get_active_binding(&keyboard->state_keycodes,
 | 
				
			||||||
| 
						 | 
					@ -290,8 +278,23 @@ static void handle_keyboard_key(struct wl_listener *listener, void *data) {
 | 
				
			||||||
				raw_modifiers, false, input_inhibited);
 | 
									raw_modifiers, false, input_inhibited);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (binding_pressed) {
 | 
							if (binding_pressed) {
 | 
				
			||||||
			keyboard_execute_command(keyboard, binding_pressed);
 | 
								seat_execute_command(seat, binding_pressed);
 | 
				
			||||||
			handled = true;
 | 
								handled = true;
 | 
				
			||||||
 | 
								next_repeat_binding = binding_pressed;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Set up (or clear) keyboard repeat for a pressed binding
 | 
				
			||||||
 | 
						if (next_repeat_binding && wlr_device->keyboard->repeat_info.delay > 0) {
 | 
				
			||||||
 | 
							keyboard->repeat_binding = next_repeat_binding;
 | 
				
			||||||
 | 
							if (wl_event_source_timer_update(keyboard->key_repeat_source,
 | 
				
			||||||
 | 
									wlr_device->keyboard->repeat_info.delay) < 0) {
 | 
				
			||||||
 | 
								wlr_log(WLR_DEBUG, "failed to set key repeat timer");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else if (keyboard->repeat_binding) {
 | 
				
			||||||
 | 
							keyboard->repeat_binding = NULL;
 | 
				
			||||||
 | 
							if (wl_event_source_timer_update(keyboard->key_repeat_source, 0) < 0) {
 | 
				
			||||||
 | 
								wlr_log(WLR_DEBUG, "failed to disarm key repeat timer");
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -312,6 +315,28 @@ static void handle_keyboard_key(struct wl_listener *listener, void *data) {
 | 
				
			||||||
		wlr_seat_keyboard_notify_key(wlr_seat, event->time_msec,
 | 
							wlr_seat_keyboard_notify_key(wlr_seat, event->time_msec,
 | 
				
			||||||
				event->keycode, event->state);
 | 
									event->keycode, event->state);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						transaction_commit_dirty();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int handle_keyboard_repeat(void *data) {
 | 
				
			||||||
 | 
						struct sway_keyboard *keyboard = (struct sway_keyboard *)data;
 | 
				
			||||||
 | 
						struct wlr_keyboard *wlr_device =
 | 
				
			||||||
 | 
								keyboard->seat_device->input_device->wlr_device->keyboard;
 | 
				
			||||||
 | 
						if (keyboard->repeat_binding) {
 | 
				
			||||||
 | 
							if (wlr_device->repeat_info.rate > 0) {
 | 
				
			||||||
 | 
								// We queue the next event first, as the command might cancel it
 | 
				
			||||||
 | 
								if (wl_event_source_timer_update(keyboard->key_repeat_source,
 | 
				
			||||||
 | 
										1000 / wlr_device->repeat_info.rate) < 0) {
 | 
				
			||||||
 | 
									wlr_log(WLR_DEBUG, "failed to update key repeat timer");
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							seat_execute_command(keyboard->seat_device->sway_seat,
 | 
				
			||||||
 | 
									keyboard->repeat_binding);
 | 
				
			||||||
 | 
							transaction_commit_dirty();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void handle_keyboard_modifiers(struct wl_listener *listener,
 | 
					static void handle_keyboard_modifiers(struct wl_listener *listener,
 | 
				
			||||||
| 
						 | 
					@ -339,6 +364,9 @@ struct sway_keyboard *sway_keyboard_create(struct sway_seat *seat,
 | 
				
			||||||
	wl_list_init(&keyboard->keyboard_key.link);
 | 
						wl_list_init(&keyboard->keyboard_key.link);
 | 
				
			||||||
	wl_list_init(&keyboard->keyboard_modifiers.link);
 | 
						wl_list_init(&keyboard->keyboard_modifiers.link);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						keyboard->key_repeat_source = wl_event_loop_add_timer(server.wl_event_loop,
 | 
				
			||||||
 | 
								handle_keyboard_repeat, keyboard);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return keyboard;
 | 
						return keyboard;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -397,6 +425,31 @@ void sway_keyboard_configure(struct sway_keyboard *keyboard) {
 | 
				
			||||||
	keyboard->keymap = keymap;
 | 
						keyboard->keymap = keymap;
 | 
				
			||||||
	wlr_keyboard_set_keymap(wlr_device->keyboard, keyboard->keymap);
 | 
						wlr_keyboard_set_keymap(wlr_device->keyboard, keyboard->keymap);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						xkb_mod_mask_t locked_mods = 0;
 | 
				
			||||||
 | 
						if (input_config && input_config->xkb_numlock > 0) {
 | 
				
			||||||
 | 
							xkb_mod_index_t mod_index = xkb_map_mod_get_index(keymap, XKB_MOD_NAME_NUM);
 | 
				
			||||||
 | 
							if (mod_index != XKB_MOD_INVALID) {
 | 
				
			||||||
 | 
							       locked_mods |= (uint32_t)1 << mod_index;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (input_config && input_config->xkb_capslock > 0) {
 | 
				
			||||||
 | 
							xkb_mod_index_t mod_index = xkb_map_mod_get_index(keymap, XKB_MOD_NAME_CAPS);
 | 
				
			||||||
 | 
							if (mod_index != XKB_MOD_INVALID) {
 | 
				
			||||||
 | 
							       locked_mods |= (uint32_t)1 << mod_index;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (locked_mods) {
 | 
				
			||||||
 | 
							wlr_keyboard_notify_modifiers(wlr_device->keyboard, 0, 0, locked_mods, 0);
 | 
				
			||||||
 | 
							uint32_t leds = 0;
 | 
				
			||||||
 | 
							for (uint32_t i = 0; i < WLR_LED_COUNT; ++i) {
 | 
				
			||||||
 | 
								if (xkb_state_led_index_is_active(wlr_device->keyboard->xkb_state,
 | 
				
			||||||
 | 
										wlr_device->keyboard->led_indexes[i])) {
 | 
				
			||||||
 | 
									leds |= (1 << i);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							wlr_keyboard_led_update(wlr_device->keyboard, leds);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (input_config && input_config->repeat_delay != INT_MIN
 | 
						if (input_config && input_config->repeat_delay != INT_MIN
 | 
				
			||||||
			&& input_config->repeat_rate != INT_MIN) {
 | 
								&& input_config->repeat_rate != INT_MIN) {
 | 
				
			||||||
		wlr_keyboard_set_repeat_info(wlr_device->keyboard,
 | 
							wlr_keyboard_set_repeat_info(wlr_device->keyboard,
 | 
				
			||||||
| 
						 | 
					@ -427,5 +480,6 @@ void sway_keyboard_destroy(struct sway_keyboard *keyboard) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	wl_list_remove(&keyboard->keyboard_key.link);
 | 
						wl_list_remove(&keyboard->keyboard_key.link);
 | 
				
			||||||
	wl_list_remove(&keyboard->keyboard_modifiers.link);
 | 
						wl_list_remove(&keyboard->keyboard_modifiers.link);
 | 
				
			||||||
 | 
						wl_event_source_remove(keyboard->key_repeat_source);
 | 
				
			||||||
	free(keyboard);
 | 
						free(keyboard);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,12 +1,19 @@
 | 
				
			||||||
#define _XOPEN_SOURCE 700
 | 
					#define _XOPEN_SOURCE 700
 | 
				
			||||||
#define _POSIX_C_SOURCE 199309L
 | 
					#define _POSIX_C_SOURCE 199309L
 | 
				
			||||||
#include <assert.h>
 | 
					#include <assert.h>
 | 
				
			||||||
 | 
					#include <errno.h>
 | 
				
			||||||
 | 
					#ifdef __linux__
 | 
				
			||||||
 | 
					#include <linux/input-event-codes.h>
 | 
				
			||||||
 | 
					#elif __FreeBSD__
 | 
				
			||||||
 | 
					#include <dev/evdev/input-event-codes.h>
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
#include <strings.h>
 | 
					#include <strings.h>
 | 
				
			||||||
#include <time.h>
 | 
					#include <time.h>
 | 
				
			||||||
#include <wlr/types/wlr_cursor.h>
 | 
					#include <wlr/types/wlr_cursor.h>
 | 
				
			||||||
#include <wlr/types/wlr_output_layout.h>
 | 
					#include <wlr/types/wlr_output_layout.h>
 | 
				
			||||||
#include <wlr/types/wlr_xcursor_manager.h>
 | 
					#include <wlr/types/wlr_xcursor_manager.h>
 | 
				
			||||||
#include "log.h"
 | 
					#include "log.h"
 | 
				
			||||||
 | 
					#include "config.h"
 | 
				
			||||||
#include "sway/debug.h"
 | 
					#include "sway/debug.h"
 | 
				
			||||||
#include "sway/desktop.h"
 | 
					#include "sway/desktop.h"
 | 
				
			||||||
#include "sway/input/cursor.h"
 | 
					#include "sway/input/cursor.h"
 | 
				
			||||||
| 
						 | 
					@ -98,11 +105,13 @@ static void seat_send_focus(struct sway_container *con,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (con->type == C_VIEW
 | 
						if (con->type == C_VIEW
 | 
				
			||||||
			&& seat_is_input_allowed(seat, con->sway_view->surface)) {
 | 
								&& seat_is_input_allowed(seat, con->sway_view->surface)) {
 | 
				
			||||||
 | 
					#ifdef HAVE_XWAYLAND
 | 
				
			||||||
		if (con->sway_view->type == SWAY_VIEW_XWAYLAND) {
 | 
							if (con->sway_view->type == SWAY_VIEW_XWAYLAND) {
 | 
				
			||||||
			struct wlr_xwayland *xwayland =
 | 
								struct wlr_xwayland *xwayland =
 | 
				
			||||||
				seat->input->server->xwayland.wlr_xwayland;
 | 
									seat->input->server->xwayland.wlr_xwayland;
 | 
				
			||||||
			wlr_xwayland_set_seat(xwayland, seat->wlr_seat);
 | 
								wlr_xwayland_set_seat(xwayland, seat->wlr_seat);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
		struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat->wlr_seat);
 | 
							struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat->wlr_seat);
 | 
				
			||||||
		if (keyboard) {
 | 
							if (keyboard) {
 | 
				
			||||||
			wlr_seat_keyboard_notify_enter(seat->wlr_seat,
 | 
								wlr_seat_keyboard_notify_enter(seat->wlr_seat,
 | 
				
			||||||
| 
						 | 
					@ -116,12 +125,14 @@ static void seat_send_focus(struct sway_container *con,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct sway_container *seat_get_focus_by_type(struct sway_seat *seat,
 | 
					static struct sway_container *seat_get_focus_by_type(struct sway_seat *seat,
 | 
				
			||||||
		struct sway_container *container, enum sway_container_type type) {
 | 
							struct sway_container *container, enum sway_container_type type,
 | 
				
			||||||
 | 
							bool only_tiling) {
 | 
				
			||||||
	if (container->type == C_VIEW) {
 | 
						if (container->type == C_VIEW) {
 | 
				
			||||||
		return container;
 | 
							return container;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct sway_container *floating = container->type == C_WORKSPACE ?
 | 
						struct sway_container *floating =
 | 
				
			||||||
 | 
							container->type == C_WORKSPACE && !only_tiling ?
 | 
				
			||||||
		container->sway_workspace->floating : NULL;
 | 
							container->sway_workspace->floating : NULL;
 | 
				
			||||||
	if (container->children->length == 0 &&
 | 
						if (container->children->length == 0 &&
 | 
				
			||||||
			(!floating || floating->children->length == 0)) {
 | 
								(!floating || floating->children->length == 0)) {
 | 
				
			||||||
| 
						 | 
					@ -135,6 +146,10 @@ static struct sway_container *seat_get_focus_by_type(struct sway_seat *seat,
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (container_has_child(container, current->container)) {
 | 
							if (container_has_child(container, current->container)) {
 | 
				
			||||||
 | 
								if (only_tiling &&
 | 
				
			||||||
 | 
										container_is_floating_or_child(current->container)) {
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			return current->container;
 | 
								return current->container;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if (floating && container_has_child(floating, current->container)) {
 | 
							if (floating && container_has_child(floating, current->container)) {
 | 
				
			||||||
| 
						 | 
					@ -161,7 +176,7 @@ void seat_focus_inactive_children_for_each(struct sway_seat *seat,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct sway_container *seat_get_focus_inactive_view(struct sway_seat *seat,
 | 
					struct sway_container *seat_get_focus_inactive_view(struct sway_seat *seat,
 | 
				
			||||||
		struct sway_container *container) {
 | 
							struct sway_container *container) {
 | 
				
			||||||
	return seat_get_focus_by_type(seat, container, C_VIEW);
 | 
						return seat_get_focus_by_type(seat, container, C_VIEW, false);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void handle_seat_container_destroy(struct wl_listener *listener,
 | 
					static void handle_seat_container_destroy(struct wl_listener *listener,
 | 
				
			||||||
| 
						 | 
					@ -183,7 +198,7 @@ static void handle_seat_container_destroy(struct wl_listener *listener,
 | 
				
			||||||
	if (set_focus) {
 | 
						if (set_focus) {
 | 
				
			||||||
		struct sway_container *next_focus = NULL;
 | 
							struct sway_container *next_focus = NULL;
 | 
				
			||||||
		while (next_focus == NULL) {
 | 
							while (next_focus == NULL) {
 | 
				
			||||||
			next_focus = seat_get_focus_by_type(seat, parent, C_VIEW);
 | 
								next_focus = seat_get_focus_by_type(seat, parent, C_VIEW, false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (next_focus == NULL && parent->type == C_WORKSPACE) {
 | 
								if (next_focus == NULL && parent->type == C_WORKSPACE) {
 | 
				
			||||||
				next_focus = parent;
 | 
									next_focus = parent;
 | 
				
			||||||
| 
						 | 
					@ -348,6 +363,7 @@ struct sway_seat *seat_create(struct sway_input_manager *input,
 | 
				
			||||||
		free(seat);
 | 
							free(seat);
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						seat->wlr_seat->data = seat;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	seat->cursor = sway_cursor_create(seat);
 | 
						seat->cursor = sway_cursor_create(seat);
 | 
				
			||||||
	if (!seat->cursor) {
 | 
						if (!seat->cursor) {
 | 
				
			||||||
| 
						 | 
					@ -377,7 +393,6 @@ struct sway_seat *seat_create(struct sway_input_manager *input,
 | 
				
			||||||
		WL_SEAT_CAPABILITY_POINTER |
 | 
							WL_SEAT_CAPABILITY_POINTER |
 | 
				
			||||||
		WL_SEAT_CAPABILITY_TOUCH);
 | 
							WL_SEAT_CAPABILITY_TOUCH);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	seat_configure_xcursor(seat);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wl_list_insert(&input->seats, &seat->link);
 | 
						wl_list_insert(&input->seats, &seat->link);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -422,6 +437,7 @@ static void seat_apply_input_config(struct sway_seat *seat,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void seat_configure_pointer(struct sway_seat *seat,
 | 
					static void seat_configure_pointer(struct sway_seat *seat,
 | 
				
			||||||
		struct sway_seat_device *sway_device) {
 | 
							struct sway_seat_device *sway_device) {
 | 
				
			||||||
 | 
						seat_configure_xcursor(seat);
 | 
				
			||||||
	wlr_cursor_attach_input_device(seat->cursor->cursor,
 | 
						wlr_cursor_attach_input_device(seat->cursor->cursor,
 | 
				
			||||||
		sway_device->input_device->wlr_device);
 | 
							sway_device->input_device->wlr_device);
 | 
				
			||||||
	seat_apply_input_config(seat, sway_device);
 | 
						seat_apply_input_config(seat, sway_device);
 | 
				
			||||||
| 
						 | 
					@ -601,7 +617,7 @@ static int handle_urgent_timeout(void *data) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void seat_set_focus_warp(struct sway_seat *seat,
 | 
					void seat_set_focus_warp(struct sway_seat *seat,
 | 
				
			||||||
		struct sway_container *container, bool warp) {
 | 
							struct sway_container *container, bool warp, bool notify) {
 | 
				
			||||||
	if (seat->focused_layer) {
 | 
						if (seat->focused_layer) {
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -622,7 +638,7 @@ void seat_set_focus_warp(struct sway_seat *seat,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (last_workspace && last_workspace == new_workspace
 | 
						if (last_workspace && last_workspace == new_workspace
 | 
				
			||||||
			&& last_workspace->sway_workspace->fullscreen
 | 
								&& last_workspace->sway_workspace->fullscreen
 | 
				
			||||||
			&& !container->sway_view->is_fullscreen) {
 | 
								&& container && !container_is_fullscreen_or_child(container)) {
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -639,7 +655,7 @@ void seat_set_focus_warp(struct sway_seat *seat,
 | 
				
			||||||
	struct sway_container *new_output_last_ws = NULL;
 | 
						struct sway_container *new_output_last_ws = NULL;
 | 
				
			||||||
	if (last_output && new_output && last_output != new_output) {
 | 
						if (last_output && new_output && last_output != new_output) {
 | 
				
			||||||
		new_output_last_ws =
 | 
							new_output_last_ws =
 | 
				
			||||||
			seat_get_focus_by_type(seat, new_output, C_WORKSPACE);
 | 
								seat_get_focus_by_type(seat, new_output, C_WORKSPACE, false);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (container && container->parent) {
 | 
						if (container && container->parent) {
 | 
				
			||||||
| 
						 | 
					@ -686,8 +702,14 @@ void seat_set_focus_warp(struct sway_seat *seat,
 | 
				
			||||||
				config->urgent_timeout > 0) {
 | 
									config->urgent_timeout > 0) {
 | 
				
			||||||
			view->urgent_timer = wl_event_loop_add_timer(server.wl_event_loop,
 | 
								view->urgent_timer = wl_event_loop_add_timer(server.wl_event_loop,
 | 
				
			||||||
					handle_urgent_timeout, view);
 | 
										handle_urgent_timeout, view);
 | 
				
			||||||
 | 
								if (view->urgent_timer) {
 | 
				
			||||||
				wl_event_source_timer_update(view->urgent_timer,
 | 
									wl_event_source_timer_update(view->urgent_timer,
 | 
				
			||||||
						config->urgent_timeout);
 | 
											config->urgent_timeout);
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									wlr_log(WLR_ERROR, "Unable to create urgency timer (%s)",
 | 
				
			||||||
 | 
											strerror(errno));
 | 
				
			||||||
 | 
									handle_urgent_timeout(view);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			view_set_urgent(view, false);
 | 
								view_set_urgent(view, false);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -715,9 +737,18 @@ void seat_set_focus_warp(struct sway_seat *seat,
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Close any popups on the old focus
 | 
				
			||||||
 | 
						if (last_focus && last_focus != container) {
 | 
				
			||||||
 | 
							if (last_focus->type == C_VIEW) {
 | 
				
			||||||
 | 
								view_close_popups(last_focus->sway_view);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (last_focus) {
 | 
						if (last_focus) {
 | 
				
			||||||
		if (last_workspace) {
 | 
							if (last_workspace) {
 | 
				
			||||||
			ipc_event_workspace(last_workspace, container, "focus");
 | 
								if (notify && last_workspace != new_workspace) {
 | 
				
			||||||
 | 
									 ipc_event_workspace(last_workspace, new_workspace, "focus");
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			if (!workspace_is_visible(last_workspace)
 | 
								if (!workspace_is_visible(last_workspace)
 | 
				
			||||||
					&& workspace_is_empty(last_workspace)) {
 | 
										&& workspace_is_empty(last_workspace)) {
 | 
				
			||||||
				if (last_workspace == last_focus) {
 | 
									if (last_workspace == last_focus) {
 | 
				
			||||||
| 
						 | 
					@ -744,8 +775,12 @@ void seat_set_focus_warp(struct sway_seat *seat,
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (last_focus != NULL) {
 | 
						if (container) {
 | 
				
			||||||
		cursor_send_pointer_motion(seat->cursor, 0, true);
 | 
							if (container->type == C_VIEW) {
 | 
				
			||||||
 | 
								ipc_event_window(container, "focus");
 | 
				
			||||||
 | 
							} else if (container->type == C_WORKSPACE) {
 | 
				
			||||||
 | 
								ipc_event_workspace(NULL, container, "focus");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	seat->has_focus = (container != NULL);
 | 
						seat->has_focus = (container != NULL);
 | 
				
			||||||
| 
						 | 
					@ -755,7 +790,7 @@ void seat_set_focus_warp(struct sway_seat *seat,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void seat_set_focus(struct sway_seat *seat,
 | 
					void seat_set_focus(struct sway_seat *seat,
 | 
				
			||||||
		struct sway_container *container) {
 | 
							struct sway_container *container) {
 | 
				
			||||||
	seat_set_focus_warp(seat, container, true);
 | 
						seat_set_focus_warp(seat, container, true, true);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void seat_set_focus_surface(struct sway_seat *seat,
 | 
					void seat_set_focus_surface(struct sway_seat *seat,
 | 
				
			||||||
| 
						 | 
					@ -848,7 +883,12 @@ void seat_set_exclusive_client(struct sway_seat *seat,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct sway_container *seat_get_focus_inactive(struct sway_seat *seat,
 | 
					struct sway_container *seat_get_focus_inactive(struct sway_seat *seat,
 | 
				
			||||||
		struct sway_container *container) {
 | 
							struct sway_container *container) {
 | 
				
			||||||
	return seat_get_focus_by_type(seat, container, C_TYPES);
 | 
						return seat_get_focus_by_type(seat, container, C_TYPES, false);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct sway_container *seat_get_focus_inactive_tiling(struct sway_seat *seat,
 | 
				
			||||||
 | 
							struct sway_container *container) {
 | 
				
			||||||
 | 
						return seat_get_focus_by_type(seat, container, C_TYPES, true);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct sway_container *seat_get_active_child(struct sway_seat *seat,
 | 
					struct sway_container *seat_get_active_child(struct sway_seat *seat,
 | 
				
			||||||
| 
						 | 
					@ -894,3 +934,68 @@ struct seat_config *seat_get_config(struct sway_seat *seat) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return NULL;
 | 
						return NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void seat_begin_move(struct sway_seat *seat, struct sway_container *con,
 | 
				
			||||||
 | 
							uint32_t button) {
 | 
				
			||||||
 | 
						if (!seat->cursor) {
 | 
				
			||||||
 | 
							wlr_log(WLR_DEBUG, "Ignoring move request due to no cursor device");
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						seat->operation = OP_MOVE;
 | 
				
			||||||
 | 
						seat->op_container = con;
 | 
				
			||||||
 | 
						seat->op_button = button;
 | 
				
			||||||
 | 
						cursor_set_image(seat->cursor, "grab", NULL);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void seat_begin_resize(struct sway_seat *seat, struct sway_container *con,
 | 
				
			||||||
 | 
							uint32_t button, enum wlr_edges edge) {
 | 
				
			||||||
 | 
						if (!seat->cursor) {
 | 
				
			||||||
 | 
							wlr_log(WLR_DEBUG, "Ignoring resize request due to no cursor device");
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat->wlr_seat);
 | 
				
			||||||
 | 
						seat->operation = OP_RESIZE;
 | 
				
			||||||
 | 
						seat->op_container = con;
 | 
				
			||||||
 | 
						seat->op_resize_preserve_ratio = keyboard &&
 | 
				
			||||||
 | 
							(wlr_keyboard_get_modifiers(keyboard) & WLR_MODIFIER_SHIFT);
 | 
				
			||||||
 | 
						seat->op_resize_edge = edge == WLR_EDGE_NONE ?
 | 
				
			||||||
 | 
							RESIZE_EDGE_BOTTOM | RESIZE_EDGE_RIGHT : edge;
 | 
				
			||||||
 | 
						seat->op_button = button;
 | 
				
			||||||
 | 
						seat->op_ref_lx = seat->cursor->cursor->x;
 | 
				
			||||||
 | 
						seat->op_ref_ly = seat->cursor->cursor->y;
 | 
				
			||||||
 | 
						seat->op_ref_con_lx = con->x;
 | 
				
			||||||
 | 
						seat->op_ref_con_ly = con->y;
 | 
				
			||||||
 | 
						seat->op_ref_width = con->width;
 | 
				
			||||||
 | 
						seat->op_ref_height = con->height;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						const char *image = edge == WLR_EDGE_NONE ?
 | 
				
			||||||
 | 
							"se-resize" : wlr_xcursor_get_resize_name(edge);
 | 
				
			||||||
 | 
						cursor_set_image(seat->cursor, image, NULL);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void seat_end_mouse_operation(struct sway_seat *seat) {
 | 
				
			||||||
 | 
						switch (seat->operation) {
 | 
				
			||||||
 | 
						case OP_MOVE:
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								// We "move" the container to its own location so it discovers its
 | 
				
			||||||
 | 
								// output again.
 | 
				
			||||||
 | 
								struct sway_container *con = seat->op_container;
 | 
				
			||||||
 | 
								container_floating_move_to(con, con->x, con->y);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						case OP_RESIZE:
 | 
				
			||||||
 | 
							// Don't need to do anything here.
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case OP_NONE:
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						seat->operation = OP_NONE;
 | 
				
			||||||
 | 
						seat->op_container = NULL;
 | 
				
			||||||
 | 
						cursor_set_image(seat->cursor, "left_ptr", NULL);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void seat_pointer_notify_button(struct sway_seat *seat, uint32_t time_msec,
 | 
				
			||||||
 | 
							uint32_t button, enum wlr_button_state state) {
 | 
				
			||||||
 | 
						seat->last_button = button;
 | 
				
			||||||
 | 
						seat->last_button_serial = wlr_seat_pointer_notify_button(seat->wlr_seat,
 | 
				
			||||||
 | 
								time_msec, button, state);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -201,6 +201,15 @@ static void ipc_json_describe_view(struct sway_container *c, json_object *object
 | 
				
			||||||
	bool urgent = c->type == C_VIEW ?
 | 
						bool urgent = c->type == C_VIEW ?
 | 
				
			||||||
		view_is_urgent(c->sway_view) : container_has_urgent_child(c);
 | 
							view_is_urgent(c->sway_view) : container_has_urgent_child(c);
 | 
				
			||||||
	json_object_object_add(object, "urgent", json_object_new_boolean(urgent));
 | 
						json_object_object_add(object, "urgent", json_object_new_boolean(urgent));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (c->type == C_VIEW) {
 | 
				
			||||||
 | 
							json_object *marks = json_object_new_array();
 | 
				
			||||||
 | 
							list_t *view_marks = c->sway_view->marks;
 | 
				
			||||||
 | 
							for (int i = 0; i < view_marks->length; ++i) {
 | 
				
			||||||
 | 
								json_object_array_add(marks, json_object_new_string(view_marks->items[i]));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							json_object_object_add(object, "marks", marks);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void focus_inactive_children_iterator(struct sway_container *c, void *data) {
 | 
					static void focus_inactive_children_iterator(struct sway_container *c, void *data) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,12 +3,18 @@
 | 
				
			||||||
// Any value will hide SOCK_CLOEXEC on FreeBSD (__BSD_VISIBLE=0)
 | 
					// Any value will hide SOCK_CLOEXEC on FreeBSD (__BSD_VISIBLE=0)
 | 
				
			||||||
#define _XOPEN_SOURCE 700
 | 
					#define _XOPEN_SOURCE 700
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					#ifdef __linux__
 | 
				
			||||||
 | 
					#include <linux/input-event-codes.h>
 | 
				
			||||||
 | 
					#elif __FreeBSD__
 | 
				
			||||||
 | 
					#include <dev/evdev/input-event-codes.h>
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
#include <assert.h>
 | 
					#include <assert.h>
 | 
				
			||||||
#include <errno.h>
 | 
					#include <errno.h>
 | 
				
			||||||
#include <fcntl.h>
 | 
					#include <fcntl.h>
 | 
				
			||||||
#include <json-c/json.h>
 | 
					#include <json-c/json.h>
 | 
				
			||||||
#include <stdbool.h>
 | 
					#include <stdbool.h>
 | 
				
			||||||
#include <stdint.h>
 | 
					#include <stdint.h>
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
#include <stdlib.h>
 | 
					#include <stdlib.h>
 | 
				
			||||||
#include <string.h>
 | 
					#include <string.h>
 | 
				
			||||||
#include <sys/socket.h>
 | 
					#include <sys/socket.h>
 | 
				
			||||||
| 
						 | 
					@ -28,6 +34,7 @@
 | 
				
			||||||
#include "sway/tree/view.h"
 | 
					#include "sway/tree/view.h"
 | 
				
			||||||
#include "list.h"
 | 
					#include "list.h"
 | 
				
			||||||
#include "log.h"
 | 
					#include "log.h"
 | 
				
			||||||
 | 
					#include "util.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int ipc_socket = -1;
 | 
					static int ipc_socket = -1;
 | 
				
			||||||
static struct wl_event_source *ipc_event_source =  NULL;
 | 
					static struct wl_event_source *ipc_event_source =  NULL;
 | 
				
			||||||
| 
						 | 
					@ -291,14 +298,12 @@ void ipc_event_workspace(struct sway_container *old,
 | 
				
			||||||
	wlr_log(WLR_DEBUG, "Sending workspace::%s event", change);
 | 
						wlr_log(WLR_DEBUG, "Sending workspace::%s event", change);
 | 
				
			||||||
	json_object *obj = json_object_new_object();
 | 
						json_object *obj = json_object_new_object();
 | 
				
			||||||
	json_object_object_add(obj, "change", json_object_new_string(change));
 | 
						json_object_object_add(obj, "change", json_object_new_string(change));
 | 
				
			||||||
	if (strcmp("focus", change) == 0) {
 | 
					 | 
				
			||||||
	if (old) {
 | 
						if (old) {
 | 
				
			||||||
		json_object_object_add(obj, "old",
 | 
							json_object_object_add(obj, "old",
 | 
				
			||||||
				ipc_json_describe_container_recursive(old));
 | 
									ipc_json_describe_container_recursive(old));
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		json_object_object_add(obj, "old", NULL);
 | 
							json_object_object_add(obj, "old", NULL);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (new) {
 | 
						if (new) {
 | 
				
			||||||
		json_object_object_add(obj, "current",
 | 
							json_object_object_add(obj, "current",
 | 
				
			||||||
| 
						 | 
					@ -353,6 +358,104 @@ void ipc_event_mode(const char *mode, bool pango) {
 | 
				
			||||||
	json_object_put(obj);
 | 
						json_object_put(obj);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ipc_event_shutdown(const char *reason) {
 | 
				
			||||||
 | 
						if (!ipc_has_event_listeners(IPC_EVENT_SHUTDOWN)) {
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						wlr_log(WLR_DEBUG, "Sending shutdown::%s event", reason);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						json_object *json = json_object_new_object();
 | 
				
			||||||
 | 
						json_object_object_add(json, "change", json_object_new_string(reason));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						const char *json_string = json_object_to_json_string(json);
 | 
				
			||||||
 | 
						ipc_send_event(json_string, IPC_EVENT_SHUTDOWN);
 | 
				
			||||||
 | 
						json_object_put(json);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ipc_event_binding(struct sway_binding *binding) {
 | 
				
			||||||
 | 
						if (!ipc_has_event_listeners(IPC_EVENT_BINDING)) {
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						wlr_log(WLR_DEBUG, "Sending binding event");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						json_object *json_binding = json_object_new_object();
 | 
				
			||||||
 | 
						json_object_object_add(json_binding, "command", json_object_new_string(binding->command));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						const char *names[10];
 | 
				
			||||||
 | 
						int len = get_modifier_names(names, binding->modifiers);
 | 
				
			||||||
 | 
						json_object *modifiers = json_object_new_array();
 | 
				
			||||||
 | 
						for (int i = 0; i < len; ++i) {
 | 
				
			||||||
 | 
							json_object_array_add(modifiers, json_object_new_string(names[i]));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						json_object_object_add(json_binding, "event_state_mask", modifiers);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						json_object *input_codes = json_object_new_array();
 | 
				
			||||||
 | 
						int input_code = 0;
 | 
				
			||||||
 | 
						json_object *symbols = json_object_new_array();
 | 
				
			||||||
 | 
						json_object *symbol = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (binding->type == BINDING_KEYCODE) { // bindcode: populate input_codes
 | 
				
			||||||
 | 
							uint32_t keycode;
 | 
				
			||||||
 | 
							for (int i = 0; i < binding->keys->length; ++i) {
 | 
				
			||||||
 | 
								keycode = *(uint32_t *)binding->keys->items[i];
 | 
				
			||||||
 | 
								json_object_array_add(input_codes, json_object_new_int(keycode));
 | 
				
			||||||
 | 
								if (i == 0) {
 | 
				
			||||||
 | 
									input_code = keycode;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else { // bindsym/mouse: populate symbols
 | 
				
			||||||
 | 
							uint32_t keysym;
 | 
				
			||||||
 | 
							char buffer[64];
 | 
				
			||||||
 | 
							for (int i = 0; i < binding->keys->length; ++i) {
 | 
				
			||||||
 | 
								keysym = *(uint32_t *)binding->keys->items[i];
 | 
				
			||||||
 | 
								if (keysym >= BTN_LEFT && keysym <= BTN_LEFT + 8) {
 | 
				
			||||||
 | 
									snprintf(buffer, 64, "button%u", keysym - BTN_LEFT + 1);
 | 
				
			||||||
 | 
								} else if (xkb_keysym_get_name(keysym, buffer, 64) < 0) {
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								json_object *str = json_object_new_string(buffer);
 | 
				
			||||||
 | 
								if (i == 0) {
 | 
				
			||||||
 | 
									// str is owned by both symbol and symbols. Make sure
 | 
				
			||||||
 | 
									// to bump the ref count.
 | 
				
			||||||
 | 
									json_object_array_add(symbols, json_object_get(str));
 | 
				
			||||||
 | 
									symbol = str;
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									json_object_array_add(symbols, str);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						json_object_object_add(json_binding, "input_codes", input_codes);
 | 
				
			||||||
 | 
						json_object_object_add(json_binding, "input_code", json_object_new_int(input_code));
 | 
				
			||||||
 | 
						json_object_object_add(json_binding, "symbols", symbols);
 | 
				
			||||||
 | 
						json_object_object_add(json_binding, "symbol", symbol);
 | 
				
			||||||
 | 
						json_object_object_add(json_binding, "input_type", binding->type == BINDING_MOUSE ?
 | 
				
			||||||
 | 
								json_object_new_string("mouse") : json_object_new_string("keyboard"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						json_object *json = json_object_new_object();
 | 
				
			||||||
 | 
						json_object_object_add(json, "change", json_object_new_string("run"));
 | 
				
			||||||
 | 
						json_object_object_add(json, "binding", json_binding);
 | 
				
			||||||
 | 
						const char *json_string = json_object_to_json_string(json);
 | 
				
			||||||
 | 
						ipc_send_event(json_string, IPC_EVENT_BINDING);
 | 
				
			||||||
 | 
						json_object_put(json);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void ipc_event_tick(const char *payload) {
 | 
				
			||||||
 | 
						if (!ipc_has_event_listeners(IPC_EVENT_TICK)) {
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						wlr_log(WLR_DEBUG, "Sending tick event");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						json_object *json = json_object_new_object();
 | 
				
			||||||
 | 
						json_object_object_add(json, "first", json_object_new_boolean(false));
 | 
				
			||||||
 | 
						json_object_object_add(json, "payload", json_object_new_string(payload));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						const char *json_string = json_object_to_json_string(json);
 | 
				
			||||||
 | 
						ipc_send_event(json_string, IPC_EVENT_TICK);
 | 
				
			||||||
 | 
						json_object_put(json);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int ipc_client_handle_writable(int client_fd, uint32_t mask, void *data) {
 | 
					int ipc_client_handle_writable(int client_fd, uint32_t mask, void *data) {
 | 
				
			||||||
	struct ipc_client *client = data;
 | 
						struct ipc_client *client = data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -494,6 +597,13 @@ void ipc_client_handle_command(struct ipc_client *client) {
 | 
				
			||||||
		goto exit_cleanup;
 | 
							goto exit_cleanup;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case IPC_SEND_TICK:
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							ipc_event_tick(buf);
 | 
				
			||||||
 | 
							ipc_send_reply(client, "{\"success\": true}", 17);
 | 
				
			||||||
 | 
							goto exit_cleanup;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case IPC_GET_OUTPUTS:
 | 
						case IPC_GET_OUTPUTS:
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		json_object *outputs = json_object_new_array();
 | 
							json_object *outputs = json_object_new_array();
 | 
				
			||||||
| 
						 | 
					@ -540,6 +650,7 @@ void ipc_client_handle_command(struct ipc_client *client) {
 | 
				
			||||||
			goto exit_cleanup;
 | 
								goto exit_cleanup;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							bool is_tick = false;
 | 
				
			||||||
		// parse requested event types
 | 
							// parse requested event types
 | 
				
			||||||
		for (size_t i = 0; i < json_object_array_length(request); i++) {
 | 
							for (size_t i = 0; i < json_object_array_length(request); i++) {
 | 
				
			||||||
			const char *event_type = json_object_get_string(json_object_array_get_idx(request, i));
 | 
								const char *event_type = json_object_get_string(json_object_array_get_idx(request, i));
 | 
				
			||||||
| 
						 | 
					@ -549,12 +660,15 @@ void ipc_client_handle_command(struct ipc_client *client) {
 | 
				
			||||||
				client->subscribed_events |= event_mask(IPC_EVENT_BARCONFIG_UPDATE);
 | 
									client->subscribed_events |= event_mask(IPC_EVENT_BARCONFIG_UPDATE);
 | 
				
			||||||
			} else if (strcmp(event_type, "mode") == 0) {
 | 
								} else if (strcmp(event_type, "mode") == 0) {
 | 
				
			||||||
				client->subscribed_events |= event_mask(IPC_EVENT_MODE);
 | 
									client->subscribed_events |= event_mask(IPC_EVENT_MODE);
 | 
				
			||||||
 | 
								} else if (strcmp(event_type, "shutdown") == 0) {
 | 
				
			||||||
 | 
									client->subscribed_events |= event_mask(IPC_EVENT_SHUTDOWN);
 | 
				
			||||||
			} else if (strcmp(event_type, "window") == 0) {
 | 
								} else if (strcmp(event_type, "window") == 0) {
 | 
				
			||||||
				client->subscribed_events |= event_mask(IPC_EVENT_WINDOW);
 | 
									client->subscribed_events |= event_mask(IPC_EVENT_WINDOW);
 | 
				
			||||||
			} else if (strcmp(event_type, "modifier") == 0) {
 | 
					 | 
				
			||||||
				client->subscribed_events |= event_mask(IPC_EVENT_MODIFIER);
 | 
					 | 
				
			||||||
			} else if (strcmp(event_type, "binding") == 0) {
 | 
								} else if (strcmp(event_type, "binding") == 0) {
 | 
				
			||||||
				client->subscribed_events |= event_mask(IPC_EVENT_BINDING);
 | 
									client->subscribed_events |= event_mask(IPC_EVENT_BINDING);
 | 
				
			||||||
 | 
								} else if (strcmp(event_type, "tick") == 0) {
 | 
				
			||||||
 | 
									client->subscribed_events |= event_mask(IPC_EVENT_TICK);
 | 
				
			||||||
 | 
									is_tick = true;
 | 
				
			||||||
			} else {
 | 
								} else {
 | 
				
			||||||
				client_valid =
 | 
									client_valid =
 | 
				
			||||||
					ipc_send_reply(client, "{\"success\": false}", 18);
 | 
										ipc_send_reply(client, "{\"success\": false}", 18);
 | 
				
			||||||
| 
						 | 
					@ -566,6 +680,10 @@ void ipc_client_handle_command(struct ipc_client *client) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		json_object_put(request);
 | 
							json_object_put(request);
 | 
				
			||||||
		client_valid = ipc_send_reply(client, "{\"success\": true}", 17);
 | 
							client_valid = ipc_send_reply(client, "{\"success\": true}", 17);
 | 
				
			||||||
 | 
							if (is_tick) {
 | 
				
			||||||
 | 
								client->current_command = IPC_EVENT_TICK;
 | 
				
			||||||
 | 
								ipc_send_reply(client, "{\"first\": true, \"payload\": \"\"}", 30);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		goto exit_cleanup;
 | 
							goto exit_cleanup;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -36,6 +36,7 @@ struct sway_server server;
 | 
				
			||||||
void sway_terminate(int exit_code) {
 | 
					void sway_terminate(int exit_code) {
 | 
				
			||||||
	terminate_request = true;
 | 
						terminate_request = true;
 | 
				
			||||||
	exit_value = exit_code;
 | 
						exit_value = exit_code;
 | 
				
			||||||
 | 
						ipc_event_shutdown("exit");
 | 
				
			||||||
	wl_display_terminate(server.wl_display);
 | 
						wl_display_terminate(server.wl_display);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,6 +7,7 @@ sway_sources = files(
 | 
				
			||||||
	'debug-tree.c',
 | 
						'debug-tree.c',
 | 
				
			||||||
	'ipc-json.c',
 | 
						'ipc-json.c',
 | 
				
			||||||
	'ipc-server.c',
 | 
						'ipc-server.c',
 | 
				
			||||||
 | 
						'scratchpad.c',
 | 
				
			||||||
	'security.c',
 | 
						'security.c',
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	'desktop/desktop.c',
 | 
						'desktop/desktop.c',
 | 
				
			||||||
| 
						 | 
					@ -17,7 +18,6 @@ sway_sources = files(
 | 
				
			||||||
	'desktop/transaction.c',
 | 
						'desktop/transaction.c',
 | 
				
			||||||
	'desktop/xdg_shell_v6.c',
 | 
						'desktop/xdg_shell_v6.c',
 | 
				
			||||||
	'desktop/xdg_shell.c',
 | 
						'desktop/xdg_shell.c',
 | 
				
			||||||
	'desktop/xwayland.c',
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	'input/input-manager.c',
 | 
						'input/input-manager.c',
 | 
				
			||||||
	'input/seat.c',
 | 
						'input/seat.c',
 | 
				
			||||||
| 
						 | 
					@ -42,6 +42,7 @@ sway_sources = files(
 | 
				
			||||||
	'commands/exec_always.c',
 | 
						'commands/exec_always.c',
 | 
				
			||||||
	'commands/floating.c',
 | 
						'commands/floating.c',
 | 
				
			||||||
	'commands/floating_minmax_size.c',
 | 
						'commands/floating_minmax_size.c',
 | 
				
			||||||
 | 
						'commands/floating_modifier.c',
 | 
				
			||||||
	'commands/focus.c',
 | 
						'commands/focus.c',
 | 
				
			||||||
	'commands/focus_follows_mouse.c',
 | 
						'commands/focus_follows_mouse.c',
 | 
				
			||||||
	'commands/focus_wrapping.c',
 | 
						'commands/focus_wrapping.c',
 | 
				
			||||||
| 
						 | 
					@ -66,6 +67,7 @@ sway_sources = files(
 | 
				
			||||||
	'commands/reload.c',
 | 
						'commands/reload.c',
 | 
				
			||||||
	'commands/rename.c',
 | 
						'commands/rename.c',
 | 
				
			||||||
	'commands/resize.c',
 | 
						'commands/resize.c',
 | 
				
			||||||
 | 
						'commands/scratchpad.c',
 | 
				
			||||||
	'commands/seat.c',
 | 
						'commands/seat.c',
 | 
				
			||||||
	'commands/seat/attach.c',
 | 
						'commands/seat/attach.c',
 | 
				
			||||||
	'commands/seat/cursor.c',
 | 
						'commands/seat/cursor.c',
 | 
				
			||||||
| 
						 | 
					@ -126,8 +128,10 @@ sway_sources = files(
 | 
				
			||||||
	'commands/input/scroll_method.c',
 | 
						'commands/input/scroll_method.c',
 | 
				
			||||||
	'commands/input/tap.c',
 | 
						'commands/input/tap.c',
 | 
				
			||||||
	'commands/input/tap_button_map.c',
 | 
						'commands/input/tap_button_map.c',
 | 
				
			||||||
 | 
						'commands/input/xkb_capslock.c',
 | 
				
			||||||
	'commands/input/xkb_layout.c',
 | 
						'commands/input/xkb_layout.c',
 | 
				
			||||||
	'commands/input/xkb_model.c',
 | 
						'commands/input/xkb_model.c',
 | 
				
			||||||
 | 
						'commands/input/xkb_numlock.c',
 | 
				
			||||||
	'commands/input/xkb_options.c',
 | 
						'commands/input/xkb_options.c',
 | 
				
			||||||
	'commands/input/xkb_rules.c',
 | 
						'commands/input/xkb_rules.c',
 | 
				
			||||||
	'commands/input/xkb_variant.c',
 | 
						'commands/input/xkb_variant.c',
 | 
				
			||||||
| 
						 | 
					@ -162,10 +166,14 @@ sway_deps = [
 | 
				
			||||||
	server_protos,
 | 
						server_protos,
 | 
				
			||||||
	wayland_server,
 | 
						wayland_server,
 | 
				
			||||||
	wlroots,
 | 
						wlroots,
 | 
				
			||||||
	xcb,
 | 
					 | 
				
			||||||
	xkbcommon,
 | 
						xkbcommon,
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if get_option('enable-xwayland')
 | 
				
			||||||
 | 
						sway_sources += 'desktop/xwayland.c'
 | 
				
			||||||
 | 
						sway_deps += xcb
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
executable(
 | 
					executable(
 | 
				
			||||||
	'sway',
 | 
						'sway',
 | 
				
			||||||
	sway_sources,
 | 
						sway_sources,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										181
									
								
								sway/scratchpad.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										181
									
								
								sway/scratchpad.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,181 @@
 | 
				
			||||||
 | 
					#define _XOPEN_SOURCE 700
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <stdbool.h>
 | 
				
			||||||
 | 
					#include "sway/scratchpad.h"
 | 
				
			||||||
 | 
					#include "sway/input/seat.h"
 | 
				
			||||||
 | 
					#include "sway/tree/arrange.h"
 | 
				
			||||||
 | 
					#include "sway/tree/container.h"
 | 
				
			||||||
 | 
					#include "sway/tree/view.h"
 | 
				
			||||||
 | 
					#include "sway/tree/workspace.h"
 | 
				
			||||||
 | 
					#include "list.h"
 | 
				
			||||||
 | 
					#include "log.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void scratchpad_add_container(struct sway_container *con) {
 | 
				
			||||||
 | 
						if (!sway_assert(!con->scratchpad, "Container is already in scratchpad")) {
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						con->scratchpad = true;
 | 
				
			||||||
 | 
						list_add(root_container.sway_root->scratchpad, con);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct sway_container *parent = con->parent;
 | 
				
			||||||
 | 
						container_set_floating(con, true);
 | 
				
			||||||
 | 
						container_remove_child(con);
 | 
				
			||||||
 | 
						arrange_windows(parent);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct sway_seat *seat = input_manager_current_seat(input_manager);
 | 
				
			||||||
 | 
						seat_set_focus(seat, seat_get_focus_inactive(seat, parent));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void scratchpad_remove_container(struct sway_container *con) {
 | 
				
			||||||
 | 
						if (!sway_assert(con->scratchpad, "Container is not in scratchpad")) {
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						con->scratchpad = false;
 | 
				
			||||||
 | 
						for (int i = 0; i < root_container.sway_root->scratchpad->length; ++i) {
 | 
				
			||||||
 | 
							if (root_container.sway_root->scratchpad->items[i] == con) {
 | 
				
			||||||
 | 
								list_del(root_container.sway_root->scratchpad, i);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Show a single scratchpad container.
 | 
				
			||||||
 | 
					 * The container might be visible on another workspace already.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static void scratchpad_show(struct sway_container *con) {
 | 
				
			||||||
 | 
						struct sway_seat *seat = input_manager_current_seat(input_manager);
 | 
				
			||||||
 | 
						struct sway_container *ws = seat_get_focus(seat);
 | 
				
			||||||
 | 
						if (ws->type != C_WORKSPACE) {
 | 
				
			||||||
 | 
							ws = container_parent(ws, C_WORKSPACE);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // If the current con or any of its parents are in fullscreen mode, we
 | 
				
			||||||
 | 
					    // first need to disable it before showing the scratchpad con.
 | 
				
			||||||
 | 
						if (ws->sway_workspace->fullscreen) {
 | 
				
			||||||
 | 
							container_set_fullscreen(ws->sway_workspace->fullscreen, false);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Show the container
 | 
				
			||||||
 | 
						if (con->parent) {
 | 
				
			||||||
 | 
							container_remove_child(con);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						container_add_child(ws->sway_workspace->floating, con);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Make sure the container's center point overlaps this workspace
 | 
				
			||||||
 | 
						double center_lx = con->x + con->width / 2;
 | 
				
			||||||
 | 
						double center_ly = con->y + con->height / 2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct wlr_box workspace_box;
 | 
				
			||||||
 | 
						container_get_box(ws, &workspace_box);
 | 
				
			||||||
 | 
						if (!wlr_box_contains_point(&workspace_box, center_lx, center_ly)) {
 | 
				
			||||||
 | 
							// Maybe resize it
 | 
				
			||||||
 | 
							if (con->width > ws->width || con->height > ws->height) {
 | 
				
			||||||
 | 
								container_init_floating(con);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Center it
 | 
				
			||||||
 | 
							double new_lx = ws->x + (ws->width - con->width) / 2;
 | 
				
			||||||
 | 
							double new_ly = ws->y + (ws->height - con->height) / 2;
 | 
				
			||||||
 | 
							container_floating_move_to(con, new_lx, new_ly);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						arrange_windows(ws);
 | 
				
			||||||
 | 
						seat_set_focus(seat, seat_get_focus_inactive(seat, con));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						container_set_dirty(con->parent);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Hide a single scratchpad container.
 | 
				
			||||||
 | 
					 * The container might not be the focused container (eg. when using criteria).
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static void scratchpad_hide(struct sway_container *con) {
 | 
				
			||||||
 | 
						struct sway_seat *seat = input_manager_current_seat(input_manager);
 | 
				
			||||||
 | 
						struct sway_container *focus = seat_get_focus(seat);
 | 
				
			||||||
 | 
						struct sway_container *ws = container_parent(con, C_WORKSPACE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						container_remove_child(con);
 | 
				
			||||||
 | 
						arrange_windows(ws);
 | 
				
			||||||
 | 
						if (con == focus) {
 | 
				
			||||||
 | 
							seat_set_focus(seat, seat_get_focus_inactive(seat, ws));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						list_move_to_end(root_container.sway_root->scratchpad, con);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void scratchpad_toggle_auto(void) {
 | 
				
			||||||
 | 
						struct sway_seat *seat = input_manager_current_seat(input_manager);
 | 
				
			||||||
 | 
						struct sway_container *focus = seat_get_focus(seat);
 | 
				
			||||||
 | 
						struct sway_container *ws = focus->type == C_WORKSPACE ?
 | 
				
			||||||
 | 
							focus : container_parent(focus, C_WORKSPACE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// If the focus is in a floating split container,
 | 
				
			||||||
 | 
						// operate on the split container instead of the child.
 | 
				
			||||||
 | 
						if (container_is_floating_or_child(focus)) {
 | 
				
			||||||
 | 
							while (focus->parent->layout != L_FLOATING) {
 | 
				
			||||||
 | 
								focus = focus->parent;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Check if the currently focused window is a scratchpad window and should
 | 
				
			||||||
 | 
					    // be hidden again.
 | 
				
			||||||
 | 
						if (focus->scratchpad) {
 | 
				
			||||||
 | 
							wlr_log(WLR_DEBUG, "Focus is a scratchpad window - hiding %s",
 | 
				
			||||||
 | 
									focus->name);
 | 
				
			||||||
 | 
							scratchpad_hide(focus);
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Check if there is an unfocused scratchpad window on the current workspace
 | 
				
			||||||
 | 
					    // and focus it.
 | 
				
			||||||
 | 
						for (int i = 0; i < ws->sway_workspace->floating->children->length; ++i) {
 | 
				
			||||||
 | 
							struct sway_container *floater =
 | 
				
			||||||
 | 
								ws->sway_workspace->floating->children->items[i];
 | 
				
			||||||
 | 
							if (floater->scratchpad && focus != floater) {
 | 
				
			||||||
 | 
								wlr_log(WLR_DEBUG,
 | 
				
			||||||
 | 
										"Focusing other scratchpad window (%s) in this workspace",
 | 
				
			||||||
 | 
										floater->name);
 | 
				
			||||||
 | 
								scratchpad_show(floater);
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Check if there is a visible scratchpad window on another workspace.
 | 
				
			||||||
 | 
					    // In this case we move it to the current workspace.
 | 
				
			||||||
 | 
						for (int i = 0; i < root_container.sway_root->scratchpad->length; ++i) {
 | 
				
			||||||
 | 
							struct sway_container *con =
 | 
				
			||||||
 | 
								root_container.sway_root->scratchpad->items[i];
 | 
				
			||||||
 | 
							if (con->parent) {
 | 
				
			||||||
 | 
								wlr_log(WLR_DEBUG,
 | 
				
			||||||
 | 
										"Moving a visible scratchpad window (%s) to this workspace",
 | 
				
			||||||
 | 
										con->name);
 | 
				
			||||||
 | 
								scratchpad_show(con);
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Take the container at the bottom of the scratchpad list
 | 
				
			||||||
 | 
						if (!sway_assert(root_container.sway_root->scratchpad->length,
 | 
				
			||||||
 | 
									"Scratchpad is empty")) {
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						struct sway_container *con = root_container.sway_root->scratchpad->items[0];
 | 
				
			||||||
 | 
						wlr_log(WLR_DEBUG, "Showing %s from list", con->name);
 | 
				
			||||||
 | 
						scratchpad_show(con);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void scratchpad_toggle_container(struct sway_container *con) {
 | 
				
			||||||
 | 
						if (!sway_assert(con->scratchpad, "Container isn't in the scratchpad")) {
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Check if it matches a currently visible scratchpad window and hide it.
 | 
				
			||||||
 | 
						if (con->parent) {
 | 
				
			||||||
 | 
							scratchpad_hide(con);
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						scratchpad_show(con);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -26,7 +26,10 @@
 | 
				
			||||||
#include "sway/input/input-manager.h"
 | 
					#include "sway/input/input-manager.h"
 | 
				
			||||||
#include "sway/server.h"
 | 
					#include "sway/server.h"
 | 
				
			||||||
#include "sway/tree/layout.h"
 | 
					#include "sway/tree/layout.h"
 | 
				
			||||||
 | 
					#include "config.h"
 | 
				
			||||||
 | 
					#ifdef HAVE_XWAYLAND
 | 
				
			||||||
#include "sway/xwayland.h"
 | 
					#include "sway/xwayland.h"
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool server_privileged_prepare(struct sway_server *server) {
 | 
					bool server_privileged_prepare(struct sway_server *server) {
 | 
				
			||||||
	wlr_log(WLR_DEBUG, "Preparing Wayland server initialization");
 | 
						wlr_log(WLR_DEBUG, "Preparing Wayland server initialization");
 | 
				
			||||||
| 
						 | 
					@ -83,6 +86,7 @@ bool server_init(struct sway_server *server) {
 | 
				
			||||||
	server->xdg_shell_surface.notify = handle_xdg_shell_surface;
 | 
						server->xdg_shell_surface.notify = handle_xdg_shell_surface;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// TODO make xwayland optional
 | 
						// TODO make xwayland optional
 | 
				
			||||||
 | 
					#ifdef HAVE_XWAYLAND
 | 
				
			||||||
	server->xwayland.wlr_xwayland =
 | 
						server->xwayland.wlr_xwayland =
 | 
				
			||||||
		wlr_xwayland_create(server->wl_display, server->compositor, true);
 | 
							wlr_xwayland_create(server->wl_display, server->compositor, true);
 | 
				
			||||||
	wl_signal_add(&server->xwayland.wlr_xwayland->events.new_surface,
 | 
						wl_signal_add(&server->xwayland.wlr_xwayland->events.new_surface,
 | 
				
			||||||
| 
						 | 
					@ -103,6 +107,7 @@ bool server_init(struct sway_server *server) {
 | 
				
			||||||
			image->width * 4, image->width, image->height, image->hotspot_x,
 | 
								image->width * 4, image->width, image->height, image->hotspot_x,
 | 
				
			||||||
			image->hotspot_y);
 | 
								image->hotspot_y);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// TODO: Integration with sway borders
 | 
						// TODO: Integration with sway borders
 | 
				
			||||||
	struct wlr_server_decoration_manager *deco_manager =
 | 
						struct wlr_server_decoration_manager *deco_manager =
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -33,6 +33,14 @@ For more information on these xkb configuration options, see
 | 
				
			||||||
*input* <identifier> xkb\_variant <variant>
 | 
					*input* <identifier> xkb\_variant <variant>
 | 
				
			||||||
	Sets the variant of the keyboard like _dvorak_ or _colemak_.
 | 
						Sets the variant of the keyboard like _dvorak_ or _colemak_.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The following commands may only be used in the configuration file.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*input* <identifier> xkb\_capslock enabled|disabled
 | 
				
			||||||
 | 
						Initially enables or disables CapsLock, the default is disabled.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*input* <identifier> xkb\_numlock enabled|disabled
 | 
				
			||||||
 | 
						Initially enables or disables NumLock, the default is disabled.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## MAPPING CONFIGURATION
 | 
					## MAPPING CONFIGURATION
 | 
				
			||||||
 | 
					
 | 
				
			||||||
*input* <identifier> map\_to\_output <identifier>
 | 
					*input* <identifier> map\_to\_output <identifier>
 | 
				
			||||||
| 
						 | 
					@ -100,7 +108,7 @@ For more information on these xkb configuration options, see
 | 
				
			||||||
*input* <identifier> tap enabled|disabled
 | 
					*input* <identifier> tap enabled|disabled
 | 
				
			||||||
	Enables or disables tap for specified input device.
 | 
						Enables or disables tap for specified input device.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
*input* <identifier> tap_button_map lrm|lmr
 | 
					*input* <identifier> tap\_button\_map lrm|lmr
 | 
				
			||||||
	Specifies which button mapping to use for tapping. _lrm_ treats 1 finger as
 | 
						Specifies which button mapping to use for tapping. _lrm_ treats 1 finger as
 | 
				
			||||||
	left click, 2 fingers as right click, and 3 fingers as middle click. _lmr_
 | 
						left click, 2 fingers as right click, and 3 fingers as middle click. _lmr_
 | 
				
			||||||
	treats 1 finger as left click, 2 fingers as middle click, and 3 fingers as
 | 
						treats 1 finger as left click, 2 fingers as middle click, and 3 fingers as
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -92,4 +92,4 @@ source contributors. For more information about sway development, see
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# SEE ALSO
 | 
					# SEE ALSO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
*sway*(5) *swaymsg*(1) *swaygrab*(1) *sway-input*(5) *sway-bar*(5)
 | 
					*sway*(5) *swaymsg*(1) *sway-input*(5) *sway-bar*(5)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -220,9 +220,23 @@ static void arrange_workspace(struct sway_container *workspace) {
 | 
				
			||||||
	container_set_dirty(workspace);
 | 
						container_set_dirty(workspace);
 | 
				
			||||||
	wlr_log(WLR_DEBUG, "Arranging workspace '%s' at %f, %f", workspace->name,
 | 
						wlr_log(WLR_DEBUG, "Arranging workspace '%s' at %f, %f", workspace->name,
 | 
				
			||||||
			workspace->x, workspace->y);
 | 
								workspace->x, workspace->y);
 | 
				
			||||||
 | 
						if (workspace->sway_workspace->fullscreen) {
 | 
				
			||||||
 | 
							struct sway_container *fs = workspace->sway_workspace->fullscreen;
 | 
				
			||||||
 | 
							fs->x = workspace->parent->x;
 | 
				
			||||||
 | 
							fs->y = workspace->parent->y;
 | 
				
			||||||
 | 
							fs->width = workspace->parent->width;
 | 
				
			||||||
 | 
							fs->height = workspace->parent->height;
 | 
				
			||||||
 | 
							if (fs->type == C_VIEW) {
 | 
				
			||||||
 | 
								view_autoconfigure(fs->sway_view);
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								arrange_children_of(fs);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							container_set_dirty(fs);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
		arrange_floating(workspace->sway_workspace->floating);
 | 
							arrange_floating(workspace->sway_workspace->floating);
 | 
				
			||||||
		arrange_children_of(workspace);
 | 
							arrange_children_of(workspace);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void arrange_output(struct sway_container *output) {
 | 
					static void arrange_output(struct sway_container *output) {
 | 
				
			||||||
	if (config->reloading) {
 | 
						if (config->reloading) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -17,6 +17,7 @@
 | 
				
			||||||
#include "sway/input/seat.h"
 | 
					#include "sway/input/seat.h"
 | 
				
			||||||
#include "sway/ipc-server.h"
 | 
					#include "sway/ipc-server.h"
 | 
				
			||||||
#include "sway/output.h"
 | 
					#include "sway/output.h"
 | 
				
			||||||
 | 
					#include "sway/scratchpad.h"
 | 
				
			||||||
#include "sway/server.h"
 | 
					#include "sway/server.h"
 | 
				
			||||||
#include "sway/tree/arrange.h"
 | 
					#include "sway/tree/arrange.h"
 | 
				
			||||||
#include "sway/tree/layout.h"
 | 
					#include "sway/tree/layout.h"
 | 
				
			||||||
| 
						 | 
					@ -61,13 +62,17 @@ void container_create_notify(struct sway_container *container) {
 | 
				
			||||||
	// TODO send ipc event type based on the container type
 | 
						// TODO send ipc event type based on the container type
 | 
				
			||||||
	wl_signal_emit(&root_container.sway_root->events.new_container, container);
 | 
						wl_signal_emit(&root_container.sway_root->events.new_container, container);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (container->type == C_VIEW || container->type == C_CONTAINER) {
 | 
						if (container->type == C_VIEW) {
 | 
				
			||||||
		ipc_event_window(container, "new");
 | 
							ipc_event_window(container, "new");
 | 
				
			||||||
 | 
						} else if (container->type == C_WORKSPACE) {
 | 
				
			||||||
 | 
							ipc_event_workspace(NULL, container, "init");
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void container_update_textures_recursive(struct sway_container *con) {
 | 
					void container_update_textures_recursive(struct sway_container *con) {
 | 
				
			||||||
 | 
						if (con->type == C_CONTAINER || con->type == C_VIEW) {
 | 
				
			||||||
		container_update_title_textures(con);
 | 
							container_update_title_textures(con);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (con->type == C_VIEW) {
 | 
						if (con->type == C_VIEW) {
 | 
				
			||||||
		view_update_marks_textures(con->sway_view);
 | 
							view_update_marks_textures(con->sway_view);
 | 
				
			||||||
| 
						 | 
					@ -76,6 +81,10 @@ static void container_update_textures_recursive(struct sway_container *con) {
 | 
				
			||||||
			struct sway_container *child = con->children->items[i];
 | 
								struct sway_container *child = con->children->items[i];
 | 
				
			||||||
			container_update_textures_recursive(child);
 | 
								container_update_textures_recursive(child);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (con->type == C_WORKSPACE) {
 | 
				
			||||||
 | 
								container_update_textures_recursive(con->sway_workspace->floating);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -139,8 +148,6 @@ struct sway_container *container_create(enum sway_container_type type) {
 | 
				
			||||||
static void container_workspace_free(struct sway_workspace *ws) {
 | 
					static void container_workspace_free(struct sway_workspace *ws) {
 | 
				
			||||||
	list_foreach(ws->output_priority, free);
 | 
						list_foreach(ws->output_priority, free);
 | 
				
			||||||
	list_free(ws->output_priority);
 | 
						list_free(ws->output_priority);
 | 
				
			||||||
	ws->floating->destroying = true;
 | 
					 | 
				
			||||||
	container_free(ws->floating);
 | 
					 | 
				
			||||||
	free(ws);
 | 
						free(ws);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -193,6 +200,9 @@ void container_free(struct sway_container *cont) {
 | 
				
			||||||
	free(cont);
 | 
						free(cont);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct sway_container *container_destroy_noreaping(
 | 
				
			||||||
 | 
							struct sway_container *con);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct sway_container *container_workspace_destroy(
 | 
					static struct sway_container *container_workspace_destroy(
 | 
				
			||||||
		struct sway_container *workspace) {
 | 
							struct sway_container *workspace) {
 | 
				
			||||||
	if (!sway_assert(workspace, "cannot destroy null workspace")) {
 | 
						if (!sway_assert(workspace, "cannot destroy null workspace")) {
 | 
				
			||||||
| 
						 | 
					@ -237,6 +247,8 @@ static struct sway_container *container_workspace_destroy(
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						container_destroy_noreaping(workspace->sway_workspace->floating);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return output;
 | 
						return output;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -271,7 +283,7 @@ static struct sway_container *container_output_destroy(
 | 
				
			||||||
				container_remove_child(workspace);
 | 
									container_remove_child(workspace);
 | 
				
			||||||
				if (!workspace_is_empty(workspace)) {
 | 
									if (!workspace_is_empty(workspace)) {
 | 
				
			||||||
					container_add_child(new_output, workspace);
 | 
										container_add_child(new_output, workspace);
 | 
				
			||||||
					ipc_event_workspace(workspace, NULL, "move");
 | 
										ipc_event_workspace(NULL, workspace, "move");
 | 
				
			||||||
				} else {
 | 
									} else {
 | 
				
			||||||
					container_destroy(workspace);
 | 
										container_destroy(workspace);
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
| 
						 | 
					@ -309,7 +321,13 @@ static struct sway_container *container_destroy_noreaping(
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wl_signal_emit(&con->events.destroy, con);
 | 
						wl_signal_emit(&con->events.destroy, con);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// emit IPC event
 | 
				
			||||||
 | 
						if (con->type == C_VIEW) {
 | 
				
			||||||
		ipc_event_window(con, "close");
 | 
							ipc_event_window(con, "close");
 | 
				
			||||||
 | 
						} else if (con->type == C_WORKSPACE) {
 | 
				
			||||||
 | 
							ipc_event_workspace(NULL, con, "empty");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// The below functions move their children to somewhere else.
 | 
						// The below functions move their children to somewhere else.
 | 
				
			||||||
	if (con->type == C_OUTPUT) {
 | 
						if (con->type == C_OUTPUT) {
 | 
				
			||||||
| 
						 | 
					@ -323,9 +341,15 @@ static struct sway_container *container_destroy_noreaping(
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						container_end_mouse_operation(con);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	con->destroying = true;
 | 
						con->destroying = true;
 | 
				
			||||||
	container_set_dirty(con);
 | 
						container_set_dirty(con);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (con->scratchpad) {
 | 
				
			||||||
 | 
							scratchpad_remove_container(con);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!con->parent) {
 | 
						if (!con->parent) {
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -398,6 +422,10 @@ struct sway_container *container_flatten(struct sway_container *container) {
 | 
				
			||||||
 * This function just wraps container_destroy_noreaping(), then does reaping.
 | 
					 * This function just wraps container_destroy_noreaping(), then does reaping.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
struct sway_container *container_destroy(struct sway_container *con) {
 | 
					struct sway_container *container_destroy(struct sway_container *con) {
 | 
				
			||||||
 | 
						if (con->is_fullscreen) {
 | 
				
			||||||
 | 
							struct sway_container *ws = container_parent(con, C_WORKSPACE);
 | 
				
			||||||
 | 
							ws->sway_workspace->fullscreen = NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	struct sway_container *parent = container_destroy_noreaping(con);
 | 
						struct sway_container *parent = container_destroy_noreaping(con);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!parent) {
 | 
						if (!parent) {
 | 
				
			||||||
| 
						 | 
					@ -507,7 +535,7 @@ struct sway_container *container_parent(struct sway_container *container,
 | 
				
			||||||
	return container;
 | 
						return container;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct sway_container *container_at_view(struct sway_container *swayc,
 | 
					struct sway_container *container_at_view(struct sway_container *swayc,
 | 
				
			||||||
		double lx, double ly,
 | 
							double lx, double ly,
 | 
				
			||||||
		struct wlr_surface **surface, double *sx, double *sy) {
 | 
							struct wlr_surface **surface, double *sx, double *sy) {
 | 
				
			||||||
	if (!sway_assert(swayc->type == C_VIEW, "Expected a view")) {
 | 
						if (!sway_assert(swayc->type == C_VIEW, "Expected a view")) {
 | 
				
			||||||
| 
						 | 
					@ -520,10 +548,12 @@ static struct sway_container *container_at_view(struct sway_container *swayc,
 | 
				
			||||||
	double _sx, _sy;
 | 
						double _sx, _sy;
 | 
				
			||||||
	struct wlr_surface *_surface = NULL;
 | 
						struct wlr_surface *_surface = NULL;
 | 
				
			||||||
	switch (sview->type) {
 | 
						switch (sview->type) {
 | 
				
			||||||
 | 
					#ifdef HAVE_XWAYLAND
 | 
				
			||||||
	case SWAY_VIEW_XWAYLAND:
 | 
						case SWAY_VIEW_XWAYLAND:
 | 
				
			||||||
		_surface = wlr_surface_surface_at(sview->surface,
 | 
							_surface = wlr_surface_surface_at(sview->surface,
 | 
				
			||||||
				view_sx, view_sy, &_sx, &_sy);
 | 
									view_sx, view_sy, &_sx, &_sy);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
	case SWAY_VIEW_XDG_SHELL_V6:
 | 
						case SWAY_VIEW_XDG_SHELL_V6:
 | 
				
			||||||
		_surface = wlr_xdg_surface_v6_surface_at(
 | 
							_surface = wlr_xdg_surface_v6_surface_at(
 | 
				
			||||||
				sview->wlr_xdg_surface_v6,
 | 
									sview->wlr_xdg_surface_v6,
 | 
				
			||||||
| 
						 | 
					@ -539,9 +569,14 @@ static struct sway_container *container_at_view(struct sway_container *swayc,
 | 
				
			||||||
		*sx = _sx;
 | 
							*sx = _sx;
 | 
				
			||||||
		*sy = _sy;
 | 
							*sy = _sy;
 | 
				
			||||||
		*surface = _surface;
 | 
							*surface = _surface;
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
		return swayc;
 | 
							return swayc;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct sway_container *tiling_container_at(
 | 
				
			||||||
 | 
							struct sway_container *con, double lx, double ly,
 | 
				
			||||||
 | 
							struct wlr_surface **surface, double *sx, double *sy);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * container_at for a container with layout L_TABBED.
 | 
					 * container_at for a container with layout L_TABBED.
 | 
				
			||||||
| 
						 | 
					@ -569,7 +604,7 @@ static struct sway_container *container_at_tabbed(struct sway_container *parent,
 | 
				
			||||||
	// Surfaces
 | 
						// Surfaces
 | 
				
			||||||
	struct sway_container *current = seat_get_active_child(seat, parent);
 | 
						struct sway_container *current = seat_get_active_child(seat, parent);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return container_at(current, lx, ly, surface, sx, sy);
 | 
						return tiling_container_at(current, lx, ly, surface, sx, sy);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
| 
						 | 
					@ -594,7 +629,7 @@ static struct sway_container *container_at_stacked(
 | 
				
			||||||
	// Surfaces
 | 
						// Surfaces
 | 
				
			||||||
	struct sway_container *current = seat_get_active_child(seat, parent);
 | 
						struct sway_container *current = seat_get_active_child(seat, parent);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return container_at(current, lx, ly, surface, sx, sy);
 | 
						return tiling_container_at(current, lx, ly, surface, sx, sy);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
| 
						 | 
					@ -612,45 +647,13 @@ static struct sway_container *container_at_linear(struct sway_container *parent,
 | 
				
			||||||
			.height = child->height,
 | 
								.height = child->height,
 | 
				
			||||||
		};
 | 
							};
 | 
				
			||||||
		if (wlr_box_contains_point(&box, lx, ly)) {
 | 
							if (wlr_box_contains_point(&box, lx, ly)) {
 | 
				
			||||||
			return container_at(child, lx, ly, surface, sx, sy);
 | 
								return tiling_container_at(child, lx, ly, surface, sx, sy);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return NULL;
 | 
						return NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct sway_container *container_at(struct sway_container *parent,
 | 
					static struct sway_container *floating_container_at(double lx, double ly,
 | 
				
			||||||
		double lx, double ly,
 | 
					 | 
				
			||||||
		struct wlr_surface **surface, double *sx, double *sy) {
 | 
					 | 
				
			||||||
	if (!sway_assert(parent->type >= C_WORKSPACE,
 | 
					 | 
				
			||||||
				"Expected workspace or deeper")) {
 | 
					 | 
				
			||||||
		return NULL;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if (parent->type == C_VIEW) {
 | 
					 | 
				
			||||||
		return container_at_view(parent, lx, ly, surface, sx, sy);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if (!parent->children->length) {
 | 
					 | 
				
			||||||
		return NULL;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	switch (parent->layout) {
 | 
					 | 
				
			||||||
	case L_HORIZ:
 | 
					 | 
				
			||||||
	case L_VERT:
 | 
					 | 
				
			||||||
		return container_at_linear(parent, lx, ly, surface, sx, sy);
 | 
					 | 
				
			||||||
	case L_TABBED:
 | 
					 | 
				
			||||||
		return container_at_tabbed(parent, lx, ly, surface, sx, sy);
 | 
					 | 
				
			||||||
	case L_STACKED:
 | 
					 | 
				
			||||||
		return container_at_stacked(parent, lx, ly, surface, sx, sy);
 | 
					 | 
				
			||||||
	case L_FLOATING:
 | 
					 | 
				
			||||||
		sway_assert(false, "Didn't expect to see floating here");
 | 
					 | 
				
			||||||
		return NULL;
 | 
					 | 
				
			||||||
	case L_NONE:
 | 
					 | 
				
			||||||
		return NULL;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return NULL;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct sway_container *floating_container_at(double lx, double ly,
 | 
					 | 
				
			||||||
		struct wlr_surface **surface, double *sx, double *sy) {
 | 
							struct wlr_surface **surface, double *sx, double *sy) {
 | 
				
			||||||
	for (int i = 0; i < root_container.children->length; ++i) {
 | 
						for (int i = 0; i < root_container.children->length; ++i) {
 | 
				
			||||||
		struct sway_container *output = root_container.children->items[i];
 | 
							struct sway_container *output = root_container.children->items[i];
 | 
				
			||||||
| 
						 | 
					@ -672,7 +675,8 @@ struct sway_container *floating_container_at(double lx, double ly,
 | 
				
			||||||
					.height = floater->height,
 | 
										.height = floater->height,
 | 
				
			||||||
				};
 | 
									};
 | 
				
			||||||
				if (wlr_box_contains_point(&box, lx, ly)) {
 | 
									if (wlr_box_contains_point(&box, lx, ly)) {
 | 
				
			||||||
					return container_at(floater, lx, ly, surface, sx, sy);
 | 
										return tiling_container_at(floater, lx, ly,
 | 
				
			||||||
 | 
												surface, sx, sy);
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -680,6 +684,90 @@ struct sway_container *floating_container_at(double lx, double ly,
 | 
				
			||||||
	return NULL;
 | 
						return NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct sway_container *tiling_container_at(
 | 
				
			||||||
 | 
							struct sway_container *con, double lx, double ly,
 | 
				
			||||||
 | 
							struct wlr_surface **surface, double *sx, double *sy) {
 | 
				
			||||||
 | 
						if (con->type == C_VIEW) {
 | 
				
			||||||
 | 
							return container_at_view(con, lx, ly, surface, sx, sy);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (!con->children->length) {
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (con->layout) {
 | 
				
			||||||
 | 
						case L_HORIZ:
 | 
				
			||||||
 | 
						case L_VERT:
 | 
				
			||||||
 | 
							return container_at_linear(con, lx, ly, surface, sx, sy);
 | 
				
			||||||
 | 
						case L_TABBED:
 | 
				
			||||||
 | 
							return container_at_tabbed(con, lx, ly, surface, sx, sy);
 | 
				
			||||||
 | 
						case L_STACKED:
 | 
				
			||||||
 | 
							return container_at_stacked(con, lx, ly, surface, sx, sy);
 | 
				
			||||||
 | 
						case L_FLOATING:
 | 
				
			||||||
 | 
							sway_assert(false, "Didn't expect to see floating here");
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						case L_NONE:
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool surface_is_popup(struct wlr_surface *surface) {
 | 
				
			||||||
 | 
						if (wlr_surface_is_xdg_surface(surface)) {
 | 
				
			||||||
 | 
							struct wlr_xdg_surface *xdg_surface =
 | 
				
			||||||
 | 
								wlr_xdg_surface_from_wlr_surface(surface);
 | 
				
			||||||
 | 
							while (xdg_surface) {
 | 
				
			||||||
 | 
								if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP) {
 | 
				
			||||||
 | 
									return true;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								xdg_surface = xdg_surface->toplevel->parent;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (wlr_surface_is_xdg_surface_v6(surface)) {
 | 
				
			||||||
 | 
							struct wlr_xdg_surface_v6 *xdg_surface_v6 =
 | 
				
			||||||
 | 
								wlr_xdg_surface_v6_from_wlr_surface(surface);
 | 
				
			||||||
 | 
							while (xdg_surface_v6) {
 | 
				
			||||||
 | 
								if (xdg_surface_v6->role == WLR_XDG_SURFACE_V6_ROLE_POPUP) {
 | 
				
			||||||
 | 
									return true;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								xdg_surface_v6 = xdg_surface_v6->toplevel->parent;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct sway_container *container_at(struct sway_container *workspace,
 | 
				
			||||||
 | 
							double lx, double ly,
 | 
				
			||||||
 | 
							struct wlr_surface **surface, double *sx, double *sy) {
 | 
				
			||||||
 | 
						if (!sway_assert(workspace->type == C_WORKSPACE, "Expected a workspace")) {
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						struct sway_container *c;
 | 
				
			||||||
 | 
						// Focused view's popups
 | 
				
			||||||
 | 
						struct sway_seat *seat = input_manager_current_seat(input_manager);
 | 
				
			||||||
 | 
						struct sway_container *focus =
 | 
				
			||||||
 | 
							seat_get_focus_inactive(seat, &root_container);
 | 
				
			||||||
 | 
						if (focus && focus->type == C_VIEW) {
 | 
				
			||||||
 | 
							container_at_view(focus, lx, ly, surface, sx, sy);
 | 
				
			||||||
 | 
							if (*surface && surface_is_popup(*surface)) {
 | 
				
			||||||
 | 
								return focus;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							*surface = NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						// Floating
 | 
				
			||||||
 | 
						if ((c = floating_container_at(lx, ly, surface, sx, sy))) {
 | 
				
			||||||
 | 
							return c;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						// Tiling
 | 
				
			||||||
 | 
						if ((c = tiling_container_at(workspace, lx, ly, surface, sx, sy))) {
 | 
				
			||||||
 | 
							return c;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void container_for_each_descendant_dfs(struct sway_container *container,
 | 
					void container_for_each_descendant_dfs(struct sway_container *container,
 | 
				
			||||||
		void (*f)(struct sway_container *container, void *data),
 | 
							void (*f)(struct sway_container *container, void *data),
 | 
				
			||||||
		void *data) {
 | 
							void *data) {
 | 
				
			||||||
| 
						 | 
					@ -934,36 +1022,104 @@ size_t container_titlebar_height() {
 | 
				
			||||||
	return config->font_height + TITLEBAR_V_PADDING * 2;
 | 
						return config->font_height + TITLEBAR_V_PADDING * 2;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void container_init_floating(struct sway_container *con) {
 | 
				
			||||||
 | 
						if (!sway_assert(con->type == C_VIEW || con->type == C_CONTAINER,
 | 
				
			||||||
 | 
								"Expected a view or container")) {
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						struct sway_container *ws = container_parent(con, C_WORKSPACE);
 | 
				
			||||||
 | 
						int min_width, min_height;
 | 
				
			||||||
 | 
						int max_width, max_height;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (config->floating_minimum_width == -1) { // no minimum
 | 
				
			||||||
 | 
							min_width = 0;
 | 
				
			||||||
 | 
						} else if (config->floating_minimum_width == 0) { // automatic
 | 
				
			||||||
 | 
							min_width = 75;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							min_width = config->floating_minimum_width;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (config->floating_minimum_height == -1) { // no minimum
 | 
				
			||||||
 | 
							min_height = 0;
 | 
				
			||||||
 | 
						} else if (config->floating_minimum_height == 0) { // automatic
 | 
				
			||||||
 | 
							min_height = 50;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							min_height = config->floating_minimum_height;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (config->floating_maximum_width == -1) { // no maximum
 | 
				
			||||||
 | 
							max_width = INT_MAX;
 | 
				
			||||||
 | 
						} else if (config->floating_maximum_width == 0) { // automatic
 | 
				
			||||||
 | 
							max_width = ws->width * 0.6666;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							max_width = config->floating_maximum_width;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (config->floating_maximum_height == -1) { // no maximum
 | 
				
			||||||
 | 
							max_height = INT_MAX;
 | 
				
			||||||
 | 
						} else if (config->floating_maximum_height == 0) { // automatic
 | 
				
			||||||
 | 
							max_height = ws->height * 0.6666;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							max_height = config->floating_maximum_height;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (con->type == C_CONTAINER) {
 | 
				
			||||||
 | 
							con->width = max_width;
 | 
				
			||||||
 | 
							con->height = max_height;
 | 
				
			||||||
 | 
							con->x = ws->x + (ws->width - con->width) / 2;
 | 
				
			||||||
 | 
							con->y = ws->y + (ws->height - con->height) / 2;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							struct sway_view *view = con->sway_view;
 | 
				
			||||||
 | 
							view->width = fmax(min_width, fmin(view->natural_width, max_width));
 | 
				
			||||||
 | 
							view->height = fmax(min_height, fmin(view->natural_height, max_height));
 | 
				
			||||||
 | 
							view->x = ws->x + (ws->width - view->width) / 2;
 | 
				
			||||||
 | 
							view->y = ws->y + (ws->height - view->height) / 2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// If the view's border is B_NONE then these properties are ignored.
 | 
				
			||||||
 | 
							view->border_top = view->border_bottom = true;
 | 
				
			||||||
 | 
							view->border_left = view->border_right = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							container_set_geometry_from_floating_view(view->swayc);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void container_set_floating(struct sway_container *container, bool enable) {
 | 
					void container_set_floating(struct sway_container *container, bool enable) {
 | 
				
			||||||
	if (container_is_floating(container) == enable) {
 | 
						if (container_is_floating(container) == enable) {
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct sway_container *workspace = container_parent(container, C_WORKSPACE);
 | 
					 | 
				
			||||||
	struct sway_seat *seat = input_manager_current_seat(input_manager);
 | 
						struct sway_seat *seat = input_manager_current_seat(input_manager);
 | 
				
			||||||
 | 
						struct sway_container *workspace = container_parent(container, C_WORKSPACE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (enable) {
 | 
						if (enable) {
 | 
				
			||||||
		container_remove_child(container);
 | 
							container_remove_child(container);
 | 
				
			||||||
		container_add_child(workspace->sway_workspace->floating, container);
 | 
							container_add_child(workspace->sway_workspace->floating, container);
 | 
				
			||||||
 | 
							container_init_floating(container);
 | 
				
			||||||
		if (container->type == C_VIEW) {
 | 
							if (container->type == C_VIEW) {
 | 
				
			||||||
			view_init_floating(container->sway_view);
 | 
					 | 
				
			||||||
			view_set_tiled(container->sway_view, false);
 | 
								view_set_tiled(container->sway_view, false);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		seat_set_focus(seat, seat_get_focus_inactive(seat, container));
 | 
					 | 
				
			||||||
		container_reap_empty_recursive(workspace);
 | 
					 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		// Returning to tiled
 | 
							// Returning to tiled
 | 
				
			||||||
 | 
							if (container->scratchpad) {
 | 
				
			||||||
 | 
								scratchpad_remove_container(container);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		container_remove_child(container);
 | 
							container_remove_child(container);
 | 
				
			||||||
		container_add_child(workspace, container);
 | 
							struct sway_container *reference =
 | 
				
			||||||
 | 
								seat_get_focus_inactive_tiling(seat, workspace);
 | 
				
			||||||
 | 
							if (reference->type == C_VIEW) {
 | 
				
			||||||
 | 
								reference = reference->parent;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							container_add_child(reference, container);
 | 
				
			||||||
		container->width = container->parent->width;
 | 
							container->width = container->parent->width;
 | 
				
			||||||
		container->height = container->parent->height;
 | 
							container->height = container->parent->height;
 | 
				
			||||||
		if (container->type == C_VIEW) {
 | 
							if (container->type == C_VIEW) {
 | 
				
			||||||
			view_set_tiled(container->sway_view, true);
 | 
								view_set_tiled(container->sway_view, true);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		container->is_sticky = false;
 | 
							container->is_sticky = false;
 | 
				
			||||||
		container_reap_empty_recursive(workspace->sway_workspace->floating);
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						container_end_mouse_operation(container);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ipc_event_window(container, "floating");
 | 
						ipc_event_window(container, "floating");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1009,7 +1165,7 @@ void container_get_box(struct sway_container *container, struct wlr_box *box) {
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Translate the container's position as well as all children.
 | 
					 * Translate the container's position as well as all children.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static void container_floating_translate(struct sway_container *con,
 | 
					void container_floating_translate(struct sway_container *con,
 | 
				
			||||||
		double x_amount, double y_amount) {
 | 
							double x_amount, double y_amount) {
 | 
				
			||||||
	con->x += x_amount;
 | 
						con->x += x_amount;
 | 
				
			||||||
	con->y += y_amount;
 | 
						con->y += y_amount;
 | 
				
			||||||
| 
						 | 
					@ -1105,3 +1261,110 @@ static bool find_urgent_iterator(struct sway_container *con,
 | 
				
			||||||
bool container_has_urgent_child(struct sway_container *container) {
 | 
					bool container_has_urgent_child(struct sway_container *container) {
 | 
				
			||||||
	return container_find(container, find_urgent_iterator, NULL);
 | 
						return container_find(container, find_urgent_iterator, NULL);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void container_end_mouse_operation(struct sway_container *container) {
 | 
				
			||||||
 | 
						struct sway_seat *seat;
 | 
				
			||||||
 | 
						wl_list_for_each(seat, &input_manager->seats, link) {
 | 
				
			||||||
 | 
							if (seat->op_container == container) {
 | 
				
			||||||
 | 
								seat_end_mouse_operation(seat);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void set_fullscreen_iterator(struct sway_container *con, void *data) {
 | 
				
			||||||
 | 
						if (con->type != C_VIEW) {
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (con->sway_view->impl->set_fullscreen) {
 | 
				
			||||||
 | 
							bool *enable = data;
 | 
				
			||||||
 | 
							con->sway_view->impl->set_fullscreen(con->sway_view, *enable);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void container_set_fullscreen(struct sway_container *container, bool enable) {
 | 
				
			||||||
 | 
						if (container->is_fullscreen == enable) {
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct sway_container *workspace = container_parent(container, C_WORKSPACE);
 | 
				
			||||||
 | 
						if (enable && workspace->sway_workspace->fullscreen) {
 | 
				
			||||||
 | 
							container_set_fullscreen(workspace->sway_workspace->fullscreen, false);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						container_for_each_descendant_dfs(container,
 | 
				
			||||||
 | 
								set_fullscreen_iterator, &enable);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						container->is_fullscreen = enable;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (enable) {
 | 
				
			||||||
 | 
							workspace->sway_workspace->fullscreen = container;
 | 
				
			||||||
 | 
							container->saved_x = container->x;
 | 
				
			||||||
 | 
							container->saved_y = container->y;
 | 
				
			||||||
 | 
							container->saved_width = container->width;
 | 
				
			||||||
 | 
							container->saved_height = container->height;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							struct sway_seat *seat;
 | 
				
			||||||
 | 
							struct sway_container *focus, *focus_ws;
 | 
				
			||||||
 | 
							wl_list_for_each(seat, &input_manager->seats, link) {
 | 
				
			||||||
 | 
								focus = seat_get_focus(seat);
 | 
				
			||||||
 | 
								if (focus) {
 | 
				
			||||||
 | 
									focus_ws = focus;
 | 
				
			||||||
 | 
									if (focus_ws->type != C_WORKSPACE) {
 | 
				
			||||||
 | 
										focus_ws = container_parent(focus_ws, C_WORKSPACE);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									if (focus_ws == workspace) {
 | 
				
			||||||
 | 
										seat_set_focus(seat, container);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							workspace->sway_workspace->fullscreen = NULL;
 | 
				
			||||||
 | 
							if (container_is_floating(container)) {
 | 
				
			||||||
 | 
								container->x = container->saved_x;
 | 
				
			||||||
 | 
								container->y = container->saved_y;
 | 
				
			||||||
 | 
								container->width = container->saved_width;
 | 
				
			||||||
 | 
								container->height = container->saved_height;
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								container->width = container->saved_width;
 | 
				
			||||||
 | 
								container->height = container->saved_height;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						container_end_mouse_operation(container);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ipc_event_window(container, "fullscreen_mode");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool container_is_floating_or_child(struct sway_container *container) {
 | 
				
			||||||
 | 
						do {
 | 
				
			||||||
 | 
							if (container->parent && container->parent->layout == L_FLOATING) {
 | 
				
			||||||
 | 
								return true;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							container = container->parent;
 | 
				
			||||||
 | 
						} while (container && container->type != C_WORKSPACE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool container_is_fullscreen_or_child(struct sway_container *container) {
 | 
				
			||||||
 | 
						do {
 | 
				
			||||||
 | 
							if (container->is_fullscreen) {
 | 
				
			||||||
 | 
								return true;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							container = container->parent;
 | 
				
			||||||
 | 
						} while (container && container->type != C_WORKSPACE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct sway_container *container_wrap_children(struct sway_container *parent) {
 | 
				
			||||||
 | 
						struct sway_container *middle = container_create(C_CONTAINER);
 | 
				
			||||||
 | 
						middle->layout = parent->layout;
 | 
				
			||||||
 | 
						while (parent->children->length) {
 | 
				
			||||||
 | 
							struct sway_container *child = parent->children->items[0];
 | 
				
			||||||
 | 
							container_remove_child(child);
 | 
				
			||||||
 | 
							container_add_child(middle, child);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						container_add_child(parent, middle);
 | 
				
			||||||
 | 
						return middle;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6,6 +6,7 @@
 | 
				
			||||||
#include <string.h>
 | 
					#include <string.h>
 | 
				
			||||||
#include <wlr/types/wlr_output.h>
 | 
					#include <wlr/types/wlr_output.h>
 | 
				
			||||||
#include <wlr/types/wlr_output_layout.h>
 | 
					#include <wlr/types/wlr_output_layout.h>
 | 
				
			||||||
 | 
					#include "config.h"
 | 
				
			||||||
#include "sway/debug.h"
 | 
					#include "sway/debug.h"
 | 
				
			||||||
#include "sway/tree/arrange.h"
 | 
					#include "sway/tree/arrange.h"
 | 
				
			||||||
#include "sway/tree/container.h"
 | 
					#include "sway/tree/container.h"
 | 
				
			||||||
| 
						 | 
					@ -39,9 +40,12 @@ void layout_init(void) {
 | 
				
			||||||
	root_container.sway_root = calloc(1, sizeof(*root_container.sway_root));
 | 
						root_container.sway_root = calloc(1, sizeof(*root_container.sway_root));
 | 
				
			||||||
	root_container.sway_root->output_layout = wlr_output_layout_create();
 | 
						root_container.sway_root->output_layout = wlr_output_layout_create();
 | 
				
			||||||
	wl_list_init(&root_container.sway_root->outputs);
 | 
						wl_list_init(&root_container.sway_root->outputs);
 | 
				
			||||||
 | 
					#ifdef HAVE_XWAYLAND
 | 
				
			||||||
	wl_list_init(&root_container.sway_root->xwayland_unmanaged);
 | 
						wl_list_init(&root_container.sway_root->xwayland_unmanaged);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
	wl_list_init(&root_container.sway_root->drag_icons);
 | 
						wl_list_init(&root_container.sway_root->drag_icons);
 | 
				
			||||||
	wl_signal_init(&root_container.sway_root->events.new_container);
 | 
						wl_signal_init(&root_container.sway_root->events.new_container);
 | 
				
			||||||
 | 
						root_container.sway_root->scratchpad = create_list();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	root_container.sway_root->output_layout_change.notify =
 | 
						root_container.sway_root->output_layout_change.notify =
 | 
				
			||||||
		output_layout_handle_change;
 | 
							output_layout_handle_change;
 | 
				
			||||||
| 
						 | 
					@ -62,10 +66,9 @@ static int index_child(const struct sway_container *child) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void container_handle_fullscreen_reparent(struct sway_container *con,
 | 
					static void container_handle_fullscreen_reparent(struct sway_container *con,
 | 
				
			||||||
		struct sway_container *old_parent) {
 | 
							struct sway_container *old_parent) {
 | 
				
			||||||
	if (con->type != C_VIEW || !con->sway_view->is_fullscreen) {
 | 
						if (!con->is_fullscreen) {
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	struct sway_view *view = con->sway_view;
 | 
					 | 
				
			||||||
	struct sway_container *old_workspace = old_parent;
 | 
						struct sway_container *old_workspace = old_parent;
 | 
				
			||||||
	if (old_workspace && old_workspace->type != C_WORKSPACE) {
 | 
						if (old_workspace && old_workspace->type != C_WORKSPACE) {
 | 
				
			||||||
		old_workspace = container_parent(old_workspace, C_WORKSPACE);
 | 
							old_workspace = container_parent(old_workspace, C_WORKSPACE);
 | 
				
			||||||
| 
						 | 
					@ -81,19 +84,27 @@ static void container_handle_fullscreen_reparent(struct sway_container *con,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Mark the new workspace as fullscreen
 | 
						// Mark the new workspace as fullscreen
 | 
				
			||||||
	if (new_workspace->sway_workspace->fullscreen) {
 | 
						if (new_workspace->sway_workspace->fullscreen) {
 | 
				
			||||||
		view_set_fullscreen(new_workspace->sway_workspace->fullscreen, false);
 | 
							container_set_fullscreen(
 | 
				
			||||||
 | 
									new_workspace->sway_workspace->fullscreen, false);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	new_workspace->sway_workspace->fullscreen = view;
 | 
						new_workspace->sway_workspace->fullscreen = con;
 | 
				
			||||||
	// Resize view to new output dimensions
 | 
					
 | 
				
			||||||
 | 
						// Resize container to new output dimensions
 | 
				
			||||||
	struct sway_container *output = new_workspace->parent;
 | 
						struct sway_container *output = new_workspace->parent;
 | 
				
			||||||
	view->x = output->x;
 | 
					 | 
				
			||||||
	view->y = output->y;
 | 
					 | 
				
			||||||
	view->width = output->width;
 | 
					 | 
				
			||||||
	view->height = output->height;
 | 
					 | 
				
			||||||
	con->x = output->x;
 | 
						con->x = output->x;
 | 
				
			||||||
	con->y = output->y;
 | 
						con->y = output->y;
 | 
				
			||||||
	con->width = output->width;
 | 
						con->width = output->width;
 | 
				
			||||||
	con->height = output->height;
 | 
						con->height = output->height;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (con->type == C_VIEW) {
 | 
				
			||||||
 | 
							struct sway_view *view = con->sway_view;
 | 
				
			||||||
 | 
							view->x = output->x;
 | 
				
			||||||
 | 
							view->y = output->y;
 | 
				
			||||||
 | 
							view->width = output->width;
 | 
				
			||||||
 | 
							view->height = output->height;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							arrange_windows(new_workspace);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void container_insert_child(struct sway_container *parent,
 | 
					void container_insert_child(struct sway_container *parent,
 | 
				
			||||||
| 
						 | 
					@ -135,10 +146,14 @@ void container_add_child(struct sway_container *parent,
 | 
				
			||||||
	list_add(parent->children, child);
 | 
						list_add(parent->children, child);
 | 
				
			||||||
	child->parent = parent;
 | 
						child->parent = parent;
 | 
				
			||||||
	container_handle_fullscreen_reparent(child, old_parent);
 | 
						container_handle_fullscreen_reparent(child, old_parent);
 | 
				
			||||||
 | 
						if (old_parent) {
 | 
				
			||||||
 | 
							container_set_dirty(old_parent);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						container_set_dirty(child);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct sway_container *container_remove_child(struct sway_container *child) {
 | 
					struct sway_container *container_remove_child(struct sway_container *child) {
 | 
				
			||||||
	if (child->type == C_VIEW && child->sway_view->is_fullscreen) {
 | 
						if (child->is_fullscreen) {
 | 
				
			||||||
		struct sway_container *workspace = container_parent(child, C_WORKSPACE);
 | 
							struct sway_container *workspace = container_parent(child, C_WORKSPACE);
 | 
				
			||||||
		workspace->sway_workspace->fullscreen = NULL;
 | 
							workspace->sway_workspace->fullscreen = NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -153,6 +168,9 @@ struct sway_container *container_remove_child(struct sway_container *child) {
 | 
				
			||||||
	child->parent = NULL;
 | 
						child->parent = NULL;
 | 
				
			||||||
	container_notify_subtree_changed(parent);
 | 
						container_notify_subtree_changed(parent);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						container_set_dirty(parent);
 | 
				
			||||||
 | 
						container_set_dirty(child);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return parent;
 | 
						return parent;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -199,7 +217,9 @@ void container_move_to(struct sway_container *container,
 | 
				
			||||||
		container_sort_workspaces(new_parent);
 | 
							container_sort_workspaces(new_parent);
 | 
				
			||||||
		seat_set_focus(seat, new_parent);
 | 
							seat_set_focus(seat, new_parent);
 | 
				
			||||||
		workspace_output_raise_priority(container, old_parent, new_parent);
 | 
							workspace_output_raise_priority(container, old_parent, new_parent);
 | 
				
			||||||
		ipc_event_workspace(container, NULL, "move");
 | 
							ipc_event_workspace(NULL, container, "move");
 | 
				
			||||||
 | 
						} else if (container->type == C_VIEW) {
 | 
				
			||||||
 | 
							ipc_event_window(container, "move");
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	container_notify_subtree_changed(old_parent);
 | 
						container_notify_subtree_changed(old_parent);
 | 
				
			||||||
	container_notify_subtree_changed(new_parent);
 | 
						container_notify_subtree_changed(new_parent);
 | 
				
			||||||
| 
						 | 
					@ -218,10 +238,10 @@ void container_move_to(struct sway_container *container,
 | 
				
			||||||
			if (focus_ws->type != C_WORKSPACE) {
 | 
								if (focus_ws->type != C_WORKSPACE) {
 | 
				
			||||||
				focus_ws = container_parent(focus_ws, C_WORKSPACE);
 | 
									focus_ws = container_parent(focus_ws, C_WORKSPACE);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			seat_set_focus(seat,
 | 
								if (focus_ws == new_workspace) {
 | 
				
			||||||
					new_workspace->sway_workspace->fullscreen->swayc);
 | 
									struct sway_container *new_focus = seat_get_focus_inactive(seat,
 | 
				
			||||||
			if (focus_ws != new_workspace) {
 | 
											new_workspace->sway_workspace->fullscreen);
 | 
				
			||||||
				seat_set_focus(seat, focus);
 | 
									seat_set_focus(seat, new_focus);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -364,10 +384,18 @@ void container_move(struct sway_container *container,
 | 
				
			||||||
	struct sway_container *sibling = NULL;
 | 
						struct sway_container *sibling = NULL;
 | 
				
			||||||
	struct sway_container *current = container;
 | 
						struct sway_container *current = container;
 | 
				
			||||||
	struct sway_container *parent = current->parent;
 | 
						struct sway_container *parent = current->parent;
 | 
				
			||||||
 | 
						struct sway_container *top = &root_container;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// If moving a fullscreen view, only consider outputs
 | 
						// If moving a fullscreen view, only consider outputs
 | 
				
			||||||
	if (container->type == C_VIEW && container->sway_view->is_fullscreen) {
 | 
						if (container->is_fullscreen) {
 | 
				
			||||||
		current = container_parent(container, C_OUTPUT);
 | 
							current = container_parent(container, C_OUTPUT);
 | 
				
			||||||
 | 
						} else if (container_is_fullscreen_or_child(container) ||
 | 
				
			||||||
 | 
								container_is_floating_or_child(container)) {
 | 
				
			||||||
 | 
							// If we've fullscreened a split container, only allow the child to move
 | 
				
			||||||
 | 
							// around within the fullscreen parent.
 | 
				
			||||||
 | 
							// Same with floating a split container.
 | 
				
			||||||
 | 
							struct sway_container *ws = container_parent(container, C_WORKSPACE);
 | 
				
			||||||
 | 
							top = ws->sway_workspace->fullscreen;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct sway_container *new_parent = container_flatten(parent);
 | 
						struct sway_container *new_parent = container_flatten(parent);
 | 
				
			||||||
| 
						 | 
					@ -377,7 +405,7 @@ void container_move(struct sway_container *container,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	while (!sibling) {
 | 
						while (!sibling) {
 | 
				
			||||||
		if (current->type == C_ROOT) {
 | 
							if (current == top) {
 | 
				
			||||||
			return;
 | 
								return;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -441,8 +469,12 @@ void container_move(struct sway_container *container,
 | 
				
			||||||
				if ((index == parent->children->length - 1 && offs > 0)
 | 
									if ((index == parent->children->length - 1 && offs > 0)
 | 
				
			||||||
						|| (index == 0 && offs < 0)) {
 | 
											|| (index == 0 && offs < 0)) {
 | 
				
			||||||
					if (current->parent == container->parent) {
 | 
										if (current->parent == container->parent) {
 | 
				
			||||||
						if (parent->layout == L_TABBED
 | 
											if (parent->parent->layout == L_FLOATING) {
 | 
				
			||||||
								|| parent->layout == L_STACKED) {
 | 
												return;
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
											if (!parent->is_fullscreen &&
 | 
				
			||||||
 | 
													(parent->layout == L_TABBED ||
 | 
				
			||||||
 | 
													 parent->layout == L_STACKED)) {
 | 
				
			||||||
							move_out_of_tabs_stacks(container, current,
 | 
												move_out_of_tabs_stacks(container, current,
 | 
				
			||||||
									move_dir, offs);
 | 
														move_dir, offs);
 | 
				
			||||||
							return;
 | 
												return;
 | 
				
			||||||
| 
						 | 
					@ -463,10 +495,14 @@ void container_move(struct sway_container *container,
 | 
				
			||||||
					sibling = parent->children->items[index + offs];
 | 
										sibling = parent->children->items[index + offs];
 | 
				
			||||||
					wlr_log(WLR_DEBUG, "Selecting sibling id:%zd", sibling->id);
 | 
										wlr_log(WLR_DEBUG, "Selecting sibling id:%zd", sibling->id);
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			} else if (parent->layout == L_TABBED
 | 
								} else if (!parent->is_fullscreen &&
 | 
				
			||||||
					|| parent->layout == L_STACKED) {
 | 
										parent->parent->layout != L_FLOATING &&
 | 
				
			||||||
 | 
										(parent->layout == L_TABBED ||
 | 
				
			||||||
 | 
											parent->layout == L_STACKED)) {
 | 
				
			||||||
				move_out_of_tabs_stacks(container, current, move_dir, offs);
 | 
									move_out_of_tabs_stacks(container, current, move_dir, offs);
 | 
				
			||||||
				return;
 | 
									return;
 | 
				
			||||||
 | 
								} else if (parent->parent->layout == L_FLOATING) {
 | 
				
			||||||
 | 
									return;
 | 
				
			||||||
			} else {
 | 
								} else {
 | 
				
			||||||
				wlr_log(WLR_DEBUG, "Moving up to find a parallel container");
 | 
									wlr_log(WLR_DEBUG, "Moving up to find a parallel container");
 | 
				
			||||||
				current = current->parent;
 | 
									current = current->parent;
 | 
				
			||||||
| 
						 | 
					@ -544,6 +580,10 @@ void container_move(struct sway_container *container,
 | 
				
			||||||
	container_notify_subtree_changed(old_parent);
 | 
						container_notify_subtree_changed(old_parent);
 | 
				
			||||||
	container_notify_subtree_changed(container->parent);
 | 
						container_notify_subtree_changed(container->parent);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (container->type == C_VIEW) {
 | 
				
			||||||
 | 
							ipc_event_window(container, "move");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (old_parent) {
 | 
						if (old_parent) {
 | 
				
			||||||
		seat_set_focus(config->handler_context.seat, old_parent);
 | 
							seat_set_focus(config->handler_context.seat, old_parent);
 | 
				
			||||||
		seat_set_focus(config->handler_context.seat, container);
 | 
							seat_set_focus(config->handler_context.seat, container);
 | 
				
			||||||
| 
						 | 
					@ -558,10 +598,11 @@ void container_move(struct sway_container *container,
 | 
				
			||||||
		next_ws = container_parent(next_ws, C_WORKSPACE);
 | 
							next_ws = container_parent(next_ws, C_WORKSPACE);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (last_ws && next_ws && last_ws != next_ws) {
 | 
						if (last_ws && next_ws && last_ws != next_ws) {
 | 
				
			||||||
		ipc_event_workspace(last_ws, container, "focus");
 | 
							ipc_event_workspace(last_ws, next_ws, "focus");
 | 
				
			||||||
		workspace_detect_urgent(last_ws);
 | 
							workspace_detect_urgent(last_ws);
 | 
				
			||||||
		workspace_detect_urgent(next_ws);
 | 
							workspace_detect_urgent(next_ws);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						container_end_mouse_operation(container);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum sway_container_layout container_get_default_layout(
 | 
					enum sway_container_layout container_get_default_layout(
 | 
				
			||||||
| 
						 | 
					@ -691,22 +732,18 @@ struct sway_container *container_get_in_direction(
 | 
				
			||||||
		enum movement_direction dir) {
 | 
							enum movement_direction dir) {
 | 
				
			||||||
	struct sway_container *parent = container->parent;
 | 
						struct sway_container *parent = container->parent;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (container_is_floating(container)) {
 | 
						if (dir == MOVE_CHILD) {
 | 
				
			||||||
		return NULL;
 | 
							return seat_get_focus_inactive(seat, container);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if (container->is_fullscreen) {
 | 
				
			||||||
	if (container->type == C_VIEW && container->sway_view->is_fullscreen) {
 | 
							if (dir == MOVE_PARENT) {
 | 
				
			||||||
		if (dir == MOVE_PARENT || dir == MOVE_CHILD) {
 | 
					 | 
				
			||||||
			return NULL;
 | 
								return NULL;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		container = container_parent(container, C_OUTPUT);
 | 
							container = container_parent(container, C_OUTPUT);
 | 
				
			||||||
		parent = container->parent;
 | 
							parent = container->parent;
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		if (dir == MOVE_CHILD) {
 | 
					 | 
				
			||||||
			return seat_get_focus_inactive(seat, container);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if (dir == MOVE_PARENT) {
 | 
							if (dir == MOVE_PARENT) {
 | 
				
			||||||
			if (parent->type == C_OUTPUT) {
 | 
								if (parent->type == C_OUTPUT || container_is_floating(container)) {
 | 
				
			||||||
				return NULL;
 | 
									return NULL;
 | 
				
			||||||
			} else {
 | 
								} else {
 | 
				
			||||||
				return parent;
 | 
									return parent;
 | 
				
			||||||
| 
						 | 
					@ -755,7 +792,8 @@ struct sway_container *container_get_in_direction(
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			sway_assert(next_workspace, "Next container has no workspace");
 | 
								sway_assert(next_workspace, "Next container has no workspace");
 | 
				
			||||||
			if (next_workspace->sway_workspace->fullscreen) {
 | 
								if (next_workspace->sway_workspace->fullscreen) {
 | 
				
			||||||
				return next_workspace->sway_workspace->fullscreen->swayc;
 | 
									return seat_get_focus_inactive(seat,
 | 
				
			||||||
 | 
											next_workspace->sway_workspace->fullscreen);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			if (next->children && next->children->length) {
 | 
								if (next->children && next->children->length) {
 | 
				
			||||||
				// TODO consider floating children as well
 | 
									// TODO consider floating children as well
 | 
				
			||||||
| 
						 | 
					@ -963,13 +1001,13 @@ static void swap_focus(struct sway_container *con1,
 | 
				
			||||||
		if (focus == con1 && (con2->parent->layout == L_TABBED
 | 
							if (focus == con1 && (con2->parent->layout == L_TABBED
 | 
				
			||||||
					|| con2->parent->layout == L_STACKED)) {
 | 
										|| con2->parent->layout == L_STACKED)) {
 | 
				
			||||||
			if (workspace_is_visible(ws2)) {
 | 
								if (workspace_is_visible(ws2)) {
 | 
				
			||||||
				seat_set_focus_warp(seat, con2, false);
 | 
									seat_set_focus_warp(seat, con2, false, true);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			seat_set_focus(seat, ws1 != ws2 ? con2 : con1);
 | 
								seat_set_focus(seat, ws1 != ws2 ? con2 : con1);
 | 
				
			||||||
		} else if (focus == con2 && (con1->parent->layout == L_TABBED
 | 
							} else if (focus == con2 && (con1->parent->layout == L_TABBED
 | 
				
			||||||
					|| con1->parent->layout == L_STACKED)) {
 | 
										|| con1->parent->layout == L_STACKED)) {
 | 
				
			||||||
			if (workspace_is_visible(ws1)) {
 | 
								if (workspace_is_visible(ws1)) {
 | 
				
			||||||
				seat_set_focus_warp(seat, con1, false);
 | 
									seat_set_focus_warp(seat, con1, false, true);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			seat_set_focus(seat, ws1 != ws2 ? con1 : con2);
 | 
								seat_set_focus(seat, ws1 != ws2 ? con1 : con2);
 | 
				
			||||||
		} else if (ws1 != ws2) {
 | 
							} else if (ws1 != ws2) {
 | 
				
			||||||
| 
						 | 
					@ -1002,13 +1040,13 @@ void container_swap(struct sway_container *con1, struct sway_container *con2) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wlr_log(WLR_DEBUG, "Swapping containers %zu and %zu", con1->id, con2->id);
 | 
						wlr_log(WLR_DEBUG, "Swapping containers %zu and %zu", con1->id, con2->id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int fs1 = con1->type == C_VIEW && con1->sway_view->is_fullscreen;
 | 
						int fs1 = con1->is_fullscreen;
 | 
				
			||||||
	int fs2 = con2->type == C_VIEW && con2->sway_view->is_fullscreen;
 | 
						int fs2 = con2->is_fullscreen;
 | 
				
			||||||
	if (fs1) {
 | 
						if (fs1) {
 | 
				
			||||||
		view_set_fullscreen(con1->sway_view, false);
 | 
							container_set_fullscreen(con1, false);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (fs2) {
 | 
						if (fs2) {
 | 
				
			||||||
		view_set_fullscreen(con2->sway_view, false);
 | 
							container_set_fullscreen(con2, false);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct sway_seat *seat = input_manager_get_default_seat(input_manager);
 | 
						struct sway_seat *seat = input_manager_get_default_seat(input_manager);
 | 
				
			||||||
| 
						 | 
					@ -1041,10 +1079,10 @@ void container_swap(struct sway_container *con1, struct sway_container *con2) {
 | 
				
			||||||
		prev_workspace_name = stored_prev_name;
 | 
							prev_workspace_name = stored_prev_name;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (fs1 && con2->type == C_VIEW) {
 | 
						if (fs1) {
 | 
				
			||||||
		view_set_fullscreen(con2->sway_view, true);
 | 
							container_set_fullscreen(con2, true);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (fs2 && con1->type == C_VIEW) {
 | 
						if (fs2) {
 | 
				
			||||||
		view_set_fullscreen(con1->sway_view, true);
 | 
							container_set_fullscreen(con1, true);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -22,7 +22,7 @@ static void restore_workspaces(struct sway_container *output) {
 | 
				
			||||||
			if (highest == output) {
 | 
								if (highest == output) {
 | 
				
			||||||
				container_remove_child(ws);
 | 
									container_remove_child(ws);
 | 
				
			||||||
				container_add_child(output, ws);
 | 
									container_add_child(output, ws);
 | 
				
			||||||
				ipc_event_workspace(ws, NULL, "move");
 | 
									ipc_event_workspace(NULL, ws, "move");
 | 
				
			||||||
				j--;
 | 
									j--;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
Some files were not shown because too many files have changed in this diff Show more
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue