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
26 changes: 0 additions & 26 deletions bin/omarchy-brightness-shift

This file was deleted.

25 changes: 18 additions & 7 deletions bin/omarchy-menu-keybindings
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,21 @@ declare -A LUA_BIND_KEY_MAP
declare -A LUA_BIND_DISPATCHER_MAP
declare -A LUA_BIND_ARG_MAP

# A platform package can name keys the way its keyboards print them: one
# "<keysym> <name>" per line (on a MacBook, XF86MonBrightnessUp is F2).
key_names_file="${OMARCHY_PACKAGED_PATH:-/usr/share/omarchy}/default/omarchy/platform/key-names"

# Hyprland reports XKB keycodes for code: bindings. Resolve them to symbols
# via the compiled keymap, with a small fallback for common keys so the menu
# remains readable if xkbcli cannot resolve a symbol.
parse_keycodes() {
local apple=0
omarchy-hw-apple-silicon && apple=1
awk -v apple="$apple" '
awk -v key_names="$key_names_file" '
BEGIN {
while ((getline line < key_names) > 0) {
if (split(line, name_parts, /[ \t]+/) == 2 && name_parts[1] ~ /^[A-Za-z0-9_]+$/ && name_parts[2] ~ /^[A-Za-z0-9_]+$/) key_name[name_parts[1]] = name_parts[2]
}
close(key_names)

split("10=1 11=2 12=3 13=4 14=5 15=6 16=7 17=8 18=9 19=0 20=MINUS 21=EQUAL 59=COMMA 60=PERIOD 61=SLASH", fallbacks, " ")
for (i in fallbacks) {
separator = index(fallbacks[i], "=")
Expand Down Expand Up @@ -61,10 +68,13 @@ parse_keycodes() {
symbol = mouse_symbol[code]
if (symbol == "") symbol = "mouse:" code
sub("mouse:" code, symbol)
} else if (apple) {
# On Apple Silicon MacBooks XF86MonBrightnessUp/Down ARE F2/F1.
gsub(/XF86MonBrightnessUp/, "F2")
gsub(/XF86MonBrightnessDown/, "F1")
} else if ((first = index($0, ",")) > 0) {
# Only the key (the second field) is renamed: the description, the
# dispatcher and its argument are left as they are.
rest = substr($0, first + 1)
second = index(rest, ",")
key = second > 0 ? substr(rest, 1, second - 1) : rest
if (key in key_name) $0 = substr($0, 1, first) key_name[key] (second > 0 ? substr(rest, second) : "")
}

print
Expand Down Expand Up @@ -538,6 +548,7 @@ keybindings_cache_key() {
{
printf 'v14\n'
hyprctl devices 2>/dev/null | grep -F 'active keymap:'
cat "$key_names_file" 2>/dev/null
hyprctl binds 2>/dev/null
} | sha256sum | awk '{ print $1 }'
}
Expand Down
5 changes: 0 additions & 5 deletions config/hypr/input.lua
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,6 @@
-- },
-- })

-- Re-enable tap-to-click on the built-in Apple touchpad.
-- Find its name with `hyprctl devices` and uncomment the matching line.
-- hl.device({ name = "apple-mtp-multi-touch", tap_to_click = true })
-- hl.device({ name = "apple-spi-trackpad", tap_to_click = true })

