Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions .github/workflows/workstation-mac-polish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
name: workstation-mac-polish

on:
pull_request:
paths:
- 'profiles/linux-dev/workstation-v0/bin/mac-screenshot.sh'
- 'profiles/linux-dev/workstation-v0/bin/install-sourceos-cli.sh'
- 'profiles/linux-dev/workstation-v0/gnome/mac-defaults.sh'
- 'profiles/linux-dev/workstation-v0/gnome/README.md'
- 'profiles/linux-dev/workstation-v0/manifest.yaml'
- 'docs/workstation/**'
- '.github/workflows/workstation-mac-polish.yml'
push:
branches:
- main
paths:
- 'profiles/linux-dev/workstation-v0/bin/mac-screenshot.sh'
- 'profiles/linux-dev/workstation-v0/bin/install-sourceos-cli.sh'
- 'profiles/linux-dev/workstation-v0/gnome/mac-defaults.sh'
- 'profiles/linux-dev/workstation-v0/gnome/README.md'
- 'profiles/linux-dev/workstation-v0/manifest.yaml'
- 'docs/workstation/**'
- '.github/workflows/workstation-mac-polish.yml'

jobs:
mac-polish-smoke:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Syntax check Mac polish scripts
run: |
set -euo pipefail
bash -n profiles/linux-dev/workstation-v0/bin/mac-screenshot.sh
bash -n profiles/linux-dev/workstation-v0/bin/install-sourceos-cli.sh
bash -n profiles/linux-dev/workstation-v0/gnome/mac-defaults.sh

- name: Smoke: installer writes user wrappers
run: |
set -euo pipefail
installer='profiles/linux-dev/workstation-v0/bin/install-sourceos-cli.sh'
tmp_home=$(mktemp -d)
HOME="$tmp_home" bash "$installer"
test -x "$tmp_home/.local/bin/sourceos"
test -x "$tmp_home/.local/bin/mac-screenshot.sh"
test -s "$tmp_home/.config/sourceos/profile.path"
28 changes: 28 additions & 0 deletions docs/workstation/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ It triggers on PRs and main pushes touching:
Workflow files:
- `.github/workflows/workstation-scripts.yml`
- `.github/workflows/workstation-lampstand.yml`
- `.github/workflows/workstation-mac-polish.yml`

## Workstation v0 goals

Expand All @@ -46,6 +47,7 @@ Workflow files:
- Compatibility remap lanes: `xremap` and `kinto` (explicit compatibility path, not default).
- Touchpad gesture lane: `fusuma`.
- Mac-like GNOME behavior pack: left-side window controls, hot corners off, 12h clock, Files on `Super+E`, Terminal on `Super+Return`, dock favorites seeded.
- Mac polish v1: Sushi quick preview, macOS-style screenshot helper, `Super+Shift+3/4/5/6` screenshot bindings, and `~/Pictures/Screenshots` output lane.
- Local status/doctor surfaces that can be opened from the launcher (`sourceos status --open`, `sourceos doctor --open`).

## Apply
Expand Down Expand Up @@ -74,6 +76,31 @@ Or via the installed helper:
sourceos status --json
sourceos search 'report OR invoice' --snippet

## GNOME Mac polish commands

The profile installs `mac-screenshot.sh` into `~/.local/bin` as a wrapper around the profile-local helper.

Screenshot commands:

mac-screenshot.sh screen
mac-screenshot.sh area
mac-screenshot.sh window
mac-screenshot.sh interactive
mac-screenshot.sh open-dir

Default screenshot output path:

~/Pictures/Screenshots

GNOME keybindings applied by `gnome/mac-defaults.sh`:

Super+Shift+3 full-screen screenshot
Super+Shift+4 area screenshot
Super+Shift+5 interactive screenshot UI
Super+Shift+6 open screenshots folder

Quick preview behavior uses Fedora's `sushi` package, GNOME's Quick Look-style previewer for Nautilus.

## Lampstand runtime commands

Search and runtime inspection are exposed through the same workstation helper so the launcher remains an action bus and Lampstand remains the file-search authority:
Expand Down Expand Up @@ -112,6 +139,7 @@ Notes:
- Kinto is treated as an explicit compatibility lane rather than the default Wayland-first path.
- File search should resolve through Lampstand when available; the launcher must not run a redundant second file-search pass.
- Lampstand is installed in user space and exposed through a user service, not as a mandatory host-system package.
- Mac polish v1 stays inside bounded GNOME defaults and package installs; it does not fork GNOME Shell or replace libadwaita.

## Related docs

Expand Down
70 changes: 44 additions & 26 deletions profiles/linux-dev/workstation-v0/bin/install-sourceos-cli.sh
Original file line number Diff line number Diff line change
@@ -1,23 +1,18 @@
#!/usr/bin/env bash
set -euo pipefail

# Install the profile-local `sourceos` helper CLI to user scope.
# Target: ~/.local/bin/sourceos
#
# IMPORTANT:
# - We do NOT copy the helper script itself into ~/.local/bin.
# - Instead we install a small wrapper that pins the profile directory in
# $XDG_CONFIG_HOME/sourceos/profile.path and execs the profile-local helper.
#
# Rationale:
# - The helper CLI is profile-scoped (linux-dev/workstation-v0). Copying it out of
# the profile directory breaks relative-path assumptions and can drift.
# Install profile-local workstation helper CLIs to user scope.
# Targets:
# - ~/.local/bin/sourceos
# - ~/.local/bin/mac-screenshot.sh

PROFILE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
IMPL="$PROFILE_DIR/bin/sourceos"
SOURCEOS_IMPL="$PROFILE_DIR/bin/sourceos"
SCREENSHOT_IMPL="$PROFILE_DIR/bin/mac-screenshot.sh"

DEST_DIR="${HOME}/.local/bin"
DEST="$DEST_DIR/sourceos"
SOURCEOS_DEST="$DEST_DIR/sourceos"
SCREENSHOT_DEST="$DEST_DIR/mac-screenshot.sh"

CFG_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/sourceos"
PROFILE_FILE="$CFG_DIR/profile.path"
Expand All @@ -26,17 +21,28 @@ info(){ printf "INFO: %s\n" "$*" >&2; }
warn(){ printf "WARN: %s\n" "$*" >&2; }
err(){ printf "ERROR: %s\n" "$*" >&2; }

main(){
[[ -x "$IMPL" ]] || { err "sourceos helper missing: $IMPL"; exit 2; }
install_sourceos_wrapper(){
cat > "$SOURCEOS_DEST" <<'EOF'
#!/usr/bin/env bash
set -euo pipefail

mkdir -p "$DEST_DIR"
mkdir -p "$CFG_DIR"
PROFILE_FILE="${XDG_CONFIG_HOME:-$HOME/.config}/sourceos/profile.path"
PROFILE_DIR="$(cat "$PROFILE_FILE" 2>/dev/null || true)"

# Persist the profile dir
printf '%s\n' "$PROFILE_DIR" > "$PROFILE_FILE"
if [[ -z "$PROFILE_DIR" ]]; then
echo "ERROR: SourceOS profile path file missing or empty: $PROFILE_FILE" >&2
echo "Re-run the workstation profile installer to regenerate it." >&2
exit 2
fi

export SOURCEOS_PROFILE_DIR="$PROFILE_DIR"
exec "$PROFILE_DIR/bin/sourceos" "$@"
EOF
chmod +x "$SOURCEOS_DEST"
}

# Install wrapper
cat > "$DEST" <<'EOF'
install_screenshot_wrapper(){
cat > "$SCREENSHOT_DEST" <<'EOF'
#!/usr/bin/env bash
set -euo pipefail

Expand All @@ -49,17 +55,29 @@ if [[ -z "$PROFILE_DIR" ]]; then
exit 2
fi

export SOURCEOS_PROFILE_DIR="$PROFILE_DIR"
exec "$PROFILE_DIR/bin/sourceos" "$@"
exec bash "$PROFILE_DIR/bin/mac-screenshot.sh" "$@"
EOF
chmod +x "$SCREENSHOT_DEST"
}

main(){
[[ -x "$SOURCEOS_IMPL" ]] || { err "sourceos helper missing: $SOURCEOS_IMPL"; exit 2; }
[[ -f "$SCREENSHOT_IMPL" ]] || { err "screenshot helper missing: $SCREENSHOT_IMPL"; exit 2; }

mkdir -p "$DEST_DIR"
mkdir -p "$CFG_DIR"

printf '%s\n' "$PROFILE_DIR" > "$PROFILE_FILE"

chmod +x "$DEST"
install_sourceos_wrapper
install_screenshot_wrapper

info "installed wrapper: $DEST"
info "installed wrapper: $SOURCEOS_DEST"
info "installed wrapper: $SCREENSHOT_DEST"
info "pinned profile dir: $PROFILE_FILE"

if [[ ":$PATH:" != *":$DEST_DIR:"* ]]; then
warn "$DEST_DIR is not on PATH. Add it to your shell rc before using sourceos."
warn "$DEST_DIR is not on PATH. Add it to your shell rc before using sourceos or mac-screenshot.sh."
fi
}

Expand Down
84 changes: 84 additions & 0 deletions profiles/linux-dev/workstation-v0/bin/mac-screenshot.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
#!/usr/bin/env bash
set -euo pipefail

# Mac-style screenshot helper for SourceOS workstation-v0.
# Intended GNOME bindings:
# - Super+Shift+3 -> full screen
# - Super+Shift+4 -> area selection
# - Super+Shift+5 -> interactive screenshot UI

err(){ printf "ERROR: %s\n" "$*" >&2; }
info(){ printf "INFO: %s\n" "$*" >&2; }
have(){ command -v "$1" >/dev/null 2>&1; }

screenshot_dir(){
printf '%s\n' "${SOURCEOS_SCREENSHOT_DIR:-$HOME/Pictures/Screenshots}"
}

stamp(){ date +%Y-%m-%d-%H%M%S; }

open_dir(){
local d=$1
if have xdg-open; then
xdg-open "$d" >/dev/null 2>&1 || true
elif have open; then
open "$d" >/dev/null 2>&1 || true
fi
}

shot(){
local mode=$1
local d out
d="$(screenshot_dir)"
mkdir -p "$d"
out="$d/Screenshot-$(stamp).png"

if ! have gnome-screenshot; then
err "gnome-screenshot is not installed"
exit 127
fi

case "$mode" in
screen)
gnome-screenshot -f "$out"
;;
area)
gnome-screenshot -a -f "$out"
;;
window)
gnome-screenshot -w -f "$out"
;;
interactive)
gnome-screenshot -i
exit 0
;;
*)
err "unknown screenshot mode: $mode (use screen|area|window|interactive|open-dir)"
exit 2
;;
esac

info "wrote: $out"
}

main(){
case "${1:-screen}" in
screen|area|window|interactive)
shot "$1"
;;
open-dir)
mkdir -p "$(screenshot_dir)"
open_dir "$(screenshot_dir)"
;;
-h|--help|help)
cat <<'EOF'
Usage: mac-screenshot.sh [screen|area|window|interactive|open-dir]
EOF
;;
*)
shot "$1"
;;
esac
}

main "$@"
33 changes: 25 additions & 8 deletions profiles/linux-dev/workstation-v0/gnome/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,43 @@ This directory contains a **minimal GNOME baseline** for the workstation profile

Principles:

- Behavioral configuration via **GSettings** (no GNOME core forks).
- Behavioral configuration via **GSettings**.
- Conservative defaults that are stable across GNOME upgrades.
- Avoid invasive keybinding rewrites until we pin and validate a full shortcut map.
- Mac-like behavior is implemented as bounded GNOME defaults, helper scripts, and packaged GNOME components.

## Apply

```bash
./apply.sh
./extensions-install.sh
./mac-defaults.sh
```

## Current baseline (v0)

- Enable window buttons: close/minimize/maximize (left)
- Touchpad: tap-to-click + natural scrolling
- Show battery percentage
- Show weekday in clock
- Show weekday/date in clock
- Enable dynamic workspaces

Future work:

- Extension pinset (dash-to-dock, appindicator, etc.)
- Albert hotkey binding (Super+Space) once the command surface is confirmed
- Wayland-safe keyboard remap lane (keyd/xremap) in addition to Kinto
- Dash-to-Dock and AppIndicator extension pinset
- SourceOS palette on `Super+Space`
- Files on `Super+E`
- Terminal on `Super+Return`

## Mac polish v1

- Quick preview through Fedora's `sushi` package
- Screenshot helper wrapper installed as `~/.local/bin/mac-screenshot.sh`
- Screenshot output directory at `~/Pictures/Screenshots`
- `Super+Shift+3` full-screen screenshot
- `Super+Shift+4` area screenshot
- `Super+Shift+5` interactive screenshot UI
- `Super+Shift+6` open screenshot directory

## Follow-on work

- Wayland-safe keyboard remap lane expansion
- Optional bounded icon/cursor/font appearance pack
- More complete macOS-style shortcut map after validation
15 changes: 13 additions & 2 deletions profiles/linux-dev/workstation-v0/gnome/mac-defaults.sh
Original file line number Diff line number Diff line change
Expand Up @@ -62,18 +62,29 @@ main(){
set_key org.gnome.nautilus.preferences click-policy 'double'
set_key org.gnome.nautilus.preferences show-delete-permanently true

# Screenshots
mkdir -p "$HOME/Pictures/Screenshots"

# Favorites / dock seed (best-effort)
set_key org.gnome.shell favorite-apps "['org.gnome.Nautilus.desktop', 'org.gnome.Terminal.desktop', 'firefox.desktop', 'org.gnome.Settings.desktop']"

# Preserve palette hotkey in custom0, then add Finder/Terminal-like bindings.
# Preserve palette hotkey in custom0, then add Finder/Terminal/screenshot bindings.
local base="/org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/"
local custom0="${base}custom0/"
local custom1="${base}custom1/"
local custom2="${base}custom2/"
gsettings set org.gnome.settings-daemon.plugins.media-keys custom-keybindings "['${custom0}', '${custom1}', '${custom2}']" || true
local custom3="${base}custom3/"
local custom4="${base}custom4/"
local custom5="${base}custom5/"
local custom6="${base}custom6/"
gsettings set org.gnome.settings-daemon.plugins.media-keys custom-keybindings "['${custom0}', '${custom1}', '${custom2}', '${custom3}', '${custom4}', '${custom5}', '${custom6}']" || true

set_custom_binding custom1 "SourceOS Files" "nautilus --new-window" "<Super>e"
set_custom_binding custom2 "SourceOS Terminal" "gnome-terminal" "<Super>Return"
set_custom_binding custom3 "SourceOS Screenshot Screen" "mac-screenshot.sh screen" "<Super><Shift>3"
set_custom_binding custom4 "SourceOS Screenshot Area" "mac-screenshot.sh area" "<Super><Shift>4"
set_custom_binding custom5 "SourceOS Screenshot Interactive" "mac-screenshot.sh interactive" "<Super><Shift>5"
set_custom_binding custom6 "SourceOS Screenshots Folder" "mac-screenshot.sh open-dir" "<Super><Shift>6"

info "Mac-like GNOME defaults pack applied"
}
Expand Down
9 changes: 5 additions & 4 deletions profiles/linux-dev/workstation-v0/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,16 @@ autopatch_enabled(){
}

install_system(){
local packages=(git openssh-clients podman toolbox wl-clipboard jq xclip sushi gnome-screenshot)
if have rpm-ostree; then
info "rpm-ostree detected: installing minimal SYSTEM layer (may require reboot)"
sudo rpm-ostree install git openssh-clients podman toolbox wl-clipboard jq xclip || true
info "rpm-ostree detected: installing SYSTEM layer (may require reboot)"
sudo rpm-ostree install "${packages[@]}" || true
info "If new packages were layered, reboot before continuing."
return
fi
if have dnf; then
info "dnf detected: installing minimal SYSTEM layer"
sudo dnf install -y git openssh-clients podman toolbox wl-clipboard jq xclip || true
info "dnf detected: installing SYSTEM layer"
sudo dnf install -y "${packages[@]}" || true
return
fi
err "No rpm-ostree/dnf found; cannot apply SYSTEM layer"
Expand Down
Loading