Added -d and -D flags to generate a default I38 setup. -D also creates the .xinitrc and .xprofiles. This is basically a silent mode with no prompts and uses the items it finds with other sane defaults, e.g. alt+escape for RP mode and control+escape for personal mode.

This commit is contained in:
Storm Dragon
2026-06-28 14:02:56 -04:00
parent d3fb549fd1
commit 19e1d458a3
4 changed files with 204 additions and 16 deletions
+4
View File
@@ -421,6 +421,10 @@ To update I38 on this system:
Running `./i38.sh` regenerates your I38 configuration and refreshes the installed scripts. Your personal shortcuts in `~/.config/i3/customizations` are preserved.
To generate the default configuration without prompts, use `./i38.sh -d`. To also generate `~/.xinitrc` and `~/.xprofile` without prompts, use `./i38.sh -D`.
Default configuration mode uses I38Lock when it is installed and supported by the screen-reader setup. In that case I38 locks on startup and autolocks after 5 minutes when `xprintidle` is available.
If you only need to copy the latest scripts and do not want to regenerate the full i3 configuration, you can use `./i38.sh -u` instead.
## Getting Help
+4
View File
@@ -111,11 +111,15 @@ You can apply the same configuration to GTK2 apps. Create or edit ~/.gtkrc-2.0
## Usage:
- With no arguments, create the i3 configuration.
- -d: Generate the default I38 configuration without prompting.
- -D: Generate the default I38 configuration plus ~/.xinitrc and ~/.xprofile without prompting.
- -h: Help screen.
- -u: Copy over the latest version of scripts.
- -x: Generate ~/.xinitrc and ~/.xprofile.
- -X: Generate ~/.xprofile only.
Default configuration mode uses I38Lock when it is installed and supported by the screen-reader setup. In that case I38 locks on startup and autolocks after 5 minutes when `xprintidle` is available.
## Dependency Helpers
Distro-specific dependency helpers live in `extra/`. On Arch Linux, run:
+122 -16
View File
@@ -16,6 +16,8 @@ i3msg="i3-msg"
configFile="${PWD}/I38_preferences.conf"
i38VersionFile="${i3Path}/i38-version"
i38CheckoutPath="${PWD}"
defaultConfig=0
defaultGenerateX=0
# Dialog accessibility
export DIALOGOPTS='--no-lines --visit-items'
@@ -184,10 +186,82 @@ rangebox() {
yesno() {
# Returns: Yes 0 or No 1
# Args: Question to user.
if [[ $defaultConfig -eq 1 ]]; then
return 0
fi
dialog --clear --title "I38" --yesno "$*" -1 -1 --stdout
return $?
}
first_available_program() {
local program
for program in "$@"; do
if command -v "${program#-}" &> /dev/null; then
printf '%s\n' "${program#-}"
return 0
fi
done
return 1
}
first_available_path() {
local program
if program="$(first_available_program "$@")"; then
command -v "$program"
fi
}
set_default_configuration() {
escapeKey="Mod1+Escape"
mod="Mod1"
kbd=()
volumeJump=5
i3FontSize=12
screenReader="$(first_available_path cthulhu orca || true)"
screenReader="${screenReader:-none}"
emailClient="$(first_available_path betterbird evolution thunderbird || true)"
webBrowser="$(first_available_path brave chromium epiphany firefox google-chrome-stable google-chrome-unstable microsoft-edge-stable microsoft-edge-beta microsoft-edge-dev midori seamonkey vivaldi || true)"
textEditor="$(first_available_path emacs geany gedit kate kwrite l3afpad leafpad libreoffice mousepad pluma || true)"
fileBrowser="$(first_available_path caja nemo nautilus pcmanfm pcmanfm-qt thunar || true)"
ircClient="$(first_available_path albikirc Albikirc access-irc || true)"
terminalEmulator="$(first_available_path mate-terminal lxterminal gnome-terminal terminator xfce4-terminal tilix ptyxis kgx sakura roxterm termit guake tilda qterminal konsole || true)"
if [[ -z "$terminalEmulator" ]] && command -v xterm &> /dev/null && command -v fenrir &> /dev/null; then
terminalEmulator="$(command -v xterm)"
fi
udiskie=1
if command -v udiskie &> /dev/null; then
udiskie=0
fi
dex=1
if command -v dex &> /dev/null; then
dex=0
fi
batteryAlert=1
if command -v acpi &> /dev/null; then
batteryAlert=0
fi
brlapi=1
if [[ "$screenReader" != "none" ]] && [[ -n "$screenReader" ]]; then
brlapi=0
fi
sounds=0
screenlockMethod="none"
screenlockPinHash=""
screenlockAutolockSeconds=0
screenlockOnStartup=1
if i38lock_is_supported; then
screenlockMethod="i38lock"
screenlockAutolockSeconds=300
screenlockOnStartup=0
fi
personalModeEnabled=0
personalModeKey="Control+Escape"
waytrayUseI38Config=0
}
# Personal mode helpers
normalize_ratpoison_key() {
local key="$1"
@@ -414,7 +488,7 @@ load_config() {
source "$configFile"
# Convert kbd string back to array if present
if [[ -n "$kbd" ]]; then
if [[ -n "${kbd[*]:-}" ]]; then
IFS=' ' read -ra kbd <<< "$kbd"
fi
@@ -424,6 +498,10 @@ load_config() {
}
save_config() {
if [[ $defaultConfig -eq 1 ]]; then
return 0
fi
if yesno "Save this configuration for future runs?"; then
cat > "$configFile" << EOF
# I38 Configuration Preferences
@@ -576,7 +654,6 @@ if new_content:
new_content += block
xprofile_path.write_text(new_content, encoding="utf-8")
PY
exit 0
}
apply_screenlock_pin() {
@@ -722,6 +799,8 @@ write_i38_version() {
# Array of command line arguments
declare -A command=(
[h]="This help screen."
[d]="Generate the default I38 configuration without prompting."
[D]="Generate the default I38 configuration plus ~/.xinitrc and ~/.xprofile without prompting."
[u]="Copy over the latest version of scripts."
[x]="Generate ~/.xinitrc and ~/.xprofile."
[X]="Generate ~/.xprofile only."
@@ -733,16 +812,27 @@ args="${args//[[:space:]]/}"
while getopts "${args}" i ; do
case "$i" in
h) help;;
d) defaultConfig=1;;
D) defaultConfig=1; defaultGenerateX=1;;
u) update_scripts;;
x) write_xinitrc ;&
X) write_xprofile ;;
x) write_xinitrc; write_xprofile; exit 0;;
X) write_xprofile; exit 0;;
esac
done
if [[ $defaultConfig -eq 1 ]]; then
set_default_configuration
fi
if [[ $defaultGenerateX -eq 1 ]]; then
write_xinitrc
write_xprofile
fi
# Load saved configuration if available
configLoaded=0
configChanged=0
if load_config; then
if [[ $defaultConfig -eq 0 ]] && load_config; then
configLoaded=1
dialog --title "I38" --msgbox "Loaded saved preferences from $configFile\n\nMissing or invalid values will be prompted." 0 0
fi
@@ -772,7 +862,7 @@ if [[ -z "$escapeKey" ]] || [[ -z "$mod" ]]; then
done
fi
# Multiple keyboard layouts
if [[ ${#kbd[@]} -eq 0 ]]; then
if [[ $defaultConfig -eq 0 && ${#kbd[@]} -eq 0 ]]; then
if yesno "Do you want to use multiple keyboard layouts?"; then
unset kbd
while : ; do
@@ -792,7 +882,7 @@ if [[ -z "$i3FontSize" ]] || [[ ! "$i3FontSize" =~ ^[0-9]+$ ]]; then
fi
fi
# Screen Reader
if [[ -z "$screenReader" ]] || { [[ "$screenReader" != "none" ]] && ! command -v "$screenReader" &> /dev/null; }; then
if [[ $defaultConfig -eq 0 ]] && { [[ -z "$screenReader" ]] || { [[ "$screenReader" != "none" ]] && ! command -v "$screenReader" &> /dev/null; }; }; then
programList=()
for i in cthulhu orca ; do
if command -v "${i/#-/}" &> /dev/null ; then
@@ -816,7 +906,7 @@ else
export screenReader
fi
# Email client
if [[ -z "$emailClient" ]] || ! command -v "$emailClient" &> /dev/null; then
if [[ $defaultConfig -eq 0 ]] && { [[ -z "$emailClient" ]] || ! command -v "$emailClient" &> /dev/null; }; then
programList=()
for i in betterbird evolution thunderbird ; do
if command -v "${i/#-/}" &> /dev/null ; then
@@ -835,7 +925,7 @@ else
export emailClient
fi
# Web browser
if [[ -z "$webBrowser" ]] || ! command -v "$webBrowser" &> /dev/null; then
if [[ $defaultConfig -eq 0 ]] && { [[ -z "$webBrowser" ]] || ! command -v "$webBrowser" &> /dev/null; }; then
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
if command -v "${i/#-/}" &> /dev/null ; then
@@ -854,7 +944,7 @@ else
export webBrowser
fi
# Text editor
if [[ -z "$textEditor" ]] || ! command -v "$textEditor" &> /dev/null; then
if [[ $defaultConfig -eq 0 ]] && { [[ -z "$textEditor" ]] || ! command -v "$textEditor" &> /dev/null; }; then
programList=()
for i in emacs geany gedit kate kwrite l3afpad leafpad libreoffice mousepad pluma ; do
if command -v "${i/#-/}" &> /dev/null ; then
@@ -873,7 +963,7 @@ else
export textEditor
fi
# File browser
if [[ -z "$fileBrowser" ]] || ! command -v "$fileBrowser" &> /dev/null; then
if [[ $defaultConfig -eq 0 ]] && { [[ -z "$fileBrowser" ]] || ! command -v "$fileBrowser" &> /dev/null; }; then
programList=()
for i in caja nemo nautilus pcmanfm pcmanfm-qt thunar ; do
if command -v "${i/#-/}" &> /dev/null ; then
@@ -892,7 +982,7 @@ else
export fileBrowser
fi
# IRC client
if [[ -z "$ircClient" ]] || ! command -v "$ircClient" &> /dev/null; then
if [[ $defaultConfig -eq 0 ]] && { [[ -z "$ircClient" ]] || ! command -v "$ircClient" &> /dev/null; }; then
programList=()
for i in albikirc Albikirc access-irc ; do
if command -v "${i/#-/}" &> /dev/null ; then
@@ -911,7 +1001,11 @@ else
export ircClient
fi
# Terminal emulator
if [[ -z "$terminalEmulator" ]] || { [[ ! -x "$terminalEmulator" ]] && ! command -v "$terminalEmulator" &> /dev/null; }; then
if [[ $defaultConfig -eq 1 && -z "$terminalEmulator" ]]; then
echo "No supported terminal emulator was found. Please install mate-terminal, lxterminal, gnome-terminal, terminator, another supported accessible terminal, or install both xterm and fenrir."
exit 1
fi
if [[ $defaultConfig -eq 0 ]] && { [[ -z "$terminalEmulator" ]] || { [[ ! -x "$terminalEmulator" ]] && ! command -v "$terminalEmulator" &> /dev/null; }; }; then
configChanged=1
programList=()
for i in mate-terminal lxterminal gnome-terminal terminator xfce4-terminal tilix ptyxis kgx sakura roxterm termit guake tilda qterminal konsole ; do
@@ -986,7 +1080,7 @@ if [[ -z "$sounds" ]]; then
sounds=1
fi
fi
if [[ -z "$screenlockPinHash" ]]; then
if [[ $defaultConfig -eq 0 && -z "$screenlockPinHash" ]]; then
screenlockPinFile="${i3Path}/.screenpin"
if [[ -f "$screenlockPinFile" ]]; then
read -r screenlockPinHash < "$screenlockPinFile"
@@ -997,7 +1091,7 @@ if [[ -z "${screenlockMethod+x}" ]]; then
screenlockNeedsSelection=1
fi
if [[ -z "$screenlockMethod" || "$screenlockMethod" == "none" ]]; then
if [[ -n "$screenlockPinHash" ]]; then
if [[ $defaultConfig -eq 0 && -n "$screenlockPinHash" ]]; then
screenlockMethod="pin"
else
screenlockMethod="none"
@@ -1115,7 +1209,11 @@ write_i38_version
write_desktop_shortcuts_template
write_i38_xresources
# Move scripts into place
copy_scripts | dialog --backtitle "I38" --progressbox "Moving scripts into place and writing config..." -1 -1
if [[ $defaultConfig -eq 1 ]]; then
copy_scripts > /dev/null
else
copy_scripts | dialog --backtitle "I38" --progressbox "Moving scripts into place and writing config..." -1 -1
fi
apply_screenlock_pin
update_personal_customizations
@@ -1537,6 +1635,11 @@ fi
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
case "${fileBrowser##*/}" in
thunar|pcmanfm|pcmanfm-qt)
echo "exec_always --no-startup-id ${i3Path}/scripts/filemanager.sh ${fileBrowser}"
;;
esac
echo "exec_always --no-startup-id ${i3Path}/scripts/i38-clipboard.py --daemon"
echo "exec_always --no-startup-id ${i3Path}/scripts/desktop.sh"
echo "exec_always --no-startup-id ${i3Path}/scripts/i38-update-check.sh"
@@ -1800,3 +1903,6 @@ PY
# Create the firstrun file
touch "${i3Path}/firstrun"
if [[ $defaultConfig -eq 1 ]]; then
echo "Default I38 configuration generated."
fi
+74
View File
@@ -0,0 +1,74 @@
#!/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.
set -u
set_ini_key() {
local filePath="$1"
local sectionName="$2"
local keyName="$3"
local keyValue="$4"
local tempFile
mkdir -p -- "$(dirname -- "$filePath")" || return 0
touch -- "$filePath" || return 0
tempFile="$(mktemp "${filePath}.tmp.XXXXXX")" || return 0
awk -v section="$sectionName" -v key="$keyName" -v value="$keyValue" '
BEGIN {
inSection = 0
sawSection = 0
wroteKey = 0
}
$0 ~ "^\\[" {
if (inSection && !wroteKey) {
print key "=" value
wroteKey = 1
}
inSection = ($0 == "[" section "]")
if (inSection) {
sawSection = 1
}
}
inSection && $0 ~ "^[[:space:]]*" key "[[:space:]]*=" {
if (!wroteKey) {
print key "=" value
wroteKey = 1
}
next
}
{ print }
END {
if (sawSection && inSection && !wroteKey) {
print key "=" value
} else if (!sawSection) {
print ""
print "[" section "]"
print key "=" value
}
}
' "$filePath" > "$tempFile" && mv -- "$tempFile" "$filePath"
rm -f -- "$tempFile"
}
fileManager="${1:-}"
fileManager="${fileManager##*/}"
case "$fileManager" in
thunar)
command -v xfconf-query > /dev/null || exit 0
xfconf-query -c thunar -p /last-view -s ThunarDetailsView > /dev/null 2>&1 || true
;;
pcmanfm)
set_ini_key "${XDG_CONFIG_HOME:-${HOME}/.config}/pcmanfm/default/pcmanfm.conf" "ui" "view_mode" "list"
;;
pcmanfm-qt)
set_ini_key "${XDG_CONFIG_HOME:-${HOME}/.config}/pcmanfm-qt/lxqt/settings.conf" "FolderView" "Mode" "list"
;;
esac