mirror of
				https://github.com/wizbright/waybox.git
				synced 2025-11-03 09:01:45 -05:00 
			
		
		
		
	Compare commits
	
		
			No commits in common. "master" and "0.2.1" have entirely different histories.
		
	
	
		
	
		
					 41 changed files with 518 additions and 1261 deletions
				
			
		
							
								
								
									
										19
									
								
								.build.yml
									
										
									
									
									
								
							
							
						
						
									
										19
									
								
								.build.yml
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -3,27 +3,20 @@
 | 
			
		|||
#
 | 
			
		||||
image: archlinux
 | 
			
		||||
packages:
 | 
			
		||||
  - clang
 | 
			
		||||
  - gcc
 | 
			
		||||
  - libevdev
 | 
			
		||||
  - libinput
 | 
			
		||||
  - libxkbcommon
 | 
			
		||||
  - libxml2
 | 
			
		||||
  - meson
 | 
			
		||||
  - wayland
 | 
			
		||||
  - wayland-protocols
 | 
			
		||||
  - wlroots-git
 | 
			
		||||
  - libinput
 | 
			
		||||
  - libxkbcommon
 | 
			
		||||
  - libxml2
 | 
			
		||||
  - wlroots
 | 
			
		||||
  - xorg-server-xwayland
 | 
			
		||||
sources:
 | 
			
		||||
  - https://github.com/wizbright/waybox
 | 
			
		||||
tasks:
 | 
			
		||||
  - setup: |
 | 
			
		||||
      cd waybox
 | 
			
		||||
      CC=gcc meson setup build-gcc
 | 
			
		||||
      meson setup build
 | 
			
		||||
  - build: |
 | 
			
		||||
      cd waybox
 | 
			
		||||
      ninja -C build-gcc
 | 
			
		||||
  - clang: |
 | 
			
		||||
      cd waybox
 | 
			
		||||
      CC=clang meson setup build-clang
 | 
			
		||||
      ninja -C build-clang
 | 
			
		||||
      ninja -C build
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,7 +14,7 @@ block_comment_start = /*
 | 
			
		|||
block_comment_end = */
 | 
			
		||||
 | 
			
		||||
curly_bracket_next_line = false
 | 
			
		||||
max_line_length = 100
 | 
			
		||||
max_line_length = 80
 | 
			
		||||
spaces_around_brackets = outside
 | 
			
		||||
spaces_around_operators = true
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										20
									
								
								.github/workflows/build.yml
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										20
									
								
								.github/workflows/build.yml
									
										
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -12,18 +12,18 @@ on: [push, pull_request]
 | 
			
		|||
jobs:
 | 
			
		||||
    build:
 | 
			
		||||
        runs-on: ubuntu-latest
 | 
			
		||||
        container: alpine:edge
 | 
			
		||||
        container: archlinux:base-devel
 | 
			
		||||
        steps:
 | 
			
		||||
            - name: packages
 | 
			
		||||
              run: |
 | 
			
		||||
                apk add clang gcc libevdev-dev libinput-dev libxkbcommon-dev libxml2-dev meson musl-dev wayland-dev wayland-protocols wlroots wlroots-dev xwayland
 | 
			
		||||
            # actions/checkout@v4 clones the repository
 | 
			
		||||
            - uses: actions/checkout@v4
 | 
			
		||||
            - name: build-gcc
 | 
			
		||||
                pacman-key --init
 | 
			
		||||
                pacman -Syu --noconfirm
 | 
			
		||||
                pacman -S --noconfirm git meson libxkbcommon libinput libxml2 wayland wayland-protocols wlroots xorg-server-xwayland
 | 
			
		||||
            # actions/checkout@v2 clones the repository
 | 
			
		||||
            - uses: actions/checkout@v2
 | 
			
		||||
            - name: setup
 | 
			
		||||
              run: |
 | 
			
		||||
                CC=gcc meson setup build-gcc
 | 
			
		||||
                ninja -C build-gcc
 | 
			
		||||
            - name: build-clang
 | 
			
		||||
                meson setup build
 | 
			
		||||
            - name: build
 | 
			
		||||
              run: |
 | 
			
		||||
                CC=clang meson setup build-clang
 | 
			
		||||
                ninja -C build-clang
 | 
			
		||||
                ninja -C build
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -136,7 +136,7 @@ Try to break the line in the place which you think is the most appropriate.
 | 
			
		|||
 | 
			
		||||
### Line Length
 | 
			
		||||
 | 
			
		||||
Try to keep your lines under 100 columns, but you can break this rule if it
 | 
			
		||||
Try to keep your lines under 80 columns, but you can go up to 100 if it
 | 
			
		||||
improves readability. Don't break lines indiscriminately, try to find nice
 | 
			
		||||
breaking points so your code is easy to read.
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										39
									
								
								README.md
									
										
									
									
									
								
							
							
						
						
									
										39
									
								
								README.md
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -1,10 +1,8 @@
 | 
			
		|||
# Waybox
 | 
			
		||||
 | 
			
		||||
A \*box-style (minimalist) Wayland compositor modeled largely on Openbox (WIP)
 | 
			
		||||
An Openbox clone on Wayland (WIP)
 | 
			
		||||
 | 
			
		||||
### Goals
 | 
			
		||||
 | 
			
		||||
The main goal of this project is to provide a similar feel to \*box-style window managers but on Wayland
 | 
			
		||||
The main goal of this project is to provide a similar feel to Openbox but on Wayland
 | 
			
		||||
 | 
			
		||||
### Contributing
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -13,15 +11,14 @@ contributing.](https://github.com/wizbright/waybox/blob/master/CONTRIBUTING.md)
 | 
			
		|||
 | 
			
		||||
### Dependencies
 | 
			
		||||
 | 
			
		||||
* [Meson](https://mesonbuild.com/) or [muon](http://muon.build)
 | 
			
		||||
* [Wayland](https://wayland.freedesktop.org/)
 | 
			
		||||
* [libevdev](https://www.freedesktop.org/wiki/Software/libevdev/)
 | 
			
		||||
* [libinput](http://www.freedesktop.org/wiki/Software/libinput)
 | 
			
		||||
* [libxml2](http://xmlsoft.org/)
 | 
			
		||||
* [Meson](https://mesonbuild.com/)
 | 
			
		||||
* [wlroots](https://gitlab.freedesktop.org/wlroots/wlroots/)
 | 
			
		||||
* [libxml2](http://xmlsoft.org/)
 | 
			
		||||
* [Wayland](https://wayland.freedesktop.org/)
 | 
			
		||||
* [xkbcommon](https://xkbcommon.org/)
 | 
			
		||||
 | 
			
		||||
### Build instructions
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
meson setup build
 | 
			
		||||
cd build
 | 
			
		||||
| 
						 | 
				
			
			@ -30,30 +27,6 @@ ninja
 | 
			
		|||
 | 
			
		||||
After that, you should have an executable as waybox/waybox
 | 
			
		||||
 | 
			
		||||
For those who don't want to use a Python-based build system, it's also possible
 | 
			
		||||
to use muon instead of Meson.
 | 
			
		||||
 | 
			
		||||
### Screenshots
 | 
			
		||||
 | 
			
		||||

 | 
			
		||||
 | 
			
		||||

 | 
			
		||||
 | 
			
		||||

 | 
			
		||||
 | 
			
		||||
### Useful Programs
 | 
			
		||||
 | 
			
		||||
Because \*box-style compositors are minimalist, most functionality is left to external programs.  As such, Waybox only functions as a box in which you can put whatever you need.  Here are some useful programs to complement Waybox if you desire:
 | 
			
		||||
 | 
			
		||||
* Panel: You can use [Waybar](https://github.com/Alexays/Waybar) or [yambar](https://codeberg.org/dnkl/yambar), similar to tint2 or fbpanel in Openbox or Fluxbox.
 | 
			
		||||
* Dock: You can use [Cairo Dock](https://www.glx-dock.org/) just like you did on Openbox.  There's also a [port with Wayland-specific enhancements](https://github.com/dkondor/cairo-dock-core/) that you may want to try. A much more compact option is [LavaLauncher](https://sr.ht/~leon_plickat/LavaLauncher/), but it's much harder to configure.
 | 
			
		||||
* Wallpaper utility: There are various utilities to set your wallpaper, each with their own advantages, including [wpaperd](https://github.com/danyspin97/wpaperd) (can select a random wallpaper from a directory), [swaybg](https://github.com/swaywm/swaybg) (can set the background color as well well as a wallpaper), and [hyprpaper](https://github.com/hyprwm/hyprpaper) (can change the wallpaper dynamically during runtime through IPC).
 | 
			
		||||
* Notification client: [mako](https://wayland.emersion.fr/mako/)
 | 
			
		||||
* [wl-clipboard](https://wayland.emersion.fr/mako/): Access the clipboard in scripts (also used by [neovim](https://neovim.io/))
 | 
			
		||||
* Screenshots: [grim](https://git.sr.ht/~emersion/grim) and [slurp](https://github.com/emersion/slurp)
 | 
			
		||||
* Screen recording: [wf-recorder](https://github.com/ammen99/wf-recorder)
 | 
			
		||||
* Menu support: [rofi-wayland](https://github.com/lbonn/rofi)
 | 
			
		||||
 | 
			
		||||
### Contact
 | 
			
		||||
I can be found as wiz on Rizon and wizbright on Libera. 
 | 
			
		||||
Join [#waybox](https://libera.chat/guides/connect) for discussion
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,48 +23,15 @@ cairo-dock &
 | 
			
		|||
mako &
 | 
			
		||||
 | 
			
		||||
# Load a random wallpaper
 | 
			
		||||
get_random_wallpaper()
 | 
			
		||||
{
 | 
			
		||||
    oldifs=$IFS
 | 
			
		||||
    IFS=:
 | 
			
		||||
    data_dirs=${XDG_DATA_DIRS:-${datadir:-/usr/share}}:${XDG_DATA_HOME:-~/.local/share}
 | 
			
		||||
    for data_dir in $data_dirs;do
 | 
			
		||||
        IFS=$oldifs
 | 
			
		||||
oldifs=$IFS
 | 
			
		||||
IFS=:
 | 
			
		||||
data_dirs=${XDG_DATA_DIRS:-${datadir:-/usr/share}}:${XDG_DATA_HOME:-~/.local/share}
 | 
			
		||||
for data_dir in $data_dirs;
 | 
			
		||||
do
 | 
			
		||||
    wpdir="$data_dir/wallpapers"
 | 
			
		||||
    test -d "$wpdir" && \
 | 
			
		||||
        find $wpdir -name '*.jpg' -o -name '*.png' -o -name '*.svg'
 | 
			
		||||
    done | (shuf -n 1 || tail -n 1)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
load_wallpaper() {
 | 
			
		||||
    uses_wayland_info=0
 | 
			
		||||
    if (which hyprpaper && which socat && (test "$uses_wayland_info" = "0" || which wayland-info)) >/dev/null 2>&1; then
 | 
			
		||||
        hyprpaper &
 | 
			
		||||
        HYPRPAPER_SOCKET="${XDG_RUNTIME_DIR:-"/run/user/$(id -u)"}"/hypr/.hyprpaper.sock
 | 
			
		||||
        # Change the wallpaper every hour
 | 
			
		||||
        while test -S "$HYPRPAPER_SOCKET"; do
 | 
			
		||||
            if test "$uses_wayland_info" != "0";
 | 
			
		||||
            then
 | 
			
		||||
                current_output=$(wayland-info -i wl_output | \
 | 
			
		||||
                    grep 'name:' | tail -n 1 | cut -d : -f 2 | tr -d ' ')
 | 
			
		||||
            fi
 | 
			
		||||
            random_wallpaper="$(get_random_wallpaper)"
 | 
			
		||||
            for cmd in "preload $random_wallpaper" \
 | 
			
		||||
                "wallpaper $current_output,$random_wallpaper" \
 | 
			
		||||
                'unload all';
 | 
			
		||||
            do
 | 
			
		||||
                printf "$cmd" | socat UNIX-CONNECT:"$HYPRPAPER_SOCKET" -
 | 
			
		||||
            done
 | 
			
		||||
            [ $? -ne 0 ] && rm -f $HYPRPAPER_SOCKET
 | 
			
		||||
            sleep 60m
 | 
			
		||||
        done
 | 
			
		||||
    elif which swaybg >/dev/null 2>&1; then
 | 
			
		||||
        get_random_wallpaper | xargs swaybg -c '#303030' -m fill -i &
 | 
			
		||||
    elif which wpaperd >/dev/null 2>&1; then
 | 
			
		||||
        wpaperd &
 | 
			
		||||
    fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
load_wallpaper &
 | 
			
		||||
done | (shuf -n 1 || tail -n 1) | xargs swaybg -m fill -i &
 | 
			
		||||
IFS=$oldifs
 | 
			
		||||
 | 
			
		||||
# vim: ft=sh
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -30,25 +30,17 @@ if test -n "$DISPLAY" && test -d /etc/X11/xinit/xinitrc.d;
 | 
			
		|||
then
 | 
			
		||||
    for f in /etc/X11/xinit/xinitrc.d/*.sh;
 | 
			
		||||
    do
 | 
			
		||||
        test -r "$f" && . "$f"
 | 
			
		||||
        test -f "$f" && . "$f"
 | 
			
		||||
    done
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
# Emerging standard, used by i.a. modern GTK versions instead of the obsolete
 | 
			
		||||
# org.gnome.default-applications.terminal.exec gsetting (which is now ignored)
 | 
			
		||||
# https://github.com/Vladimir-csp/xdg-terminal-exec (or create a symlink to
 | 
			
		||||
# your preferred terminal emulator)
 | 
			
		||||
TERMINAL=xdg-terminal-exec
 | 
			
		||||
# Get the preferred terminal from GNOME (if you use mostly GTK apps)
 | 
			
		||||
TERMINAL=$(gsettings get org.gnome.desktop.default-applications.terminal exec | tr -d \')
 | 
			
		||||
# Get the preferred terminal from KDE (if you use mostly Qt apps)
 | 
			
		||||
#TERMINAL=$(kreadconfig5 --file kdeglobals --group General --key TerminalApplication --default "konsole")
 | 
			
		||||
# Or just set it hard:
 | 
			
		||||
#TERMINAL=kitty
 | 
			
		||||
export TERMINAL
 | 
			
		||||
 | 
			
		||||
if command -v xdg-autostart >/dev/null 2>&1;
 | 
			
		||||
then
 | 
			
		||||
    export XDG_CURRENT_DESTKOP=OPENBOX
 | 
			
		||||
else
 | 
			
		||||
    # Use autostart scripts for these environments
 | 
			
		||||
    export WB_AUTOSTART_ENVIRONMENT=GNOME:KDE:OPENBOX
 | 
			
		||||
fi
 | 
			
		||||
# Use autostart scripts for these environments
 | 
			
		||||
export WB_AUTOSTART_ENVIRONMENT=GNOME:KDE
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										71
									
								
								data/menu
									
										
									
									
									
								
							
							
						
						
									
										71
									
								
								data/menu
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -1,71 +0,0 @@
 | 
			
		|||
#!/bin/env python
 | 
			
		||||
 | 
			
		||||
import os, subprocess, sys
 | 
			
		||||
import shlex
 | 
			
		||||
import xml.dom.minidom as dom
 | 
			
		||||
 | 
			
		||||
def get_waybox_pid(name='waybox'):
 | 
			
		||||
    lines = subprocess.Popen(['pgrep', '-x', name], stdout=subprocess.PIPE).stdout.read().splitlines()
 | 
			
		||||
    if lines:
 | 
			
		||||
        return int(lines[0])
 | 
			
		||||
    else:
 | 
			
		||||
        return 0
 | 
			
		||||
 | 
			
		||||
def get_menu_items(menu, indent, expand):
 | 
			
		||||
    menu_id = menu.getAttribute('id')
 | 
			
		||||
    nonselectable = str(bool(menu_id == '')).lower()
 | 
			
		||||
    print("%s%s ⇢\0info\x1f{\"menu\": \"%s\"}\x1fnonselectable\x1f%s" % (indent, menu.getAttribute('label').replace('_', '') or menu_id, menu_id, nonselectable))
 | 
			
		||||
    indent = indent + " "
 | 
			
		||||
    children = menu.childNodes
 | 
			
		||||
    for i in range(0, children.length):
 | 
			
		||||
        if expand:
 | 
			
		||||
            if children[i].nodeType == dom.Node.ELEMENT_NODE and children[i].tagName == 'item':
 | 
			
		||||
                action = children[i].getElementsByTagName('action')[0].getAttribute('name')
 | 
			
		||||
                cmd = ""
 | 
			
		||||
                icon = children[i].getAttribute('icon')
 | 
			
		||||
                label = children[i].getAttribute('label').replace('_', '')
 | 
			
		||||
                if action == 'Execute':
 | 
			
		||||
                    cmd = children[i].getElementsByTagName('execute')[0].firstChild.nodeValue
 | 
			
		||||
                elif action == 'Exit':
 | 
			
		||||
                    cmd = "kill -s SIGTERM %d" % get_waybox_pid()
 | 
			
		||||
                elif action == 'Reconfigure':
 | 
			
		||||
                    cmd = "kill -s SIGUSR2 %d" % get_waybox_pid()
 | 
			
		||||
                print("%s\0info\x1f{\"exec\": \"%s\"}\x1ficon\x1f%s\x1fdisplay\x1f%s %s" % (cmd, cmd.replace('"', '\\"'), icon, indent, label))
 | 
			
		||||
            elif children[i].nodeType == dom.Node.ELEMENT_NODE and children[i].tagName == 'menu':
 | 
			
		||||
                if children[i].getAttribute('execute') == "":
 | 
			
		||||
                    get_menu_items(children[i], indent, os.getenv('ROFI_RETV') is None)
 | 
			
		||||
                else:
 | 
			
		||||
                    try:
 | 
			
		||||
                        import xml.parsers.expat
 | 
			
		||||
                        lines = subprocess.Popen(shlex.split(children[i].getAttribute('execute')), stdout=subprocess.PIPE).stdout.read()
 | 
			
		||||
                        pipe = dom.parseString(lines)
 | 
			
		||||
                        pipes = pipe.getElementsByTagName('menu')
 | 
			
		||||
                        for j in range(0, pipes.length):
 | 
			
		||||
                            get_menu_items(pipes[j], indent, True)
 | 
			
		||||
                    # If a script doesn't function correctly anymore, don't stop rendering the menu
 | 
			
		||||
                    except xml.parsers.expat.ExpatError:
 | 
			
		||||
                        pass
 | 
			
		||||
 | 
			
		||||
menu_xml = os.getenv("WB_MENU_XML") or "menu.xml"
 | 
			
		||||
document = dom.parse(menu_xml)
 | 
			
		||||
 | 
			
		||||
print("\0message\x1f%s" % os.path.abspath(menu_xml))
 | 
			
		||||
if not (info := os.getenv('ROFI_INFO')) is None:
 | 
			
		||||
    import json
 | 
			
		||||
    obj = json.JSONDecoder().decode(s=info)
 | 
			
		||||
    if 'exec' in info:
 | 
			
		||||
        subprocess.Popen(shlex.split(obj['exec']), stdout=subprocess.PIPE)
 | 
			
		||||
        sys.exit(0)
 | 
			
		||||
    elif 'menu' in obj:
 | 
			
		||||
        # Eh document.getElementById() seems not to work
 | 
			
		||||
        menus = document.getElementsByTagName('menu')
 | 
			
		||||
        for i in range(0, menus.length):
 | 
			
		||||
            if menus[i].getAttribute('id') == obj['menu']:
 | 
			
		||||
                menu = menus[i]
 | 
			
		||||
                if not menu is None:
 | 
			
		||||
                    get_menu_items(menu, "", True)
 | 
			
		||||
                    print("---\0nonselectable\x1ftrue")
 | 
			
		||||
                break
 | 
			
		||||
 | 
			
		||||
root_menu = document.getElementsByTagName('menu')[0]
 | 
			
		||||
get_menu_items(root_menu, "", True)
 | 
			
		||||
| 
						 | 
				
			
			@ -1,5 +1,4 @@
 | 
			
		|||
cfdata = configuration_data()
 | 
			
		||||
cfdata.set('bindir', get_option('prefix') / get_option('bindir'))
 | 
			
		||||
cfdata.set('libexecdir', get_option('prefix') / get_option('libexecdir'))
 | 
			
		||||
cfdata.set('localedir', get_option('prefix') / get_option('localedir'))
 | 
			
		||||
cfdata.set('sysconfdir', get_option('prefix') / get_option('sysconfdir'))
 | 
			
		||||
| 
						 | 
				
			
			@ -34,21 +33,8 @@ install_data(
 | 
			
		|||
  install_mode: 'rw-r--r--',
 | 
			
		||||
  )
 | 
			
		||||
 | 
			
		||||
install_data(
 | 
			
		||||
  'waybox.svg',
 | 
			
		||||
  install_dir: get_option('prefix') / get_option('datadir') / 'icons',
 | 
			
		||||
  install_mode: 'rw-r--r--',
 | 
			
		||||
  )
 | 
			
		||||
 | 
			
		||||
install_data(
 | 
			
		||||
  'waybox.desktop',
 | 
			
		||||
  install_dir: get_option('prefix') / get_option('datadir') + '/wayland-sessions',
 | 
			
		||||
  install_mode: 'rw-r--r--',
 | 
			
		||||
  )
 | 
			
		||||
 | 
			
		||||
install_data(
 | 
			
		||||
  'menu',
 | 
			
		||||
  install_dir: get_option('prefix') / get_option('bindir'),
 | 
			
		||||
  install_mode: 'rwxr-xr-x',
 | 
			
		||||
  rename: ['waybox-menu']
 | 
			
		||||
  )
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										49
									
								
								data/rc.xml
									
										
									
									
									
								
							
							
						
						
									
										49
									
								
								data/rc.xml
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -9,15 +9,15 @@
 | 
			
		|||
    <right>0</right>
 | 
			
		||||
  </margins>
 | 
			
		||||
  <keyboard>
 | 
			
		||||
    <!-- XKB configuration.  See `man xkeyboard-config` for more information -->
 | 
			
		||||
    <!-- Keyboard layout.  See `man xkeyboard-config` for more information -->
 | 
			
		||||
    <!-- You can use the XKB_* environment variables instead -->
 | 
			
		||||
    <!-- <xkb>
 | 
			
		||||
    <!-- <keyboardLayout>
 | 
			
		||||
      <model>105</model>
 | 
			
		||||
      <layout>us</layout>
 | 
			
		||||
      <options>ctrl:swapcaps,esperanto:dvorak,lv3:ralt_switch_multikey</options>
 | 
			
		||||
      <rules>evdev</rules>
 | 
			
		||||
      <variant>dvorak</variant>
 | 
			
		||||
    </xkb> -->
 | 
			
		||||
    </keyboardLayout> -->
 | 
			
		||||
    <!-- Keybindings for windows -->
 | 
			
		||||
    <keybind key="A-F4">
 | 
			
		||||
      <action name="Close"/>
 | 
			
		||||
| 
						 | 
				
			
			@ -42,16 +42,25 @@
 | 
			
		|||
    </keybind>
 | 
			
		||||
    <!-- Keybindings for window switching -->
 | 
			
		||||
    <keybind key="A-Tab">
 | 
			
		||||
      <action name="NextWindow"/>
 | 
			
		||||
      <action name="NextWindow">
 | 
			
		||||
        <finalactions>
 | 
			
		||||
          <action name="Unshade"/>
 | 
			
		||||
        </finalactions>
 | 
			
		||||
      </action>
 | 
			
		||||
    </keybind>
 | 
			
		||||
    <keybind key="A-S-ISO_Left_Tab">
 | 
			
		||||
      <action name="PreviousWindow"/>
 | 
			
		||||
      <action name="PreviousWindow">
 | 
			
		||||
        <finalactions>
 | 
			
		||||
          <action name="Unshade"/>
 | 
			
		||||
        </finalactions>
 | 
			
		||||
      </action>
 | 
			
		||||
    </keybind>
 | 
			
		||||
    <keybind key="C-A-Tab">
 | 
			
		||||
      <action name="NextWindow"/>
 | 
			
		||||
      <action name="NextWindow">
 | 
			
		||||
        <finalactions>
 | 
			
		||||
          <action name="Unshade"/>
 | 
			
		||||
        </finalactions>
 | 
			
		||||
      </action>
 | 
			
		||||
    </keybind>
 | 
			
		||||
    <!-- Keybindings for running applications -->
 | 
			
		||||
    <keybind key="W-Return">
 | 
			
		||||
| 
						 | 
				
			
			@ -69,12 +78,6 @@
 | 
			
		|||
        <execute>grim -g "$(slurp -d)" "$(xdg-user-dir PICTURES)/$(date +'%Y-%m-%d-%H%M%S_grim_sel.png')"</execute>
 | 
			
		||||
      </action>
 | 
			
		||||
    </keybind>
 | 
			
		||||
    <keybind key="A-r">
 | 
			
		||||
      <action name="Execute">
 | 
			
		||||
        <!-- If you'd prefer to use something like wmenu: `waybox-menu | wmenu | xargs env` -->
 | 
			
		||||
        <execute>rofi -show waybox-menu</execute>
 | 
			
		||||
      </action>
 | 
			
		||||
    </keybind>
 | 
			
		||||
    <keybind key="A-F2">
 | 
			
		||||
      <action name="Execute">
 | 
			
		||||
        <execute>obrun l</execute>
 | 
			
		||||
| 
						 | 
				
			
			@ -112,26 +115,4 @@
 | 
			
		|||
      </action>
 | 
			
		||||
    </keybind>
 | 
			
		||||
  </keyboard>
 | 
			
		||||
  <!-- Configuration for mice and other pointers. <mouse> instead of <pointer> only for backwards compatibility. -->
 | 
			
		||||
  <mouse>
 | 
			
		||||
    <!-- libinput configuration. -->
 | 
			
		||||
    <!-- <libinput>
 | 
			
		||||
      <accelProfile>adaptive</accelProfile>
 | 
			
		||||
      <accelSpeed>0.9</accelSpeed>
 | 
			
		||||
      <calibrationMatrix>0 0 0 0 0 0</calibrationMatrix>
 | 
			
		||||
      <clickMethod>buttonAreas</clickMethod>
 | 
			
		||||
      <disableWhileTrackpointing>enabled</disableWhileTrackpointing>
 | 
			
		||||
      <disableWhileTyping>enabled</disableWhileTyping>
 | 
			
		||||
      <leftHanded>disabled</leftHanded>
 | 
			
		||||
      <middleEmulation>enabled</middleEmulation>
 | 
			
		||||
      <naturalScroll>disabled</naturalScroll>
 | 
			
		||||
      <scrollButton>BTN_MIDDLE</scrollButton>
 | 
			
		||||
      <scrollButtonLock>disabled</scrollButtonLock>
 | 
			
		||||
      <scrollMethod>twofinger</scrollMethod>
 | 
			
		||||
      <tap>enabled</tap>
 | 
			
		||||
      <tapButtonMap>lrm</tapButtonMap>
 | 
			
		||||
      <tapDrag>enabled</tapDrag>
 | 
			
		||||
      <tapDragLock>enabled</tapDragLock>
 | 
			
		||||
    </libinput> -->
 | 
			
		||||
  </mouse>
 | 
			
		||||
</openbox_config>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,5 +4,4 @@ Comment=An Openbox-like compositor for Wayland
 | 
			
		|||
Comment[de]=Ein Wayland-Compositor ähnlich zu Openbox
 | 
			
		||||
Comment[eo]=Komponilo de Wayland, kiu similas je Openbox
 | 
			
		||||
Exec=waybox
 | 
			
		||||
Icon=waybox
 | 
			
		||||
Type=Application
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -60,12 +60,7 @@ then
 | 
			
		|||
fi
 | 
			
		||||
 | 
			
		||||
# And the XDG autostart script
 | 
			
		||||
if command -v xdg-autostart >/dev/null 2>&1;
 | 
			
		||||
then
 | 
			
		||||
    # Probably what you want instead of my simple shell script.
 | 
			
		||||
    # https://gitlab.com/somini/xdg-autostart/
 | 
			
		||||
    WB_XDG_AUTOSTART="xdg-autostart"
 | 
			
		||||
elif test -x $WB_USER_CONF_DIR/xdg-autostart;
 | 
			
		||||
if test -x $WB_USER_CONF_DIR/xdg-autostart;
 | 
			
		||||
then
 | 
			
		||||
    WB_XDG_AUTOSTART=$WB_USER_CONF_DIR/xdg-autostart;
 | 
			
		||||
elif test -x $WB_SYS_CONF_DIR/xdg-autostart;
 | 
			
		||||
| 
						 | 
				
			
			@ -77,26 +72,6 @@ then
 | 
			
		|||
    WB_XDG_AUTOSTART="@libexecdir@/openbox-autostart OPENBOX";
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
if test -f $WB_USER_CONF_DIR/menu.xml;
 | 
			
		||||
then
 | 
			
		||||
    WB_MENU_XML=$WB_USER_CONF_DIR/menu.xml
 | 
			
		||||
elif test -f $WB_SYS_CONF_DIR/menu.xml;
 | 
			
		||||
then
 | 
			
		||||
    WB_MENU_XML=$WB_SYS_CONF_DIR/menu.xml
 | 
			
		||||
elif test -f $OB_USER_CONF_DIR/menu.xml;
 | 
			
		||||
then
 | 
			
		||||
    _ "WARNING: Using files from Openbox. These may not work correctly."
 | 
			
		||||
    WB_MENU_XML=$OB_USER_CONF_DIR/menu.xml
 | 
			
		||||
elif test -f $OB_SYS_CONF_DIR/menu.xml;
 | 
			
		||||
then
 | 
			
		||||
    _ "WARNING: Using files from Openbox. These may not work correctly."
 | 
			
		||||
    WB_MENU_XML=$OB_SYS_CONF_DIR/menu.xml;
 | 
			
		||||
else
 | 
			
		||||
    _ "ERROR: No menu file found." >&2
 | 
			
		||||
    exit 1
 | 
			
		||||
fi
 | 
			
		||||
export WB_MENU_XML
 | 
			
		||||
 | 
			
		||||
if test -f $WB_USER_CONF_DIR/rc.xml;
 | 
			
		||||
then
 | 
			
		||||
    WB_RC_XML=$WB_USER_CONF_DIR/rc.xml
 | 
			
		||||
| 
						 | 
				
			
			@ -119,11 +94,9 @@ export WB_RC_XML
 | 
			
		|||
 | 
			
		||||
if which dbus-launch >/dev/null 2>&1;
 | 
			
		||||
then
 | 
			
		||||
    DBUS_LAUNCH="dbus-launch --exit-with-session"
 | 
			
		||||
    DBUS_LANCH="dbus-launch --exit-with-session"
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
export PATH=@bindir@:$PATH
 | 
			
		||||
 | 
			
		||||
# No need to export these to Waybox
 | 
			
		||||
unset TEXTDOMAIN TEXTDOMAINDIR
 | 
			
		||||
$DBUS_LAUNCH @libexecdir@/waybox --startup "${WB_AUTOSTART:-true}; ${WB_XDG_AUTOSTART:-true}" "$@"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,14 +0,0 @@
 | 
			
		|||
<?xml version="1.0" standalone="no"?>
 | 
			
		||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
 | 
			
		||||
  "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
 | 
			
		||||
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" height="48px" width="48px">
 | 
			
		||||
  <desc>Waybox icon</desc>
 | 
			
		||||
  <defs>
 | 
			
		||||
    <linearGradient id="titlegradient" x1="0" y1="0" x2="0" y2="1">
 | 
			
		||||
        <stop offset="0%" stop-color="#589bda" />
 | 
			
		||||
        <stop offset="100%" stop-color="#3c7cb7" />
 | 
			
		||||
    </linearGradient>
 | 
			
		||||
  </defs>
 | 
			
		||||
  <rect height="10" width="48" x="0" y="0" fill="url(#titlegradient)" />
 | 
			
		||||
  <rect height="38" width="48" x="0" y="10" fill="#eaeaea" />
 | 
			
		||||
</svg>
 | 
			
		||||
| 
		 Before Width: | Height: | Size: 601 B  | 
| 
						 | 
				
			
			@ -66,8 +66,6 @@ do
 | 
			
		|||
                    then
 | 
			
		||||
                        show_in=0
 | 
			
		||||
                        break 2
 | 
			
		||||
                    else
 | 
			
		||||
                        show_in=1
 | 
			
		||||
                    fi
 | 
			
		||||
                done
 | 
			
		||||
            done
 | 
			
		||||
| 
						 | 
				
			
			@ -90,7 +88,7 @@ do
 | 
			
		|||
        then
 | 
			
		||||
            # Don't run the Exec key if a non-empty TryExec command can't be found
 | 
			
		||||
            TRY_EXEC=$(cat "$f" | grep '^TryExec\s*=\s*\S' | sed -e 's/^TryExec\s*=\s*//g');
 | 
			
		||||
            if test -n "$TRY_EXEC" && ! command -v $TRY_EXEC >/dev/null 2>&1;
 | 
			
		||||
            if test -n "$TRY_EXEC" && ! which $TRY_EXEC;
 | 
			
		||||
            then
 | 
			
		||||
                continue
 | 
			
		||||
            fi
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,10 +1,10 @@
 | 
			
		|||
#ifndef _WB_OUTPUT_H
 | 
			
		||||
#define _WB_OUTPUT_H
 | 
			
		||||
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <time.h>
 | 
			
		||||
 | 
			
		||||
#include "waybox/server.h"
 | 
			
		||||
#include <wlr/types/wlr_output_management_v1.h>
 | 
			
		||||
 | 
			
		||||
struct wb_output {
 | 
			
		||||
	struct wlr_output *wlr_output;
 | 
			
		||||
| 
						 | 
				
			
			@ -18,19 +18,42 @@ struct wb_output {
 | 
			
		|||
		struct wlr_scene_tree *shell_top;
 | 
			
		||||
	} layers;
 | 
			
		||||
 | 
			
		||||
	bool gamma_lut_changed;
 | 
			
		||||
#if ! WLR_CHECK_VERSION(0, 17, 0)
 | 
			
		||||
	/* DEPRECATED: Use a tool like swaybg instead */
 | 
			
		||||
	struct wlr_scene_rect *background;
 | 
			
		||||
#endif
 | 
			
		||||
	struct wlr_box geometry;
 | 
			
		||||
 | 
			
		||||
	struct wl_listener destroy;
 | 
			
		||||
	struct wl_listener frame;
 | 
			
		||||
	struct wl_listener request_state;
 | 
			
		||||
 | 
			
		||||
	struct wl_list link;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void handle_gamma_control_set_gamma(struct wl_listener *listener, void *data);
 | 
			
		||||
void output_frame_notify(struct wl_listener *listener, void *data);
 | 
			
		||||
void output_destroy_notify(struct wl_listener *listener, void *data);
 | 
			
		||||
void init_output(struct wb_server *server);
 | 
			
		||||
struct wb_view {
 | 
			
		||||
	struct wl_list link;
 | 
			
		||||
	struct wb_server *server;
 | 
			
		||||
	struct wlr_xdg_toplevel *xdg_toplevel;
 | 
			
		||||
	struct wlr_scene_tree *scene_tree;
 | 
			
		||||
 | 
			
		||||
	struct wlr_xdg_toplevel_decoration_v1 *decoration;
 | 
			
		||||
 | 
			
		||||
	struct wl_listener map;
 | 
			
		||||
	struct wl_listener unmap;
 | 
			
		||||
	struct wl_listener destroy;
 | 
			
		||||
	struct wl_listener new_popup;
 | 
			
		||||
	struct wl_listener request_fullscreen;
 | 
			
		||||
	struct wl_listener request_maximize;
 | 
			
		||||
	struct wl_listener request_minimize;
 | 
			
		||||
	struct wl_listener request_move;
 | 
			
		||||
	struct wl_listener request_resize;
 | 
			
		||||
 | 
			
		||||
	struct wlr_box geometry;
 | 
			
		||||
	struct wlr_box previous_geometry;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void output_frame_notify(struct wl_listener* listener, void *data);
 | 
			
		||||
void output_destroy_notify(struct wl_listener* listener, void *data);
 | 
			
		||||
void new_output_notify(struct wl_listener* listener, void *data);
 | 
			
		||||
 | 
			
		||||
#endif /* output.h */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -12,7 +12,6 @@
 | 
			
		|||
#include <wlr/render/wlr_renderer.h>
 | 
			
		||||
#include <wlr/types/wlr_compositor.h>
 | 
			
		||||
#include <wlr/types/wlr_data_device.h>
 | 
			
		||||
#include <wlr/types/wlr_ext_foreign_toplevel_list_v1.h>
 | 
			
		||||
#include <wlr/types/wlr_gamma_control_v1.h>
 | 
			
		||||
#include <wlr/types/wlr_idle_notify_v1.h>
 | 
			
		||||
#include <wlr/types/wlr_output_layout.h>
 | 
			
		||||
| 
						 | 
				
			
			@ -23,8 +22,6 @@
 | 
			
		|||
#include <wlr/types/wlr_xdg_shell.h>
 | 
			
		||||
#include <wlr/util/log.h>
 | 
			
		||||
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
 | 
			
		||||
#ifdef USE_NLS
 | 
			
		||||
#	include <libintl.h>
 | 
			
		||||
#	include <locale.h>
 | 
			
		||||
| 
						 | 
				
			
			@ -37,27 +34,21 @@
 | 
			
		|||
#include "waybox/cursor.h"
 | 
			
		||||
#include "decoration.h"
 | 
			
		||||
#include "layer_shell.h"
 | 
			
		||||
#include "waybox/xdg_shell.h"
 | 
			
		||||
#include "waybox/output.h"
 | 
			
		||||
#include "waybox/seat.h"
 | 
			
		||||
 | 
			
		||||
struct wb_server {
 | 
			
		||||
	struct wl_display *wl_display;
 | 
			
		||||
	struct wl_event_loop *wl_event_loop;
 | 
			
		||||
 | 
			
		||||
	struct wlr_allocator *allocator;
 | 
			
		||||
	struct wlr_backend *backend;
 | 
			
		||||
	struct wlr_compositor *compositor;
 | 
			
		||||
	struct wlr_gamma_control_manager_v1 *gamma_control_manager;
 | 
			
		||||
	struct wlr_idle_inhibit_manager_v1 *idle_inhibit_manager;
 | 
			
		||||
	struct wlr_idle_notifier_v1 *idle_notifier;
 | 
			
		||||
	struct wlr_output_layout *output_layout;
 | 
			
		||||
	struct wlr_xdg_output_manager_v1 *output_manager;
 | 
			
		||||
	struct wlr_renderer *renderer;
 | 
			
		||||
	struct wlr_scene *scene;
 | 
			
		||||
	struct wlr_scene_output_layout *scene_layout;
 | 
			
		||||
	struct wlr_session *session;
 | 
			
		||||
	struct wlr_subcompositor *subcompositor;
 | 
			
		||||
	struct wlr_output_manager_v1 *wlr_output_manager;
 | 
			
		||||
 | 
			
		||||
	struct wb_config *config;
 | 
			
		||||
	char *config_file;
 | 
			
		||||
| 
						 | 
				
			
			@ -65,31 +56,21 @@ struct wb_server {
 | 
			
		|||
	struct wb_cursor *cursor;
 | 
			
		||||
	struct wb_seat *seat;
 | 
			
		||||
 | 
			
		||||
	struct wb_toplevel *grabbed_toplevel;
 | 
			
		||||
	struct wb_view *grabbed_view;
 | 
			
		||||
	struct wlr_box grab_geo_box;
 | 
			
		||||
	double grab_x, grab_y;
 | 
			
		||||
	uint32_t resize_edges;
 | 
			
		||||
	struct wlr_ext_foreign_toplevel_list_v1 *foreign_toplevel_list;
 | 
			
		||||
	struct wl_list toplevels;
 | 
			
		||||
	struct wl_list views;
 | 
			
		||||
 | 
			
		||||
	struct wlr_layer_shell_v1 *layer_shell;
 | 
			
		||||
	struct wlr_xdg_shell *xdg_shell;
 | 
			
		||||
 | 
			
		||||
	struct wl_listener gamma_control_set_gamma;
 | 
			
		||||
	struct wl_listener new_layer_surface;
 | 
			
		||||
	struct wl_listener new_xdg_surface;
 | 
			
		||||
	struct wl_listener new_xdg_decoration;
 | 
			
		||||
	struct wl_listener new_xdg_popup;
 | 
			
		||||
	struct wl_listener new_xdg_toplevel;
 | 
			
		||||
 | 
			
		||||
	struct wl_listener destroy_inhibit_manager;
 | 
			
		||||
	struct wl_listener destroy_inhibitor;
 | 
			
		||||
	struct wl_listener new_inhibitor;
 | 
			
		||||
	struct wl_list inhibitors;
 | 
			
		||||
 | 
			
		||||
	struct wl_listener new_input;
 | 
			
		||||
	struct wl_listener new_output;
 | 
			
		||||
	struct wl_listener output_configuration_applied;
 | 
			
		||||
	struct wl_listener output_configuration_tested;
 | 
			
		||||
	struct wl_list outputs; /* wb_output::link */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,49 +1,12 @@
 | 
			
		|||
#ifndef _WB_XDG_SHELL_H
 | 
			
		||||
#define _WB_XDG_SHELL_H
 | 
			
		||||
 | 
			
		||||
#include <wlr/types/wlr_fractional_scale_v1.h>
 | 
			
		||||
 | 
			
		||||
#include "waybox/server.h"
 | 
			
		||||
 | 
			
		||||
struct wb_popup {
 | 
			
		||||
	struct wlr_xdg_popup *xdg_popup;
 | 
			
		||||
	struct wl_listener commit;
 | 
			
		||||
	struct wl_listener destroy;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct wb_toplevel {
 | 
			
		||||
	struct wb_server *server;
 | 
			
		||||
	struct wlr_xdg_toplevel *xdg_toplevel;
 | 
			
		||||
	struct wlr_scene_tree *scene_tree;
 | 
			
		||||
 | 
			
		||||
	struct wlr_xdg_toplevel_decoration_v1 *decoration;
 | 
			
		||||
 | 
			
		||||
	struct wlr_ext_foreign_toplevel_handle_v1 *foreign_toplevel_handle;
 | 
			
		||||
	struct wlr_ext_foreign_toplevel_handle_v1_state foreign_toplevel_state;
 | 
			
		||||
 | 
			
		||||
	struct wl_listener map;
 | 
			
		||||
	struct wl_listener unmap;
 | 
			
		||||
	struct wl_listener commit;
 | 
			
		||||
	struct wl_listener destroy;
 | 
			
		||||
	struct wl_listener new_popup;
 | 
			
		||||
	struct wl_listener request_fullscreen;
 | 
			
		||||
	struct wl_listener request_maximize;
 | 
			
		||||
	struct wl_listener request_minimize;
 | 
			
		||||
	struct wl_listener request_move;
 | 
			
		||||
	struct wl_listener request_resize;
 | 
			
		||||
	struct wl_listener set_app_id;
 | 
			
		||||
	struct wl_listener set_title;
 | 
			
		||||
 | 
			
		||||
	struct wlr_box geometry;
 | 
			
		||||
	struct wlr_box previous_geometry;
 | 
			
		||||
 | 
			
		||||
	struct wl_list link;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void init_xdg_shell(struct wb_server *server);
 | 
			
		||||
void focus_toplevel(struct wb_toplevel *toplevel);
 | 
			
		||||
struct wlr_output *get_active_output(struct wb_toplevel *toplevel);
 | 
			
		||||
struct wb_toplevel *get_toplevel_at(
 | 
			
		||||
void focus_view(struct wb_view *view, struct wlr_surface *surface);
 | 
			
		||||
struct wlr_output *get_active_output(struct wb_view *view);
 | 
			
		||||
struct wb_view *get_view_at(
 | 
			
		||||
		struct wb_server *server, double lx, double ly,
 | 
			
		||||
		struct wlr_surface **surface, double *sx, double *sy);
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										22
									
								
								meson.build
									
										
									
									
									
								
							
							
						
						
									
										22
									
								
								meson.build
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -1,9 +1,9 @@
 | 
			
		|||
project(
 | 
			
		||||
  'Waybox',
 | 
			
		||||
  'c',
 | 
			
		||||
  version: '0.2.3',
 | 
			
		||||
  version: '0.2.1',
 | 
			
		||||
  license: 'MIT',
 | 
			
		||||
  meson_version: '>=0.60.0',
 | 
			
		||||
  meson_version: '>=0.52.0',
 | 
			
		||||
  default_options: [
 | 
			
		||||
    'c_std=c11',
 | 
			
		||||
    'warning_level=2',
 | 
			
		||||
| 
						 | 
				
			
			@ -15,7 +15,6 @@ add_project_arguments(
 | 
			
		|||
  '-Wno-unused-parameter',
 | 
			
		||||
  '-D_DEFAULT_SOURCE',
 | 
			
		||||
  '-D_POSIX_C_SOURCE=200112L',
 | 
			
		||||
  '-DWL_HIDE_DEPRECATED', # Hide the deprecated parts of the Wayland API
 | 
			
		||||
  '-DWLR_USE_UNSTABLE',
 | 
			
		||||
  '-DPACKAGE_NAME="' + meson.project_name() + '"',
 | 
			
		||||
  '-DPACKAGE_VERSION="' + meson.project_version() + '"',
 | 
			
		||||
| 
						 | 
				
			
			@ -26,27 +25,16 @@ cc = meson.get_compiler('c')
 | 
			
		|||
# Adding include directory
 | 
			
		||||
inc_dir = include_directories('include')
 | 
			
		||||
 | 
			
		||||
if get_option('wlroots-version') != ''
 | 
			
		||||
  wlroots_version = get_option('wlroots-version')
 | 
			
		||||
else
 | 
			
		||||
  wlroots_version = ['wlroots-0.20', 'wlroots-0.19', 'wlroots-0.18']
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
libevdev = dependency('libevdev')
 | 
			
		||||
libinput = dependency('libinput', version: '>=1.21.0', required: false)
 | 
			
		||||
libxml2 = dependency('libxml-2.0')
 | 
			
		||||
wayland_protos = dependency('wayland-protocols', version: '>=1.37')
 | 
			
		||||
wlroots = dependency('wlroots', version: '>=0.16.0')
 | 
			
		||||
wayland_server = dependency('wayland-server', version: '>=1.15')
 | 
			
		||||
wlroots = dependency(wlroots_version, version: '>=0.17.0')
 | 
			
		||||
wayland_protos  = dependency('wayland-protocols', version: '>=1.27')
 | 
			
		||||
xkbcommon  = dependency('xkbcommon')
 | 
			
		||||
 | 
			
		||||
if libinput.found()
 | 
			
		||||
  add_project_arguments('-DHAS_LIBINPUT', language: 'c')
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
msgfmt = find_program('msgfmt', required: false)
 | 
			
		||||
if msgfmt.found()
 | 
			
		||||
  source_root = meson.current_source_dir()
 | 
			
		||||
  add_project_arguments('-DUSE_NLS=1', language: 'c')
 | 
			
		||||
  subdir('po')
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1 +0,0 @@
 | 
			
		|||
option('wlroots-version', type: 'string', value: '', description: 'The version of wlroots with which to compile the compositor')
 | 
			
		||||
							
								
								
									
										97
									
								
								po/de.po
									
										
									
									
									
								
							
							
						
						
									
										97
									
								
								po/de.po
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -11,8 +11,8 @@ msgid ""
 | 
			
		|||
msgstr ""
 | 
			
		||||
"Project-Id-Version: Waybox 0.0.1\n"
 | 
			
		||||
"Report-Msgid-Bugs-To: https://github.com/wizbright/waybox/issues\n"
 | 
			
		||||
"POT-Creation-Date: 2024-01-25 21:21-0500\n"
 | 
			
		||||
"PO-Revision-Date: 2024-01-25 21:34-0500\n"
 | 
			
		||||
"POT-Creation-Date: 2022-12-06 22:27-0500\n"
 | 
			
		||||
"PO-Revision-Date: 2022-12-06 22:30-0500\n"
 | 
			
		||||
"Last-Translator: Volker Ribbert <volker.nospam@netcologne.de>\n"
 | 
			
		||||
"Language-Team:  <de@li.org>\n"
 | 
			
		||||
"Language: de\n"
 | 
			
		||||
| 
						 | 
				
			
			@ -22,10 +22,10 @@ msgstr ""
 | 
			
		|||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
 | 
			
		||||
 | 
			
		||||
msgid "WARNING: Using files from Openbox. These may not work correctly."
 | 
			
		||||
msgstr "WARNUNG: Benutze Dateien von Openbox, was nicht richtig funktionieren wird."
 | 
			
		||||
msgstr "WARNUNG: Benutzt Dateien aus Openbox. Das wird nicht richtig werken."
 | 
			
		||||
 | 
			
		||||
msgid "ERROR: No configuration file found."
 | 
			
		||||
msgstr "FEHLER: Keine Konfigurationsdatei gefunden."
 | 
			
		||||
msgstr "FEHLER: Keine Einstellungsdatei gefunden."
 | 
			
		||||
 | 
			
		||||
msgid "Unable to evaluate expression"
 | 
			
		||||
msgstr "Konnte den Ausdruck nicht evaluieren"
 | 
			
		||||
| 
						 | 
				
			
			@ -39,18 +39,18 @@ msgstr "Kein nodeset"
 | 
			
		|||
msgid ""
 | 
			
		||||
"Unable to parse the configuration file. Consult stderr for more information."
 | 
			
		||||
msgstr ""
 | 
			
		||||
"Kann die Konfigurationsdatei nicht verarbeiten. Für weitere Informationen siehe "
 | 
			
		||||
"die Standardfehlerausgabe."
 | 
			
		||||
"Kann nicht die Einstullungsdatei analisieren. Für mehr Informationen die "
 | 
			
		||||
"Standardfehlerausgabe lesen."
 | 
			
		||||
 | 
			
		||||
msgid "Couldn't create new context!"
 | 
			
		||||
msgstr "Konnte keinen neuen Kontext erstellen!"
 | 
			
		||||
msgstr "Konnte einen neuen Zusammenhang nicht erstellen"
 | 
			
		||||
 | 
			
		||||
msgid "Couldn't register the namespace"
 | 
			
		||||
msgstr "Konnte den Namensraum nicht registrieren"
 | 
			
		||||
msgstr "Konte dem Namensnraum nicht registrieren"
 | 
			
		||||
 | 
			
		||||
#, c-format
 | 
			
		||||
msgid "Syntax: %s [options]\n"
 | 
			
		||||
msgstr "Syntax: %s [Optionen]\n"
 | 
			
		||||
msgstr "Eingabe: %s [Optionen]\n"
 | 
			
		||||
 | 
			
		||||
#, c-format
 | 
			
		||||
msgid ""
 | 
			
		||||
| 
						 | 
				
			
			@ -75,7 +75,7 @@ msgstr "  --config-file DATEI Pfad zur Konfigurationsdatei\n"
 | 
			
		|||
 | 
			
		||||
#, c-format
 | 
			
		||||
msgid "  --sm-disable        Disable connection to the session manager\n"
 | 
			
		||||
msgstr "  --sm-disable        Deaktiviere Verbindung zum Sitzungsmanager\n"
 | 
			
		||||
msgstr "  --sm-disable        Verbindung zum Sitzungsmanager trennen\n"
 | 
			
		||||
 | 
			
		||||
#, c-format
 | 
			
		||||
msgid "  --startup CMD       Run CMD after starting\n"
 | 
			
		||||
| 
						 | 
				
			
			@ -83,7 +83,7 @@ msgstr "  --startup CMD       CMD nach Start ausführen\n"
 | 
			
		|||
 | 
			
		||||
#, c-format
 | 
			
		||||
msgid "  --debug             Display debugging output\n"
 | 
			
		||||
msgstr "  --debug             Ausgabe von Debug-Informationen\n"
 | 
			
		||||
msgstr "  --debug             Fehlersuche-Ergebnis anzeigen\n"
 | 
			
		||||
 | 
			
		||||
#, c-format
 | 
			
		||||
msgid ""
 | 
			
		||||
| 
						 | 
				
			
			@ -92,8 +92,8 @@ msgid ""
 | 
			
		|||
"on Wayland.\n"
 | 
			
		||||
msgstr ""
 | 
			
		||||
"\n"
 | 
			
		||||
"Weitere Openbox-Optionen werden nicht angenommen, da sie überwiegend "
 | 
			
		||||
"sinnlos unter Wayland sind.\n"
 | 
			
		||||
"Weitere Openbox-Optionen sind nicht angenommen, meistens wegen sie sind "
 | 
			
		||||
"sinnlos auf Wayland.\n"
 | 
			
		||||
 | 
			
		||||
#, c-format
 | 
			
		||||
msgid "%s requires an argument\n"
 | 
			
		||||
| 
						 | 
				
			
			@ -101,25 +101,25 @@ msgstr "%s erfordert einen Parameter\n"
 | 
			
		|||
 | 
			
		||||
#, c-format
 | 
			
		||||
msgid "%s hasn't been implemented yet.\n"
 | 
			
		||||
msgstr "%s wurde bisher nicht implementiert.\n"
 | 
			
		||||
msgstr "%s ist schon nicht implementiert.\n"
 | 
			
		||||
 | 
			
		||||
msgid "Successfully created backend"
 | 
			
		||||
msgstr "Das Backend wurde erfolgreich erstellt"
 | 
			
		||||
msgstr "Das Backend wurde erfolgreich hergestellt"
 | 
			
		||||
 | 
			
		||||
msgid "Failed to create backend"
 | 
			
		||||
msgstr "Das Backend wurde nicht erstellt"
 | 
			
		||||
msgstr "Das Backend wurde nicht erfolgreich hergestellt"
 | 
			
		||||
 | 
			
		||||
msgid "Successfully started server"
 | 
			
		||||
msgstr "Der Server wurde erfolgreich gestartet"
 | 
			
		||||
 | 
			
		||||
msgid "Failed to start server"
 | 
			
		||||
msgstr "Der Server wurde nicht gestartet"
 | 
			
		||||
msgstr "Der Server wurde nicht erfolgreich gestartet"
 | 
			
		||||
 | 
			
		||||
msgid "New output device detected"
 | 
			
		||||
msgstr "Neues Ausgabegerät entdeckt"
 | 
			
		||||
msgstr "Neue Ausgabegerät entdeckt"
 | 
			
		||||
 | 
			
		||||
msgid "Could not add an output layout."
 | 
			
		||||
msgstr "Konnte keine neue Ausgabenanordnung hinzufügen."
 | 
			
		||||
msgid "Couldn't commit pending frame to output"
 | 
			
		||||
msgstr "Konnte sich nicht an den anstehenden Rahmen an die Ausgabe eintragen"
 | 
			
		||||
 | 
			
		||||
msgid "New keyboard detected"
 | 
			
		||||
msgstr "Neue Tastatur entdeckt"
 | 
			
		||||
| 
						 | 
				
			
			@ -128,25 +128,22 @@ msgid "New pointer detected"
 | 
			
		|||
msgstr "Neuer Zeiger entdeckt"
 | 
			
		||||
 | 
			
		||||
msgid "Unsupported input device detected"
 | 
			
		||||
msgstr "Unbekanntes Eingabegerät entdeckt"
 | 
			
		||||
msgstr "Unerkanntes Eingabegerät entdeckt"
 | 
			
		||||
 | 
			
		||||
msgid "Failed to connect to a Wayland display"
 | 
			
		||||
msgstr "Scheiterte mit Verbindung an ein Wayland-Display"
 | 
			
		||||
 | 
			
		||||
msgid "Failed to get an event loop"
 | 
			
		||||
msgstr "Scheiterte eine Ereignisschleife zu bekommen"
 | 
			
		||||
msgstr "Scheiterte an eines Wayland-Displays verbinden"
 | 
			
		||||
 | 
			
		||||
msgid "Failed to create renderer"
 | 
			
		||||
msgstr "Der Renderer wurde nicht erstellt"
 | 
			
		||||
msgstr "Das Renderer wurde nicht erfolgreich hergestellt"
 | 
			
		||||
 | 
			
		||||
msgid "Failed to create allocator"
 | 
			
		||||
msgstr "Der Allokator wurde nicht erstellt"
 | 
			
		||||
msgstr "Das Allokator wurde nicht erfolgreich hergestellt"
 | 
			
		||||
 | 
			
		||||
msgid "Failed to start backend"
 | 
			
		||||
msgstr "Starten des Backend gescheitert"
 | 
			
		||||
 | 
			
		||||
msgid "Running Wayland compositor on Wayland display"
 | 
			
		||||
msgstr "Führe Wayland-Compositor auf Wayland-Display aus"
 | 
			
		||||
msgstr "Ausführt Wayland-Compositor auf Wayland-Display"
 | 
			
		||||
 | 
			
		||||
msgid "Display destroyed"
 | 
			
		||||
msgstr "Display zerstört"
 | 
			
		||||
| 
						 | 
				
			
			@ -154,32 +151,28 @@ msgstr "Display zerstört"
 | 
			
		|||
msgid "Keyboard focus is now on surface"
 | 
			
		||||
msgstr "Tastaturfokus ist jetzt auf Oberfläche"
 | 
			
		||||
 | 
			
		||||
msgid "Focusing next toplevel"
 | 
			
		||||
msgstr "Fokussiere nächst höhere Ebene"
 | 
			
		||||
 | 
			
		||||
#~ msgid "Couldn't commit pending frame to output"
 | 
			
		||||
#~ msgstr ""
 | 
			
		||||
#~ "Der anstehende Frame konnte nicht an die Ausgabe übergeben werden"
 | 
			
		||||
msgid "Focusing next view"
 | 
			
		||||
msgstr "Fokussiert nächste Ansicht"
 | 
			
		||||
 | 
			
		||||
#, fuzzy
 | 
			
		||||
#~ msgid "Failed to create wlr_backend"
 | 
			
		||||
#~ msgstr "wlr_backend wurde nicht erstellt"
 | 
			
		||||
#~ msgstr "Das Backend wurde nicht erfolgreich hergestellt"
 | 
			
		||||
 | 
			
		||||
#~ msgid "Couldn't get a surface texture"
 | 
			
		||||
#~ msgstr "Konnte keine Oberflächentextur bekommen"
 | 
			
		||||
 | 
			
		||||
#~ msgid "Couldn't attach renderer to output"
 | 
			
		||||
#~ msgstr "Konnte Renderer nicht an die Ausgabe binden"
 | 
			
		||||
#~ msgstr "Konnte nicht einen Renderer an die Ausgabe nicht anbringen"
 | 
			
		||||
 | 
			
		||||
#~ msgid "Focusing current view"
 | 
			
		||||
#~ msgstr "Fokussiert jetzige Ansicht"
 | 
			
		||||
 | 
			
		||||
#~ msgid "Unable to parse XML file"
 | 
			
		||||
#~ msgstr "Konnte die XML-Datei nicht analysieren"
 | 
			
		||||
#~ msgstr "Konnte die XML-Datei nicht analisieren"
 | 
			
		||||
 | 
			
		||||
#, c-format
 | 
			
		||||
#~ msgid "Invalid action \"%s\" requested. No such action exists."
 | 
			
		||||
#~ msgstr "Ungültige Aktion \"%s\" angefordert. Diese existiert nicht."
 | 
			
		||||
#~ msgstr "Ungültige Aktion \"%s\" angefordert. Es gibt keine solche."
 | 
			
		||||
 | 
			
		||||
#~ msgid "No"
 | 
			
		||||
#~ msgstr "Nein"
 | 
			
		||||
| 
						 | 
				
			
			@ -262,7 +255,7 @@ msgstr "Fokussiere nächst höhere Ebene"
 | 
			
		|||
#~ msgstr "Immer im _Hintergrund"
 | 
			
		||||
 | 
			
		||||
#~ msgid "_Send to desktop"
 | 
			
		||||
#~ msgstr "_Sende an Desktop"
 | 
			
		||||
#~ msgstr "_Verschieben nach"
 | 
			
		||||
 | 
			
		||||
#~ msgid "Client menu"
 | 
			
		||||
#~ msgstr "Anwendungsmenü"
 | 
			
		||||
| 
						 | 
				
			
			@ -299,8 +292,8 @@ msgstr "Fokussiere nächst höhere Ebene"
 | 
			
		|||
#~ "Waybox was compiled without image loading support. Icons in menus will "
 | 
			
		||||
#~ "not be loaded."
 | 
			
		||||
#~ msgstr ""
 | 
			
		||||
#~ "Waybox wurde ohne Unterstützung für Bilder kompiliert. Diese werden in Menüs "
 | 
			
		||||
#~ "daher nicht geladen."
 | 
			
		||||
#~ "Waybox wurde ohne Bildladungsunterstützung kompiliert. Ikone in Menüs "
 | 
			
		||||
#~ "werden nicht geladen werden."
 | 
			
		||||
 | 
			
		||||
#~ msgid "Conflict with key binding in config file"
 | 
			
		||||
#~ msgstr "Störende Tastenkombination in Konfigurationsdatei"
 | 
			
		||||
| 
						 | 
				
			
			@ -319,18 +312,18 @@ msgstr "Fokussiere nächst höhere Ebene"
 | 
			
		|||
 | 
			
		||||
#, c-format
 | 
			
		||||
#~ msgid "Attempted to access menu \"%s\" but it does not exist"
 | 
			
		||||
#~ msgstr "Versuchter Zugriff auf Menü \"%s\", welches nicht existiert"
 | 
			
		||||
#~ msgstr "Versuchter Zugriff auf Menü \"%s\", doch es existiert nicht"
 | 
			
		||||
 | 
			
		||||
#~ msgid "More..."
 | 
			
		||||
#~ msgstr "Mehr..."
 | 
			
		||||
 | 
			
		||||
#, c-format
 | 
			
		||||
#~ msgid "Invalid button \"%s\" in mouse binding"
 | 
			
		||||
#~ msgstr "Maus-Kombination mit ungültiger Taste \"%s\""
 | 
			
		||||
#~ msgstr "Maus-Einbindung mit ungültiger Taste \"%s\""
 | 
			
		||||
 | 
			
		||||
#, c-format
 | 
			
		||||
#~ msgid "Invalid context \"%s\" in mouse binding"
 | 
			
		||||
#~ msgstr "Maus-Kombination mit ungültigem Kontext \"%s\""
 | 
			
		||||
#~ msgstr "Maus-Einbindung mit ungültigem Kontext \"%s\""
 | 
			
		||||
 | 
			
		||||
#, c-format
 | 
			
		||||
#~ msgid "Unable to change to home directory \"%s\": %s"
 | 
			
		||||
| 
						 | 
				
			
			@ -338,8 +331,8 @@ msgstr "Fokussiere nächst höhere Ebene"
 | 
			
		|||
 | 
			
		||||
#~ msgid "Unable to find a valid config file, using some simple defaults"
 | 
			
		||||
#~ msgstr ""
 | 
			
		||||
#~ "Keine gültige Konfigurationsdatei vorhanden, daher werden einfache "
 | 
			
		||||
#~ "Standardwerte benutzt"
 | 
			
		||||
#~ "Keine gültige Konfigurationsdatei vorhanden, benutze einfache "
 | 
			
		||||
#~ "Standardwerte"
 | 
			
		||||
 | 
			
		||||
#~ msgid "Unable to load a theme."
 | 
			
		||||
#~ msgstr "Kann kein Thema laden."
 | 
			
		||||
| 
						 | 
				
			
			@ -379,12 +372,12 @@ msgstr "Fokussiere nächst höhere Ebene"
 | 
			
		|||
 | 
			
		||||
#~ msgid "  --debug-focus       Display debugging output for focus handling\n"
 | 
			
		||||
#~ msgstr ""
 | 
			
		||||
#~ "  --debug-focus       Debug-Informationen für Fokus-Handling anzeigen\n"
 | 
			
		||||
#~ "  --debug-focus       Fehlersuche-Ergebnis für Fokus-Handling anzeigen\n"
 | 
			
		||||
 | 
			
		||||
#~ msgid ""
 | 
			
		||||
#~ "  --debug-session     Display debugging output for session management\n"
 | 
			
		||||
#~ msgstr ""
 | 
			
		||||
#~ "  --debug-session     Debug-Informationen für Sitzungsmanager anzeigen\n"
 | 
			
		||||
#~ "  --debug-session     Fehler-Ergebnis für Sitzungsmanager anzeigen\n"
 | 
			
		||||
 | 
			
		||||
#, c-format
 | 
			
		||||
#~ msgid ""
 | 
			
		||||
| 
						 | 
				
			
			@ -418,7 +411,7 @@ msgstr "Fokussiere nächst höhere Ebene"
 | 
			
		|||
 | 
			
		||||
#, c-format
 | 
			
		||||
#~ msgid "Unable to make directory \"%s\": %s"
 | 
			
		||||
#~ msgstr "Kann Verzeichnis \"%s\" nicht erstellen: %s"
 | 
			
		||||
#~ msgstr "Kann nicht Verzeichnis \"%s\" machen: %s"
 | 
			
		||||
 | 
			
		||||
#, c-format
 | 
			
		||||
#~ msgid "Unable to save the session to \"%s\": %s"
 | 
			
		||||
| 
						 | 
				
			
			@ -426,10 +419,10 @@ msgstr "Fokussiere nächst höhere Ebene"
 | 
			
		|||
 | 
			
		||||
#, c-format
 | 
			
		||||
#~ msgid "Error while saving the session to \"%s\": %s"
 | 
			
		||||
#~ msgstr "Fehler beim Speichern der Sitzung in \"%s\": %s"
 | 
			
		||||
#~ msgstr "Fehler während die Sitzung in \"%s\" speichern: %s"
 | 
			
		||||
 | 
			
		||||
#~ msgid "Not connected to a session manager"
 | 
			
		||||
#~ msgstr "Nicht mit Sitzungsmanager verbunden"
 | 
			
		||||
#~ msgstr "An einer Sitzungsmanager nicht verbindet"
 | 
			
		||||
 | 
			
		||||
#, c-format
 | 
			
		||||
#~ msgid "Running %s"
 | 
			
		||||
| 
						 | 
				
			
			@ -437,7 +430,7 @@ msgstr "Fokussiere nächst höhere Ebene"
 | 
			
		|||
 | 
			
		||||
#, c-format
 | 
			
		||||
#~ msgid "Invalid modifier key \"%s\" in key/mouse binding"
 | 
			
		||||
#~ msgstr "Ungültige Modifier-Taste \"%s\" in Tasten/Maus-Kombination"
 | 
			
		||||
#~ msgstr "Ungültige Modifier-Taste \"%s\" in Tasten/Maus-Einbindung"
 | 
			
		||||
 | 
			
		||||
#, c-format
 | 
			
		||||
#~ msgid "Invalid key code \"%s\" in key binding"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										34
									
								
								po/eo.po
									
										
									
									
									
								
							
							
						
						
									
										34
									
								
								po/eo.po
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -7,8 +7,8 @@ msgid ""
 | 
			
		|||
msgstr ""
 | 
			
		||||
"Project-Id-Version: Waybox 0.0.1\n"
 | 
			
		||||
"Report-Msgid-Bugs-To: https://github.com/wizbright/waybox/issues\n"
 | 
			
		||||
"POT-Creation-Date: 2024-01-25 21:21-0500\n"
 | 
			
		||||
"PO-Revision-Date: 2024-01-25 21:35-0500\n"
 | 
			
		||||
"POT-Creation-Date: 2022-12-06 22:27-0500\n"
 | 
			
		||||
"PO-Revision-Date: 2022-12-06 22:33-0500\n"
 | 
			
		||||
"Last-Translator: Keith <keith@localhost>\n"
 | 
			
		||||
"Language-Team: Esperanto\n"
 | 
			
		||||
"Language: eo\n"
 | 
			
		||||
| 
						 | 
				
			
			@ -24,7 +24,7 @@ msgid "ERROR: No configuration file found."
 | 
			
		|||
msgstr "ERARO: Neniu agordo-dosiero trovita."
 | 
			
		||||
 | 
			
		||||
msgid "Unable to evaluate expression"
 | 
			
		||||
msgstr "Ne eblis taksi esprimon"
 | 
			
		||||
msgstr "Ne povas taksi esprimon"
 | 
			
		||||
 | 
			
		||||
msgid "No nodesetval"
 | 
			
		||||
msgstr "Neniu nodara valoro"
 | 
			
		||||
| 
						 | 
				
			
			@ -41,7 +41,7 @@ msgid "Couldn't create new context!"
 | 
			
		|||
msgstr "Ne povis krei novan kuntekston!"
 | 
			
		||||
 | 
			
		||||
msgid "Couldn't register the namespace"
 | 
			
		||||
msgstr "Ne eblis registri la nomspacon"
 | 
			
		||||
msgstr "Ne povas registri lo nomspacon"
 | 
			
		||||
 | 
			
		||||
#, c-format
 | 
			
		||||
msgid "Syntax: %s [options]\n"
 | 
			
		||||
| 
						 | 
				
			
			@ -98,13 +98,13 @@ msgstr "%s postulas argumenton\n"
 | 
			
		|||
 | 
			
		||||
#, c-format
 | 
			
		||||
msgid "%s hasn't been implemented yet.\n"
 | 
			
		||||
msgstr "%s ankoraŭ ne estas efektivigita.\n"
 | 
			
		||||
msgstr "%s ankoraŭ ne estas efektigita.\n"
 | 
			
		||||
 | 
			
		||||
msgid "Successfully created backend"
 | 
			
		||||
msgstr "Sukcese kreis servilan dorson"
 | 
			
		||||
 | 
			
		||||
msgid "Failed to create backend"
 | 
			
		||||
msgstr "Malsukcesis krei servilan dorson"
 | 
			
		||||
msgstr "Malsukesis krei servilan dorson"
 | 
			
		||||
 | 
			
		||||
msgid "Successfully started server"
 | 
			
		||||
msgstr "Sukcese startigis servilon"
 | 
			
		||||
| 
						 | 
				
			
			@ -113,10 +113,10 @@ msgid "Failed to start server"
 | 
			
		|||
msgstr "Malsukcesis startigi servilon"
 | 
			
		||||
 | 
			
		||||
msgid "New output device detected"
 | 
			
		||||
msgstr "Nova eligilo malkovrita"
 | 
			
		||||
msgstr "Nova enigilo malkovrita"
 | 
			
		||||
 | 
			
		||||
msgid "Could not add an output layout."
 | 
			
		||||
msgstr "Ne eblis aldoni eligan aranĝon."
 | 
			
		||||
msgid "Couldn't commit pending frame to output"
 | 
			
		||||
msgstr "Ne povis surmeti atendantan framon sur eligon"
 | 
			
		||||
 | 
			
		||||
msgid "New keyboard detected"
 | 
			
		||||
msgstr "Nova klavaro malkovrita"
 | 
			
		||||
| 
						 | 
				
			
			@ -130,17 +130,14 @@ msgstr "Nerekonata enigilo malkovrita"
 | 
			
		|||
msgid "Failed to connect to a Wayland display"
 | 
			
		||||
msgstr "Malsukcesis konektiĝi al Wayland-ekrano"
 | 
			
		||||
 | 
			
		||||
msgid "Failed to get an event loop"
 | 
			
		||||
msgstr "Malsukcesis atingi evento-iteracion"
 | 
			
		||||
 | 
			
		||||
msgid "Failed to create renderer"
 | 
			
		||||
msgstr "Malsukcesis krei servilan bildigilon"
 | 
			
		||||
msgstr "Malsukesis krei servilan bildigilon"
 | 
			
		||||
 | 
			
		||||
msgid "Failed to create allocator"
 | 
			
		||||
msgstr "Malsukcesis krei servilan asignilon"
 | 
			
		||||
msgstr "Malsukesis krei servilan asignilon"
 | 
			
		||||
 | 
			
		||||
msgid "Failed to start backend"
 | 
			
		||||
msgstr "Malsukcesis startigi servilan dorson"
 | 
			
		||||
msgstr "Malsukesis startigi servilan dorson"
 | 
			
		||||
 | 
			
		||||
msgid "Running Wayland compositor on Wayland display"
 | 
			
		||||
msgstr "Plenumas Wayland-komponilon sur Wayland-ekrano"
 | 
			
		||||
| 
						 | 
				
			
			@ -151,11 +148,8 @@ msgstr "Ekrano finigita"
 | 
			
		|||
msgid "Keyboard focus is now on surface"
 | 
			
		||||
msgstr "Klavara fokuso nun estas sur surfaco"
 | 
			
		||||
 | 
			
		||||
msgid "Focusing next toplevel"
 | 
			
		||||
msgstr "Fokusas la sekvan supran nivelon"
 | 
			
		||||
 | 
			
		||||
#~ msgid "Couldn't commit pending frame to output"
 | 
			
		||||
#~ msgstr "Ne eblis surmeti atendantan framon sur eligon"
 | 
			
		||||
msgid "Focusing next view"
 | 
			
		||||
msgstr "Fokusas la sekvan vidon"
 | 
			
		||||
 | 
			
		||||
#, fuzzy
 | 
			
		||||
#~ msgid "Failed to create wlr_backend"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,14 +1,11 @@
 | 
			
		|||
i18n = import('i18n')
 | 
			
		||||
add_project_arguments('-DGETTEXT_PACKAGE="' + meson.project_name().to_lower() + '"',
 | 
			
		||||
  '-DLOCALEDIR="' + get_option('prefix') / get_option('localedir') + '"',
 | 
			
		||||
  '-DUSE_NLS=1', language: 'c')
 | 
			
		||||
 | 
			
		||||
i18n = import('i18n', required: false)
 | 
			
		||||
if i18n.found()
 | 
			
		||||
  i18n.gettext(meson.project_name().to_lower(),
 | 
			
		||||
  language:'c')
 | 
			
		||||
i18n.gettext(meson.project_name().to_lower(),
 | 
			
		||||
  args: ['--directory=' + source_root,
 | 
			
		||||
    '--add-comments=TRANSLATORS',
 | 
			
		||||
    '--no-location',
 | 
			
		||||
    '--keyword=_',
 | 
			
		||||
    '--msgid-bugs=https://github.com/wizbright/waybox/issues']
 | 
			
		||||
)
 | 
			
		||||
endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,7 +8,7 @@ msgid ""
 | 
			
		|||
msgstr ""
 | 
			
		||||
"Project-Id-Version: waybox\n"
 | 
			
		||||
"Report-Msgid-Bugs-To: https://github.com/wizbright/waybox/issues\n"
 | 
			
		||||
"POT-Creation-Date: 2024-01-25 21:21-0500\n"
 | 
			
		||||
"POT-Creation-Date: 2022-12-06 22:27-0500\n"
 | 
			
		||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 | 
			
		||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 | 
			
		||||
"Language-Team: LANGUAGE <LL@li.org>\n"
 | 
			
		||||
| 
						 | 
				
			
			@ -107,7 +107,7 @@ msgstr ""
 | 
			
		|||
msgid "New output device detected"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
msgid "Could not add an output layout."
 | 
			
		||||
msgid "Couldn't commit pending frame to output"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
msgid "New keyboard detected"
 | 
			
		||||
| 
						 | 
				
			
			@ -122,9 +122,6 @@ msgstr ""
 | 
			
		|||
msgid "Failed to connect to a Wayland display"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
msgid "Failed to get an event loop"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
msgid "Failed to create renderer"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -143,5 +140,5 @@ msgstr ""
 | 
			
		|||
msgid "Keyboard focus is now on surface"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
msgid "Focusing next toplevel"
 | 
			
		||||
msgid "Focusing next view"
 | 
			
		||||
msgstr ""
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,7 +1,6 @@
 | 
			
		|||
wl_protocol_dir = wayland_protos.get_variable(pkgconfig: 'pkgdatadir')
 | 
			
		||||
 | 
			
		||||
wayland_scanner_dep = dependency('wayland-scanner', version: '>=1.15')
 | 
			
		||||
wayland_scanner = find_program(wayland_scanner_dep.get_variable(pkgconfig: 'wayland_scanner'))
 | 
			
		||||
wayland_scanner = find_program('wayland-scanner', version: '>= 1.15')
 | 
			
		||||
 | 
			
		||||
wayland_scanner_server = generator(
 | 
			
		||||
  wayland_scanner,
 | 
			
		||||
| 
						 | 
				
			
			@ -25,18 +24,19 @@ protocols = [
 | 
			
		|||
  [wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'],
 | 
			
		||||
  [wl_protocol_dir, 'staging/ext-idle-notify/ext-idle-notify-v1.xml'],
 | 
			
		||||
  [wl_protocol_dir, 'unstable/idle-inhibit/idle-inhibit-unstable-v1.xml'],
 | 
			
		||||
  [wl_protocol_dir, 'unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml'],
 | 
			
		||||
  [wl_protocol_dir, 'unstable/primary-selection/primary-selection-unstable-v1.xml'],
 | 
			
		||||
  [wl_protocol_dir, 'unstable/xdg-decoration/xdg-decoration-unstable-v1.xml'],
 | 
			
		||||
  [wl_protocol_dir, 'unstable/xdg-output/xdg-output-unstable-v1.xml'],
 | 
			
		||||
  'wlr-gamma-control-unstable-v1.xml',
 | 
			
		||||
  'wlr-layer-shell-unstable-v1.xml',
 | 
			
		||||
  'wlr-screencopy-unstable-v1.xml',
 | 
			
		||||
  'wlr-layer-shell-unstable-v1.xml',
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
client_protocols = [
 | 
			
		||||
  [wl_protocol_dir, 'unstable/idle-inhibit/idle-inhibit-unstable-v1.xml'],
 | 
			
		||||
  'wlr-layer-shell-unstable-v1.xml',
 | 
			
		||||
  'wlr-screencopy-unstable-v1.xml',
 | 
			
		||||
  'wlr-layer-shell-unstable-v1.xml',
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
wl_protos_src = []
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
										
											Binary file not shown.
										
									
								
							| 
		 Before Width: | Height: | Size: 763 KiB  | 
										
											Binary file not shown.
										
									
								
							| 
		 Before Width: | Height: | Size: 749 KiB  | 
										
											Binary file not shown.
										
									
								
							| 
		 Before Width: | Height: | Size: 142 KiB  | 
| 
						 | 
				
			
			@ -1,4 +1,3 @@
 | 
			
		|||
#include <libxml/parser.h>
 | 
			
		||||
#include <libxml/xpath.h>
 | 
			
		||||
#include <libxml/xpathInternals.h>
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -152,7 +151,6 @@ bool init_config(struct wb_server *server) {
 | 
			
		|||
 | 
			
		||||
	doc = xmlReadFile(rc_file, NULL, XML_PARSE_RECOVER);
 | 
			
		||||
	wlr_log(WLR_INFO, "Using config file %s", rc_file);
 | 
			
		||||
	setenv("WAYBOX_CONFIG_FILE", rc_file, true);
 | 
			
		||||
	free(rc_file);
 | 
			
		||||
	if (doc == NULL) {
 | 
			
		||||
		wlr_log(WLR_ERROR, "%s", _("Unable to parse the configuration file. Consult stderr for more information."));
 | 
			
		||||
| 
						 | 
				
			
			@ -168,35 +166,15 @@ bool init_config(struct wb_server *server) {
 | 
			
		|||
		wlr_log(WLR_INFO, "%s", _("Couldn't register the namespace"));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	config->keyboard_layout.use_config = parse_xpath_expr("//ob:keyboard//ob:xkb", ctxt) != NULL;
 | 
			
		||||
	config->keyboard_layout.use_config = parse_xpath_expr("//ob:keyboard//ob:keyboardLayout", ctxt) != NULL;
 | 
			
		||||
 | 
			
		||||
	if (config->keyboard_layout.use_config) {
 | 
			
		||||
		config->keyboard_layout.layout = parse_xpath_expr("//ob:keyboard//ob:xkb//ob:layout", ctxt);
 | 
			
		||||
		config->keyboard_layout.model = parse_xpath_expr("//ob:keyboard//ob:xkb//ob:model", ctxt);
 | 
			
		||||
		config->keyboard_layout.options = parse_xpath_expr("//ob:keyboard//ob:xkb//ob:options", ctxt);
 | 
			
		||||
		config->keyboard_layout.rules = parse_xpath_expr("//ob:keyboard//ob:xkb//ob:rules", ctxt);
 | 
			
		||||
		config->keyboard_layout.variant = parse_xpath_expr("//ob:keyboard//ob:xkb//ob:variant", ctxt);
 | 
			
		||||
		config->keyboard_layout.layout = parse_xpath_expr("//ob:keyboard//ob:keyboardLayout//ob:layout", ctxt);
 | 
			
		||||
		config->keyboard_layout.model = parse_xpath_expr("//ob:keyboard//ob:keyboardLayout//ob:model", ctxt);
 | 
			
		||||
		config->keyboard_layout.options = parse_xpath_expr("//ob:keyboard//ob:keyboardLayout//ob:options", ctxt);
 | 
			
		||||
		config->keyboard_layout.rules = parse_xpath_expr("//ob:keyboard//ob:keyboardLayout//ob:rules", ctxt);
 | 
			
		||||
		config->keyboard_layout.variant = parse_xpath_expr("//ob:keyboard//ob:keyboardLayout//ob:variant", ctxt);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	config->libinput_config.use_config = parse_xpath_expr("//ob:mouse//ob:libinput", ctxt) != NULL;
 | 
			
		||||
	if (config->libinput_config.use_config) {
 | 
			
		||||
		config->libinput_config.accel_profile = parse_xpath_expr("//ob:mouse//ob:libinput/ob:accelProfile", ctxt);
 | 
			
		||||
		config->libinput_config.accel_speed = parse_xpath_expr("//ob:mouse//ob:libinput/ob:accelSpeed", ctxt);
 | 
			
		||||
		config->libinput_config.calibration_matrix = parse_xpath_expr("//ob:mouse//ob:libinput/ob:calibrationMatrix", ctxt);
 | 
			
		||||
		config->libinput_config.click_method = parse_xpath_expr("//ob:mouse//ob:libinput/ob:clickMethod", ctxt);
 | 
			
		||||
		config->libinput_config.dwt = parse_xpath_expr("//ob:mouse//ob:libinput/ob:disableWhileTyping", ctxt);
 | 
			
		||||
		config->libinput_config.dwtp = parse_xpath_expr("//ob:mouse//ob:libinput/ob:disableWhileTrackpointing", ctxt);
 | 
			
		||||
		config->libinput_config.left_handed = parse_xpath_expr("//ob:mouse//ob:libinput/ob:leftHanded", ctxt);
 | 
			
		||||
		config->libinput_config.middle_emulation = parse_xpath_expr("//ob:mouse//ob:libinput/ob:middleEmulation", ctxt);
 | 
			
		||||
		config->libinput_config.natural_scroll = parse_xpath_expr("//ob:mouse//ob:libinput/ob:naturalScroll", ctxt);
 | 
			
		||||
		config->libinput_config.scroll_button = parse_xpath_expr("//ob:mouse//ob:libinput/ob:scrollButton", ctxt);
 | 
			
		||||
		config->libinput_config.scroll_button_lock = parse_xpath_expr("//ob:mouse//ob:libinput/ob:scrollButtonLock", ctxt);
 | 
			
		||||
		config->libinput_config.scroll_method = parse_xpath_expr("//ob:mouse//ob:libinput/ob:scrollMethod", ctxt);
 | 
			
		||||
		config->libinput_config.tap = parse_xpath_expr("//ob:mouse//ob:libinput/ob:tap", ctxt);
 | 
			
		||||
		config->libinput_config.tap_button_map = parse_xpath_expr("//ob:mouse//ob:libinput/ob:tapButtonMap", ctxt);
 | 
			
		||||
		config->libinput_config.tap_drag = parse_xpath_expr("//ob:mouse//ob:libinput/ob:tapDrag", ctxt);
 | 
			
		||||
		config->libinput_config.tap_drag = parse_xpath_expr("//ob:mouse//ob:libinput/ob:tapDragLock", ctxt);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!parse_key_bindings(config, ctxt)) {
 | 
			
		||||
		xmlFreeDoc(doc);
 | 
			
		||||
		return false;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -27,26 +27,6 @@ struct wb_config {
 | 
			
		|||
 | 
			
		||||
		bool use_config;
 | 
			
		||||
	} keyboard_layout;
 | 
			
		||||
	struct {
 | 
			
		||||
		char *accel_profile;
 | 
			
		||||
		char *accel_speed;
 | 
			
		||||
		char *calibration_matrix;
 | 
			
		||||
		char *click_method;
 | 
			
		||||
		char *dwt;
 | 
			
		||||
		char *dwtp;
 | 
			
		||||
		char *left_handed;
 | 
			
		||||
		char *middle_emulation;
 | 
			
		||||
		char *natural_scroll;
 | 
			
		||||
		char *scroll_button;
 | 
			
		||||
		char *scroll_button_lock;
 | 
			
		||||
		char *scroll_method;
 | 
			
		||||
		char *tap;
 | 
			
		||||
		char *tap_button_map;
 | 
			
		||||
		char *tap_drag;
 | 
			
		||||
		char *tap_drag_lock;
 | 
			
		||||
 | 
			
		||||
		bool use_config;
 | 
			
		||||
	} libinput_config;
 | 
			
		||||
	struct {
 | 
			
		||||
		int bottom;
 | 
			
		||||
		int left;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,22 +4,22 @@
 | 
			
		|||
void reset_cursor_mode(struct wb_server *server) {
 | 
			
		||||
	/* Reset the cursor mode to passthrough */
 | 
			
		||||
	server->cursor->cursor_mode = WB_CURSOR_PASSTHROUGH;
 | 
			
		||||
	server->grabbed_toplevel = NULL;
 | 
			
		||||
	server->grabbed_view = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void process_cursor_move(struct wb_server *server) {
 | 
			
		||||
	/* Move the grabbed toplevel to the new position. */
 | 
			
		||||
	struct wb_toplevel *toplevel = server->grabbed_toplevel;
 | 
			
		||||
	if (toplevel->scene_tree->node.type == WLR_SCENE_NODE_TREE) {
 | 
			
		||||
		toplevel->geometry.x = server->cursor->cursor->x - server->grab_x;
 | 
			
		||||
		toplevel->geometry.y = server->cursor->cursor->y - server->grab_y;
 | 
			
		||||
		wlr_scene_node_set_position(&toplevel->scene_tree->node,
 | 
			
		||||
				toplevel->geometry.x, toplevel->geometry.y);
 | 
			
		||||
	/* Move the grabbed view to the new position. */
 | 
			
		||||
	struct wb_view *view = server->grabbed_view;
 | 
			
		||||
	if (view->scene_tree->node.type == WLR_SCENE_NODE_TREE) {
 | 
			
		||||
		view->geometry.x = server->cursor->cursor->x - server->grab_x;
 | 
			
		||||
		view->geometry.y = server->cursor->cursor->y - server->grab_y;
 | 
			
		||||
		wlr_scene_node_set_position(&view->scene_tree->node,
 | 
			
		||||
				view->geometry.x, view->geometry.y);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void process_cursor_resize(struct wb_server *server) {
 | 
			
		||||
	struct wb_toplevel *toplevel = server->grabbed_toplevel;
 | 
			
		||||
	struct wb_view *view = server->grabbed_view;
 | 
			
		||||
	double border_x = server->cursor->cursor->x - server->grab_x;
 | 
			
		||||
	double border_y = server->cursor->cursor->y - server->grab_y;
 | 
			
		||||
	int new_left = server->grab_geo_box.x;
 | 
			
		||||
| 
						 | 
				
			
			@ -50,20 +50,16 @@ static void process_cursor_resize(struct wb_server *server) {
 | 
			
		|||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
#if WLR_CHECK_VERSION(0, 19, 0)
 | 
			
		||||
	struct wlr_box geo_box = toplevel->xdg_toplevel->base->geometry;
 | 
			
		||||
#else
 | 
			
		||||
	struct wlr_box geo_box;
 | 
			
		||||
	wlr_xdg_surface_get_geometry(toplevel->xdg_toplevel->base, &geo_box);
 | 
			
		||||
#endif
 | 
			
		||||
	toplevel->geometry.x = new_left - geo_box.x;
 | 
			
		||||
	toplevel->geometry.y = new_top - geo_box.y;
 | 
			
		||||
		wlr_scene_node_set_position(&toplevel->scene_tree->node,
 | 
			
		||||
				toplevel->geometry.x, toplevel->geometry.y);
 | 
			
		||||
	wlr_xdg_surface_get_geometry(view->xdg_toplevel->base, &geo_box);
 | 
			
		||||
	view->geometry.x = new_left - geo_box.x;
 | 
			
		||||
	view->geometry.y = new_top - geo_box.y;
 | 
			
		||||
		wlr_scene_node_set_position(&view->scene_tree->node,
 | 
			
		||||
				view->geometry.x, view->geometry.y);
 | 
			
		||||
 | 
			
		||||
	int new_width = new_right - new_left;
 | 
			
		||||
	int new_height = new_bottom - new_top;
 | 
			
		||||
	wlr_xdg_toplevel_set_size(toplevel->xdg_toplevel, new_width, new_height);
 | 
			
		||||
	wlr_xdg_toplevel_set_size(view->xdg_toplevel, new_width, new_height);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void process_cursor_motion(struct wb_server *server, uint32_t time) {
 | 
			
		||||
| 
						 | 
				
			
			@ -76,18 +72,18 @@ static void process_cursor_motion(struct wb_server *server, uint32_t time) {
 | 
			
		|||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Otherwise, find the toplevel under the pointer and send the event along. */
 | 
			
		||||
	/* Otherwise, find the view under the pointer and send the event along. */
 | 
			
		||||
	double sx, sy;
 | 
			
		||||
	struct wlr_seat *seat = server->seat->seat;
 | 
			
		||||
	struct wlr_surface *surface = NULL;
 | 
			
		||||
	struct wb_toplevel *toplevel = get_toplevel_at(server,
 | 
			
		||||
	struct wb_view *view = get_view_at(server,
 | 
			
		||||
			server->cursor->cursor->x, server->cursor->cursor->y, &surface, &sx, &sy);
 | 
			
		||||
	if (!toplevel) {
 | 
			
		||||
		/* If there's no toplevel under the cursor, set the cursor image to a
 | 
			
		||||
	if (!view) {
 | 
			
		||||
		/* If there's no view under the cursor, set the cursor image to a
 | 
			
		||||
		 * default. This is what makes the cursor image appear when you move it
 | 
			
		||||
		 * around the screen, not over any toplevels. */
 | 
			
		||||
		wlr_cursor_set_xcursor(
 | 
			
		||||
				server->cursor->cursor, server->cursor->xcursor_manager, "default");
 | 
			
		||||
		 * around the screen, not over any views. */
 | 
			
		||||
		wlr_xcursor_manager_set_cursor_image(
 | 
			
		||||
				server->cursor->xcursor_manager, "left_ptr", server->cursor->cursor);
 | 
			
		||||
	}
 | 
			
		||||
	if (surface) {
 | 
			
		||||
		/*
 | 
			
		||||
| 
						 | 
				
			
			@ -138,14 +134,14 @@ static void handle_cursor_button(struct wl_listener *listener, void *data) {
 | 
			
		|||
			event->time_msec, event->button, event->state);
 | 
			
		||||
	double sx, sy;
 | 
			
		||||
	struct wlr_surface *surface = NULL;
 | 
			
		||||
	struct wb_toplevel *toplevel = get_toplevel_at(cursor->server,
 | 
			
		||||
	struct wb_view *view = get_view_at(cursor->server,
 | 
			
		||||
			cursor->server->cursor->cursor->x, cursor->server->cursor->cursor->y, &surface, &sx, &sy);
 | 
			
		||||
	if (event->state == WL_POINTER_BUTTON_STATE_RELEASED) {
 | 
			
		||||
	if (event->state == WLR_BUTTON_RELEASED) {
 | 
			
		||||
		/* If you released any buttons, we exit interactive move/resize mode. */
 | 
			
		||||
		reset_cursor_mode(cursor->server);
 | 
			
		||||
	} else {
 | 
			
		||||
		/* Focus that client if the button was _pressed_ */
 | 
			
		||||
		focus_toplevel(toplevel);
 | 
			
		||||
		focus_view(view, surface);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	wlr_idle_notifier_v1_notify_activity(cursor->server->idle_notifier, cursor->server->seat->seat);
 | 
			
		||||
| 
						 | 
				
			
			@ -160,7 +156,7 @@ static void handle_cursor_axis(struct wl_listener *listener, void *data) {
 | 
			
		|||
	/* Notify the client with pointer focus of the axis event. */
 | 
			
		||||
	wlr_seat_pointer_notify_axis(cursor->server->seat->seat,
 | 
			
		||||
			event->time_msec, event->orientation, event->delta,
 | 
			
		||||
			event->delta_discrete, event->source, event->relative_direction);
 | 
			
		||||
			event->delta_discrete, event->source);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_cursor_frame(struct wl_listener *listener, void *data) {
 | 
			
		||||
| 
						 | 
				
			
			@ -202,6 +198,7 @@ struct wb_cursor *wb_cursor_create(struct wb_server *server) {
 | 
			
		|||
	const char *xcursor_size = getenv("XCURSOR_SIZE");
 | 
			
		||||
	cursor->xcursor_manager = wlr_xcursor_manager_create(getenv("XCURSOR_THEME"),
 | 
			
		||||
				xcursor_size ? strtoul(xcursor_size, (char **) NULL, 10) : 24);
 | 
			
		||||
	wlr_xcursor_manager_load(cursor->xcursor_manager, 1);
 | 
			
		||||
 | 
			
		||||
	cursor->cursor_motion.notify = handle_cursor_motion;
 | 
			
		||||
	wl_signal_add(&cursor->cursor->events.motion, &cursor->cursor_motion);
 | 
			
		||||
| 
						 | 
				
			
			@ -232,14 +229,6 @@ void wb_cursor_destroy(struct wb_cursor *cursor) {
 | 
			
		|||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	wl_list_remove(&cursor->request_cursor.link);
 | 
			
		||||
	wl_list_remove(&cursor->cursor_motion.link);
 | 
			
		||||
	wl_list_remove(&cursor->cursor_motion_absolute.link);
 | 
			
		||||
 | 
			
		||||
	wl_list_remove(&cursor->cursor_button.link);
 | 
			
		||||
	wl_list_remove(&cursor->cursor_axis.link);
 | 
			
		||||
	wl_list_remove(&cursor->cursor_frame.link);
 | 
			
		||||
 | 
			
		||||
	wlr_xcursor_manager_destroy(cursor->xcursor_manager);
 | 
			
		||||
	wlr_cursor_destroy(cursor->cursor);
 | 
			
		||||
	free(cursor);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -15,10 +15,9 @@ static void free_xdg_decoration_mode(struct wl_listener *listener, void *data) {
 | 
			
		|||
static void handle_xdg_decoration_mode(struct wl_listener *listener, void *data) {
 | 
			
		||||
	struct wlr_xdg_toplevel_decoration_v1 *toplevel_decoration = data;
 | 
			
		||||
	struct wb_decoration *decoration = wl_container_of(listener, decoration, request_mode);
 | 
			
		||||
	struct wb_toplevel *toplevel = wl_container_of(decoration->server->toplevels.next, toplevel, link);
 | 
			
		||||
	if (toplevel->xdg_toplevel->base->initialized)
 | 
			
		||||
	struct wb_view *view = wl_container_of(decoration->server->views.next, view, link);
 | 
			
		||||
	wlr_xdg_toplevel_decoration_v1_set_mode(toplevel_decoration, WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE);
 | 
			
		||||
	toplevel->decoration = toplevel_decoration;
 | 
			
		||||
	view->decoration = toplevel_decoration;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_new_xdg_toplevel_decoration(struct wl_listener *listener, void *data) {
 | 
			
		||||
| 
						 | 
				
			
			@ -32,6 +31,8 @@ static void handle_new_xdg_toplevel_decoration(struct wl_listener *listener, voi
 | 
			
		|||
	wl_signal_add(&toplevel_decoration->events.request_mode, &decoration->request_mode);
 | 
			
		||||
	decoration->mode_destroy.notify = free_xdg_decoration_mode;
 | 
			
		||||
	wl_signal_add(&toplevel_decoration->events.destroy, &decoration->mode_destroy);
 | 
			
		||||
	/* For some reason, a lot of clients don't emit the request_mode signal. */
 | 
			
		||||
	handle_xdg_decoration_mode(&decoration->request_mode, toplevel_decoration);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void init_xdg_decoration(struct wb_server *server) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,41 +0,0 @@
 | 
			
		|||
#include <wlr/types/wlr_idle_inhibit_v1.h>
 | 
			
		||||
 | 
			
		||||
#include "idle.h"
 | 
			
		||||
 | 
			
		||||
static void idle_inhibit_manager_destroy(struct wl_listener *listener, void *data) {
 | 
			
		||||
	struct wb_server *server = wl_container_of(listener, server, destroy_inhibit_manager);
 | 
			
		||||
	wl_list_remove(&server->new_inhibitor.link);
 | 
			
		||||
	wl_list_remove(&server->inhibitors);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void idle_inhibitor_destroy(struct wl_listener *listener, void *data) {
 | 
			
		||||
	struct wb_server *server = wl_container_of(listener, server, destroy_inhibitor);
 | 
			
		||||
	/* wlroots will destroy the inhibitor after this callback, so this number will be 1 if the
 | 
			
		||||
	 * last inhibitor is being destroyed. */
 | 
			
		||||
	wl_list_remove(&server->destroy_inhibitor.link);
 | 
			
		||||
	wlr_idle_notifier_v1_set_inhibited(server->idle_notifier,
 | 
			
		||||
			wl_list_length(&server->inhibitors) > 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void idle_inhibitor_new(struct wl_listener *listener, void *data) {
 | 
			
		||||
	struct wb_server *server = wl_container_of(listener, server, new_inhibitor);
 | 
			
		||||
	struct wlr_idle_inhibitor_v1 *inhibitor = data;
 | 
			
		||||
 | 
			
		||||
	server->destroy_inhibitor.notify = idle_inhibitor_destroy;
 | 
			
		||||
	wl_signal_add(&inhibitor->events.destroy, &server->destroy_inhibitor);
 | 
			
		||||
	wl_list_remove(&inhibitor->link);
 | 
			
		||||
	wl_list_insert(&server->inhibitors, &inhibitor->link);
 | 
			
		||||
	wlr_idle_notifier_v1_set_inhibited(server->idle_notifier, true);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool create_idle_manager(struct wb_server *server) {
 | 
			
		||||
	server->idle_notifier = wlr_idle_notifier_v1_create(server->wl_display);
 | 
			
		||||
	server->idle_inhibit_manager = wlr_idle_inhibit_v1_create(server->wl_display);
 | 
			
		||||
 | 
			
		||||
	wl_list_init(&server->inhibitors);
 | 
			
		||||
	server->new_inhibitor.notify = idle_inhibitor_new;
 | 
			
		||||
	wl_signal_add(&server->idle_inhibit_manager->events.new_inhibitor, &server->new_inhibitor);
 | 
			
		||||
	server->destroy_inhibit_manager.notify = idle_inhibit_manager_destroy;
 | 
			
		||||
	wl_signal_add(&server->idle_inhibit_manager->events.destroy, &server->destroy_inhibit_manager);
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,3 +0,0 @@
 | 
			
		|||
#include "waybox/server.h"
 | 
			
		||||
 | 
			
		||||
bool create_idle_manager(struct wb_server *server);
 | 
			
		||||
| 
						 | 
				
			
			@ -53,7 +53,6 @@ static void arrange_surface(struct wb_output *output, struct wlr_box *full_area,
 | 
			
		|||
 | 
			
		||||
		if (desc->type == WB_SCENE_DESC_LAYER_SHELL) {
 | 
			
		||||
			struct wb_layer_surface *surface = desc->data;
 | 
			
		||||
			surface->scene->layer_surface->initialized = true;
 | 
			
		||||
			wlr_scene_layer_surface_v1_configure(surface->scene,
 | 
			
		||||
					full_area, usable_area);
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -106,13 +105,10 @@ static struct wb_layer_surface *wb_layer_surface_create(
 | 
			
		|||
static void handle_surface_commit(struct wl_listener *listener, void *data) {
 | 
			
		||||
	struct wb_layer_surface *surface =
 | 
			
		||||
		wl_container_of(listener, surface, surface_commit);
 | 
			
		||||
	struct wb_toplevel *current_toplevel =
 | 
			
		||||
		wl_container_of(surface->server->toplevels.next, current_toplevel, link);
 | 
			
		||||
 | 
			
		||||
	if (!surface->output || current_toplevel->xdg_toplevel->current.fullscreen) {
 | 
			
		||||
	if (!surface->output) {
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	wlr_fractional_scale_v1_notify_scale(surface->scene->layer_surface->surface, surface->output->wlr_output->scale);
 | 
			
		||||
 | 
			
		||||
	struct wlr_layer_surface_v1 *layer_surface = surface->scene->layer_surface;
 | 
			
		||||
	uint32_t committed = layer_surface->current.committed;
 | 
			
		||||
| 
						 | 
				
			
			@ -125,8 +121,8 @@ static void handle_surface_commit(struct wl_listener *listener, void *data) {
 | 
			
		|||
		wlr_scene_node_reparent(&surface->scene->tree->node, output_layer);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (committed || layer_surface->surface->mapped != surface->mapped) {
 | 
			
		||||
		surface->mapped = layer_surface->surface->mapped;
 | 
			
		||||
	if (committed || layer_surface->mapped != surface->mapped) {
 | 
			
		||||
		surface->mapped = layer_surface->mapped;
 | 
			
		||||
		arrange_layers(surface->output);
 | 
			
		||||
 | 
			
		||||
		struct timespec now;
 | 
			
		||||
| 
						 | 
				
			
			@ -174,12 +170,9 @@ static void handle_unmap(struct wl_listener *listener, void *data) {
 | 
			
		|||
		seat_set_focus_layer(seat, NULL);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!wl_list_empty(&surface->server->toplevels)) {
 | 
			
		||||
		struct wb_toplevel *toplevel =
 | 
			
		||||
			wl_container_of(surface->server->toplevels.next, toplevel, link);
 | 
			
		||||
		if (toplevel && toplevel->scene_tree && toplevel->scene_tree->node.enabled) {
 | 
			
		||||
			focus_toplevel(toplevel);
 | 
			
		||||
		}
 | 
			
		||||
	struct wb_view *view = wl_container_of(surface->server->views.next, view, link);
 | 
			
		||||
	if (view && view->scene_tree && view->scene_tree->node.enabled) {
 | 
			
		||||
		focus_view(view, view->xdg_toplevel->base->surface);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -188,10 +181,6 @@ static void wb_layer_surface_destroy(struct wb_layer_surface *surface) {
 | 
			
		|||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (surface->scene->layer_surface->surface != NULL)
 | 
			
		||||
		wlr_fractional_scale_v1_notify_scale(surface->scene->layer_surface->surface,
 | 
			
		||||
				surface->output->wlr_output->scale);
 | 
			
		||||
 | 
			
		||||
	wl_list_remove(&surface->map.link);
 | 
			
		||||
	wl_list_remove(&surface->unmap.link);
 | 
			
		||||
	wl_list_remove(&surface->surface_commit.link);
 | 
			
		||||
| 
						 | 
				
			
			@ -208,7 +197,6 @@ static void handle_destroy(struct wl_listener *listener, void *data) {
 | 
			
		|||
		arrange_layers(surface->output);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	wl_list_remove(&surface->new_popup.link);
 | 
			
		||||
	wb_layer_surface_destroy(surface);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -317,10 +305,9 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) {
 | 
			
		|||
	if (layer_surface->output == NULL) {
 | 
			
		||||
		struct wb_server *server =
 | 
			
		||||
			wl_container_of(listener, server, new_layer_surface);
 | 
			
		||||
		if (wl_list_length(&server->toplevels) == 0) return;
 | 
			
		||||
		struct wb_toplevel *toplevel =
 | 
			
		||||
			wl_container_of(server->toplevels.next, toplevel, link);
 | 
			
		||||
		layer_surface->output = get_active_output(toplevel);
 | 
			
		||||
		struct wb_view *view =
 | 
			
		||||
			wl_container_of(server->views.next, view, link);
 | 
			
		||||
		layer_surface->output = get_active_output(view);
 | 
			
		||||
	}
 | 
			
		||||
	struct wb_output *output = layer_surface->output->data;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -356,9 +343,9 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) {
 | 
			
		|||
	wl_signal_add(&layer_surface->surface->events.commit,
 | 
			
		||||
		&surface->surface_commit);
 | 
			
		||||
	surface->map.notify = handle_map;
 | 
			
		||||
	wl_signal_add(&layer_surface->surface->events.map, &surface->map);
 | 
			
		||||
	wl_signal_add(&layer_surface->events.map, &surface->map);
 | 
			
		||||
	surface->unmap.notify = handle_unmap;
 | 
			
		||||
	wl_signal_add(&layer_surface->surface->events.unmap, &surface->unmap);
 | 
			
		||||
	wl_signal_add(&layer_surface->events.unmap, &surface->unmap);
 | 
			
		||||
	surface->destroy.notify = handle_destroy;
 | 
			
		||||
	wl_signal_add(&layer_surface->events.destroy, &surface->destroy);
 | 
			
		||||
	surface->new_popup.notify = handle_new_popup;
 | 
			
		||||
| 
						 | 
				
			
			@ -373,7 +360,7 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
void init_layer_shell(struct wb_server *server) {
 | 
			
		||||
	server->layer_shell = wlr_layer_shell_v1_create(server->wl_display, 4);
 | 
			
		||||
	server->layer_shell = wlr_layer_shell_v1_create(server->wl_display);
 | 
			
		||||
	server->new_layer_surface.notify = handle_layer_shell_surface;
 | 
			
		||||
	wl_signal_add(&server->layer_shell->events.new_surface,
 | 
			
		||||
			&server->new_layer_surface);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,7 +2,7 @@
 | 
			
		|||
#define _WB_LAYERS_H
 | 
			
		||||
#include <wlr/types/wlr_layer_shell_v1.h>
 | 
			
		||||
 | 
			
		||||
#include "waybox/output.h"
 | 
			
		||||
struct wb_server;
 | 
			
		||||
 | 
			
		||||
struct wb_layer_surface {
 | 
			
		||||
	struct wb_output *output;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -28,8 +28,8 @@ void signal_handler(int sig) {
 | 
			
		|||
			wl_display_terminate(server.wl_display);
 | 
			
		||||
			break;
 | 
			
		||||
		case SIGUSR1:
 | 
			
		||||
			/* Openbox uses SIGUSR1 to restart and SIGUSR2 to reconfigure.
 | 
			
		||||
			 * What's the difference?
 | 
			
		||||
			/* Openbox uses SIGUSR1 to restart. I'm not sure of the
 | 
			
		||||
			 * difference between restarting and reconfiguring.
 | 
			
		||||
			 */
 | 
			
		||||
		case SIGUSR2:
 | 
			
		||||
			deinit_config(server.config);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,7 +2,6 @@ wb_src = files(
 | 
			
		|||
  'config.c',
 | 
			
		||||
  'cursor.c',
 | 
			
		||||
  'decoration.c',
 | 
			
		||||
  'idle.c',
 | 
			
		||||
  'layer_shell.c',
 | 
			
		||||
  'main.c',
 | 
			
		||||
  'output.c',
 | 
			
		||||
| 
						 | 
				
			
			@ -12,8 +11,6 @@ wb_src = files(
 | 
			
		|||
  )
 | 
			
		||||
 | 
			
		||||
wb_dep = [
 | 
			
		||||
  libevdev,
 | 
			
		||||
  libinput,
 | 
			
		||||
  libxml2,
 | 
			
		||||
  wayland_server,
 | 
			
		||||
  wlroots,
 | 
			
		||||
| 
						 | 
				
			
			@ -27,5 +24,4 @@ executable(
 | 
			
		|||
  dependencies: [wb_dep, wlr_protos],
 | 
			
		||||
  install: true,
 | 
			
		||||
  install_dir: get_option('prefix') / get_option('libexecdir'),
 | 
			
		||||
  link_args: ['-Wl,-lm'],
 | 
			
		||||
  )
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										106
									
								
								waybox/output.c
									
										
									
									
									
								
							
							
						
						
									
										106
									
								
								waybox/output.c
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -10,32 +10,14 @@ void output_frame_notify(struct wl_listener *listener, void *data) {
 | 
			
		|||
 | 
			
		||||
	wlr_output_layout_get_box(output->server->output_layout,
 | 
			
		||||
			output->wlr_output, &output->geometry);
 | 
			
		||||
 | 
			
		||||
	if (output->gamma_lut_changed) {
 | 
			
		||||
		output->gamma_lut_changed = false;
 | 
			
		||||
		struct wlr_gamma_control_v1 *gamma_control =
 | 
			
		||||
			wlr_gamma_control_manager_v1_get_control(output->server->gamma_control_manager,
 | 
			
		||||
					output->wlr_output);
 | 
			
		||||
		struct wlr_output_state pending;
 | 
			
		||||
		if (!wlr_scene_output_build_state(scene_output, &pending, NULL))
 | 
			
		||||
			return;
 | 
			
		||||
 | 
			
		||||
		if (!wlr_gamma_control_v1_apply(gamma_control, &pending)) {
 | 
			
		||||
			wlr_output_state_finish(&pending);
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (!wlr_output_test_state(output->wlr_output, &pending)) {
 | 
			
		||||
			wlr_gamma_control_v1_send_failed_and_destroy(gamma_control);
 | 
			
		||||
			wlr_output_state_finish(&pending);
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		wlr_output_state_finish(&pending);
 | 
			
		||||
	}
 | 
			
		||||
#if ! WLR_CHECK_VERSION(0, 17, 0)
 | 
			
		||||
	/* Update the background for the current output size. */
 | 
			
		||||
	wlr_scene_rect_set_size(output->background,
 | 
			
		||||
			output->geometry.width, output->geometry.height);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	/* Render the scene if needed and commit the output */
 | 
			
		||||
	wlr_scene_output_commit(scene_output, NULL);
 | 
			
		||||
	wlr_scene_output_commit(scene_output);
 | 
			
		||||
 | 
			
		||||
	/* This lets the client know that we've displayed that frame and it can
 | 
			
		||||
	 * prepare another one now if it likes. */
 | 
			
		||||
| 
						 | 
				
			
			@ -44,39 +26,11 @@ void output_frame_notify(struct wl_listener *listener, void *data) {
 | 
			
		|||
	wlr_scene_output_send_frame_done(scene_output, &now);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void output_configuration_applied(struct wl_listener *listener, void *data) {
 | 
			
		||||
	struct wb_server *server = wl_container_of(listener, server, wlr_output_manager);
 | 
			
		||||
	struct wlr_output_configuration_v1 *configuration = data;
 | 
			
		||||
	wlr_output_configuration_v1_send_succeeded(configuration);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void output_configuration_tested(struct wl_listener *listener, void *data) {
 | 
			
		||||
	output_configuration_applied(listener, data);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void output_request_state_notify(struct wl_listener *listener, void *data) {
 | 
			
		||||
	struct wb_output *output = wl_container_of(listener, output, request_state);
 | 
			
		||||
	const struct wlr_output_event_request_state *event = data;
 | 
			
		||||
 | 
			
		||||
	struct wlr_output_configuration_v1 *configuration = wlr_output_configuration_v1_create();
 | 
			
		||||
	wlr_output_manager_v1_set_configuration(output->server->wlr_output_manager, configuration);
 | 
			
		||||
 | 
			
		||||
	wlr_output_commit_state(output->wlr_output, event->state);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void handle_gamma_control_set_gamma(struct wl_listener *listener, void *data) {
 | 
			
		||||
	const struct wlr_gamma_control_manager_v1_set_gamma_event *event = data;
 | 
			
		||||
	struct wb_output *output = event->output->data;
 | 
			
		||||
	output->gamma_lut_changed = true;
 | 
			
		||||
	wlr_output_schedule_frame(output->wlr_output);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void output_destroy_notify(struct wl_listener *listener, void *data) {
 | 
			
		||||
       	struct wb_output *output = wl_container_of(listener, output, destroy);
 | 
			
		||||
 | 
			
		||||
	wl_list_remove(&output->destroy.link);
 | 
			
		||||
	wl_list_remove(&output->frame.link);
 | 
			
		||||
	wl_list_remove(&output->request_state.link);
 | 
			
		||||
 | 
			
		||||
	/* Frees the layers */
 | 
			
		||||
	size_t num_layers = sizeof(output->layers) / sizeof(struct wlr_scene_node *);
 | 
			
		||||
| 
						 | 
				
			
			@ -101,23 +55,29 @@ void new_output_notify(struct wl_listener *listener, void *data) {
 | 
			
		|||
         * and our renderer */
 | 
			
		||||
	wlr_output_init_render(wlr_output, server->allocator, server->renderer);
 | 
			
		||||
 | 
			
		||||
	if (!wl_list_empty(&wlr_output->modes)) {
 | 
			
		||||
		struct wlr_output_mode *mode = wlr_output_preferred_mode(wlr_output);
 | 
			
		||||
	struct wlr_output_state state;
 | 
			
		||||
	wlr_output_state_init(&state);
 | 
			
		||||
	wlr_output_state_set_enabled(&state, true);
 | 
			
		||||
		wlr_output_set_mode(wlr_output, mode);
 | 
			
		||||
		wlr_output_enable(wlr_output, true);
 | 
			
		||||
 | 
			
		||||
	if (mode != NULL) {
 | 
			
		||||
		wlr_output_state_set_mode(&state, mode);
 | 
			
		||||
		if (!wlr_output_commit(wlr_output)) {
 | 
			
		||||
			wlr_log_errno(WLR_ERROR, "%s", _("Couldn't commit pending frame to output"));
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	wlr_output_commit_state(wlr_output, &state);
 | 
			
		||||
	wlr_output_state_finish(&state);
 | 
			
		||||
 | 
			
		||||
	struct wb_output *output = calloc(1, sizeof(struct wb_output));
 | 
			
		||||
	output->server = server;
 | 
			
		||||
	output->wlr_output = wlr_output;
 | 
			
		||||
	wlr_output->data = output;
 | 
			
		||||
 | 
			
		||||
#if ! WLR_CHECK_VERSION(0, 17, 0)
 | 
			
		||||
	/* Set the background color */
 | 
			
		||||
	float color[4] = {0.1875, 0.1875, 0.1875, 1.0};
 | 
			
		||||
	output->background = wlr_scene_rect_create(&server->scene->tree, 0, 0, color);
 | 
			
		||||
	wlr_scene_node_lower_to_bottom(&output->background->node);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	/* Initializes the layers */
 | 
			
		||||
	size_t num_layers = sizeof(output->layers) / sizeof(struct wlr_scene_node *);
 | 
			
		||||
	for (size_t i = 0; i < num_layers; i++) {
 | 
			
		||||
| 
						 | 
				
			
			@ -131,8 +91,6 @@ void new_output_notify(struct wl_listener *listener, void *data) {
 | 
			
		|||
	wl_signal_add(&wlr_output->events.destroy, &output->destroy);
 | 
			
		||||
	output->frame.notify = output_frame_notify;
 | 
			
		||||
	wl_signal_add(&wlr_output->events.frame, &output->frame);
 | 
			
		||||
	output->request_state.notify = output_request_state_notify;
 | 
			
		||||
	wl_signal_add(&wlr_output->events.request_state, &output->request_state);
 | 
			
		||||
 | 
			
		||||
	/* Adds this to the output layout. The add_auto function arranges outputs
 | 
			
		||||
	 * from left-to-right in the order they appear. A more sophisticated
 | 
			
		||||
| 
						 | 
				
			
			@ -143,29 +101,5 @@ void new_output_notify(struct wl_listener *listener, void *data) {
 | 
			
		|||
	 * display, which Wayland clients can see to find out information about the
 | 
			
		||||
	 * output (such as DPI, scale factor, manufacturer, etc).
 | 
			
		||||
	 */
 | 
			
		||||
	struct wlr_output_layout_output *l_output =
 | 
			
		||||
	wlr_output_layout_add_auto(server->output_layout, wlr_output);
 | 
			
		||||
	if (!l_output) {
 | 
			
		||||
		wlr_log(WLR_ERROR, "%s", _("Could not add an output layout."));
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	struct wlr_output_configuration_v1 *configuration = wlr_output_configuration_v1_create();
 | 
			
		||||
	wlr_output_configuration_head_v1_create(configuration, wlr_output);
 | 
			
		||||
	wlr_output_manager_v1_set_configuration(server->wlr_output_manager, configuration);
 | 
			
		||||
 | 
			
		||||
	struct wlr_scene_output *scene_output = wlr_scene_output_create(server->scene, wlr_output);
 | 
			
		||||
	wlr_scene_output_layout_add_output(server->scene_layout, l_output, scene_output);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void init_output(struct wb_server *server) {
 | 
			
		||||
	wl_list_init(&server->outputs);
 | 
			
		||||
 | 
			
		||||
	server->new_output.notify = new_output_notify;
 | 
			
		||||
	wl_signal_add(&server->backend->events.new_output, &server->new_output);
 | 
			
		||||
 | 
			
		||||
	server->wlr_output_manager = wlr_output_manager_v1_create(server->wl_display);
 | 
			
		||||
	server->output_configuration_applied.notify = output_configuration_applied;
 | 
			
		||||
	wl_signal_add(&server->wlr_output_manager->events.apply, &server->output_configuration_applied);
 | 
			
		||||
	wl_signal_add(&server->wlr_output_manager->events.test, &server->output_configuration_tested);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										238
									
								
								waybox/seat.c
									
										
									
									
									
								
							
							
						
						
									
										238
									
								
								waybox/seat.c
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -1,58 +1,50 @@
 | 
			
		|||
#include <libevdev/libevdev.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
 | 
			
		||||
#include <wlr/config.h>
 | 
			
		||||
#if WLR_HAS_LIBINPUT_BACKEND && defined(HAS_LIBINPUT)
 | 
			
		||||
#include <wlr/backend/libinput.h>
 | 
			
		||||
#else
 | 
			
		||||
#undef HAS_LIBINPUT
 | 
			
		||||
#endif
 | 
			
		||||
#include <wlr/backend/session.h>
 | 
			
		||||
#include <wlr/types/wlr_primary_selection.h>
 | 
			
		||||
#include <wlr/types/wlr_primary_selection_v1.h>
 | 
			
		||||
 | 
			
		||||
#include "waybox/seat.h"
 | 
			
		||||
#include "waybox/xdg_shell.h"
 | 
			
		||||
 | 
			
		||||
static void deiconify_toplevel(struct wb_toplevel *toplevel) {
 | 
			
		||||
	if (toplevel->xdg_toplevel->requested.minimized) {
 | 
			
		||||
		toplevel->xdg_toplevel->requested.minimized = false;
 | 
			
		||||
		wl_signal_emit(&toplevel->xdg_toplevel->events.request_minimize, NULL);
 | 
			
		||||
static void deiconify_view(struct wb_view *view) {
 | 
			
		||||
	if (view->xdg_toplevel->requested.minimized) {
 | 
			
		||||
		view->xdg_toplevel->requested.minimized = false;
 | 
			
		||||
		wl_signal_emit(&view->xdg_toplevel->events.request_minimize, NULL);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void cycle_toplevels(struct wb_server *server) {
 | 
			
		||||
	/* Cycle to the next toplevel */
 | 
			
		||||
	if (wl_list_length(&server->toplevels) < 1) {
 | 
			
		||||
static void cycle_views(struct wb_server *server) {
 | 
			
		||||
	/* Cycle to the next view */
 | 
			
		||||
	if (wl_list_length(&server->views) < 1) {
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	struct wb_toplevel *current_toplevel = wl_container_of(
 | 
			
		||||
		server->toplevels.prev, current_toplevel, link);
 | 
			
		||||
	deiconify_toplevel(current_toplevel);
 | 
			
		||||
	focus_toplevel(current_toplevel);
 | 
			
		||||
	struct wb_view *current_view = wl_container_of(
 | 
			
		||||
		server->views.prev, current_view, link);
 | 
			
		||||
	deiconify_view(current_view);
 | 
			
		||||
	focus_view(current_view, current_view->xdg_toplevel->base->surface);
 | 
			
		||||
 | 
			
		||||
	/* Move the current toplevel to the beginning of the list */
 | 
			
		||||
	wl_list_remove(¤t_toplevel->link);
 | 
			
		||||
	wl_list_insert(&server->toplevels, ¤t_toplevel->link);
 | 
			
		||||
	/* Move the current view to the beginning of the list */
 | 
			
		||||
	wl_list_remove(¤t_view->link);
 | 
			
		||||
	wl_list_insert(&server->views, ¤t_view->link);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void cycle_toplevels_reverse(struct wb_server *server) {
 | 
			
		||||
	/* Cycle to the previous toplevel */
 | 
			
		||||
	if (wl_list_length(&server->toplevels) < 1) {
 | 
			
		||||
static void cycle_views_reverse(struct wb_server *server) {
 | 
			
		||||
	/* Cycle to the previous view */
 | 
			
		||||
	if (wl_list_length(&server->views) < 1) {
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	struct wb_toplevel *current_toplevel = wl_container_of(
 | 
			
		||||
		server->toplevels.next, current_toplevel, link);
 | 
			
		||||
	struct wb_toplevel *next_toplevel = wl_container_of(
 | 
			
		||||
		current_toplevel->link.next, next_toplevel, link);
 | 
			
		||||
	deiconify_toplevel(next_toplevel);
 | 
			
		||||
	focus_toplevel(next_toplevel);
 | 
			
		||||
	struct wb_view *current_view = wl_container_of(
 | 
			
		||||
		server->views.next, current_view, link);
 | 
			
		||||
	struct wb_view *next_view = wl_container_of(
 | 
			
		||||
		current_view->link.next, next_view, link);
 | 
			
		||||
	deiconify_view(next_view);
 | 
			
		||||
	focus_view(next_view, next_view->xdg_toplevel->base->surface);
 | 
			
		||||
 | 
			
		||||
	/* Move the current toplevel to after the previous toplevel in the list */
 | 
			
		||||
	wl_list_remove(¤t_toplevel->link);
 | 
			
		||||
	wl_list_insert(server->toplevels.prev, ¤t_toplevel->link);
 | 
			
		||||
	/* Move the current view to after the previous view in the list */
 | 
			
		||||
	wl_list_remove(¤t_view->link);
 | 
			
		||||
	wl_list_insert(server->views.prev, ¤t_view->link);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool handle_keybinding(struct wb_server *server, xkb_keysym_t sym, uint32_t modifiers) {
 | 
			
		||||
| 
						 | 
				
			
			@ -64,25 +56,14 @@ static bool handle_keybinding(struct wb_server *server, xkb_keysym_t sym, uint32
 | 
			
		|||
	 * Returns true if the keybinding is handled, false to send it to the
 | 
			
		||||
	 * client.
 | 
			
		||||
	 */
 | 
			
		||||
 | 
			
		||||
	/* TODO: Make these configurable through rc.xml */
 | 
			
		||||
	if (modifiers & (WLR_MODIFIER_CTRL|WLR_MODIFIER_ALT) &&
 | 
			
		||||
		sym >= XKB_KEY_XF86Switch_VT_1 &&
 | 
			
		||||
		sym <= XKB_KEY_XF86Switch_VT_12) {
 | 
			
		||||
		unsigned int vt = sym - XKB_KEY_XF86Switch_VT_1 + 1;
 | 
			
		||||
		wlr_session_change_vt (server->session, vt);
 | 
			
		||||
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!server->config) {
 | 
			
		||||
		/* Some default key bindings, when the rc.xml file can't be
 | 
			
		||||
		 * parsed. */
 | 
			
		||||
		if (modifiers & WLR_MODIFIER_ALT && sym == XKB_KEY_Tab)
 | 
			
		||||
			cycle_toplevels(server);
 | 
			
		||||
			cycle_views(server);
 | 
			
		||||
		else if (modifiers & (WLR_MODIFIER_ALT|WLR_MODIFIER_SHIFT) &&
 | 
			
		||||
				sym == XKB_KEY_Tab)
 | 
			
		||||
			cycle_toplevels_reverse(server);
 | 
			
		||||
			cycle_views_reverse(server);
 | 
			
		||||
		else if (sym == XKB_KEY_Escape && modifiers & WLR_MODIFIER_CTRL)
 | 
			
		||||
			wl_display_terminate(server->wl_display);
 | 
			
		||||
		else
 | 
			
		||||
| 
						 | 
				
			
			@ -94,14 +75,14 @@ static bool handle_keybinding(struct wb_server *server, xkb_keysym_t sym, uint32
 | 
			
		|||
	wl_list_for_each(key_binding, &server->config->key_bindings, link) {
 | 
			
		||||
		if (sym == key_binding->sym && modifiers == key_binding->modifiers) {
 | 
			
		||||
			if (key_binding->action & ACTION_NEXT_WINDOW)
 | 
			
		||||
				cycle_toplevels(server);
 | 
			
		||||
				cycle_views(server);
 | 
			
		||||
			if (key_binding->action & ACTION_PREVIOUS_WINDOW)
 | 
			
		||||
				cycle_toplevels_reverse(server);
 | 
			
		||||
				cycle_views_reverse(server);
 | 
			
		||||
			if (key_binding->action & ACTION_CLOSE) {
 | 
			
		||||
				struct wb_toplevel *current_toplevel = wl_container_of(
 | 
			
		||||
						server->toplevels.next, current_toplevel, link);
 | 
			
		||||
				if (current_toplevel->scene_tree->node.enabled)
 | 
			
		||||
					wlr_xdg_toplevel_send_close(current_toplevel->xdg_toplevel);
 | 
			
		||||
				struct wb_view *current_view = wl_container_of(
 | 
			
		||||
						server->views.next, current_view, link);
 | 
			
		||||
				if (current_view->scene_tree->node.enabled)
 | 
			
		||||
					wlr_xdg_toplevel_send_close(current_view->xdg_toplevel);
 | 
			
		||||
			}
 | 
			
		||||
			if (key_binding->action & ACTION_EXECUTE) {
 | 
			
		||||
				if (fork() == 0) {
 | 
			
		||||
| 
						 | 
				
			
			@ -109,38 +90,34 @@ static bool handle_keybinding(struct wb_server *server, xkb_keysym_t sym, uint32
 | 
			
		|||
				}
 | 
			
		||||
			}
 | 
			
		||||
			if (key_binding->action & ACTION_TOGGLE_MAXIMIZE) {
 | 
			
		||||
				struct wb_toplevel *toplevel = wl_container_of(server->toplevels.next, toplevel, link);
 | 
			
		||||
				if (toplevel->scene_tree->node.enabled)
 | 
			
		||||
					wl_signal_emit(&toplevel->xdg_toplevel->events.request_maximize, NULL);
 | 
			
		||||
				struct wb_view *view = wl_container_of(server->views.next, view, link);
 | 
			
		||||
				if (view->scene_tree->node.enabled)
 | 
			
		||||
					wl_signal_emit(&view->xdg_toplevel->events.request_maximize, NULL);
 | 
			
		||||
			}
 | 
			
		||||
			if (key_binding->action & ACTION_ICONIFY) {
 | 
			
		||||
				struct wb_toplevel *toplevel = wl_container_of(server->toplevels.next, toplevel, link);
 | 
			
		||||
				if (toplevel->scene_tree->node.enabled) {
 | 
			
		||||
					toplevel->xdg_toplevel->requested.minimized = true;
 | 
			
		||||
					wl_signal_emit(&toplevel->xdg_toplevel->events.request_minimize, NULL);
 | 
			
		||||
				struct wb_view *view = wl_container_of(server->views.next, view, link);
 | 
			
		||||
				if (view->scene_tree->node.enabled) {
 | 
			
		||||
					view->xdg_toplevel->requested.minimized = true;
 | 
			
		||||
					wl_signal_emit(&view->xdg_toplevel->events.request_minimize, NULL);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			if (key_binding->action & ACTION_SHADE) {
 | 
			
		||||
				struct wb_toplevel *toplevel = wl_container_of(server->toplevels.next, toplevel, link);
 | 
			
		||||
				if (toplevel->scene_tree->node.enabled) {
 | 
			
		||||
#if WLR_CHECK_VERSION(0, 19, 0)
 | 
			
		||||
					struct wlr_box geo_box = toplevel->xdg_toplevel->base->geometry;
 | 
			
		||||
#else
 | 
			
		||||
				struct wb_view *view = wl_container_of(server->views.next, view, link);
 | 
			
		||||
				if (view->scene_tree->node.enabled) {
 | 
			
		||||
					struct wlr_box geo_box;
 | 
			
		||||
					wlr_xdg_surface_get_geometry(toplevel->xdg_toplevel->base, &geo_box);
 | 
			
		||||
#endif
 | 
			
		||||
					int decoration_height = MAX(geo_box.y - toplevel->geometry.y, TITLEBAR_HEIGHT);
 | 
			
		||||
					wlr_xdg_surface_get_geometry(view->xdg_toplevel->base, &geo_box);
 | 
			
		||||
					int decoration_height = MAX(geo_box.y - view->geometry.y, TITLEBAR_HEIGHT);
 | 
			
		||||
 | 
			
		||||
					toplevel->previous_geometry = toplevel->geometry;
 | 
			
		||||
					wlr_xdg_toplevel_set_size(toplevel->xdg_toplevel,
 | 
			
		||||
							toplevel->geometry.width, decoration_height);
 | 
			
		||||
					view->previous_geometry = view->geometry;
 | 
			
		||||
					wlr_xdg_toplevel_set_size(view->xdg_toplevel,
 | 
			
		||||
							view->geometry.width, decoration_height);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			if (key_binding->action & ACTION_UNSHADE) {
 | 
			
		||||
				struct wb_toplevel *toplevel = wl_container_of(server->toplevels.next, toplevel, link);
 | 
			
		||||
				if (toplevel->previous_geometry.height > 0 && toplevel->previous_geometry.width > 0 && toplevel->scene_tree->node.enabled) {
 | 
			
		||||
					wlr_xdg_toplevel_set_size(toplevel->xdg_toplevel,
 | 
			
		||||
							toplevel->previous_geometry.width, toplevel->previous_geometry.height);
 | 
			
		||||
				struct wb_view *view = wl_container_of(server->views.next, view, link);
 | 
			
		||||
				if (view->scene_tree->node.enabled) {
 | 
			
		||||
					wlr_xdg_toplevel_set_size(view->xdg_toplevel,
 | 
			
		||||
							view->previous_geometry.width, view->previous_geometry.height);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			if (key_binding->action & ACTION_RECONFIGURE) {
 | 
			
		||||
| 
						 | 
				
			
			@ -273,113 +250,6 @@ static void handle_new_keyboard(struct wb_server *server,
 | 
			
		|||
	wl_list_insert(&server->seat->keyboards, &keyboard->link);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef HAS_LIBINPUT
 | 
			
		||||
static bool libinput_config_get_enabled(char *config) {
 | 
			
		||||
	return strcmp(config, "disabled") != 0;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static void handle_new_pointer(struct wb_server *server, struct wlr_input_device *device) {
 | 
			
		||||
#ifdef HAS_LIBINPUT
 | 
			
		||||
	struct wb_config *config = server->config;
 | 
			
		||||
	if (wlr_input_device_is_libinput(device) && config->libinput_config.use_config) {
 | 
			
		||||
		struct libinput_device *libinput_handle =
 | 
			
		||||
			wlr_libinput_get_device_handle(device);
 | 
			
		||||
 | 
			
		||||
		if (config->libinput_config.accel_profile) {
 | 
			
		||||
			enum libinput_config_accel_profile accel_profile =
 | 
			
		||||
				LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE;
 | 
			
		||||
			if (strcmp(config->libinput_config.accel_profile, "flat") == 0)
 | 
			
		||||
				accel_profile = LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT;
 | 
			
		||||
			else if (strcmp(config->libinput_config.accel_profile, "none") == 0)
 | 
			
		||||
				accel_profile = LIBINPUT_CONFIG_ACCEL_PROFILE_NONE;
 | 
			
		||||
			libinput_device_config_accel_set_profile(libinput_handle, accel_profile);
 | 
			
		||||
		}
 | 
			
		||||
		if (config->libinput_config.accel_speed) {
 | 
			
		||||
			double accel_speed = strtod(config->libinput_config.accel_speed, NULL);
 | 
			
		||||
			libinput_device_config_accel_set_speed(libinput_handle, accel_speed);
 | 
			
		||||
		}
 | 
			
		||||
		if (config->libinput_config.calibration_matrix) {
 | 
			
		||||
			float matrix[6];
 | 
			
		||||
			unsigned short i = 0;
 | 
			
		||||
			while ((matrix[i] = strtod(strtok(config->libinput_config.calibration_matrix, " "), NULL) && i < 6)) {
 | 
			
		||||
				config->libinput_config.calibration_matrix = NULL;
 | 
			
		||||
				i++;
 | 
			
		||||
			}
 | 
			
		||||
			libinput_device_config_calibration_set_matrix(libinput_handle, matrix);
 | 
			
		||||
		}
 | 
			
		||||
		if (config->libinput_config.click_method) {
 | 
			
		||||
			enum libinput_config_click_method click_method = LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS;
 | 
			
		||||
			if (strcmp(config->libinput_config.click_method, "clickfinger") == 0)
 | 
			
		||||
				click_method = LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER;
 | 
			
		||||
			else if (strcmp(config->libinput_config.click_method, "none") == 0)
 | 
			
		||||
				click_method = LIBINPUT_CONFIG_CLICK_METHOD_NONE;
 | 
			
		||||
			libinput_device_config_click_set_method(libinput_handle, click_method);
 | 
			
		||||
		}
 | 
			
		||||
		if (config->libinput_config.dwt) {
 | 
			
		||||
			libinput_device_config_dwt_set_enabled(libinput_handle,
 | 
			
		||||
					libinput_config_get_enabled(config->libinput_config.dwt));
 | 
			
		||||
		}
 | 
			
		||||
		if (config->libinput_config.dwtp) {
 | 
			
		||||
			libinput_device_config_dwtp_set_enabled(libinput_handle,
 | 
			
		||||
					libinput_config_get_enabled(config->libinput_config.dwtp));
 | 
			
		||||
		}
 | 
			
		||||
		if (config->libinput_config.left_handed) {
 | 
			
		||||
			libinput_device_config_left_handed_set(libinput_handle,
 | 
			
		||||
					libinput_config_get_enabled(config->libinput_config.left_handed));
 | 
			
		||||
		}
 | 
			
		||||
		if (config->libinput_config.middle_emulation) {
 | 
			
		||||
			libinput_device_config_middle_emulation_set_enabled(libinput_handle,
 | 
			
		||||
					libinput_config_get_enabled(config->libinput_config.middle_emulation));
 | 
			
		||||
		}
 | 
			
		||||
		if (config->libinput_config.natural_scroll) {
 | 
			
		||||
			libinput_device_config_scroll_set_natural_scroll_enabled(libinput_handle,
 | 
			
		||||
					libinput_config_get_enabled(config->libinput_config.natural_scroll));
 | 
			
		||||
		}
 | 
			
		||||
		if (config->libinput_config.scroll_button) {
 | 
			
		||||
			int button = libevdev_event_code_from_name(EV_KEY, config->libinput_config.scroll_button);
 | 
			
		||||
			if (button != -1) {
 | 
			
		||||
				libinput_device_config_scroll_set_button(libinput_handle, button);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if (config->libinput_config.scroll_button_lock) {
 | 
			
		||||
			libinput_device_config_scroll_set_button_lock(libinput_handle,
 | 
			
		||||
					libinput_config_get_enabled(config->libinput_config.scroll_button_lock));
 | 
			
		||||
		}
 | 
			
		||||
		if (config->libinput_config.scroll_method) {
 | 
			
		||||
			enum libinput_config_scroll_method scroll_method = LIBINPUT_CONFIG_SCROLL_2FG;
 | 
			
		||||
			if (strcmp(config->libinput_config.scroll_method, "edge") == 0)
 | 
			
		||||
				scroll_method = LIBINPUT_CONFIG_SCROLL_EDGE;
 | 
			
		||||
			else if (strcmp(config->libinput_config.scroll_method, "none") == 0)
 | 
			
		||||
				scroll_method = LIBINPUT_CONFIG_SCROLL_NO_SCROLL;
 | 
			
		||||
			else if (strcmp(config->libinput_config.scroll_method, "button") == 0)
 | 
			
		||||
				scroll_method = LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN;
 | 
			
		||||
			libinput_device_config_scroll_set_method(libinput_handle, scroll_method);
 | 
			
		||||
		}
 | 
			
		||||
		if (config->libinput_config.tap) {
 | 
			
		||||
			libinput_device_config_tap_set_enabled(libinput_handle,
 | 
			
		||||
					libinput_config_get_enabled(config->libinput_config.tap));
 | 
			
		||||
		}
 | 
			
		||||
		if (config->libinput_config.tap_button_map) {
 | 
			
		||||
			enum libinput_config_tap_button_map map = LIBINPUT_CONFIG_TAP_MAP_LRM;
 | 
			
		||||
			if (strcmp(config->libinput_config.tap_button_map, "lmr") == 0)
 | 
			
		||||
				map = LIBINPUT_CONFIG_TAP_MAP_LMR;
 | 
			
		||||
			libinput_device_config_tap_set_button_map(libinput_handle, map);
 | 
			
		||||
		}
 | 
			
		||||
		if (config->libinput_config.tap_drag) {
 | 
			
		||||
			libinput_device_config_tap_set_drag_enabled(libinput_handle,
 | 
			
		||||
					libinput_config_get_enabled(config->libinput_config.tap_drag));
 | 
			
		||||
		};
 | 
			
		||||
		if (config->libinput_config.tap_drag_lock) {
 | 
			
		||||
			libinput_device_config_tap_set_drag_lock_enabled(libinput_handle,
 | 
			
		||||
					libinput_config_get_enabled(config->libinput_config.tap_drag_lock));
 | 
			
		||||
		};
 | 
			
		||||
	}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	wlr_cursor_attach_input_device(server->cursor->cursor, device);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void new_input_notify(struct wl_listener *listener, void *data) {
 | 
			
		||||
	struct wlr_input_device *device = data;
 | 
			
		||||
	struct wb_server *server = wl_container_of(listener, server, new_input);
 | 
			
		||||
| 
						 | 
				
			
			@ -390,7 +260,7 @@ static void new_input_notify(struct wl_listener *listener, void *data) {
 | 
			
		|||
			break;
 | 
			
		||||
		case WLR_INPUT_DEVICE_POINTER:
 | 
			
		||||
			wlr_log(WLR_INFO, "%s: %s", _("New pointer detected"), device->name);
 | 
			
		||||
			handle_new_pointer(server, device);
 | 
			
		||||
			wlr_cursor_attach_input_device(server->cursor->cursor, device);
 | 
			
		||||
			break;
 | 
			
		||||
		default:
 | 
			
		||||
			wlr_log(WLR_INFO, "%s: %s", _("Unsupported input device detected"), device->name);
 | 
			
		||||
| 
						 | 
				
			
			@ -423,7 +293,7 @@ void seat_set_focus_layer(struct wb_seat *seat, struct wlr_layer_surface_v1 *lay
 | 
			
		|||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	seat_focus_surface(seat, layer->surface);
 | 
			
		||||
	if (layer->current.layer > ZWLR_LAYER_SHELL_V1_LAYER_TOP) {
 | 
			
		||||
	if (layer->current.layer >= ZWLR_LAYER_SHELL_V1_LAYER_TOP) {
 | 
			
		||||
		seat->focused_layer = layer;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,13 +1,5 @@
 | 
			
		|||
#include <wlr/types/wlr_data_control_v1.h>
 | 
			
		||||
#include <wlr/types/wlr_fractional_scale_v1.h>
 | 
			
		||||
#include <wlr/types/wlr_viewporter.h>
 | 
			
		||||
 | 
			
		||||
#include "idle.h"
 | 
			
		||||
#include "waybox/server.h"
 | 
			
		||||
#include "waybox/xdg_shell.h"
 | 
			
		||||
#if WLR_CHECK_VERSION(0, 19, 0)
 | 
			
		||||
#	include <wlr/types/wlr_xdg_toplevel_icon_v1.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
bool wb_create_backend(struct wb_server* server) {
 | 
			
		||||
	/* The Wayland display is managed by libwayland. It handles accepting
 | 
			
		||||
| 
						 | 
				
			
			@ -18,17 +10,15 @@ bool wb_create_backend(struct wb_server* server) {
 | 
			
		|||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	server->wl_event_loop = wl_display_get_event_loop(server->wl_display);
 | 
			
		||||
	if (server->wl_event_loop == NULL) {
 | 
			
		||||
		wlr_log(WLR_ERROR, "%s", _("Failed to get an event loop"));
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* The backend is a wlroots feature which abstracts the underlying input and
 | 
			
		||||
	 * output hardware. The autocreate option will choose the most suitable
 | 
			
		||||
	 * backend based on the current environment, such as opening an X11 window
 | 
			
		||||
	 * if an X11 server is running. */
 | 
			
		||||
	server->backend = wlr_backend_autocreate(server->wl_event_loop, &server->session);
 | 
			
		||||
#if ! WLR_CHECK_VERSION(0, 13, 0) || WLR_CHECK_VERSION(0, 17, 0)
 | 
			
		||||
	server->backend = wlr_backend_autocreate(server->wl_display, NULL);
 | 
			
		||||
#else
 | 
			
		||||
	server->backend = wlr_backend_autocreate(server->wl_display);
 | 
			
		||||
#endif
 | 
			
		||||
	if (server->backend == NULL) {
 | 
			
		||||
		wlr_log(WLR_ERROR, "%s", _("Failed to create backend"));
 | 
			
		||||
		return false;
 | 
			
		||||
| 
						 | 
				
			
			@ -56,10 +46,10 @@ bool wb_create_backend(struct wb_server* server) {
 | 
			
		|||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	server->compositor =
 | 
			
		||||
		wlr_compositor_create(server->wl_display, 5, server->renderer);
 | 
			
		||||
	server->compositor = wlr_compositor_create(server->wl_display,
 | 
			
		||||
			server->renderer);
 | 
			
		||||
	server->subcompositor = wlr_subcompositor_create(server->wl_display);
 | 
			
		||||
	server->output_layout = wlr_output_layout_create(server->wl_display);
 | 
			
		||||
	server->output_layout = wlr_output_layout_create();
 | 
			
		||||
	server->seat = wb_seat_create(server);
 | 
			
		||||
	server->cursor = wb_cursor_create(server);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -71,7 +61,10 @@ bool wb_create_backend(struct wb_server* server) {
 | 
			
		|||
 | 
			
		||||
bool wb_start_server(struct wb_server* server) {
 | 
			
		||||
	init_config(server);
 | 
			
		||||
	init_output(server);
 | 
			
		||||
	wl_list_init(&server->outputs);
 | 
			
		||||
 | 
			
		||||
	server->new_output.notify = new_output_notify;
 | 
			
		||||
	wl_signal_add(&server->backend->events.new_output, &server->new_output);
 | 
			
		||||
 | 
			
		||||
	/* Create a scene graph. This is a wlroots abstraction that handles all
 | 
			
		||||
	 * rendering and damage tracking. All the compositor author needs to do
 | 
			
		||||
| 
						 | 
				
			
			@ -80,7 +73,6 @@ bool wb_start_server(struct wb_server* server) {
 | 
			
		|||
	 * necessary.
 | 
			
		||||
	 */
 | 
			
		||||
	server->scene = wlr_scene_create();
 | 
			
		||||
	server->scene_layout =
 | 
			
		||||
	wlr_scene_attach_output_layout(server->scene, server->output_layout);
 | 
			
		||||
 | 
			
		||||
	const char *socket = wl_display_add_socket_auto(server->wl_display);
 | 
			
		||||
| 
						 | 
				
			
			@ -99,38 +91,23 @@ bool wb_start_server(struct wb_server* server) {
 | 
			
		|||
	wlr_log(WLR_INFO, "%s: WAYLAND_DISPLAY=%s", _("Running Wayland compositor on Wayland display"), socket);
 | 
			
		||||
	setenv("WAYLAND_DISPLAY", socket, true);
 | 
			
		||||
 | 
			
		||||
	wlr_data_control_manager_v1_create(server->wl_display);
 | 
			
		||||
	wlr_data_device_manager_create(server->wl_display);
 | 
			
		||||
 | 
			
		||||
	server->foreign_toplevel_list =
 | 
			
		||||
		wlr_ext_foreign_toplevel_list_v1_create(server->wl_display, 1);
 | 
			
		||||
 | 
			
		||||
	server->gamma_control_manager =
 | 
			
		||||
	wlr_gamma_control_manager_v1_create(server->wl_display);
 | 
			
		||||
	server->gamma_control_set_gamma.notify = handle_gamma_control_set_gamma;
 | 
			
		||||
	wl_signal_add(&server->gamma_control_manager->events.set_gamma, &server->gamma_control_set_gamma);
 | 
			
		||||
 | 
			
		||||
	wlr_screencopy_manager_v1_create(server->wl_display);
 | 
			
		||||
	create_idle_manager(server);
 | 
			
		||||
	server->idle_notifier = wlr_idle_notifier_v1_create(server->wl_display);
 | 
			
		||||
 | 
			
		||||
	wl_list_init(&server->toplevels);
 | 
			
		||||
	wlr_data_device_manager_create(server->wl_display);
 | 
			
		||||
	wl_list_init(&server->views);
 | 
			
		||||
	init_xdg_decoration(server);
 | 
			
		||||
	init_layer_shell(server);
 | 
			
		||||
 | 
			
		||||
	/* Set up the xdg-shell. The xdg-shell is a Wayland protocol which is used
 | 
			
		||||
	 * for application windows. For more detail on shells, refer to
 | 
			
		||||
	 * for application windows. For more detail on shells, refer to Drew
 | 
			
		||||
	 * DeVault's article:
 | 
			
		||||
	 *
 | 
			
		||||
	 * https://drewdevault.com/2018/07/29/Wayland-shells.html
 | 
			
		||||
	 */
 | 
			
		||||
	init_xdg_shell(server);
 | 
			
		||||
 | 
			
		||||
	wlr_fractional_scale_manager_v1_create(server->wl_display, 1);
 | 
			
		||||
	wlr_viewporter_create(server->wl_display);
 | 
			
		||||
#if WLR_CHECK_VERSION(0, 19, 0)
 | 
			
		||||
	struct wlr_xdg_toplevel_icon_manager_v1 * icon_manager = wlr_xdg_toplevel_icon_manager_v1_create(server->wl_display, 1);
 | 
			
		||||
	int sizes[] = {16, 24, 32, 48, 64};
 | 
			
		||||
	wlr_xdg_toplevel_icon_manager_v1_set_sizes(icon_manager, (int *) sizes, 5);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -139,27 +116,9 @@ bool wb_terminate(struct wb_server* server) {
 | 
			
		|||
	wl_list_remove(&server->new_xdg_decoration.link); /* wb_decoration_destroy */
 | 
			
		||||
	deinit_config(server->config);
 | 
			
		||||
	wl_display_destroy_clients(server->wl_display);
 | 
			
		||||
	wlr_output_layout_destroy(server->output_layout);
 | 
			
		||||
	wlr_allocator_destroy(server->allocator);
 | 
			
		||||
	wlr_renderer_destroy(server->renderer);
 | 
			
		||||
 | 
			
		||||
	wl_list_remove(&server->new_input.link);
 | 
			
		||||
	wl_list_remove(&server->new_output.link);
 | 
			
		||||
	wl_list_remove(&server->output_configuration_applied.link);
 | 
			
		||||
	wl_list_remove(&server->output_configuration_tested.link);
 | 
			
		||||
	wl_list_remove(&server->new_inhibitor.link);
 | 
			
		||||
	wl_list_remove(&server->inhibitors);
 | 
			
		||||
	wl_list_remove(&server->destroy_inhibit_manager.link);
 | 
			
		||||
	wl_list_remove(&server->gamma_control_set_gamma.link);
 | 
			
		||||
	wl_list_remove(&server->new_layer_surface.link);
 | 
			
		||||
 | 
			
		||||
	wl_list_remove(&server->new_xdg_toplevel.link);
 | 
			
		||||
	wl_list_remove(&server->new_xdg_popup.link);
 | 
			
		||||
 | 
			
		||||
	wlr_backend_destroy(server->backend);
 | 
			
		||||
	wb_seat_destroy(server->seat);
 | 
			
		||||
	wl_display_destroy(server->wl_display);
 | 
			
		||||
	wlr_scene_node_destroy(&server->scene->tree.node);
 | 
			
		||||
	wb_seat_destroy(server->seat);
 | 
			
		||||
	wlr_output_layout_destroy(server->output_layout);
 | 
			
		||||
 | 
			
		||||
	wlr_log(WLR_INFO, "%s", _("Display destroyed"));
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,12 +1,11 @@
 | 
			
		|||
#include "idle.h"
 | 
			
		||||
#include "waybox/xdg_shell.h"
 | 
			
		||||
 | 
			
		||||
struct wb_toplevel *get_toplevel_at(
 | 
			
		||||
struct wb_view *get_view_at(
 | 
			
		||||
		struct wb_server *server, double lx, double ly,
 | 
			
		||||
		struct wlr_surface **surface, double *sx, double *sy) {
 | 
			
		||||
	/* This returns the topmost node in the scene at the given layout coords.
 | 
			
		||||
	 * we only care about surface nodes as we are specifically looking for a
 | 
			
		||||
	 * surface in the surface tree of a wb_toplevel. */
 | 
			
		||||
	 * surface in the surface tree of a wb_view. */
 | 
			
		||||
	struct wlr_scene_node *node =
 | 
			
		||||
		wlr_scene_node_at(&server->scene->tree.node, lx, ly, sx, sy);
 | 
			
		||||
	if (node == NULL || node->type != WLR_SCENE_NODE_BUFFER) {
 | 
			
		||||
| 
						 | 
				
			
			@ -14,13 +13,13 @@ struct wb_toplevel *get_toplevel_at(
 | 
			
		|||
	}
 | 
			
		||||
	struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node);
 | 
			
		||||
	struct wlr_scene_surface *scene_surface =
 | 
			
		||||
		wlr_scene_surface_try_from_buffer(scene_buffer);
 | 
			
		||||
		wlr_scene_surface_from_buffer(scene_buffer);
 | 
			
		||||
	if (!scene_surface) {
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	*surface = scene_surface->surface;
 | 
			
		||||
	/* Find the node corresponding to the wb_toplevel at the root of this
 | 
			
		||||
	/* Find the node corresponding to the wb_view at the root of this
 | 
			
		||||
	 * surface tree, it is the only one for which we set the data field. */
 | 
			
		||||
	struct wlr_scene_tree *tree = node->parent;
 | 
			
		||||
	while (tree != NULL && tree->node.data == NULL) {
 | 
			
		||||
| 
						 | 
				
			
			@ -29,67 +28,62 @@ struct wb_toplevel *get_toplevel_at(
 | 
			
		|||
	return tree->node.data;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void focus_toplevel(struct wb_toplevel *toplevel) {
 | 
			
		||||
void focus_view(struct wb_view *view, struct wlr_surface *surface) {
 | 
			
		||||
	/* Note: this function only deals with keyboard focus. */
 | 
			
		||||
	if (toplevel == NULL || toplevel->xdg_toplevel->base->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL) {
 | 
			
		||||
	if (view == NULL || surface == NULL || !wlr_surface_is_xdg_surface(surface)) {
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	struct wlr_surface *surface = toplevel->xdg_toplevel->base->surface;
 | 
			
		||||
	struct wlr_xdg_surface *xdg_surface = wlr_xdg_surface_try_from_wlr_surface(surface);
 | 
			
		||||
	if (xdg_surface != NULL)
 | 
			
		||||
	struct wlr_xdg_surface *xdg_surface = wlr_xdg_surface_from_wlr_surface(surface);
 | 
			
		||||
	if (xdg_surface)
 | 
			
		||||
		wlr_log(WLR_INFO, "%s: %s", _("Keyboard focus is now on surface"),
 | 
			
		||||
				xdg_surface->toplevel->app_id);
 | 
			
		||||
 | 
			
		||||
	struct wb_server *server = toplevel->server;
 | 
			
		||||
	if (server->seat->focused_layer != NULL) {
 | 
			
		||||
		/* If a layer is focused, don't focus a toplevel. */
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	struct wb_server *server = view->server;
 | 
			
		||||
	struct wlr_seat *seat = server->seat->seat;
 | 
			
		||||
	struct wlr_surface *prev_surface = seat->keyboard_state.focused_surface;
 | 
			
		||||
	if (prev_surface == surface) {
 | 
			
		||||
		/* Don't focus a surface that's already focused. */
 | 
			
		||||
		/* Don't re-focus an already focused surface. */
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	if (prev_surface != NULL) {
 | 
			
		||||
	if (prev_surface && wlr_surface_is_xdg_surface(prev_surface)) {
 | 
			
		||||
		/*
 | 
			
		||||
		 * Deactivate the previously focused surface. This lets the client know
 | 
			
		||||
		 * it no longer has focus and the client will repaint accordingly, e.g.
 | 
			
		||||
		 * stop displaying a caret.
 | 
			
		||||
		 */
 | 
			
		||||
		struct wlr_xdg_toplevel *prev_toplevel =
 | 
			
		||||
			wlr_xdg_toplevel_try_from_wlr_surface(prev_surface);
 | 
			
		||||
		if (prev_toplevel != NULL) {
 | 
			
		||||
			wlr_xdg_toplevel_set_activated(prev_toplevel, false);
 | 
			
		||||
		struct wlr_xdg_surface *previous =
 | 
			
		||||
			wlr_xdg_surface_from_wlr_surface(prev_surface);
 | 
			
		||||
		wlr_xdg_toplevel_set_activated(previous->toplevel, false);
 | 
			
		||||
	}
 | 
			
		||||
	/* Move the view to the front */
 | 
			
		||||
	if (!server->seat->focused_layer) {
 | 
			
		||||
		wlr_scene_node_raise_to_top(&view->scene_tree->node);
 | 
			
		||||
	}
 | 
			
		||||
	/* Move the toplevel to the front */
 | 
			
		||||
	wlr_scene_node_raise_to_top(&toplevel->scene_tree->node);
 | 
			
		||||
	wl_list_remove(&toplevel->link);
 | 
			
		||||
	wl_list_insert(&server->toplevels, &toplevel->link);
 | 
			
		||||
	wl_list_remove(&view->link);
 | 
			
		||||
	wl_list_insert(&server->views, &view->link);
 | 
			
		||||
	/* Activate the new surface */
 | 
			
		||||
	wlr_xdg_toplevel_set_activated(toplevel->xdg_toplevel, true);
 | 
			
		||||
	wlr_xdg_toplevel_set_activated(view->xdg_toplevel, true);
 | 
			
		||||
	/*
 | 
			
		||||
	 * Tell the seat to have the keyboard enter this surface. wlroots will keep
 | 
			
		||||
	 * track of this and automatically send key events to the appropriate
 | 
			
		||||
	 * clients without additional work on your part.
 | 
			
		||||
	 */
 | 
			
		||||
	seat_focus_surface(server->seat, surface);
 | 
			
		||||
	seat_focus_surface(server->seat, view->xdg_toplevel->base->surface);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct wlr_output *get_active_output(struct wb_toplevel *toplevel) {
 | 
			
		||||
struct wlr_output *get_active_output(struct wb_view *view) {
 | 
			
		||||
	double closest_x, closest_y;
 | 
			
		||||
	struct wlr_output *output = NULL;
 | 
			
		||||
	wlr_output_layout_closest_point(toplevel->server->output_layout, output,
 | 
			
		||||
			toplevel->geometry.x + toplevel->geometry.width / 2,
 | 
			
		||||
			toplevel->geometry.y + toplevel->geometry.height / 2,
 | 
			
		||||
	wlr_output_layout_closest_point(view->server->output_layout, output,
 | 
			
		||||
			view->geometry.x + view->geometry.width / 2,
 | 
			
		||||
			view->geometry.y + view->geometry.height / 2,
 | 
			
		||||
			&closest_x, &closest_y);
 | 
			
		||||
	return wlr_output_layout_output_at(toplevel->server->output_layout, closest_x, closest_y);
 | 
			
		||||
	return wlr_output_layout_output_at(view->server->output_layout, closest_x, closest_y);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct wlr_box get_usable_area(struct wb_toplevel *toplevel) {
 | 
			
		||||
	struct wlr_output *output = get_active_output(toplevel);
 | 
			
		||||
static struct wlr_box get_usable_area(struct wb_view *view) {
 | 
			
		||||
	struct wlr_output *output = get_active_output(view);
 | 
			
		||||
	struct wlr_box usable_area = {0};
 | 
			
		||||
	wlr_output_effective_resolution(output, &usable_area.width, &usable_area.height);
 | 
			
		||||
	return usable_area;
 | 
			
		||||
| 
						 | 
				
			
			@ -97,155 +91,89 @@ static struct wlr_box get_usable_area(struct wb_toplevel *toplevel) {
 | 
			
		|||
 | 
			
		||||
static void xdg_toplevel_map(struct wl_listener *listener, void *data) {
 | 
			
		||||
	/* Called when the surface is mapped, or ready to display on-screen. */
 | 
			
		||||
	struct wb_toplevel *toplevel = wl_container_of(listener, toplevel, map);
 | 
			
		||||
	if (toplevel->xdg_toplevel->base->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL)
 | 
			
		||||
	struct wb_view *view = wl_container_of(listener, view, map);
 | 
			
		||||
	if (view->xdg_toplevel->base->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	struct wb_config *config = toplevel->server->config;
 | 
			
		||||
	struct wlr_box usable_area = get_usable_area(toplevel);
 | 
			
		||||
#if WLR_CHECK_VERSION(0, 19, 0)
 | 
			
		||||
	struct wlr_box geo_box = toplevel->xdg_toplevel->base->geometry;
 | 
			
		||||
#else
 | 
			
		||||
	struct wb_config *config = view->server->config;
 | 
			
		||||
	struct wlr_box geo_box = {0};
 | 
			
		||||
	wlr_xdg_surface_get_geometry(toplevel->xdg_toplevel->base, &geo_box);
 | 
			
		||||
#endif
 | 
			
		||||
	struct wlr_box usable_area = get_usable_area(view);
 | 
			
		||||
	wlr_xdg_surface_get_geometry(view->xdg_toplevel->base, &geo_box);
 | 
			
		||||
 | 
			
		||||
	if (config) {
 | 
			
		||||
		toplevel->geometry.height = MIN(geo_box.height,
 | 
			
		||||
		view->geometry.height = MIN(geo_box.height,
 | 
			
		||||
				usable_area.height - config->margins.top - config->margins.bottom);
 | 
			
		||||
		toplevel->geometry.width = MIN(geo_box.width,
 | 
			
		||||
		view->geometry.width = MIN(geo_box.width,
 | 
			
		||||
				usable_area.width - config->margins.left - config->margins.right);
 | 
			
		||||
		toplevel->geometry.x = config->margins.left;
 | 
			
		||||
		toplevel->geometry.y = config->margins.top;
 | 
			
		||||
		view->geometry.x = config->margins.left;
 | 
			
		||||
		view->geometry.y = config->margins.top;
 | 
			
		||||
	} else {
 | 
			
		||||
		toplevel->geometry.height = MIN(geo_box.height, usable_area.height);
 | 
			
		||||
		toplevel->geometry.width = MIN(geo_box.width, usable_area.width);
 | 
			
		||||
		toplevel->geometry.x = 0;
 | 
			
		||||
		toplevel->geometry.y = 0;
 | 
			
		||||
		view->geometry.height = MIN(geo_box.height, usable_area.height);
 | 
			
		||||
		view->geometry.width = MIN(geo_box.width, usable_area.width);
 | 
			
		||||
		view->geometry.x = 0;
 | 
			
		||||
		view->geometry.y = 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	wlr_xdg_toplevel_set_size(toplevel->xdg_toplevel,
 | 
			
		||||
			toplevel->geometry.width, toplevel->geometry.height);
 | 
			
		||||
	focus_toplevel(toplevel);
 | 
			
		||||
	/* A view no larger than a title bar shouldn't be sized or focused */
 | 
			
		||||
	if (view->geometry.height > TITLEBAR_HEIGHT &&
 | 
			
		||||
			view->geometry.height > TITLEBAR_HEIGHT *
 | 
			
		||||
			(usable_area.width / usable_area.height)) {
 | 
			
		||||
		wlr_xdg_toplevel_set_size(view->xdg_toplevel,
 | 
			
		||||
				view->geometry.width, view->geometry.height);
 | 
			
		||||
		focus_view(view, view->xdg_toplevel->base->surface);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	wlr_scene_node_set_position(&toplevel->scene_tree->node,
 | 
			
		||||
			toplevel->geometry.x, toplevel->geometry.y);
 | 
			
		||||
	wlr_scene_node_set_position(&view->scene_tree->node,
 | 
			
		||||
			view->geometry.x, view->geometry.y);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void xdg_toplevel_unmap(struct wl_listener *listener, void *data) {
 | 
			
		||||
	/* Called when the surface is unmapped, and should no longer be shown. */
 | 
			
		||||
	struct wb_toplevel *toplevel = wl_container_of(listener, toplevel, unmap);
 | 
			
		||||
	if (toplevel->xdg_toplevel->base->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL)
 | 
			
		||||
	struct wb_view *view = wl_container_of(listener, view, unmap);
 | 
			
		||||
	if (view->xdg_toplevel->base->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL)
 | 
			
		||||
		return;
 | 
			
		||||
	reset_cursor_mode(toplevel->server);
 | 
			
		||||
	reset_cursor_mode(view->server);
 | 
			
		||||
 | 
			
		||||
	/* Focus the next toplevel, if any. */
 | 
			
		||||
	if (wl_list_length(&toplevel->link) > 1) {
 | 
			
		||||
		struct wb_toplevel *next_toplevel = wl_container_of(toplevel->link.next, next_toplevel, link);
 | 
			
		||||
		if (next_toplevel && next_toplevel->xdg_toplevel && next_toplevel->scene_tree && next_toplevel->scene_tree->node.enabled) {
 | 
			
		||||
			wlr_log(WLR_INFO, "%s: %s", _("Focusing next toplevel"),
 | 
			
		||||
					next_toplevel->xdg_toplevel->app_id);
 | 
			
		||||
			focus_toplevel(next_toplevel);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void update_fractional_scale(struct wlr_surface *surface) {
 | 
			
		||||
	float scale = 1;
 | 
			
		||||
	struct wlr_surface_output *surface_output;
 | 
			
		||||
	wl_list_for_each(surface_output, &surface->current_outputs, link) {
 | 
			
		||||
		if (surface_output->output->scale > scale) {
 | 
			
		||||
			scale = surface_output->output->scale;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	wlr_fractional_scale_v1_notify_scale(surface, scale);
 | 
			
		||||
	wlr_surface_set_preferred_buffer_scale(surface, ceil(scale));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void xdg_toplevel_commit(struct wl_listener *listener, void *data) {
 | 
			
		||||
	struct wb_toplevel *toplevel = wl_container_of(listener, toplevel, commit);
 | 
			
		||||
	struct wlr_xdg_surface *base = toplevel->xdg_toplevel->base;
 | 
			
		||||
 | 
			
		||||
	struct wlr_output *output = get_active_output(toplevel);
 | 
			
		||||
	wlr_surface_send_enter(base->surface, output);
 | 
			
		||||
	update_fractional_scale(base->surface);
 | 
			
		||||
 | 
			
		||||
	if (base->initial_commit) {
 | 
			
		||||
		wlr_xdg_toplevel_set_size(toplevel->xdg_toplevel, 0, 0);
 | 
			
		||||
		if (toplevel->decoration != NULL)
 | 
			
		||||
			wl_signal_emit(&toplevel->decoration->events.request_mode, toplevel->decoration);
 | 
			
		||||
	/* Focus the next view, if any. */
 | 
			
		||||
	struct wb_view *next_view = wl_container_of(view->link.next, next_view, link);
 | 
			
		||||
	if (next_view && next_view->scene_tree && next_view->scene_tree->node.enabled) {
 | 
			
		||||
		wlr_log(WLR_INFO, "%s: %s", _("Focusing next view"),
 | 
			
		||||
				next_view->xdg_toplevel->app_id);
 | 
			
		||||
		focus_view(next_view, next_view->xdg_toplevel->base->surface);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void xdg_toplevel_destroy(struct wl_listener *listener, void *data) {
 | 
			
		||||
	/* Called when the xdg_toplevel is destroyed and should never be shown again. */
 | 
			
		||||
	struct wb_toplevel *toplevel = wl_container_of(listener, toplevel, destroy);
 | 
			
		||||
	/* Called when the surface is destroyed and should never be shown again. */
 | 
			
		||||
	struct wb_view *view = wl_container_of(listener, view, destroy);
 | 
			
		||||
 | 
			
		||||
	struct wlr_output *output = get_active_output(toplevel);
 | 
			
		||||
	struct wlr_xdg_surface *base = toplevel->xdg_toplevel->base;
 | 
			
		||||
	wlr_surface_send_leave(base->surface, output);
 | 
			
		||||
	update_fractional_scale(base->surface);
 | 
			
		||||
	wlr_ext_foreign_toplevel_handle_v1_destroy(toplevel->foreign_toplevel_handle);
 | 
			
		||||
	wl_list_remove(&view->map.link);
 | 
			
		||||
	wl_list_remove(&view->unmap.link);
 | 
			
		||||
	wl_list_remove(&view->destroy.link);
 | 
			
		||||
	wl_list_remove(&view->new_popup.link);
 | 
			
		||||
 | 
			
		||||
	wl_list_remove(&toplevel->map.link);
 | 
			
		||||
	wl_list_remove(&toplevel->unmap.link);
 | 
			
		||||
	wl_list_remove(&toplevel->commit.link);
 | 
			
		||||
	wl_list_remove(&toplevel->destroy.link);
 | 
			
		||||
	wl_list_remove(&toplevel->new_popup.link);
 | 
			
		||||
	if (view->xdg_toplevel->base->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL) {
 | 
			
		||||
		wl_list_remove(&view->request_fullscreen.link);
 | 
			
		||||
		wl_list_remove(&view->request_minimize.link);
 | 
			
		||||
		wl_list_remove(&view->request_maximize.link);
 | 
			
		||||
		wl_list_remove(&view->request_move.link);
 | 
			
		||||
		wl_list_remove(&view->request_resize.link);
 | 
			
		||||
		wl_list_remove(&view->link);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	wl_list_remove(&toplevel->request_fullscreen.link);
 | 
			
		||||
	wl_list_remove(&toplevel->request_minimize.link);
 | 
			
		||||
	wl_list_remove(&toplevel->request_maximize.link);
 | 
			
		||||
	wl_list_remove(&toplevel->request_move.link);
 | 
			
		||||
	wl_list_remove(&toplevel->request_resize.link);
 | 
			
		||||
	wl_list_remove(&toplevel->set_app_id.link);
 | 
			
		||||
	wl_list_remove(&toplevel->set_title.link);
 | 
			
		||||
 | 
			
		||||
	wl_list_remove(&toplevel->link);
 | 
			
		||||
	free(toplevel);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void xdg_toplevel_set_app_id(
 | 
			
		||||
		struct wl_listener *listener, void *data) {
 | 
			
		||||
	struct wb_toplevel *toplevel =
 | 
			
		||||
		wl_container_of(listener, toplevel, set_app_id);
 | 
			
		||||
	toplevel->foreign_toplevel_state.app_id = toplevel->xdg_toplevel->app_id;
 | 
			
		||||
	wlr_ext_foreign_toplevel_handle_v1_update_state(
 | 
			
		||||
			toplevel->foreign_toplevel_handle, &toplevel->foreign_toplevel_state);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void xdg_toplevel_set_title(
 | 
			
		||||
		struct wl_listener *listener, void *data) {
 | 
			
		||||
	struct wb_toplevel *toplevel =
 | 
			
		||||
		wl_container_of(listener, toplevel, set_title);
 | 
			
		||||
	toplevel->foreign_toplevel_state.title = toplevel->xdg_toplevel->title;
 | 
			
		||||
	wlr_ext_foreign_toplevel_handle_v1_update_state(
 | 
			
		||||
			toplevel->foreign_toplevel_handle, &toplevel->foreign_toplevel_state);
 | 
			
		||||
	free(view);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void xdg_toplevel_request_fullscreen(
 | 
			
		||||
		struct wl_listener *listener, void *data) {
 | 
			
		||||
	/* This event is raised when a client would like to set itself to
 | 
			
		||||
	 * fullscreen. */
 | 
			
		||||
	struct wb_toplevel *toplevel =
 | 
			
		||||
		wl_container_of(listener, toplevel, request_fullscreen);
 | 
			
		||||
	bool is_fullscreen = toplevel->xdg_toplevel->current.fullscreen;
 | 
			
		||||
	if (!is_fullscreen) {
 | 
			
		||||
		struct wlr_output *wlr_output = get_active_output(toplevel);
 | 
			
		||||
		struct wb_output *output = wlr_output->data;
 | 
			
		||||
		toplevel->previous_geometry = toplevel->geometry;
 | 
			
		||||
		toplevel->geometry.x = 0;
 | 
			
		||||
		toplevel->geometry.y = 0;
 | 
			
		||||
		toplevel->geometry.height = output->geometry.height;
 | 
			
		||||
		toplevel->geometry.width = output->geometry.width;
 | 
			
		||||
		wlr_scene_node_raise_to_top(&toplevel->scene_tree->node);
 | 
			
		||||
	} else {
 | 
			
		||||
		toplevel->geometry = toplevel->previous_geometry;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	wlr_xdg_toplevel_set_size(toplevel->xdg_toplevel, toplevel->geometry.width, toplevel->geometry.height);
 | 
			
		||||
	wlr_xdg_toplevel_set_fullscreen(toplevel->xdg_toplevel, !is_fullscreen);
 | 
			
		||||
	wlr_scene_node_set_position(&toplevel->scene_tree->node, toplevel->geometry.x, toplevel->geometry.y);
 | 
			
		||||
	 * fullscreen. waybox currently doesn't support fullscreen, but to
 | 
			
		||||
	 * conform to xdg-shell protocol we still must send a configure.
 | 
			
		||||
	 * wlr_xdg_surface_schedule_configure() is used to send an empty reply.
 | 
			
		||||
	 */
 | 
			
		||||
	struct wb_view *view =
 | 
			
		||||
		wl_container_of(listener, view, request_fullscreen);
 | 
			
		||||
	wlr_xdg_surface_schedule_configure(view->xdg_toplevel->base);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void xdg_toplevel_request_maximize(struct wl_listener *listener, void *data) {
 | 
			
		||||
| 
						 | 
				
			
			@ -253,83 +181,85 @@ static void xdg_toplevel_request_maximize(struct wl_listener *listener, void *da
 | 
			
		|||
	 * typically because the user clicked on the maximize button on
 | 
			
		||||
	 * client-side decorations.
 | 
			
		||||
	 */
 | 
			
		||||
	struct wb_toplevel *toplevel = wl_container_of(listener, toplevel, request_maximize);
 | 
			
		||||
	struct wlr_box usable_area = get_usable_area(toplevel);
 | 
			
		||||
	struct wb_view *view = wl_container_of(listener, view, request_maximize);
 | 
			
		||||
	struct wlr_box usable_area = get_usable_area(view);
 | 
			
		||||
 | 
			
		||||
	bool is_maximized = toplevel->xdg_toplevel->current.maximized;
 | 
			
		||||
	bool is_maximized = view->xdg_toplevel->current.maximized;
 | 
			
		||||
	if (!is_maximized) {
 | 
			
		||||
		struct wb_config *config = toplevel->server->config;
 | 
			
		||||
		toplevel->previous_geometry = toplevel->geometry;
 | 
			
		||||
		struct wb_config *config = view->server->config;
 | 
			
		||||
		view->previous_geometry = view->geometry;
 | 
			
		||||
		if (config) {
 | 
			
		||||
			toplevel->geometry.x = config->margins.left;
 | 
			
		||||
			toplevel->geometry.y = config->margins.top;
 | 
			
		||||
			view->geometry.x = config->margins.left;
 | 
			
		||||
			view->geometry.y = config->margins.top;
 | 
			
		||||
			usable_area.height -= config->margins.top + config->margins.bottom;
 | 
			
		||||
			usable_area.width -= config->margins.left + config->margins.right;
 | 
			
		||||
		} else {
 | 
			
		||||
			toplevel->geometry.x = 0;
 | 
			
		||||
			toplevel->geometry.y = 0;
 | 
			
		||||
			view->geometry.x = 0;
 | 
			
		||||
			view->geometry.y = 0;
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		usable_area = toplevel->previous_geometry;
 | 
			
		||||
		toplevel->geometry.x = toplevel->previous_geometry.x;
 | 
			
		||||
		toplevel->geometry.y = toplevel->previous_geometry.y;
 | 
			
		||||
		usable_area = view->previous_geometry;
 | 
			
		||||
		view->geometry.x = view->previous_geometry.x;
 | 
			
		||||
		view->geometry.y = view->previous_geometry.y;
 | 
			
		||||
	}
 | 
			
		||||
	wlr_xdg_toplevel_set_size(toplevel->xdg_toplevel, usable_area.width, usable_area.height);
 | 
			
		||||
	wlr_xdg_toplevel_set_maximized(toplevel->xdg_toplevel, !is_maximized);
 | 
			
		||||
	wlr_scene_node_set_position(&toplevel->scene_tree->node,
 | 
			
		||||
			toplevel->geometry.x, toplevel->geometry.y);
 | 
			
		||||
	wlr_xdg_toplevel_set_size(view->xdg_toplevel, usable_area.width, usable_area.height);
 | 
			
		||||
	wlr_xdg_toplevel_set_maximized(view->xdg_toplevel, !is_maximized);
 | 
			
		||||
	wlr_scene_node_set_position(&view->scene_tree->node,
 | 
			
		||||
			view->geometry.x, view->geometry.y);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void xdg_toplevel_request_minimize(struct wl_listener *listener, void *data) {
 | 
			
		||||
	struct wb_toplevel *toplevel = wl_container_of(listener, toplevel, request_minimize);
 | 
			
		||||
	bool minimize_requested = toplevel->xdg_toplevel->requested.minimized;
 | 
			
		||||
	struct wb_view *view = wl_container_of(listener, view, request_minimize);
 | 
			
		||||
	bool minimize_requested = view->xdg_toplevel->requested.minimized;
 | 
			
		||||
	if (minimize_requested) {
 | 
			
		||||
		toplevel->previous_geometry = toplevel->geometry;
 | 
			
		||||
		toplevel->geometry.y = -toplevel->geometry.height;
 | 
			
		||||
		view->previous_geometry = view->geometry;
 | 
			
		||||
		view->geometry.y = -view->geometry.height;
 | 
			
		||||
 | 
			
		||||
		struct wb_toplevel *next_toplevel = wl_container_of(toplevel->link.next, next_toplevel, link);
 | 
			
		||||
		if (wl_list_length(&toplevel->link) > 1)
 | 
			
		||||
			focus_toplevel(next_toplevel);
 | 
			
		||||
		struct wb_view *next_view = wl_container_of(view->link.next, next_view, link);
 | 
			
		||||
		if (wl_list_length(&view->link) > 1)
 | 
			
		||||
			focus_view(next_view, next_view->xdg_toplevel->base->surface);
 | 
			
		||||
		else
 | 
			
		||||
			focus_toplevel(toplevel);
 | 
			
		||||
			focus_view(view, view->xdg_toplevel->base->surface);
 | 
			
		||||
	} else {
 | 
			
		||||
		toplevel->geometry = toplevel->previous_geometry;
 | 
			
		||||
		view->geometry = view->previous_geometry;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	wlr_scene_node_set_position(&toplevel->scene_tree->node,
 | 
			
		||||
			toplevel->geometry.x, toplevel->geometry.y);
 | 
			
		||||
	wlr_scene_node_set_position(&view->scene_tree->node,
 | 
			
		||||
			view->geometry.x, view->geometry.y);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void begin_interactive(struct wb_toplevel *toplevel,
 | 
			
		||||
static void begin_interactive(struct wb_view *view,
 | 
			
		||||
		enum wb_cursor_mode mode, uint32_t edges) {
 | 
			
		||||
	/* This function sets up an interactive move or resize operation, where the
 | 
			
		||||
	 * compositor stops propagating pointer events to clients and instead
 | 
			
		||||
	 * consumes them itself, to move or resize windows. */
 | 
			
		||||
	struct wb_server *server = toplevel->server;
 | 
			
		||||
	server->grabbed_toplevel = toplevel;
 | 
			
		||||
	struct wb_server *server = view->server;
 | 
			
		||||
	struct wlr_surface *focused_surface =
 | 
			
		||||
		server->seat->seat->pointer_state.focused_surface;
 | 
			
		||||
	if (view->xdg_toplevel->base->surface != wlr_surface_get_root_surface(focused_surface)) {
 | 
			
		||||
		/* Deny move/resize requests from unfocused clients. */
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	server->grabbed_view = view;
 | 
			
		||||
	server->cursor->cursor_mode = mode;
 | 
			
		||||
 | 
			
		||||
	if (mode == WB_CURSOR_MOVE) {
 | 
			
		||||
		server->grab_x = server->cursor->cursor->x - toplevel->geometry.x;
 | 
			
		||||
		server->grab_y = server->cursor->cursor->y - toplevel->geometry.y;
 | 
			
		||||
		server->grab_x = server->cursor->cursor->x - view->geometry.x;
 | 
			
		||||
		server->grab_y = server->cursor->cursor->y - view->geometry.y;
 | 
			
		||||
	} else if (mode == WB_CURSOR_RESIZE) {
 | 
			
		||||
#if WLR_CHECK_VERSION(0, 19, 0)
 | 
			
		||||
		struct wlr_box geo_box = toplevel->xdg_toplevel->base->geometry;
 | 
			
		||||
#else
 | 
			
		||||
		struct wlr_box geo_box;
 | 
			
		||||
		wlr_xdg_surface_get_geometry(toplevel->xdg_toplevel->base, &geo_box);
 | 
			
		||||
#endif
 | 
			
		||||
		wlr_xdg_surface_get_geometry(view->xdg_toplevel->base, &geo_box);
 | 
			
		||||
 | 
			
		||||
		double border_x = (toplevel->geometry.x + geo_box.x) +
 | 
			
		||||
		double border_x = (view->geometry.x + geo_box.x) +
 | 
			
		||||
			((edges & WLR_EDGE_RIGHT) ? geo_box.width : 0);
 | 
			
		||||
		double border_y = (toplevel->geometry.y + geo_box.y) +
 | 
			
		||||
		double border_y = (view->geometry.y + geo_box.y) +
 | 
			
		||||
			((edges & WLR_EDGE_BOTTOM) ? geo_box.height : 0);
 | 
			
		||||
		server->grab_x = server->cursor->cursor->x - border_x;
 | 
			
		||||
		server->grab_y = server->cursor->cursor->y - border_y;
 | 
			
		||||
 | 
			
		||||
		server->grab_geo_box = geo_box;
 | 
			
		||||
		server->grab_geo_box.x += toplevel->geometry.x;
 | 
			
		||||
		server->grab_geo_box.y += toplevel->geometry.y;
 | 
			
		||||
		server->grab_geo_box.x += view->geometry.x;
 | 
			
		||||
		server->grab_geo_box.y += view->geometry.y;
 | 
			
		||||
 | 
			
		||||
		server->resize_edges = edges;
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -340,8 +270,8 @@ static void xdg_toplevel_request_move(
 | 
			
		|||
	/* This event is raised when a client would like to begin an interactive
 | 
			
		||||
	 * move, typically because the user clicked on their client-side
 | 
			
		||||
	 * decorations. */
 | 
			
		||||
	struct wb_toplevel *toplevel = wl_container_of(listener, toplevel, request_move);
 | 
			
		||||
	begin_interactive(toplevel, WB_CURSOR_MOVE, 0);
 | 
			
		||||
	struct wb_view *view = wl_container_of(listener, view, request_move);
 | 
			
		||||
	begin_interactive(view, WB_CURSOR_MOVE, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void xdg_toplevel_request_resize(
 | 
			
		||||
| 
						 | 
				
			
			@ -350,135 +280,100 @@ static void xdg_toplevel_request_resize(
 | 
			
		|||
	 * resize, typically because the user clicked on their client-side
 | 
			
		||||
	 * decorations. */
 | 
			
		||||
	struct wlr_xdg_toplevel_resize_event *event = data;
 | 
			
		||||
	struct wb_toplevel *toplevel = wl_container_of(listener, toplevel, request_resize);
 | 
			
		||||
	begin_interactive(toplevel, WB_CURSOR_RESIZE, event->edges);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void xdg_popup_commit(struct wl_listener *listener, void *data) {
 | 
			
		||||
	struct wb_popup *popup = wl_container_of(listener, popup, commit);
 | 
			
		||||
	if (!popup->xdg_popup) return;
 | 
			
		||||
	struct wlr_xdg_surface *base = popup->xdg_popup->base;
 | 
			
		||||
 | 
			
		||||
	if (base && base->initial_commit) {
 | 
			
		||||
		update_fractional_scale(base->surface);
 | 
			
		||||
		wlr_xdg_surface_schedule_configure(base);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void xdg_popup_destroy(struct wl_listener *listener, void *data) {
 | 
			
		||||
	struct wb_popup *popup = wl_container_of(listener, popup, destroy);
 | 
			
		||||
	if (popup->xdg_popup)
 | 
			
		||||
		update_fractional_scale(popup->xdg_popup->base->surface);
 | 
			
		||||
 | 
			
		||||
	wl_list_remove(&popup->commit.link);
 | 
			
		||||
	wl_list_remove(&popup->destroy.link);
 | 
			
		||||
	free(popup);
 | 
			
		||||
	struct wb_view *view = wl_container_of(listener, view, request_resize);
 | 
			
		||||
	begin_interactive(view, WB_CURSOR_RESIZE, event->edges);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_new_popup(struct wl_listener *listener, void *data) {
 | 
			
		||||
	struct wlr_xdg_popup *popup = data;
 | 
			
		||||
	struct wb_toplevel *toplevel = wl_container_of(listener, toplevel, new_popup);
 | 
			
		||||
	struct wb_view *view = wl_container_of(listener, view, new_popup);
 | 
			
		||||
 | 
			
		||||
	struct wlr_output *wlr_output = wlr_output_layout_output_at(
 | 
			
		||||
			toplevel->server->output_layout,
 | 
			
		||||
			toplevel->geometry.x + popup->current.geometry.x,
 | 
			
		||||
			toplevel->geometry.y + popup->current.geometry.y);
 | 
			
		||||
			view->server->output_layout,
 | 
			
		||||
			view->geometry.x + popup->current.geometry.x,
 | 
			
		||||
			view->geometry.y + popup->current.geometry.y);
 | 
			
		||||
 | 
			
		||||
	if (!wlr_output) {
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	if (!wlr_output) return;
 | 
			
		||||
	struct wb_output *output = wlr_output->data;
 | 
			
		||||
 | 
			
		||||
	int top_margin = (toplevel->server->config) ?
 | 
			
		||||
		toplevel->server->config->margins.top : 0;
 | 
			
		||||
	int top_margin = (view->server->config) ?
 | 
			
		||||
		view->server->config->margins.top : 0;
 | 
			
		||||
	struct wlr_box output_toplevel_box = {
 | 
			
		||||
		.x = output->geometry.x - toplevel->geometry.x,
 | 
			
		||||
		.y = output->geometry.y - toplevel->geometry.y,
 | 
			
		||||
		.x = output->geometry.x - view->geometry.x,
 | 
			
		||||
		.y = output->geometry.y - view->geometry.y,
 | 
			
		||||
		.width = output->geometry.width,
 | 
			
		||||
		.height = output->geometry.height - top_margin,
 | 
			
		||||
	};
 | 
			
		||||
	wlr_xdg_popup_unconstrain_from_box(popup, &output_toplevel_box);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_new_xdg_popup(struct wl_listener *listener, void *data) {
 | 
			
		||||
static void handle_new_xdg_surface(struct wl_listener *listener, void *data) {
 | 
			
		||||
	/* This event is raised when wlr_xdg_shell receives a new xdg surface from a
 | 
			
		||||
	 * client, either a toplevel (application window) or popup. */
 | 
			
		||||
	struct wb_server *server =
 | 
			
		||||
		wl_container_of(listener, server, new_xdg_surface);
 | 
			
		||||
	struct wlr_xdg_surface *xdg_surface = data;
 | 
			
		||||
 | 
			
		||||
	/* We must add xdg popups to the scene graph so they get rendered. The
 | 
			
		||||
	 * wlroots scene graph provides a helper for this, but to use it we must
 | 
			
		||||
	 * provide the proper parent scene node of the xdg popup. To enable this,
 | 
			
		||||
	 * we always set the user data field of xdg_surfaces to the corresponding
 | 
			
		||||
	 * scene node. */
 | 
			
		||||
	struct wlr_xdg_popup *xdg_popup = data;
 | 
			
		||||
	if (xdg_popup->parent) {
 | 
			
		||||
		struct wlr_xdg_surface *parent = wlr_xdg_surface_try_from_wlr_surface(
 | 
			
		||||
			xdg_popup->parent);
 | 
			
		||||
		if (parent != NULL) {
 | 
			
		||||
	if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP) {
 | 
			
		||||
		if (wlr_surface_is_xdg_surface(xdg_surface->popup->parent)) {
 | 
			
		||||
			struct wlr_xdg_surface *parent = wlr_xdg_surface_from_wlr_surface(
 | 
			
		||||
				xdg_surface->popup->parent);
 | 
			
		||||
			struct wlr_scene_tree *parent_tree = parent->data;
 | 
			
		||||
			xdg_popup->base->data = wlr_scene_xdg_surface_create(
 | 
			
		||||
				parent_tree, xdg_popup->base);
 | 
			
		||||
			xdg_surface->data = wlr_scene_xdg_surface_create(
 | 
			
		||||
				parent_tree, xdg_surface);
 | 
			
		||||
		}
 | 
			
		||||
		/* The scene graph doesn't currently unconstrain popups, so keep going */
 | 
			
		||||
		/* return; */
 | 
			
		||||
	}
 | 
			
		||||
	if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_NONE)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	struct wb_popup *popup = calloc(1, sizeof(struct wb_popup));
 | 
			
		||||
	popup->commit.notify = xdg_popup_commit;
 | 
			
		||||
	wl_signal_add(&xdg_popup->base->surface->events.commit, &popup->commit);
 | 
			
		||||
 | 
			
		||||
	popup->destroy.notify = xdg_popup_destroy;
 | 
			
		||||
	wl_signal_add(&xdg_popup->events.destroy, &popup->destroy);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_new_xdg_toplevel(struct wl_listener *listener, void *data) {
 | 
			
		||||
	struct wb_server *server =
 | 
			
		||||
		wl_container_of(listener, server, new_xdg_toplevel);
 | 
			
		||||
	struct wlr_xdg_toplevel *xdg_toplevel = data;
 | 
			
		||||
 | 
			
		||||
	/* Allocate a wb_toplevel for this toplevel */
 | 
			
		||||
	struct wb_toplevel *toplevel =
 | 
			
		||||
		calloc(1, sizeof(struct wb_toplevel));
 | 
			
		||||
	toplevel->server = server;
 | 
			
		||||
	toplevel->xdg_toplevel = xdg_toplevel;
 | 
			
		||||
 | 
			
		||||
	toplevel->foreign_toplevel_handle = wlr_ext_foreign_toplevel_handle_v1_create(
 | 
			
		||||
			server->foreign_toplevel_list, &toplevel->foreign_toplevel_state);
 | 
			
		||||
	/* Allocate a wb_view for this surface */
 | 
			
		||||
	struct wb_view *view =
 | 
			
		||||
		calloc(1, sizeof(struct wb_view));
 | 
			
		||||
	view->server = server;
 | 
			
		||||
	view->xdg_toplevel = xdg_surface->toplevel;
 | 
			
		||||
 | 
			
		||||
	/* Listen to the various events it can emit */
 | 
			
		||||
	toplevel->map.notify = xdg_toplevel_map;
 | 
			
		||||
	wl_signal_add(&xdg_toplevel->base->surface->events.map, &toplevel->map);
 | 
			
		||||
	toplevel->unmap.notify = xdg_toplevel_unmap;
 | 
			
		||||
	wl_signal_add(&xdg_toplevel->base->surface->events.unmap, &toplevel->unmap);
 | 
			
		||||
	toplevel->commit.notify = xdg_toplevel_commit;
 | 
			
		||||
	wl_signal_add(&xdg_toplevel->base->surface->events.commit, &toplevel->commit);
 | 
			
		||||
	toplevel->destroy.notify = xdg_toplevel_destroy;
 | 
			
		||||
	wl_signal_add(&xdg_toplevel->events.destroy, &toplevel->destroy);
 | 
			
		||||
	toplevel->new_popup.notify = handle_new_popup;
 | 
			
		||||
	wl_signal_add(&xdg_toplevel->base->events.new_popup, &toplevel->new_popup);
 | 
			
		||||
	view->map.notify = xdg_toplevel_map;
 | 
			
		||||
	wl_signal_add(&xdg_surface->events.map, &view->map);
 | 
			
		||||
	view->unmap.notify = xdg_toplevel_unmap;
 | 
			
		||||
	wl_signal_add(&xdg_surface->events.unmap, &view->unmap);
 | 
			
		||||
	view->destroy.notify = xdg_toplevel_destroy;
 | 
			
		||||
	wl_signal_add(&xdg_surface->events.destroy, &view->destroy);
 | 
			
		||||
	view->new_popup.notify = handle_new_popup;
 | 
			
		||||
	wl_signal_add(&xdg_surface->events.new_popup, &view->new_popup);
 | 
			
		||||
 | 
			
		||||
	toplevel->scene_tree = wlr_scene_xdg_surface_create(
 | 
			
		||||
		&toplevel->server->scene->tree, xdg_toplevel->base);
 | 
			
		||||
	toplevel->scene_tree->node.data = toplevel;
 | 
			
		||||
	xdg_toplevel->base->data = toplevel->scene_tree;
 | 
			
		||||
	if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL) {
 | 
			
		||||
		view->scene_tree = wlr_scene_xdg_surface_create(
 | 
			
		||||
			&view->server->scene->tree, view->xdg_toplevel->base);
 | 
			
		||||
		view->scene_tree->node.data = view;
 | 
			
		||||
		xdg_surface->data = view->scene_tree;
 | 
			
		||||
 | 
			
		||||
	toplevel->request_fullscreen.notify = xdg_toplevel_request_fullscreen;
 | 
			
		||||
	wl_signal_add(&xdg_toplevel->events.request_fullscreen, &toplevel->request_fullscreen);
 | 
			
		||||
	toplevel->request_maximize.notify = xdg_toplevel_request_maximize;
 | 
			
		||||
	wl_signal_add(&xdg_toplevel->events.request_maximize, &toplevel->request_maximize);
 | 
			
		||||
	toplevel->request_minimize.notify = xdg_toplevel_request_minimize;
 | 
			
		||||
	wl_signal_add(&xdg_toplevel->events.request_minimize, &toplevel->request_minimize);
 | 
			
		||||
	toplevel->request_move.notify = xdg_toplevel_request_move;
 | 
			
		||||
	wl_signal_add(&xdg_toplevel->events.request_move, &toplevel->request_move);
 | 
			
		||||
	toplevel->request_resize.notify = xdg_toplevel_request_resize;
 | 
			
		||||
	wl_signal_add(&xdg_toplevel->events.request_resize, &toplevel->request_resize);
 | 
			
		||||
	toplevel->set_app_id.notify = xdg_toplevel_set_app_id;
 | 
			
		||||
	wl_signal_add(&xdg_toplevel->events.set_app_id, &toplevel->set_app_id);
 | 
			
		||||
	toplevel->set_title.notify = xdg_toplevel_set_title;
 | 
			
		||||
	wl_signal_add(&xdg_toplevel->events.set_title, &toplevel->set_title);
 | 
			
		||||
		struct wlr_xdg_toplevel *toplevel = view->xdg_toplevel;
 | 
			
		||||
		view->request_fullscreen.notify = xdg_toplevel_request_fullscreen;
 | 
			
		||||
		wl_signal_add(&toplevel->events.request_fullscreen, &view->request_fullscreen);
 | 
			
		||||
		view->request_maximize.notify = xdg_toplevel_request_maximize;
 | 
			
		||||
		wl_signal_add(&toplevel->events.request_maximize, &view->request_maximize);
 | 
			
		||||
		view->request_minimize.notify = xdg_toplevel_request_minimize;
 | 
			
		||||
		wl_signal_add(&toplevel->events.request_minimize, &view->request_minimize);
 | 
			
		||||
		view->request_move.notify = xdg_toplevel_request_move;
 | 
			
		||||
		wl_signal_add(&toplevel->events.request_move, &view->request_move);
 | 
			
		||||
		view->request_resize.notify = xdg_toplevel_request_resize;
 | 
			
		||||
		wl_signal_add(&toplevel->events.request_resize, &view->request_resize);
 | 
			
		||||
 | 
			
		||||
	wl_list_insert(&toplevel->server->toplevels, &toplevel->link);
 | 
			
		||||
		wl_list_insert(&view->server->views, &view->link);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void init_xdg_shell(struct wb_server *server) {
 | 
			
		||||
	/* xdg-shell version 3 */
 | 
			
		||||
	server->xdg_shell = wlr_xdg_shell_create(server->wl_display, 3);
 | 
			
		||||
	server->new_xdg_popup.notify = handle_new_xdg_popup;
 | 
			
		||||
	wl_signal_add(&server->xdg_shell->events.new_popup, &server->new_xdg_popup);
 | 
			
		||||
	server->new_xdg_toplevel.notify = handle_new_xdg_toplevel;
 | 
			
		||||
	wl_signal_add(&server->xdg_shell->events.new_toplevel, &server->new_xdg_toplevel);
 | 
			
		||||
	server->new_xdg_surface.notify = handle_new_xdg_surface;
 | 
			
		||||
	wl_signal_add(&server->xdg_shell->events.new_surface, &server->new_xdg_surface);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue