Screen lock and power management now native I38 scripts. Removed customizations and added a personal mode template option instead. This means things added by users should not be removed on updates.
This commit is contained in:
@@ -21,7 +21,6 @@ An uppercase I looks like a 1, 3 from i3, and 8 because the song [We Are 138](ht
|
|||||||
- i3-wm: The i3 window manager.
|
- i3-wm: The i3 window manager.
|
||||||
- jq: for getting the current workspace
|
- jq: for getting the current workspace
|
||||||
- libnotify: For sending notifications
|
- libnotify: For sending notifications
|
||||||
- lxsession: [optional] For GUI power options like shutdown
|
|
||||||
- magic-wormhole: [optional] for file sharing with magic-wormhole GUI
|
- magic-wormhole: [optional] for file sharing with magic-wormhole GUI
|
||||||
- notification-daemon: To handle notifications
|
- notification-daemon: To handle notifications
|
||||||
- pamixer: for the mute-unmute script
|
- pamixer: for the mute-unmute script
|
||||||
|
|||||||
522
i38.sh
522
i38.sh
@@ -169,7 +169,7 @@ menulist() {
|
|||||||
rangebox() {
|
rangebox() {
|
||||||
dialog --title "I38" \
|
dialog --title "I38" \
|
||||||
--backtitle "Use the arrow keys to select a number, then press enter." \
|
--backtitle "Use the arrow keys to select a number, then press enter." \
|
||||||
--rangebox "$1" -1 -1 $2 $3 $4 --stdout
|
--rangebox "$1" -1 -1 "$2" "$3" "$4" --stdout
|
||||||
}
|
}
|
||||||
|
|
||||||
yesno() {
|
yesno() {
|
||||||
@@ -179,161 +179,85 @@ yesno() {
|
|||||||
return $?
|
return $?
|
||||||
}
|
}
|
||||||
|
|
||||||
# Custom application keybinding functions
|
# Personal mode helpers
|
||||||
declare -A usedKeys
|
normalize_ratpoison_key() {
|
||||||
declare -a customApps
|
local key="$1"
|
||||||
|
|
||||||
showKeybindingHelp() {
|
key="${key//Alt/Mod1}"
|
||||||
dialog --title "I38 Keybinding Help" --msgbox \
|
key="${key//Super Left/Super_L}"
|
||||||
"Keybinding Notation:
|
key="${key//Super Right/Super_R}"
|
||||||
Modifiers: ^ = Ctrl, ! = Alt, # = Super, m = your mod key
|
|
||||||
Special keys: f1-f12, up/down/left/right, space, tab, return
|
|
||||||
home/end/insert/delete/pageup/pagedown, print
|
|
||||||
backspace, escape
|
|
||||||
|
|
||||||
Examples:
|
echo "$key"
|
||||||
c = just 'c' key
|
|
||||||
^c = Ctrl+c
|
|
||||||
!f1 = Alt+F1
|
|
||||||
mspace = mod+Space
|
|
||||||
^!up = Ctrl+Alt+Up
|
|
||||||
#pagedown = Super+Page_Down
|
|
||||||
|
|
||||||
Uppercase letters imply Shift (e.g., C = Shift+c)" 0 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
convertKeybinding() {
|
select_personal_mode_key() {
|
||||||
local input="$1"
|
local ratpoisonModeKeys=(
|
||||||
local result=""
|
"Control+t"
|
||||||
local baseKey=""
|
"Control+z"
|
||||||
|
"Control+Escape"
|
||||||
# Handle modifiers
|
"Alt+Escape"
|
||||||
if [[ "$input" == *"^"* ]]; then
|
"Control+space"
|
||||||
result+="Control+"
|
"Super Left"
|
||||||
input="${input//^/}"
|
"Super Right"
|
||||||
fi
|
)
|
||||||
if [[ "$input" == *"!"* ]]; then
|
local personalModeKeyOptions=()
|
||||||
result+="Mod1+"
|
local option normalizedOption
|
||||||
input="${input//!/}"
|
|
||||||
fi
|
|
||||||
if [[ "$input" == *"#"* ]]; then
|
|
||||||
result+="Mod4+"
|
|
||||||
input="${input//#/}"
|
|
||||||
fi
|
|
||||||
if [[ "$input" == *"m"* ]]; then
|
|
||||||
result+="\$mod+"
|
|
||||||
input="${input//m/}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Handle shift for uppercase letters
|
|
||||||
if [[ "$input" =~ [A-Z] ]]; then
|
|
||||||
result+="Shift+"
|
|
||||||
input="${input,,}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Convert special keys
|
|
||||||
case "$input" in
|
|
||||||
f[1-9]|f1[0-2]) baseKey="F${input#f}" ;;
|
|
||||||
up|down|left|right) baseKey="$input" ;;
|
|
||||||
space) baseKey="space" ;;
|
|
||||||
tab) baseKey="Tab" ;;
|
|
||||||
return) baseKey="Return" ;;
|
|
||||||
escape) baseKey="Escape" ;;
|
|
||||||
backspace) baseKey="BackSpace" ;;
|
|
||||||
print) baseKey="Print" ;;
|
|
||||||
home) baseKey="Home" ;;
|
|
||||||
end) baseKey="End" ;;
|
|
||||||
insert) baseKey="Insert" ;;
|
|
||||||
delete) baseKey="Delete" ;;
|
|
||||||
pageup) baseKey="Page_Up" ;;
|
|
||||||
pagedown) baseKey="Page_Down" ;;
|
|
||||||
*) baseKey="$input" ;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
echo "${result}${baseKey}"
|
|
||||||
}
|
|
||||||
|
|
||||||
populateUsedKeys() {
|
for option in "${ratpoisonModeKeys[@]}"; do
|
||||||
# Populate with existing ratpoison mode bindings
|
normalizedOption="$(normalize_ratpoison_key "$option")"
|
||||||
usedKeys["Shift+slash"]=1
|
if [[ "$normalizedOption" != "$escapeKey" ]]; then
|
||||||
usedKeys["c"]=1
|
personalModeKeyOptions+=("$option")
|
||||||
usedKeys["e"]=1
|
fi
|
||||||
usedKeys["f"]=1
|
|
||||||
usedKeys["\$mod+e"]=1
|
|
||||||
usedKeys["w"]=1
|
|
||||||
usedKeys["k"]=1
|
|
||||||
usedKeys["m"]=1
|
|
||||||
usedKeys["Print"]=1
|
|
||||||
usedKeys["\$mod+r"]=1
|
|
||||||
usedKeys["p"]=1
|
|
||||||
usedKeys["\$mod+s"]=1
|
|
||||||
usedKeys["Mod1+Shift+0"]=1
|
|
||||||
usedKeys["Mod1+Shift+9"]=1
|
|
||||||
usedKeys["Mod1+Shift+equal"]=1
|
|
||||||
usedKeys["Mod1+Shift+minus"]=1
|
|
||||||
usedKeys["Mod1+Shift+z"]=1
|
|
||||||
usedKeys["Mod1+Shift+c"]=1
|
|
||||||
usedKeys["Mod1+Shift+x"]=1
|
|
||||||
usedKeys["Mod1+Shift+v"]=1
|
|
||||||
usedKeys["Mod1+Shift+b"]=1
|
|
||||||
usedKeys["Mod1+Shift+u"]=1
|
|
||||||
usedKeys["Mod1+b"]=1
|
|
||||||
usedKeys["g"]=1
|
|
||||||
usedKeys["apostrophe"]=1
|
|
||||||
usedKeys["Shift+c"]=1
|
|
||||||
usedKeys["Shift+o"]=1
|
|
||||||
usedKeys["Shift+t"]=1
|
|
||||||
usedKeys["Control+semicolon"]=1
|
|
||||||
usedKeys["Control+Shift+semicolon"]=1
|
|
||||||
usedKeys["Shift+exclam"]=1
|
|
||||||
usedKeys["\$mod+q"]=1
|
|
||||||
usedKeys["Control+\$mod+q"]=1
|
|
||||||
usedKeys["Escape"]=1
|
|
||||||
usedKeys["Control+g"]=1
|
|
||||||
}
|
|
||||||
|
|
||||||
inputText() {
|
|
||||||
# Args: prompt text
|
|
||||||
dialog --title "I38" --inputbox "$1" 0 0 --stdout
|
|
||||||
}
|
|
||||||
|
|
||||||
addCustomApplication() {
|
|
||||||
local appName appCommand appFlags keybinding convertedKey
|
|
||||||
|
|
||||||
populateUsedKeys
|
|
||||||
|
|
||||||
while true; do
|
|
||||||
appName="$(inputText "Custom Applications:\n\nEnter application name (or press enter when finished):")"
|
|
||||||
[[ -z "$appName" ]] && break
|
|
||||||
|
|
||||||
appCommand="$(inputText "Enter execution path/command for $appName:")"
|
|
||||||
[[ -z "$appCommand" ]] && continue
|
|
||||||
|
|
||||||
appFlags="$(inputText "Enter command line flags for $appName (optional):")"
|
|
||||||
|
|
||||||
while true; do
|
|
||||||
keybinding="$(inputText "Enter keybinding for $appName (Examples: c, ^c, !f1, mspace, ^!up) or ? for help:")"
|
|
||||||
|
|
||||||
if [[ "$keybinding" == "?" ]]; then
|
|
||||||
showKeybindingHelp
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
|
|
||||||
[[ -z "$keybinding" ]] && break
|
|
||||||
|
|
||||||
convertedKey="$(convertKeybinding "$keybinding")"
|
|
||||||
|
|
||||||
if [[ -n "${usedKeys[$convertedKey]}" ]]; then
|
|
||||||
dialog --title "I38" --msgbox "Keybinding '$keybinding' ($convertedKey) is already in use. Please choose another." 0 0
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Add to arrays
|
|
||||||
customApps+=("$appName|$appCommand|$appFlags|$convertedKey")
|
|
||||||
usedKeys["$convertedKey"]=1
|
|
||||||
break
|
|
||||||
done
|
|
||||||
done
|
done
|
||||||
|
|
||||||
|
if [[ ${#personalModeKeyOptions[@]} -eq 0 ]]; then
|
||||||
|
echo ""
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
local selectedKey
|
||||||
|
selectedKey="$(menulist "Personal mode key:" "${personalModeKeyOptions[@]}")"
|
||||||
|
normalize_ratpoison_key "$selectedKey"
|
||||||
|
}
|
||||||
|
|
||||||
|
update_personal_customizations() {
|
||||||
|
local customizationsPath="${i3Path}/customizations"
|
||||||
|
local startMarker="# I38 Personal mode start"
|
||||||
|
local endMarker="# I38 Personal mode end"
|
||||||
|
local personalModeBlock
|
||||||
|
|
||||||
|
if personal_mode_exists; then
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "${personalModeEnabled:-1}" -ne 0 ]] || [[ -z "$personalModeKey" ]]; then
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
personalModeBlock=$(cat << EOF
|
||||||
|
${startMarker}
|
||||||
|
bindsym ${personalModeKey} mode "personal"
|
||||||
|
# A template mode where you can bind items that will not be overwritten during updates
|
||||||
|
mode "personal" {
|
||||||
|
bindsym F1 exec ${i3Path}/scripts/i38-help-personal.sh, mode "default"
|
||||||
|
bindsym Escape mode "default"
|
||||||
|
bindsym Control+g mode "default"
|
||||||
|
}
|
||||||
|
${endMarker}
|
||||||
|
EOF
|
||||||
|
)
|
||||||
|
|
||||||
|
if [[ -f "$customizationsPath" ]] && [[ -s "$customizationsPath" ]]; then
|
||||||
|
printf "\n%s\n" "$personalModeBlock" >> "$customizationsPath"
|
||||||
|
else
|
||||||
|
printf "%s\n" "$personalModeBlock" > "$customizationsPath"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
personal_mode_exists() {
|
||||||
|
local customizationsPath="${i3Path}/customizations"
|
||||||
|
|
||||||
|
[[ -f "$customizationsPath" ]] && grep -q 'mode "personal"' "$customizationsPath"
|
||||||
}
|
}
|
||||||
|
|
||||||
load_config() {
|
load_config() {
|
||||||
@@ -347,20 +271,6 @@ load_config() {
|
|||||||
IFS=' ' read -ra kbd <<< "$kbd"
|
IFS=' ' read -ra kbd <<< "$kbd"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Reconstruct customApps array from numbered entries
|
|
||||||
customApps=()
|
|
||||||
local i=0
|
|
||||||
local varName
|
|
||||||
while : ; do
|
|
||||||
varName="customApp_$i"
|
|
||||||
if [[ -n "${!varName}" ]]; then
|
|
||||||
customApps+=("${!varName}")
|
|
||||||
((i++))
|
|
||||||
else
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
return 1
|
return 1
|
||||||
@@ -398,12 +308,13 @@ batteryAlert="${batteryAlert:-1}"
|
|||||||
brlapi="$brlapi"
|
brlapi="$brlapi"
|
||||||
sounds="$sounds"
|
sounds="$sounds"
|
||||||
|
|
||||||
# Custom applications
|
# Screen lock
|
||||||
|
screenlockPinHash="$screenlockPinHash"
|
||||||
|
|
||||||
|
# Personal mode
|
||||||
|
personalModeEnabled="${personalModeEnabled:-1}"
|
||||||
|
personalModeKey="$personalModeKey"
|
||||||
EOF
|
EOF
|
||||||
# Save custom apps with numbered keys
|
|
||||||
for i in "${!customApps[@]}"; do
|
|
||||||
echo "customApp_$i=\"${customApps[$i]}\"" >> "$configFile"
|
|
||||||
done
|
|
||||||
|
|
||||||
dialog --title "I38" --msgbox "Configuration saved to $configFile\n\nYou can edit this file manually or delete it to reconfigure from scratch." 0 0
|
dialog --title "I38" --msgbox "Configuration saved to $configFile\n\nYou can edit this file manually or delete it to reconfigure from scratch." 0 0
|
||||||
fi
|
fi
|
||||||
@@ -429,6 +340,11 @@ write_xinitrc()
|
|||||||
if [[ -f "$HOME/.xinitrc" ]]; then
|
if [[ -f "$HOME/.xinitrc" ]]; then
|
||||||
yesno "This will overwrite your existing $HOME/.xinitrc file. Do you want to continue?" || exit 0
|
yesno "This will overwrite your existing $HOME/.xinitrc file. Do you want to continue?" || exit 0
|
||||||
fi
|
fi
|
||||||
|
if yesno "Do you want to launch i3 without an isolated D-Bus session? Selecting No will keep the dbus-session-launch wrapper."; then
|
||||||
|
sessionCommand="exec -- i3"
|
||||||
|
else
|
||||||
|
sessionCommand="exec dbus-session-launch -- i3"
|
||||||
|
fi
|
||||||
cat << 'EOF' > ~/.xinitrc
|
cat << 'EOF' > ~/.xinitrc
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
#
|
#
|
||||||
@@ -436,10 +352,11 @@ cat << 'EOF' > ~/.xinitrc
|
|||||||
#
|
#
|
||||||
# Executed by startx (run your window manager from here)
|
# Executed by startx (run your window manager from here)
|
||||||
|
|
||||||
[[ -f ~/.Xresources ]] && xrdb -merge -I$HOME ~/.Xresources
|
[[ -f ~/.Xresources ]] && xrdb -merge -I\$HOME ~/.Xresources
|
||||||
|
|
||||||
if [ -d /etc/X11/xinit/xinitrc.d ]; then
|
if [ -d /etc/X11/xinit/xinitrc.d ]; then
|
||||||
for f in /etc/X11/xinit/xinitrc.d/*; do
|
for f in /etc/X11/xinit/xinitrc.d/*; do
|
||||||
|
# shellcheck disable=SC2154
|
||||||
[ -x "$f" ] && . "$f"
|
[ -x "$f" ] && . "$f"
|
||||||
done
|
done
|
||||||
unset f
|
unset f
|
||||||
@@ -447,9 +364,8 @@ fi
|
|||||||
|
|
||||||
[ -f /etc/xprofile ] && . /etc/xprofile
|
[ -f /etc/xprofile ] && . /etc/xprofile
|
||||||
[ -f ~/.xprofile ] && . ~/.xprofile
|
[ -f ~/.xprofile ] && . ~/.xprofile
|
||||||
|
|
||||||
exec dbus-run-session -- i3
|
|
||||||
EOF
|
EOF
|
||||||
|
echo "$sessionCommand" >> ~/.xinitrc
|
||||||
chmod +x ~/.xinitrc
|
chmod +x ~/.xinitrc
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -472,8 +388,35 @@ EOF
|
|||||||
exit 0
|
exit 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
apply_screenlock_pin() {
|
||||||
|
local pinFile="${i3Path}/.screenpin"
|
||||||
|
local pinValue="$screenlockPinHash"
|
||||||
|
|
||||||
|
if [[ -z "$pinValue" ]]; then
|
||||||
|
rm -f "$pinFile"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf "%s\n" "$pinValue" > "$pinFile"
|
||||||
|
chmod 600 "$pinFile"
|
||||||
|
}
|
||||||
|
|
||||||
update_scripts() {
|
update_scripts() {
|
||||||
|
local existingPinHash=""
|
||||||
|
local pinFile="${i3Path}/.screenpin"
|
||||||
|
if [[ -f "$pinFile" ]]; then
|
||||||
|
read -r existingPinHash < "$pinFile"
|
||||||
|
fi
|
||||||
|
if [[ -z "$existingPinHash" ]] && [[ -f "$configFile" ]]; then
|
||||||
|
# shellcheck source=/dev/null
|
||||||
|
source "$configFile"
|
||||||
|
existingPinHash="$screenlockPinHash"
|
||||||
|
fi
|
||||||
cp -rv scripts/ "${i3Path}/" | dialog --backtitle "I38" --progressbox "Updating scripts..." -1 -1
|
cp -rv scripts/ "${i3Path}/" | dialog --backtitle "I38" --progressbox "Updating scripts..." -1 -1
|
||||||
|
if [[ -n "$existingPinHash" ]]; then
|
||||||
|
screenlockPinHash="$existingPinHash"
|
||||||
|
apply_screenlock_pin
|
||||||
|
fi
|
||||||
exit 0
|
exit 0
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -589,132 +532,114 @@ if [[ -z "$volumeJump" ]]; then
|
|||||||
fi
|
fi
|
||||||
# Screen Reader
|
# Screen Reader
|
||||||
if [[ -z "$screenReader" ]] || ! command -v "$screenReader" &> /dev/null; then
|
if [[ -z "$screenReader" ]] || ! command -v "$screenReader" &> /dev/null; then
|
||||||
unset programList
|
programList=()
|
||||||
for i in cthulhu orca ; do
|
for i in cthulhu orca ; do
|
||||||
if command -v ${i/#-/} &> /dev/null ; then
|
if command -v "${i/#-/}" &> /dev/null ; then
|
||||||
if [ -n "$programList" ]; then
|
programList+=("$i")
|
||||||
programList="$programList $i"
|
|
||||||
else
|
|
||||||
programList="$i"
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
if [ "$programList" != "${programList// /}" ]; then
|
if [[ ${#programList[@]} -gt 1 ]]; then
|
||||||
screenReader="$(menulist ":Screen Reader" $programList)"
|
screenReader="$(menulist ":Screen Reader" "${programList[@]}")"
|
||||||
else
|
else
|
||||||
screenReader="${programList/#-/}"
|
screenReader="${programList[0]#-}"
|
||||||
fi
|
fi
|
||||||
export screenReader="$(command -v $screenReader)"
|
screenReader="$(command -v "$screenReader")"
|
||||||
|
export screenReader
|
||||||
else
|
else
|
||||||
# Validate and export existing preference
|
# Validate and export existing preference
|
||||||
export screenReader
|
export screenReader
|
||||||
fi
|
fi
|
||||||
# Email client
|
# Email client
|
||||||
if [[ -z "$emailClient" ]] || ! command -v "$emailClient" &> /dev/null; then
|
if [[ -z "$emailClient" ]] || ! command -v "$emailClient" &> /dev/null; then
|
||||||
unset programList
|
programList=()
|
||||||
for i in betterbird evolution thunderbird ; do
|
for i in betterbird evolution thunderbird ; do
|
||||||
if command -v ${i/#-/} &> /dev/null ; then
|
if command -v "${i/#-/}" &> /dev/null ; then
|
||||||
if [ -n "$programList" ]; then
|
programList+=("$i")
|
||||||
programList="$programList $i"
|
|
||||||
else
|
|
||||||
programList="$i"
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
if [ "$programList" != "${programList// /}" ]; then
|
if [[ ${#programList[@]} -gt 1 ]]; then
|
||||||
emailClient="$(menulist "Email client:" $programList)"
|
emailClient="$(menulist "Email client:" "${programList[@]}")"
|
||||||
else
|
else
|
||||||
emailClient="${programList/#-/}"
|
emailClient="${programList[0]#-}"
|
||||||
fi
|
fi
|
||||||
export emailClient="$(command -v $emailClient)"
|
emailClient="$(command -v "$emailClient")"
|
||||||
|
export emailClient
|
||||||
else
|
else
|
||||||
# Validate and export existing preference
|
# Validate and export existing preference
|
||||||
export emailClient
|
export emailClient
|
||||||
fi
|
fi
|
||||||
# Web browser
|
# Web browser
|
||||||
if [[ -z "$webBrowser" ]] || ! command -v "$webBrowser" &> /dev/null; then
|
if [[ -z "$webBrowser" ]] || ! command -v "$webBrowser" &> /dev/null; then
|
||||||
unset programList
|
programList=()
|
||||||
for i in brave chromium epiphany firefox google-chrome-stable google-chrome-unstable microsoft-edge-stable microsoft-edge-beta microsoft-edge-dev midori seamonkey vivaldi ; do
|
for i in brave chromium epiphany firefox google-chrome-stable google-chrome-unstable microsoft-edge-stable microsoft-edge-beta microsoft-edge-dev midori seamonkey vivaldi ; do
|
||||||
if command -v ${i/#-/} &> /dev/null ; then
|
if command -v "${i/#-/}" &> /dev/null ; then
|
||||||
if [ -n "$programList" ]; then
|
programList+=("$i")
|
||||||
programList="$programList $i"
|
|
||||||
else
|
|
||||||
programList="$i"
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
if [ "$programList" != "${programList// /}" ]; then
|
if [[ ${#programList[@]} -gt 1 ]]; then
|
||||||
webBrowser="$(menulist "Web browser:" $programList)"
|
webBrowser="$(menulist "Web browser:" "${programList[@]}")"
|
||||||
else
|
else
|
||||||
webBrowser="${programList/#-/}"
|
webBrowser="${programList[0]#-}"
|
||||||
fi
|
fi
|
||||||
export webBrowser="$(command -v $webBrowser)"
|
webBrowser="$(command -v "$webBrowser")"
|
||||||
|
export webBrowser
|
||||||
else
|
else
|
||||||
# Validate and export existing preference
|
# Validate and export existing preference
|
||||||
export webBrowser
|
export webBrowser
|
||||||
fi
|
fi
|
||||||
# Text editor
|
# Text editor
|
||||||
if [[ -z "$textEditor" ]] || ! command -v "$textEditor" &> /dev/null; then
|
if [[ -z "$textEditor" ]] || ! command -v "$textEditor" &> /dev/null; then
|
||||||
unset programList
|
programList=()
|
||||||
for i in emacs geany gedit kate kwrite l3afpad leafpad libreoffice mousepad pluma ; do
|
for i in emacs geany gedit kate kwrite l3afpad leafpad libreoffice mousepad pluma ; do
|
||||||
if hash ${i/#-/} &> /dev/null ; then
|
if command -v "${i/#-/}" &> /dev/null ; then
|
||||||
if [ -n "$programList" ]; then
|
programList+=("$i")
|
||||||
programList="$programList $i"
|
|
||||||
else
|
|
||||||
programList="$i"
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
if [ "$programList" != "${programList// /}" ]; then
|
if [[ ${#programList[@]} -gt 1 ]]; then
|
||||||
textEditor="$(menulist "Text editor:" $programList)"
|
textEditor="$(menulist "Text editor:" "${programList[@]}")"
|
||||||
else
|
else
|
||||||
textEditor="${programList/#-/}"
|
textEditor="${programList[0]#-}"
|
||||||
fi
|
fi
|
||||||
export textEditor="$(command -v $textEditor)"
|
textEditor="$(command -v "$textEditor")"
|
||||||
|
export textEditor
|
||||||
else
|
else
|
||||||
# Validate and export existing preference
|
# Validate and export existing preference
|
||||||
export textEditor
|
export textEditor
|
||||||
fi
|
fi
|
||||||
# File browser
|
# File browser
|
||||||
if [[ -z "$fileBrowser" ]] || ! command -v "$fileBrowser" &> /dev/null; then
|
if [[ -z "$fileBrowser" ]] || ! command -v "$fileBrowser" &> /dev/null; then
|
||||||
unset programList
|
programList=()
|
||||||
for i in caja nemo nautilus pcmanfm pcmanfm-qt thunar ; do
|
for i in caja nemo nautilus pcmanfm pcmanfm-qt thunar ; do
|
||||||
if hash ${i/#-/} &> /dev/null ; then
|
if command -v "${i/#-/}" &> /dev/null ; then
|
||||||
if [ -n "$programList" ]; then
|
programList+=("$i")
|
||||||
programList="$programList $i"
|
|
||||||
else
|
|
||||||
programList="$i"
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
if [ "$programList" != "${programList// /}" ]; then
|
if [[ ${#programList[@]} -gt 1 ]]; then
|
||||||
fileBrowser="$(menulist "File browser:" $programList)"
|
fileBrowser="$(menulist "File browser:" "${programList[@]}")"
|
||||||
else
|
else
|
||||||
fileBrowser="${programList/#-/}"
|
fileBrowser="${programList[0]#-}"
|
||||||
fi
|
fi
|
||||||
export fileBrowser="$(command -v $fileBrowser)"
|
fileBrowser="$(command -v "$fileBrowser")"
|
||||||
|
export fileBrowser
|
||||||
else
|
else
|
||||||
# Validate and export existing preference
|
# Validate and export existing preference
|
||||||
export fileBrowser
|
export fileBrowser
|
||||||
fi
|
fi
|
||||||
# IRC client
|
# IRC client
|
||||||
if [[ -z "$ircClient" ]] || ! command -v "$ircClient" &> /dev/null; then
|
if [[ -z "$ircClient" ]] || ! command -v "$ircClient" &> /dev/null; then
|
||||||
unset programList
|
programList=()
|
||||||
for i in albikirc Albikirc access-irc ; do
|
for i in albikirc Albikirc access-irc ; do
|
||||||
if command -v ${i/#-/} &> /dev/null ; then
|
if command -v "${i/#-/}" &> /dev/null ; then
|
||||||
if [ -n "$programList" ]; then
|
programList+=("$i")
|
||||||
programList="$programList $i"
|
|
||||||
else
|
|
||||||
programList="$i"
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
if [ "$programList" != "${programList// /}" ]; then
|
if [[ ${#programList[@]} -gt 1 ]]; then
|
||||||
ircClient="$(menulist "IRC client:" $programList)"
|
ircClient="$(menulist "IRC client:" "${programList[@]}")"
|
||||||
else
|
else
|
||||||
ircClient="${programList/#-/}"
|
ircClient="${programList[0]#-}"
|
||||||
fi
|
fi
|
||||||
export ircClient="$(command -v $ircClient)"
|
ircClient="$(command -v "$ircClient")"
|
||||||
|
export ircClient
|
||||||
else
|
else
|
||||||
# Validate and export existing preference
|
# Validate and export existing preference
|
||||||
export ircClient
|
export ircClient
|
||||||
@@ -742,7 +667,7 @@ if [[ -z "$dex" ]]; then
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
if [[ $dex -eq 0 ]]; then
|
if [[ $dex -eq 0 ]]; then
|
||||||
dex -t "${XDG_CONFIG_HOME:-${HOME}/.config}/autostart" -c $(command -v $screenReader)
|
dex -t "${XDG_CONFIG_HOME:-${HOME}/.config}/autostart" -c "$(command -v "$screenReader")"
|
||||||
fi
|
fi
|
||||||
if [[ -z "$batteryAlert" ]]; then
|
if [[ -z "$batteryAlert" ]]; then
|
||||||
if command -v acpi &> /dev/null ; then
|
if command -v acpi &> /dev/null ; then
|
||||||
@@ -767,9 +692,65 @@ if [[ -z "$sounds" ]]; then
|
|||||||
sounds=1
|
sounds=1
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
# Custom applications for ratpoison mode
|
if [[ -z "$screenlockPinHash" ]]; then
|
||||||
if [[ ${#customApps[@]} -eq 0 ]]; then
|
screenlockPinFile="${i3Path}/.screenpin"
|
||||||
addCustomApplication
|
if [[ -f "$screenlockPinFile" ]]; then
|
||||||
|
read -r screenlockPinHash < "$screenlockPinFile"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
if [[ -z "$screenlockPinHash" ]]; then
|
||||||
|
if yesno "Do you want to enable the I38 screen lock (privacy screen only, not a secure system lock)?"; then
|
||||||
|
while : ; do
|
||||||
|
screenlockPin="$(dialog --title "I38" --clear --passwordbox "Enter a 4-digit PIN to enable screen lock." -1 -1 --stdout)"
|
||||||
|
dialogResult=$?
|
||||||
|
if [[ $dialogResult -ne 0 ]]; then
|
||||||
|
screenlockPinHash=""
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
if [[ ! "$screenlockPin" =~ ^[0-9]{4}$ ]]; then
|
||||||
|
dialog --title "I38" --msgbox "PIN must be exactly 4 digits." -1 -1
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
screenlockPinConfirm="$(dialog --title "I38" --clear --passwordbox "Re-enter the 4-digit PIN to confirm." -1 -1 --stdout)"
|
||||||
|
dialogResult=$?
|
||||||
|
if [[ $dialogResult -ne 0 ]]; then
|
||||||
|
screenlockPinHash=""
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
if [[ "$screenlockPin" != "$screenlockPinConfirm" ]]; then
|
||||||
|
dialog --title "I38" --msgbox "PINs do not match. Please try again." -1 -1
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
screenlockPinHash="$(printf "%s" "$screenlockPin" | sha512sum | awk '{print $1}')"
|
||||||
|
unset screenlockPin screenlockPinConfirm
|
||||||
|
break
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
# Personal mode
|
||||||
|
personalModeExists=1
|
||||||
|
if personal_mode_exists; then
|
||||||
|
personalModeExists=0
|
||||||
|
personalModeEnabled=0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ $personalModeExists -ne 0 ]]; then
|
||||||
|
if yesno "Would you like a Personal mode?"; then
|
||||||
|
personalModeEnabled=0
|
||||||
|
else
|
||||||
|
personalModeEnabled=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$personalModeEnabled" -eq 0 ]]; then
|
||||||
|
if [[ -z "$personalModeKey" ]] || [[ "$personalModeKey" == "$escapeKey" ]]; then
|
||||||
|
personalModeKey="$(select_personal_mode_key)"
|
||||||
|
fi
|
||||||
|
if [[ -z "$personalModeKey" ]]; then
|
||||||
|
personalModeEnabled=1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Save configuration if requested (only on first run)
|
# Save configuration if requested (only on first run)
|
||||||
@@ -788,8 +769,10 @@ write_waytray_config
|
|||||||
mkdir -p "${i3Path}"
|
mkdir -p "${i3Path}"
|
||||||
# Move scripts into place
|
# Move scripts into place
|
||||||
cp -rv scripts/ "${i3Path}/" | dialog --backtitle "I38" --progressbox "Moving scripts into place and writing config..." -1 -1
|
cp -rv scripts/ "${i3Path}/" | dialog --backtitle "I38" --progressbox "Moving scripts into place and writing config..." -1 -1
|
||||||
|
apply_screenlock_pin
|
||||||
|
update_personal_customizations
|
||||||
|
|
||||||
cat << EOF > ${i3Path}/config
|
cat << EOF > "${i3Path}/config"
|
||||||
# Generated by I38 (${0##*/}) https://git.stormux.org/storm/I38
|
# Generated by I38 (${0##*/}) https://git.stormux.org/storm/I38
|
||||||
# $(date '+%A, %B %d, %Y at %I:%M%p')
|
# $(date '+%A, %B %d, %Y at %I:%M%p')
|
||||||
EOF
|
EOF
|
||||||
@@ -797,13 +780,13 @@ EOF
|
|||||||
# If we are using Sway, we need to load in the system configuration
|
# If we are using Sway, we need to load in the system configuration
|
||||||
# Usually, this is for system specific dBus things that the distro knows how to manage; we should trust their judgment with that
|
# Usually, this is for system specific dBus things that the distro knows how to manage; we should trust their judgment with that
|
||||||
if [[ $usingSway ]] && [[ -d "${swaySystemIncludesPath}" ]]; then
|
if [[ $usingSway ]] && [[ -d "${swaySystemIncludesPath}" ]]; then
|
||||||
cat << EOF >> ${i3Path}/config
|
cat << EOF >> "${i3Path}/config"
|
||||||
# Include your distribution Sway configuration files.
|
# Include your distribution Sway configuration files.
|
||||||
include ${swaySystemIncludesPath}/*
|
include ${swaySystemIncludesPath}/*
|
||||||
EOF
|
EOF
|
||||||
fi
|
fi
|
||||||
|
|
||||||
cat << EOF >> ${i3Path}/config
|
cat << EOF >> "${i3Path}/config"
|
||||||
# i3 config file (v4)
|
# i3 config file (v4)
|
||||||
#
|
#
|
||||||
# Please see https://i3wm.org/docs/userguide.html for a complete reference!
|
# Please see https://i3wm.org/docs/userguide.html for a complete reference!
|
||||||
@@ -972,18 +955,29 @@ bindsym $mod+Shift+BackSpace mode "default"
|
|||||||
|
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
|
if [[ -n "$screenlockPinHash" ]]; then
|
||||||
|
cat << EOF >> "${i3Path}/config"
|
||||||
|
# Screen lock mode (managed by screenlock.sh)
|
||||||
|
mode "screenlock" {
|
||||||
|
bindsym Escape nop
|
||||||
|
bindsym Control+g nop
|
||||||
|
}
|
||||||
|
|
||||||
|
EOF
|
||||||
|
fi
|
||||||
|
|
||||||
# Perform OCR on screen
|
# Perform OCR on screen
|
||||||
echo "bindsym ${mod}+F5 exec ${i3Path}/scripts/ocr.py" >> ${i3Path}/config
|
echo "bindsym ${mod}+F5 exec ${i3Path}/scripts/ocr.py" >> "${i3Path}/config"
|
||||||
# Interrupt speech output
|
# Interrupt speech output
|
||||||
echo "bindsym ${mod}+Shift+F5 exec spd-say -C" >> ${i3Path}/config
|
echo "bindsym ${mod}+Shift+F5 exec spd-say -C" >> "${i3Path}/config"
|
||||||
|
|
||||||
# Multiple keyboard layouts if requested.
|
# Multiple keyboard layouts if requested.
|
||||||
if [[ ${#kbd[@]} -gt 1 ]]; then
|
if [[ ${#kbd[@]} -gt 1 ]]; then
|
||||||
echo "bindsym Mod4+space exec ${i3Path}/scripts/keyboard.sh cycle ${kbd[*]}" >> ${i3Path}/config
|
echo "bindsym Mod4+space exec ${i3Path}/scripts/keyboard.sh cycle ${kbd[*]}" >> "${i3Path}/config"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Create panel mode
|
# Create panel mode
|
||||||
cat << EOF >> ${i3Path}/config
|
cat << EOF >> "${i3Path}/config"
|
||||||
# Panel mode configuration
|
# Panel mode configuration
|
||||||
bindsym Control+Mod1+Tab mode "panel"
|
bindsym Control+Mod1+Tab mode "panel"
|
||||||
mode "panel" {
|
mode "panel" {
|
||||||
@@ -1023,9 +1017,13 @@ fi)
|
|||||||
# Detailed battery information bound to Shift+b
|
# Detailed battery information bound to Shift+b
|
||||||
bindsym Shift+b exec --no-startup-id ${i3Path}/scripts/battery_status.sh --detailed, mode "default"
|
bindsym Shift+b exec --no-startup-id ${i3Path}/scripts/battery_status.sh --detailed, mode "default"
|
||||||
|
|
||||||
$(if command -v lxsession-logout &> /dev/null ; then
|
# Power options bound to p
|
||||||
echo "# Power options bound to p"
|
bindsym p exec --no-startup-id ${i3Path}/scripts/power.sh, mode "default"
|
||||||
echo "bindsym p exec --no-startup-id lxsession-logout, mode \"default\""
|
|
||||||
|
$(if [[ -n "$screenlockPinHash" ]]; then
|
||||||
|
echo " # Screen lock (privacy screen only)"
|
||||||
|
echo " bindsym Control+\$mod+l exec --no-startup-id ${i3Path}/scripts/screenlock.sh, mode \"default\""
|
||||||
|
echo " "
|
||||||
fi)
|
fi)
|
||||||
|
|
||||||
# Exit panel mode without any action
|
# Exit panel mode without any action
|
||||||
@@ -1036,7 +1034,7 @@ EOF
|
|||||||
|
|
||||||
# Create ratpoison mode if requested.
|
# Create ratpoison mode if requested.
|
||||||
if [[ -n "${escapeKey}" ]]; then
|
if [[ -n "${escapeKey}" ]]; then
|
||||||
cat << EOF >> ${i3Path}/config
|
cat << EOF >> "${i3Path}/config"
|
||||||
# Enter ratpoison mode
|
# Enter ratpoison mode
|
||||||
bindsym $escapeKey mode "ratpoison"
|
bindsym $escapeKey mode "ratpoison"
|
||||||
mode "ratpoison" {
|
mode "ratpoison" {
|
||||||
@@ -1107,24 +1105,14 @@ bindsym Shift+o exec $(command -v orca) --replace, mode "default"
|
|||||||
bindsym Shift+t exec ${i3Path}/scripts/toggle_screenreader.sh, mode "default"
|
bindsym Shift+t exec ${i3Path}/scripts/toggle_screenreader.sh, mode "default"
|
||||||
$(if [[ $usingSway -eq 0 ]]; then
|
$(if [[ $usingSway -eq 0 ]]; then
|
||||||
echo "# reload the configuration file"
|
echo "# reload the configuration file"
|
||||||
echo "bindsym Control+semicolon exec bash -c '$i3msg -t command reload && spd-say -P important -Cw "I38 Configuration reloaded."', mode "default""
|
echo "bindsym Control+semicolon exec bash -c '$i3msg -t command reload && spd-say -P important -Cw \"I38 Configuration reloaded.\"', mode \"default\""
|
||||||
|
|
||||||
else
|
else
|
||||||
echo "# reload the configuration file"
|
echo "# reload the configuration file"
|
||||||
echo "bindsym Control+semicolon exec bash -c '$i3msg -t run_command reload && spd-say -P important -Cw "I38 Configuration reloaded."', mode "default""
|
echo "bindsym Control+semicolon exec bash -c '$i3msg -t run_command reload && spd-say -P important -Cw \"I38 Configuration reloaded.\"', mode \"default\""
|
||||||
echo "# restart i3 inplace (preserves your layout/session, can be used to upgrade i3)"
|
echo "# restart i3 inplace (preserves your layout/session, can be used to upgrade i3)"
|
||||||
echo "bindsym Control+Shift+semicolon exec $i3msg -t run_command restart && spd-say -P important -Cw "I3 restarted.", mode "default""
|
echo "bindsym Control+Shift+semicolon exec $i3msg -t run_command restart && spd-say -P important -Cw \"I3 restarted.\", mode \"default\""
|
||||||
fi)
|
fi)
|
||||||
# Custom applications
|
|
||||||
$(for app in "${customApps[@]}"; do
|
|
||||||
IFS='|' read -r appName appCommand appFlags appKey <<< "$app"
|
|
||||||
echo "# $appName bound to $appKey"
|
|
||||||
if [[ -n "$appFlags" ]]; then
|
|
||||||
echo "bindsym $appKey exec $appCommand $appFlags, mode \"default\""
|
|
||||||
else
|
|
||||||
echo "bindsym $appKey exec $appCommand, mode \"default\""
|
|
||||||
fi
|
|
||||||
done)
|
|
||||||
# Run dialog with exclamation
|
# Run dialog with exclamation
|
||||||
bindsym Shift+exclam exec ${i3Path}/scripts/run_dialog.sh, mode "default"
|
bindsym Shift+exclam exec ${i3Path}/scripts/run_dialog.sh, mode "default"
|
||||||
# exit i3 (logs you out of your X session)
|
# exit i3 (logs you out of your X session)
|
||||||
@@ -1140,7 +1128,7 @@ EOF
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
cat << EOF >> ${i3Path}/config
|
cat << EOF >> "${i3Path}/config"
|
||||||
# Auto start section
|
# Auto start section
|
||||||
$(if [[ $sounds -eq 0 ]]; then
|
$(if [[ $sounds -eq 0 ]]; then
|
||||||
if [[ $usingSway -eq 0 ]]; then
|
if [[ $usingSway -eq 0 ]]; then
|
||||||
|
|||||||
65
scripts/i38-help-personal.sh
Executable file
65
scripts/i38-help-personal.sh
Executable file
@@ -0,0 +1,65 @@
|
|||||||
|
#!/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/>.
|
||||||
|
|
||||||
|
configPath="$(readlink -f "$0")"
|
||||||
|
configPath="${configPath%/*/*}"
|
||||||
|
customizationsPath="${configPath}/customizations"
|
||||||
|
|
||||||
|
if [[ -f "${configPath}/config" ]]; then
|
||||||
|
mod="$(grep "set \$mod " "${configPath}/config" | cut -d ' ' -f3)"
|
||||||
|
mod="${mod//Mod1/Alt}"
|
||||||
|
mod="${mod//Mod4/Super}"
|
||||||
|
else
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ! -f "$customizationsPath" ]] || ! grep -q '^mode "personal"' "$customizationsPath"; then
|
||||||
|
message="Personal mode bindings were not found. Check ${customizationsPath}."
|
||||||
|
echo -e "$message" | yad --text-info --show-cursor --title "I38 - Personal Mode Help" --button "Close:0" --listen
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
personalModeKey="$(grep -m1 -E '^bindsym[[:space:]]+.*mode "personal"' "$customizationsPath" | \
|
||||||
|
sed -e 's/^bindsym[[:space:]]*//' -e 's/[[:space:]]*mode "personal".*$//')"
|
||||||
|
if [[ -n "$personalModeKey" ]]; then
|
||||||
|
personalModeKey="${personalModeKey//\$mod/$mod}"
|
||||||
|
personalModeKey="${personalModeKey//Mod1/Alt}"
|
||||||
|
personalModeKey="${personalModeKey//Mod4/Super}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
mapfile helpText < <(sed -n '/^mode "personal"/,/^}$/p' "$customizationsPath" | \
|
||||||
|
sed -e '/^mode "personal"/d' \
|
||||||
|
-e '/^}$/d' \
|
||||||
|
-e 's/bindsym/Key:/g' \
|
||||||
|
-e 's/Mod1/Alt/g' \
|
||||||
|
-e 's/, mode "default"//g' \
|
||||||
|
-e 's/--no-startup-id //g' \
|
||||||
|
-e "s/\$mod/$mod/g")
|
||||||
|
|
||||||
|
for i in "${!helpText[@]}" ; do
|
||||||
|
helpText[i]="${helpText[i]//${configPath}\/scripts\//}"
|
||||||
|
helpText[i]="${helpText[i]/.sh/}"
|
||||||
|
helpText[i]="${helpText[i]/.py/}"
|
||||||
|
done
|
||||||
|
|
||||||
|
header="Personal Mode Keybindings\n\n"
|
||||||
|
if [[ -n "$personalModeKey" ]]; then
|
||||||
|
header+="Press ${personalModeKey} to enter personal mode, then use these shortcuts:\n\n"
|
||||||
|
else
|
||||||
|
header+="Use these shortcuts while in personal mode:\n\n"
|
||||||
|
fi
|
||||||
|
|
||||||
|
helpText=("$header" "${helpText[@]}" "End of personal mode help. Press Control+Home to jump to the beginning.")
|
||||||
|
|
||||||
|
echo -e "${helpText[@]}" | yad --text-info --show-cursor --title "I38 - Personal Mode Help" --button "Close:0" --listen
|
||||||
|
|
||||||
|
exit 0
|
||||||
160
scripts/power.sh
Executable file
160
scripts/power.sh
Executable file
@@ -0,0 +1,160 @@
|
|||||||
|
#!/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/>.
|
||||||
|
|
||||||
|
if ! command -v yad &> /dev/null; then
|
||||||
|
echo "yad is required for power options."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
action="$(yad --title "I38" --text "Power options" --list \
|
||||||
|
--column "Action" --column "Description" \
|
||||||
|
"Power off" "Shut down the system" \
|
||||||
|
"Reboot" "Restart the system" \
|
||||||
|
"Log out" "Exit the current session" \
|
||||||
|
--print-column=1 --separator="" --button "Select:0" --button "Cancel:1")"
|
||||||
|
|
||||||
|
yadResult=$?
|
||||||
|
if [[ $yadResult -ne 0 ]]; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$action" in
|
||||||
|
"Power off")
|
||||||
|
powerAction="poweroff"
|
||||||
|
login1Method="PowerOff"
|
||||||
|
consolekitMethod="Stop"
|
||||||
|
;;
|
||||||
|
"Reboot")
|
||||||
|
powerAction="reboot"
|
||||||
|
login1Method="Reboot"
|
||||||
|
consolekitMethod="Restart"
|
||||||
|
;;
|
||||||
|
"Log out")
|
||||||
|
powerAction="logout"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
confirmAction() {
|
||||||
|
local promptText="$1"
|
||||||
|
yad --title "I38" --text "$promptText" --button "Yes:0" --button "No:1"
|
||||||
|
return $?
|
||||||
|
}
|
||||||
|
|
||||||
|
case "$powerAction" in
|
||||||
|
"poweroff")
|
||||||
|
confirmAction "Power off the system now?" || exit 0
|
||||||
|
;;
|
||||||
|
"reboot")
|
||||||
|
confirmAction "Reboot the system now?" || exit 0
|
||||||
|
;;
|
||||||
|
"logout")
|
||||||
|
confirmAction "Log out of the current session now?" || exit 0
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
try_logout() {
|
||||||
|
if [[ -n "${SWAYSOCK:-}" ]] && command -v swaymsg &> /dev/null; then
|
||||||
|
swaymsg -t command exit &> /dev/null
|
||||||
|
return $?
|
||||||
|
fi
|
||||||
|
if [[ -n "${I3SOCK:-}" ]] && command -v i3-msg &> /dev/null; then
|
||||||
|
i3-msg -t command exit &> /dev/null
|
||||||
|
return $?
|
||||||
|
fi
|
||||||
|
if command -v swaymsg &> /dev/null; then
|
||||||
|
swaymsg -t command exit &> /dev/null
|
||||||
|
return $?
|
||||||
|
fi
|
||||||
|
if command -v i3-msg &> /dev/null; then
|
||||||
|
i3-msg -t command exit &> /dev/null
|
||||||
|
return $?
|
||||||
|
fi
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
try_loginctl() {
|
||||||
|
command -v loginctl &> /dev/null || return 1
|
||||||
|
loginctl "$powerAction" --no-ask-password &> /dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
try_systemctl() {
|
||||||
|
command -v systemctl &> /dev/null || return 1
|
||||||
|
systemctl "$powerAction" --no-ask-password &> /dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
try_gdbus_login1() {
|
||||||
|
command -v gdbus &> /dev/null || return 1
|
||||||
|
gdbus call --system \
|
||||||
|
--dest org.freedesktop.login1 \
|
||||||
|
--object-path /org/freedesktop/login1 \
|
||||||
|
--method "org.freedesktop.login1.Manager.${login1Method}" false \
|
||||||
|
&> /dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
try_gdbus_consolekit() {
|
||||||
|
command -v gdbus &> /dev/null || return 1
|
||||||
|
gdbus call --system \
|
||||||
|
--dest org.freedesktop.ConsoleKit \
|
||||||
|
--object-path /org/freedesktop/ConsoleKit/Manager \
|
||||||
|
--method "org.freedesktop.ConsoleKit.Manager.${consolekitMethod}" \
|
||||||
|
&> /dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
try_dbus_send_login1() {
|
||||||
|
command -v dbus-send &> /dev/null || return 1
|
||||||
|
dbus-send --system --print-reply \
|
||||||
|
--dest=org.freedesktop.login1 \
|
||||||
|
/org/freedesktop/login1 \
|
||||||
|
"org.freedesktop.login1.Manager.${login1Method}" \
|
||||||
|
boolean:false \
|
||||||
|
&> /dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
try_dbus_send_consolekit() {
|
||||||
|
command -v dbus-send &> /dev/null || return 1
|
||||||
|
dbus-send --system --print-reply \
|
||||||
|
--dest=org.freedesktop.ConsoleKit \
|
||||||
|
/org/freedesktop/ConsoleKit/Manager \
|
||||||
|
"org.freedesktop.ConsoleKit.Manager.${consolekitMethod}" \
|
||||||
|
&> /dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
try_shutdown() {
|
||||||
|
command -v shutdown &> /dev/null || return 1
|
||||||
|
if [[ "$powerAction" == "poweroff" ]]; then
|
||||||
|
shutdown -h now &> /dev/null
|
||||||
|
else
|
||||||
|
shutdown -r now &> /dev/null
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
try_direct() {
|
||||||
|
command -v "$powerAction" &> /dev/null || return 1
|
||||||
|
"$powerAction" &> /dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
if [[ "$powerAction" == "logout" ]]; then
|
||||||
|
if try_logout; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
if try_loginctl || try_systemctl || try_gdbus_login1 || try_dbus_send_login1 || \
|
||||||
|
try_gdbus_consolekit || try_dbus_send_consolekit || try_shutdown || try_direct; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
yad --title "I38" --text "Power action failed. You may need permission or a polkit agent to continue." --button "Close:0"
|
||||||
|
exit 1
|
||||||
100
scripts/screenlock.sh
Executable file
100
scripts/screenlock.sh
Executable file
@@ -0,0 +1,100 @@
|
|||||||
|
#!/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/>.
|
||||||
|
|
||||||
|
screenlockPinHash=""
|
||||||
|
scriptPath="$(readlink -f "$0")"
|
||||||
|
scriptDir="${scriptPath%/*}"
|
||||||
|
i3Path="${scriptDir%/scripts}"
|
||||||
|
pinFile="${i3Path}/.screenpin"
|
||||||
|
|
||||||
|
if [[ -f "$pinFile" ]]; then
|
||||||
|
read -r screenlockPinHash < "$pinFile"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -z "$screenlockPinHash" ]]; then
|
||||||
|
yad --title "I38" --text "Screen lock is not configured. Run i38.sh and set a 4-digit PIN to enable it." --button "Close:0"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! command -v yad &> /dev/null; then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! command -v jq &> /dev/null; then
|
||||||
|
yad --title "I38" --text "Screen lock requires jq to determine the current workspace." --button "Close:0"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! command -v sha512sum &> /dev/null; then
|
||||||
|
yad --title "I38" --text "Screen lock requires sha512sum to validate the PIN." --button "Close:0"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
wmMsg="i3-msg"
|
||||||
|
if [[ -n "${SWAYSOCK:-}" ]] && command -v swaymsg &> /dev/null; then
|
||||||
|
wmMsg="swaymsg"
|
||||||
|
elif [[ -n "${I3SOCK:-}" ]] && command -v i3-msg &> /dev/null; then
|
||||||
|
wmMsg="i3-msg"
|
||||||
|
elif command -v swaymsg &> /dev/null; then
|
||||||
|
wmMsg="swaymsg"
|
||||||
|
elif command -v i3-msg &> /dev/null; then
|
||||||
|
wmMsg="i3-msg"
|
||||||
|
else
|
||||||
|
yad --title "I38" --text "No i3 or sway command interface was found for screen lock." --button "Close:0"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
currentWorkspace="$($wmMsg -t get_workspaces | jq -r '.[] | select(.focused==true) | .name')"
|
||||||
|
lockWorkspace="i38-lock"
|
||||||
|
if $wmMsg -t get_workspaces | jq -e --arg name "$lockWorkspace" '.[] | select(.name==$name)' &> /dev/null; then
|
||||||
|
lockWorkspace="i38-lock-$$"
|
||||||
|
fi
|
||||||
|
|
||||||
|
$wmMsg -t command "workspace --no-auto-back-and-forth \"$lockWorkspace\"" &> /dev/null
|
||||||
|
$wmMsg -t command "mode screenlock" &> /dev/null
|
||||||
|
|
||||||
|
attemptCount=0
|
||||||
|
while : ; do
|
||||||
|
if [[ $attemptCount -eq 0 ]]; then
|
||||||
|
promptText="Screen lock is enabled. Enter your 4-digit PIN to unlock."
|
||||||
|
else
|
||||||
|
promptText="Incorrect PIN. Enter your 4-digit PIN to unlock."
|
||||||
|
fi
|
||||||
|
|
||||||
|
pinInput="$(yad --entry --hide-text --title "I38" --text "$promptText" --entry-label "Screen lock PIN" --button "Unlock:0" --on-top --sticky --skip-taskbar --fixed --center --undecorated --fullscreen --no-escape)"
|
||||||
|
yadResult=$?
|
||||||
|
if [[ $yadResult -ne 0 ]]; then
|
||||||
|
attemptCount=$((attemptCount + 1))
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ! "$pinInput" =~ ^[0-9]{4}$ ]]; then
|
||||||
|
attemptCount=$((attemptCount + 1))
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
pinHash="$(printf "%s" "$pinInput" | sha512sum | awk '{print $1}')"
|
||||||
|
unset pinInput
|
||||||
|
|
||||||
|
if [[ "$pinHash" == "$screenlockPinHash" ]]; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
|
||||||
|
attemptCount=$((attemptCount + 1))
|
||||||
|
done
|
||||||
|
|
||||||
|
$wmMsg -t command "mode default" &> /dev/null
|
||||||
|
if [[ -n "$currentWorkspace" ]]; then
|
||||||
|
$wmMsg -t command "workspace \"$currentWorkspace\"" &> /dev/null
|
||||||
|
fi
|
||||||
|
|
||||||
|
exit 0
|
||||||
@@ -71,12 +71,16 @@ def on_mode(self,event):
|
|||||||
mode = event.change
|
mode = event.change
|
||||||
if mode == 'ratpoison':
|
if mode == 'ratpoison':
|
||||||
play_sound_async('play -qV0 "|sox -np synth .07 sq 400" "|sox -np synth .5 sq 800" fade h 0 .5 .5 norm -20')
|
play_sound_async('play -qV0 "|sox -np synth .07 sq 400" "|sox -np synth .5 sq 800" fade h 0 .5 .5 norm -20')
|
||||||
|
elif mode == 'personal':
|
||||||
|
play_sound_async('play -nqV0 synth pl E3 pl B3 remix - fade h 0 .25 .2 overdrive riaa norm -12')
|
||||||
elif mode == 'bypass':
|
elif mode == 'bypass':
|
||||||
play_sound_async('play -nqV0 synth .1 saw 700 saw 1200 delay 0 .04 remix - norm -6')
|
play_sound_async('play -nqV0 synth .1 saw 700 saw 1200 delay 0 .04 remix - norm -6')
|
||||||
elif mode == 'default':
|
elif mode == 'default':
|
||||||
# Play different sounds based on which mode we're exiting
|
# Play different sounds based on which mode we're exiting
|
||||||
if currentMode == 'ratpoison':
|
if currentMode == 'ratpoison':
|
||||||
play_sound_async('play -qV0 "|sox -np synth .07 sq 400" "|sox -np synth .5 sq 800" fade h 0 .5 .5 norm -20 reverse')
|
play_sound_async('play -qV0 "|sox -np synth .07 sq 400" "|sox -np synth .5 sq 800" fade h 0 .5 .5 norm -20 reverse')
|
||||||
|
elif currentMode == 'personal':
|
||||||
|
play_sound_async('play -nqV0 synth pl E3 pl B3 remix - fade h 0 .25 .2 overdrive riaa norm -12 reverse')
|
||||||
elif currentMode == 'panel':
|
elif currentMode == 'panel':
|
||||||
play_sound_async('play -nqV0 synth 0.05 pluck C5 norm -8 : synth 0.05 pluck F4 norm -8 : synth 0.05 pluck C4 norm -8 : synth 0.05 pluck F3 norm -8')
|
play_sound_async('play -nqV0 synth 0.05 pluck C5 norm -8 : synth 0.05 pluck F4 norm -8 : synth 0.05 pluck C4 norm -8 : synth 0.05 pluck F3 norm -8')
|
||||||
elif currentMode == 'bypass':
|
elif currentMode == 'bypass':
|
||||||
|
|||||||
Reference in New Issue
Block a user