8 Commits
x86_64 ... main

Author SHA1 Message Date
klein panic
44c4941cbc Automated update 2025-04-11 22:00:02 -04:00
klein panic
9584b06da3 added clock display, changed battery color 2025-04-09 11:57:07 -04:00
klein panic
0daf43a708 Automated update 2025-03-07 22:00:00 -05:00
klein panic
d56151fe12 updated keys to include slock usage 2025-03-05 20:34:38 -05:00
klein panic
68e5037858 added dependency installer - not tested for all OS - on debian it works as intended 2025-03-05 20:26:44 -05:00
klein panic
e6e9270a5c Automated update 2025-02-07 22:05:52 -05:00
klein panic
abfd1f8f6b Automated update 2025-01-31 20:01:00 -05:00
Klein
a938a2832c Merge pull request #1 from kleinpanic/x86_64
X86 64
2024-10-15 16:03:08 -04:00
21 changed files with 1318 additions and 8 deletions

34
KleinDwm/colors/fa.h Normal file
View File

@@ -0,0 +1,34 @@
static const char col_gray1[] = "#0f161e";
static const char col_gray3[] = "#fff7d0";
static const char col_gray4[] = "#FF609A";
static const char col_gray2[] = "#282A2E";
static const char col_cyan[] = "#0f161e";
static const char tag1[] = "#bf8427";
static const char tag2[] = "#5865F2";
static const char tag3[] = "#FF5500";
static const char tag4[] = "#FF609A";
static const char tag5[] = "#842291";
static const char tag6[] = "#900C3F";
static const char tag7[] = "#67AFA5";
static const char tag8[] = "#1DB954";
static const char tag9[] = "#FFFFFF";
static const char *colors[][3] = {
/* fg bg border */
[SchemeNorm] = { col_gray3, col_gray1, col_cyan },
[SchemeSel] = { col_gray4, col_cyan, col_gray2 },
[SchemeTitle] = { col_gray4, col_cyan, col_cyan },
};
static const char *tagsel[][2] = {
{ tag1, col_gray1 },
{ tag2, col_gray1 },
{ tag3, col_gray1 },
{ tag4, col_gray1 },
{ tag5, col_gray1 },
{ tag6, col_gray1 },
{ tag7, col_gray1 },
{ tag8, col_gray1 },
{ tag9, col_gray1 },
};

View File

@@ -6,7 +6,7 @@
#define ICONSIZE 20 /* icon size */
#define ICONSPACING 5 /* space between icon and title */
static const unsigned int borderpx = 2; /* border pixel of windows */
static const unsigned int gappx = 10; /* gaps between windows */
static const unsigned int gappx = 5; /* gaps between windows */
static const unsigned int snap = 32; /* snap pixel */
static const unsigned int systraypinning = 0; /* 0: sloppy systray follows selected monitor, >0: pin systray to monitor X */
static const unsigned int systrayonleft = 0; /* 0: systray in the right corner, >0: systray on left of status text */

Binary file not shown.

515
KleinDwm/dwm-deps-installer.sh Executable file
View File

@@ -0,0 +1,515 @@
#!/usr/bin/env bash
#
# Please be aware that I only run debian. Idk if this script will work for all
# Name: dwm-deps-installer.sh
# Purpose: Attempt to install dependencies for dwm (with multiple patches)
# across a wide range of Operating Systems and distributions.
# Author: ChatGPT (with users requirements)
# ---------------------------------------------------------------------
set -Eeuo pipefail
#----------------------------------------------
# Helper Functions
#----------------------------------------------
# Colored echo helpers (optional, remove if you dont want colors):
RED="$(tput setaf 1 || true)"
GREEN="$(tput setaf 2 || true)"
YELLOW="$(tput setaf 3 || true)"
BLUE="$(tput setaf 4 || true)"
BOLD="$(tput bold || true)"
RESET="$(tput sgr0 || true)"
info() { echo -e "${BLUE}[INFO]${RESET} $*"; }
warn() { echo -e "${YELLOW}[WARN]${RESET} $*"; }
error() { echo -e "${RED}[ERROR]${RESET} $*" >&2; }
success() { echo -e "${GREEN}[OK]${RESET} $*"; }
# Ensure the user is either root or can use sudo (for distros that require it).
check_root_or_sudo() {
if (( $EUID == 0 )); then
info "Running as root."
else
# Check if sudo is present
if ! command -v sudo &>/dev/null; then
error "You need 'sudo' installed or to run this script as root!"
exit 1
fi
fi
}
#----------------------------------------------
# Detect Operating System
#----------------------------------------------
# Strategy:
# 1. Check `uname -s` for high-level OS detection (e.g., "Linux", "Darwin", "FreeBSD", "OpenBSD", "NetBSD", "SunOS", "CYGWIN_NT-10.0", "MSYS_NT-10.0", etc.).
# 2. If Linux, parse /etc/os-release for distribution ID.
# 3. If *BSD, parse `uname -s` or other known markers.
# 4. If Windows (Cygwin, MSYS, etc.), note that direct DWM usage is limited unless WSL is used.
# 5. If macOS (Darwin), note that you can't replace the system WM. We'll still do a brew-based install for X-related libs.
# 6. If illumos/Solaris (SunOS), attempt typical "pkg" or "pkgutil" usage, but this can vary widely.
detect_os() {
local unameOut
unameOut="$(uname -s 2>/dev/null || true)"
case "${unameOut}" in
Linux*) echo "Linux";;
Darwin*) echo "macOS";;
FreeBSD*) echo "FreeBSD";;
OpenBSD*) echo "OpenBSD";;
NetBSD*) echo "NetBSD";;
DragonFly*) echo "DragonFlyBSD";;
SunOS*) echo "SunOS";; # Could be illumos or Solaris
CYGWIN*|MINGW*|MSYS*) echo "Windows";;
*)
# unknown
echo "UnknownOS"
;;
esac
}
#----------------------------------------------
# Install function for Linux distributions
#----------------------------------------------
install_deps_linux() {
# We'll attempt to parse /etc/os-release to get the distribution ID
local distro="Unknown"
if [[ -f /etc/os-release ]]; then
# shellcheck source=/dev/null
. /etc/os-release
distro="${ID:-Unknown}"
# Some distros (like Pop!_OS) might have ID=ubuntu but ID_LIKE=debian
# We might also check $ID_LIKE to refine guesses
fi
info "Detected distro ID: $distro"
# Lowercase just in case
distro="${distro,,}"
# Basic note: We need dev packages for:
# - X11 (libx11, dev headers)
# - Xft (libxft, dev)
# - Xinerama (libxinerama, dev)
# - Yajl (libyajl, dev) for certain patches
# - xinit
# - xorg/xserver
case "$distro" in
# ---------------------------------------------------------------
# Debian / Ubuntu / Mint / etc. (apt-based)
# ---------------------------------------------------------------
debian|ubuntu|linuxmint|pop|neon|elementary|zorin|kali|parrot|\
raspbian|devuan|galliumos|lite|sparkylinux|peppermint|bunsenlabs|\
bodhi|pureos|siduction)
info "Using apt-get/apt to install dependencies..."
sudo apt-get update
sudo apt-get install -y \
libx11-dev libxft-dev libxinerama-dev libyajl-dev \
xorg xinit
;;
# ---------------------------------------------------------------
# Arch / Manjaro / Endeavour / Artix / etc. (pacman-based)
# ---------------------------------------------------------------
arch|manjaro|endeavouros|arco|artix|garuda)
info "Using pacman to install dependencies..."
sudo pacman -Syu --noconfirm --needed \
xorg-server xorg-xinit libx11 libxft libxinerama yajl
;;
# ---------------------------------------------------------------
# Fedora (dnf)
# ---------------------------------------------------------------
fedora)
info "Using dnf to install dependencies..."
sudo dnf install -y \
libX11-devel libXft-devel libXinerama-devel yajl-devel \
xorg-x11-server-Xorg xorg-x11-xinit
;;
# ---------------------------------------------------------------
# RHEL / CentOS / Rocky / Alma (dnf/yum)
# ---------------------------------------------------------------
rhel|centos|rocky|alma)
info "Using dnf (or yum) to install dependencies..."
sudo dnf install -y \
libX11-devel libXft-devel libXinerama-devel yajl-devel \
xorg-x11-server-Xorg xorg-x11-xinit
;;
# ---------------------------------------------------------------
# openSUSE / SUSE (zypper)
# ---------------------------------------------------------------
opensuse*|suse|sle*)
info "Using zypper to install dependencies..."
sudo zypper refresh
sudo zypper install -y \
libX11-devel libXft-devel libXinerama-devel libyajl-devel \
xorg-x11-server xinit
;;
# ---------------------------------------------------------------
# Mageia / OpenMandriva (urpmi or dnf in some versions)
# ---------------------------------------------------------------
mageia|openmandriva)
# Mageia uses urpmi
if command -v urpmi &>/dev/null; then
info "Using urpmi to install dependencies..."
sudo urpmi.update -a
sudo urpmi --auto \
lib64x11-devel lib64xft-devel lib64xinerama-devel lib64yajl-devel \
xinit x11-server-xorg
else
# Some derivatives might use dnf
warn "urpmi not found. Trying dnf..."
sudo dnf install -y \
libX11-devel libXft-devel libXinerama-devel yajl-devel \
xorg-x11-server-Xorg xorg-x11-xinit
fi
;;
# ---------------------------------------------------------------
# PCLinuxOS (apt-rpm? Synaptic? Hard to detect. Possibly uses urpmi.)
# ---------------------------------------------------------------
pclinuxos)
warn "PCLinuxOS uses apt-rpm or Synaptic. Attempting apt-get..."
sudo apt-get update || true
sudo apt-get install -y \
libx11-dev libxft-dev libxinerama-dev libyajl-dev \
xorg xinit || {
error "Failed apt-get on PCLinuxOS. Please install manually."
exit 1
}
;;
# ---------------------------------------------------------------
# Slackware (slackpkg)
# Slackware typically includes dev headers by default, but let's try:
# slackpkg update
# slackpkg install xorg x11 x11-devel etc.
# Slackware doesnt always break them into separate -dev packages.
# If you have the Slackware DVD, you may need to install the "X"
# series and "D" (development) series fully.
# We'll attempt partial coverage:
# ---------------------------------------------------------------
slackware)
warn "Slackware detection. Attempting 'slackpkg' usage..."
# Well do a best-effort. Might require manual steps:
sudo slackpkg update || true
# There might not be exact package naming for dev libs.
warn "Please ensure X, x11 dev, xinerama dev, xft dev, and yajl dev are installed from Slackware's 'X' and 'D' series. Attempting partial installation..."
# Slackpkg might not have granularity for these. We'll try:
sudo slackpkg install x11 xorg || true
# Yajl might be in SlackBuilds or might already be included.
success "Slackware can be tricky. Check your installed packages or SlackBuild for Yajl if needed."
;;
# ---------------------------------------------------------------
# Gentoo / Funtoo / Sabayon / Calculate (emerge or equo for Sabayon)
# ---------------------------------------------------------------
gentoo|funtoo)
info "Using emerge for Gentoo/Funtoo..."
sudo emerge --sync
# On Gentoo, you might set USE flags. We'll do a minimal approach:
# The relevant packages might be x11-libs/libX11, x11-libs/libXft,
# x11-libs/libXinerama, dev-libs/yajl, x11-base/xorg-server, x11-apps/xinit
sudo emerge -n \
x11-libs/libX11 x11-libs/libXft x11-libs/libXinerama dev-libs/yajl \
x11-base/xorg-server x11-apps/xinit
;;
sabayon)
info "Sabayon (now part of MocaccinoOS?), using 'equo' or 'emerge'..."
if command -v equo &>/dev/null; then
sudo equo update
sudo equo install \
x11-libs/libX11 x11-libs/libXft x11-libs/libXinerama dev-libs/yajl \
xorg-server xinit
else
warn "No 'equo'. Trying emerge..."
sudo emerge -n \
x11-libs/libX11 x11-libs/libXft x11-libs/libXinerama dev-libs/yajl \
x11-base/xorg-server x11-apps/xinit
fi
;;
# ---------------------------------------------------------------
# Void (xbps)
# ---------------------------------------------------------------
void)
info "Using xbps-install for Void..."
sudo xbps-install -S
sudo xbps-install -y \
libX11-devel libXft-devel libXinerama-devel yajl-devel \
xorg xorg-server xinit
;;
# ---------------------------------------------------------------
# Alpine (apk)
# ---------------------------------------------------------------
alpine)
info "Using apk for Alpine..."
sudo apk update
sudo apk add \
libx11-dev libxft-dev libxinerama-dev yajl-dev \
xorg-server xinit
;;
# ---------------------------------------------------------------
# NixOS
# On NixOS, you generally manage environment/system packages in
# configuration.nix or use `nix-env -iA`.
# ---------------------------------------------------------------
nixos)
warn "NixOS detected. Attempting 'nix-env -iA nixpkgs.packageName'..."
warn "You may want to manage this in /etc/nixos/configuration.nix."
nix-env -iA nixpkgs.libX11 nixpkgs.libXft nixpkgs.libXinerama nixpkgs.yajl nixpkgs.xorg.xorgserver nixpkgs.xorg.xinit
;;
# ---------------------------------------------------------------
# Clear Linux (swupd)
# ---------------------------------------------------------------
clear-linux*|clearlinux)
info "Clear Linux detected. Using swupd..."
sudo swupd update
sudo swupd bundle-add \
x11-tools os-core-dev C-basic libsdl devpkg-yajl # best guess
warn "Ensure xorg-server and xinit equivalents are installed in Clear Linux (bundles)."
;;
# ---------------------------------------------------------------
# Solus (eopkg)
# ---------------------------------------------------------------
solus)
info "Solus detected. Using eopkg..."
sudo eopkg update-repo
sudo eopkg install -y \
libx11-devel libxft-devel libxinerama-devel yajl-devel \
xorg-server xorg-xinit
;;
# ---------------------------------------------------------------
# If we get here, we don't have a recognized distro or ID is missing
# We'll attempt a generic approach or just print instructions.
# ---------------------------------------------------------------
*)
error "Unrecognized or unsupported Linux distro: '$distro'"
echo
echo "Please manually install the following packages for your distro's package manager:"
echo " * X11 development libraries (libX11, dev headers)"
echo " * Xft (libXft) with dev headers"
echo " * Xinerama (libXinerama) with dev headers"
echo " * Yajl (libyajl) with dev headers"
echo " * xorg-server / xinit"
echo "Then you can compile dwm."
exit 1
;;
esac
success "Dependency installation complete for distro: $distro"
}
#----------------------------------------------
# Install function for BSD
#----------------------------------------------
install_deps_bsd() {
local bsdName="$1"
info "Detected $bsdName..."
case "$bsdName" in
FreeBSD)
# FreeBSD typically uses pkg
sudo pkg update
sudo pkg install -y \
libX11 libXft libXinerama yajl xorg xorg-server xinit
;;
OpenBSD)
# OpenBSD uses pkg_add. Checking package names can be tricky,
# they might be named slightly differently, e.g., "xbase" might
# be part of the OS sets. We'll do a best effort here:
# Usually X is part of base for OpenBSD. We'll just do the libs:
# Some packages might be named e.g. `xenocara-libX11`, etc. This is approximate.
sudo pkg_add xbase xfont xserv # might already be installed
sudo pkg_add xorg # might include many components
# For dev libraries:
sudo pkg_add x11 x11-fmw xft # approximate
# Yajl is often just "yajl"
sudo pkg_add yajl
;;
NetBSD)
# NetBSD might use pkgin or pkg_add from pkgsrc
if command -v pkgin &>/dev/null; then
sudo pkgin update
sudo pkgin -y install libX11 libXft libXinerama yajl xorg
else
# fallback to pkg_add
warn "pkgin not found, trying pkg_add for NetBSD..."
# Typically you set PKG_PATH, etc. This is a best guess
sudo pkg_add libX11 libXft libXinerama yajl xorg
fi
;;
DragonFlyBSD)
# DragonFly also uses pkg (like FreeBSD).
# Some packages might differ in naming:
sudo pkg update
sudo pkg install -y \
xorg libX11 libXft libXinerama yajl
;;
*)
warn "Generic BSD fallback: Please install X11 dev, Xft dev, Xinerama dev, Yajl dev, xinit, xserver from your BSD's packages/ports."
;;
esac
success "Finished (attempted) dependency installation on $bsdName."
}
#----------------------------------------------
# Install function for macOS
#----------------------------------------------
install_deps_macos() {
info "Detected macOS (Darwin)."
# You cannot truly replace the macOS window manager with dwm.
# You *can* compile it and run it under an X server (e.g. XQuartz).
# So well attempt to install the relevant libraries via Homebrew.
if ! command -v brew &>/dev/null; then
error "Homebrew is not installed. Please install Homebrew from https://brew.sh."
exit 1
fi
# Install XQuartz from cask (optional), plus libs
brew update
brew install pkg-config xorg libx11 libxft libxinerama yajl
# For an X server, often you can do:
brew install --cask xquartz
success "macOS libs installed via Homebrew. Remember: you cant fully replace the macOS WM with dwm!"
}
#----------------------------------------------
# Install function for SunOS / Solaris / illumos
#----------------------------------------------
install_deps_sunos() {
info "Detected SunOS (Solaris/illumos)."
# This can vary widely. Some illumos-based distros use "pkg" (OpenIndiana),
# some use "pkgin" (SmartOS), some use "pkgutil" (OpenCSW on Solaris),
# or "apt-like" commands in certain forks.
# We'll guess for OpenIndiana (pkg):
# "pfexec" is typically used in place of sudo for Solaris derivatives.
# This is extremely approximate:
if command -v pfexec &>/dev/null; then
# Attempt OpenIndiana approach:
pfexec pkg refresh
pfexec pkg install x11/header x11/library/libx11 x11/library/libxft \
x11/library/libxinerama library/yajl \
x11/server/xorg x11/session/xinit
else
# fallback approach
warn "No pfexec found. Trying 'sudo pkg' or 'sudo pkgutil'."
if command -v pkg &>/dev/null; then
sudo pkg refresh || true
sudo pkg install x11/header x11/library/libx11 x11/library/libxft \
x11/library/libxinerama library/yajl \
x11/server/xorg x11/session/xinit || {
error "Solaris/illumos install attempt failed. Install these packages manually."
}
elif command -v pkgutil &>/dev/null; then
# Possibly using OpenCSW on Solaris
sudo pkgutil -U
sudo pkgutil -i \
libx11_dev libxft_dev libxinerama_dev yajl_dev xorg xinit || {
error "Could not install via pkgutil. Please do it manually."
}
else
error "No recognized pkg tool on Solaris/illumos. Please install manually."
exit 1
fi
fi
success "Finished attempted install on SunOS/illumos. This might require manual verification."
}
#----------------------------------------------
# Windows approach
#----------------------------------------------
install_deps_windows() {
info "Detected Windows environment (Cygwin/Mingw/MSYS)."
# You cannot replace the Windows manager with dwm. You can compile and run it
# in an X server environment (like VcXsrv or Xming or MobaXterm).
#
# Option 1: WSL (Windows Subsystem for Linux):
# If running in WSL, youre effectively on a Linux environment, so you'd want
# to detect that as "Linux" (some older WSL might say "Microsoft" in /etc/os-release).
# In that case, the user can do the standard Linux approach above.
#
# Option 2: MSYS2 / Cygwin with X packages:
# For MSYS2: pacman -S xorg-server xorg-xinit xorgproto libX11-devel ...
# For Cygwin: setup-x86_64.exe or "apt-cyg" might be used
#
# We'll attempt a best guess for MSYS2 (since it also uses pacman).
# If it fails, we instruct manual steps.
if command -v pacman &>/dev/null; then
# Probably MSYS2
info "MSYS2 environment detected. Using pacman for MSYS2..."
pacman -Syu --noconfirm --needed \
mingw-w64-x86_64-xorgproto mingw-w64-x86_64-libx11 \
mingw-w64-x86_64-libxft mingw-w64-x86_64-libxinerama \
mingw-w64-x86_64-yajl
success "MSYS2 pacman approach done. You still need to run an X server separately."
else
warn "No MSYS2 pacman found. Possibly Cygwin or something else. Please install X11 dev libs, X server, X init, Yajl manually using Cygwin setup or chocolatey, etc."
warn "You CANNOT replace the Windows shell with dwm, only run it under an X server."
fi
}
#----------------------------------------------
# Main script logic
#----------------------------------------------
main() {
check_root_or_sudo
local OS
OS="$(detect_os)"
info "Operating System detected as: $OS"
case "$OS" in
Linux)
install_deps_linux
;;
FreeBSD|OpenBSD|NetBSD|DragonFlyBSD)
install_deps_bsd "$OS"
;;
macOS)
install_deps_macos
;;
SunOS)
install_deps_sunos
;;
Windows)
install_deps_windows
;;
*)
error "Unsupported or unknown OS: $OS"
echo "If youre on an unsupported Linux distro, you can manually install these packages:"
echo " libx11-dev, libxft-dev, libxinerama-dev, libyajl-dev, xserver, xinit"
echo "If youre on another BSD or obscure system, install the equivalents from your package manager."
exit 1
;;
esac
success "Script completed successfully!"
echo "You should now have the libraries required to build dwm with your patches (where possible)."
echo
}
main "$@"

Binary file not shown.

View File

@@ -28,8 +28,6 @@ static const char *termcmd[] = { TERMINAL, NULL };
static const char *inc_light[] = { "brightness", "-a", "up", NULL};
static const char *dec_light[] = { "brightness", "-a", "down", NULL };
/*xrandr control gui wrapper*/
static const char *xrandrwrap[] = { "xrandrwrap", NULL };
/* screenshot command */
static const char *scrotselcmd[] = { "scrot", "-s", "/home/klein/Pictures/screenshots/Screenshot_%Y-%m-%d_%H-%M-%S.png", NULL };
@@ -79,7 +77,7 @@ static const Key keys[] = {
{ MODKEY, XK_c, XK_b, spawn, SHCMD("xdotool key Super_L+3 && qutebrowser") },
{ MODKEY, XK_c, XK_f, spawn, SHCMD("xdotool key Super_L+4 && freetube") },
{ MODKEY, XK_c, XK_g, spawn, SHCMD("xdotool key Super_L+5 && qutebrowser github.com") },
{ MODKEY, XK_c, XK_n, spawn, SHCMD("xdotool key Super_L+7 && nvim") },
{ MODKEY, XK_c, XK_n, spawn, SHCMD("xdotool key Super_L+7 && st nvim") },
{ MODKEY, XK_c, XK_s, spawn, SHCMD("xdotool key Super_L+8 && spotube") },
{ MODKEY, XK_c, XK_z, spawn, SHCMD("xdotool key Super_L+9 && alacritty") },
{ MODKEY, XK_n, XK_v, spawn, {.v = nvimcmd } },
@@ -100,7 +98,8 @@ static const Key keys[] = {
{ 0, -1, XK_F10, spawn, { .v = scrotselcmd } },
{ 0, -1, XF86XK_MonBrightnessUp, spawn, { .v = inc_light } },
{ 0, -1, XF86XK_MonBrightnessDown, spawn, { .v = dec_light } },
{ 0, -1, XK_F8, spawn, { .v = xrandrwrap } },
{ MODKEY|ShiftMask, -1, XK_l, spawn, SHCMD("slock") }
};
/* button definitions */

View File

@@ -10,6 +10,94 @@ max_height=23
bar_width=5
gap=5
clock() {
# Adjusted dimensions for the clock icon
local icon_width=18
local icon_height=$((max_height - 2))
# Determine the center of the icon (for the dial)
local center_x=$((base_x + icon_width / 2))
local center_y=$(((base_y + 2) + icon_height / 2))
# Begin drawing the clock icon.
# Outer border (clock frame) in medium gray.
local clock_icon=""
clock_icon+="^c#888888^"
clock_icon+="^r${base_x},$((base_y + 2)),${icon_width},${icon_height}^"
# Inner dial (face), inset by 3 pixels on all sides.
clock_icon+="^c#000000^"
clock_icon+="^r$((base_x + 3)),$((base_y + 5)),$((icon_width - 6)),$((icon_height - 6))^"
# Get current time details.
local hour=$(date +%H)
local minute=$(date +%M)
hour=$((10#$hour))
minute=$((10#$minute))
# Calculate angles in radians.
# Hour hand: each hour is 30° plus half a degree per minute.
local hour_angle
hour_angle=$(awk -v h="$hour" -v m="$minute" 'BEGIN {
printf "%.2f", ((-((h % 12) * 30 + m * 0.5) + 90) * 3.14159265 / 180)
}')
# Minute hand: each minute represents 6°.
local minute_angle
minute_angle=$(awk -v m="$minute" 'BEGIN {
printf "%.2f", ((-(m * 6) + 90) * 3.14159265 / 180)
}')
# Define inner radius from inner dial (the dial drawn is (icon_width-6) wide).
local inner_radius=$(( (icon_width - 6) / 2 ))
# Define hand lengths as fractions of the inner radius.
local hour_hand_length
hour_hand_length=$(awk -v r="$inner_radius" 'BEGIN { printf "%d", r * 0.6 }')
local minute_hand_length
minute_hand_length=$(awk -v r="$inner_radius" 'BEGIN { printf "%d", r * 0.9 }')
# Function to draw a hand from the center to a given length with specified angle and color.
# It draws a series of 1x1 pixel rectangles along the hand's path.
draw_hand() {
local length=$1
local angle=$2
local color=$3
local hand_line=""
for (( i=0; i<=length; i++ )); do
# Compute x and y offset using AWK's cosine and sine functions.
local dx
dx=$(awk -v i="$i" -v a="$angle" 'BEGIN { printf "%d", i * cos(a) }')
local dy
dy=$(awk -v i="$i" -v a="$angle" 'BEGIN { printf "%d", i * sin(a) }')
# Note: subtract dy because screen y coordinates increase downward.
local px=$(( center_x + dx ))
local py=$(( center_y - dy ))
hand_line+="^c${color}^"
hand_line+="^r${px},${py},1,1^"
done
echo -n "${hand_line}"
}
# Draw the hour hand (white) and the minute hand (light gray).
local hour_line
hour_line=$(draw_hand "$hour_hand_length" "$hour_angle" "#FFFFFF")
local minute_line
minute_line=$(draw_hand "$minute_hand_length" "$minute_angle" "#AAAAAA")
# Append the hand drawings to the clock icon.
clock_icon+="${hour_line}${minute_line}"
# Decrease the gap between the icon and the time text by forwarding the drawing cursor by a smaller amount.
# Here, we move the cursor by icon_width + gap - 2 pixels.
clock_icon+="^d^^f$(( icon_width + gap - 2 ))^"
# Fetch the current time (military format HH:MM) with no background.
local time_str
time_str=$(date +%H:%M:%S)
local time_text="^c#FFFFFF^ ${time_str} ^d^"
# Output the complete clock icon and time text without any label.
echo "${clock_icon}${time_text}"
}
cpu() {
local cpu_line1=$(grep '^cpu ' /proc/stat)
sleep 2
@@ -141,13 +229,13 @@ battery() {
fi
local adj_y=7
local fill_width=$(($capacity * 20 / 100))
local battery_icon="^c$black^"
local battery_icon="^c$white^"
battery_icon+="^r2,10,24,12^"
battery_icon+="^c$grey^"
battery_icon+="^r4,12,20,8^"
battery_icon+="^c$color^"
battery_icon+="^r4,12,$fill_width,8^"
battery_icon+="^c$black^"
battery_icon+="^c$white^"
battery_icon+="^r26,13,4,6^"
battery_icon+="^d^^f35^"
local color_status=$white
@@ -215,7 +303,7 @@ wifi() {
}
status(){
echo "$(cpu)|$(ram)|$(swap)$(disk)|$(cpu_temperature)|$(battery)|$(wifi)"
echo "$(clock)|$(cpu)|$(ram)|$(swap)$(disk)|$(cpu_temperature)|$(battery)|$(wifi)"
}
while true; do
xsetroot -name "$(status)"

25
slock/LICENSE Normal file
View File

@@ -0,0 +1,25 @@
MIT/X Consortium License
© 2015-2016 Markus Teich <markus.teich@stusta.mhn.de>
© 2014 Dimitris Papastamos <sin@2f30.org>
© 2006-2014 Anselm R Garbe <anselm@garbe.us>
© 2014-2016 Laslo Hunhold <dev@frign.de>
© 2016-2023 Hiltjo Posthuma <hiltjo@codemadness.org>
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

46
slock/Makefile Normal file
View File

@@ -0,0 +1,46 @@
# slock - simple screen locker
# See LICENSE file for copyright and license details.
include config.mk
SRC = slock.c ${COMPATSRC}
OBJ = ${SRC:.c=.o}
all: slock
.c.o:
${CC} -c ${CFLAGS} $<
${OBJ}: config.h config.mk arg.h util.h
config.h:
cp config.def.h $@
slock: ${OBJ}
${CC} -o $@ ${OBJ} ${LDFLAGS}
clean:
rm -f slock ${OBJ} slock-${VERSION}.tar.gz
dist: clean
mkdir -p slock-${VERSION}
cp -R LICENSE Makefile README slock.1 config.mk \
${SRC} config.def.h arg.h util.h slock-${VERSION}
tar -cf slock-${VERSION}.tar slock-${VERSION}
gzip slock-${VERSION}.tar
rm -rf slock-${VERSION}
install: all
mkdir -p ${DESTDIR}${PREFIX}/bin
cp -f slock ${DESTDIR}${PREFIX}/bin
chmod 755 ${DESTDIR}${PREFIX}/bin/slock
chmod u+s ${DESTDIR}${PREFIX}/bin/slock
mkdir -p ${DESTDIR}${MANPREFIX}/man1
sed "s/VERSION/${VERSION}/g" <slock.1 >${DESTDIR}${MANPREFIX}/man1/slock.1
chmod 644 ${DESTDIR}${MANPREFIX}/man1/slock.1
uninstall:
rm -f ${DESTDIR}${PREFIX}/bin/slock
rm -f ${DESTDIR}${MANPREFIX}/man1/slock.1
.PHONY: all clean dist install uninstall

24
slock/README Normal file
View File

@@ -0,0 +1,24 @@
slock - simple screen locker
============================
simple screen locker utility for X.
Requirements
------------
In order to build slock you need the Xlib header files.
Installation
------------
Edit config.mk to match your local setup (slock is installed into
the /usr/local namespace by default).
Afterwards enter the following command to build and install slock
(if necessary as root):
make clean install
Running slock
-------------
Simply invoke the 'slock' command. To get out of it, enter your password.

65
slock/arg.h Normal file
View File

@@ -0,0 +1,65 @@
/*
* Copy me if you can.
* by 20h
*/
#ifndef ARG_H__
#define ARG_H__
extern char *argv0;
/* use main(int argc, char *argv[]) */
#define ARGBEGIN for (argv0 = *argv, argv++, argc--;\
argv[0] && argv[0][0] == '-'\
&& argv[0][1];\
argc--, argv++) {\
char argc_;\
char **argv_;\
int brk_;\
if (argv[0][1] == '-' && argv[0][2] == '\0') {\
argv++;\
argc--;\
break;\
}\
for (brk_ = 0, argv[0]++, argv_ = argv;\
argv[0][0] && !brk_;\
argv[0]++) {\
if (argv_ != argv)\
break;\
argc_ = argv[0][0];\
switch (argc_)
/* Handles obsolete -NUM syntax */
#define ARGNUM case '0':\
case '1':\
case '2':\
case '3':\
case '4':\
case '5':\
case '6':\
case '7':\
case '8':\
case '9'
#define ARGEND }\
}
#define ARGC() argc_
#define ARGNUMF() (brk_ = 1, estrtonum(argv[0], 0, INT_MAX))
#define EARGF(x) ((argv[0][1] == '\0' && argv[1] == NULL)?\
((x), abort(), (char *)0) :\
(brk_ = 1, (argv[0][1] != '\0')?\
(&argv[0][1]) :\
(argc--, argv++, argv[0])))
#define ARGF() ((argv[0][1] == '\0' && argv[1] == NULL)?\
(char *)0 :\
(brk_ = 1, (argv[0][1] != '\0')?\
(&argv[0][1]) :\
(argc--, argv++, argv[0])))
#define LNGARG() &argv[0][0]
#endif

12
slock/config.def.h Normal file
View File

@@ -0,0 +1,12 @@
/* user and group to drop privileges to */
static const char *user = "nobody";
static const char *group = "nogroup";
static const char *colorname[NUMCOLS] = {
[INIT] = "black", /* after initialization */
[INPUT] = "#005577", /* during input */
[FAILED] = "#CC3333", /* wrong password */
};
/* treat a cleared input like a wrong password (color) */
static const int failonclear = 1;

12
slock/config.h Normal file
View File

@@ -0,0 +1,12 @@
/* user and group to drop privileges to */
static const char *user = "nobody";
static const char *group = "nogroup";
static const char *colorname[NUMCOLS] = {
[INIT] = "black", /* after initialization */
[INPUT] = "#005577", /* during input */
[FAILED] = "#CC3333", /* wrong password */
};
/* treat a cleared input like a wrong password (color) */
static const int failonclear = 1;

29
slock/config.mk Normal file
View File

@@ -0,0 +1,29 @@
# slock version
VERSION = 1.5
# Customize below to fit your system
# paths
PREFIX = /usr/local
MANPREFIX = ${PREFIX}/share/man
X11INC = /usr/X11R6/include
X11LIB = /usr/X11R6/lib
# includes and libs
INCS = -I. -I/usr/include -I${X11INC}
LIBS = -L/usr/lib -lc -lcrypt -L${X11LIB} -lX11 -lXext -lXrandr
# flags
CPPFLAGS = -DVERSION=\"${VERSION}\" -D_DEFAULT_SOURCE -DHAVE_SHADOW_H
CFLAGS = -std=c99 -pedantic -Wall -Os ${INCS} ${CPPFLAGS}
LDFLAGS = -s ${LIBS}
COMPATSRC = explicit_bzero.c
# On OpenBSD and Darwin remove -lcrypt from LIBS
#LIBS = -L/usr/lib -lc -L${X11LIB} -lX11 -lXext -lXrandr
# On *BSD remove -DHAVE_SHADOW_H from CPPFLAGS
# On NetBSD add -D_NETBSD_SOURCE to CPPFLAGS
#CPPFLAGS = -DVERSION=\"${VERSION}\" -D_BSD_SOURCE -D_NETBSD_SOURCE
# On OpenBSD set COMPATSRC to empty
#COMPATSRC =

19
slock/explicit_bzero.c Normal file
View File

@@ -0,0 +1,19 @@
/* $OpenBSD: explicit_bzero.c,v 1.3 2014/06/21 02:34:26 matthew Exp $ */
/*
* Public domain.
* Written by Matthew Dempsky.
*/
#include <string.h>
__attribute__((weak)) void
__explicit_bzero_hook(void *buf, size_t len)
{
}
void
explicit_bzero(void *buf, size_t len)
{
memset(buf, 0, len);
__explicit_bzero_hook(buf, len);
}

BIN
slock/explicit_bzero.o Normal file

Binary file not shown.

BIN
slock/slock Executable file

Binary file not shown.

45
slock/slock.1 Normal file
View File

@@ -0,0 +1,45 @@
.Dd October 6, 2023
.Dt SLOCK 1
.Os
.Sh NAME
.Nm slock
.Nd simple X screen locker
.Sh SYNOPSIS
.Nm
.Op Fl v
.Op Ar cmd Op Ar arg ...
.Sh DESCRIPTION
.Nm
is a simple X screen locker.
If provided,
.Ar cmd
is executed after the screen has been locked.
.Pp
The options are as follows:
.Bl -tag -width Ds
.It Fl v
Print version information to stdout and exit.
.El
.Sh EXIT STATUS
.Ex -std
.Sh EXAMPLES
$
.Nm
/usr/sbin/s2ram
.Sh SECURITY CONSIDERATIONS
To make sure a locked screen can not be bypassed by switching VTs
or killing the X server with Ctrl+Alt+Backspace, it is recommended
to disable both in
.Xr xorg.conf 5
for maximum security:
.Bd -literal
Section "ServerFlags"
Option "DontVTSwitch" "True"
Option "DontZap" "True"
EndSection
.Ed
.Sh CUSTOMIZATION
.Nm
can be customized by creating a custom config.h from config.def.h and
(re)compiling the source code.
This keeps it fast, secure and simple.

395
slock/slock.c Normal file
View File

@@ -0,0 +1,395 @@
/* See LICENSE file for license details. */
#define _XOPEN_SOURCE 500
#if HAVE_SHADOW_H
#include <shadow.h>
#endif
#include <ctype.h>
#include <errno.h>
#include <grp.h>
#include <pwd.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <X11/extensions/Xrandr.h>
#include <X11/keysym.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include "arg.h"
#include "util.h"
char *argv0;
enum {
INIT,
INPUT,
FAILED,
NUMCOLS
};
struct lock {
int screen;
Window root, win;
Pixmap pmap;
unsigned long colors[NUMCOLS];
};
struct xrandr {
int active;
int evbase;
int errbase;
};
#include "config.h"
static void
die(const char *errstr, ...)
{
va_list ap;
va_start(ap, errstr);
vfprintf(stderr, errstr, ap);
va_end(ap);
exit(1);
}
#ifdef __linux__
#include <fcntl.h>
#include <linux/oom.h>
static void
dontkillme(void)
{
FILE *f;
const char oomfile[] = "/proc/self/oom_score_adj";
if (!(f = fopen(oomfile, "w"))) {
if (errno == ENOENT)
return;
die("slock: fopen %s: %s\n", oomfile, strerror(errno));
}
fprintf(f, "%d", OOM_SCORE_ADJ_MIN);
if (fclose(f)) {
if (errno == EACCES)
die("slock: unable to disable OOM killer. "
"Make sure to suid or sgid slock.\n");
else
die("slock: fclose %s: %s\n", oomfile, strerror(errno));
}
}
#endif
static const char *
gethash(void)
{
const char *hash;
struct passwd *pw;
/* Check if the current user has a password entry */
errno = 0;
if (!(pw = getpwuid(getuid()))) {
if (errno)
die("slock: getpwuid: %s\n", strerror(errno));
else
die("slock: cannot retrieve password entry\n");
}
hash = pw->pw_passwd;
#if HAVE_SHADOW_H
if (!strcmp(hash, "x")) {
struct spwd *sp;
if (!(sp = getspnam(pw->pw_name)))
die("slock: getspnam: cannot retrieve shadow entry. "
"Make sure to suid or sgid slock.\n");
hash = sp->sp_pwdp;
}
#else
if (!strcmp(hash, "*")) {
#ifdef __OpenBSD__
if (!(pw = getpwuid_shadow(getuid())))
die("slock: getpwnam_shadow: cannot retrieve shadow entry. "
"Make sure to suid or sgid slock.\n");
hash = pw->pw_passwd;
#else
die("slock: getpwuid: cannot retrieve shadow entry. "
"Make sure to suid or sgid slock.\n");
#endif /* __OpenBSD__ */
}
#endif /* HAVE_SHADOW_H */
return hash;
}
static void
readpw(Display *dpy, struct xrandr *rr, struct lock **locks, int nscreens,
const char *hash)
{
XRRScreenChangeNotifyEvent *rre;
char buf[32], passwd[256], *inputhash;
int num, screen, running, failure, oldc;
unsigned int len, color;
KeySym ksym;
XEvent ev;
len = 0;
running = 1;
failure = 0;
oldc = INIT;
while (running && !XNextEvent(dpy, &ev)) {
if (ev.type == KeyPress) {
explicit_bzero(&buf, sizeof(buf));
num = XLookupString(&ev.xkey, buf, sizeof(buf), &ksym, 0);
if (IsKeypadKey(ksym)) {
if (ksym == XK_KP_Enter)
ksym = XK_Return;
else if (ksym >= XK_KP_0 && ksym <= XK_KP_9)
ksym = (ksym - XK_KP_0) + XK_0;
}
if (IsFunctionKey(ksym) ||
IsKeypadKey(ksym) ||
IsMiscFunctionKey(ksym) ||
IsPFKey(ksym) ||
IsPrivateKeypadKey(ksym))
continue;
switch (ksym) {
case XK_Return:
passwd[len] = '\0';
errno = 0;
if (!(inputhash = crypt(passwd, hash)))
fprintf(stderr, "slock: crypt: %s\n", strerror(errno));
else
running = !!strcmp(inputhash, hash);
if (running) {
XBell(dpy, 100);
failure = 1;
}
explicit_bzero(&passwd, sizeof(passwd));
len = 0;
break;
case XK_Escape:
explicit_bzero(&passwd, sizeof(passwd));
len = 0;
break;
case XK_BackSpace:
if (len)
passwd[--len] = '\0';
break;
default:
if (num && !iscntrl((int)buf[0]) &&
(len + num < sizeof(passwd))) {
memcpy(passwd + len, buf, num);
len += num;
}
break;
}
color = len ? INPUT : ((failure || failonclear) ? FAILED : INIT);
if (running && oldc != color) {
for (screen = 0; screen < nscreens; screen++) {
XSetWindowBackground(dpy,
locks[screen]->win,
locks[screen]->colors[color]);
XClearWindow(dpy, locks[screen]->win);
}
oldc = color;
}
} else if (rr->active && ev.type == rr->evbase + RRScreenChangeNotify) {
rre = (XRRScreenChangeNotifyEvent*)&ev;
for (screen = 0; screen < nscreens; screen++) {
if (locks[screen]->win == rre->window) {
if (rre->rotation == RR_Rotate_90 ||
rre->rotation == RR_Rotate_270)
XResizeWindow(dpy, locks[screen]->win,
rre->height, rre->width);
else
XResizeWindow(dpy, locks[screen]->win,
rre->width, rre->height);
XClearWindow(dpy, locks[screen]->win);
break;
}
}
} else {
for (screen = 0; screen < nscreens; screen++)
XRaiseWindow(dpy, locks[screen]->win);
}
}
}
static struct lock *
lockscreen(Display *dpy, struct xrandr *rr, int screen)
{
char curs[] = {0, 0, 0, 0, 0, 0, 0, 0};
int i, ptgrab, kbgrab;
struct lock *lock;
XColor color, dummy;
XSetWindowAttributes wa;
Cursor invisible;
if (dpy == NULL || screen < 0 || !(lock = malloc(sizeof(struct lock))))
return NULL;
lock->screen = screen;
lock->root = RootWindow(dpy, lock->screen);
for (i = 0; i < NUMCOLS; i++) {
XAllocNamedColor(dpy, DefaultColormap(dpy, lock->screen),
colorname[i], &color, &dummy);
lock->colors[i] = color.pixel;
}
/* init */
wa.override_redirect = 1;
wa.background_pixel = lock->colors[INIT];
lock->win = XCreateWindow(dpy, lock->root, 0, 0,
DisplayWidth(dpy, lock->screen),
DisplayHeight(dpy, lock->screen),
0, DefaultDepth(dpy, lock->screen),
CopyFromParent,
DefaultVisual(dpy, lock->screen),
CWOverrideRedirect | CWBackPixel, &wa);
lock->pmap = XCreateBitmapFromData(dpy, lock->win, curs, 8, 8);
invisible = XCreatePixmapCursor(dpy, lock->pmap, lock->pmap,
&color, &color, 0, 0);
XDefineCursor(dpy, lock->win, invisible);
/* Try to grab mouse pointer *and* keyboard for 600ms, else fail the lock */
for (i = 0, ptgrab = kbgrab = -1; i < 6; i++) {
if (ptgrab != GrabSuccess) {
ptgrab = XGrabPointer(dpy, lock->root, False,
ButtonPressMask | ButtonReleaseMask |
PointerMotionMask, GrabModeAsync,
GrabModeAsync, None, invisible, CurrentTime);
}
if (kbgrab != GrabSuccess) {
kbgrab = XGrabKeyboard(dpy, lock->root, True,
GrabModeAsync, GrabModeAsync, CurrentTime);
}
/* input is grabbed: we can lock the screen */
if (ptgrab == GrabSuccess && kbgrab == GrabSuccess) {
XMapRaised(dpy, lock->win);
if (rr->active)
XRRSelectInput(dpy, lock->win, RRScreenChangeNotifyMask);
XSelectInput(dpy, lock->root, SubstructureNotifyMask);
return lock;
}
/* retry on AlreadyGrabbed but fail on other errors */
if ((ptgrab != AlreadyGrabbed && ptgrab != GrabSuccess) ||
(kbgrab != AlreadyGrabbed && kbgrab != GrabSuccess))
break;
usleep(100000);
}
/* we couldn't grab all input: fail out */
if (ptgrab != GrabSuccess)
fprintf(stderr, "slock: unable to grab mouse pointer for screen %d\n",
screen);
if (kbgrab != GrabSuccess)
fprintf(stderr, "slock: unable to grab keyboard for screen %d\n",
screen);
return NULL;
}
static void
usage(void)
{
die("usage: slock [-v] [cmd [arg ...]]\n");
}
int
main(int argc, char **argv) {
struct xrandr rr;
struct lock **locks;
struct passwd *pwd;
struct group *grp;
uid_t duid;
gid_t dgid;
const char *hash;
Display *dpy;
int s, nlocks, nscreens;
ARGBEGIN {
case 'v':
puts("slock-"VERSION);
return 0;
default:
usage();
} ARGEND
/* validate drop-user and -group */
errno = 0;
if (!(pwd = getpwnam(user)))
die("slock: getpwnam %s: %s\n", user,
errno ? strerror(errno) : "user entry not found");
duid = pwd->pw_uid;
errno = 0;
if (!(grp = getgrnam(group)))
die("slock: getgrnam %s: %s\n", group,
errno ? strerror(errno) : "group entry not found");
dgid = grp->gr_gid;
#ifdef __linux__
dontkillme();
#endif
hash = gethash();
errno = 0;
if (!crypt("", hash))
die("slock: crypt: %s\n", strerror(errno));
if (!(dpy = XOpenDisplay(NULL)))
die("slock: cannot open display\n");
/* drop privileges */
if (setgroups(0, NULL) < 0)
die("slock: setgroups: %s\n", strerror(errno));
if (setgid(dgid) < 0)
die("slock: setgid: %s\n", strerror(errno));
if (setuid(duid) < 0)
die("slock: setuid: %s\n", strerror(errno));
/* check for Xrandr support */
rr.active = XRRQueryExtension(dpy, &rr.evbase, &rr.errbase);
/* get number of screens in display "dpy" and blank them */
nscreens = ScreenCount(dpy);
if (!(locks = calloc(nscreens, sizeof(struct lock *))))
die("slock: out of memory\n");
for (nlocks = 0, s = 0; s < nscreens; s++) {
if ((locks[s] = lockscreen(dpy, &rr, s)) != NULL)
nlocks++;
else
break;
}
XSync(dpy, 0);
/* did we manage to lock everything? */
if (nlocks != nscreens)
return 1;
/* run post-lock command */
if (argc > 0) {
switch (fork()) {
case -1:
die("slock: fork failed: %s\n", strerror(errno));
case 0:
if (close(ConnectionNumber(dpy)) < 0)
die("slock: close: %s\n", strerror(errno));
execvp(argv[0], argv);
fprintf(stderr, "slock: execvp %s: %s\n", argv[0], strerror(errno));
_exit(1);
}
}
/* everything is now blank. Wait for the correct password */
readpw(dpy, &rr, locks, nscreens, hash);
return 0;
}

BIN
slock/slock.o Normal file

Binary file not shown.

2
slock/util.h Normal file
View File

@@ -0,0 +1,2 @@
#undef explicit_bzero
void explicit_bzero(void *, size_t);