swaywm

64 readers
1 users here now

dedicated to the Sway window manager, a drop-in replacement for the i3 window manager, but for Wayland instead of X11.

founded 2 months ago
MODERATORS
1
2
 
 

Author @ExtremeDullard@lemmy.sdf.org

If you're trying to use another Sway session inside your own Sway session (either a nested Sway session or a remote Sway session) or you use an application that uses the same shortcuts as Sway, then you'd like Sway to "get out of the way" and let those shortcuts through.

You can do that by defining a passthrough mode in ~/.config/sway/config:

# Passthrough mode
mode "passthru" {
        bindsym $mod+Escape mode "default"
}
bindsym $mod+Escape mode "passthru"

When you hit Mod+Escape, it enters the "passthru" mode, in which the same binding, Mod+Escape, is the only binding that does anything at all - and that is returning to normal mode. All other normal bindings in that mode will be ignored by Sway and will reach either your nested / remote Sway desktop or your application that expects them.

Here's an example of Sway / application conflict:

In my Sway, Ctrl+Shift+e is set to brings up the emoji picker (rofimoji if you're curious). But Ctrl+Shift+e is also the shortcut to bring up the Developer Tools pane in Firefox. So when I infrequently need the latter, I enable the passthrough mode first.

Of course, when you enter the passthrough mode, passthru appears in your (s)waybar. You'd think it makes it obvious that you're in a special mode, but it's actually really easy to enter the passthrough mode and forget about it. Therefore, if no bindings seem to work properly anymore, remember to look down ๐Ÿ˜ƒ

Also, if you ever need to enter the passthrough mode in a nested / remote Sway session - like for example if you need the Firefox Developer Tools pane in a remote Sway session, then you'll have to define a different binding to switch passthrough on and off, either in the local session or in the remote session, otherwise they're going to clash.

But it happens very rarely for me, so I didn't bother: all my machines use the same passthrough mode binding in i3 and Sway and I've never run into the problem. But it can happen.

3
 
 

Author @ExtremeDullard@lemmy.sdf.org How to Xephyr in Sway: running nested Sway sessions as other users

If you come from i3, you might be missing Xephyr or Xnest-like functionalities in Sway - that is, the ability to run another desktop session as another user inside your current desktop.

In i3, I log into my test desktops all the time without leaving my main desktop, and that's something I really miss in Sway / Wayland. So I spent some time putting a script together to do that seamlessly in Sway too. You may find it useful.

In fairness, Sway - or more precisely wlroots - can already run nested natively without any modification. You can test that by opening a terminal and typing sway in it: you'll get a second, identical desktop inside your current one.

The problems come when you want to run another user's desktop within yours, for the following reasons:

  1. Wayland makes the incredibly restrictive assumption that the Wayland compositor and clients always run as the same user, and therefore puts the Wayland socket in the user's XDG_RUNTIME_DIR (usually /run/user/<userid>/).

    That's a problem if you want a Wayland application running as another user to connect to that Wayland socket, because other users can't access your XDG_RUNTIME_DIR, and you really don't want to open it up to other users just to be able to access the socket because it's full of sensitive files pertaining to your running session.

    Moreover, since XDG_RUNTIME_DIR is usually a mounted tmpfs, you can't symlink the socket outside the directory either because sockets can't be symlinked across filesystems in Linux.

    In other words, again, Wayland makes it extra difficult to do something simple for no good reason.

  2. Sway requires a full login environment - and particularly XDG_RUNTIME_DIR - to be set in the environment, which usually implies that it should also be setup and mounted in /run/user.

    Unfortunately, you can't just sudo into the account you want to run your nested Sway desktop as and start Sway because PAM explicitely doesn't set XDG when su'ing or sudo'ing, and doing it manually is a recipe for problems.

To solve 1., we use a clever piece of software called filterway, which conveniently solves two problems:

  • It acts as a sort of gateway: it connects to a Wayland socket on one side, creates its own socket on the other side and links the two. This functionality is used to expose the primary Wayland socket securely without compromising XDG_RUNTIME_DIR.

  • It replaces the app ID of the top Wayland client that connects to it - which is really its primary party trick. In this use case, that's useful to track the state of the nested Sway session in the primary session's tree.

There is no package for filterway so you have to clone the Github repo, build the binary and install it somewhere in your PATH. Fortunately, it's just a small utility so building it is really simple.

To solve 2., we use systemd-run to setup the target user's environment as if it was a full login, then run Sway with the correct setup to connect to the primary Wayland display's socket.

The following script ties everything together: it starts filterway, starts Sway as the other user, then takes care of stopping Sway and filterway and cleaning things up when the session is closed. Alll you need is to add your name to the sudoers.

#!/bin/sh

# Make sure we run in Wayland
if [ ! "${WAYLAND_DISPLAY}" ]; then
  echo "$0 must be run in a Wayland environment"
  exit
fi

# Make sure we run in Sway
if [ ! "${SWAYSOCK}" ]; then
  echo "$0 must be run in a Sway session"
  exit
fi

# Pass the nested session's user as first argument
if [ ! "$1" ]; then
  echo "Usage: $0 username"
  exit
fi
NUSER=$1

# Make sure the nested session's user exists
# Replace "password" with "passwd" here, change due to Lemmy posting glitch
if ! grep -q "^${NUSER}:" /etc/password; then
  echo "User ${NUSER} doesn't exist"
  exit
fi

# Make sure filterway is installed
if ! which -s filterway; then
  echo "filterway not found in the PATH."
  echo "Please install if from https://github.com/andrewbaxter/filterway"
  exit
fi

# Get a unique ID for this nested session
UUID=$(uuidgen)

# Figure out where our Wayland socket is and make sure it exists
if echo ${WAYLAND_DISPLAY} | grep -q "^/"; then 
  RSOCKPATH=${WAYLAND_DISPLAY}
else
  RSOCKPATH=${XDG_RUNTIME_DIR}/${WAYLAND_DISPLAY}
fi
if ! [ -S ${RSOCKPATH} ]; then 
  echo "Socket file ${RSOCKPATH} for this Wayland display \"${WAYLAND_DISPLAY}\" doesn't exist!?"
  echo "Giving up..."
  exit
fi

# Unique nested session's Wayland display name
NWDISPLAY=wayland-nested-${UUID}

# Unique filespec for the nested session's Wayland socket
NSOCKPATH=/tmp/${NWDISPLAY}

# Unique filespec for the nested Sway socket
NSWAYSOCK=/tmp/sway-nested-ipc.${NUSER}.${UUID}.sock

# Run filterway in the background to expose our private Wayland socket in ${XDG_RUNTIME_DIR} (which is most likely a tmpfs-mounted directory that can't be shared outside without compromising the private $(XDG_RUNTIME_DIR}) and to rename the nested session's app ID
rm -f ${NSOCKPATH}
filterway --upstream ${RSOCKPATH} --downstream ${NSOCKPATH} --app-id "Nested Sway - ${NUSER} ($UUID)" &
FILTERWAY_PID=$!

# Wait until filterway has created the socket and associated lock files for the nested session
RETRY=3
while [ ${RETRY} -gt 0 ] && ! ( [ -S ${NSOCKPATH} ] && [ -f ${NSOCKPATH}.lock ] ); do
  sleep 1
  RETRY=$((RETRY-1))
done

# If filterway somehow didn't start, try to kill it and clean up its files for good measure
if [ ${RETRY} = 0 ]; then
  kill ${FILTERWAY_PID}
  rm -f ${NSOCKPATH} ${NSOCKPATH}.lock
fi

# Fix up the permissions of the socket and associated lock files for the nested session so it's only accessible to the owner
chmod 600 ${NSOCKPATH} ${NSOCKPATH}.lock

# Become root
sudo -s -- << EOF

  # Give the socket and associated lock files to the nested session's user
  chown ${NUSER}: ${NSOCKPATH} ${NSOCKPATH}.lock

  # Remove stale symlinks then start Sway as that user in a new session in the background
  systemd-run --pipe --machine ${NUSER}@ --setenv=WAYLAND_DISPLAY=${NWDISPLAY} --setenv=SWAYSOCK=${NSWAYSOCK} --user /bin/sh -c '[ "\${XDG_RUNTIME_DIR}" ] && (find \${XDG_RUNTIME_DIR} -maxdepth 1 -name "wayland-nested-*" -xtype l -exec rm -f {} \; || true) && rm -f \${XDG_RUNTIME_DIR}/${NWDISPLAY} && ln -s ${NSOCKPATH} \${XDG_RUNTIME_DIR}/${NWDISPLAY} && sway' &

  # Wait for the Sway container to appear within 3 seconds after starting Sway, then wait for it to disappear for more than 5 seconds afterwards
  export SWAYSOCK=${SWAYSOCK}
  COUNTDOWN=3
  while [ \${COUNTDOWN} -gt 0 ]; do
    if swaymsg -t get_tree | grep -q 'app_id.*${UUID}'; then
      COUNTDOWN=5
    fi
    sleep 1
    COUNTDOWN=\$((COUNTDOWN-1))
  done

  # Stop the nested Sway
  SWAYSOCK=${NSWAYSOCK} swaymsg exit

  # Kill filterway
  kill ${FILTERWAY_PID}

  # Remove the filterway socket and socket lock files
  rm -f ${NUSER}: ${NSOCKPATH} ${NSOCKPATH}.lock

EOF

I called it nest_sway.sh and it lives in my ~/scripts directory, which is in my PATH. Whenever I want to start a desktop as another user within my desktop, I simply type

$ nest_sway.sh <username>

and hey-presto, the desktop appears. Just like with Xephy.

4
 
 

Author @ExtremeDullard@lemmy.sdf.org

To configure several keyboard input layouts, it's quite simple - especially if you come from i3: no need for ibus or fcitx (both bring their own problems in Sway/Wayland).

All you have to do is edit your keyboard input preferences right in your Sway config file. For example:

input type:keyboard {
        xkb_layout us,fr,fi,es
        xkb_options grp:alt_space_toggle,lv3:ralt_switch
}

This sets up 4 keyboard layout (US, French, Finnish and Spanish) and Alt+space as the shortcut to cycle through them.

There's a plethora of XKB layouts and options. You can see them all by doing man xkeyboard-config. Pick the ones you want.

Then if you use Waybar, you can set it up so that it displays the layout currently in use with the sway/language module. For instance, put this in your Waybar config file:

"sway/language": {                                                           
    "format": "{flag}",                                                      
    "tooltip": false,                                                        
    "on-click": "swaymsg input type:keyboard xkb_switch_layout next",        
    "on-click-right": "swaymsg input type:keyboard xkb_switch_layout prev"   
},                                                                         

This shows the current layout as the corresponding country flag and configures left- and right-click to cycle through the layouts when clicking on the flag.

Finally, if you like to type emojis and you don't want to remember the unicode numbers (which you can enter in hexadecimal with Ctrl+Shift+u in case you didn't know), install rofimoji and wtype: rofimoji is a very nice Rofi-based emoji picker, and wtype is the Wayland typer it needs to inject the emojis through the Wayland virtual keyboard:

Then add a key binding in your Sway config file to call the emoji picker. I personally use Ctrl+Shift+e:

bindsym Ctrl+Shift+e exec rofimoji

Final twist: if you use several input layouts and you display the current layout in Waybar, you'll notice that wtype (called by rofimoji) makes the Waybar language icon disappear.

That's because there's a bug in the Waybar Sway language module: it doesn't mess up the keyboard input, it just makes the icon disappear until you change the layout, and then it comes back.

So here's a workaroud, since nobody seems to be in a hurry to fix this bug ๐Ÿ˜ƒ:

  • In .local/bin, create a wtype file with the following content:
#!/bin/sh
/usr/bin/wtype $@ && swaymsg input type:keyboard xkb_switch_layout next && swaymsg input type:keyboard xkb_switch_layout prev

What this script does is call the real wtype, then switch the keyboard layout back and forth to make the Waybar language icon reappear.

  • Add .local/bin to your PATH environment variable BEFORE /usr/bin, so your wtype wrapper is called by rofimoji in lieu of the real wtype. To do that in Sway:

    • Add the modified PATH to ~/.config, e.g.:
    PATH=$HOME/.local/bin:$PATH
    
    • call systemctl --user daemon-reload
    • Log out and back in

    (if you wonder why you have to do all this to set a simple environment variable in Sway, see here)

After that, the language icon should stay put when you enter emojis.

5
 
 

Author @ExtremeDullard@lemmy.sdf.org

The following two key bindings will add simple screen recording hotkeys:

  • Mod+Shift+Alt+F11 records a region or the full screen to ~/Videos/screen_capture.mp4
  • Mod+Shift+Alt+F12 records a region or the full screen to ~/Videos/screen_capture.mp4 with the audio output.
bindsym $mod+Shift+Alt+F11 exec pkill wf-recorder && notify-send "Video captured in ~/Videos/screen_capture.mp4" || wf-recorder -y -g "$(slurp)" -f ~/Videos/screen_capture.mp4
bindsym $mod+Shift+Alt+F12 exec pkill wf-recorder && notify-send "Video with audio output captured in ~/Videos/screen_capture.mp4" || wf-recorder -y -g "$(slurp)" -f ~/Videos/screen_capture.mp4 -a=alsa_output.platform-analog-sound.stereo-fallback.monitor

Hit the key combo, select the whole screen or the region you want to record, then hit the key combo again to stop the recording.

You need to install wf-recorder, slurp and notify-send for those key bindings to work.

In addition, for the Mod+Shift+Alt+F12 binding, you need Pulseaudio or Pipewire to capture the audio sink's monitor, and you probably need to find out what name it has on your system and replace the name after -a=

To figure out the name of the monitor, simply list the audio sources on your system:

$ pactl list sources | grep Name
	Name: alsa_output.platform-analog-sound.stereo-fallback.monitor
	Name: alsa_input.platform-analog-sound.stereo-fallback

Naturally, you can use any other source you want - your microphone for example if you want to talk over the screen capture.

6
 
 

Author: @ExtremeDullard@lemmy.sdf.org

KDEConnect is a fantastic tool to integrate your cellphone with your desktop. But while it generally works well, it has a few issues in Sway.

Here's a quick overview of how to make it work correctly.

First of all, you need to start the KDEConnect daemon when the session opens. No biggie, it's just a regular config line:

exec QT_QPA_PLATFORM=xcb kdeconnectd

The KDEConnect runs silently in the background. You can tell if it's working properly by trying to list devices it sees around on the network:

$ kdeconnect-cli -l
- Fairphone4:  (paired and reachable)
- lloyd@november: _24be2fd9_7c47_47de_a454_618bb6e0e016_ (reachable)
- rosco@alfa: _508af911_1c83_4b3b_af01_7e2ca78c776a_ (reachable)
3 devices found

Then you want to run the KDEConnect indicator in the system tray. You can try to run the KDEConnect-supplied indicator program from the Sway config file by adding this line after starting the daemon:

exec kdeconnect-indicator

If it works for you, great! You're done with that.

Unfortunately, I find that it doesn't play so nicely with Waybar. It works 75% of the time, but it regularly fails to show up in my system tray - as in, it runs okay, but the icon is missing, which kind of defeats the purpose.

If this happens to you too, you're in luck: a kind soul has written a simple Python replacement that works great. You can download it here:

https://github.com/juanramoncastan/xfconnect-indicator/tree/main

No need to clone the repo, you just need the Python script here and the two icons here and here.

  • Copy xfconnect-indicator.py in /usr/local/bin
  • Copy xfconnect-icon.svg and xfconnect-icon-disconnected.svg in /usr/share/icons

Then replace the kdeconnect-indicator startup line above in your Sway config file with:

exec --no-startup-id (sleep 1 && xfconnect-indicator.py) || (sleep 1 && xfconnect-indicator.py) || (sleep 1 && xfconnect-indicator.py) || (sleep 1 && xfconnect-indicator.py) || (sleep 1 && xfconnect-indicator.py)

Why this convoluted line you ask?

Because xfconnect-indicator.py fails with an exception if the KDEConnect daemon isn't running instead of retrying to connect. This ensures Sway tries to start it 5 times with a 1 second delay when it starts, giving the KDEConnect daemon time to start on its own.

The xfconnect-indicator icon should appear in the system tray reliably, and the functionalities are identical to kdeconnect-indicator.

Finally, arguably the most useful bit of KDEConnect won't necessarily work quite right for you: the sftp plugin, aka the "Browse remote" option in the indicator, that lets you browse your cellphone's files with the file manager.

In KDE, Gnome or Cinnamon, this is usually well integrated (particularly in KDE naturally): when you click on "Browse remote", Dolphin, Nautilus or Nemo appears and you can browse your cellphone's storage.

In Sway, not so much.

Most likely, if you hit "Browse remote", your default browser will open with a funky-looking kdeconnect://<uuid> URI that it won't know what to do with.

To fix this problem, create this shell script somewhere in your home directoy. I usually put all my scripts in ~/scripts and I called this one nautilus_kdeconnect_browse_remote.sh. It opens Nautilus but any file manager should work. Feel free to do your own thing instead ๐Ÿ˜ƒ

#!/bin/bash
DIR=/run/user/$(id -u)/$(echo $1 | sed -e "s/kdeconnect:\/\///")/storage/emulated/0
nautilus --new-window $DIR

This script extracts the UUID from the kdeconnect:// URI and uses it to work out the mountpoint / sub-directory corresponding to your cellphone's internal storage, where KDEConnect has mounted the SSHFS filesystem - usually /run/user/<your userid>/<uuid>/.

You can test it by calling it with the funky URI in your browser as argument: Nautilus should open at the right directory and you should see your cellphone's files.

Then you need to make a .desktop file for the shell script, so xdg knows what to do with it. To do this, create the file ~/.local/share/applications/nautilus_kdeconnect_browse_remote.desktop with the following content:

[Desktop Entry]
Name=nautilus_kdeconnect_browse_remote.sh
Comment=Open Nautilus at the right location when passed a kdeconnect://<uuid> URI
Exec=/home/ppc/scripts/nautilus_kdeconnect_browse_remote.sh
Type=Application
MimeType=x-scheme-handler/kdeconnect

You can validate that the .desktop file is correct by doing:

desktop-file-validate ~/.local/share/applications/nautilus_kdeconnect_browse_remote.desktop

Finally, register your .desktop file as the default handler for the kdeconnect:// scheme by adding this to your ~/.config/mimeapps.list (create the file if it doesn't exist):

[Default Applications]                                                           
x-scheme-handler/kdeconnect=nautilus_kdeconnect_browse_remote.desktop;

Check that it all works by trying to open the funky URI with xdg-open - which is really what KDEConnect does:

$ xdg-open kdeconnect://02bb6f9f_5907_4b00_ee73_8d439a9e6451

Nautilus should open at the correct directory now, instead of the browser:

And of course, the same should happen when you hit "Browse remote" too.

7
 
 

Author: @ExtremeDullard@lemmy.sdf.org

Flameshot is arguably the best Linux screenshot utility out there. Unfortunately, it has a really annoying issue: copy-to-clipboard doesn't work in Wayland. Everything else works just great, but only being able to save screenshots to files totally breaks my workflow.

Fortunately, there's a way around this: Flameshot also has a --raw command line argument that makes it send whatever it captures to stdout. That means it's really easy to pipe it to wl-copy to send the content to the Wayland clipboard.

Here are a couple of key bindings that exploit this and make Flameshot work great in Sway:

bindsym $mod+Alt+F11 exec bash -c 'flameshot gui --raw 2> >(grep aborted || notify-send "Screenshot copied to the clipboard") | wl-copy'
bindsym $mod+Alt+F12 exec flameshot screen --raw | wl-copy && notify-send 'Screeshot copied to the clipboard'

Those command do require notify-send to be installed, which is supplied by different packages depending on your particular Linux distro. Debian has it in the libnotify-bin package.

If you don't want to install it, you can strip the fancy scripting and just define those two key bindings instead:

bindsym $mod+Alt+F11 exec flameshot gui --raw | wl-copy
bindsym $mod+Alt+F12 exec flameshot screen --raw | wl-copy

They work just as well, but they don't notify you when the screenshot is copied to the clipboard or aborted, which can be disconcerting.

8
 
 

Author: @ExtremeDullard@lemmy.sdf.org

The typical Sway config file has a key binding to pop a nagging message to exit the session, like this one:

bindsym $mod+Shift+e exec swaynag -t warning -m 'You pressed the exit shortcut. Do you really want to exit sway? This will end your Wayland session.' -b 'Yes, exit sway' 'swaymsg exit'

But it's annoying because if you hit mod+shift+e accidentally, you have to go and click on the X to dismiss the nag. Weirdly, it happens to me a lot more than it should.

Here's a slightly jazzed up keybinding you might like:

bindsym $mod+Shift+e exec pkill swaynag || (swaynag -t warning -m 'You pressed the exit shortcut. Do you really want to exit sway? This will end your Wayland session.' -b 'Yes, exit sway' 'swaymsg exit' & sleep 5 && pkill swaynag)

This adds two things:

  • If you hit mod+shift+e accidentally, hit it again to dismiss the nag.
  • Wait 5 seconds and the nag will disappear on its own anyway.
9
 
 

Author: @ExtremeDullard@lemmy.sdf.org

If you're new to Wayland as I am, you haven't failed to be frustrated by the greeter / Sway not sourcing any of the usual X or profile configuration files. In i3, you export your variables in .profile and they're set everywhere for the whole session. Not so in Sway.

That means if you have a custom PATH or some exported variable you would like to define session-wide - setting QT_QPA_PLATFORMTHEME so all QT apps use the correct theme in Gnome for instance - you can't. Not the usual way anyway.

Those variables are set if you run a terminal with the shell in login mode, if they're defined in /etc/profile or .profile, but not if you run the program directly in Sway, such as wofi / rofi for example, or any program that needs an environment variable that isn't set.

Here's how to set environment variables for the entire session in Sway:

  • Choose a greeter that understands systemd's environment.d. Unfortunately, there aren't very many. GDM and Plasma are the only two that I know of that do.

  • Define your environment variables in ~/.config/environment.d/envvars.conf. You can define them the usual way like in profile, including extending variables like $PATH, e.g.:

    QT_QPA_PLATFORMTHEME=qt5ct
    PATH=$PATH:/usr/games:~/scripts
    
  • Either reboot for the changes to take effect, or run systemctl --user daemon-reload to get systemd to parse your file again, then log out and back in as with Xorg.

Unfortunately, simply logging out and back in without informing systemd of your changes isn't enough - which is why you need to reboot if you don't do the daemon-reload command.

That's it!

Not too obvious, and not great. But in fairness, it's no more confusing than the mess of shell and X configuration files that existed before systemd and Wayland. It's just that systemd and Wayland are an entirely different complete trainwreck that takes getting used to ๐Ÿ˜ƒ

10
 
 

OC by @ExtremeDullard@lemmy.sdf.org

This is Sway running on my ARM64 laptop. It took some effort to get everything going just right in Wayland but now that it\s all setup, I really like it.

The one thing I miss in Sway / Waybar is the ability to bind mouse and scroll events to commands when they happen in the empty parts of the bar like in i3 / i3blocks. If anybody knows how to achieve that, I'd be extremely grateful!

11
12
 
 
13