-- App-specific touchpad scroll speeds.
-- o.window("(Alacritty|kitty)", { scroll_touchpad = 1.5 })
-- o.window("foot", { scroll_touchpad = 2.0 })
Expand Down
5 changes: 2 additions & 3 deletions default/hypr/bindings/media.lua
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,8 @@ o.bind("XF86AudioMute", "Mute", "omarchy-audio-output-volume mute-toggle", { loc
o.bind("XF86AudioMicMute", "Mute microphone", "omarchy-audio-input-mute", { locked = true })
o.bind("XF86MonBrightnessUp", "Brightness up", "omarchy-brightness-display +5%", { locked = true, repeating = true })
o.bind("XF86MonBrightnessDown", "Brightness down", "omarchy-brightness-display 5%-", { locked = true, repeating = true })
o.bind("SHIFT + XF86MonBrightnessUp", "Brightness maximum", "omarchy-brightness-shift up", { locked = true, repeating = true })
o.bind("SHIFT + XF86MonBrightnessDown", "Brightness minimum", "omarchy-brightness-shift down", { locked = true, repeating = true })

o.bind("SHIFT + XF86MonBrightnessUp", "Brightness maximum", "omarchy-brightness-display 100%", { locked = true, repeating = true })
o.bind("SHIFT + XF86MonBrightnessDown", "Brightness minimum", "omarchy-brightness-display 1%", { locked = true, repeating = true })
o.bind("XF86KbdBrightnessUp", "Keyboard brightness up", "omarchy-brightness-keyboard up", { locked = true, repeating = true })
o.bind("XF86KbdBrightnessDown", "Keyboard brightness down", "omarchy-brightness-keyboard down", { locked = true, repeating = true })
o.bind("XF86KbdLightOnOff", "Keyboard backlight cycle", "omarchy-brightness-keyboard cycle", { locked = true })
Expand Down
18 changes: 0 additions & 18 deletions default/hypr/bindings/utilities.lua
Original file line number Diff line number Diff line change
Expand Up @@ -34,27 +34,9 @@ o.bind("SUPER + CTRL + Delete", "Toggle laptop display", "omarchy-hyprland-monit
o.bind("SUPER + CTRL + ALT + Delete", "Toggle laptop display mirroring", "omarchy-hyprland-monitor-internal-mirror toggle")
o.bind("switch:on:Lid Switch", nil, "omarchy-system-lid-close", { locked = true })
o.bind("switch:off:Lid Switch", nil, "omarchy-hyprland-monitor-clamshell", { locked = true })
-- Apple Silicon names the lid switch "Apple SMC power/lid events", so the
-- generic "Lid Switch" binds above never fire on that hardware.
o.bind("switch:on:Apple SMC power/lid events", nil, "omarchy-system-lid-close", { locked = true })
o.bind("switch:off:Apple SMC power/lid events", nil, "omarchy-hyprland-monitor-clamshell", { locked = true })


o.bind("PRINT", "Screenshot", "omarchy-capture-screenshot")
o.bind("ALT + PRINT", "Screenrecording", "omarchy-capture-screenrecording --stop-recording || omarchy-menu toggle trigger.capture.screenrecord")
-- Apple keyboards have no PRINT key. SUPER+F10–F12 and the same chords on the
-- top-row media keysyms cover capture without holding Fn in media-first mode. Only
-- on Apple Silicon: everywhere else SUPER+F10–F12 stay unbound, as shipped, so
-- these must not claim them.
if o.shell_succeeds("omarchy-hw-apple-silicon") then
o.bind("SUPER + F12", "Screenshot Display", "omarchy-capture-screenshot fullscreen")
o.bind("SUPER + F11", "Screenshot Region", "omarchy-capture-screenshot region")
o.bind("SUPER + F10", "Screenshot Window", "omarchy-capture-screenshot windows")
o.bind("SUPER + XF86AudioMute", "Screenshot Window (Apple top row)", "omarchy-capture-screenshot windows")
o.bind("SUPER + XF86AudioLowerVolume", "Screenshot Region (Apple top row)", "omarchy-capture-screenshot region")
o.bind("SUPER + XF86AudioRaiseVolume", "Screenshot Display (Apple top row)", "omarchy-capture-screenshot fullscreen")
end

o.bind("SUPER + ALT + code:34", "Make webcam overlay smaller", "omarchy-capture-webcam-resize smaller")
o.bind("SUPER + ALT + code:35", "Make webcam overlay larger", "omarchy-capture-webcam-resize larger")
o.bind("SUPER + PRINT", "Color picker", "pkill hyprpicker || hyprpicker -a")
Expand Down
96 changes: 42 additions & 54 deletions default/hypr/helpers.lua
Original file line number Diff line number Diff line change
Expand Up @@ -89,62 +89,35 @@ function o.preinstalled_bindings_enabled()
return not file_exists((os.getenv("HOME") or "") .. "/.local/state/omarchy/preinstalls-removed")
end

-- The MacBook's own keyboard as Hyprland names it: SPI on M1, MTP on M2 and later.
local builtin_keyboards = { "apple-spi-keyboard", "apple-mtp-keyboard" }
local overlay_prefixes = {
"omarchy-menu",
"omarchy-shell shell toggle ",
"omarchy-shell -q shell togglePanelAt ",
}
-- Pickers that paste into the focused window stay with that window's screen.
local pastes_into_focused_window = {
["omarchy-shell shell toggle omarchy.emojis"] = true,
["omarchy-shell shell toggle omarchy.clipboard"] = true,
}
local apple_silicon

local function opens_overlay(command)
if type(command) ~= "string" or pastes_into_focused_window[command] then
return false
end

for _, prefix in ipairs(overlay_prefixes) do
if command:sub(1, #prefix) == prefix then
return true
-- A platform package's defaults load before Omarchy's (see omarchy.lua). A chord
-- they bind replaces Omarchy's own default for it, and a decorator they add runs
-- for every later bind, before it is made, so it can bind something that must
-- run first (Hyprland runs the binds of a key press in the order they were
-- added). The user's files, loaded after both, can still unbind or rebind any
-- chord. Both start empty on every load.
o.platform_chords = {}
o.bind_decorators = {}
o.decorating = false

-- Modifier order, case and aliases don't change the chord Hyprland binds.
local modifier_aliases = { CONTROL = "CTRL", WIN = "SUPER", LOGO = "SUPER", MOD4 = "SUPER", META = "SUPER", MOD1 = "ALT" }

local function chord(keys)
local parts = {}
for raw in (tostring(keys) .. "+"):gmatch("([^+]*)%+") do
local part = raw:match("^%s*(.-)%s*$"):upper()
if part ~= "" then
table.insert(parts, part)
end
end

return false
end

function o.apple_silicon()
if apple_silicon == nil then
apple_silicon = o.shell_succeeds("omarchy-hw-apple-silicon")
end

return apple_silicon
end

function o.focus_builtin_screen()
for _, monitor in ipairs(hl.get_monitors()) do
if monitor.name:match("^eDP%-") then
if not monitor.focused then
hl.dispatch(hl.dsp.focus({ monitor = monitor.name }))
end
return
end
for index = 1, #parts - 1 do
parts[index] = modifier_aliases[parts[index]] or parts[index]
end
end

-- A menu or panel pressed on the MacBook's own keyboard opens on the MacBook's
-- own screen; apps keep opening on the focused screen. Hyprland runs every bind
-- matching a key press in the order they were added, so this bind, scoped to the
-- built-in keyboard, moves focus before the menu bind runs. Other keyboards only
-- match the menu bind.
local function bind_builtin_screen_focus(keys)
if o.apple_silicon() then
hl.bind(keys, o.focus_builtin_screen, { device = { inclusive = true, list = builtin_keyboards } })
end
local key = table.remove(parts) or ""
table.sort(parts)
table.insert(parts, key)
return table.concat(parts, "+")
end

function o.bind(keys, description, dispatcher, options)
Expand All @@ -156,8 +129,23 @@ function o.bind(keys, description, dispatcher, options)

dispatcher = command_from(dispatcher, description)

if opens_overlay(dispatcher) and not opts.locked then
bind_builtin_screen_focus(keys)
if o.binding_phase == "defaults" and o.platform_chords[chord(keys)] then
return
elseif o.binding_phase == "platform" then
o.platform_chords[chord(keys)] = true
end

-- A bind a decorator makes through o.bind is not decorated again.
if not o.decorating then
o.decorating = true
for _, decorate in ipairs(o.bind_decorators) do
local ok, err = pcall(decorate, keys, dispatcher, opts)
if not ok then
o.decorating = false
error(err, 0)
end
end
o.decorating = false
end

if type(dispatcher) == "string" then
Expand Down
4 changes: 0 additions & 4 deletions default/hypr/input.lua
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,6 @@ hl.config({
},
})

-- Avoid stray taps while typing on the built-in Apple touchpad.
hl.device({ name = "apple-mtp-multi-touch", tap_to_click = false })
hl.device({ name = "apple-spi-trackpad", tap_to_click = false })

-- Scroll nicely in the terminal.
o.window("(Alacritty|kitty)", { scroll_touchpad = 1.5 })
-- foot only applies its scrollback multiplier to wheel clicks, not precise touchpad scrolling.
Expand Down
13 changes: 13 additions & 0 deletions default/hypr/omarchy.lua
Original file line number Diff line number Diff line change
@@ -1,8 +1,20 @@
-- Omarchy Hyprland setup: helpers, defaults, and current theme overrides.

require("default.hypr.helpers")
local paths = require("default.hypr.paths")
local require_all = require("default.hypr.require_all")
local require_optional = require("default.hypr.require_optional")

-- A platform package's own defaults (default/hypr/platform/defaults/*.lua in
-- the packaged tree), loaded before Omarchy's so that a chord they bind replaces
-- Omarchy's default for it and the user's files can override both. See
-- o.platform_chords in helpers.lua.
local platform_defaults = paths.packaged_path .. "/default/hypr/platform/defaults"
package.path = platform_defaults .. "/?.lua;" .. package.path
o.binding_phase = "platform"
require_all.files(platform_defaults, nil, { reload = true })
o.binding_phase = "defaults"

-- Use Omarchy defaults, but don't edit these directly.
require("default.hypr.autostart")
if _G.omarchy_default_bindings ~= false then
Expand All @@ -13,6 +25,7 @@ if _G.omarchy_default_bindings ~= false then
require("default.hypr.bindings.voxtype")
require_optional.module("default.hypr.bindings.applications")
end
o.binding_phase = nil
require("default.hypr.envs")
require("default.hypr.looknfeel")
require("default.hypr.qconsole")
Expand Down
7 changes: 4 additions & 3 deletions default/hypr/toggles.lua
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,10 @@ disabled_input_device("touchscreen")

require("default.hypr.workspace-layouts")

-- A platform package's own defaults, loaded after the user's files so that the
-- user's settings can keep them out. They are read from the packaged tree, so a
-- development checkout keeps them.
-- A platform package's own late defaults (default/hypr/platform/*.lua), loaded
-- after the user's files so that the user's settings can keep them out (a
-- default gesture stepping aside for the user's own, say). They are read from
-- the packaged tree, so a development checkout in OMARCHY_PATH keeps them.
local platform_dir = paths.packaged_path .. "/default/hypr/platform"
package.path = platform_dir .. "/?.lua;" .. package.path
require_all.files(platform_dir, nil, { reload = true })
9 changes: 9 additions & 0 deletions docs/lifecycle-dispatch.md
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,15 @@ The recovery passphrase is core code; whether setup creates one is the platform

Snapshot restore is not a dispatch operation. A Limine Mac restores through `limine-snapper-restore`, as x86 does: limine-snapper-sync swaps the root and puts the snapshot's saved UKI and menu entry back itself, so nothing is rebuilt afterwards. `omarchy-mac-boot` checks the restore through limine-snapper-sync's own hook interface, the one its Limine activation gate already uses. Its pre hook (`/etc/boot/hooks/pre.d/04-omarchy-mac-snapshot-check`) runs the boot check `update-verify` runs (`--boot-chain`) on the booted snapshot, with no reboot pending, and stops a restore the boot files do not match. Its post hook (`post.d/99-omarchy-mac-snapshot-check`) checks the root the restore put back, which limine-snapper-restore's own list can make a different snapshot, and keeps the reboot from being offered when it does not match. `omarchy-snapshot restore` sends a Mac that still boots GRUB to `omarchy-system-snapshot-restore`, which refuses a Limine Mac and asks `omarchy-mac-snapshot-check` about the chosen snapshot on a GRUB one.

## Platform desktop defaults

A platform's runtime package can also ship Hyprland defaults, without an operation and without a branch in Omarchy's config. Both directories are read from the packaged tree (`/usr/share/omarchy`, which a development checkout in `OMARCHY_PATH` does not replace; `OMARCHY_PACKAGED_PATH` moves it for tests), and Omarchy ships nothing in either.

- **Early: `default/hypr/platform/defaults/*.lua`**, loaded by `default/hypr/omarchy.lua` right after the helpers, before Omarchy's own defaults and the user's files. A chord bound there with `o.bind` replaces Omarchy's default for the same chord (`o.platform_chords`), and a function added to `o.bind_decorators` runs for every later `o.bind`, Omarchy's and the user's, before the bind is made, so it can bind something that has to run first (Hyprland runs a key press's binds in the order they were added). The user's files load after and can unbind or rebind any of it. A file that binds keys honors `omarchy_default_bindings = false`. Settings Omarchy's defaults also set belong in the late directory.
- **Late: `default/hypr/platform/*.lua`**, loaded by `default/hypr/toggles.lua` after the user's files, for defaults that must see the user's: `o.registered_gestures` lists the gestures registered before it, so a default gesture can step aside for the user's own.
- **Key names: `default/omarchy/platform/key-names`**, one `<keysym> <name>` per line, which the keybindings menu shows in place of the keysym (a MacBook's `XF86MonBrightnessUp` is its F2 key).
- **Display cutouts: `default/shell/platform/display-cutouts.json`**, the camera cutouts the bar keeps a top bar out of (see `docs/omarchy-shell.md`).

## Qualcomm

Snapdragon laptops boot Limine with unified kernel images, like x86, and `qualcomm` is unregistered. Every operation is a no-op there, and provisioning uses the Limine UKI callbacks, so Dragon behaves exactly as before. To plug in a Qualcomm implementation:
Expand Down
8 changes: 8 additions & 0 deletions docs/omarchy-shell.md
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,14 @@ size-vertical = 28 # left/right bar width at base-size 12

Set `scale-with-font = false` to keep those bar sizes as fixed pixels.

A panel with a camera cutout (a notch) at its top keeps a top bar out of it: the bar is never shorter than the cutout, and its center section sits beside the right one. Omarchy knows no panel's cutout itself; the platform's own package describes them in `default/shell/platform/display-cutouts.json` under the packaged tree (`/usr/share/omarchy`):

```json
{ "panels": [ { "connector": "eDP", "width": 3024, "height": 1964, "top": 64 } ] }
```

A panel matches a screen whose connector name starts with `connector` and whose mode is `width` x `height` physical pixels; `top` is the physical rows the cutout covers. On such a panel, `[bar] notch-height` (logical pixels, not scaled with the font) sets the floor by hand. The bar reads the file when the shell starts and whenever it changes; a file installed where its directory didn't exist yet is read at the next shell start.

## Custom bar modules

If a full plugin is overkill, declare a one-off module inline in
Expand Down
1 change: 1 addition & 0 deletions packages/omarchy-mac/ORIGINS.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,4 @@ The network backend default follows Marcelo Alcantara's Apple Silicon integratio
- `omarchy-hw-apple` alias: Scott Jones, `bea1a1ba5` (Preserve optional Apple audio and hardware detection interfaces), moved from the runtime's `bin/`; root no longer falls back to anything but the predicate in `/usr/bin`.
- Three-finger workspace swipe: Marcelo Alcantara, omarchy-mac#629 (`25454328c`, `4ba3490a8`), moved from the runtime's `default/hypr/apple-gestures.lua` into the runtime's platform directory; the gesture registry it reads stays in the runtime's helpers, now on every platform.
- Steam FEX launcher setup: Scott Jones, from the runtime's Steam installer branch and migration `1789522888` (`b5463029e`); the launcher itself is omarchy-pkgs' `omarchy-steam-fex`.
- Mac desktop defaults moved into the platform hooks: Scott Jones's SMC lid binds (`30e876969`), capture chords (`b86e2aff9`), Shift+brightness on the keyboard backlight (`0022c4374`) and F1/F2 key names (`c1673ae67`); Marcelo Alcantara's menus on the built-in screen (`cf575a9d4`, `3598e5493`); the trackpad's tap-to-click default and the notch sizes (from the runtime's `BarModel.js`), moved out of the runtime's shared files unchanged in behaviour.
Loading
Loading