Skip to content

Instantly share code, notes, and snippets.

@mal1k-me
Created November 13, 2025 16:08
Show Gist options
  • Select an option

  • Save mal1k-me/65eb954d204ea0d302a854ac64d56199 to your computer and use it in GitHub Desktop.

Select an option

Save mal1k-me/65eb954d204ea0d302a854ac64d56199 to your computer and use it in GitHub Desktop.
Patch `.desktop` Files to Disable Client Side Decorations of GTK 3, GTK 4 and Libadwaita Applications in KDE Plasma on Arch Linux
#!/usr/bin/env bash
# NOTE: Install gtk-nocsd-git from AUR first
set -euo pipefail
readonly WRAPPER_PATH="/usr/local/bin/gtk-nocsd-wrapper"
readonly DEST_DIR="${HOME}/.local/share/applications"
# ────────────────────────────────────────────────────────────────────────────────
log() {
printf '[%s] %s\n' "$(date +%H:%M:%S)" "$*"
}
# ────────────────────────────────────────────────────────────────────────────────
create_wrapper() {
if [[ -f "${WRAPPER_PATH}" ]]; then
log "Wrapper already exists: ${WRAPPER_PATH}"
return 0
fi
log "Creating wrapper at ${WRAPPER_PATH}"
# Create wrapper content
sudo tee "${WRAPPER_PATH}" >/dev/null <<'EOF'
#!/usr/bin/env bash
# Wrapper: load libgtk-nocsd only on KDE Plasma sessions
if [[ "${XDG_CURRENT_DESKTOP:-}" =~ KDE ]]; then
exec env LD_PRELOAD="/usr/lib/libgtk-nocsd.so" "$@"
else
exec "$@"
fi
EOF
sudo chmod +x "${WRAPPER_PATH}"
}
# ────────────────────────────────────────────────────────────────────────────────
is_gtk_pkg() {
pacman -Qi "$1" 2>/dev/null | grep -Eq 'Depends On.*(gtk3|gtk4|libadwaita)'
}
# ────────────────────────────────────────────────────────────────────────────────
merge_desktop_file() {
local src="$1"
local dest="$2"
# If destination doesn't exist, copy directly and patch Exec
if [[ ! -f "${dest}" ]]; then
cp -f "${src}" "${dest}"
patch_exec_line "${dest}"
log "Added new: $(basename "${dest}")"
return 0
fi
# Otherwise, merge differences excluding Exec= line
local tmp
tmp="$(mktemp)"
awk '
BEGIN { exec_line = "" }
/^Exec=/ {
exec_line = $0
next
}
{ print }
END {
if (exec_line != "")
print exec_line
}
' "${dest}" >"${tmp}.user"
awk '
/^Exec=/ { next }
{ print }
' "${src}" >"${tmp}.sys"
# If files differ aside from Exec=, update user copy
if ! diff -q "${tmp}.user" "${tmp}.sys" >/dev/null 2>&1; then
log "Updating non-Exec changes: $(basename "${dest}")"
# Replace all non-Exec lines from src into dest, keep Exec line intact
awk '
NR==FNR {
if ($0 ~ /^Exec=/) { exec_line = $0; next }
user[NR]=$0
next
}
{
if ($0 ~ /^Exec=/) { print exec_line; next }
print
}
' "${dest}" "${src}" >"${tmp}"
mv "${tmp}" "${dest}"
fi
patch_exec_line "${dest}"
rm -f "${tmp}.user" "${tmp}.sys"
}
# ────────────────────────────────────────────────────────────────────────────────
patch_exec_line() {
local file="$1"
# Extract current Exec line
local current
current="$(grep '^Exec=' "${file}" || true)"
# Skip if already using wrapper
if grep -q '^Exec=gtk-nocsd-wrapper' <<<"${current}"; then
log "Exec already patched: $(basename "${file}")"
return 0
fi
local tmp
tmp="$(mktemp)"
awk '
/^Exec=/ {
line=$0
# Preserve any env prefix; just insert wrapper at the start
if (line ~ /^Exec=env /) {
sub(/^Exec=env /, "Exec=gtk-nocsd-wrapper env ", line)
} else {
sub(/^Exec=/, "Exec=gtk-nocsd-wrapper ", line)
}
print line
next
}
{ print }
' "${file}" >"${tmp}"
mv "${tmp}" "${file}"
log "Patched Exec: $(basename "${file}")"
}
# ────────────────────────────────────────────────────────────────────────────────
process_packages() {
mkdir -p "${DEST_DIR}"
log "Scanning installed GTK packages…"
local pkg
for pkg in $(pacman -Qq); do
if is_gtk_pkg "${pkg}"; then
pacman -Ql "${pkg}" 2>/dev/null | awk '/\.desktop$/ {print $2}' | while read -r desktop; do
[[ -f "${desktop}" ]] || continue
local dest
dest="${DEST_DIR}/$(basename "${desktop}")"
merge_desktop_file "${desktop}" "${dest}"
done
fi
done
}
# ────────────────────────────────────────────────────────────────────────────────
main() {
create_wrapper
process_packages
log "Done. Patched .desktop files are in ${DEST_DIR}"
}
main "$@"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment