[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:
parent
1cd1dfe2e0
commit
1914e3f0db
2 changed files with 226 additions and 20 deletions
|
@ -75,27 +75,122 @@ bar:
|
|||
spacing: 10
|
||||
|
||||
left:
|
||||
- i3:
|
||||
sort: ascending
|
||||
#- i3:
|
||||
#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:
|
||||
"":
|
||||
map:
|
||||
tag: state
|
||||
default: {string: {text: "{name}", foreground: *col_fg_alt, margin: 7}}
|
||||
values:
|
||||
"focused": {string: {text: "{name}", margin: 7}}
|
||||
#current:
|
||||
#list:
|
||||
#left-margin: 25
|
||||
#spacing: 0
|
||||
#items:
|
||||
#- { string: {text: "{application}", foreground: *col_fg_alt}}
|
||||
#- map:
|
||||
#tag: application
|
||||
#default: { string: {text: ": ", foreground: *col_fg_alt}}
|
||||
#values:
|
||||
#"": {empty: {}}
|
||||
#- { string: {text: "{title}", foreground: *col_fg_alt}}
|
||||
- list:
|
||||
spacing: 0
|
||||
items:
|
||||
- map:
|
||||
default: {string: {text: "{ws0}", <<: *ws_default}}
|
||||
conditions:
|
||||
ws0_state == unused: {empty: {}}
|
||||
ws0_state == focused: {string: {text: "{ws0}", <<: *ws_focused}}
|
||||
ws0_state == visible: {string: {text: "{ws0}", <<: *ws_visible}}
|
||||
- map: {default: {empty: {}}, conditions: {ws1_new_monitor: *monitor_sep}}
|
||||
- map:
|
||||
default: {string: {text: "{ws1}", <<: *ws_default}}
|
||||
conditions:
|
||||
ws1_state == unused: {empty: {}}
|
||||
ws1_state == focused: {string: {text: "{ws1}", <<: *ws_focused}}
|
||||
ws1_state == visible: {string: {text: "{ws1}", <<: *ws_visible}}
|
||||
- map: {default: {empty: {}}, conditions: {ws2_new_monitor: *monitor_sep}}
|
||||
- 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:
|
||||
interval: 1500
|
||||
|
|
111
yambar/sway.py
Executable file
111
yambar/sway.py
Executable 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()
|
Loading…
Reference in a new issue