feat: wofi

This commit is contained in:
Elias Renman
2023-11-30 00:46:04 +01:00
parent 209b1d686f
commit 09aefa9c00
5 changed files with 270 additions and 0 deletions

32
wofi/config Normal file
View File

@@ -0,0 +1,32 @@
# hide_scroll=true
# show=drun
# width=35%
# lines=15
# line_wrap=word
# term=alacritty
# allow_markup=true
# always_parse_args=true
# show_all=true
# print_command=true
# layer=overlay
# allow_images=true
# insensitive=true
# prompt=
# image_size=15
# display_generic=true
# location=center
width=700
height=350
show=drun
prompt=Search...
filter_rate=100
allow_markup=true
no_actions=true
halign=fill
orientation=vertical
content_halign=fill
insensitive=true
allow_images=true
image_size=30
gtk_dark=true

9
wofi/config.screenshot Normal file
View File

@@ -0,0 +1,9 @@
hide_search=true
hide_scroll=true
insensitive=true
width=1
show=dmenu
lines=5
location=centre
x=870
y=455

61
wofi/style.css Normal file
View File

@@ -0,0 +1,61 @@
/*
Arc-Dark Color Scheme
*/
/* @define-color highlight #e30b9b; */
@define-color highlight #f7768e;
@define-color base1 rgba(0,0,0,0.2);
@define-color base2 rgba(0,0,0,0.8);
@define-color base3 rgba(0,0,0,0.1);
*{
font-family: JetBrains Mono Nerd Font;
}
window {
/* border: 1px solid @highlight; */
border-radius: 18px;
/* background: rgba(0,0,0,0); */
color: #bb9af7;
position: relative;
background: linear-gradient(to bottom right, #73daca, #f7768e);
padding: 1px;
}
#input {
margin-bottom: 15px;
padding:3px;
border-radius: 5px;
border:none;
outline:none;
/* color: white; */
color: #bb9af7;
/* background: @base1; */
background-color: #0a0a0a;
}
#inner-box {
/* background: @base3; */
}
#outer-box {
margin: 3px;
padding:15px;
background-color: #0a0a0a;
border-radius: 8px;
}
#text {
padding: 5px;
}
/* #entry:nth-child(even) { */
/* background-color: @base1; */
/* } */
#entry:selected {
color: black;
background-color: @highlight;
border:none;
outline:none;
}

49
wofi/style.widgets.css Normal file
View File

@@ -0,0 +1,49 @@
/*
Arc-Dark Color Scheme
*/
@define-color highlight #f7768e;
@define-color base1 rgba(0,0,0,0.6);
@define-color base2 rgba(0,0,0,0.8);
@define-color base3 rgba(0,0,0,0.1);
*{
font-family: JetBrainsMono;
/* height: fit-content; */
}
#window {
border: 2px solid @highlight;
border-radius: 4px;
background-color: rgba(0,0,0,0);
color: #bb9af7;
padding: 5px;
}
#inner-box {
background-color: @base1;
/* background-color: @base2; */
}
#outer-box {
/*margin: 5px;
padding:5px 10px;
*/
border-radius: 4px;
margin-top: -32px;
}
#text {
padding: 5px;
/* color: white; */
}
#entry:nth-child(even) {
/* background-color: pink; */
}
#entry:selected {
color: black;
background-color: @highlight;
}

119
wofi/windows.py Executable file
View File

@@ -0,0 +1,119 @@
#!/bin/python3
import json
import subprocess
from argparse import ArgumentParser
ENTER = "\n"
def get_windows():
command = "swaymsg -t get_tree"
process = subprocess.Popen(
command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE
)
process = subprocess.Popen(
command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE
)
data = json.loads(process.communicate()[0])
# Select outputs that are active
windows = []
for output in data["nodes"]:
# The scratchpad (under __i3) is not supported
if output.get("name") != "__i3" and output.get("type") == "output":
workspaces = output.get("nodes", [])
for ws in workspaces:
if ws.get("type") == "workspace":
windows.extend(extract_nodes_iterative(ws))
return windows
# Extracts all windows from a sway workspace json object
def extract_nodes_iterative(workspace):
all_nodes = []
floating_nodes = workspace.get("floating_nodes", [])
for floating_node in floating_nodes:
all_nodes.append(floating_node)
nodes = workspace.get("nodes", [])
for node in nodes:
# Leaf node
if not node.get("nodes"):
all_nodes.append(node)
# Nested node, handled iterative
else:
for inner_node in node.get("nodes"):
nodes.append(inner_node)
return all_nodes
# Returns an array of all windows
def parse_windows(windows):
return [window.get("name") for window in windows]
# Returns a newline seperated UFT-8 encoded string of all windows for wofi
def build_wofi_string(windows):
return ENTER.join(windows).encode("UTF-8")
# Executes wofi with the given input string
def show_wofi(windows):
command = 'wofi -c ~/.config/wofi/menu -s ~/.config/wofi/style.css -p "Windows: " -d -i --hide-scroll'
process = subprocess.Popen(
command, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE
)
return process.communicate(input=windows)[0]
# Returns the sway window id of the window that was selected by the user inside wofi
def parse_id(windows, parsed_windows, selected):
if not selected:
return None
else:
selected = (selected.decode("UTF-8"))[:-1] # Remove new line character
window_index = int(
parsed_windows.index(selected)
) # Get index of selected window in the parsed window array
return str(
windows[window_index].get("id")
) # Get sway window id based on the index
# Switches the focus to the given id
def switch_window(id):
command = "swaymsg [con_id={}] focus".format(id)
process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE)
process.communicate()[0]
# Entry point
if __name__ == "__main__":
parser = ArgumentParser(description="Wofi based window switcher")
windows = get_windows()
parsed_windows = parse_windows(windows)
wofi_string = build_wofi_string(parsed_windows)
selected = show_wofi(wofi_string)
# Otherwise no point in running
if selected:
selected_id = parse_id(windows, parsed_windows, selected)
switch_window(selected_id)