[yambar] Add custom sway module

Script module for sway that handles multi-monitor setups a little bit
better, and that shows current mode.
This commit is contained in:
Midgard 2022-09-01 15:01:01 +02:00
parent 1cd1dfe2e0
commit 1914e3f0db
Signed by untrusted user who does not match committer: midgard
GPG key ID: 511C112F1331BBB4
2 changed files with 226 additions and 20 deletions

View file

@ -75,27 +75,122 @@ bar:
spacing: 10 spacing: 10
left: left:
- i3: #- i3:
sort: ascending #sort: ascending
#content:
#"":
#map:
#default: {string: {text: "{name}", foreground: *col_fg_alt, margin: 7}}
#conditions:
#state == focused: {string: {text: "{name}", margin: 7}}
- script:
path: /home/midgard/.config/yambar/sway.py
anchors:
monitor_sep: &monitor_sep {string: {text: "|"}}
ws_common: &ws_common {left-margin: 7, right-margin: 7}
ws_default: &ws_default {foreground: *col_fg_alt, <<: *ws_common}
ws_focused: &ws_focused {foreground: *col_fg, <<: *ws_common}
ws_visible: &ws_visible {foreground: *col_visible_ws, <<: *ws_common}
content: content:
"": - list:
map: spacing: 0
tag: state items:
default: {string: {text: "{name}", foreground: *col_fg_alt, margin: 7}} - map:
values: default: {string: {text: "{ws0}", <<: *ws_default}}
"focused": {string: {text: "{name}", margin: 7}} conditions:
#current: ws0_state == unused: {empty: {}}
#list: ws0_state == focused: {string: {text: "{ws0}", <<: *ws_focused}}
#left-margin: 25 ws0_state == visible: {string: {text: "{ws0}", <<: *ws_visible}}
#spacing: 0 - map: {default: {empty: {}}, conditions: {ws1_new_monitor: *monitor_sep}}
#items: - map:
#- { string: {text: "{application}", foreground: *col_fg_alt}} default: {string: {text: "{ws1}", <<: *ws_default}}
#- map: conditions:
#tag: application ws1_state == unused: {empty: {}}
#default: { string: {text: ": ", foreground: *col_fg_alt}} ws1_state == focused: {string: {text: "{ws1}", <<: *ws_focused}}
#values: ws1_state == visible: {string: {text: "{ws1}", <<: *ws_visible}}
#"": {empty: {}} - map: {default: {empty: {}}, conditions: {ws2_new_monitor: *monitor_sep}}
#- { string: {text: "{title}", foreground: *col_fg_alt}} - map:
default: {string: {text: "{ws2}", <<: *ws_default}}
conditions:
ws2_state == unused: {empty: {}}
ws2_state == focused: {string: {text: "{ws2}", <<: *ws_focused}}
ws2_state == visible: {string: {text: "{ws2}", <<: *ws_visible}}
- map: {default: {empty: {}}, conditions: {ws3_new_monitor: *monitor_sep}}
- map:
default: {string: {text: "{ws3}", <<: *ws_default}}
conditions:
ws3_state == unused: {empty: {}}
ws3_state == focused: {string: {text: "{ws3}", <<: *ws_focused}}
ws3_state == visible: {string: {text: "{ws3}", <<: *ws_visible}}
- map: {default: {empty: {}}, conditions: {ws4_new_monitor: *monitor_sep}}
- map:
default: {string: {text: "{ws4}", <<: *ws_default}}
conditions:
ws4_state == unused: {empty: {}}
ws4_state == focused: {string: {text: "{ws4}", <<: *ws_focused}}
ws4_state == visible: {string: {text: "{ws4}", <<: *ws_visible}}
- map: {default: {empty: {}}, conditions: {ws5_new_monitor: *monitor_sep}}
- map:
default: {string: {text: "{ws5}", <<: *ws_default}}
conditions:
ws5_state == unused: {empty: {}}
ws5_state == focused: {string: {text: "{ws5}", <<: *ws_focused}}
ws5_state == visible: {string: {text: "{ws5}", <<: *ws_visible}}
- map: {default: {empty: {}}, conditions: {ws6_new_monitor: *monitor_sep}}
- map:
default: {string: {text: "{ws6}", <<: *ws_default}}
conditions:
ws6_state == unused: {empty: {}}
ws6_state == focused: {string: {text: "{ws6}", <<: *ws_focused}}
ws6_state == visible: {string: {text: "{ws6}", <<: *ws_visible}}
- map: {default: {empty: {}}, conditions: {ws7_new_monitor: *monitor_sep}}
- map:
default: {string: {text: "{ws7}", <<: *ws_default}}
conditions:
ws7_state == unused: {empty: {}}
ws7_state == focused: {string: {text: "{ws7}", <<: *ws_focused}}
ws7_state == visible: {string: {text: "{ws7}", <<: *ws_visible}}
- map: {default: {empty: {}}, conditions: {ws8_new_monitor: *monitor_sep}}
- map:
default: {string: {text: "{ws8}", <<: *ws_default}}
conditions:
ws8_state == unused: {empty: {}}
ws8_state == focused: {string: {text: "{ws8}", <<: *ws_focused}}
ws8_state == visible: {string: {text: "{ws8}", <<: *ws_visible}}
- map: {default: {empty: {}}, conditions: {ws9_new_monitor: *monitor_sep}}
- map:
default: {string: {text: "{ws9}", <<: *ws_default}}
conditions:
ws9_state == unused: {empty: {}}
ws9_state == focused: {string: {text: "{ws9}", <<: *ws_focused}}
ws9_state == visible: {string: {text: "{ws9}", <<: *ws_visible}}
- map: {default: {empty: {}}, conditions: {ws10_new_monitor: *monitor_sep}}
- map:
default: {string: {text: "{ws10}", <<: *ws_default}}
conditions:
ws10_state == unused: {empty: {}}
ws10_state == focused: {string: {text: "{ws10}", <<: *ws_focused}}
ws10_state == visible: {string: {text: "{ws10}", <<: *ws_visible}}
- map: {default: {empty: {}}, conditions: {ws11_new_monitor: *monitor_sep}}
- map:
default: {string: {text: "{ws11}", <<: *ws_default}}
conditions:
ws11_state == unused: {empty: {}}
ws11_state == focused: {string: {text: "{ws11}", <<: *ws_focused}}
ws11_state == visible: {string: {text: "{ws11}", <<: *ws_visible}}
- map:
default:
- {empty: {left-margin: 5}}
- string:
text: "{mode}"
left-margin: 5
right-margin: 5
deco:
background:
color: 9c5842d8
conditions:
mode == default: {empty: {}}
- mem: - mem:
interval: 1500 interval: 1500

