mirror of
https://github.com/wizbright/waybox.git
synced 2025-10-29 05:40:20 -04:00
Compare commits
56 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
62dd0a5c8b | ||
|
|
557bb4ae05 | ||
|
|
4c6a762e12 | ||
|
|
b802cadffa | ||
|
|
ac626fc5d5 | ||
|
|
f6ebf16a95 | ||
|
|
606663a390 | ||
|
|
db79d83076 | ||
|
|
b2e686171f | ||
|
|
a6e9a04495 | ||
|
|
d4d033e685 | ||
|
|
d7f4d1001f | ||
|
|
80bc1d51cd | ||
|
|
73eb94d18a | ||
|
|
3e000a9087 | ||
|
|
19339ac6a0 | ||
|
|
88ce9ad366 | ||
|
|
4cf3ee8a05 | ||
|
|
0f9461c4c0 | ||
|
|
2643966144 | ||
|
|
3f0814fd56 | ||
|
|
ca2587f4f9 | ||
|
|
7a679988ac | ||
|
|
77652741b5 | ||
|
|
c9b187afc8 | ||
|
|
35b3e5af11 | ||
|
|
3a64d3955c | ||
|
|
f967bfae17 | ||
|
|
fb3c8eb152 | ||
|
|
cf2c1a97a7 | ||
|
|
b7e7cde0a5 | ||
|
|
fb3a845354 | ||
|
|
bce423cd72 | ||
|
|
0294b25f27 | ||
|
|
fa36852a58 | ||
|
|
b274485c9c | ||
|
|
b5f4055904 | ||
|
|
3687099182 | ||
|
|
d139b41259 | ||
|
|
ead6648438 | ||
|
|
ae42d9d2f7 | ||
|
|
bceafa5b6b | ||
|
|
7fb889d171 | ||
|
|
2b38536dec | ||
|
|
fd0c5b04d3 | ||
|
|
6dc905d758 | ||
|
|
e6bac6d366 | ||
|
|
f50ab866f9 | ||
|
|
4eb4536b28 | ||
|
|
3f2a6f7b6c | ||
|
|
8fa589a132 | ||
|
|
e938552d15 | ||
|
|
0df03fcd9d | ||
|
|
bf0f9215dc | ||
|
|
e4b603a082 | ||
|
|
6c6d0214b4 |
41 changed files with 1262 additions and 519 deletions
19
.build.yml
19
.build.yml
|
|
@ -3,20 +3,27 @@
|
|||
#
|
||||
image: archlinux
|
||||
packages:
|
||||
- meson
|
||||
- wayland
|
||||
- wayland-protocols
|
||||
- clang
|
||||
- gcc
|
||||
- libevdev
|
||||
- libinput
|
||||
- libxkbcommon
|
||||
- libxml2
|
||||
- wlroots
|
||||
- meson
|
||||
- wayland
|
||||
- wayland-protocols
|
||||
- wlroots-git
|
||||
- xorg-server-xwayland
|
||||
sources:
|
||||
- https://github.com/wizbright/waybox
|
||||
tasks:
|
||||
- setup: |
|
||||
cd waybox
|
||||
meson setup build
|
||||
CC=gcc meson setup build-gcc
|
||||
- build: |
|
||||
cd waybox
|
||||
ninja -C build
|
||||
ninja -C build-gcc
|
||||
- clang: |
|
||||
cd waybox
|
||||
CC=clang meson setup build-clang
|
||||
ninja -C build-clang
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ block_comment_start = /*
|
|||
block_comment_end = */
|
||||
|
||||
curly_bracket_next_line = false
|
||||
max_line_length = 80
|
||||
max_line_length = 100
|
||||
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: archlinux:base-devel
|
||||
container: alpine:edge
|
||||
steps:
|
||||
- name: packages
|
||||
run: |
|
||||
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
|
||||
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
|
||||
run: |
|
||||
meson setup build
|
||||
- name: build
|
||||
CC=gcc meson setup build-gcc
|
||||
ninja -C build-gcc
|
||||
- name: build-clang
|
||||
run: |
|
||||
ninja -C build
|
||||
CC=clang meson setup build-clang
|
||||
ninja -C build-clang
|
||||
|
|
|
|||
|
|
@ -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 80 columns, but you can go up to 100 if it
|
||||
Try to keep your lines under 100 columns, but you can break this rule 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,8 +1,10 @@
|
|||
# Waybox
|
||||
An Openbox clone on Wayland (WIP)
|
||||
|
||||
A \*box-style (minimalist) Wayland compositor modeled largely on Openbox (WIP)
|
||||
|
||||
### Goals
|
||||
The main goal of this project is to provide a similar feel to Openbox but on Wayland
|
||||
|
||||
The main goal of this project is to provide a similar feel to \*box-style window managers but on Wayland
|
||||
|
||||
### Contributing
|
||||
|
||||
|
|
@ -11,14 +13,15 @@ contributing.](https://github.com/wizbright/waybox/blob/master/CONTRIBUTING.md)
|
|||
|
||||
### Dependencies
|
||||
|
||||
* [Meson](https://mesonbuild.com/)
|
||||
* [wlroots](https://gitlab.freedesktop.org/wlroots/wlroots/)
|
||||
* [libxml2](http://xmlsoft.org/)
|
||||
* [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/)
|
||||
* [wlroots](https://gitlab.freedesktop.org/wlroots/wlroots/)
|
||||
* [xkbcommon](https://xkbcommon.org/)
|
||||
|
||||
### Build instructions
|
||||
|
||||
```
|
||||
meson setup build
|
||||
cd build
|
||||
|
|
@ -27,6 +30,30 @@ 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,15 +23,48 @@ cairo-dock &
|
|||
mako &
|
||||
|
||||
# Load a 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
|
||||
wpdir="$data_dir/wallpapers"
|
||||
test -d "$wpdir" && \
|
||||
find $wpdir -name '*.jpg' -o -name '*.png' -o -name '*.svg'
|
||||
done | (shuf -n 1 || tail -n 1) | xargs swaybg -m fill -i &
|
||||
IFS=$oldifs
|
||||
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
|
||||
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 &
|
||||
|
||||
# vim: ft=sh
|
||||
|
|
|
|||
|
|
@ -30,17 +30,25 @@ if test -n "$DISPLAY" && test -d /etc/X11/xinit/xinitrc.d;
|
|||
then
|
||||
for f in /etc/X11/xinit/xinitrc.d/*.sh;
|
||||
do
|
||||
test -f "$f" && . "$f"
|
||||
test -r "$f" && . "$f"
|
||||
done
|
||||
fi
|
||||
|
||||
# Get the preferred terminal from GNOME (if you use mostly GTK apps)
|
||||
TERMINAL=$(gsettings get org.gnome.desktop.default-applications.terminal exec | tr -d \')
|
||||
# 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 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
|
||||
|
||||
# Use autostart scripts for these environments
|
||||
export WB_AUTOSTART_ENVIRONMENT=GNOME:KDE
|
||||
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
|
||||
|
|
|
|||
71
data/menu
Normal file
71
data/menu
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
#!/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,4 +1,5 @@
|
|||
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'))
|
||||
|
|
@ -33,8 +34,21 @@ 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']
|
||||
)
|
||||
|
|
|
|||
55
data/rc.xml
55
data/rc.xml
|
|
@ -9,15 +9,15 @@
|
|||
<right>0</right>
|
||||
</margins>
|
||||
<keyboard>
|
||||
<!-- Keyboard layout. See `man xkeyboard-config` for more information -->
|
||||
<!-- XKB configuration. See `man xkeyboard-config` for more information -->
|
||||
<!-- You can use the XKB_* environment variables instead -->
|
||||
<!-- <keyboardLayout>
|
||||
<!-- <xkb>
|
||||
<model>105</model>
|
||||
<layout>us</layout>
|
||||
<options>ctrl:swapcaps,esperanto:dvorak,lv3:ralt_switch_multikey</options>
|
||||
<rules>evdev</rules>
|
||||
<variant>dvorak</variant>
|
||||
</keyboardLayout> -->
|
||||
</xkb> -->
|
||||
<!-- Keybindings for windows -->
|
||||
<keybind key="A-F4">
|
||||
<action name="Close"/>
|
||||
|
|
@ -42,25 +42,16 @@
|
|||
</keybind>
|
||||
<!-- Keybindings for window switching -->
|
||||
<keybind key="A-Tab">
|
||||
<action name="NextWindow">
|
||||
<finalactions>
|
||||
<action name="Unshade"/>
|
||||
</finalactions>
|
||||
</action>
|
||||
<action name="NextWindow"/>
|
||||
<action name="Unshade"/>
|
||||
</keybind>
|
||||
<keybind key="A-S-ISO_Left_Tab">
|
||||
<action name="PreviousWindow">
|
||||
<finalactions>
|
||||
<action name="Unshade"/>
|
||||
</finalactions>
|
||||
</action>
|
||||
<action name="PreviousWindow"/>
|
||||
<action name="Unshade"/>
|
||||
</keybind>
|
||||
<keybind key="C-A-Tab">
|
||||
<action name="NextWindow">
|
||||
<finalactions>
|
||||
<action name="Unshade"/>
|
||||
</finalactions>
|
||||
</action>
|
||||
<action name="NextWindow"/>
|
||||
<action name="Unshade"/>
|
||||
</keybind>
|
||||
<!-- Keybindings for running applications -->
|
||||
<keybind key="W-Return">
|
||||
|
|
@ -78,6 +69,12 @@
|
|||
<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>
|
||||
|
|
@ -115,4 +112,26 @@
|
|||
</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,4 +4,5 @@ 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,7 +60,12 @@ then
|
|||
fi
|
||||
|
||||
# And the XDG autostart script
|
||||
if test -x $WB_USER_CONF_DIR/xdg-autostart;
|
||||
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;
|
||||
then
|
||||
WB_XDG_AUTOSTART=$WB_USER_CONF_DIR/xdg-autostart;
|
||||
elif test -x $WB_SYS_CONF_DIR/xdg-autostart;
|
||||
|
|
@ -72,6 +77,26 @@ 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
|
||||
|
|
@ -94,9 +119,11 @@ export WB_RC_XML
|
|||
|
||||
if which dbus-launch >/dev/null 2>&1;
|
||||
then
|
||||
DBUS_LANCH="dbus-launch --exit-with-session"
|
||||
DBUS_LAUNCH="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}" "$@"
|
||||
|
|
|
|||
14
data/waybox.svg
Normal file
14
data/waybox.svg
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
<?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>
|
||||
|
After Width: | Height: | Size: 601 B |
|
|
@ -66,6 +66,8 @@ do
|
|||
then
|
||||
show_in=0
|
||||
break 2
|
||||
else
|
||||
show_in=1
|
||||
fi
|
||||
done
|
||||
done
|
||||
|
|
@ -88,7 +90,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" && ! which $TRY_EXEC;
|
||||
if test -n "$TRY_EXEC" && ! command -v $TRY_EXEC >/dev/null 2>&1;
|
||||
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,42 +18,19 @@ struct wb_output {
|
|||
struct wlr_scene_tree *shell_top;
|
||||
} layers;
|
||||
|
||||
#if ! WLR_CHECK_VERSION(0, 17, 0)
|
||||
/* DEPRECATED: Use a tool like swaybg instead */
|
||||
struct wlr_scene_rect *background;
|
||||
#endif
|
||||
bool gamma_lut_changed;
|
||||
struct wlr_box geometry;
|
||||
|
||||
struct wl_listener destroy;
|
||||
struct wl_listener frame;
|
||||
struct wl_listener request_state;
|
||||
|
||||
struct wl_list link;
|
||||
};
|
||||
|
||||
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);
|
||||
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);
|
||||
|
||||
#endif /* output.h */
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
#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>
|
||||
|
|
@ -22,6 +23,8 @@
|
|||
#include <wlr/types/wlr_xdg_shell.h>
|
||||
#include <wlr/util/log.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef USE_NLS
|
||||
# include <libintl.h>
|
||||
# include <locale.h>
|
||||
|
|
@ -34,21 +37,27 @@
|
|||
#include "waybox/cursor.h"
|
||||
#include "decoration.h"
|
||||
#include "layer_shell.h"
|
||||
#include "waybox/output.h"
|
||||
#include "waybox/xdg_shell.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;
|
||||
|
|
@ -56,21 +65,31 @@ struct wb_server {
|
|||
struct wb_cursor *cursor;
|
||||
struct wb_seat *seat;
|
||||
|
||||
struct wb_view *grabbed_view;
|
||||
struct wb_toplevel *grabbed_toplevel;
|
||||
struct wlr_box grab_geo_box;
|
||||
double grab_x, grab_y;
|
||||
uint32_t resize_edges;
|
||||
struct wl_list views;
|
||||
struct wlr_ext_foreign_toplevel_list_v1 *foreign_toplevel_list;
|
||||
struct wl_list toplevels;
|
||||
|
||||
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,12 +1,49 @@
|
|||
#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_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(
|
||||
void focus_toplevel(struct wb_toplevel *toplevel);
|
||||
struct wlr_output *get_active_output(struct wb_toplevel *toplevel);
|
||||
struct wb_toplevel *get_toplevel_at(
|
||||
struct wb_server *server, double lx, double ly,
|
||||
struct wlr_surface **surface, double *sx, double *sy);
|
||||
#endif
|
||||
|
|
|
|||
24
meson.build
24
meson.build
|
|
@ -1,9 +1,9 @@
|
|||
project(
|
||||
'Waybox',
|
||||
'c',
|
||||
version: '0.2.1',
|
||||
version: '0.2.3',
|
||||
license: 'MIT',
|
||||
meson_version: '>=0.52.0',
|
||||
meson_version: '>=0.60.0',
|
||||
default_options: [
|
||||
'c_std=c11',
|
||||
'warning_level=2',
|
||||
|
|
@ -15,6 +15,7 @@ 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() + '"',
|
||||
|
|
@ -25,16 +26,27 @@ 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')
|
||||
wlroots = dependency('wlroots', version: '>=0.16.0')
|
||||
wayland_protos = dependency('wayland-protocols', version: '>=1.37')
|
||||
wayland_server = dependency('wayland-server', version: '>=1.15')
|
||||
wayland_protos = dependency('wayland-protocols', version: '>=1.27')
|
||||
xkbcommon = dependency('xkbcommon')
|
||||
wlroots = dependency(wlroots_version, version: '>=0.17.0')
|
||||
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
meson_options.txt
Normal file
1
meson_options.txt
Normal file
|
|
@ -0,0 +1 @@
|
|||
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: 2022-12-06 22:27-0500\n"
|
||||
"PO-Revision-Date: 2022-12-06 22:30-0500\n"
|
||||
"POT-Creation-Date: 2024-01-25 21:21-0500\n"
|
||||
"PO-Revision-Date: 2024-01-25 21:34-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: Benutzt Dateien aus Openbox. Das wird nicht richtig werken."
|
||||
msgstr "WARNUNG: Benutze Dateien von Openbox, was nicht richtig funktionieren wird."
|
||||
|
||||
msgid "ERROR: No configuration file found."
|
||||
msgstr "FEHLER: Keine Einstellungsdatei gefunden."
|
||||
msgstr "FEHLER: Keine Konfigurationsdatei 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 nicht die Einstullungsdatei analisieren. Für mehr Informationen die "
|
||||
"Standardfehlerausgabe lesen."
|
||||
"Kann die Konfigurationsdatei nicht verarbeiten. Für weitere Informationen siehe "
|
||||
"die Standardfehlerausgabe."
|
||||
|
||||
msgid "Couldn't create new context!"
|
||||
msgstr "Konnte einen neuen Zusammenhang nicht erstellen"
|
||||
msgstr "Konnte keinen neuen Kontext erstellen!"
|
||||
|
||||
msgid "Couldn't register the namespace"
|
||||
msgstr "Konte dem Namensnraum nicht registrieren"
|
||||
msgstr "Konnte den Namensraum nicht registrieren"
|
||||
|
||||
#, c-format
|
||||
msgid "Syntax: %s [options]\n"
|
||||
msgstr "Eingabe: %s [Optionen]\n"
|
||||
msgstr "Syntax: %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 Verbindung zum Sitzungsmanager trennen\n"
|
||||
msgstr " --sm-disable Deaktiviere Verbindung zum Sitzungsmanager\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 Fehlersuche-Ergebnis anzeigen\n"
|
||||
msgstr " --debug Ausgabe von Debug-Informationen\n"
|
||||
|
||||
#, c-format
|
||||
msgid ""
|
||||
|
|
@ -92,8 +92,8 @@ msgid ""
|
|||
"on Wayland.\n"
|
||||
msgstr ""
|
||||
"\n"
|
||||
"Weitere Openbox-Optionen sind nicht angenommen, meistens wegen sie sind "
|
||||
"sinnlos auf Wayland.\n"
|
||||
"Weitere Openbox-Optionen werden nicht angenommen, da sie überwiegend "
|
||||
"sinnlos unter Wayland sind.\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 ist schon nicht implementiert.\n"
|
||||
msgstr "%s wurde bisher nicht implementiert.\n"
|
||||
|
||||
msgid "Successfully created backend"
|
||||
msgstr "Das Backend wurde erfolgreich hergestellt"
|
||||
msgstr "Das Backend wurde erfolgreich erstellt"
|
||||
|
||||
msgid "Failed to create backend"
|
||||
msgstr "Das Backend wurde nicht erfolgreich hergestellt"
|
||||
msgstr "Das Backend wurde nicht erstellt"
|
||||
|
||||
msgid "Successfully started server"
|
||||
msgstr "Der Server wurde erfolgreich gestartet"
|
||||
|
||||
msgid "Failed to start server"
|
||||
msgstr "Der Server wurde nicht erfolgreich gestartet"
|
||||
msgstr "Der Server wurde nicht gestartet"
|
||||
|
||||
msgid "New output device detected"
|
||||
msgstr "Neue Ausgabegerät entdeckt"
|
||||
msgstr "Neues Ausgabegerät entdeckt"
|
||||
|
||||
msgid "Couldn't commit pending frame to output"
|
||||
msgstr "Konnte sich nicht an den anstehenden Rahmen an die Ausgabe eintragen"
|
||||
msgid "Could not add an output layout."
|
||||
msgstr "Konnte keine neue Ausgabenanordnung hinzufügen."
|
||||
|
||||
msgid "New keyboard detected"
|
||||
msgstr "Neue Tastatur entdeckt"
|
||||
|
|
@ -128,22 +128,25 @@ msgid "New pointer detected"
|
|||
msgstr "Neuer Zeiger entdeckt"
|
||||
|
||||
msgid "Unsupported input device detected"
|
||||
msgstr "Unerkanntes Eingabegerät entdeckt"
|
||||
msgstr "Unbekanntes Eingabegerät entdeckt"
|
||||
|
||||
msgid "Failed to connect to a Wayland display"
|
||||
msgstr "Scheiterte an eines Wayland-Displays verbinden"
|
||||
msgstr "Scheiterte mit Verbindung an ein Wayland-Display"
|
||||
|
||||
msgid "Failed to get an event loop"
|
||||
msgstr "Scheiterte eine Ereignisschleife zu bekommen"
|
||||
|
||||
msgid "Failed to create renderer"
|
||||
msgstr "Das Renderer wurde nicht erfolgreich hergestellt"
|
||||
msgstr "Der Renderer wurde nicht erstellt"
|
||||
|
||||
msgid "Failed to create allocator"
|
||||
msgstr "Das Allokator wurde nicht erfolgreich hergestellt"
|
||||
msgstr "Der Allokator wurde nicht erstellt"
|
||||
|
||||
msgid "Failed to start backend"
|
||||
msgstr "Starten des Backend gescheitert"
|
||||
|
||||
msgid "Running Wayland compositor on Wayland display"
|
||||
msgstr "Ausführt Wayland-Compositor auf Wayland-Display"
|
||||
msgstr "Führe Wayland-Compositor auf Wayland-Display aus"
|
||||
|
||||
msgid "Display destroyed"
|
||||
msgstr "Display zerstört"
|
||||
|
|
@ -151,28 +154,32 @@ msgstr "Display zerstört"
|
|||
msgid "Keyboard focus is now on surface"
|
||||
msgstr "Tastaturfokus ist jetzt auf Oberfläche"
|
||||
|
||||
msgid "Focusing next view"
|
||||
msgstr "Fokussiert nächste Ansicht"
|
||||
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"
|
||||
|
||||
#, fuzzy
|
||||
#~ msgid "Failed to create wlr_backend"
|
||||
#~ msgstr "Das Backend wurde nicht erfolgreich hergestellt"
|
||||
#~ msgstr "wlr_backend wurde nicht erstellt"
|
||||
|
||||
#~ msgid "Couldn't get a surface texture"
|
||||
#~ msgstr "Konnte keine Oberflächentextur bekommen"
|
||||
|
||||
#~ msgid "Couldn't attach renderer to output"
|
||||
#~ msgstr "Konnte nicht einen Renderer an die Ausgabe nicht anbringen"
|
||||
#~ msgstr "Konnte Renderer nicht an die Ausgabe binden"
|
||||
|
||||
#~ msgid "Focusing current view"
|
||||
#~ msgstr "Fokussiert jetzige Ansicht"
|
||||
|
||||
#~ msgid "Unable to parse XML file"
|
||||
#~ msgstr "Konnte die XML-Datei nicht analisieren"
|
||||
#~ msgstr "Konnte die XML-Datei nicht analysieren"
|
||||
|
||||
#, c-format
|
||||
#~ msgid "Invalid action \"%s\" requested. No such action exists."
|
||||
#~ msgstr "Ungültige Aktion \"%s\" angefordert. Es gibt keine solche."
|
||||
#~ msgstr "Ungültige Aktion \"%s\" angefordert. Diese existiert nicht."
|
||||
|
||||
#~ msgid "No"
|
||||
#~ msgstr "Nein"
|
||||
|
|
@ -255,7 +262,7 @@ msgstr "Fokussiert nächste Ansicht"
|
|||
#~ msgstr "Immer im _Hintergrund"
|
||||
|
||||
#~ msgid "_Send to desktop"
|
||||
#~ msgstr "_Verschieben nach"
|
||||
#~ msgstr "_Sende an Desktop"
|
||||
|
||||
#~ msgid "Client menu"
|
||||
#~ msgstr "Anwendungsmenü"
|
||||
|
|
@ -292,8 +299,8 @@ msgstr "Fokussiert nächste Ansicht"
|
|||
#~ "Waybox was compiled without image loading support. Icons in menus will "
|
||||
#~ "not be loaded."
|
||||
#~ msgstr ""
|
||||
#~ "Waybox wurde ohne Bildladungsunterstützung kompiliert. Ikone in Menüs "
|
||||
#~ "werden nicht geladen werden."
|
||||
#~ "Waybox wurde ohne Unterstützung für Bilder kompiliert. Diese werden in Menüs "
|
||||
#~ "daher nicht geladen."
|
||||
|
||||
#~ msgid "Conflict with key binding in config file"
|
||||
#~ msgstr "Störende Tastenkombination in Konfigurationsdatei"
|
||||
|
|
@ -312,18 +319,18 @@ msgstr "Fokussiert nächste Ansicht"
|
|||
|
||||
#, c-format
|
||||
#~ msgid "Attempted to access menu \"%s\" but it does not exist"
|
||||
#~ msgstr "Versuchter Zugriff auf Menü \"%s\", doch es existiert nicht"
|
||||
#~ msgstr "Versuchter Zugriff auf Menü \"%s\", welches nicht existiert"
|
||||
|
||||
#~ msgid "More..."
|
||||
#~ msgstr "Mehr..."
|
||||
|
||||
#, c-format
|
||||
#~ msgid "Invalid button \"%s\" in mouse binding"
|
||||
#~ msgstr "Maus-Einbindung mit ungültiger Taste \"%s\""
|
||||
#~ msgstr "Maus-Kombination mit ungültiger Taste \"%s\""
|
||||
|
||||
#, c-format
|
||||
#~ msgid "Invalid context \"%s\" in mouse binding"
|
||||
#~ msgstr "Maus-Einbindung mit ungültigem Kontext \"%s\""
|
||||
#~ msgstr "Maus-Kombination mit ungültigem Kontext \"%s\""
|
||||
|
||||
#, c-format
|
||||
#~ msgid "Unable to change to home directory \"%s\": %s"
|
||||
|
|
@ -331,8 +338,8 @@ msgstr "Fokussiert nächste Ansicht"
|
|||
|
||||
#~ msgid "Unable to find a valid config file, using some simple defaults"
|
||||
#~ msgstr ""
|
||||
#~ "Keine gültige Konfigurationsdatei vorhanden, benutze einfache "
|
||||
#~ "Standardwerte"
|
||||
#~ "Keine gültige Konfigurationsdatei vorhanden, daher werden einfache "
|
||||
#~ "Standardwerte benutzt"
|
||||
|
||||
#~ msgid "Unable to load a theme."
|
||||
#~ msgstr "Kann kein Thema laden."
|
||||
|
|
@ -372,12 +379,12 @@ msgstr "Fokussiert nächste Ansicht"
|
|||
|
||||
#~ msgid " --debug-focus Display debugging output for focus handling\n"
|
||||
#~ msgstr ""
|
||||
#~ " --debug-focus Fehlersuche-Ergebnis für Fokus-Handling anzeigen\n"
|
||||
#~ " --debug-focus Debug-Informationen für Fokus-Handling anzeigen\n"
|
||||
|
||||
#~ msgid ""
|
||||
#~ " --debug-session Display debugging output for session management\n"
|
||||
#~ msgstr ""
|
||||
#~ " --debug-session Fehler-Ergebnis für Sitzungsmanager anzeigen\n"
|
||||
#~ " --debug-session Debug-Informationen für Sitzungsmanager anzeigen\n"
|
||||
|
||||
#, c-format
|
||||
#~ msgid ""
|
||||
|
|
@ -411,7 +418,7 @@ msgstr "Fokussiert nächste Ansicht"
|
|||
|
||||
#, c-format
|
||||
#~ msgid "Unable to make directory \"%s\": %s"
|
||||
#~ msgstr "Kann nicht Verzeichnis \"%s\" machen: %s"
|
||||
#~ msgstr "Kann Verzeichnis \"%s\" nicht erstellen: %s"
|
||||
|
||||
#, c-format
|
||||
#~ msgid "Unable to save the session to \"%s\": %s"
|
||||
|
|
@ -419,10 +426,10 @@ msgstr "Fokussiert nächste Ansicht"
|
|||
|
||||
#, c-format
|
||||
#~ msgid "Error while saving the session to \"%s\": %s"
|
||||
#~ msgstr "Fehler während die Sitzung in \"%s\" speichern: %s"
|
||||
#~ msgstr "Fehler beim Speichern der Sitzung in \"%s\": %s"
|
||||
|
||||
#~ msgid "Not connected to a session manager"
|
||||
#~ msgstr "An einer Sitzungsmanager nicht verbindet"
|
||||
#~ msgstr "Nicht mit Sitzungsmanager verbunden"
|
||||
|
||||
#, c-format
|
||||
#~ msgid "Running %s"
|
||||
|
|
@ -430,7 +437,7 @@ msgstr "Fokussiert nächste Ansicht"
|
|||
|
||||
#, c-format
|
||||
#~ msgid "Invalid modifier key \"%s\" in key/mouse binding"
|
||||
#~ msgstr "Ungültige Modifier-Taste \"%s\" in Tasten/Maus-Einbindung"
|
||||
#~ msgstr "Ungültige Modifier-Taste \"%s\" in Tasten/Maus-Kombination"
|
||||
|
||||
#, 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: 2022-12-06 22:27-0500\n"
|
||||
"PO-Revision-Date: 2022-12-06 22:33-0500\n"
|
||||
"POT-Creation-Date: 2024-01-25 21:21-0500\n"
|
||||
"PO-Revision-Date: 2024-01-25 21:35-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 povas taksi esprimon"
|
||||
msgstr "Ne eblis 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 povas registri lo nomspacon"
|
||||
msgstr "Ne eblis registri la 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 efektigita.\n"
|
||||
msgstr "%s ankoraŭ ne estas efektivigita.\n"
|
||||
|
||||
msgid "Successfully created backend"
|
||||
msgstr "Sukcese kreis servilan dorson"
|
||||
|
||||
msgid "Failed to create backend"
|
||||
msgstr "Malsukesis krei servilan dorson"
|
||||
msgstr "Malsukcesis 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 enigilo malkovrita"
|
||||
msgstr "Nova eligilo malkovrita"
|
||||
|
||||
msgid "Couldn't commit pending frame to output"
|
||||
msgstr "Ne povis surmeti atendantan framon sur eligon"
|
||||
msgid "Could not add an output layout."
|
||||
msgstr "Ne eblis aldoni eligan aranĝon."
|
||||
|
||||
msgid "New keyboard detected"
|
||||
msgstr "Nova klavaro malkovrita"
|
||||
|
|
@ -130,14 +130,17 @@ 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 "Malsukesis krei servilan bildigilon"
|
||||
msgstr "Malsukcesis krei servilan bildigilon"
|
||||
|
||||
msgid "Failed to create allocator"
|
||||
msgstr "Malsukesis krei servilan asignilon"
|
||||
msgstr "Malsukcesis krei servilan asignilon"
|
||||
|
||||
msgid "Failed to start backend"
|
||||
msgstr "Malsukesis startigi servilan dorson"
|
||||
msgstr "Malsukcesis startigi servilan dorson"
|
||||
|
||||
msgid "Running Wayland compositor on Wayland display"
|
||||
msgstr "Plenumas Wayland-komponilon sur Wayland-ekrano"
|
||||
|
|
@ -148,8 +151,11 @@ msgstr "Ekrano finigita"
|
|||
msgid "Keyboard focus is now on surface"
|
||||
msgstr "Klavara fokuso nun estas sur surfaco"
|
||||
|
||||
msgid "Focusing next view"
|
||||
msgstr "Fokusas la sekvan vidon"
|
||||
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"
|
||||
|
||||
#, fuzzy
|
||||
#~ msgid "Failed to create wlr_backend"
|
||||
|
|
|
|||
|
|
@ -1,11 +1,14 @@
|
|||
i18n = import('i18n')
|
||||
add_project_arguments('-DGETTEXT_PACKAGE="' + meson.project_name().to_lower() + '"',
|
||||
'-DLOCALEDIR="' + get_option('prefix') / get_option('localedir') + '"',
|
||||
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']
|
||||
'-DUSE_NLS=1', language: 'c')
|
||||
|
||||
i18n = import('i18n', required: false)
|
||||
if i18n.found()
|
||||
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: 2022-12-06 22:27-0500\n"
|
||||
"POT-Creation-Date: 2024-01-25 21:21-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 "Couldn't commit pending frame to output"
|
||||
msgid "Could not add an output layout."
|
||||
msgstr ""
|
||||
|
||||
msgid "New keyboard detected"
|
||||
|
|
@ -122,6 +122,9 @@ msgstr ""
|
|||
msgid "Failed to connect to a Wayland display"
|
||||
msgstr ""
|
||||
|
||||
msgid "Failed to get an event loop"
|
||||
msgstr ""
|
||||
|
||||
msgid "Failed to create renderer"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -140,5 +143,5 @@ msgstr ""
|
|||
msgid "Keyboard focus is now on surface"
|
||||
msgstr ""
|
||||
|
||||
msgid "Focusing next view"
|
||||
msgid "Focusing next toplevel"
|
||||
msgstr ""
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
wl_protocol_dir = wayland_protos.get_variable(pkgconfig: 'pkgdatadir')
|
||||
|
||||
wayland_scanner = find_program('wayland-scanner', version: '>= 1.15')
|
||||
wayland_scanner_dep = dependency('wayland-scanner', version: '>=1.15')
|
||||
wayland_scanner = find_program(wayland_scanner_dep.get_variable(pkgconfig: 'wayland_scanner'))
|
||||
|
||||
wayland_scanner_server = generator(
|
||||
wayland_scanner,
|
||||
|
|
@ -24,19 +25,18 @@ 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-screencopy-unstable-v1.xml',
|
||||
'wlr-layer-shell-unstable-v1.xml',
|
||||
'wlr-screencopy-unstable-v1.xml',
|
||||
]
|
||||
|
||||
client_protocols = [
|
||||
[wl_protocol_dir, 'unstable/idle-inhibit/idle-inhibit-unstable-v1.xml'],
|
||||
'wlr-screencopy-unstable-v1.xml',
|
||||
'wlr-layer-shell-unstable-v1.xml',
|
||||
'wlr-screencopy-unstable-v1.xml',
|
||||
]
|
||||
|
||||
wl_protos_src = []
|
||||
|
|
|
|||
BIN
screenshots/emptydesktop.png
Normal file
BIN
screenshots/emptydesktop.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 763 KiB |
BIN
screenshots/play.png
Normal file
BIN
screenshots/play.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 749 KiB |
BIN
screenshots/work.png
Normal file
BIN
screenshots/work.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 142 KiB |
|
|
@ -1,3 +1,4 @@
|
|||
#include <libxml/parser.h>
|
||||
#include <libxml/xpath.h>
|
||||
#include <libxml/xpathInternals.h>
|
||||
|
||||
|
|
@ -151,6 +152,7 @@ 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."));
|
||||
|
|
@ -166,15 +168,35 @@ 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:keyboardLayout", ctxt) != NULL;
|
||||
|
||||
config->keyboard_layout.use_config = parse_xpath_expr("//ob:keyboard//ob:xkb", ctxt) != NULL;
|
||||
if (config->keyboard_layout.use_config) {
|
||||
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->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->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,6 +27,26 @@ 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_view = NULL;
|
||||
server->grabbed_toplevel = NULL;
|
||||
}
|
||||
|
||||
static void process_cursor_move(struct wb_server *server) {
|
||||
/* 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);
|
||||
/* 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);
|
||||
}
|
||||
}
|
||||
|
||||
static void process_cursor_resize(struct wb_server *server) {
|
||||
struct wb_view *view = server->grabbed_view;
|
||||
struct wb_toplevel *toplevel = server->grabbed_toplevel;
|
||||
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,16 +50,20 @@ 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(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);
|
||||
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);
|
||||
|
||||
int new_width = new_right - new_left;
|
||||
int new_height = new_bottom - new_top;
|
||||
wlr_xdg_toplevel_set_size(view->xdg_toplevel, new_width, new_height);
|
||||
wlr_xdg_toplevel_set_size(toplevel->xdg_toplevel, new_width, new_height);
|
||||
}
|
||||
|
||||
static void process_cursor_motion(struct wb_server *server, uint32_t time) {
|
||||
|
|
@ -72,18 +76,18 @@ static void process_cursor_motion(struct wb_server *server, uint32_t time) {
|
|||
return;
|
||||
}
|
||||
|
||||
/* Otherwise, find the view under the pointer and send the event along. */
|
||||
/* Otherwise, find the toplevel 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_view *view = get_view_at(server,
|
||||
struct wb_toplevel *toplevel = get_toplevel_at(server,
|
||||
server->cursor->cursor->x, server->cursor->cursor->y, &surface, &sx, &sy);
|
||||
if (!view) {
|
||||
/* If there's no view under the cursor, set the cursor image to a
|
||||
if (!toplevel) {
|
||||
/* If there's no toplevel 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 views. */
|
||||
wlr_xcursor_manager_set_cursor_image(
|
||||
server->cursor->xcursor_manager, "left_ptr", server->cursor->cursor);
|
||||
* around the screen, not over any toplevels. */
|
||||
wlr_cursor_set_xcursor(
|
||||
server->cursor->cursor, server->cursor->xcursor_manager, "default");
|
||||
}
|
||||
if (surface) {
|
||||
/*
|
||||
|
|
@ -134,14 +138,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_view *view = get_view_at(cursor->server,
|
||||
struct wb_toplevel *toplevel = get_toplevel_at(cursor->server,
|
||||
cursor->server->cursor->cursor->x, cursor->server->cursor->cursor->y, &surface, &sx, &sy);
|
||||
if (event->state == WLR_BUTTON_RELEASED) {
|
||||
if (event->state == WL_POINTER_BUTTON_STATE_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_view(view, surface);
|
||||
focus_toplevel(toplevel);
|
||||
}
|
||||
|
||||
wlr_idle_notifier_v1_notify_activity(cursor->server->idle_notifier, cursor->server->seat->seat);
|
||||
|
|
@ -156,7 +160,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->delta_discrete, event->source, event->relative_direction);
|
||||
}
|
||||
|
||||
static void handle_cursor_frame(struct wl_listener *listener, void *data) {
|
||||
|
|
@ -198,7 +202,6 @@ 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);
|
||||
|
|
@ -229,6 +232,14 @@ 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,9 +15,10 @@ 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_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);
|
||||
view->decoration = toplevel_decoration;
|
||||
struct wb_toplevel *toplevel = wl_container_of(decoration->server->toplevels.next, toplevel, link);
|
||||
if (toplevel->xdg_toplevel->base->initialized)
|
||||
wlr_xdg_toplevel_decoration_v1_set_mode(toplevel_decoration, WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE);
|
||||
toplevel->decoration = toplevel_decoration;
|
||||
}
|
||||
|
||||
static void handle_new_xdg_toplevel_decoration(struct wl_listener *listener, void *data) {
|
||||
|
|
@ -31,8 +32,6 @@ 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) {
|
||||
|
|
|
|||
41
waybox/idle.c
Normal file
41
waybox/idle.c
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
#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;
|
||||
}
|
||||
3
waybox/idle.h
Normal file
3
waybox/idle.h
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
#include "waybox/server.h"
|
||||
|
||||
bool create_idle_manager(struct wb_server *server);
|
||||
|
|
@ -53,6 +53,7 @@ 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);
|
||||
}
|
||||
|
|
@ -105,10 +106,13 @@ 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) {
|
||||
if (!surface->output || current_toplevel->xdg_toplevel->current.fullscreen) {
|
||||
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;
|
||||
|
|
@ -121,8 +125,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->mapped != surface->mapped) {
|
||||
surface->mapped = layer_surface->mapped;
|
||||
if (committed || layer_surface->surface->mapped != surface->mapped) {
|
||||
surface->mapped = layer_surface->surface->mapped;
|
||||
arrange_layers(surface->output);
|
||||
|
||||
struct timespec now;
|
||||
|
|
@ -170,9 +174,12 @@ static void handle_unmap(struct wl_listener *listener, void *data) {
|
|||
seat_set_focus_layer(seat, NULL);
|
||||
}
|
||||
|
||||
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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -181,6 +188,10 @@ 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);
|
||||
|
|
@ -197,6 +208,7 @@ 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);
|
||||
}
|
||||
|
||||
|
|
@ -305,9 +317,10 @@ 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);
|
||||
struct wb_view *view =
|
||||
wl_container_of(server->views.next, view, link);
|
||||
layer_surface->output = get_active_output(view);
|
||||
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_output *output = layer_surface->output->data;
|
||||
|
||||
|
|
@ -343,9 +356,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->events.map, &surface->map);
|
||||
wl_signal_add(&layer_surface->surface->events.map, &surface->map);
|
||||
surface->unmap.notify = handle_unmap;
|
||||
wl_signal_add(&layer_surface->events.unmap, &surface->unmap);
|
||||
wl_signal_add(&layer_surface->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;
|
||||
|
|
@ -360,7 +373,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);
|
||||
server->layer_shell = wlr_layer_shell_v1_create(server->wl_display, 4);
|
||||
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>
|
||||
|
||||
struct wb_server;
|
||||
#include "waybox/output.h"
|
||||
|
||||
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. I'm not sure of the
|
||||
* difference between restarting and reconfiguring.
|
||||
/* Openbox uses SIGUSR1 to restart and SIGUSR2 to reconfigure.
|
||||
* What's the difference?
|
||||
*/
|
||||
case SIGUSR2:
|
||||
deinit_config(server.config);
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ wb_src = files(
|
|||
'config.c',
|
||||
'cursor.c',
|
||||
'decoration.c',
|
||||
'idle.c',
|
||||
'layer_shell.c',
|
||||
'main.c',
|
||||
'output.c',
|
||||
|
|
@ -11,6 +12,8 @@ wb_src = files(
|
|||
)
|
||||
|
||||
wb_dep = [
|
||||
libevdev,
|
||||
libinput,
|
||||
libxml2,
|
||||
wayland_server,
|
||||
wlroots,
|
||||
|
|
@ -24,4 +27,5 @@ executable(
|
|||
dependencies: [wb_dep, wlr_protos],
|
||||
install: true,
|
||||
install_dir: get_option('prefix') / get_option('libexecdir'),
|
||||
link_args: ['-Wl,-lm'],
|
||||
)
|
||||
|
|
|
|||
110
waybox/output.c
110
waybox/output.c
|
|
@ -10,14 +10,32 @@ 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 ! 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
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/* Render the scene if needed and commit the output */
|
||||
wlr_scene_output_commit(scene_output);
|
||||
wlr_scene_output_commit(scene_output, NULL);
|
||||
|
||||
/* This lets the client know that we've displayed that frame and it can
|
||||
* prepare another one now if it likes. */
|
||||
|
|
@ -26,11 +44,39 @@ 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 *);
|
||||
|
|
@ -55,29 +101,23 @@ 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);
|
||||
wlr_output_set_mode(wlr_output, mode);
|
||||
wlr_output_enable(wlr_output, true);
|
||||
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);
|
||||
|
||||
if (!wlr_output_commit(wlr_output)) {
|
||||
wlr_log_errno(WLR_ERROR, "%s", _("Couldn't commit pending frame to output"));
|
||||
return;
|
||||
}
|
||||
if (mode != NULL) {
|
||||
wlr_output_state_set_mode(&state, mode);
|
||||
}
|
||||
|
||||
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++) {
|
||||
|
|
@ -91,6 +131,8 @@ 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
|
||||
|
|
@ -101,5 +143,29 @@ 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).
|
||||
*/
|
||||
wlr_output_layout_add_auto(server->output_layout, wlr_output);
|
||||
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,50 +1,58 @@
|
|||
#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_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 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 cycle_views(struct wb_server *server) {
|
||||
/* Cycle to the next view */
|
||||
if (wl_list_length(&server->views) < 1) {
|
||||
static void cycle_toplevels(struct wb_server *server) {
|
||||
/* Cycle to the next toplevel */
|
||||
if (wl_list_length(&server->toplevels) < 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
struct wb_toplevel *current_toplevel = wl_container_of(
|
||||
server->toplevels.prev, current_toplevel, link);
|
||||
deiconify_toplevel(current_toplevel);
|
||||
focus_toplevel(current_toplevel);
|
||||
|
||||
/* Move the current view to the beginning of the list */
|
||||
wl_list_remove(¤t_view->link);
|
||||
wl_list_insert(&server->views, ¤t_view->link);
|
||||
/* Move the current toplevel to the beginning of the list */
|
||||
wl_list_remove(¤t_toplevel->link);
|
||||
wl_list_insert(&server->toplevels, ¤t_toplevel->link);
|
||||
}
|
||||
|
||||
static void cycle_views_reverse(struct wb_server *server) {
|
||||
/* Cycle to the previous view */
|
||||
if (wl_list_length(&server->views) < 1) {
|
||||
static void cycle_toplevels_reverse(struct wb_server *server) {
|
||||
/* Cycle to the previous toplevel */
|
||||
if (wl_list_length(&server->toplevels) < 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
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);
|
||||
|
||||
/* 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);
|
||||
/* 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);
|
||||
}
|
||||
|
||||
static bool handle_keybinding(struct wb_server *server, xkb_keysym_t sym, uint32_t modifiers) {
|
||||
|
|
@ -56,14 +64,25 @@ 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_views(server);
|
||||
cycle_toplevels(server);
|
||||
else if (modifiers & (WLR_MODIFIER_ALT|WLR_MODIFIER_SHIFT) &&
|
||||
sym == XKB_KEY_Tab)
|
||||
cycle_views_reverse(server);
|
||||
cycle_toplevels_reverse(server);
|
||||
else if (sym == XKB_KEY_Escape && modifiers & WLR_MODIFIER_CTRL)
|
||||
wl_display_terminate(server->wl_display);
|
||||
else
|
||||
|
|
@ -75,14 +94,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_views(server);
|
||||
cycle_toplevels(server);
|
||||
if (key_binding->action & ACTION_PREVIOUS_WINDOW)
|
||||
cycle_views_reverse(server);
|
||||
cycle_toplevels_reverse(server);
|
||||
if (key_binding->action & ACTION_CLOSE) {
|
||||
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);
|
||||
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);
|
||||
}
|
||||
if (key_binding->action & ACTION_EXECUTE) {
|
||||
if (fork() == 0) {
|
||||
|
|
@ -90,34 +109,38 @@ static bool handle_keybinding(struct wb_server *server, xkb_keysym_t sym, uint32
|
|||
}
|
||||
}
|
||||
if (key_binding->action & ACTION_TOGGLE_MAXIMIZE) {
|
||||
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);
|
||||
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);
|
||||
}
|
||||
if (key_binding->action & ACTION_ICONIFY) {
|
||||
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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
if (key_binding->action & ACTION_SHADE) {
|
||||
struct wb_view *view = wl_container_of(server->views.next, view, link);
|
||||
if (view->scene_tree->node.enabled) {
|
||||
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 wlr_box geo_box;
|
||||
wlr_xdg_surface_get_geometry(view->xdg_toplevel->base, &geo_box);
|
||||
int decoration_height = MAX(geo_box.y - view->geometry.y, TITLEBAR_HEIGHT);
|
||||
wlr_xdg_surface_get_geometry(toplevel->xdg_toplevel->base, &geo_box);
|
||||
#endif
|
||||
int decoration_height = MAX(geo_box.y - toplevel->geometry.y, TITLEBAR_HEIGHT);
|
||||
|
||||
view->previous_geometry = view->geometry;
|
||||
wlr_xdg_toplevel_set_size(view->xdg_toplevel,
|
||||
view->geometry.width, decoration_height);
|
||||
toplevel->previous_geometry = toplevel->geometry;
|
||||
wlr_xdg_toplevel_set_size(toplevel->xdg_toplevel,
|
||||
toplevel->geometry.width, decoration_height);
|
||||
}
|
||||
}
|
||||
if (key_binding->action & ACTION_UNSHADE) {
|
||||
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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
if (key_binding->action & ACTION_RECONFIGURE) {
|
||||
|
|
@ -250,6 +273,113 @@ 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);
|
||||
|
|
@ -260,7 +390,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);
|
||||
wlr_cursor_attach_input_device(server->cursor->cursor, device);
|
||||
handle_new_pointer(server, device);
|
||||
break;
|
||||
default:
|
||||
wlr_log(WLR_INFO, "%s: %s", _("Unsupported input device detected"), device->name);
|
||||
|
|
@ -293,7 +423,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,5 +1,13 @@
|
|||
#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
|
||||
|
|
@ -10,15 +18,17 @@ 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. */
|
||||
#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
|
||||
server->backend = wlr_backend_autocreate(server->wl_event_loop, &server->session);
|
||||
if (server->backend == NULL) {
|
||||
wlr_log(WLR_ERROR, "%s", _("Failed to create backend"));
|
||||
return false;
|
||||
|
|
@ -46,10 +56,10 @@ bool wb_create_backend(struct wb_server* server) {
|
|||
return false;
|
||||
}
|
||||
|
||||
server->compositor = wlr_compositor_create(server->wl_display,
|
||||
server->renderer);
|
||||
server->compositor =
|
||||
wlr_compositor_create(server->wl_display, 5, server->renderer);
|
||||
server->subcompositor = wlr_subcompositor_create(server->wl_display);
|
||||
server->output_layout = wlr_output_layout_create();
|
||||
server->output_layout = wlr_output_layout_create(server->wl_display);
|
||||
server->seat = wb_seat_create(server);
|
||||
server->cursor = wb_cursor_create(server);
|
||||
|
||||
|
|
@ -61,10 +71,7 @@ bool wb_create_backend(struct wb_server* server) {
|
|||
|
||||
bool wb_start_server(struct wb_server* server) {
|
||||
init_config(server);
|
||||
wl_list_init(&server->outputs);
|
||||
|
||||
server->new_output.notify = new_output_notify;
|
||||
wl_signal_add(&server->backend->events.new_output, &server->new_output);
|
||||
init_output(server);
|
||||
|
||||
/* Create a scene graph. This is a wlroots abstraction that handles all
|
||||
* rendering and damage tracking. All the compositor author needs to do
|
||||
|
|
@ -73,7 +80,8 @@ bool wb_start_server(struct wb_server* server) {
|
|||
* necessary.
|
||||
*/
|
||||
server->scene = wlr_scene_create();
|
||||
wlr_scene_attach_output_layout(server->scene, server->output_layout);
|
||||
server->scene_layout =
|
||||
wlr_scene_attach_output_layout(server->scene, server->output_layout);
|
||||
|
||||
const char *socket = wl_display_add_socket_auto(server->wl_display);
|
||||
if (!socket) {
|
||||
|
|
@ -91,23 +99,38 @@ 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_gamma_control_manager_v1_create(server->wl_display);
|
||||
wlr_screencopy_manager_v1_create(server->wl_display);
|
||||
server->idle_notifier = wlr_idle_notifier_v1_create(server->wl_display);
|
||||
|
||||
wlr_data_control_manager_v1_create(server->wl_display);
|
||||
wlr_data_device_manager_create(server->wl_display);
|
||||
wl_list_init(&server->views);
|
||||
|
||||
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);
|
||||
|
||||
wl_list_init(&server->toplevels);
|
||||
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 Drew
|
||||
* DeVault's article:
|
||||
*
|
||||
* for application windows. For more detail on shells, refer to
|
||||
* 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;
|
||||
}
|
||||
|
||||
|
|
@ -116,9 +139,27 @@ 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);
|
||||
wl_display_destroy(server->wl_display);
|
||||
wb_seat_destroy(server->seat);
|
||||
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);
|
||||
|
||||
wlr_log(WLR_INFO, "%s", _("Display destroyed"));
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
#include "idle.h"
|
||||
#include "waybox/xdg_shell.h"
|
||||
|
||||
struct wb_view *get_view_at(
|
||||
struct wb_toplevel *get_toplevel_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_view. */
|
||||
* surface in the surface tree of a wb_toplevel. */
|
||||
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) {
|
||||
|
|
@ -13,13 +14,13 @@ struct wb_view *get_view_at(
|
|||
}
|
||||
struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node);
|
||||
struct wlr_scene_surface *scene_surface =
|
||||
wlr_scene_surface_from_buffer(scene_buffer);
|
||||
wlr_scene_surface_try_from_buffer(scene_buffer);
|
||||
if (!scene_surface) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*surface = scene_surface->surface;
|
||||
/* Find the node corresponding to the wb_view at the root of this
|
||||
/* Find the node corresponding to the wb_toplevel 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) {
|
||||
|
|
@ -28,62 +29,67 @@ struct wb_view *get_view_at(
|
|||
return tree->node.data;
|
||||
}
|
||||
|
||||
void focus_view(struct wb_view *view, struct wlr_surface *surface) {
|
||||
void focus_toplevel(struct wb_toplevel *toplevel) {
|
||||
/* Note: this function only deals with keyboard focus. */
|
||||
if (view == NULL || surface == NULL || !wlr_surface_is_xdg_surface(surface)) {
|
||||
if (toplevel == NULL || toplevel->xdg_toplevel->base->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct wlr_xdg_surface *xdg_surface = wlr_xdg_surface_from_wlr_surface(surface);
|
||||
if (xdg_surface)
|
||||
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)
|
||||
wlr_log(WLR_INFO, "%s: %s", _("Keyboard focus is now on surface"),
|
||||
xdg_surface->toplevel->app_id);
|
||||
|
||||
struct wb_server *server = view->server;
|
||||
struct wb_server *server = toplevel->server;
|
||||
if (server->seat->focused_layer != NULL) {
|
||||
/* If a layer is focused, don't focus a toplevel. */
|
||||
return;
|
||||
}
|
||||
struct wlr_seat *seat = server->seat->seat;
|
||||
struct wlr_surface *prev_surface = seat->keyboard_state.focused_surface;
|
||||
if (prev_surface == surface) {
|
||||
/* Don't re-focus an already focused surface. */
|
||||
/* Don't focus a surface that's already focused. */
|
||||
return;
|
||||
}
|
||||
if (prev_surface && wlr_surface_is_xdg_surface(prev_surface)) {
|
||||
if (prev_surface != NULL) {
|
||||
/*
|
||||
* 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_surface *previous =
|
||||
wlr_xdg_surface_from_wlr_surface(prev_surface);
|
||||
wlr_xdg_toplevel_set_activated(previous->toplevel, false);
|
||||
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);
|
||||
}
|
||||
}
|
||||
/* Move the view to the front */
|
||||
if (!server->seat->focused_layer) {
|
||||
wlr_scene_node_raise_to_top(&view->scene_tree->node);
|
||||
}
|
||||
wl_list_remove(&view->link);
|
||||
wl_list_insert(&server->views, &view->link);
|
||||
/* 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);
|
||||
/* Activate the new surface */
|
||||
wlr_xdg_toplevel_set_activated(view->xdg_toplevel, true);
|
||||
wlr_xdg_toplevel_set_activated(toplevel->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, view->xdg_toplevel->base->surface);
|
||||
seat_focus_surface(server->seat, surface);
|
||||
}
|
||||
|
||||
struct wlr_output *get_active_output(struct wb_view *view) {
|
||||
struct wlr_output *get_active_output(struct wb_toplevel *toplevel) {
|
||||
double closest_x, closest_y;
|
||||
struct wlr_output *output = NULL;
|
||||
wlr_output_layout_closest_point(view->server->output_layout, output,
|
||||
view->geometry.x + view->geometry.width / 2,
|
||||
view->geometry.y + view->geometry.height / 2,
|
||||
wlr_output_layout_closest_point(toplevel->server->output_layout, output,
|
||||
toplevel->geometry.x + toplevel->geometry.width / 2,
|
||||
toplevel->geometry.y + toplevel->geometry.height / 2,
|
||||
&closest_x, &closest_y);
|
||||
return wlr_output_layout_output_at(view->server->output_layout, closest_x, closest_y);
|
||||
return wlr_output_layout_output_at(toplevel->server->output_layout, closest_x, closest_y);
|
||||
}
|
||||
|
||||
static struct wlr_box get_usable_area(struct wb_view *view) {
|
||||
struct wlr_output *output = get_active_output(view);
|
||||
static struct wlr_box get_usable_area(struct wb_toplevel *toplevel) {
|
||||
struct wlr_output *output = get_active_output(toplevel);
|
||||
struct wlr_box usable_area = {0};
|
||||
wlr_output_effective_resolution(output, &usable_area.width, &usable_area.height);
|
||||
return usable_area;
|
||||
|
|
@ -91,89 +97,155 @@ static struct wlr_box get_usable_area(struct wb_view *view) {
|
|||
|
||||
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_view *view = wl_container_of(listener, view, map);
|
||||
if (view->xdg_toplevel->base->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL)
|
||||
struct wb_toplevel *toplevel = wl_container_of(listener, toplevel, map);
|
||||
if (toplevel->xdg_toplevel->base->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL)
|
||||
return;
|
||||
|
||||
struct wb_config *config = view->server->config;
|
||||
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 wlr_box geo_box = {0};
|
||||
struct wlr_box usable_area = get_usable_area(view);
|
||||
wlr_xdg_surface_get_geometry(view->xdg_toplevel->base, &geo_box);
|
||||
wlr_xdg_surface_get_geometry(toplevel->xdg_toplevel->base, &geo_box);
|
||||
#endif
|
||||
|
||||
if (config) {
|
||||
view->geometry.height = MIN(geo_box.height,
|
||||
toplevel->geometry.height = MIN(geo_box.height,
|
||||
usable_area.height - config->margins.top - config->margins.bottom);
|
||||
view->geometry.width = MIN(geo_box.width,
|
||||
toplevel->geometry.width = MIN(geo_box.width,
|
||||
usable_area.width - config->margins.left - config->margins.right);
|
||||
view->geometry.x = config->margins.left;
|
||||
view->geometry.y = config->margins.top;
|
||||
toplevel->geometry.x = config->margins.left;
|
||||
toplevel->geometry.y = config->margins.top;
|
||||
} else {
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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_xdg_toplevel_set_size(toplevel->xdg_toplevel,
|
||||
toplevel->geometry.width, toplevel->geometry.height);
|
||||
focus_toplevel(toplevel);
|
||||
|
||||
wlr_scene_node_set_position(&view->scene_tree->node,
|
||||
view->geometry.x, view->geometry.y);
|
||||
wlr_scene_node_set_position(&toplevel->scene_tree->node,
|
||||
toplevel->geometry.x, toplevel->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_view *view = wl_container_of(listener, view, unmap);
|
||||
if (view->xdg_toplevel->base->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL)
|
||||
struct wb_toplevel *toplevel = wl_container_of(listener, toplevel, unmap);
|
||||
if (toplevel->xdg_toplevel->base->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL)
|
||||
return;
|
||||
reset_cursor_mode(view->server);
|
||||
reset_cursor_mode(toplevel->server);
|
||||
|
||||
/* 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);
|
||||
/* 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);
|
||||
}
|
||||
}
|
||||
|
||||
static void xdg_toplevel_destroy(struct wl_listener *listener, void *data) {
|
||||
/* Called when the surface is destroyed and should never be shown again. */
|
||||
struct wb_view *view = wl_container_of(listener, view, destroy);
|
||||
/* Called when the xdg_toplevel is destroyed and should never be shown again. */
|
||||
struct wb_toplevel *toplevel = wl_container_of(listener, toplevel, destroy);
|
||||
|
||||
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);
|
||||
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);
|
||||
|
||||
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->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);
|
||||
|
||||
free(view);
|
||||
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);
|
||||
}
|
||||
|
||||
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. 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);
|
||||
* 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);
|
||||
}
|
||||
|
||||
static void xdg_toplevel_request_maximize(struct wl_listener *listener, void *data) {
|
||||
|
|
@ -181,85 +253,83 @@ 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_view *view = wl_container_of(listener, view, request_maximize);
|
||||
struct wlr_box usable_area = get_usable_area(view);
|
||||
struct wb_toplevel *toplevel = wl_container_of(listener, toplevel, request_maximize);
|
||||
struct wlr_box usable_area = get_usable_area(toplevel);
|
||||
|
||||
bool is_maximized = view->xdg_toplevel->current.maximized;
|
||||
bool is_maximized = toplevel->xdg_toplevel->current.maximized;
|
||||
if (!is_maximized) {
|
||||
struct wb_config *config = view->server->config;
|
||||
view->previous_geometry = view->geometry;
|
||||
struct wb_config *config = toplevel->server->config;
|
||||
toplevel->previous_geometry = toplevel->geometry;
|
||||
if (config) {
|
||||
view->geometry.x = config->margins.left;
|
||||
view->geometry.y = config->margins.top;
|
||||
toplevel->geometry.x = config->margins.left;
|
||||
toplevel->geometry.y = config->margins.top;
|
||||
usable_area.height -= config->margins.top + config->margins.bottom;
|
||||
usable_area.width -= config->margins.left + config->margins.right;
|
||||
} else {
|
||||
view->geometry.x = 0;
|
||||
view->geometry.y = 0;
|
||||
toplevel->geometry.x = 0;
|
||||
toplevel->geometry.y = 0;
|
||||
}
|
||||
} else {
|
||||
usable_area = view->previous_geometry;
|
||||
view->geometry.x = view->previous_geometry.x;
|
||||
view->geometry.y = view->previous_geometry.y;
|
||||
usable_area = toplevel->previous_geometry;
|
||||
toplevel->geometry.x = toplevel->previous_geometry.x;
|
||||
toplevel->geometry.y = toplevel->previous_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);
|
||||
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);
|
||||
}
|
||||
|
||||
static void xdg_toplevel_request_minimize(struct wl_listener *listener, void *data) {
|
||||
struct wb_view *view = wl_container_of(listener, view, request_minimize);
|
||||
bool minimize_requested = view->xdg_toplevel->requested.minimized;
|
||||
struct wb_toplevel *toplevel = wl_container_of(listener, toplevel, request_minimize);
|
||||
bool minimize_requested = toplevel->xdg_toplevel->requested.minimized;
|
||||
if (minimize_requested) {
|
||||
view->previous_geometry = view->geometry;
|
||||
view->geometry.y = -view->geometry.height;
|
||||
toplevel->previous_geometry = toplevel->geometry;
|
||||
toplevel->geometry.y = -toplevel->geometry.height;
|
||||
|
||||
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);
|
||||
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);
|
||||
else
|
||||
focus_view(view, view->xdg_toplevel->base->surface);
|
||||
focus_toplevel(toplevel);
|
||||
} else {
|
||||
view->geometry = view->previous_geometry;
|
||||
toplevel->geometry = toplevel->previous_geometry;
|
||||
}
|
||||
|
||||
wlr_scene_node_set_position(&view->scene_tree->node,
|
||||
view->geometry.x, view->geometry.y);
|
||||
wlr_scene_node_set_position(&toplevel->scene_tree->node,
|
||||
toplevel->geometry.x, toplevel->geometry.y);
|
||||
}
|
||||
|
||||
static void begin_interactive(struct wb_view *view,
|
||||
static void begin_interactive(struct wb_toplevel *toplevel,
|
||||
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 = 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;
|
||||
struct wb_server *server = toplevel->server;
|
||||
server->grabbed_toplevel = toplevel;
|
||||
server->cursor->cursor_mode = mode;
|
||||
|
||||
if (mode == WB_CURSOR_MOVE) {
|
||||
server->grab_x = server->cursor->cursor->x - view->geometry.x;
|
||||
server->grab_y = server->cursor->cursor->y - view->geometry.y;
|
||||
server->grab_x = server->cursor->cursor->x - toplevel->geometry.x;
|
||||
server->grab_y = server->cursor->cursor->y - toplevel->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(view->xdg_toplevel->base, &geo_box);
|
||||
wlr_xdg_surface_get_geometry(toplevel->xdg_toplevel->base, &geo_box);
|
||||
#endif
|
||||
|
||||
double border_x = (view->geometry.x + geo_box.x) +
|
||||
double border_x = (toplevel->geometry.x + geo_box.x) +
|
||||
((edges & WLR_EDGE_RIGHT) ? geo_box.width : 0);
|
||||
double border_y = (view->geometry.y + geo_box.y) +
|
||||
double border_y = (toplevel->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 += view->geometry.x;
|
||||
server->grab_geo_box.y += view->geometry.y;
|
||||
server->grab_geo_box.x += toplevel->geometry.x;
|
||||
server->grab_geo_box.y += toplevel->geometry.y;
|
||||
|
||||
server->resize_edges = edges;
|
||||
}
|
||||
|
|
@ -270,8 +340,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_view *view = wl_container_of(listener, view, request_move);
|
||||
begin_interactive(view, WB_CURSOR_MOVE, 0);
|
||||
struct wb_toplevel *toplevel = wl_container_of(listener, toplevel, request_move);
|
||||
begin_interactive(toplevel, WB_CURSOR_MOVE, 0);
|
||||
}
|
||||
|
||||
static void xdg_toplevel_request_resize(
|
||||
|
|
@ -280,100 +350,135 @@ 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_view *view = wl_container_of(listener, view, request_resize);
|
||||
begin_interactive(view, WB_CURSOR_RESIZE, event->edges);
|
||||
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);
|
||||
}
|
||||
|
||||
static void handle_new_popup(struct wl_listener *listener, void *data) {
|
||||
struct wlr_xdg_popup *popup = data;
|
||||
struct wb_view *view = wl_container_of(listener, view, new_popup);
|
||||
struct wb_toplevel *toplevel = wl_container_of(listener, toplevel, new_popup);
|
||||
|
||||
struct wlr_output *wlr_output = wlr_output_layout_output_at(
|
||||
view->server->output_layout,
|
||||
view->geometry.x + popup->current.geometry.x,
|
||||
view->geometry.y + popup->current.geometry.y);
|
||||
toplevel->server->output_layout,
|
||||
toplevel->geometry.x + popup->current.geometry.x,
|
||||
toplevel->geometry.y + popup->current.geometry.y);
|
||||
|
||||
if (!wlr_output) return;
|
||||
if (!wlr_output) {
|
||||
return;
|
||||
}
|
||||
struct wb_output *output = wlr_output->data;
|
||||
|
||||
int top_margin = (view->server->config) ?
|
||||
view->server->config->margins.top : 0;
|
||||
int top_margin = (toplevel->server->config) ?
|
||||
toplevel->server->config->margins.top : 0;
|
||||
struct wlr_box output_toplevel_box = {
|
||||
.x = output->geometry.x - view->geometry.x,
|
||||
.y = output->geometry.y - view->geometry.y,
|
||||
.x = output->geometry.x - toplevel->geometry.x,
|
||||
.y = output->geometry.y - toplevel->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_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;
|
||||
|
||||
static void handle_new_xdg_popup(struct wl_listener *listener, void *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. */
|
||||
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_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) {
|
||||
struct wlr_scene_tree *parent_tree = parent->data;
|
||||
xdg_surface->data = wlr_scene_xdg_surface_create(
|
||||
parent_tree, xdg_surface);
|
||||
xdg_popup->base->data = wlr_scene_xdg_surface_create(
|
||||
parent_tree, xdg_popup->base);
|
||||
}
|
||||
/* The scene graph doesn't currently unconstrain popups, so keep going */
|
||||
/* return; */
|
||||
}
|
||||
if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_NONE)
|
||||
return;
|
||||
|
||||
/* 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;
|
||||
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);
|
||||
|
||||
/* Listen to the various events it can emit */
|
||||
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->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);
|
||||
|
||||
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->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;
|
||||
|
||||
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);
|
||||
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);
|
||||
|
||||
wl_list_insert(&view->server->views, &view->link);
|
||||
}
|
||||
wl_list_insert(&toplevel->server->toplevels, &toplevel->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_surface.notify = handle_new_xdg_surface;
|
||||
wl_signal_add(&server->xdg_shell->events.new_surface, &server->new_xdg_surface);
|
||||
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);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue