added wayshell framework
This commit is contained in:
Executable
+45
@@ -0,0 +1,45 @@
|
||||
#!/bin/bash
|
||||
#===============================================================================
|
||||
# Focused Module — Detect client focus/unfocus events
|
||||
#===============================================================================
|
||||
# Description:
|
||||
# Subscribes to `mmsg watch focusing-client` and emits JSON when the focused
|
||||
# client changes. Tracks the previously focused app_id to emit unfocused
|
||||
# events.
|
||||
#
|
||||
# Output format (JSON lines):
|
||||
# {"app_id":"firefox","state":"focused"}
|
||||
# {"app_id":"firefox","state":"unfocused"}
|
||||
# {"app_id":"com.mitchellh.ghostty","state":"focused"}
|
||||
#
|
||||
# Dependencies:
|
||||
# - jq
|
||||
# - mmsg
|
||||
#===============================================================================
|
||||
|
||||
PREV_APP_ID=""
|
||||
|
||||
if ! command -v mmsg &>/dev/null || ! command -v jq &>/dev/null; then
|
||||
echo "focused.sh: mmsg and jq are required" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
while read -r line; do
|
||||
app_id=$(jq -r '.appid // empty' <<< "$line" 2>/dev/null)
|
||||
|
||||
if [[ -z "$app_id" || "$app_id" == "null" ]]; then
|
||||
if [[ -n "$PREV_APP_ID" ]]; then
|
||||
echo "{\"app_id\":\"$PREV_APP_ID\",\"state\":\"unfocused\"}"
|
||||
PREV_APP_ID=""
|
||||
fi
|
||||
continue
|
||||
fi
|
||||
|
||||
if [[ "$app_id" != "$PREV_APP_ID" ]]; then
|
||||
if [[ -n "$PREV_APP_ID" ]]; then
|
||||
echo "{\"app_id\":\"$PREV_APP_ID\",\"state\":\"unfocused\"}"
|
||||
fi
|
||||
echo "{\"app_id\":\"$app_id\",\"state\":\"focused\"}"
|
||||
PREV_APP_ID="$app_id"
|
||||
fi
|
||||
done < <(mmsg watch focusing-client 2>/dev/null)
|
||||
Executable
+68
@@ -0,0 +1,68 @@
|
||||
#!/bin/bash
|
||||
#===============================================================================
|
||||
# Layout Module — Detect layout activation/deactivation events
|
||||
#===============================================================================
|
||||
# Description:
|
||||
# Subscribes to `mmsg watch all-tags` and emits JSON when any tag's layout
|
||||
# becomes active or inactive on any monitor.
|
||||
#
|
||||
# Output format (JSON lines):
|
||||
# {"layout":"M","state":"active","monitor":"DP-1","tag":1}
|
||||
# {"layout":"M","state":"inactive","monitor":"DP-1","tag":1}
|
||||
#
|
||||
# Dependencies:
|
||||
# - jq
|
||||
# - mmsg
|
||||
#===============================================================================
|
||||
|
||||
declare -A ACTIVE_LAYOUTS
|
||||
|
||||
make_key() {
|
||||
echo "${1}:${2}:${3}"
|
||||
}
|
||||
|
||||
process_tags_update() {
|
||||
local json="$1"
|
||||
local monitors monitor tag layout is_active key new_keys=""
|
||||
|
||||
monitors=$(jq -c '.all_tags[]' <<< "$json" 2>/dev/null)
|
||||
|
||||
while IFS= read -r entry; do
|
||||
[[ -z "$entry" ]] && continue
|
||||
monitor=$(jq -r '.monitor' <<< "$entry" 2>/dev/null)
|
||||
[[ -z "$monitor" ]] && continue
|
||||
|
||||
while IFS= read -r tag_entry; do
|
||||
[[ -z "$tag_entry" ]] && continue
|
||||
tag=$(jq -r '.index' <<< "$tag_entry" 2>/dev/null)
|
||||
layout=$(jq -r '.layout' <<< "$tag_entry" 2>/dev/null)
|
||||
is_active=$(jq -r '.is_active' <<< "$tag_entry" 2>/dev/null)
|
||||
key=$(make_key "$monitor" "$tag" "$layout")
|
||||
new_keys="$new_keys $key"
|
||||
|
||||
if [[ "$is_active" == "true" ]]; then
|
||||
if [[ -z "${ACTIVE_LAYOUTS[$key]}" ]]; then
|
||||
echo "{\"layout\":\"$layout\",\"state\":\"active\",\"monitor\":\"$monitor\",\"tag\":$tag}"
|
||||
fi
|
||||
ACTIVE_LAYOUTS["$key"]="active"
|
||||
fi
|
||||
done < <(jq -c '.tags[]' <<< "$entry" 2>/dev/null)
|
||||
done <<< "$monitors"
|
||||
|
||||
for key in "${!ACTIVE_LAYOUTS[@]}"; do
|
||||
if [[ ! " $new_keys " =~ $key ]]; then
|
||||
IFS=':' read -r monitor tag layout <<< "$key"
|
||||
echo "{\"layout\":\"$layout\",\"state\":\"inactive\",\"monitor\":\"$monitor\",\"tag\":$tag}"
|
||||
unset "ACTIVE_LAYOUTS[$key]"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
if ! command -v mmsg &>/dev/null || ! command -v jq &>/dev/null; then
|
||||
echo "layout.sh: mmsg and jq are required" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
while read -r line; do
|
||||
process_tags_update "$line"
|
||||
done < <(mmsg watch all-tags 2>/dev/null)
|
||||
Executable
+103
@@ -0,0 +1,103 @@
|
||||
#!/bin/bash
|
||||
#===============================================================================
|
||||
# Zone Detection Daemon
|
||||
#===============================================================================
|
||||
# Description:
|
||||
# Polls cursor position via `mmsg get cursorpos` and outputs JSON when the
|
||||
# cursor is within ZONE_BUFFER pixels of any screen edge. Emits an exit
|
||||
# event when the cursor leaves the edge zone, so the daemon knows the
|
||||
# exact departure time for proper trailing-edge debounce.
|
||||
#
|
||||
# Uses monitor-relative coordinates so edge detection works on any monitor.
|
||||
#
|
||||
# Dependencies: jq, mmsg
|
||||
#
|
||||
# Output format (JSON lines):
|
||||
# In zone: {"x":<float>,"y":<float>,"monitor":"<name>"}
|
||||
# On exit: {"state":"exit","x":<float>,"y":<float>,"monitor":"<name>"}
|
||||
#===============================================================================
|
||||
|
||||
CONFIG_FILE="${HOME}/.config/sdgos/wayshell/wayshell.conf"
|
||||
|
||||
ZONE_BUFFER=$(grep -oP 'zone_buffer=\K[0-9]+' "$CONFIG_FILE" 2>/dev/null || echo "10")
|
||||
ZONE_BUFFER=${ZONE_BUFFER:-10}
|
||||
POLL_INTERVAL=0.1
|
||||
|
||||
was_in_zone=false
|
||||
last_x=""
|
||||
last_y=""
|
||||
last_monitor=""
|
||||
|
||||
declare -A MONITOR_CACHE
|
||||
MONITOR_CACHE_AGE=0
|
||||
|
||||
get_monitor_info() {
|
||||
local mon="$1"
|
||||
local now
|
||||
now=$(date +%s)
|
||||
|
||||
if (( now - MONITOR_CACHE_AGE > 5 )) || [[ -z "${MONITOR_CACHE[$mon]}" ]]; then
|
||||
local json entry name w h ox oy
|
||||
json=$(mmsg get all-monitors 2>/dev/null)
|
||||
if [[ -n "$json" ]]; then
|
||||
while IFS= read -r entry; do
|
||||
name=$(jq -r '.name' <<< "$entry" 2>/dev/null)
|
||||
w=$(jq -r '.width' <<< "$entry" 2>/dev/null)
|
||||
h=$(jq -r '.height' <<< "$entry" 2>/dev/null)
|
||||
ox=$(jq -r '.x' <<< "$entry" 2>/dev/null)
|
||||
oy=$(jq -r '.y' <<< "$entry" 2>/dev/null)
|
||||
if [[ -n "$name" && "$w" != "null" && "$h" != "null" ]]; then
|
||||
MONITOR_CACHE["$name"]="$w $h ${ox:-0} ${oy:-0}"
|
||||
fi
|
||||
done < <(jq -c '.monitors[]' <<< "$json" 2>/dev/null)
|
||||
fi
|
||||
MONITOR_CACHE_AGE=$now
|
||||
fi
|
||||
|
||||
echo "${MONITOR_CACHE[$mon]:-1920 1080 0 0}"
|
||||
}
|
||||
|
||||
while true; do
|
||||
cursor_info=$(mmsg get cursorpos 2>/dev/null)
|
||||
if [[ -z "$cursor_info" ]]; then
|
||||
sleep "$POLL_INTERVAL"
|
||||
continue
|
||||
fi
|
||||
|
||||
x=$(jq -r '.x' <<< "$cursor_info" 2>/dev/null)
|
||||
y=$(jq -r '.y' <<< "$cursor_info" 2>/dev/null)
|
||||
monitor=$(jq -r '.monitor' <<< "$cursor_info" 2>/dev/null)
|
||||
|
||||
if [[ -z "$x" || -z "$y" || -z "$monitor" ]]; then
|
||||
sleep "$POLL_INTERVAL"
|
||||
continue
|
||||
fi
|
||||
|
||||
read -r width height m_x m_y <<< "$(get_monitor_info "$monitor")"
|
||||
if [[ -z "$width" || -z "$height" ]]; then
|
||||
sleep "$POLL_INTERVAL"
|
||||
continue
|
||||
fi
|
||||
|
||||
local_x=$(( ${x%.*} - m_x ))
|
||||
local_y=$(( ${y%.*} - m_y ))
|
||||
|
||||
in_zone=false
|
||||
(( local_x < ZONE_BUFFER )) && in_zone=true
|
||||
(( local_x > width - ZONE_BUFFER )) && in_zone=true
|
||||
(( local_y < ZONE_BUFFER )) && in_zone=true
|
||||
(( local_y > height - ZONE_BUFFER )) && in_zone=true
|
||||
|
||||
if $in_zone && ! $was_in_zone; then
|
||||
echo "$cursor_info"
|
||||
elif ! $in_zone && $was_in_zone; then
|
||||
echo "{\"state\":\"exit\",\"x\":$last_x,\"y\":$last_y,\"monitor\":\"$last_monitor\"}"
|
||||
fi
|
||||
|
||||
was_in_zone=$in_zone
|
||||
last_x=$x
|
||||
last_y=$y
|
||||
last_monitor=$monitor
|
||||
|
||||
sleep "$POLL_INTERVAL"
|
||||
done
|
||||
Reference in New Issue
Block a user