Battery was suposed to be in panel, fixed that. Added support for waytray.

This commit is contained in:
Storm Dragon
2025-12-05 16:30:59 -05:00
parent 00f3c93594
commit 63fcf8e283
3 changed files with 286 additions and 23 deletions

24
I38.md
View File

@@ -95,6 +95,7 @@ In Panel Mode, single keypresses launch different information panels:
| `F1` | Show panel mode keybindings |
| `w` | Display weather information |
| `Shift` + `w` | Open Magic Wormhole file transfer GUI |
| `t` | System Tray - Access minimized applications, status indicators, and background services *(requires waytray)* |
| `s` | Show system information |
| `r` | Open reminder panel |
| `n` | Launch notes application |
@@ -134,7 +135,28 @@ The notes panel (`n` key in Panel Mode) provides a simple application for creati
The reminder panel (`r` key in Panel Mode) offers the same reminder functionality described in the Reminders and Notifications section, It was previously in ratpoison mode but has been moved to panel mode because it is a better fit.
*Note:* Because Panel Mode uses a custom implementation rather than a traditional system tray, applications that require a system tray to run may not work with I38.
### System Tray (Optional)
If you have waytray installed, I38 provides keyboard-accessible system tray functionality through the StatusNotifierItem (SNI) protocol. This allows you to interact with applications that use the system tray for status indicators or minimize to tray.
**Features:**
- Access minimized applications (Discord, Slack, Telegram, etc.)
- View and interact with status indicators (NetworkManager, volume, VPN, etc.)
- Control background services through their tray context menus
- Full keyboard navigation without mouse required
**Usage:**
1. Press `Control` + `Alt` + `Tab` to enter Panel Mode
2. Press `t` to open the system tray window
3. Use arrow keys to navigate between tray items
4. Press `Enter` or `Space` to activate the selected item
5. Press `Menu` key or `Shift` + `F10` to open context menus
6. Press `Escape` to close the tray window
**Installation:**
waytray is an optional dependency. If installed, I38 will automatically configure it to provide only system tray functionality (battery, weather, and system information are disabled to avoid duplication with I38's panel utilities).
*Note:* Without waytray installed, applications that require a system tray to run may not work with I38. However, many applications offer alternative ways to run without a tray.
## Accessibility Features

57
i38.sh
View File

@@ -401,6 +401,44 @@ update_scripts() {
exit 0
}
write_waytray_config() {
# Only create config if waytray binaries are detected
if ! command -v waytray-daemon &> /dev/null || ! command -v waytray &> /dev/null ; then
return 1
fi
local waytrayConfigDir="${XDG_CONFIG_HOME:-$HOME/.config}/waytray"
local waytrayConfig="${waytrayConfigDir}/config.toml"
mkdir -p "${waytrayConfigDir}"
# Ask user if config already exists
if [[ -f "${waytrayConfig}" ]]; then
if ! yesno "Existing waytray configuration detected. Replace with I38's minimal tray-only config?\n\n(Select 'No' to keep your existing waytray configuration with all modules enabled)"; then
return 0 # User wants to keep existing config
fi
fi
# Create I38's minimal tray-only config
cat << 'EOF' > "${waytrayConfig}"
# WayTray Configuration - Generated by I38
# I38 provides its own battery, weather, and system info utilities
# This config enables ONLY the system tray (SNI) functionality
[modules]
order = ["tray"]
[modules.tray]
enabled = true
[notifications]
enabled = true
timeout_ms = 5000
EOF
return 0
}
# Array of command line arguments
declare -A command=(
@@ -597,6 +635,9 @@ mkdir -p "${i3Path}"
# Move scripts into place
cp -rv scripts/ "${i3Path}/" | dialog --backtitle "I38" --progressbox "Moving scripts into place and writing config..." -1 -1
# Configure waytray if available
write_waytray_config
cat << EOF > ${i3Path}/config
# Generated by I38 (${0##*/}) https://git.stormux.org/storm/I38
# $(date '+%A, %B %d, %Y at %I:%M%p')
@@ -799,10 +840,15 @@ mode "panel" {
# Magic wormhole bound to shift+W
bindsym Shift+w exec --no-startup-id ${i3Path}/scripts/wormhole.py, mode "default"
$(if command -v waytray &> /dev/null ; then
echo " # System tray bound to t"
echo " bindsym t exec --no-startup-id waytray, mode \"default\""
echo " "
fi)
# System information bound to s
bindsym s exec --no-startup-id ${i3Path}/scripts/sysinfo.sh, mode "default"
$(if command -v remind &> /dev/null ; then
echo "# Reminders bound to r"
echo "bindsym r exec --no-startup-id ${i3Path}/scripts/reminder.sh, mode \"default\""
@@ -816,6 +862,9 @@ $(if command -v blueman-manager &> /dev/null ; then
echo "bindsym b exec --no-startup-id blueman-manager, mode \"default\""
fi)
# Detailed battery information bound to Shift+b
bindsym Shift+b exec --no-startup-id ${i3Path}/scripts/battery_status.sh --detailed, mode "default"
$(if command -v lxsession-logout &> /dev/null ; then
echo "# Power options bound to p"
echo "bindsym p exec --no-startup-id lxsession-logout, mode \"default\""
@@ -980,6 +1029,10 @@ fi
if [[ $batteryAlert -eq 0 ]]; then
echo "exec_always --no-startup-id ${i3Path}/scripts/battery_alert.sh"
fi
# WayTray system tray daemon
if command -v waytray-daemon &> /dev/null ; then
echo 'exec_always --no-startup-id bash -c "pgrep -x waytray-daemon > /dev/null || waytray-daemon"'
fi
if [[ $dex -eq 0 ]]; then
echo '# Start XDG autostart .desktop files using dex. See also'
echo '# https://wiki.archlinux.org/index.php/XDG_Autostart'

View File

@@ -1,29 +1,217 @@
#!/usr/bin/env bash
# This file is part of I38.
# I38 is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation,
# either version 3 of the License, or (at your option) any later version.
# I38 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
# PURPOSE. See the GNU General Public License for more details.
# You should have received a copy of the GNU General Public License along with I38. If not, see <https://www.gnu.org/licenses/>.
#check for acpi
if command -v acpi &> /dev/null; then
bat="$(acpi -b)"
spd-say -P important -Cw "$bat"
else
find /sys/class/power_supply -type l -exec bash -c '
for i ; do
if [[ -e "$i/capacity" ]]; then
bat="${i##*/}"
bat="${bat//BAT/Battery }"
bat="${bat}: $( { cat "${i}/status";echo -n ", "; cat "${i}/capacity"; } | tr -d \\n) percent."
spd-say -P important -Cw "$bat"
fi
done
' _ {} \;
# Parse command line arguments
detailedMode=0
if [[ "$1" == "-d" ]] || [[ "$1" == "--detailed" ]]; then
detailedMode=1
fi
get_battery_details() {
local batteryPath="$1"
local batteryName="${batteryPath##*/}"
local modelName=""
local manufacturer=""
local capacity=""
local status=""
local health=""
local cycleCount=""
local technology=""
local voltage=""
local current=""
local power=""
local output=""
# Get model name if available
if [[ -f "${batteryPath}/model_name" ]]; then
modelName="$(cat "${batteryPath}/model_name" 2>/dev/null | tr -d '\n')"
fi
# Get manufacturer if available
if [[ -f "${batteryPath}/manufacturer" ]]; then
manufacturer="$(cat "${batteryPath}/manufacturer" 2>/dev/null | tr -d '\n')"
fi
# Get capacity (charge percentage)
if [[ -f "${batteryPath}/capacity" ]]; then
capacity="$(cat "${batteryPath}/capacity" 2>/dev/null | tr -d '\n')"
fi
# Get status (Charging, Discharging, Full, etc.)
if [[ -f "${batteryPath}/status" ]]; then
status="$(cat "${batteryPath}/status" 2>/dev/null | tr -d '\n')"
fi
# Get health/capacity level if available
if [[ -f "${batteryPath}/capacity_level" ]]; then
health="$(cat "${batteryPath}/capacity_level" 2>/dev/null | tr -d '\n')"
fi
# Get cycle count if available
if [[ -f "${batteryPath}/cycle_count" ]]; then
cycleCount="$(cat "${batteryPath}/cycle_count" 2>/dev/null | tr -d '\n')"
fi
# Get technology (Li-ion, Li-poly, etc.)
if [[ -f "${batteryPath}/technology" ]]; then
technology="$(cat "${batteryPath}/technology" 2>/dev/null | tr -d '\n')"
fi
# Get voltage (in microvolts, convert to volts)
if [[ -f "${batteryPath}/voltage_now" ]]; then
local voltageUv
voltageUv="$(cat "${batteryPath}/voltage_now" 2>/dev/null | tr -d '\n')"
if [[ -n "$voltageUv" ]] && [[ "$voltageUv" =~ ^[0-9]+$ ]]; then
voltage="$(awk "BEGIN {printf \"%.2f\", $voltageUv/1000000}")"
fi
fi
# Get current (in microamps, convert to amps)
if [[ -f "${batteryPath}/current_now" ]]; then
local currentUa
currentUa="$(cat "${batteryPath}/current_now" 2>/dev/null | tr -d '\n')"
if [[ -n "$currentUa" ]] && [[ "$currentUa" =~ ^[0-9]+$ ]]; then
current="$(awk "BEGIN {printf \"%.2f\", $currentUa/1000000}")"
fi
fi
# Get power (in microwatts, convert to watts)
if [[ -f "${batteryPath}/power_now" ]]; then
local powerUw
powerUw="$(cat "${batteryPath}/power_now" 2>/dev/null | tr -d '\n')"
if [[ -n "$powerUw" ]] && [[ "$powerUw" =~ ^[0-9]+$ ]]; then
power="$(awk "BEGIN {printf \"%.2f\", $powerUw/1000000}")"
fi
fi
# Build readable device name
local deviceName="$batteryName"
if [[ -n "$manufacturer" ]] && [[ -n "$modelName" ]]; then
deviceName="$manufacturer $modelName"
elif [[ -n "$modelName" ]]; then
deviceName="$modelName"
elif [[ -n "$manufacturer" ]]; then
deviceName="$manufacturer Battery"
else
# Try to make the battery name more readable
deviceName="${batteryName//BAT/Battery }"
deviceName="${deviceName//hid-/}"
deviceName="${deviceName//_/ }"
fi
# Build the output string
output="$deviceName"
if [[ -n "$capacity" ]]; then
output="$output, ${capacity}%"
fi
if [[ -n "$status" ]]; then
output="$output, ${status,,}"
fi
if [[ -n "$health" ]]; then
output="$output, health: ${health,,}"
fi
if [[ -n "$technology" ]]; then
output="$output, type: $technology"
fi
if [[ -n "$voltage" ]]; then
output="$output, voltage: ${voltage}V"
fi
if [[ -n "$current" ]]; then
output="$output, current: ${current}A"
fi
if [[ -n "$power" ]]; then
output="$output, power: ${power}W"
fi
if [[ -n "$cycleCount" ]]; then
output="$output, cycles: $cycleCount"
fi
echo "$output"
}
# Simple battery status (default mode)
get_battery_simple() {
local batteryPath="$1"
local bat="${batteryPath##*/}"
bat="${bat//BAT/Battery }"
bat="${bat}: $( { cat "${batteryPath}/status";echo -n ", "; cat "${batteryPath}/capacity"; } | tr -d \\n) percent."
echo "$bat"
}
# Main script
if [[ $detailedMode -eq 1 ]]; then
# Detailed mode
if command -v acpi &> /dev/null; then
# Try acpi first for more detailed info
batteryInfo=""
while IFS= read -r line; do
if [[ -n "$batteryInfo" ]]; then
batteryInfo="${batteryInfo}. "
fi
batteryInfo="${batteryInfo}${line}"
done < <(acpi -V 2>/dev/null | grep -i battery)
if [[ -n "$batteryInfo" ]]; then
spd-say -P important -Cw "$batteryInfo"
exit 0
fi
fi
# Fallback to /sys/class/power_supply for detailed info
batteryCount=0
batteryOutput=""
while IFS= read -r batteryPath; do
if [[ -e "${batteryPath}/capacity" ]] || [[ -e "${batteryPath}/status" ]]; then
batteryDetails="$(get_battery_details "$batteryPath")"
if [[ -n "$batteryDetails" ]]; then
((batteryCount++))
if [[ -n "$batteryOutput" ]]; then
batteryOutput="${batteryOutput}. "
fi
batteryOutput="${batteryOutput}${batteryDetails}"
fi
fi
done < <(find /sys/class/power_supply -type l 2>/dev/null)
if [[ $batteryCount -eq 0 ]]; then
spd-say -P important -Cw "No battery information available"
else
spd-say -P important -Cw "$batteryOutput"
fi
else
# Simple mode (default)
if command -v acpi &> /dev/null; then
bat="$(acpi -b)"
spd-say -P important -Cw "$bat"
else
find /sys/class/power_supply -type l -exec bash -c '
for i ; do
if [[ -e "$i/capacity" ]]; then
bat="${i##*/}"
bat="${bat//BAT/Battery }"
bat="${bat}: $( { cat "${i}/status";echo -n ", "; cat "${i}/capacity"; } | tr -d \\n) percent."
spd-say -P important -Cw "$bat"
fi
done
' _ {} \;
fi
fi