Migration to sway #5

Merged
aniva merged 3 commits from sway into main 2023-09-23 14:46:11 -07:00
9 changed files with 350 additions and 164 deletions

92
README-Wayland.org Normal file
View File

@ -0,0 +1,92 @@
#+title: Wayland
Install [[https://wiki.archlinux.org/title/wayland][wayland]]: ~wayland~, ~xorg-xwayland~
* Login Manager
The login manager is not managed by this configuration but mentioned here since
it interacts with the desktop environment. For ~hyprland~, ~sddm~ is
recommended.
- ~sddm~: Enable ~sddm.service~
A note about themes: The themes must be placed in ~/usr/share/sddm/themes~.
Then in ~/etc/sddm.conf~, enable the relevant theme. By default the breeze
theme comes with ~plasma-workspace~ which is very bloated to install, so
consider some of the alternative themes.
* Fonts
- ~otf-font-awesome~: Needed for ~waybar~ to render icons
- Noto Sans/Serif: System font
* Status Bar and Tray
- ~waybar~: Status bar, use ~waybar-hyprland-git~ AUR repo to enable clicking!
- ~eww-wayland~: Another status bar, requires ~socat~ to listen for hyprland events.
* Sway
This is one choice of a compositor.
- ~swayfx~: Window manager
- ~python-i3ipc~: Enables inactive window opacity scripts
** Wallpaper
Use ~multibg-sway~, which assigns a different wallpaper to each workspace and
does not crash. The wallpapers directory ~~/.config/sway/wallpapers~ needs to be setup in this way:
#+begin_src
wallpapers
├─ eDP-1
│ ├─ _default.jpg
│ ├─ 1.jpg
│ ├─ 2.png
│ └─ browser.jpg
└─ HDMI-A-1
├─ 1.jpg
└─ 3.png
#+end_src
where the output information can be obtained from ~swaymsg -t get_outputs~.
Supposedly does not work with ~hypr~.
* Hyprland
This is another choice of a compositor.
Note: Setup does not work with NVIDIA GPU without some tweaks.
- [[https://wiki.archlinux.org/title/Hyprland][hyprland]]: window manager
Until [[https://github.com/elkowar/eww/issues/111][tray support]] has been added to ~eww~ in a stable manner, tray will be handled with waybar.
- ~hyprpaper~: Wallpaper engine
The command to set a wallpaper:
~hyprctl hyprpaper wallpaper "$DISPLAY,$FILE"~
The command for changing keyboard layouts is handled by ~fcitx5~.
* Utilities
- [[https://github.com/Horus645/swww][swww]]: Alternate wallpaper engine
Note that ~~/.config/hypr/wallpapers~ must have jpeg files ~{1..8}.jpg~. A
handy command can be used crop and resize images:
#+begin_src bash
convert $IN \
-resize 3840x2160^ \
-gravity center \
-extent 3840x2160 \
$OUT
#+end_src
- ~swaync~: Notification server
- ~wofi~: finding programs, drop in replacement for ~rofi~
- ~grimblast~: Screenshot engine
- ~dolphin~: File explorer
- ~swaylock-effects~: A simple lockscreen
- ~wl-clipboard~: Provides copying
- ~blueman~: Bluetooth connector
** Configuration
- ~lxappearance~: Used to configure GTK3 themes
- ~nwg-look~: Configures cursor
- ~wev~: Wayland event interceptor useful for determining keybinds

View File

@ -50,70 +50,6 @@ systemctl start --user mpd
- ~neofetch~: Screenfetch - ~neofetch~: Screenfetch
- ~macchina~ (aur): Another screenfetch - ~macchina~ (aur): Another screenfetch
* Hyprland Desktop Environment
** Login Manager
The login manager is not managed by this configuration but mentioned here since
it interacts with the desktop environment. For ~hyprland~, ~sddm~ is
recommended.
- ~sddm~: Enable ~sddm.service~
A note about themes: The themes must be placed in ~/usr/share/sddm/themes~.
Then in ~/etc/sddm.conf~, enable the relevant theme. By default the breeze
theme comes with ~plasma-workspace~ which is very bloated to install, so
consider some of the alternative themes.
** Fonts
- ~otf-font-awesome~: Needed for ~waybar~ to render icons
- Noto Sans/Serif: System font
** Hyprland
Note: Setup does not work with NVIDIA GPU without some tweaks.
- [[https://wiki.archlinux.org/title/wayland][wayland]]: display manager: ~wayland~, ~xorg-xwayland~
- [[https://wiki.archlinux.org/title/Hyprland][hyprland]]: window manager
- ~waybar~: Status bar, use ~waybar-hyprland-git~ AUR repo to enable clicking!
- ~eww-wayland~: Another status bar, requires ~socat~ to listen for hyprland events.
Until [[https://github.com/elkowar/eww/issues/111][tray support]] has been added to ~eww~ in a stable manner, tray will be handled with waybar.
- ~hyprpaper~: Wallpaper engine
The command to set a wallpaper:
~hyprctl hyprpaper wallpaper "$DISPLAY,$FILE"~
- [[https://github.com/Horus645/swww][swww]]: Alternate wallpaper engine
Note that ~~/.config/hypr/wallpapers~ must have jpeg files ~{1..8}.jpg~. A
handy command can be used crop and resize images:
#+begin_src bash
convert $IN \
-resize 3840x2160^ \
-gravity center \
-extent 3840x2160 \
$OUT
#+end_src
- ~swaync~: Notification server
The command for changing keyboard layouts is handled by ~fcitx5~.
** Utilities
- ~wofi~: finding programs, drop in replacement for ~rofi~
- ~grimblast~: Screenshot engine
- ~dolphin~: File explorer
- ~swaylock-effects~: A simple lockscreen
- ~wl-clipboard~: Provides copying
- ~blueman~: Bluetooth connector
*** Configuration
- ~lxappearance~: Used to configure GTK3 themes
- ~nwg-look~: Configures cursor
- ~wev~: Wayland event interceptor useful for determining keybinds
* Dot Files * Dot Files
All the configurations which must appear as dot files are not included: All the configurations which must appear as dot files are not included:

View File

@ -25,47 +25,6 @@
;(widget_status) ;(widget_status)
)) ))
(defwidget widget_weather [orientation]
(box
:class "weather"
:orientation orientation
:space-evenly false
:valign "start"
:halign "center"
:spacing 10
;(box :class "moon" :orientation "v" moon) ; Not very stable
(box :class "temperature" :orientation orientation
(box :class "icon" "")
"${weather.current_condition[0].temp_C}"
(box :class "feelsLike" "${weather.current_condition[0].FeelsLikeC}")
)
(box :class "uvIndex" :orientation orientation
(box :class "icon" "")
"${weather.current_condition[0].uvIndex}")
(box :class "humidity" :orientation orientation
(box :class "icon" "")
"${weather.current_condition[0].humidity}"
)
(box :class "precip" :orientation orientation
(box :class "icon" "")
"${weather.current_condition[0].precipMM}"
)
(box :class "wind" :orientation orientation
(box :class "icon" "")
"${weather.current_condition[0].windspeedKmph}"
"${weather.current_condition[0].winddir16Point}"
)
(box :class "cloud" :orientation orientation
(box :class "icon" "")
"${weather.current_condition[0].cloudcover}"
)
))
(defpoll moon :initial "" :interval "180s"
"curl wttr.in/?format=%m")
(defpoll weather :initial "{\"current_condition\": [{\"cloudcover\": \"\"}]}" :interval "180s"
"curl wttr.in/?format=j1")
(defwidget widget_workspaces [] (defwidget widget_workspaces []
(box (box
:class "workspaces" :class "workspaces"
@ -83,6 +42,37 @@
"scripts/get-workspaces") "scripts/get-workspaces")
; Weather
(defwidget widget_weather [orientation]
(box
:class "weather"
:orientation orientation
:space-evenly false
:valign "start"
:halign "center"
:spacing 10
(button :onclick "scripts/popup weather" "W")
))
(defpoll weather_text :initial "" :interval "180s"
"curl --max-time 2 wttr.in")
(defwindow weather
:geometry (geometry :x "70px"
:y "50%"
:width "270px"
:height "60px")
(box weather_text))
(defwindow calendar
:geometry (geometry :x "70px"
:y "65%"
:width "270px"
:height "60px")
(cal))
(defwidget widget_clock [] (defwidget widget_clock []
(box (box
:class "clock" :class "clock"

View File

@ -6,81 +6,121 @@ Utility to generate the workspace buttons for eww bar widget.
Currently it fetches information from monitor 0. If all monitors have Currently it fetches information from monitor 0. If all monitors have
synchronised workspaces this should not be a problem. synchronised workspaces this should not be a problem.
""" """
import os, sys, socket, json import os, sys, socket, json, subprocess
from typing import Optional
WORKSPACE_ICONS = [ WORKSPACE_ICONS = [
(1, '☱'), (1, "☱"),
(2, '☲'), (2, "☲"),
(3, '☳'), (3, "☳"),
(4, '☴'), (4, "☴"),
(5, '☵'), (5, "☵"),
(6, '☶'), (6, "☶"),
(7, '☷'), (7, "☷"),
(8, '☰'), (8, "☰"),
] ]
EXTRA_WORKSPACE_ICONS = [ EXTRA_WORKSPACE_ICONS = [
(0, '⚌'), (0, "⚌"),
(1, '⚍'), (1, "⚍"),
(2, '⚎'), (2, "⚎"),
(3, '⚏'), (3, "⚏"),
] ]
def get_workspace_info(): Workspaces = dict[int, bool]
workspaces = json.loads(os.popen('hyprctl workspaces -j').read()) def get_widgets(workspaces: Workspaces) -> str:
monitors = json.loads(os.popen('hyprctl monitors -j').read()) """
if not monitors: Create widget sexp from workspace information
print("No monitor found!", file=sys.stderr) """
return []
monitor, active = [(m['name'], m['activeWorkspace']['id'])
for m in monitors if m['id'] == 0][0]
workspaces = [(w['id'], w['id'] == active)
for w in workspaces
if w['monitor'] == monitor]
return workspaces
def get_widgets():
# get all workspace keys
workspaces = {k: v for k, v in get_workspace_info()}
def get_class(k): def get_class(k):
key = workspaces.get(k, None) key = workspaces.get(k, None)
if key is None: if key is None:
return 'inactive' return "inactive"
elif key: elif key:
return 'focused' return "focused"
else: else:
return 'active' return "active"
buttons = [ buttons = [
f'"id": "{k}", "text": "{icon}", "class": "{get_class(k)}"' f'"id": "{k}", "text": "{icon}", "class": "{get_class(k)}"'
for k, icon in WORKSPACE_ICONS for k, icon in WORKSPACE_ICONS
] ]
buttons = ', '.join(['{' + b + '}' for b in buttons]) buttons = ", ".join(["{" + b + "}" for b in buttons])
return '[' + buttons + ']' return "[" + buttons + "]"
def listen(): # Compositor specific information
def hypr_get_workspace_info() -> Workspaces:
workspaces = json.loads(os.popen("hyprctl workspaces -j").read())
monitors = json.loads(os.popen("hyprctl monitors -j").read())
if not monitors:
print("No monitor found!", file=sys.stderr)
return []
monitor, active = [
(m["name"], m["activeWorkspace"]["id"]) for m in monitors if m["id"] == 0
][0]
workspaces = {
w["id"]: w["id"] == active
for w in workspaces if w["monitor"] == monitor
}
return workspaces
def hypr_listen(socket_addr: str):
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
KEY = 'HYPRLAND_INSTANCE_SIGNATURE'
signature = os.environ.get(KEY, None)
if signature is None:
print("Hyprland variable uninitialised.", file=sys.stderr)
return
server_address = f"/tmp/hypr/{signature}/.socket2.sock"
try: try:
sock.connect(server_address) sock.connect(socket_addr)
except: except:
print(f"Could not connect to {server_address}", file=sys.stderr) print(f"Could not connect to {socket_addr}", file=sys.stderr)
raise raise
# The flush here is very important since python by default buffers! # The flush here is very important since python by default buffers!
print(get_widgets(), flush=True) workspace_info = hypr_get_workspace_info()
print(get_widgets(workspace_info), flush=True)
while sock: while sock:
data = sock.recv(1024) data = sock.recv(1024)
if b'workspace' in data: if b"workspace" in data:
print(get_widgets(), flush=True) workspace_info = hypr_get_workspace_info()
print(get_widgets(workspace_info), flush=True)
listen() def sway_get_workspace_info() -> Workspaces:
workspaces = json.loads(os.popen("swaymsg --raw -t get_workspaces").read())
# REVIEW: This has not been tested on a multi-monitor setup.
workspaces = {
int(w["num"]): w["focused"]
for w in workspaces
}
return workspaces
def sway_listen():
proc = subprocess.Popen(
["swaymsg", "-t", "subscribe", "-m", '["workspace"]'], stdout=subprocess.PIPE
)
workspace_info = sway_get_workspace_info()
print(get_widgets(workspace_info), flush=True)
while line := proc.stdout.readline():
# Not needed
info = json.loads(line)
workspace_info = sway_get_workspace_info()
print(get_widgets(workspace_info), flush=True)
def detect():
"""
Main entry point, detects the type of compositor used
"""
if signature := os.environ.get("HYPRLAND_INSTANCE_SIGNATURE", None):
socket_addr = f"/tmp/hypr/{signature}/.socket2.sock"
return hypr_listen(socket_addr)
if signature := os.environ.get("SWAYSOCK", None):
return sway_listen()
print("No compositor found.", file=sys.stderr)
return None
if __name__ == "__main__":
detect()

16
eww/bar/scripts/popup Executable file
View File

@ -0,0 +1,16 @@
#!/bin/sh
toggle_popup() {
LOCK="/tmp/eww-$1.lock"
if [[ ! -f "$LOCK" ]]; then
touch "$LOCK"
eww --config ~/.config/eww/bar open $1
else
eww --config ~/.config/eww/bar close $1
rm "$LOCK"
fi
}
if [ "$1" = weather ]; then
toggle_popup weather
fi

44
sway/config Normal file
View File

@ -0,0 +1,44 @@
# Terminal
set $term alacritty
# Launcher
set $menu wofi --show drun -I -G
set $lock swaylock
set $screenshot_full /usr/share/swayfx/scripts/grimshot copy screen
set $screenshot_area /usr/share/swayfx/scripts/grimshot copy area
xwayland enable
scratchpad_minimize disable
# Visual Effects
corner_radius 20
smart_corner_radius enable
blur on
blur_xray off
blur_passes 2
blur_radius 5
shadows on
shadows_on_csd off
shadow_blur_radius 20
shadow_color #0000007F
default_dim_inactive 0.0
dim_inactive_colors.unfocused #000000FF
dim_inactive_colors.urgent #900000FF
set $border 2
default_border pixel $border
default_floating_border pixel $border
for_window [app_id=".*"] gaps inner all set 5
for_window [app_id=".*"] gaps outer all set 15
for_window [app_id=".*"] opacity 0.85
for_window [app_id=__focused__] opacity 0.95
# Include keys
include ~/.config/sway/keys.conf
# Launching programs
include ~/.config/sway/launch.conf
# Include systemd fix
include /etc/sway/config.d/*

63
sway/keys.conf Normal file
View File

@ -0,0 +1,63 @@
set $mod Mod4
set $left h
set $down j
set $up k
set $right l
bindsym $mod+t exec $term
bindsym $mod+q kill
bindsym $mod+space exec $menu
bindsym $mod+semicolon exec $lock
bindsym $mod+Shift+c reload
bindsym Print exec $screenshot_area
bindsym Shift+Print exec $screenshot_full
# Drag floating windows by holding down $mod and left mouse button.
# Resize them with right mouse button + $mod.
# Despite the name, also works for non-floating windows.
# Change normal to inverse to use left mouse button for resizing and right
# mouse button for dragging.
floating_modifier $mod normal
bindsym $mod+f fullscreen
bindsym $mod+v floating toggle
# Move focus
bindsym $mod+$left focus left
bindsym $mod+$down focus down
bindsym $mod+$up focus up
bindsym $mod+$right focus right
# Or use $mod+[up|down|left|right]
bindsym $mod+Left focus left
bindsym $mod+Down focus down
bindsym $mod+Up focus up
bindsym $mod+Right focus right
# Move the focused window with the same, but add Shift
bindsym $mod+Shift+$left move left
bindsym $mod+Shift+$down move down
bindsym $mod+Shift+$up move up
bindsym $mod+Shift+$right move right
# Ditto, with arrow keys
bindsym $mod+Shift+Left move left
bindsym $mod+Shift+Down move down
bindsym $mod+Shift+Up move up
bindsym $mod+Shift+Right move right
bindsym $mod+1 workspace number 1
bindsym $mod+2 workspace number 2
bindsym $mod+3 workspace number 3
bindsym $mod+4 workspace number 4
bindsym $mod+5 workspace number 5
bindsym $mod+6 workspace number 6
bindsym $mod+7 workspace number 7
bindsym $mod+8 workspace number 8
# Move focused container to workspace
bindsym $mod+Shift+1 move container to workspace number 1; workspace number 1
bindsym $mod+Shift+2 move container to workspace number 2; workspace number 2
bindsym $mod+Shift+3 move container to workspace number 3; workspace number 3
bindsym $mod+Shift+4 move container to workspace number 4; workspace number 4
bindsym $mod+Shift+5 move container to workspace number 5; workspace number 5
bindsym $mod+Shift+6 move container to workspace number 6; workspace number 6
bindsym $mod+Shift+7 move container to workspace number 7; workspace number 7
bindsym $mod+Shift+8 move container to workspace number 8; workspace number 8

9
sway/launch.conf Normal file
View File

@ -0,0 +1,9 @@
exec /usr/share/swayfx/scripts/inactive-windows-transparency --opacity 0.8
exec_always eww --config ~/.config/eww/bar open bar
bar {
position top
swaybar_command waybar
}
exec_always multibg-sway ~/.config/sway/wallpapers
exec swaync
exec fcitx5

View File

@ -6,7 +6,9 @@
"margin": "0 15 0 5", "margin": "0 15 0 5",
"modules-left": [ "modules-left": [
//"wlr/workspaces", //"wlr/workspaces",
"hyprland/window"], "hyprland/window",
"sway/window"
],
"modules-center": ["mpd"], "modules-center": ["mpd"],
"modules-right": [ "modules-right": [
"tray", "tray",
@ -35,7 +37,9 @@
}, },
"hyprland/window": { "hyprland/window": {
"format": "<span color=\"#DDDDDD\" font-size=\"150%\"></span> {}", "format": "<span color=\"#DDDDDD\" font-size=\"150%\"></span> {}",
"separate-outputs": true },
"sway/window": {
"format": "<span color=\"#DDDDDD\" font-size=\"150%\"></span> {}",
}, },
"keyboard-state": { "keyboard-state": {
"numlock": true, "numlock": true,
@ -47,14 +51,6 @@
//"unlocked": "" //"unlocked": ""
} }
}, },
"hyprland/language": {
"format": "{}",
"format-en": "🇺🇸",
"format-fr": "🇨🇦",
"format-ja": "🇯🇵",
"tooltip-format": "{}",
"tooltip": true
},
"mpd": { "mpd": {
"format": "『{artist} - {album} - {title} 』<span font-size=\"60%\" font-family=\"monospace\">{stateIcon} ({elapsedTime:%M:%S}/{totalTime:%M:%S}) ⸨{songPosition}|{queueLength}⸩ {consumeIcon}{randomIcon}{repeatIcon}{singleIcon}</span>", "format": "『{artist} - {album} - {title} 』<span font-size=\"60%\" font-family=\"monospace\">{stateIcon} ({elapsedTime:%M:%S}/{totalTime:%M:%S}) ⸨{songPosition}|{queueLength}⸩ {consumeIcon}{randomIcon}{repeatIcon}{singleIcon}</span>",
"format-disconnected": "Disconnected", "format-disconnected": "Disconnected",