Skip to content
filedom
Esc
↑↓navigate↵open⌘Jpreview
On this page

filedom/system

The native macOS host bridge plus filesystem operations behind the React layer.

filedom/system is the lower-level entry point. It holds the macOS host bridge (Finder metrics, control, and input) and the filesystem operations games use to manage the desktop files they render. Use it to work below the React layer: to read live positions, drive Finder directly, capture input, or hide and restore the user’s Desktop items.

import {
  getDesktopIconPositions,
  setIconPosition,
  createFile,
  hideDesktopItems,
  restoreDesktopItems,
} from 'filedom/system';

The host functions talk to the native Swift binaries, so they only work on macOS.

Metrics & lifecycle

  • subscribeToMetrics(cb) and waitForCalibratedMetrics() stream or await the calibrated SystemMetrics (desktop width and height, icon size, grid spacing, text size, label position) that positioning depends on.
  • setupSystemUI(hide) autohides the Dock and menu bar for a session (true), then puts back the values the user had (false). The originals are recorded in ~/Library/Application Support/filedom/system-ui.json before anything changes, so the next session can still restore them after a force-quit.
  • flushPendingCommands() waits for in-flight native commands. Call it before a hard process exit so pending moves and restores finish.

Icon control

  • setIconPosition(path, x, y) and setIconPositions(...) move one or many files.
  • getDesktopIconPositions() reads the live positions Finder reports.
  • setIconColor, setFileComment, and setFileExtensionHidden set Finder metadata.
  • setCustomIconFromPath and setCustomIconFromBase64 set custom icon images.
  • synthDragAt(x, y, expectedPath?) posts a synthetic drag that raises a file’s z-order.

Grid, size & selection

  • getDesktopIconSize / setDesktopIconSize
  • getDesktopGridSpacing / setDesktopGridSpacing
  • getDesktopGridArrangement / setDesktopGridArrangement
  • getFinderSelection / setFinderSelection
  • getDesktopLabelVisibility / setDesktopLabelVisibility

Finder control

  • runFinderBatch(...) applies a batch of Finder mutations in one round-trip.
  • restartFinder() and refreshFinder() recover Finder when its state drifts.

Input

import {
  startGlobalInputListener,
  subscribeDesktopDrag,
  subscribeDesktopClick,
  checkGlobalInputPermission,
} from 'filedom/system';
  • startGlobalInputListener(cb) delivers global keydown events and returns an unsubscribe function. It needs Accessibility permission. Under Finder Mode it connects to the app’s key stream instead of starting its own listener. useGameControls in the main entry point wraps it.
  • subscribeDesktopClick, subscribeDesktopRightClick, subscribeDesktopDrag, subscribeDesktopMouseUp, and setDesktopDragRegions handle mouse interaction on the desktop surface. subscribeDesktopRightClick consumes the gesture, so Finder’s context menu never opens and the running game owns the secondary click.
  • observeDesktopRightClick(cb) receives secondary clicks without consuming them, for tooling that runs beside a game; the game’s own listener still gets the gesture. Subscribe after the game’s mouse listener is up, because observers created earlier sit behind its consuming tap and see nothing.
  • checkGlobalInputPermission() reports whether input capture is allowed.

Filesystem operations

import {
  createFile,
  createDirectory,
  writeFile,
  renameFile,
  deleteFile,
  scanDirectory,
  getFileMetadata,
  pathExists,
  nameRegistryFor,
} from 'filedom/system';

These are the filesystem helpers games use to manage the files they render. nameRegistryFor returns the per-root name registry, the library’s single filename authority for a desktop directory. createFile, createDirectory, and renameFile refuse to write over a path that filedom did not create, and isClobberRefusal(error) identifies that refusal.

const names = nameRegistryFor();        // the active desktop root
const path = names.mintPath();          // a fresh, invisible, never-reused path

Components mint from this registry themselves: Stage sprites, overlays, and banners all use it. Call it only for desktop files you place yourself outside any component, and use it instead of inventing names. A name’s shape is a z-order input, and a path a previous run used inherits that run’s stacking (law 3).

FilePool

FilePool is the recycling handle allocator the Stage uses internally. It is exported for code that manages files outside a stage:

import { FilePool } from 'filedom/system';

const pool = new FilePool({ create: (type, index) => makeHandle(type, index) });
pool.prewarm(['red', 'blue']);
const h = pool.acquire('red');   // pops a warm handle, or mints one
pool.release(h);                 // back to the free list
pool.available('red');           // free count
pool.grow('red', 4);             // top up ahead of demand (front of free list)
pool.all();                      // every handle ever minted

release throws on a double release or on a handle the pool never minted. Either mistake would put one desktop file into circulation as two logical sprites, so the error surfaces the lifecycle bug at the call that caused it.

Grown handles join the front of the free list, and acquire takes from the back, so new handles warm at the park while older warm handles are used first.

Desktop stash & restore

  • hideDesktopItems() sets the macOS hidden flag on the user’s Desktop items so a game has a clean board. Nothing is moved: the files stay in ~/Desktop, keep their icon positions, and Finder stops drawing them.
  • restoreDesktopItems() clears the flag again.

Before any flag changes, hideDesktopItems() records each item’s identity in a journal at ~/.filedom-desktop-stash. If a previous run crashed, its journal is recovered before anything new is hidden. Restore reveals an item only when it is still the same file and still carries the flag. Items the user had already hidden stay hidden, and anything the user replaced, deleted, or revealed during the session is left alone.

Finder still draws hidden items, dimmed and clickable, while its “show all files” setting is on. If that setting is on, the session turns it off with Cmd+Shift+. (recorded in the journal) and turns it back on afterwards. Synthesizing that keystroke needs an Accessibility grant; if the toggle cannot be confirmed, hiding fails before any item is hidden.

startSession calls these functions by default. Under Finder Mode (FINDER_MODE_SUPERVISED), the signed app hides and restores the Desktop itself, with its own journal at ~/.finder-mode-stash, and the session skips this step.

System helpers

getDesktopPath(), showDesktop(), and showDialog(...). Audio is in filedom/sound.

Was this page helpful?