111
yambar/sway.py Executable file
View file

@ -0,0 +1,111 @@
#!/usr/bin/env python3
import os
import sys
import socket
import struct
import json
import traceback
from time import sleep
from typing import List
MSGTYPE_GET_WORKSPACES = 1
MSGTYPE_SUBSCRIBE = 2
MSGTYPE_GET_BINDING_STATE = 12
MSGTYPE_EVENT_WORKSPACE = 0x80000000
MSGTYPE_EVENT_MODE = 0x80000002
magic = b"i3-ipc"
msg_header = struct.Struct("II")
s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
s.connect(os.getenvb(b"SWAYSOCK"))
def recv():
reply_magic = s.recv(6)
assert reply_magic == magic
reply_header = s.recv(msg_header.size)
reply_length, reply_type = msg_header.unpack(reply_header)
reply_payload = s.recv(reply_length)
return reply_type, reply_payload
def msg(msg_type: int, payload: bytes):
global s
message = (
magic +
msg_header.pack(len(payload), msg_type) +
payload
)
n_sent_bytes = s.send(message)
assert n_sent_bytes == len(message)
def subscribe(types: List[str]):
msg(MSGTYPE_SUBSCRIBE, json.dumps(types).encode("utf-8"))
reply = recv()
success = json.loads(reply[1])["success"]
if not success:
raise Exception("Could not subscribe")
def format_workspaces(workspaces):
result = []
last_output = None
for i, ws in enumerate(sorted(workspaces, key=lambda x: (x["output"], x["num"], x["name"]))):
name = ws["name"]
new_monitor = last_output is not None and last_output != ws["output"]
last_output = ws["output"]
state = (
"focused" if ws["focused"] else
"visible" if ws["visible"] else
""
)
result.append(f"ws{i}|string|{ws['name']}")
result.append(f"ws{i}_state|string|{state}")
result.append(f"ws{i}_new_monitor|bool|{'true' if new_monitor else 'false'}")
while i <= 11:
result.append(f"ws{i}|string|")
result.append(f"ws{i}_state|string|unused")
result.append(f"ws{i}_new_monitor|bool|false")
i += 1
return "\n".join(result)
msg(MSGTYPE_GET_BINDING_STATE, b'')
state_mode = json.loads(recv()[1])["name"]
msg(MSGTYPE_GET_WORKSPACES, b'')
state_workspaces = json.loads(recv()[1])
def print_state():
global state_workspaces
global state_mode
print(f"""{format_workspaces(state_workspaces)}
mode|string|{state_mode}
""", flush=True)
sleep(0.01)
print_state()
subscribe(["workspace", "mode"])
while True:
try:
item_type, item = recv()
if item_type == MSGTYPE_GET_WORKSPACES:
state_workspaces = json.loads(item)
print_state()
elif item_type == MSGTYPE_EVENT_WORKSPACE:
msg(MSGTYPE_GET_WORKSPACES, b'')
elif item_type == MSGTYPE_EVENT_MODE:
state_mode = json.loads(item)["change"]
print_state()
else:
print(f"Unhandled message of type 0x{item_type:x}", file=sys.stderr, flush=True)
except:
traceback.print_exc()