[
  {
    "path": ".github/FUNDING.yml",
    "content": "# These are supported funding model platforms\n\npatreon: aasvi\n"
  },
  {
    "path": ".gitignore",
    "content": "/bin\n/tests/bin\n/archive\n/src/osax/loader_bin.c\n/src/osax/payload_bin.c\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# Changelog\n\nAll notable changes to this project will be documented in this file.\n\nThis project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).\n\n## [Unreleased]\n### Changed\n- Validate scripting-addition socket message length to prevent possbility of stack corruption [#2751](https://github.com/asmvik/yabai/issues/2751)\n\n## [7.1.17] - 2026-02-21\n### Changed\n- Update scripting addition for macOS 26.2 and 26.3 Apple Silicon [#2693](https://github.com/asmvik/yabai/issues/2693)\n- Fix window sub-level query for macOS 26 [#2726](https://github.com/asmvik/yabai/issues/2726)\n\n## [7.1.16] - 2025-10-07\n### Changed\n- Preliminary support for macOS Tahoe (mostly for Apple Silicon) [#2634](https://github.com/asmvik/yabai/issues/2634) [#2680](https://github.com/asmvik/yabai/issues/2680)\n\n## [7.1.15] - 2025-05-18\n### Changed\n- Fetching NSRunningApplication for some processes will fail randomly; delay and retry when this happens [#2595](https://github.com/asmvik/yabai/issues/2595)\n- Fixed crash when sequence of window commands initiated while focused window is untracked [#2606](https://github.com/asmvik/yabai/issues/2606)\n- Change when window_unobserve is called [#2605](https://github.com/asmvik/yabai/issues/2605)\n\n## [7.1.14] - 2025-04-05\n### Changed\n- Update scripting addition for macOS 15.4 Intel x86-64 [#2589](https://github.com/asmvik/yabai/issues/2589)\n\n## [7.1.13] - 2025-03-23\n### Changed\n- Implement different method of focusing displays without synthesizing mouse-events [#2452](https://github.com/asmvik/yabai/issues/2452) [#2289](https://github.com/asmvik/yabai/issues/2289)\n- Display --focus command should return an error if the target display already has focus [#2574](https://github.com/asmvik/yabai/issues/2574)\n\n## [7.1.12] - 2025-03-22\n### Changed\n- Ignore applications that are being debugged [#599](https://github.com/asmvik/yabai/issues/599)\n- Fixed query output for `config auto_balance`; regression after [#190](https://github.com/asmvik/yabai/issues/190) in v7.1.6 [#2579](https://github.com/asmvik/yabai/issues/2579)\n- Workaround to acquire AX-References for windows on inactive spaces should only run at startup [#2575](https://github.com/asmvik/yabai/issues/2575)\n\n## [7.1.11] - 2025-03-09\n### Changed\n- Update scripting addition for macOS Sequoia 15.4 Beta 2 [#2558](https://github.com/asmvik/yabai/issues/2558)\n- Implement cached values for window query system to fix responsiveness issues for slow/frozen applications [#2377](https://github.com/asmvik/yabai/issues/2377)\n- Properly escape control characters U+0000 - U+001f in queries [#2517](https://github.com/asmvik/yabai/issues/2517)\n\n## [7.1.10] - 2025-02-14\n### Changed\n- Adjust to macOS API change in Sequoia 15.3 altering the behaviour of SPACE_CREATED and SPACE_DESTROYED event notifications [#2548](https://github.com/asmvik/yabai/issues/2548)\n- Resolved weird issues after making assumptions in changes made for v7.1.7 [#2551](https://github.com/asmvik/yabai/issues/2551)\n\n## [7.1.9] - 2025-02-12\n### Changed\n- Resolved issue with window query partially including non-windows, causing malformed json output (comma separators) [#2533](https://github.com/asmvik/yabai/issues/2533)\n\n## [7.1.8] - 2025-02-09\n### Changed\n- Resolved window query flag serialization issue introduced in v7.1.7.... [#2532](https://github.com/asmvik/yabai/issues/2532)\n\n## [7.1.7] - 2025-02-09\n### Changed\n- Implemented workaround to acquire AX-References for windows on inactive spaces [#2320](https://github.com/asmvik/yabai/issues/2320) [#2480](https://github.com/asmvik/yabai/issues/2480)\n\n### Removed\n- The window query property `has-ax-reference` has been removed because of the implemented workaround for AX-References rendering the information useless/unnecessary [#2320](https://github.com/asmvik/yabai/issues/2320) [#2480](https://github.com/asmvik/yabai/issues/2480)\n\n## [7.1.6] - 2025-01-22\n### Added\n- New config option `window_insertion_point` to specify where new windows are inserted [#2510](https://github.com/asmvik/yabai/issues/2510)\n\n### Changed\n- Update scripting addition for macOS Sonoma 14.7.2 and Sequoia 15.3 [#2497](https://github.com/asmvik/yabai/issues/2497)\n- Fix issue with patching macOS space switching animation on macOS 14.7 Intel x86-64 [#2440](https://github.com/asmvik/yabai/issues/2440)\n- Config *global setting* `split_type` is now categorized as a *space setting* instead [#2479](https://github.com/asmvik/yabai/issues/2479)\n- Additional options `x-axis` and `y-axis` can now be used with `config auto_balance` command [#190](https://github.com/asmvik/yabai/issues/190)\n- Minor adjustment to screen-padding and window-gap [#2502](https://github.com/asmvik/yabai/issues/2502)\n- Fix issue that could cause a crash when a newly launched application terminates rapidly during/after launch [#2522](https://github.com/asmvik/yabai/issues/2522)\n\n## [7.1.5] - 2024-11-01\n### Changed\n- Update scripting addition for macOS Sequoia 15.1 [#2441](https://github.com/asmvik/yabai/issues/2441)\n\n## [7.1.4] - 2024-09-26\n### Changed\n- Implement fallback method for macOS Sequoia to detect when a window is destroyed, because of weird system problems when other third-party software is in use [#2431](https://github.com/asmvik/yabai/issues/2431)\n\n## [7.1.3] - 2024-09-17\n### Changed\n- Fix issue causing sticky scratchpad windows to not work as expected [#2394](https://github.com/asmvik/yabai/issues/2394)\n- Fix window query scratchpad property flag [#2391](https://github.com/asmvik/yabai/issues/2391)\n- When a new window is added to a stack it is placed after the currently focused window (instead of the end) [#2387](https://github.com/asmvik/yabai/issues/2387)\n- Moving windows to other spaces requires SIP to be partially disabled for macOS Monterey 12.7.x [#2408](https://github.com/asmvik/yabai/issues/2408)\n\n## [7.1.2] - 2024-08-10\n### Changed\n- Allow *window_animation_duration* to be set to `0.0` without requesting *Screen Capture* permissions [#2378](https://github.com/asmvik/yabai/issues/2378)\n- Add new *window --toggle* option `windowed-fullscreen` to fullscreen a window, ignoring all configured padding for both managed and unmanaged windows [#2221](https://github.com/asmvik/yabai/issues/2221)\n- Moving windows to other spaces requires SIP to be disabled on macOS Sequoia [#2324](https://github.com/asmvik/yabai/issues/2324) [#2331](https://github.com/asmvik/yabai/issues/2331)\n- Updated scripting-addition mach loader/injection and payload to work for macOS Sequoia Beta 1, 2, 3, 4, and 5 [#2324](https://github.com/asmvik/yabai/issues/2324) [#2331](https://github.com/asmvik/yabai/issues/2331)\n- Extend *stack window selector* to allow numeric indices: `yabai -m window --focus stack.3` [#2342](https://github.com/asmvik/yabai/issues/2342)\n\n## [7.1.1] - 2024-05-18\n### Changed\n- Assigning a window to scratchpad using rules would incorrectly hide that window immediately [#2203](https://github.com/asmvik/yabai/issues/2203)\n- Moving windows to other spaces should once again work on macOS Sonoma 14.5 (and newer) [#2240](https://github.com/asmvik/yabai/issues/2240)\n- Update scripting addition for macOS Sonoma 14.5 Intel (Apple Silicon is already supported in v7.1.0) [#2277](https://github.com/asmvik/yabai/issues/2277)\n\n## [7.1.0] - 2024-04-04\n### Added\n- Added window commands `--raise ['<WINDOW_SEL>']` and `--lower ['<WINDOW_SEL>']` [#2198](https://github.com/asmvik/yabai/issues/2198)\n- Added window commands `--scratchpad ['<LABEL>|recover']` and `--toggle <LABEL>` [#2203](https://github.com/asmvik/yabai/issues/2203)\n- Added rule property `scratchpad='<LABEL>'` to automatically assign a window to a scratchpad [#2203](https://github.com/asmvik/yabai/issues/2203)\n- Added window and rule query property `scratchpad` [#2203](https://github.com/asmvik/yabai/issues/2203)\n\n### Changed\n- Config *global setting* `auto_balance` is now categorized as a *space setting* instead [#2200](https://github.com/asmvik/yabai/issues/2200)\n- Rule property space should have higher precedence than display [#2206](https://github.com/asmvik/yabai/issues/2206)\n- Properly escape app and title, role and subrole, regex when listing rules [#2205](https://github.com/asmvik/yabai/issues/2205)\n- Properly escape app and title regex when listing signals [#2207](https://github.com/asmvik/yabai/issues/2207)\n- Fixed issue that could cause a crash when trying to detect windows opened before yabai launch [#2208](https://github.com/asmvik/yabai/issues/2208)\n- Fixed issue that could cause a crash when terminating an application in rare cases where there is a large backlog of events [#2210](https://github.com/asmvik/yabai/issues/2210)\n\n## [7.0.4] - 2024-03-30\n### Changed\n- Consecutive window resize operations would not work correctly because it used a cached value for the window frame [#2182](https://github.com/asmvik/yabai/issues/2182)\n- Fix weird delay caused by interaction between macOS System APIs on Sonoma when using `--insert` in combination with other commands in rapid succession [#2188](https://github.com/asmvik/yabai/issues/2188)\n- Change how background processes are detected and handled [#2190](https://github.com/asmvik/yabai/issues/2190) [#2168](https://github.com/asmvik/yabai/issues/2168) [#2194](https://github.com/asmvik/yabai/issues/2194)\n\n## [7.0.3] - 2024-03-22\n### Changed\n- Whitelist zathura process for management because it incorrectly identifies as a background-only process [#2168](https://github.com/asmvik/yabai/issues/2168)\n- Config should be executed if the exec-bit is set, but interpreted if it is not [#2169](https://github.com/asmvik/yabai/issues/2169)\n- Window query property is-sticky would sometimes show the wrong value [#2175](https://github.com/asmvik/yabai/issues/2175)\n- Query commands now take an optional list of properties to select which fields should be included in the output [#2180](https://github.com/asmvik/yabai/issues/2180)\n\n## [7.0.2] - 2024-03-13\n### Changed\n- Decouple/normalize timer used for mouse_action resize throttling because event timestep varies between macOS versions [#2160](https://github.com/asmvik/yabai/issues/2160)\n\n## [7.0.1] - 2024-03-13\n### Changed\n- Fix mouse_action resize throttling issue caused by friggin Apple event timestep garbage [#2160](https://github.com/asmvik/yabai/issues/2160)\n\n## [7.0.0] - 2024-03-13\n### Added\n- Make space visible on display without stealing focus (the space must belong to the display) [#2113](https://github.com/asmvik/yabai/issues/2113)\n- Restore application_activated and application_deactivated signals [#2122](https://github.com/asmvik/yabai/issues/2122)\n- Restore system_woke signal [#2124](https://github.com/asmvik/yabai/issues/2124)\n- Added new window rules command `--apply` to apply the effects of (specific or all existing rules), or an ad-hoc rule that should only apply once, to all known windows [#2123](https://github.com/asmvik/yabai/issues/2123)\n- Added new argument `--one-shot` to window rules command `--add` to specify that this rule only runs once [#2123](https://github.com/asmvik/yabai/issues/2123)\n- Window rules marked as `--one-shot` will be ignored completely by the `--apply` command [#2123](https://github.com/asmvik/yabai/issues/2123)\n- Window queries include a new property `has-ax-reference` [#2126](https://github.com/asmvik/yabai/issues/2126)\n- Window command `--sub-layer` and rule property `sub-layer` has been added to replace `--layer` and `layer` respectively [#2128](https://github.com/asmvik/yabai/issues/2128)\n- Added new command `config window_animation_easing ..` to select easing function [#2131](https://github.com/asmvik/yabai/issues/2131)\n- Added new command `space --equalize .. ` to reset split ratios of all nodes within a space to default value [#2133](https://github.com/asmvik/yabai/issues/2133)\n- Added new command `space --switch ..` to focus a space (substitute with current focus) regardless of its display [#549](https://github.com/asmvik/yabai/issues/549)\n- Added new command `config display_arrangement_order ..` to change how yabai interprets arrangement indices used to select displays [#550](https://github.com/asmvik/yabai/issues/550)\n- Added new command `display --label ..` and display query property `label` (works like space labels) [#1616](https://github.com/asmvik/yabai/issues/1616)\n- Added display query property `has-focus` [#1616](https://github.com/asmvik/yabai/issues/1616)\n\n### Changed\n- Preserve relative space ordering when moving spaces to other displays [#2114](https://github.com/asmvik/yabai/issues/2114)\n- Make window animations compatible with window opacity fade effect [#2116](https://github.com/asmvik/yabai/issues/2116)\n- Better filter for background processes [#2118](https://github.com/asmvik/yabai/issues/2118)\n- Managed windows should snap back into place when moved incorrectly using the mouse [#1199](https://github.com/asmvik/yabai/issues/1199) [#2066](https://github.com/asmvik/yabai/issues/2066)\n- Managed windows should correct their frame when modified by external means [#2117](https://github.com/asmvik/yabai/issues/2117)\n- Window frame would sometimes not be set correctly when using window animations [#2120](https://github.com/asmvik/yabai/issues/2120)\n- Allow resetting window opacity in window rules [#2127](https://github.com/asmvik/yabai/issues/2127)\n- When adding new window rules, their effects will only apply to *windows that open after the rule has been added* [#2123](https://github.com/asmvik/yabai/issues/2123)\n- Window queries will now list information about all windows even if yabai does not yet have an AX-reference. Windows that are missing an AX-reference cannot be acted upon until its space has become active [#2126](https://github.com/asmvik/yabai/issues/2126)\n- Fixed window animation flickering [#2129](https://github.com/asmvik/yabai/issues/2129)\n- Fixed weird issue with memory ownership when synthesizing events for autofocus [#2130](https://github.com/asmvik/yabai/issues/2130)\n- Combine effects of all matching window rules before applying rule effects [#2123](https://github.com/asmvik/yabai/issues/2123)\n- Window insert feedback visual should use same layer as parent window [#2132](https://github.com/asmvik/yabai/issues/2132)\n- Updated scripting-addition mach loader/injection and payload to work for macOS Sonoma 14.4 [#2146](https://github.com/asmvik/yabai/issues/2146) [#2150](https://github.com/asmvik/yabai/issues/2150)\n- Some space and display signals (where possible) now pass additional env.vars. containing the user-facing index that can be used with yabai commands [#2152](https://github.com/asmvik/yabai/issues/2152)\n- Fixed some window commands that would incorrectly require a focused window to exist in order to operate on an arbitrary window through its id [#2153](https://github.com/asmvik/yabai/issues/2153)\n- Window grid command will now apply the configured space window gap [#932](https://github.com/asmvik/yabai/issues/932)\n- Config file no longer requires the exec-permission-bit to be set [#1993](https://github.com/asmvik/yabai/issues/1993)\n- Allow `space --swap ..` command to swap spaces between displays. This works by swapping all windows (and interior state) rather than macOS spaces [#549](https://github.com/asmvik/yabai/issues/549)\n- Focus-follows-mouse should now be a lot more responsive [#1958](https://github.com/asmvik/yabai/issues/1958)\n- Fixed issue causing Dock to not hide if the cursor is moved before animation finishes [#1552](https://github.com/asmvik/yabai/issues/1552)\n- Fixed issue causing Dock to not respect autohide-delay preference [#1951](https://github.com/asmvik/yabai/issues/1951)\n- Fixed issue where using alt as mouse_modifier would trigger macOS functionality that hides all windows [#2154](https://github.com/asmvik/yabai/issues/2154) [#1809](https://github.com/asmvik/yabai/issues/1809)\n- Fixed absurd issue where subscribing to mouse_events would cause delayed input in some cases when magic mouse is connected [#1877](https://github.com/asmvik/yabai/issues/1877)\n\n### Removed\n- When adding new window rules, their effects will only apply to *windows that open after the rule has been added*. To restore old behavior, run `yabai -m rule --apply` after adding all rules [#2123](https://github.com/asmvik/yabai/issues/2123)\n- Window command `--layer` and rule property `layer` has been renamed to `--sub-layer` and `sub-layer` respectively [#2128](https://github.com/asmvik/yabai/issues/2128)\n\n## [6.0.15] - 2024-02-22\n### Changed\n- Fix weird segfault with consumed mouse-event [#1801](https://github.com/asmvik/yabai/issues/1801)\n- Implement visual feedback for mouse_drag actions, controlled by `insert_feedback_color` [#2109](https://github.com/asmvik/yabai/issues/2109)\n\n## [6.0.14] - 2024-02-21\n### Changed\n- Mouse actions could stop working if the acting window was destroyed while a mouse action was in progress [#2038](https://github.com/asmvik/yabai/issues/2038)\n- Replicate consumed mouse-click when no mouse-drag action is initiated [#1801](https://github.com/asmvik/yabai/issues/1801)\n\n## [6.0.13] - 2024-02-19\n### Changed\n- Lock assigned handle while mouse_action resize is in progress [#2102](https://github.com/asmvik/yabai/issues/2102)\n- Modify \"no click-zone\" when using focus_follows_mouse to activate an empty display [#1892](https://github.com/asmvik/yabai/issues/1892) [#863](https://github.com/asmvik/yabai/issues/863)\n\n## [6.0.12] - 2024-02-12\n### Added\n- New config option `menubar_opacity` to make the menubar transparent (or even completely hidden, ignoring mouse-events) [#2091](https://github.com/asmvik/yabai/issues/2091)\n\n### Changed\n- Using `--toggle native-fullscreen` to exit native-fullscreen mode could sometimes leave the window unmanaged/untiled [#2090](https://github.com/asmvik/yabai/issues/2090)\n\n## [6.0.11] - 2024-02-11\n### Changed\n- Adjustments to mission control integration on Ventura and Sonoma due to subtle issues with window operations that cross monitor boundaries [#2088](https://github.com/asmvik/yabai/issues/2088)\n\n## [6.0.10] - 2024-02-10\n### Changed\n- Fixed caching issue when using focus_follows_mouse to switch focus between monitors with no windows [#2075](https://github.com/asmvik/yabai/issues/2075)\n- Attempt to resolve issue where some applications do not incorrectly pass along NSRunningApplication isObservable and isFinishedLaunching properties [#1367](https://github.com/asmvik/yabai/issues/1367)\n- Add compatibility between window animations and JankyBorders [#2087](https://github.com/asmvik/yabai/issues/2087)\n\n### Removed\n- Config option `window_animation_frame_rate` has been removed. Animations use CVDisplayLink to match monitor refresh rate [#2087](https://github.com/asmvik/yabai/issues/2087)\n\n## [6.0.9] - 2024-02-04\n### Changed\n- Fix detection of windows that are minimized before yabai is launched [#1833](https://github.com/asmvik/yabai/issues/1833)\n\n## [6.0.8] - 2024-02-04\n### Changed\n- All windows that report a non-standard window_level should be treated as floating (permanently), unless otherwise specified through manage=on rules [#2055](https://github.com/asmvik/yabai/issues/2055)\n- Fix detection of windows that are minimized before yabai is launched [#1833](https://github.com/asmvik/yabai/issues/1833)\n\n## [6.0.7] - 2024-01-25\n### Changed\n- Update scripting addition for macOS Sonoma 14.3 Intel (Apple Silicon is already supported in v6.0.6) [#2065](https://github.com/asmvik/yabai/issues/2065)\n- Fix regression causing window_destroyed signal to not trigger [#2048](https://github.com/asmvik/yabai/issues/2048)\n- Improved snappiness of window animations (time from trigger to start of animation) [#2060](https://github.com/asmvik/yabai/issues/2060)\n- Change window sublayer instead of layer, resulting in a more pleasant user experience [#2062](https://github.com/asmvik/yabai/issues/2062)\n\n## [6.0.6] - 2024-01-08\n### Changed\n- Cleanup handling of root-windows, child-windows, and window belonging to roles that are considered eligible for management [#2044](https://github.com/asmvik/yabai/issues/2044) [#2036](https://github.com/asmvik/yabai/issues/2036)\n\n## [6.0.5] - 2024-01-07\n### Changed\n- Attempt to separate root-windows from child/sub-windows to improve window detection and management logic [#2044](https://github.com/asmvik/yabai/issues/2044)\n\n## [6.0.4] - 2024-01-03\n### Changed\n- Changes to window detection logic [#2036](https://github.com/asmvik/yabai/issues/2036)\n\n## [6.0.3] - 2024-01-03\n### Changed\n- Changing window layer using rules or `window --layer` commands will exempt that window from automatic layer changes [#1929](https://github.com/asmvik/yabai/issues/1929)\n- Running `yabai --stop-service` should properly prevent yabai from starting after a reboot [#1921](https://github.com/asmvik/yabai/issues/1921)\n- `mission_control_enter/exit` signals include an environment variable to identify which mode was activated/deactivated [#2026](https://github.com/asmvik/yabai/issues/2026)\n- Stricter window type filter to avoid issues with e.g Text Completion, Input Source changes and other non-windows-that-report-as-windows [#1919](https://github.com/asmvik/yabai/issues/1919) [#1910](https://github.com/asmvik/yabai/issues/1910) [#1997](https://github.com/asmvik/yabai/issues/1997)\n- Expand process blacklist filter to ignore irrelevant processes (background services and helper services)\n\n## [6.0.2] - 2023-12-23\n### Changed\n- Update scripting addition for macOS Sonoma 14.2 and 14.2.1 [#2007](https://github.com/asmvik/yabai/issues/2007)\n- Spaces in stack layout should no longer incorrectly trigger a layout refresh on mouse down [#1493](https://github.com/asmvik/yabai/issues/1493)\n- Fix frame rounding issues causing small window displacement [#1680](https://github.com/asmvik/yabai/issues/1680)\n\n## [6.0.1] - 2023-11-12\n### Changed\n- Update scripting addition for macOS 14.1.1 (and probably 14.1) [#1936](https://github.com/asmvik/yabai/issues/1936)\n- Fix issue with focusing stacked windows due to layer changes [#1918](https://github.com/asmvik/yabai/issues/1918)\n- Allow window swap command to work on windows that are in the same space (with layout: stack), using the stack window selectors [#1952](https://github.com/asmvik/yabai/issues/1952)\n- Fix rare crash when processing window destroyed events [#1965](https://github.com/asmvik/yabai/issues/1965)\n\n## [6.0.0] - 2023-10-10\n### Added\n- Window query property `layer` has been added [#1887](https://github.com/asmvik/yabai/issues/1887)\n\n### Changed\n- Fix issue causing window animations to flicker on macOS Ventura and Sonoma [#1879](https://github.com/asmvik/yabai/issues/1879)\n- All managed (read: tiled) windows are now automatically placed in the *below* layer. All unmanaged (read: floating) windows will use the default macOS *normal* layer and appear above the tiled layer, replicating the `window_topmost` functionality in a robust way [#1887](https://github.com/asmvik/yabai/issues/1887)\n- Automatic window opacity changes will now only apply to focus switches within the same space [#1887](https://github.com/asmvik/yabai/issues/1887)\n- `space --create` command now takes an optional `<DISPLAY_SEL>` instead of an optional `<SPACE_SEL>`\n\n### Removed\n- Config option `window_topmost` has been removed [#1887](https://github.com/asmvik/yabai/issues/1887)\n- Window command `--toggle` option `topmost` has been removed [#1887](https://github.com/asmvik/yabai/issues/1887)\n- Window query property `is-topmost` has been removed [#1887](https://github.com/asmvik/yabai/issues/1887)\n- Signal `application_activated` and `application_deactivated` has been removed; use `application_front_switched` instead [#1887](https://github.com/asmvik/yabai/issues/1887)\n- Window borders (and all related options/properties) have been removed [#1889](https://github.com/asmvik/yabai/issues/1889)\n\n## [5.0.9] - 2023-10-01\n### Changed\n- Updated scripting-addition to support macOS Sonoma 14.0 [#1772](https://github.com/asmvik/yabai/issues/1772)\n- Fix window focusing (autofocus, and autoraise across multiple monitors [#109](https://github.com/asmvik/yabai/issues/109)) for macOS Sonoma [#1772](https://github.com/asmvik/yabai/issues/1772)\n- Fix scripting-addition functionality that uses Dock.app connection to the WindowServer for macOS Sonoma [#1772](https://github.com/asmvik/yabai/issues/1772)\n- Fix mission-control integration for macOS Sonoma [#1772](https://github.com/asmvik/yabai/issues/1772)\n- Prevent *focus follows mouse* from activating the menubar in vertical display arrangements [#1857](https://github.com/asmvik/yabai/issues/1857)\n\n## [5.0.8] - 2023-09-12\n### Changed\n- Workaround for macOS Ventura reporting bad window levels when running yabai as a service, causing issues with window topmost [#1704](https://github.com/asmvik/yabai/issues/1704)\n\n## [5.0.7] - 2023-08-27\n### Added\n- Add launch argument `--help, -h` to print available options. [#1825](https://github.com/asmvik/yabai/issues/1825)\n\n### Changed\n- Allow window swap commands to work on windows that are in the same stack, using the stack window selectors [#960](https://github.com/asmvik/yabai/issues/960)\n- Properly remove assigned label when a space is destroyed [#1678](https://github.com/asmvik/yabai/issues/1678)\n- Add signals for `space_created` and `space_destroyed` [#1365](https://github.com/asmvik/yabai/issues/1365)\n\n## [5.0.6] - 2023-05-27\n### Changed\n- Change launchd service to only restart automatically upon crashes. You will need to run `yabai --uninstall-service` and `yabai --install-service`. [#1755](https://github.com/asmvik/yabai/issues/1755)\n\n## [5.0.5] - 2023-05-21\n### Changed\n- Create `LaunchAgents` folder in `~/Library` when installing service file, if the directory does not already exist [#1728](https://github.com/asmvik/yabai/issues/1728)\n- Changed how the users home directory is determined when managing service file [#1742](https://github.com/asmvik/yabai/issues/1742)\n- Calculate memory requirement of service file path and contents instead of using static storage [#1749](https://github.com/asmvik/yabai/issues/1749)\n- Window selector `stack.first` and `stack.last` should return an error when there is no stack [#1748](https://github.com/asmvik/yabai/issues/1748)\n- Fixed off-by-one when checking frame positions in `xxx_in_direction` [#1511](https://github.com/asmvik/yabai/issues/1511) [#1463](https://github.com/asmvik/yabai/issues/1463)\n\n## [5.0.4] - 2023-05-01\n### Added\n- Added launch arguments to manage launchd service: `--install-service`, `--uninstall-service`, `--start-service`, `--restart-service`, `--stop-service` [#1619](https://github.com/asmvik/yabai/issues/1619)\n- Check for `-arm64e_preview_abi` bootflag on Apple Silicon before attempting to load scripting addition.\n\n## [5.0.3] - 2023-03-28\n### Changed\n- Updated scripting-addition to support macOS Ventura 13.3 [#1297](https://github.com/asmvik/yabai/issues/1297)\n- Fixed issue with window focusing caused by incorrectly intercepting a synthesized mouse event [#1551](https://github.com/asmvik/yabai/issues/1551)\n- Fixed issue with window warping across displays with only a single window tiled at both displays [#1577](https://github.com/asmvik/yabai/issues/1577)\n- Fixed issue preventing window split from being toggled for windwos on an inactive space/display [#1557](https://github.com/asmvik/yabai/issues/1557)\n- Make window zoom persistence configurable (*config window_zoom_persist*) [#1481](https://github.com/asmvik/yabai/issues/1481)\n- Make frame rate of window animations configurable (*config window_animation_frame_rate*) [#148](https://github.com/asmvik/yabai/issues/148)\n\n## [5.0.2] - 2022-12-16\n### Changed\n- Updated scripting-addition to support macOS Ventura 13.0.0-13.1.0 [#1297](https://github.com/asmvik/yabai/issues/1297)\n- Properly escape application name when returned in window queries [#1489](https://github.com/asmvik/yabai/issues/1489)\n- Remove window tags used for debugging purposes from result of window query because it could cause a crash under certain conditions when a window closes [#1475](https://github.com/asmvik/yabai/issues/1475)\n- Change window placement of warp command to be more natural when warping windows within the same space [#1435](https://github.com/asmvik/yabai/issues/1435)\n\n## [5.0.1] - 2022-09-26\n### Changed\n- Only allow *window_animation_duration* to be set if System Integrity Protection is partially disabled [#148](https://github.com/asmvik/yabai/issues/148)\n- Output useless dummy .plist file for scripting addition to silence weird AppleScript warning [#1449](https://github.com/asmvik/yabai/issues/1449)\n\n## [5.0.0] - 2022-09-23\n### Added\n- Support for animating window move/resize operations (*config window_animation_duration*) [#148](https://github.com/asmvik/yabai/issues/148)\n- Command to manually specify the default *split_type* [#1423](https://github.com/asmvik/yabai/issues/1423)\n- Window borders are now placed below and outside the window; new commands to specify hidpi, blur to act as a backdrop, and corner radius [#1430](https://github.com/asmvik/yabai/issues/1430)\n- Add *split-child* to output of window query and introduce new options for WINDOW_SEL: *sibling*, *first_nephew*, *second_nephew*, *uncle*, *first_cousin*, *second_cousin* [#192](https://github.com/asmvik/yabai/issues/192)\n\n### Changed\n- Implemented a workaround to support *window_opacity_duration*, bypassing the Apple bug [#1406](https://github.com/asmvik/yabai/issues/1406)\n- Fix regression causing a window to be moved to the active space of an inactive display when sent to an inactive space of an inactive display [#1053](https://github.com/asmvik/yabai/issues/1053)\n- Fix regression causing hidden windows to not show in window queries [#1421](https://github.com/asmvik/yabai/issues/1421)\n- Clamp split ratio instead of resetting when an out of range / invalid value is given [#1401](https://github.com/asmvik/yabai/pull/1401)\n- Applying rule with property *manage=on* would cause both minimized and hidden windows to be managed, even though the window is not visible [#1418](https://github.com/asmvik/yabai/issues/1418)\n- Fix regression causing window sticky to not work properly [#1424](https://github.com/asmvik/yabai/issues/1424)\n- Make window zoom more flexible, allow parent-zoomed window to enter fullscreen and vice versa [#1429](https://github.com/asmvik/yabai/issues/1429)\n- Fix border size issue when moving a window to a different display on macOS Big Sur [#1229](https://github.com/asmvik/yabai/issues/1229)\n- Check Dock.app isFinishedLaunching property before attempting to inject scripting addition [#749](https://github.com/asmvik/yabai/issues/749)\n- Properly update window ordering when a window is added to the top of a stack [#1311](https://github.com/asmvik/yabai/issues/1311)\n- Properly update insertion point in a window stack when the marked window is removed from the stack [#1275](https://github.com/asmvik/yabai/issues/1275)\n- Window zoom will now persist through changes to the bsp layout [#864](https://github.com/asmvik/yabai/issues/864)\n\n### Removed\n- Removed support for macOS High Sierra, Mojave, and Catalina.\n- Removed launch arguments *--install-sa* and *--check-sa*. Running *--load-sa* will automatically install/update the scripting-addition when necessary [#1287](https://github.com/asmvik/yabai/issues/1287)\n\n## [4.0.4] - 2022-09-08\n### Changed\n- Fix null-deref when an application is spawned with a non-standard window [#1399](https://github.com/asmvik/yabai/issues/1399)\n\n## [4.0.3] - 2022-09-07\n### Changed\n- Allow combining commands for *config*, *space*, and *window* domains [#1371](https://github.com/asmvik/yabai/issues/1371)\n- Fallback to using the AX API for *mouse_action move* if the scripting-addition is not available [#1376](https://github.com/asmvik/yabai/issues/1376)\n- Add *role* and *subrole* filter to window rules [#1398](https://github.com/asmvik/yabai/issues/1398)\n\n## [4.0.2] - 2022-08-24\n### Changed\n- Fixed an issue that in rare occasions caused yabai to freeze when focusing an inactve space on an inactive display [#1309](https://github.com/asmvik/yabai/issues/1309).\n- Fixed an issue that caused a window to incorrectly become focused when assigned to a space through rules [#1370](https://github.com/asmvik/yabai/issues/1370)\n- Fixed an issue that caused windows to snap back to its original position when moved between displays (to an inactive space) using mission-control [#820](https://github.com/asmvik/yabai/issues/820)\n\n## [4.0.1] - 2022-05-17\n### Changed\n- The scripting-addition will now also remove the space switch animation when using cmd+tab, clicking on an item in the Dock, and using the numeric macOS mission-control keyboard shortcuts [#1235](https://github.com/asmvik/yabai/issues/1235)\n- Improved logic used to determine the target window in a given direction [#1220](https://github.com/asmvik/yabai/issues/1220)\n- Improve behaviour of *focus_follows_mouse autoraise*, preventing a window from being raised if it would occlude some other **floating window** [#1246](https://github.com/asmvik/yabai/issues/1246)\n- The rule option *mouse_follows_focus* should now work properly (values were inverted) [#1267](https://github.com/asmvik/yabai/issues/1267)\n- Remove minor shadow artifact from border windows [#1056](https://github.com/asmvik/yabai/issues/1056)\n\n## [4.0.0] - 2022-03-16\n### Added\n- New config *window_origin_display* to specify which display a window should become managed at upon creation [#951](https://github.com/asmvik/yabai/issues/951)\n\n### Changed\n- Window borders no longer require SIP to be disabled [#1054](https://github.com/asmvik/yabai/issues/1054)\n- WINDOW_SEL *prev* should correctly identify the correct window in a nested tree [#1114](https://github.com/asmvik/yabai/issues/1114)\n- Fixed an issue with the way unix sockets were handled that would cause an incoming connection to drop in rare occasions [#1107](https://github.com/asmvik/yabai/issues/1107)\n- Update scripting addition to support macOS 12.0.0 -> 12.3 [#1054](https://github.com/asmvik/yabai/issues/1054)\n- Fixed an issue that would cause the target window to snap back to its previous position when moved between displays using the cursor inside mission-control [#820](https://github.com/asmvik/yabai/issues/820)\n- Properly drain autoreleased objects (from Apple frameworks) [#751](https://github.com/asmvik/yabai/issues/751)\n- Detect and manage windows that are moved into the first space of a display when a space with active windows on it is destroyed [#813](https://github.com/asmvik/yabai/issues/813)\n- The command *space --balance* now takes an optional axis as its argument [#985](https://github.com/asmvik/yabai/issues/985)\n- Malformed windows that are managed through rules should be eligible for window alpha, focus follows mouse, and window borders [#788](https://github.com/asmvik/yabai/issues/788)\n- Improve behaviour of *focus_follows_mouse autoraise*, preventing a window from being raised if it would occlude some other window. autoraise is temporarily disabled while a menu is opened. [#407](https://github.com/asmvik/yabai/issues/407)\n- Work around broken Apple code for retrieving menubar dimensions on Apple Silicon M1 [#793](https://github.com/asmvik/yabai/issues/793)\n- Rework query attributes and define dataformat as part of the API [#775](https://github.com/asmvik/yabai/issues/775)\n- Properly clear space.last-window and space.first-window query attributes when the last window is made floating [#786](https://github.com/asmvik/yabai/issues/786)\n- Reworked signal system; events are no longer coupled 1-1 with observed system events.\nSome events are now eligible for a new filter, *active*, only triggering for the application/window with key-focus.\nThe *window_focused* signal is now triggered when the key-window changes, regardless of whether its application is frontmost or not.\nThe *window_created* signal is now triggered for windows that are implicitly created at application launch.\nThe *window_destroyed* signal is now triggered for windows that are implicitly destroyed at application exit; it is also eligible for *app* filter [#581](https://github.com/asmvik/yabai/issues/581)\n\n### Removed\n- The following signals have been removed: *mouse_up*, *mouse_down*, *mouse_dragged*, *mouse_moved*, *mission_control_check_for_exit*, *menu_opened*, *system_woke*, *daemon_message*\n\n## [3.3.10] - 2021-05-26\n### Changed\n- Update scripting addition to support macOS 10.15.7 Supplemental Update\n\n## [3.3.9] - 2021-05-25\n### Changed\n- Update scripting addition to support macOS 11.4\n\n## [3.3.8] - 2021-04-28\n### Changed\n- Update scripting addition to support macOS 11.3\n\n## [3.3.7] - 2021-02-02\n### Changed\n- Update scripting addition to support macOS 11.2 [#823](https://github.com/asmvik/yabai/issues/823)\n\n## [3.3.6] - 2020-12-18\n### Changed\n- Update scripting addition to support macOS 11.1 [#762](https://github.com/asmvik/yabai/issues/762)\n- Try to workaround resizing issues in some applications due to weird undocumented accessibility properties [#109](https://github.com/asmvik/yabai/issues/109)\n- A sticky window will implicitly be treated as floating, but should not actually set the floating property [#760](https://github.com/asmvik/yabai/issues/760)\n\n## [3.3.5] - 2020-12-03\n### Changed\n- Improved SIP detection logic [#716](https://github.com/asmvik/yabai/issues/716)\n- Windows that do not report a title at all should be treated as having the empty string as its title [#707](https://github.com/asmvik/yabai/issues/707)\n- Allow *SPACE_SEL* to be used instead of *mission-control index* when specifying config options for a specific space [#705](https://github.com/asmvik/yabai/issues/705)\n- Native fullscreen transitions would freeze on macOS Mojave due to internal API differences between macOS version [#690](https://github.com/asmvik/yabai/issues/690)\n- Report proper error message when trying to use absolute resizing on a managed window [#661](https://github.com/asmvik/yabai/issues/661)\n- Space/Window commands that utilize the scripting addition should correctly return a non-zero exit code upon failure [#181](https://github.com/asmvik/yabai/issues/181)\n- Undo [#545](https://github.com/asmvik/yabai/issues/545) because it created weird issues with focus [#660](https://github.com/asmvik/yabai/issues/660)\n- Allow enabling/disabling *mouse_follows_focus* for specific windows using rules, overriding the global setting [#675](https://github.com/asmvik/yabai/issues/675)\n- Space labels are now allowed to start with a digit, as long as it is followed by at least one or more non-digit character(s) [#739](https://github.com/asmvik/yabai/issues/739)\n\n## [3.3.4] - 2020-11-14\n### Changed\n- Fixed an issue (exposed on Big Sur, maybe didn't exist on prior macOS versions ??) that caused yabai' message receiver to block in *read* [#714](https://github.com/asmvik/yabai/issues/714)\n\n## [3.3.3] - 2020-11-13\n### Changed\n- Prevent *window_opacity_duration* from being used on Big Sur, because of an Apple bug [#277](https://github.com/asmvik/yabai/issues/277)\n\n## [3.3.2] - 2020-11-13\n### Changed\n- Focusing a space incorrectly returned a non-zero exit code even when the operation succeeded [#181](https://github.com/asmvik/yabai/issues/181)\n\n## [3.3.1] - 2020-11-13\n### Changed\n- New self-signed certificate used to sign the released binaries. You will have to re-enable accessibility permissions after this install.\n- Update scripting-addition to support macOS Big Sur 11.0.1 [#589](https://github.com/asmvik/yabai/issues/589)\n- Return a non-zero exit code when focusing a space fails due to an issue with the scripting-addition [#181](https://github.com/asmvik/yabai/issues/181)\n\n## [3.3.0] - 2020-09-03\n### Added\n- Implemented support for stacking multiple windows in the same region (bsp node) [#203](https://github.com/asmvik/yabai/issues/203)\n- Implemented a fullscreen layout, using stacking as its backing mechanism [#337](https://github.com/asmvik/yabai/issues/337)\n\n### Changed\n- Fixed an issue that caused a window to not become unmanaged when a space with a single window changed to float [#586](https://github.com/asmvik/yabai/issues/586)\n- Restore opacity back to full if *window_opacity* is disabled [#585](https://github.com/asmvik/yabai/issues/585)\n- Prevent *window_opacity_duration* from being used on Catalina, because of an Apple bug [#277](https://github.com/asmvik/yabai/issues/277)\n- Update scripting-addition to support macOS Big Sur 11.0 Build 20A5354i [#589](https://github.com/asmvik/yabai/issues/589)\n- Border windows should not have shadows [#617](https://github.com/asmvik/yabai/issues/617)\n- *external_bar* should not have to be set before regular padding [#615](https://github.com/asmvik/yabai/issues/615)\n- Adjust reported mouse location to use when synthesizing events for ffm autofocus [#637](https://github.com/asmvik/yabai/issues/637)\n- Extend *SPACE_SEL* and *DISPLAY_SEL* to include the option *mouse* [#644](https://github.com/asmvik/yabai/issues/644)\n\n## [3.2.1] - 2020-06-17\n### Changed\n- Fixed a race condition upon receiving window destroy notifications from macOS because their API is garbage and reports duplicate notifications for the same window [#580](https://github.com/asmvik/yabai/issues/580)\n- focus-follows-mouse *autofocus* needs to perform some validation in order to see if the window is focusable [#578](https://github.com/asmvik/yabai/issues/578)\n- Properly set mouse location for synthesized events used by ffm autofocus [#545](https://github.com/asmvik/yabai/issues/545)\n\n## [3.2.0] - 2020-06-14\n### Added\n- Re-introduce a more efficient window border system [#565](https://github.com/asmvik/yabai/issues/565)\n- New command *window --opacity* to explicitly set the opacity of a window [#503](https://github.com/asmvik/yabai/issues/503)\n\n### Changed\n- Re-construct application switched and window created events in the correct order when the window is moved through a rule upon creation [#564](https://github.com/asmvik/yabai/issues/564)\n- Improve interaction between *window_topmost* and windows that enter native-fullscreen mode [#566](https://github.com/asmvik/yabai/issues/566)\n- Properly set focused window id cache upon window detection at first space activation [#567](https://github.com/asmvik/yabai/issues/567)\n- Don't modify the properties of AXUnknown and AXPopover windows [#535](https://github.com/asmvik/yabai/issues/535)\n- The window attribute *visible* should be 0 for minimized windows [#569](https://github.com/asmvik/yabai/issues/569)\n- Prevent *mouse_action move* from placing the y-coordinate of a window outside valid display boundaries [#570](https://github.com/asmvik/yabai/issues/570)\n- Properly allow the user to float windows that are forced to tile using window rules (manage=on) [#571](https://github.com/asmvik/yabai/issues/571)\n- Improve visual feedback effect of the *window --insert* message selection [#572](https://github.com/asmvik/yabai/issues/572)\n- Fix inconsistencies when mixing floating and sticky properties on a window [#574](https://github.com/asmvik/yabai/issues/574)\n\n## [3.1.2] - 2020-06-09\n### Changed\n- Revert changes because they can trigger a loop, causing slow window move/resize [#16](https://github.com/asmvik/yabai/issues/16)\n\n## [3.1.1] - 2020-06-08\n### Changed\n- If *focus follows mouse* is enabled, moving the cursor to a different display will now focus that display even if it is empty [#459](https://github.com/asmvik/yabai/issues/459)\n- Extend definition of *DISPLAY_SEL* to include *DIR_SEL* so that displays can be targetted using cardinal directions [#225](https://github.com/asmvik/yabai/issues/225)\n- When an application is launched or a window is created; tile the window on the space that has focus, rather than the display it spawned at [#467](https://github.com/asmvik/yabai/issues/467)\n- Properly re-adjust window frame of managed windows if they break the assigned region in response to an event not invoked directly by the user [#16](https://github.com/asmvik/yabai/issues/16)\n- Cardinal directions for *WINDOW_SEL* will only consider managed windows due to various issues with detecting the correct window [#562](https://github.com/asmvik/yabai/issues/562)\n\n## [3.1.0] - 2020-06-05\n### Added\n- New command to output list of registered rules and remove by index [#511](https://github.com/asmvik/yabai/issues/511)\n- New command to output list of registered signals and remove by index [#458](https://github.com/asmvik/yabai/issues/458)\n\n### Changed\n- Blacklist loginwindow and ScreenSaverEngine processes [#537](https://github.com/asmvik/yabai/issues/537)\n- Resolve some issues with the lifetime of NSRunningApplication [#543](https://github.com/asmvik/yabai/issues/543)\n- Resolve some obscure issue that would in some cases lead to a double-free upon process termination [#543](https://github.com/asmvik/yabai/issues/543)\n- Properly clear insert feedback settings if active on the root node when it is closed [#546](https://github.com/asmvik/yabai/issues/546)\n- Window selector **recent** should properly work across spaces [#544](https://github.com/asmvik/yabai/issues/544)\n\n## [3.0.2] - 2020-05-22\n### Changed\n- Properly clear focus-follows-mouse cache upon space change [#528](https://github.com/asmvik/yabai/issues/528)\n- Revised process type restrictions and observation requirements to correctly track some applications that don't identify correctly [#529](https://github.com/asmvik/yabai/issues/529)\n- Translate newline (0x0a) and carriage return (0x0d) when outputting window titles through the query system [#533](https://github.com/asmvik/yabai/issues/533)\n\n## [3.0.1] - 2020-05-09\n### Changed\n- Update scripting addition for macOS 10.15.5 Beta (19F72f) [#501](https://github.com/asmvik/yabai/issues/501)\n- Allow calling `space --label` without an argument to intentionally remove a previously assigned label [#514](https://github.com/asmvik/yabai/issues/514)\n- Fixed an issue where a window moved across displays using *mouse action move* would be invisible [#506](https://github.com/asmvik/yabai/issues/506)\n- Fixed an issue where the last window on a display would not properly update the focused window of the original display upon move, causing selectors to not work as expected [#505](https://github.com/asmvik/yabai/issues/505)\n\n## [3.0.0] - 2020-05-01\n### Removed\n- The deprecated rule option *topmost='<BOOL_SEL>'* has been removed.\n- The built-in status bar has been removed. [#486](https://github.com/asmvik/yabai/issues/486)\n- Window borders have been removed. [#487](https://github.com/asmvik/yabai/issues/487)\n\n### Added\n- New window commands `--minimize` and `--deminimize`. Minimized windows are now reported through window queries and there is a new attribute `minimized` to identify the current state [#379](https://github.com/asmvik/yabai/issues/379)\n- New config option `external_bar` to specify special padding compatible with the `space --toggle padding` option [#454](https://github.com/asmvik/yabai/issues/454)\n\n### Changed\n- New self-signed certificate used to sign the released binaries because the previous one expired at april 21th, 2020. You will have to re-enable accessibility permissions after this install. Sorry about that.\n- Window commands using cardinal directions use euclidean distance to identify best target window [#301](https://github.com/asmvik/yabai/issues/301)\n- Config option `insert_window_border_color` changed to `insert_feedback_color` [#487](https://github.com/asmvik/yabai/issues/487)\n- Fixed an issue that would invalidate a manual insertion point, if a mouse action triggered [#492](https://github.com/asmvik/yabai/issues/492)\n\n## [2.4.3] - 2020-04-14\n### Changed\n- Changed how *mouse down* events are handled to reduce cycles spent in macOS event tap callback [#376](https://github.com/asmvik/yabai/issues/376)\n- Fixed an issue that would cause a border to persist on fullscreen videos playing in Safari [#360](https://github.com/asmvik/yabai/issues/360)\n\n## [2.4.2] - 2020-04-12\n### Changed\n- Fix memory leak that would occur if realloc failed when reading from a socket [#436](https://github.com/asmvik/yabai/issues/436)\n- Increase number of window and space commands that return a non-zero exit code upon failure [#187](https://github.com/asmvik/yabai/issues/187)\n- Fixed a repositioning issue that would occur when a managed window was moved through click & drag through macOS native titlebar [#473](https://github.com/asmvik/yabai/issues/473)\n\n## [2.4.1] - 2020-03-01\n### Changed\n- Fixed a crash that could occur when reading from a socket (EBADF) or writing to a socket (SIGPIPE) [#430](https://github.com/asmvik/yabai/issues/430)\n\n## [2.4.0] - 2020-03-01\n### Added\n- Support exclusion for command arguments of type REGEX [#173](https://github.com/asmvik/yabai/issues/173)\n- Add ability to specify window layers; below (desktop), normal, and above (topmost) [#429](https://github.com/asmvik/yabai/issues/429)\n\n### Changed\n- Properly return focus to the active window on the current space when a window is moved through a rule [#418](https://github.com/asmvik/yabai/issues/418)\n- Prevent space operations (create, destroy, focus, swap, move and send to display) from applying while mission-control is active or the display is animating [#417](https://github.com/asmvik/yabai/issues/417)\n\n## [2.3.0] - 2020-02-14\n### Added\n- New command *space --swap SPACE_SEL* command to swap the selected space with a given space. The selected and given space must belong to the same display [#127](https://github.com/asmvik/yabai/issues/127)\n\n### Changed\n- Allow use of *DISPLAY_SEL* and *SPACE_SEL* for specifying display and space in rules [#378](https://github.com/asmvik/yabai/issues/378)\n- Extend *space --move* command to operate on *SPACE_SEL* instead of prev/next. However, the selected and given space must belong to the same display [#127](https://github.com/asmvik/yabai/issues/127)\n- Fixed issue where some window event would trigger a signal with an invalid window causing an invalid memory access [#412](https://github.com/asmvik/yabai/issues/412)\n\n## [2.2.3] - 2020-02-12\n### Changed\n- Ignore minimized windows when an application is unhidden (required by some applications like Chrome..) [#300](https://github.com/asmvik/yabai/issues/300)\n- Don't add window to the window tree when moved to a different space when the window is minimized (required by some applications like Chrome..) [#382](https://github.com/asmvik/yabai/issues/382)\n- Config file is no longer required for yabai to start [#393](https://github.com/asmvik/yabai/issues/393)\n- Clear umask before trying to install scripting addition [#400](https://github.com/asmvik/yabai/issues/400)\n- Update scripting addition to work with macos Catalina 10.15.4 Beta [#404](https://github.com/asmvik/yabai/issues/404)\n- Don't forward MOUSE_UP event to the target application if we consumed the corresponding MOUSE_DOWN event [#376](https://github.com/asmvik/yabai/issues/376)\n- Only float small windows if they are NOT resizable [#179](https://github.com/asmvik/yabai/issues/179)\n- Fixed an issue that caused filtering signals by window title to not work properly [#410](https://github.com/asmvik/yabai/issues/410)\n\n## [2.2.2] - 2020-01-20\n### Changed\n- Fix use after free.. [#375](https://github.com/asmvik/yabai/issues/375)\n\n## [2.2.1] - 2020-01-19\n### Changed\n- Specify minimum macOS target version 10.13 when compiling [#371](https://github.com/asmvik/yabai/issues/371)\n\n## [2.2.0] - 2020-01-19\n### Added\n- Ability to do real picture-in-picture of any arbitrary window [#286](https://github.com/asmvik/yabai/issues/286)\n\n### Changed\n- Disable live-resizing of bsp-layout when using mouse-drag so that we are consistent with other mouse-interactions [#341](https://github.com/asmvik/yabai/issues/341)\n- Improved spin-lock while waiting for native-fullscreen enter/exit animation to end [#339](https://github.com/asmvik/yabai/issues/339)\n- New attribute uuid returned through display queries [#346](https://github.com/asmvik/yabai/issues/346)\n- Ignore window moved events for windows in native-fullscreen mode. This is necessary because of weird macOS behaviour where a window in fullscreen-mode would trigger a window_moved event upon entering mission-control [#347](https://github.com/asmvik/yabai/issues/347)\n- Allow borders to join native-fullscreen spaces because some applications create sub-windows that are visible in fullscreen spaces [#353](https://github.com/asmvik/yabai/issues/353)\n- Ignore mouse-up event after clicking on a window maximize button [#354](https://github.com/asmvik/yabai/issues/354)\n- Proper error reporting for rules and signals [#357](https://github.com/asmvik/yabai/issues/357)\n- Properly preserve layout of spaces belonging to 4k and 5k displays after waking from sleep [#259](https://github.com/asmvik/yabai/issues/259)\n- Add guard to make sure that we cannot incorrectly tile a window twice in case of weird macOS event behaviour [#348](https://github.com/asmvik/yabai/issues/348)\n- Properly detect when mission-control is exited (with dock visible, hidden, and while a fullscreen space is active) [#319](https://github.com/asmvik/yabai/issues/319)\n\n## [2.1.3] - 2019-11-29\n### Changed\n- Fix regression causing window_destroyed signal to not be triggered (after adding app and title filter) [#308](https://github.com/asmvik/yabai/issues/308)\n- Fixed an invalid memory access when using mouse-drag to warp a window to another display when both displays contain only a single window [#309](https://github.com/asmvik/yabai/issues/309)\n- Reset zoom of all nodes in the subtree of the node that got removed [#289](https://github.com/asmvik/yabai/issues/289)\n- Adding/removing nodes to/from the tree should properly reset the zoom-state [#227](https://github.com/asmvik/yabai/issues/227)\n- Ability to enable/disable debug output at runtime [#312](https://github.com/asmvik/yabai/issues/312)\n- Fix improper calculation of overlapping parts of status_bar when truncating title, and resolve an invalid free if the title could not be truncated [#313](https://github.com/asmvik/yabai/issues/313)\n- Automatically offset the position of the status_bar if the macOS Menubar is not set to autohide [#220](https://github.com/asmvik/yabai/issues/220)\n- Remove the line drawn at the bottom of the status_bar in a *poorly dimmed* version of the background color.\n\n## [2.1.2] - 2019-11-10\n### Changed\n- Fix regression causing windows to be added more than once in some circumstances [#297](https://github.com/asmvik/yabai/issues/297)\n\n## [2.1.1] - 2019-11-10\n### Changed\n- Remove buffer-size restriction when reading data from socket [#221](https://github.com/asmvik/yabai/issues/221)\n- Replace strtok with custom function to parse key-value arguments in rules and signals [#307](https://github.com/asmvik/yabai/issues/307)\n\n## [2.1.0] - 2019-11-09\n### Added\n- Config option *window_border_radius* to specify roundness of corners [#281](https://github.com/asmvik/yabai/issues/281)\n- Config option *window_border_placement* to specify placement of window borders (exterior, interior, inset) [#216](https://github.com/asmvik/yabai/issues/216)\n- Config option *active_window_border_topmost* to specify if the active border should always stay on top of other windows (off, on) [#216](https://github.com/asmvik/yabai/issues/216)\n- Ability to label spaces, making the given label an alias that can be passed to any command taking a `<SPACE_SEL>` parameter [#119](https://github.com/asmvik/yabai/issues/119)\n- New command to adjust the split percentage of a window [#184](https://github.com/asmvik/yabai/issues/184)\n\n### Changed\n- Don't draw borders for minimized or hidden windows when a display is (dis)connected [#250](https://github.com/asmvik/yabai/issues/250)\n- Sticky windows are no longer automatically topmost. New option to toggle window always on top through command or rule. New attribute topmost returned in window queries. [#255](https://github.com/asmvik/yabai/issues/255)\n- Prevent the last user-space from being destroyed or moved to another display, because macOS does not actually support this [#182](https://github.com/asmvik/yabai/issues/182)\n- Properly read window titles on macOS Catalina [#278](https://github.com/asmvik/yabai/issues/278)\n- Smart swap/warp for window drag actions - the decision to swap or warp is based on where in the window the cursor is [#142](https://github.com/asmvik/yabai/issues/142)\n- Fix subtle lock-free multithreading bug in the event processing code [#240](https://github.com/asmvik/yabai/issues/240)\n- Changing border properties should not cause borders of minimized windows or hidden applications to be redrawn [#305](https://github.com/asmvik/yabai/issues/305)\n- Automatically truncate title of window drawn in status_bar if it would overlap with other parts of the bar [#214](https://github.com/asmvik/yabai/issues/214)\n- Remove throttling for mouse-drag move and lessen throttling for mouse-drag resize [#285](https://github.com/asmvik/yabai/issues/285)\n- Properly float/unfloat windows that are tiled/untiled when marked as managed=on|off with a rule [#297](https://github.com/asmvik/yabai/issues/297)\n\n## [2.0.1] - 2019-09-04\n### Changed\n- *window_opacity_duration* was a *copy-pasta* job [#208](https://github.com/asmvik/yabai/issues/208)\n\n## [2.0.0] - 2019-09-03\n### Added\n- Commands to toggle mission-control, show-desktop, and application expose [#147](https://github.com/asmvik/yabai/issues/147)\n- Command to close windows that provide a close button in its titlebar [#84](https://github.com/asmvik/yabai/issues/84)\n- Expose window shadow as a property in window queries and add shadow as an option to *window --toggle* [#171](https://github.com/asmvik/yabai/issues/171)\n- Config option to set the duration of the transition between active / normal window opacity [#208](https://github.com/asmvik/yabai/issues/208)\n\n### Changed\n- Automatically restart Dock.app after installing the scripting-addition, and tweak messages shown when a payload gets loaded, is already loaded or does not support the version of macOS it's running on [#135](https://github.com/asmvik/yabai/issues/135)\n- Work around macOS craziness so that we can properly tile a window after it leaves native fullscreen mode [#36](https://github.com/asmvik/yabai/issues/36)\n- Return an error for queries with invalid, named selectors [#158](https://github.com/asmvik/yabai/issues/158)\n- Resolve a potential multi-threaded issue due to \"undefined behaviour\" regarding x86 instruction ordering [#153](https://github.com/asmvik/yabai/issues/153)\n- Fix space padding and gap underflow when modified with a relative value [#141](https://github.com/asmvik/yabai/issues/141)\n- Window_* signals no longer pass the application pid [#154](https://github.com/asmvik/yabai/issues/154)\n- Ignore all windows that report a main role of AXPopover [#162](https://github.com/asmvik/yabai/issues/162)\n- Ignore all windows that report a sub role of AXUnknown [#164](https://github.com/asmvik/yabai/issues/164)\n- Track when the Dock changes preferences [#147](https://github.com/asmvik/yabai/issues/147)\n- Properly detect when mission-control is deactivated [#169](https://github.com/asmvik/yabai/issues/169)\n- Pass arguments to signals through environment variables instead [#167](https://github.com/asmvik/yabai/issues/167)\n- Revert change that made the status bar draw above other windows because of compatibility with \"windowed fullscreen\" applications [#170](https://github.com/asmvik/yabai/issues/170)\n- Warping a window should respect insert direction in scenarios where the default warp is equal to a swap operation [#146](https://github.com/asmvik/yabai/issues/146)\n- Exiting mission-control will invalidate the region assigned to Spaces/Views as because a Space may have been dragged to a different monitor [#118](https://github.com/asmvik/yabai/issues/118)\n- Application_Launched signal incorrectly fired multiple times due to accessibility retries [#175](https://github.com/asmvik/yabai/issues/175)\n- Global space settings should properly apply again [#176](https://github.com/asmvik/yabai/issues/176)\n- Fixed an issue that could cause windows to be overlapped when tiled [#183](https://github.com/asmvik/yabai/issues/183)\n- Verify that a message was given before trying to connect to the running yabai instance [#197](https://github.com/asmvik/yabai/issues/197)\n- Properly re-zoom a window when toggling its border [#211](https://github.com/asmvik/yabai/issues/211)\n- Workaround to make sure a window actually set the proper dimensions [#226](https://github.com/asmvik/yabai/issues/226) [#188](https://github.com/asmvik/yabai/issues/188)\n- Moving window to a different space using rules could leave an empty tile [#232](https://github.com/asmvik/yabai/issues/232)\n- Windows spawned while the owning application is hidden should not cause an empty tile to be created [#233](https://github.com/asmvik/yabai/issues/233)\n- Properly handle destruction and re-creation of view when layout changes between bsp and float [#230](https://github.com/asmvik/yabai/issues/230)\n\n## [1.1.2] - 2019-07-15\n### Changed\n- Float native macOS fullscreen spaces [#130](https://github.com/asmvik/yabai/issues/130)\n- Write error messsages returned to the client through *stderr* [#131](https://github.com/asmvik/yabai/issues/131)\n- Allow window focus command to work without the existence of a focused window [#133](https://github.com/asmvik/yabai/issues/133)\n\n## [1.1.1] - 2019-07-14\n### Changed\n- The status bar should be disabled by default, if setting is missing from the config [#126](https://github.com/asmvik/yabai/issues/126)\n\n## [1.1.0] - 2019-07-14\n### Added\n- Make loading scripting-addition more robust - validating version and functionality [#108](https://github.com/asmvik/yabai/issues/108)\n- Merge options for query constraints with command selectors to have a unified method for addressing displays, spaces, and windows,\n  as well as allowing commands to specify both a *selected* and a *given entity* of its type [#112](https://github.com/asmvik/yabai/issues/112)\n\n### Changed\n- Dragging a tiled window to another display using the mouse will cause the window to be warped to that display upon release [#103](https://github.com/asmvik/yabai/issues/103)\n- Escape quotes in window titles returned through query commands [#114](https://github.com/asmvik/yabai/issues/114)\n- Extend window, space and display properties exposed through *query* commands [#116](https://github.com/asmvik/yabai/issues/116)\n- Native macOS fullscreen spaces can now be addressed using their mission-control index, and can also be moved [#117](https://github.com/asmvik/yabai/issues/117)\n- Opacity changes only apply to windows that properly identify as  \"standard\" or \"dialog\" windows [#120](https://github.com/asmvik/yabai/issues/120)\n- The status bar should now properly draw above any potential window that overlaps its frame [#124](https://github.com/asmvik/yabai/issues/124)\n- Support *XDG_CONFIG_HOME* when locating the config file [#125](https://github.com/asmvik/yabai/issues/125)\n- Allow every single config setting to be applied at runtime with immediate effect. Run config asynchronously after initialization [#122](https://github.com/asmvik/yabai/issues/122)\n\n## [1.0.6] - 2019-07-09\n### Changed\n- No longer necessary to depend on the scripting-addition to focus a window [#102](https://github.com/asmvik/yabai/issues/102)\n- Extend definition of *WINDOW_SEL* to include *smallest* and *largest* [#105](https://github.com/asmvik/yabai/issues/105)\n\n## [1.0.5] - 2019-07-07\n### Changed\n- Fix missing quotation of string value outputted through *window query* commands [#90](https://github.com/asmvik/yabai/issues/90)\n\n## [1.0.4] - 2019-07-06\n### Changed\n- Fixed an issue that prevented *yabai* from running under multiple users simultaneously [#95](https://github.com/asmvik/yabai/issues/95)\n- Extend window properties exposed through *query* commands [#90](https://github.com/asmvik/yabai/issues/90)\n- Extend definition of *WINDOW_SEL*, *SPACE_SEL* and *DISPLAY_SEL* to include *first*, *last*, and *recent* [#85](https://github.com/asmvik/yabai/issues/85)\n\n## [1.0.3] - 2019-06-30\n### Changed\n- Prevent *status_bar* and *window borders* from displaying in native fullscreen spaces [#71](https://github.com/asmvik/yabai/issues/71)\n- Fixed an issue with the *status_bar* where *has_battery* and *charging* would not be default initialized when macOS report that there are zero power sources [#60](https://github.com/asmvik/yabai/issues/60)\n- Properly destroy the underlaying *view* when a *space* changes layout [#81](https://github.com/asmvik/yabai/issues/81)\n\n## [1.0.2] - 2019-06-25\n### Changed\n- Hide power indicator from the status-bar if a battery could not be found [#60](https://github.com/asmvik/yabai/issues/60)\n- Disable focus follows mouse while the *mouse_modifier* key is held down [#62](https://github.com/asmvik/yabai/issues/62)\n- Silence meaningless warning reported by the scripting-bridge framework [#55](https://github.com/asmvik/yabai/issues/55)\n- Extend definition of *WINDOW_SEL* to include *mouse*, targeting the window below the cursor [#66](https://github.com/asmvik/yabai/issues/66)\n- Allow all *config* (except *status_bar*) settings to be edited at runtime [#69](https://github.com/asmvik/yabai/issues/69)\n- Window should not be added to the window-tree twice when deminimized on an inactive display [#70](https://github.com/asmvik/yabai/issues/70)\n- Expose *window_placement* as a config setting to specify if windows become the first or second child [#65](https://github.com/asmvik/yabai/issues/65)\n\n## [1.0.1] - 2019-06-23\n### Added\n- First official release\n\n[Unreleased]: https://github.com/asmvik/yabai/compare/v7.1.17...HEAD\n[7.1.17]: https://github.com/asmvik/yabai/compare/v7.1.16...v7.1.17\n[7.1.16]: https://github.com/asmvik/yabai/compare/v7.1.15...v7.1.16\n[7.1.15]: https://github.com/asmvik/yabai/compare/v7.1.14...v7.1.15\n[7.1.14]: https://github.com/asmvik/yabai/compare/v7.1.13...v7.1.14\n[7.1.13]: https://github.com/asmvik/yabai/compare/v7.1.12...v7.1.13\n[7.1.12]: https://github.com/asmvik/yabai/compare/v7.1.11...v7.1.12\n[7.1.11]: https://github.com/asmvik/yabai/compare/v7.1.10...v7.1.11\n[7.1.10]: https://github.com/asmvik/yabai/compare/v7.1.9...v7.1.10\n[7.1.9]: https://github.com/asmvik/yabai/compare/v7.1.8...v7.1.9\n[7.1.8]: https://github.com/asmvik/yabai/compare/v7.1.7...v7.1.8\n[7.1.7]: https://github.com/asmvik/yabai/compare/v7.1.6...v7.1.7\n[7.1.6]: https://github.com/asmvik/yabai/compare/v7.1.5...v7.1.6\n[7.1.5]: https://github.com/asmvik/yabai/compare/v7.1.4...v7.1.5\n[7.1.4]: https://github.com/asmvik/yabai/compare/v7.1.3...v7.1.4\n[7.1.3]: https://github.com/asmvik/yabai/compare/v7.1.2...v7.1.3\n[7.1.2]: https://github.com/asmvik/yabai/compare/v7.1.1...v7.1.2\n[7.1.1]: https://github.com/asmvik/yabai/compare/v7.1.0...v7.1.1\n[7.1.0]: https://github.com/asmvik/yabai/compare/v7.0.4...v7.1.0\n[7.0.4]: https://github.com/asmvik/yabai/compare/v7.0.3...v7.0.4\n[7.0.3]: https://github.com/asmvik/yabai/compare/v7.0.2...v7.0.3\n[7.0.2]: https://github.com/asmvik/yabai/compare/v7.0.1...v7.0.2\n[7.0.1]: https://github.com/asmvik/yabai/compare/v7.0.0...v7.0.1\n[7.0.0]: https://github.com/asmvik/yabai/compare/v6.0.15...v7.0.0\n[6.0.15]: https://github.com/asmvik/yabai/compare/v6.0.14...v6.0.15\n[6.0.14]: https://github.com/asmvik/yabai/compare/v6.0.13...v6.0.14\n[6.0.13]: https://github.com/asmvik/yabai/compare/v6.0.12...v6.0.13\n[6.0.12]: https://github.com/asmvik/yabai/compare/v6.0.11...v6.0.12\n[6.0.11]: https://github.com/asmvik/yabai/compare/v6.0.10...v6.0.11\n[6.0.10]: https://github.com/asmvik/yabai/compare/v6.0.9...v6.0.10\n[6.0.9]: https://github.com/asmvik/yabai/compare/v6.0.8...v6.0.9\n[6.0.8]: https://github.com/asmvik/yabai/compare/v6.0.7...v6.0.8\n[6.0.7]: https://github.com/asmvik/yabai/compare/v6.0.6...v6.0.7\n[6.0.6]: https://github.com/asmvik/yabai/compare/v6.0.5...v6.0.6\n[6.0.5]: https://github.com/asmvik/yabai/compare/v6.0.4...v6.0.5\n[6.0.4]: https://github.com/asmvik/yabai/compare/v6.0.3...v6.0.4\n[6.0.3]: https://github.com/asmvik/yabai/compare/v6.0.2...v6.0.3\n[6.0.2]: https://github.com/asmvik/yabai/compare/v6.0.1...v6.0.2\n[6.0.1]: https://github.com/asmvik/yabai/compare/v6.0.0...v6.0.1\n[6.0.0]: https://github.com/asmvik/yabai/compare/v5.0.9...v6.0.0\n[5.0.9]: https://github.com/asmvik/yabai/compare/v5.0.8...v5.0.9\n[5.0.8]: https://github.com/asmvik/yabai/compare/v5.0.7...v5.0.8\n[5.0.7]: https://github.com/asmvik/yabai/compare/v5.0.6...v5.0.7\n[5.0.6]: https://github.com/asmvik/yabai/compare/v5.0.5...v5.0.6\n[5.0.5]: https://github.com/asmvik/yabai/compare/v5.0.4...v5.0.5\n[5.0.4]: https://github.com/asmvik/yabai/compare/v5.0.3...v5.0.4\n[5.0.3]: https://github.com/asmvik/yabai/compare/v5.0.2...v5.0.3\n[5.0.2]: https://github.com/asmvik/yabai/compare/v5.0.1...v5.0.2\n[5.0.1]: https://github.com/asmvik/yabai/compare/v5.0.0...v5.0.1\n[5.0.0]: https://github.com/asmvik/yabai/compare/v4.0.4...v5.0.0\n[4.0.4]: https://github.com/asmvik/yabai/compare/v4.0.3...v4.0.4\n[4.0.3]: https://github.com/asmvik/yabai/compare/v4.0.2...v4.0.3\n[4.0.2]: https://github.com/asmvik/yabai/compare/v4.0.1...v4.0.2\n[4.0.1]: https://github.com/asmvik/yabai/compare/v4.0.0...v4.0.1\n[4.0.0]: https://github.com/asmvik/yabai/compare/v3.3.10...v4.0.0\n[3.3.10]: https://github.com/asmvik/yabai/compare/v3.3.9...v3.3.10\n[3.3.9]: https://github.com/asmvik/yabai/compare/v3.3.8...v3.3.9\n[3.3.8]: https://github.com/asmvik/yabai/compare/v3.3.7...v3.3.8\n[3.3.7]: https://github.com/asmvik/yabai/compare/v3.3.6...v3.3.7\n[3.3.6]: https://github.com/asmvik/yabai/compare/v3.3.5...v3.3.6\n[3.3.5]: https://github.com/asmvik/yabai/compare/v3.3.4...v3.3.5\n[3.3.4]: https://github.com/asmvik/yabai/compare/v3.3.3...v3.3.4\n[3.3.3]: https://github.com/asmvik/yabai/compare/v3.3.2...v3.3.3\n[3.3.2]: https://github.com/asmvik/yabai/compare/v3.3.1...v3.3.2\n[3.3.1]: https://github.com/asmvik/yabai/compare/v3.3.0...v3.3.1\n[3.3.0]: https://github.com/asmvik/yabai/compare/v3.2.1...v3.3.0\n[3.2.1]: https://github.com/asmvik/yabai/compare/v3.2.0...v3.2.1\n[3.2.0]: https://github.com/asmvik/yabai/compare/v3.1.2...v3.2.0\n[3.1.2]: https://github.com/asmvik/yabai/compare/v3.1.1...v3.1.2\n[3.1.1]: https://github.com/asmvik/yabai/compare/v3.1.0...v3.1.1\n[3.1.0]: https://github.com/asmvik/yabai/compare/v3.0.2...v3.1.0\n[3.0.2]: https://github.com/asmvik/yabai/compare/v3.0.1...v3.0.2\n[3.0.1]: https://github.com/asmvik/yabai/compare/v3.0.0...v3.0.1\n[3.0.0]: https://github.com/asmvik/yabai/compare/v2.4.3...v3.0.0\n[2.4.3]: https://github.com/asmvik/yabai/compare/v2.4.2...v2.4.3\n[2.4.2]: https://github.com/asmvik/yabai/compare/v2.4.1...v2.4.2\n[2.4.1]: https://github.com/asmvik/yabai/compare/v2.4.0...v2.4.1\n[2.4.0]: https://github.com/asmvik/yabai/compare/v2.3.0...v2.4.0\n[2.3.0]: https://github.com/asmvik/yabai/compare/v2.2.3...v2.3.0\n[2.2.3]: https://github.com/asmvik/yabai/compare/v2.2.2...v2.2.3\n[2.2.2]: https://github.com/asmvik/yabai/compare/v2.2.1...v2.2.2\n[2.2.1]: https://github.com/asmvik/yabai/compare/v2.2.0...v2.2.1\n[2.2.0]: https://github.com/asmvik/yabai/compare/v2.1.3...v2.2.0\n[2.1.3]: https://github.com/asmvik/yabai/compare/v2.1.2...v2.1.3\n[2.1.2]: https://github.com/asmvik/yabai/compare/v2.1.1...v2.1.2\n[2.1.1]: https://github.com/asmvik/yabai/compare/v2.1.0...v2.1.1\n[2.1.0]: https://github.com/asmvik/yabai/compare/v2.0.1...v2.1.0\n[2.0.1]: https://github.com/asmvik/yabai/compare/v2.0.0...v2.0.1\n[2.0.0]: https://github.com/asmvik/yabai/compare/v1.1.2...v2.0.0\n[1.1.2]: https://github.com/asmvik/yabai/compare/v1.1.1...v1.1.2\n[1.1.1]: https://github.com/asmvik/yabai/compare/v1.1.0...v1.1.1\n[1.1.0]: https://github.com/asmvik/yabai/compare/v1.0.6...v1.1.0\n[1.0.6]: https://github.com/asmvik/yabai/compare/v1.0.5...v1.0.6\n[1.0.5]: https://github.com/asmvik/yabai/compare/v1.0.4...v1.0.5\n[1.0.4]: https://github.com/asmvik/yabai/compare/v1.0.3...v1.0.4\n[1.0.3]: https://github.com/asmvik/yabai/compare/v1.0.2...v1.0.3\n[1.0.2]: https://github.com/asmvik/yabai/compare/v1.0.1...v1.0.2\n[1.0.1]: https://github.com/asmvik/yabai/releases/tag/v1.0.1\n"
  },
  {
    "path": "LICENSE.txt",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2019 Åsmund Vikane\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "<!-- Please be careful editing the below HTML, as GitHub is quite finicky with anything that looks like an HTML tag in GitHub Flavored Markdown. -->\n<p align=\"center\">\n  <img width=\"75%\" src=\"assets/banner/banner.svg\" alt=\"Banner\">\n</p>\n<p align=\"center\">\n  <b>Tiling window management for the Mac.</b>\n</p>\n<p align=\"center\">\n  <a href=\"https://github.com/asmvik/yabai/blob/master/LICENSE.txt\">\n    <img src=\"https://img.shields.io/github/license/asmvik/yabai.svg?color=green\" alt=\"License Badge\">\n  </a>\n  <a href=\"https://github.com/asmvik/yabai/blob/master/doc/yabai.asciidoc\">\n    <img src=\"https://img.shields.io/badge/view-documentation-green.svg\" alt=\"Documentation Badge\">\n  </a>\n  <a href=\"https://github.com/asmvik/yabai/wiki\">\n    <img src=\"https://img.shields.io/badge/view-wiki-green.svg\" alt=\"Wiki Badge\">\n  </a>\n  <a href=\"https://github.com/asmvik/yabai/blob/master/CHANGELOG.md\">\n    <img src=\"https://img.shields.io/badge/view-changelog-green.svg\" alt=\"Changelog Badge\">\n  </a>\n  <a href=\"https://github.com/asmvik/yabai/releases\">\n    <img src=\"https://img.shields.io/github/commits-since/asmvik/yabai/latest.svg?color=green\" alt=\"Version Badge\">\n  </a>\n</p>\n\n## About\n\n<img align=\"right\" width=\"40%\" src=\"assets/screenshot.png\" alt=\"Screenshot\">\n\nyabai is a window management utility that is designed to work as an extension to the built-in window manager of macOS.\nyabai allows you to control your windows, spaces and displays freely using an intuitive command line interface and optionally set user-defined keyboard shortcuts using [&nearr;&nbsp;skhd][gh-skhd] and other third-party software.\n\nThe primary function of yabai is tiling window management; automatically modifying your window layout using a binary space partitioning algorithm to allow you to focus on the content of your windows without distractions.\nAdditional features of yabai include focus-follows-mouse, disabling animations for switching spaces, creating spaces past the limit of 16 spaces, and much more.\n\n## Installation and Configuration\n\n- The [&nearr;&nbsp;yabai&nbsp;wiki][yabai-wiki] has both brief and detailed installation instructions for multiple installation methods, and also explains how to uninstall yabai completely.\n- Sample configuration files can be found in the [&nearr;&nbsp;examples][yabai-examples] directory. Refer to the [&nearr;&nbsp;documentation][yabai-docs] or the wiki for further information.\n- Keyboard shortcuts can be defined with [&nearr;&nbsp;skhd][gh-skhd] or any other suitable software you may prefer.\n\n## Requirements and Caveats\n\nPlease read the below requirements carefully.\nMake sure you fulfil all of them before filing an issue.\n\n|Requirement|Note|\n|-:|:-|\n|Operating&nbsp;System&nbsp;Intel x86-64|Big Sur 11.0.0+, Monterey 12.0.0+, Ventura 13.0.0+, Sonoma 14.0.0+, and Sequoia 15.0+ is supported.|\n|Operating&nbsp;System&nbsp;Apple Silicon|Monterey 12.0.0+, Ventura 13.0.0+, Sonoma 14.0.0+, Sequoia 15.0+, and Tahoe 26.0+ is supported.|\n|Accessibility&nbsp;API|yabai must be given permission to utilize the Accessibility API and will request access upon launch. The application must be restarted after access has been granted.|\n|Screen Recording|yabai must be given Screen Recording permission if and only if you want to enable window animations, and will request access when necessary. The application must be restarted after access has been granted.|\n|System&nbsp;Preferences&nbsp;(macOS 11.x, 12.x)|In the Mission Control pane, the setting \"Displays have separate Spaces\" must be enabled.|\n|System&nbsp;Settings&nbsp;(macOS 13.x, 14.x, 15.x)|In the Desktop & Dock tab, inside the Mission Control pane, the setting \"Displays have separate Spaces\" must be enabled.|\n\nPlease also take note of the following caveats.\n\n|Caveat|Note|\n|-:|:-|\n|System&nbsp;Integrity&nbsp;Protection (Optional)|System Integrity Protection can be (partially) disabled for yabai to inject a scripting addition into Dock.app for controlling windows with functions that require elevated privileges. This enables control of the window server, which is the sole owner of all window connections, and enables additional features of yabai.|\n|Code&nbsp;Signing|When building from source (or installing from HEAD), it is necessary to codesign the binary so it retains its accessibility and automation privileges when updated or rebuilt.|\n|Finder&nbsp;Desktop|Some people disable the Finder Desktop window using an undocumented defaults write command. This breaks focusing of empty spaces and should be avoided when using yabai. To re-activate the Finder Desktop, run: \"defaults write com.apple.finder CreateDesktop -bool true\".|\n|NSDocument-based&nbsp;Applications|Windows that utilize native macOS tabs such as Terminal and Finder, [do not behave correctly when creating tabs](https://github.com/asmvik/yabai/issues/68). Avoid creating tabs in these applications, consider alternatives that do not use NSDocument's tab system, or make these windows float using rules.|\n|System&nbsp;Preferences&nbsp;(macOS 11.x, 12.x)|In the Mission Control pane, the setting \"Automatically rearrange Spaces based on most recent use\" should be disabled for commands that rely on the ordering of spaces to work reliably.|\n|System&nbsp;Settings&nbsp;(macOS 13.x, 14.x, 15.x)|In the Desktop & Dock tab, inside the Mission Control pane, the setting \"Automatically rearrange Spaces based on most recent use\" should be disabled for commands that rely on the ordering of spaces to work reliably.|\n|System&nbsp;Settings&nbsp;(macOS 14.x, 15.x)|In the Desktop & Dock tab, inside the Desktop & Stage Manager pane, the setting \"Show Items On Desktop\" should be enabled for display and space focus commands to work reliably in multi-display configurations.|\n|System&nbsp;Settings&nbsp;(macOS 14.x, 15.x)|In the Desktop & Dock tab, inside the Desktop & Stage Manager pane, the setting \"Click wallpaper to reveal Desktop\" should be set to \"Only in Stage Manager\" for display and space focus commands to work reliably.|\n\n## License and Attribution\n\nyabai is licensed under the [&nearr;&nbsp;MIT&nbsp;License][yabai-license], a short and simple permissive license with conditions only requiring preservation of copyright and license notices.\nLicensed works, modifications, and larger works may be distributed under different terms and without source code.\n\nThanks to [@fools-mate][gh-fools-mate] for creating a logo and banner for this project and making them available for free.\n\nThanks to [@dominiklohmann][gh-dominiklohmann] for contributing great documentation, support, and more, for free.\n\n## Disclaimer\n\nUse at your own discretion.\nI take no responsibility if anything should happen to your machine while trying to install, test or otherwise use this software in any form.\nYou acknowledge that you understand the potential risk that may come from disabling [&nearr;&nbsp;System&nbsp;Integrity&nbsp;Protection][external-about-sip] on your system, and I make no recommendation as to whether you should or should not disable System Integrity Protection.\n\n<!-- Project internal links -->\n[yabai-license]: LICENSE.txt\n[yabai-examples]: https://github.com/asmvik/yabai/tree/master/examples\n[yabai-wiki]: https://github.com/asmvik/yabai/wiki\n[yabai-docs]: https://github.com/asmvik/yabai/blob/master/doc/yabai.asciidoc\n\n<!-- Links to other GitHub projects/users -->\n[gh-skhd]: https://github.com/asmvik/skhd\n[gh-fools-mate]: https://github.com/fools-mate\n[gh-dominiklohmann]: https://github.com/dominiklohmann\n\n<!-- External links -->\n[external-about-sip]: https://support.apple.com/en-us/HT204899\n"
  },
  {
    "path": "assets/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>en</string>\n\t<key>CFBundleExecutable</key>\n\t<string>yabai</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>com.asmvik.yabai</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>yabai</string>\n\t<key>CFBundlePackageType</key>\n\t<string>APPL</string>\n\t<key>NSHumanReadableCopyright</key>\n\t<string>Copyright © 2019 Åsmund Vikane. All rights reserved.</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "doc/yabai.1",
    "content": "'\\\" t\n.\\\"     Title: yabai\n.\\\"    Author: [see the \"AUTHOR(S)\" section]\n.\\\" Generator: Asciidoctor 2.0.26\n.\\\"      Date: 2025-12-10\n.\\\"    Manual: Yabai Manual\n.\\\"    Source: Yabai\n.\\\"  Language: English\n.\\\"\n.TH \"YABAI\" \"1\" \"2025-12-10\" \"Yabai\" \"Yabai Manual\"\n.ie \\n(.g .ds Aq \\(aq\n.el       .ds Aq '\n.ss \\n[.ss] 0\n.nh\n.ad l\n.de URL\n\\fI\\\\$2\\fP <\\\\$1>\\\\$3\n..\n.als MTO URL\n.if \\n[.g] \\{\\\n.  mso www.tmac\n.  am URL\n.    ad l\n.  .\n.  am MTO\n.    ad l\n.  .\n.  LINKSTYLE blue R < >\n.\\}\n.SH \"NAME\"\nyabai \\- window manager\n.SH \"SYNOPSIS\"\n.sp\n\\fByabai\\fP [\\fB\\-\\-load\\-sa\\fP|\\fB\\-\\-uninstall\\-sa\\fP|\\fB\\-\\-install\\-service\\fP|\\fB\\-\\-uninstall\\-service\\fP|\\fB\\-\\-start\\-service\\fP|\\fB\\-\\-restart\\-service\\fP|\\fB\\-\\-stop\\-service\\fP|\\fB\\-\\-message\\fP,\\fB\\-m\\fP \\fImsg\\fP|\\fB\\-\\-config\\fP,\\fB\\-c\\fP \\fIconfig_file\\fP|\\fB\\-\\-verbose\\fP,\\fB\\-V\\fP|\\fB\\-\\-version\\fP,\\fB\\-v\\fP|\\fB\\-\\-help\\fP,\\fB\\-h\\fP]\n.SH \"DESCRIPTION\"\n.sp\n\\fByabai\\fP is a tiling window manager for macOS based on binary space partitioning.\n.SH \"OPTIONS\"\n.sp\n\\fB\\-\\-load\\-sa\\fP\n.RS 4\nLoad the scripting\\-addition into Dock.app.\n.br\nInstalls and updates the scripting\\-addition when necessary.\n.br\nPath is /Library/ScriptingAdditions/yabai.osax.\n.br\nSystem Integrity Protection must be partially disabled.\n.RE\n.sp\n\\fB\\-\\-uninstall\\-sa\\fP\n.RS 4\nUninstall the scripting\\-addition. Must be run as root.\n.br\nPath is /Library/ScriptingAdditions/yabai.osax.\n.br\nSystem Integrity Protection must be partially disabled.\n.RE\n.sp\n\\fB\\-\\-install\\-service\\fP\n.RS 4\nWrites a launchd service file to disk.\n.br\nPath is ~/Library/LaunchAgents/com.asmvik.yabai.plist.\n.RE\n.sp\n\\fB\\-\\-uninstall\\-service\\fP\n.RS 4\nRemoves a launchd service file from disk.\n.br\nPath is ~/Library/LaunchAgents/com.asmvik.yabai.plist.\n.RE\n.sp\n\\fB\\-\\-start\\-service\\fP\n.RS 4\nEnables, loads, and starts the launchd service.\n.br\nWill install service file if it does not exist.\n.RE\n.sp\n\\fB\\-\\-restart\\-service\\fP\n.RS 4\nAttempts to restart the service instance.\n.RE\n.sp\n\\fB\\-\\-stop\\-service\\fP\n.RS 4\nStops a running instance of the service and unloads it.\n.RE\n.sp\n\\fB\\-\\-message\\fP, \\fB\\-m\\fP \\fI<msg>\\fP\n.RS 4\nSend message to a running instance of yabai.\n.RE\n.sp\n\\fB\\-\\-config\\fP, \\fB\\-c\\fP \\fI<config_file>\\fP\n.RS 4\nUse the specified configuration file.\n.br\nExecutes using \\f(CR/usr/bin/env sh \\-c <config_file>\\fP if the exec\\-bit is set.\n.br\nInterpreted using \\f(CR/usr/bin/env sh <config_file>\\fP if the exec\\-bit is unset.\n.RE\n.sp\n\\fB\\-\\-verbose\\fP, \\fB\\-V\\fP\n.RS 4\nOutput debug information to stdout.\n.RE\n.sp\n\\fB\\-\\-version\\fP, \\fB\\-v\\fP\n.RS 4\nPrint version to stdout and exit.\n.RE\n.sp\n\\fB\\-\\-help\\fP, \\fB\\-h\\fP\n.RS 4\nPrint options to stdout and exit.\n.RE\n.SH \"DEFINITIONS\"\n.sp\n.if n .RS 4\n.nf\n.fam C\nREGEX\\&       := \\c\n.URL \"https://www.gnu.org/software/findutils/manual/html_node/find_html/posix_002dextended\\-regular\\-expression\\-syntax.html\" \"POSIX extended regular expression syntax\" \"\"\n\nLABEL\\&       := arbitrary string/text used as an identifier\n\nLAYER\\&       := below | normal | above | auto\n\nBOOL_SEL\\&    := on | off\n\nFLOAT_SEL\\&   := 0 < <value> <= 1.0\n\nRULE_SEL\\&    := <index> | LABEL\n\nSIGNAL_SEL\\&  := <index> | LABEL\n\nDIR_SEL\\&     := north | east | south | west\n\nSTACK_SEL\\&   := stack.prev | stack.next | stack.first | stack.last | stack.recent | stack.<index (1\\-based)>\n\nWINDOW_SEL\\&  := prev | next | first | last | recent | mouse | largest | smallest | sibling | first_nephew | second_nephew | uncle | first_cousin | second_cousin | STACK_SEL | DIR_SEL | <window id>\n\nDISPLAY_SEL := prev | next | first | last | recent | mouse | DIR_SEL | <arrangement index (1\\-based)> | LABEL\n\nSPACE_SEL\\&   := prev | next | first | last | recent | mouse | <mission\\-control index (1\\-based)> | LABEL\n\nEASING\\&      := ease_in_sine\\&  | ease_out_sine\\&  | ease_in_out_sine\\&  |\n               ease_in_quad\\&  | ease_out_quad\\&  | ease_in_out_quad\\&  |\n               ease_in_cubic | ease_out_cubic | ease_in_out_cubic |\n               ease_in_quart | ease_out_quart | ease_in_out_quart |\n               ease_in_quint | ease_out_quint | ease_in_out_quint |\n               ease_in_expo\\&  | ease_out_expo\\&  | ease_in_out_expo\\&  |\n               ease_in_circ\\&  | ease_out_circ\\&  | ease_in_out_circ\n.fam\n.fi\n.if n .RE\n.SH \"DOMAINS\"\n.SS \"Config\"\n.SS \"General Syntax\"\n.sp\nyabai \\-m config <global setting>\n.RS 4\nGet or set the value of <global setting>.\n.RE\n.sp\nyabai \\-m config [\\-\\-space \\fI<SPACE_SEL>\\fP] <space setting>\n.RS 4\nGet or set the value of <space setting>.\n.RE\n.SS \"Global Settings\"\n.sp\n\\fBdebug_output\\fP [\\fI<BOOL_SEL>\\fP]\n.RS 4\nEnable output of debug information to stdout.\n.RE\n.sp\n\\fBexternal_bar\\fP [\\fI<main|all|off>:<top_padding>:<bottom_padding>\\fP]\n.RS 4\nSpecify top and bottom padding for a potential custom bar that you may be running.\n.br\n\\fImain\\fP: Apply the given padding only to spaces located on the main display.\n.br\n\\fIall\\fP:  Apply the given padding to all spaces regardless of their display.\n.br\n\\fIoff\\fP:  Do not apply any special padding.\n.RE\n.sp\n\\fBmenubar_opacity\\fP [\\fI<FLOAT_SEL>\\fP]\n.RS 4\nChanges the transparency of the macOS menubar.\n.br\nIf the value is 0.0, the menubar will no longer respond to mouse\\-events, effectively hiding the menubar permanently.\n.br\nThe menubar will automatically become fully opaque upon entering a native\\-fullscreen space, and adjusted down afterwards.\n.RE\n.sp\n\\fBmouse_follows_focus\\fP [\\fI<BOOL_SEL>\\fP]\n.RS 4\nWhen focusing a window, put the mouse at its center.\n.RE\n.sp\n\\fBfocus_follows_mouse\\fP [\\fIautofocus|autoraise|off\\fP]\n.RS 4\nAutomatically focus the window under the mouse.\n.RE\n.sp\n\\fBdisplay_arrangement_order\\fP [\\fIdefault|vertical|horizontal\\fP]\n.RS 4\nSpecify how displays are ordered (determined by center point).\n.br\n\\fIdefault\\fP: Native macOS ordering.\n.br\n\\fIvertical\\fP: Order by y\\-coordinate (followed by x\\-coordinate when equal).\n.br\n\\fIhorizontal\\fP: Order by x\\-coordinate (followed by y\\-coordinate when equal).\n.RE\n.sp\n\\fBwindow_origin_display\\fP [\\fIdefault|focused|cursor\\fP]\n.RS 4\nSpecify which display a newly created window should be managed in.\n.br\n\\fIdefault\\fP: The display in which the window is created (standard macOS behaviour).\n.br\n\\fIfocused\\fP: The display that has focus when the window is created.\n.br\n\\fIcursor\\fP: The display that currently holds the mouse cursor.\n.RE\n.sp\n\\fBwindow_placement\\fP [\\fIfirst_child|second_child\\fP]\n.RS 4\nSpecify whether managed windows should become the first or second leaf\\-node.\n.RE\n.sp\n\\fBwindow_insertion_point\\fP [\\fIfocused|first|last\\fP]\n.RS 4\nSpecify where new managed windows will be inserted.\n.RE\n.sp\n\\fBwindow_zoom_persist\\fP [\\fI<BOOL_SEL>\\fP]\n.RS 4\nWindows will keep their zoom\\-state through layout changes.\n.RE\n.sp\n\\fBwindow_shadow\\fP [\\fI<BOOL_SEL>|float\\fP]\n.RS 4\nDraw shadow for windows.\n.br\nSystem Integrity Protection must be partially disabled.\n.RE\n.sp\n\\fBwindow_opacity\\fP [\\fI<BOOL_SEL>\\fP]\n.RS 4\nEnable opacity for windows.\n.br\nSystem Integrity Protection must be partially disabled.\n.RE\n.sp\n\\fBwindow_opacity_duration\\fP [\\fI<FLOAT_SEL>\\fP]\n.RS 4\nDuration of transition between active / normal opacity.\n.br\nSystem Integrity Protection must be partially disabled.\n.RE\n.sp\n\\fBactive_window_opacity\\fP [\\fI<FLOAT_SEL>\\fP]\n.RS 4\nOpacity of the focused window.\n.br\nSystem Integrity Protection must be partially disabled.\n.RE\n.sp\n\\fBnormal_window_opacity\\fP [\\fI<FLOAT_SEL>\\fP]\n.RS 4\nOpacity of an unfocused window.\n.br\nSystem Integrity Protection must be partially disabled.\n.RE\n.sp\n\\fBwindow_animation_duration\\fP [\\fI<FLOAT_SEL>\\fP]\n.RS 4\nDuration of window frame animation.\n.br\nIf 0.0, the change in dimension is not animated.\n.br\nRequires Screen Recording permissions.\n.br\nSystem Integrity Protection must be partially disabled.\n.RE\n.sp\n\\fBwindow_animation_easing\\fP [\\fI<EASING>\\fP]\n.RS 4\nEasing function to use for window animations.\n.br\nSee \\c\n.URL \"https://easings.net\" \"\" \"\"\nfor details.\n.RE\n.sp\n\\fBinsert_feedback_color\\fP [\\fI0xAARRGGBB\\fP]\n.RS 4\nColor of the \\fBwindow \\-\\-insert\\fP message and mouse_drag selection.\n.br\nThe purpose is to provide a visual preview of the new window frame.\n.RE\n.sp\n\\fBsplit_ratio\\fP [\\fI<FLOAT_SEL>\\fP]\n.RS 4\nSpecify the size distribution when a window is split.\n.RE\n.sp\n\\fBmouse_modifier\\fP [\\fIcmd|alt|shift|ctrl|fn\\fP]\n.RS 4\nKeyboard modifier used for moving and resizing windows.\n.RE\n.sp\n\\fBmouse_action1\\fP [\\fImove|resize\\fP]\n.RS 4\nAction performed when pressing \\fImouse_modifier\\fP + \\fIbutton1\\fP.\n.RE\n.sp\n\\fBmouse_action2\\fP [\\fImove|resize\\fP]\n.RS 4\nAction performed when pressing \\fImouse_modifier\\fP + \\fIbutton2\\fP.\n.RE\n.sp\n\\fBmouse_drop_action\\fP [\\fIswap|stack\\fP]\n.RS 4\nAction performed when a bsp\\-managed window is dropped in the center of some other bsp\\-managed window.\n.RE\n.SS \"Space Settings\"\n.sp\n\\fBlayout\\fP [\\fIbsp|stack|float\\fP]\n.RS 4\nSet the layout of the selected space.\n.RE\n.sp\n\\fBsplit_type\\fP [\\fIvertical|horizontal|auto\\fP]\n.RS 4\nSpecify how a window should be split.\n.br\n\\fIvertical\\fP: The window is split along the y\\-axis.\n.br\n\\fIhorizontal\\fP: The window is split along the x\\-axis.\n.br\n\\fIauto\\fP: The axis is determined based on width/height ratio.\n.RE\n.sp\n\\fBtop_padding\\fP [\\fI<integer number>\\fP]\n.RS 4\nPadding added at the upper side of the selected space.\n.RE\n.sp\n\\fBbottom_padding\\fP [\\fI<integer number>\\fP]\n.RS 4\nPadding added at the lower side of the selected space.\n.RE\n.sp\n\\fBleft_padding\\fP [\\fI<integer number>\\fP]\n.RS 4\nPadding added at the left side of the selected space.\n.RE\n.sp\n\\fBright_padding\\fP [\\fI<integer number>\\fP]\n.RS 4\nPadding added at the right side of the selected space.\n.RE\n.sp\n\\fBwindow_gap\\fP [\\fI<integer number>\\fP]\n.RS 4\nSize of the gap that separates windows for the selected space.\n.RE\n.sp\n\\fBauto_balance\\fP [\\fI<BOOL_SEL>|x\\-axis|y\\-axis\\fP]\n.RS 4\nBalance the window tree upon change, so that all windows occupy an equally sized area.\n.RE\n.SS \"Display\"\n.SS \"General Syntax\"\n.sp\nyabai \\-m display [\\fI<DISPLAY_SEL\\fP>] \\fI<COMMAND>\\fP\n.SS \"COMMAND\"\n.sp\n\\fB\\-\\-focus\\fP \\fI<DISPLAY_SEL>\\fP\n.RS 4\nFocus the given display.\n.RE\n.sp\n\\fB\\-\\-space\\fP \\fI<SPACE_SEL>\\fP\n.RS 4\nThe given space will become visible on the selected display, without changing focus.\n.br\nThe given space must belong to the selected display.\n.br\nSystem Integrity Protection must be partially disabled.\n.RE\n.sp\n\\fB\\-\\-label\\fP [\\fI<LABEL>\\fP]\n.RS 4\nLabel the selected display, allowing that label to be used as an alias in commands that take a \\f(CRDISPLAY_SEL\\fP parameter.\n.br\nIf the command is called without an argument it will try to remove a previously assigned label.\n.RE\n.SS \"Space\"\n.SS \"General Syntax\"\n.sp\nyabai \\-m space [\\fI<SPACE_SEL>\\fP] \\fI<COMMAND>\\fP\n.SS \"COMMAND\"\n.sp\n\\fB\\-\\-focus\\fP \\fI<SPACE_SEL>\\fP\n.RS 4\nFocus the given space.\n.br\nSystem Integrity Protection must be partially disabled.\n.RE\n.sp\n\\fB\\-\\-switch\\fP \\fI<SPACE_SEL>\\fP\n.RS 4\nThe selected space will always be the currently focused space.\n.br\nThe given space substitutes the selected space, gaining focus.\n.br\nIf the selected space and the given space belong to different displays, this behaves like \\fI\\-\\-swap\\fP.\n.br\nIf the selected space and the given space belong to the same display, this behaves like \\fI\\-\\-focus\\fP.\n.br\nSystem Integrity Protection must be partially disabled.\n.RE\n.sp\n\\fB\\-\\-create\\fP  [\\fI<DISPLAY_SEL>\\fP]\n.RS 4\nCreate a new space on the given display.\n.br\nIf none specified, use the display of the active space instead.\n.br\nSystem Integrity Protection must be partially disabled.\n.RE\n.sp\n\\fB\\-\\-destroy\\fP [\\fI<SPACE_SEL>\\fP]\n.RS 4\nRemove the given space.\n.br\nIf none specified, use the selected space instead.\n.br\nSystem Integrity Protection must be partially disabled.\n.RE\n.sp\n\\fB\\-\\-move\\fP \\fI<SPACE_SEL>\\fP\n.RS 4\nMove position of the selected space to the position of the given space.\n.br\nThe selected space and given space must both belong to the same display.\n.br\nSystem Integrity Protection must be partially disabled.\n.RE\n.sp\n\\fB\\-\\-swap\\fP \\fI<SPACE_SEL>\\fP\n.RS 4\nSwap the selected space with the given space.\n.br\nIf the selected space and given space belong to different displays, all the windows will swap.\n.br\nIf the selected space and given space belong to the same display, the actual spaces will swap.\n.br\nSystem Integrity Protection must be partially disabled.\n.RE\n.sp\n\\fB\\-\\-display\\fP \\fI<DISPLAY_SEL>\\fP\n.RS 4\nSend the selected space to the given display.\n.br\nSystem Integrity Protection must be partially disabled.\n.RE\n.sp\n\\fB\\-\\-equalize\\fP [\\fIx\\-axis|y\\-axis\\fP]\n.RS 4\nReset the split ratios on the selected space to the default value along the given axis.\n.br\nIf no axis is specified, use both.\n.RE\n.sp\n\\fB\\-\\-balance\\fP [\\fIx\\-axis|y\\-axis\\fP]\n.RS 4\nAdjust the split ratios on the selected space so that all windows along the given axis occupy the same area.\n.br\nIf no axis is specified, use both.\n.RE\n.sp\n\\fB\\-\\-mirror\\fP \\fIx\\-axis|y\\-axis\\fP\n.RS 4\nFlip the tree of the selected space along the given axis.\n.RE\n.sp\n\\fB\\-\\-rotate\\fP \\fI90|180|270\\fP\n.RS 4\nRotate the tree of the selected space.\n.RE\n.sp\n\\fB\\-\\-padding\\fP \\fIabs|rel:<top>:<bottom>:<left>:<right>\\fP\n.RS 4\nPadding added at the sides of the selected space.\n.RE\n.sp\n\\fB\\-\\-gap\\fP \\fIabs|rel:<gap>\\fP\n.RS 4\nSize of the gap that separates windows on the selected space.\n.RE\n.sp\n\\fB\\-\\-toggle\\fP \\fIpadding|gap|mission\\-control|show\\-desktop\\fP\n.RS 4\nToggle space setting on or off for the selected space.\n.RE\n.sp\n\\fB\\-\\-layout\\fP \\fIbsp|stack|float\\fP\n.RS 4\nSet the layout of the selected space.\n.RE\n.sp\n\\fB\\-\\-label\\fP [\\fI<LABEL>\\fP]\n.RS 4\nLabel the selected space, allowing that label to be used as an alias in commands that take a \\f(CRSPACE_SEL\\fP parameter.\n.br\nIf the command is called without an argument it will try to remove a previously assigned label.\n.RE\n.SS \"Window\"\n.SS \"General Syntax\"\n.sp\nyabai \\-m window [\\fI<WINDOW_SEL>\\fP] \\fI<COMMAND>\\fP\n.SS \"COMMAND\"\n.sp\n\\fB\\-\\-focus\\fP [\\fI<WINDOW_SEL>\\fP]\n.RS 4\nFocus the given window.\n.br\nIf none specified, focus the selected window instead.\n.RE\n.sp\n\\fB\\-\\-close\\fP [\\fI<WINDOW_SEL>\\fP]\n.RS 4\nClose the given window.\n.br\nIf none specified, close the selected window instead.\n.br\nOnly works on windows that provide a close button in its titlebar.\n.RE\n.sp\n\\fB\\-\\-minimize\\fP [\\fI<WINDOW_SEL>\\fP]\n.RS 4\nMinimize the given window.\n.br\nIf none specified, minimize the selected window instead.\n.br\nOnly works on windows that provide a minimize button in its titlebar.\n.RE\n.sp\n\\fB\\-\\-deminimize\\fP \\fI<WINDOW_SEL>\\fP\n.RS 4\nRestore the given window if it is minimized.\n.br\nThe window will only get focus if the owning application has focus.\n.br\nNote that you can also \\fI\\-\\-focus\\fP a minimized window to restore it as the focused window.\n.RE\n.sp\n\\fB\\-\\-display\\fP \\fI<DISPLAY_SEL>\\fP\n.RS 4\nSend the selected window to the given display.\n.RE\n.sp\n\\fB\\-\\-space\\fP \\fI<SPACE_SEL>\\fP\n.RS 4\nSend the selected window to the given space.\nSystem Integrity Protection must be partially disabled on macOS Monterey 12.7+, Ventura 13.6+, Sonoma 14.5+, and macOS Sequoia.\n.RE\n.sp\n\\fB\\-\\-swap\\fP \\fI<WINDOW_SEL>\\fP\n.RS 4\nSwap position of the selected window and the given window.\n.RE\n.sp\n\\fB\\-\\-warp\\fP \\fI<WINDOW_SEL>\\fP\n.RS 4\nRe\\-insert the selected window, splitting the given window.\n.RE\n.sp\n\\fB\\-\\-stack\\fP \\fI<WINDOW_SEL>\\fP\n.RS 4\nStack the given window on top of the selected window.\n.br\nAny kind of warp operation performed on a stacked window will unstack it.\n.RE\n.sp\n\\fB\\-\\-insert\\fP \\fI<DIR_SEL>|stack\\fP\n.RS 4\nSet the splitting mode of the selected window.\n.br\nIf the current splitting mode matches the selected mode, the action will be undone.\n.RE\n.sp\n\\fB\\-\\-grid\\fP \\fI<rows>:<cols>:<start\\-x>:<start\\-y>:<width>:<height>\\fP\n.RS 4\nSet the frame of the selected window based on a self\\-defined grid.\n.RE\n.sp\n\\fB\\-\\-move\\fP \\fIabs|rel:<dx>:<dy>\\fP\n.RS 4\nIf type is \\fIrel\\fP the selected window is moved by \\fIdx\\fP pixels horizontally and \\fIdy\\fP pixels vertically.\n.br\nIf type is \\fIabs\\fP \\fIdx\\fP and \\fIdy\\fP will become the new position.\n.RE\n.sp\n\\fB\\-\\-resize\\fP \\fItop|left|bottom|right|top_left|top_right|bottom_right|bottom_left|abs:<dx>:<dy>\\fP\n.RS 4\nResize the selected window by moving the given handle \\fIdx\\fP pixels horizontally and \\fIdy\\fP pixels vertically.\n.br\nIf handle is \\fIabs\\fP the new size will be \\fIdx\\fP width and \\fIdy\\fP height and cannot be used on managed windows.\n.RE\n.sp\n\\fB\\-\\-ratio\\fP \\fIrel|abs:<dr>\\fP\n.RS 4\nIf type is \\fIrel\\fP the split ratio of the selected window is changed by \\fIdr\\fP, otherwise \\fIdr\\fP will become the new split ratio.\n.br\nA positive/negative delta will increase/decrease the size of the left\\-child.\n.RE\n.sp\n\\fB\\-\\-toggle\\fP \\fIfloat|sticky|pip|shadow|split|zoom\\-parent|zoom\\-fullscreen|windowed\\-fullscreen|native\\-fullscreen|expose|<LABEL>\\fP\n.RS 4\nToggle the given property of the selected window.\n.br\nThe following properties require System Integrity Protection to be partially disabled: sticky, pip, shadow, LABEL (scratchpad identifier) .\n.RE\n.sp\n\\fB\\-\\-sub\\-layer\\fP \\fI<LAYER>\\fP\n.RS 4\nSet the stacking sub\\-layer of the selected window.\n.br\nThe window will no longer be eligible for automatic change in sub\\-layer when managed/unmanaged.\n.br\nSpecify the value \\fIauto\\fP to reset back to normal and make it become automatically managed.\n.br\nSystem Integrity Protection must be partially disabled.\n.RE\n.sp\n\\fB\\-\\-opacity\\fP \\fI<FLOAT_SEL>\\fP\n.RS 4\nSet the opacity of the selected window.\n.br\nThe window will no longer be eligible for automatic change in opacity upon focus change.\n.br\nSpecify the value \\fI0.0\\fP to reset back to full opacity and make it become automatically managed.\n.br\nSystem Integrity Protection must be partially disabled.\n.RE\n.sp\n\\fB\\-\\-raise\\fP [\\fI<WINDOW_SEL>\\fP]\n.RS 4\nOrders the selected window above the given window, or to the front within its layer.\n.br\nSystem Integrity Protection must be partially disabled.\n.RE\n.sp\n\\fB\\-\\-lower\\fP [\\fI<WINDOW_SEL>\\fP]\n.RS 4\nOrders the selected window below the given window, or to the back within its layer.\n.br\nSystem Integrity Protection must be partially disabled.\n.RE\n.sp\n\\fB\\-\\-scratchpad\\fP [\\fI<LABEL>|recover\\fP]\n.RS 4\nUnique identifier used to identify a window scratchpad.\n.br\nAn identifier may only be assigned to a single window at any given time.\n.br\nA scratchpad window will automatically be treated as a (manage=off) floating window.\n.br\nIf the scratchpad is already taken by another window, this assignment will fail.\n.br\nIf the scratchpad is re\\-assigned, the previous identifier will become available.\n.br\nIf no value is given, the window will seize to be a scratchpad window.\n.br\nThe special value \\fIrecover\\fP can be used to forcefully bring all scratchpad windows to the front.\n.br\nThis can be useful if windows become inaccessible due to a restart or crash.\n.br\nSystem Integrity Protection must be partially disabled.\n.RE\n.SS \"Query\"\n.SS \"General Syntax\"\n.sp\nyabai \\-m query \\fI<COMMAND>\\fP [\\fI<PROPERTIES>\\fP] [\\fI<ARGUMENT>\\fP]\n.SS \"COMMAND\"\n.sp\n\\fB\\-\\-displays\\fP\n.RS 4\nRetrieve information about displays.\n.RE\n.sp\n\\fB\\-\\-spaces\\fP\n.RS 4\nRetrieve information about spaces.\n.RE\n.sp\n\\fB\\-\\-windows\\fP\n.RS 4\nRetrieve information about windows.\n.RE\n.SS \"ARGUMENT\"\n.sp\n\\fB\\-\\-display\\fP [\\fI<DISPLAY_SEL>\\fP]\n.RS 4\nConstrain matches to the selected display.\n.RE\n.sp\n\\fB\\-\\-space\\fP [\\fI<SPACE_SEL>\\fP]\n.RS 4\nConstrain matches to the selected space.\n.RE\n.sp\n\\fB\\-\\-window\\fP [\\fI<WINDOW_SEL>\\fP]\n.RS 4\nConstrain matches to the selected window.\n.RE\n.SS \"PROPERTIES\"\n.sp\nA comma\\-separated string containing the name of fields to include in the output.\n.br\nThe name of the provided fields must be present in the dataformat of the corresponding entity.\n.SS \"DATAFORMAT\"\n.sp\nDISPLAY\n.sp\n.if n .RS 4\n.nf\n.fam C\n{\n    \"id\": number,\n    \"uuid\": string,\n    \"index\": number,\n    \"label\": string,\n    \"frame\": object {\n        \"x\": number,\n        \"y\": number,\n        \"w\": number,\n        \"h\": number\n    },\n    \"spaces\": array of number,\n    \"has\\-focus\": bool\n}\n.fam\n.fi\n.if n .RE\n.sp\nSPACE\n.sp\n.if n .RS 4\n.nf\n.fam C\n{\n    \"id\": number,\n    \"uuid\": string,\n    \"index\": number,\n    \"label\": string,\n    \"type\": string,\n    \"display\": number,\n    \"windows\": array of number,\n    \"first\\-window\": number,\n    \"last\\-window\": number,\n    \"has\\-focus\": bool,\n    \"is\\-visible\": bool,\n    \"is\\-native\\-fullscreen\": bool\n}\n.fam\n.fi\n.if n .RE\n.sp\nWINDOW\n.sp\n.if n .RS 4\n.nf\n.fam C\n{\n    \"id\": number,\n    \"pid\": number,\n    \"app\": string,\n    \"title\": string,\n    \"scratchpad\": string,\n    \"frame\": object {\n        \"x\": number,\n        \"y\": number,\n        \"w\": number,\n        \"h\": number,\n    },\n    \"role\": string,\n    \"subrole\": string,\n    \"root\\-window\": bool,\n    \"display\": number,\n    \"space\": number,\n    \"level\": number,\n    \"sub\\-level\": number,\n    \"layer\": string,\n    \"sub\\-layer\": string,\n    \"opacity\": number,\n    \"split\\-type\": string,\n    \"split\\-child\": string,\n    \"stack\\-index\": number,\n    \"can\\-move\": bool,\n    \"can\\-resize\": bool,\n    \"has\\-focus\": bool,\n    \"has\\-shadow\": bool,\n    \"has\\-parent\\-zoom\": bool,\n    \"has\\-fullscreen\\-zoom\": bool,\n    \"has\\-ax\\-reference\": bool,\n    \"is\\-native\\-fullscreen\": bool,\n    \"is\\-visible\": bool,\n    \"is\\-minimized\": bool,\n    \"is\\-hidden\": bool,\n    \"is\\-floating\": bool,\n    \"is\\-sticky\": bool,\n    \"is\\-grabbed\": bool\n}\n.fam\n.fi\n.if n .RE\n.sp\nSome window properties are only accessible when yabai has a valid AX\\-reference for that window.\n.br\nThis AX\\-reference can only be retrieved when the space that the window is visible on, is active.\n.br\nIf windows are already opened on inactive spaces when yabai is launched, yabai will attempt to detect\n.br\nthese using a workaround, and for most applications and windows this will work. Some windows are not\n.br\ndetected using this method, and for those windows yabai will retrieve a limited amount of information,\n.br\nuntil the window that space belongs to becomes active \\(em yabai window commands will NOT WORK for these windows.\n.br\nThese windows can be identified by looking at the \\f(CRhas\\-ax\\-reference\\fP property. Once the space that the window\n.br\nbelongs to becomes active, yabai will automatically create an AX\\-reference. The queries will from that point\n.br\nforwards contain complete information, and the window  can be used with yabai window commands.\n.sp\nThe properties that contain incorrect information for windows with \\f(CRhas\\-ax\\-reference: false\\fP are as follows:\n.sp\n.if n .RS 4\n.nf\n.fam C\n{\n    \"role\": string,\n    \"subrole\": string,\n    \"can\\-move\": bool,\n    \"can\\-resize\": bool\n}\n.fam\n.fi\n.if n .RE\n.SS \"Rule\"\n.sp\nAll rules that match the given filter will be applied in the order they were registered.\n.br\nIf multiple rules specify a value for the same property, the latter rule will end up overriding that value.\n.br\nIf the display and space properties are both set, the space property will take precedence.\n.br\nThe following properties require System Integrity Protection to be partially disabled: sticky, sub\\-layer, opacity, scratchpad.\n.SS \"General Syntax\"\n.sp\nyabai \\-m rule \\fI<COMMAND>\\fP\n.SS \"COMMAND\"\n.sp\n\\fB\\-\\-add [\\-\\-one\\-shot] [\\fI<ARGUMENT>\\fP]\\fP\n.RS 4\nAdd a new rule. Rules apply to windows that spawn after said rule has been added.\n.br\nIf \\fI\\-\\-one\\-shot\\fP is present it will apply once and automatically remove itself.\n.RE\n.sp\n\\fB\\-\\-apply [\\fI<RULE_SEL>\\fP | \\fI<ARGUMENT>\\fP]\\fP\n.RS 4\nApply a rule to currently known windows.\n.br\nIf no argument is given, all existing rules will apply.\n.br\nIf an index or label is given, that particular rule will apply.\n.br\nArguments can also be provided directly, just like in the \\fB\\-\\-add\\fP command.\n.br\nExisting \\f(CR\\-\\-one\\-shot\\fP rules that have yet to apply will be ignored by this command.\n.RE\n.sp\n\\fB\\-\\-remove \\fI<RULE_SEL>\\fP\\fP\n.RS 4\nRemove an existing rule with the given index or label.\n.RE\n.sp\n\\fB\\-\\-list\\fP\n.RS 4\nOutput list of registered rules.\n.RE\n.SS \"ARGUMENT\"\n.sp\n\\fBlabel=\\fI<LABEL>\\fP\\fP\n.RS 4\nLabel used to identify the rule with a unique name\n.RE\n.sp\n\\fBapp[!]=\\fI<REGEX>\\fP\\fP\n.RS 4\nName of application. If \\fI!\\fP is present, invert the match.\n.RE\n.sp\n\\fBtitle[!]=\\fI<REGEX>\\fP\\fP\n.RS 4\nTitle of window. If \\fI!\\fP is present, invert the match.\n.RE\n.sp\n\\fBrole[!]=\\fI<REGEX>\\fP\\fP\n.RS 4\n.URL \"https://developer.apple.com/documentation/applicationservices/carbon_accessibility/roles?language=objc\" \"Accessibility role of window\" \".\"\nIf \\fI!\\fP is present, invert the match.\n.RE\n.sp\n\\fBsubrole[!]=\\fI<REGEX>\\fP\\fP\n.RS 4\n.URL \"https://developer.apple.com/documentation/applicationservices/carbon_accessibility/subroles?language=objc\" \"Accessibility subrole of window\" \".\"\nIf \\fI!\\fP is present, invert the match.\n.RE\n.sp\n\\fBdisplay=\\fI[^]<DISPLAY_SEL>\\fP\\fP\n.RS 4\nSend window to display. If \\fI^\\fP is present, follow focus.\n.RE\n.sp\n\\fBspace=\\fI[^]<SPACE_SEL>\\fP\\fP\n.RS 4\nSend window to space. If \\fI^\\fP is present, follow focus.\n.RE\n.sp\n\\fBmanage=\\fI<BOOL_SEL>\\fP\\fP\n.RS 4\nWindow should be managed (tile vs float).\n.br\nMost windows will be managed automatically, so this should mainly be used to make a window float.\n.RE\n.sp\n\\fBsticky=\\fI<BOOL_SEL>\\fP\\fP\n.RS 4\nWindow appears on all spaces.\n.br\nSystem Integrity Protection must be partially disabled.\n.RE\n.sp\n\\fBmouse_follows_focus=\\fI<BOOL_SEL>\\fP\\fP\n.RS 4\nWhen focusing the window, put the mouse at its center. Overrides the global \\fBmouse_follows_focus\\fP setting.\n.RE\n.sp\n\\fBsub\\-layer=\\fI<LAYER>\\fP\\fP\n.RS 4\nWindow is ordered within the given stacking sub\\-layer.\n.br\nThe window will no longer be eligible for automatic change in sub\\-layer when managed/unmanaged.\n.br\nSpecify the value \\fIauto\\fP to reset back to normal and make it become automatically managed.\n.br\nSystem Integrity Protection must be partially disabled.\n.RE\n.sp\n\\fBopacity=\\fI<FLOAT_SEL>\\fP\\fP\n.RS 4\nSet window opacity.\n.br\nThe window will no longer be eligible for automatic change in opacity upon focus change.\n.br\nSpecify the value \\fI0.0\\fP to reset back to full opacity and make it become automatically managed.\n.br\nSystem Integrity Protection must be partially disabled.\n.RE\n.sp\n\\fBnative\\-fullscreen=\\fI<BOOL_SEL>\\fP\\fP\n.RS 4\nWindow should enter native macOS fullscreen mode.\n.RE\n.sp\n\\fBgrid=\\fI<rows>:<cols>:<start\\-x>:<start\\-y>:<width>:<height>\\fP\\fP\n.RS 4\nSet window frame based on a self\\-defined grid.\n.RE\n.sp\n\\fBscratchpad=\\fI<LABEL>\\fP\\fP\n.RS 4\nUnique identifier used to identify a window scratchpad.\n.br\nAn identifier may only be assigned to a single window at any given time.\n.br\nA scratchpad window will automatically be treated as a (manage=off) floating window.\n.br\nIf this rule matches multiple windows, only the first window that matched will be assigned this scratchpad identifier.\n.br\nSystem Integrity Protection must be partially disabled.\n.RE\n.SS \"DATAFORMAT\"\n.sp\n.if n .RS 4\n.nf\n.fam C\n{\n    \"index\": number,\n    \"label\": string,\n    \"app\": string,\n    \"title\": string,\n    \"role\": string,\n    \"subrole\": string,\n    \"display\": number,\n    \"space\": number,\n    \"follow_space\": bool,\n    \"opacity\": number,\n    \"manage\": bool (optional),\n    \"sticky\": bool (optional),\n    \"mouse_follows_focus\": bool (optional),\n    \"sub\\-layer\": string,\n    \"native\\-fullscreen\": bool (optional),\n    \"grid\": string,\n    \"scratchpad\": string,\n    \"one\\-shot\": bool,\n    \"flags\": string\n}\n.fam\n.fi\n.if n .RE\n.SS \"Signal\"\n.sp\nA signal is a simple way for the user to react to some event that has been processed.\n.br\nArguments are passed through environment variables.\n.SS \"General Syntax\"\n.sp\nyabai \\-m signal \\fI<COMMAND>\\fP\n.SS \"COMMAND\"\n.sp\n\\fB\\-\\-add event=\\fI<EVENT>\\fP action=\\fI<ACTION>\\fP [label=\\fI<LABEL>\\fP] [app[!]=\\fI<REGEX>\\fP] [title[!]=\\fI<REGEX>\\fP] [active=\\fIyes|no\\fP]\\fP\n.RS 4\nAdd an optionally labelled signal to execute an action after processing an event of the given type.\n.br\nSome signals can be specified to trigger based on the application name and/or window title, and its active/focused state.\n.RE\n.sp\n\\fB\\-\\-remove \\fI<SIGNAL_SEL>\\fP\\fP\n.RS 4\nRemove an existing signal with the given index or label.\n.RE\n.sp\n\\fB\\-\\-list\\fP\n.RS 4\nOutput list of registered signals.\n.RE\n.SS \"EVENT\"\n.sp\n\\fBapplication_launched\\fP\n.RS 4\nTriggered when a new application is launched.\n.br\nEligible for \\fBapp\\fP filter.\n.br\nPasses one argument: $YABAI_PROCESS_ID\n.RE\n.sp\n\\fBapplication_terminated\\fP\n.RS 4\nTriggered when an application is terminated.\n.br\nEligible for \\fBapp\\fP and \\fBactive\\fP filter.\n.br\nPasses one argument: $YABAI_PROCESS_ID\n.RE\n.sp\n\\fBapplication_front_switched\\fP\n.RS 4\nTriggered when the front\\-most application changes.\n.br\nPasses two arguments: $YABAI_PROCESS_ID, $YABAI_RECENT_PROCESS_ID\n.RE\n.sp\n\\fBapplication_activated\\fP\n.RS 4\nTriggered when an application is activated.\n.br\nEligible for \\fBapp\\fP filter.\n.br\nPasses one argument: $YABAI_PROCESS_ID\n.RE\n.sp\n\\fBapplication_deactivated\\fP\n.RS 4\nTriggered when an application is deactivated.\n.br\nEligible for \\fBapp\\fP filter.\n.br\nPasses one argument: $YABAI_PROCESS_ID\n.RE\n.sp\n\\fBapplication_visible\\fP\n.RS 4\nTriggered when an application is unhidden.\n.br\nEligible for \\fBapp\\fP filter.\n.br\nPasses one argument: $YABAI_PROCESS_ID\n.RE\n.sp\n\\fBapplication_hidden\\fP\n.RS 4\nTriggered when an application is hidden.\n.br\nEligible for \\fBapp\\fP and \\fBactive\\fP filter.\n.br\nPasses one argument: $YABAI_PROCESS_ID\n.RE\n.sp\n\\fBwindow_created\\fP\n.RS 4\nTriggered when a window is created.\n.br\nAlso applies to windows that are implicitly created at application launch.\n.br\nEligible for \\fBapp\\fP and \\fBtitle\\fP filter.\n.br\nPasses one argument: $YABAI_WINDOW_ID\n.RE\n.sp\n\\fBwindow_destroyed\\fP\n.RS 4\nTriggered when a window is destroyed.\n.br\nAlso applies to windows that are implicitly destroyed at application exit.\n.br\nEligible for \\fBapp\\fP and \\fBactive\\fP filter.\n.br\nPasses one argument: $YABAI_WINDOW_ID\n.RE\n.sp\n\\fBwindow_focused\\fP\n.RS 4\nTriggered when a window becomes the key\\-window.\n.br\nEligible for \\fBapp\\fP and \\fBtitle\\fP filter.\n.br\nPasses one argument: $YABAI_WINDOW_ID\n.RE\n.sp\n\\fBwindow_moved\\fP\n.RS 4\nTriggered when a window changes position.\n.br\nEligible for \\fBapp\\fP, \\fBtitle\\fP and \\fBactive\\fP filter.\n.br\nPasses one argument: $YABAI_WINDOW_ID\n.RE\n.sp\n\\fBwindow_resized\\fP\n.RS 4\nTriggered when a window changes dimensions.\n.br\nEligible for \\fBapp\\fP, \\fBtitle\\fP and \\fBactive\\fP filter.\n.br\nPasses one argument: $YABAI_WINDOW_ID\n.RE\n.sp\n\\fBwindow_minimized\\fP\n.RS 4\nTriggered when a window has been minimized.\n.br\nEligible for \\fBapp\\fP, \\fBtitle\\fP and \\fBactive\\fP filter.\n.br\nPasses one argument: $YABAI_WINDOW_ID\n.RE\n.sp\n\\fBwindow_deminimized\\fP\n.RS 4\nTriggered when a window has been deminimized.\n.br\nEligible for \\fBapp\\fP and \\fBtitle\\fP filter.\n.br\nPasses one argument: $YABAI_WINDOW_ID\n.RE\n.sp\n\\fBwindow_title_changed\\fP\n.RS 4\nTriggered when a window changes its title.\n.br\nEligible for \\fBapp\\fP, \\fBtitle\\fP and \\fBactive\\fP filter.\n.br\nPasses one argument: $YABAI_WINDOW_ID\n.RE\n.sp\n\\fBspace_created\\fP\n.RS 4\nTriggered when a space is created.\n.br\nPasses two arguments: $YABAI_SPACE_ID, $YABAI_SPACE_INDEX\n.RE\n.sp\n\\fBspace_destroyed\\fP\n.RS 4\nTriggered when a space is destroyed.\n.br\nPasses one argument: $YABAI_SPACE_ID\n.RE\n.sp\n\\fBspace_changed\\fP\n.RS 4\nTriggered when the active space has changed.\n.br\nPasses four arguments: $YABAI_SPACE_ID, $YABAI_SPACE_INDEX, $YABAI_RECENT_SPACE_ID, $YABAI_RECENT_SPACE_INDEX\n.RE\n.sp\n\\fBdisplay_added\\fP\n.RS 4\nTriggered when a new display has been added.\n.br\nPasses two arguments: $YABAI_DISPLAY_ID, $YABAI_DISPLAY_INDEX\n.RE\n.sp\n\\fBdisplay_removed\\fP\n.RS 4\nTriggered when a display has been removed.\n.br\nPasses one argument: $YABAI_DISPLAY_ID\n.RE\n.sp\n\\fBdisplay_moved\\fP\n.RS 4\nTriggered when a change has been made to display arrangement.\n.br\nPasses two arguments: $YABAI_DISPLAY_ID, $YABAI_DISPLAY_INDEX\n.RE\n.sp\n\\fBdisplay_resized\\fP\n.RS 4\nTriggered when a display has changed resolution.\n.br\nPasses two arguments: $YABAI_DISPLAY_ID, $YABAI_DISPLAY_INDEX\n.RE\n.sp\n\\fBdisplay_changed\\fP\n.RS 4\nTriggered when the active display has changed.\n.br\nPasses four arguments: $YABAI_DISPLAY_ID, $YABAI_DISPLAY_INDEX, $YABAI_RECENT_DISPLAY_ID, $YABAI_RECENT_DISPLAY_INDEX\n.RE\n.sp\n\\fBmission_control_enter\\fP\n.RS 4\nTriggered when mission\\-control activates.\n.br\nPasses one argument: $YABAI_MISSION_CONTROL_MODE\n.RE\n.sp\n\\fBmission_control_exit\\fP\n.RS 4\nTriggered when mission\\-control deactivates.\n.br\nPasses one argument: $YABAI_MISSION_CONTROL_MODE\n.RE\n.sp\n\\fBdock_did_change_pref\\fP\n.RS 4\nTriggered when the macOS Dock preferences changes.\n.RE\n.sp\n\\fBdock_did_restart\\fP\n.RS 4\nTriggered when Dock.app restarts.\n.RE\n.sp\n\\fBmenu_bar_hidden_changed\\fP\n.RS 4\nTriggered when the macOS menubar \\fIautohide\\fP setting changes.\n.RE\n.sp\n\\fBsystem_woke\\fP\n.RS 4\nTriggered when macOS wakes from sleep.\n.RE\n.SS \"ACTION\"\n.sp\nArbitrary command executed through \\fB/usr/bin/env sh \\-c\\fP\n.SS \"DATAFORMAT\"\n.sp\n.if n .RS 4\n.nf\n.fam C\n{\n    \"index\": number,\n    \"label\": string,\n    \"app\": string,\n    \"title\": string,\n    \"active\": bool (optional),\n    \"event\": string,\n    \"action\": string\n}\n.fam\n.fi\n.if n .RE\n.SH \"EXIT CODES\"\n.sp\nIf \\fByabai\\fP can\\(cqt handle a message, it will return a non\\-zero exit code.\n.SH \"AUTHOR\"\n.sp\nÅsmund Vikane <aasvi93 at gmail.com>"
  },
  {
    "path": "doc/yabai.asciidoc",
    "content": ":man source:   Yabai\n:man version:  {revnumber}\n:man manual:   Yabai Manual\n\nifdef::env-github[]\n:toc:\n:toc-title:\n:toc-placement!:\nendif::[]\n\nyabai(1)\n========\n\nifdef::env-github[]\ntoc::[]\nendif::[]\n\nName\n----\n\nyabai - window manager\n\nSynopsis\n--------\n\n*yabai* [*--load-sa*|*--uninstall-sa*|*--install-service*|*--uninstall-service*|*--start-service*|*--restart-service*|*--stop-service*|*--message*,*-m* 'msg'|*--config*,*-c* 'config_file'|*--verbose*,*-V*|*--version*,*-v*|*--help*,*-h*]\n\nDescription\n-----------\n\n*yabai* is a tiling window manager for macOS based on binary space partitioning.\n\nOptions\n-------\n*--load-sa*::\n    Load the scripting-addition into Dock.app. +\n    Installs and updates the scripting-addition when necessary. +\n    Path is /Library/ScriptingAdditions/yabai.osax. +\n    System Integrity Protection must be partially disabled.\n\n*--uninstall-sa*::\n    Uninstall the scripting-addition. Must be run as root. +\n    Path is /Library/ScriptingAdditions/yabai.osax. +\n    System Integrity Protection must be partially disabled.\n\n*--install-service*::\n    Writes a launchd service file to disk. +\n    Path is ~/Library/LaunchAgents/com.asmvik.yabai.plist.\n\n*--uninstall-service*::\n    Removes a launchd service file from disk. +\n    Path is ~/Library/LaunchAgents/com.asmvik.yabai.plist.\n\n*--start-service*::\n    Enables, loads, and starts the launchd service. +\n    Will install service file if it does not exist.\n\n*--restart-service*::\n    Attempts to restart the service instance.\n\n*--stop-service*::\n    Stops a running instance of the service and unloads it.\n\n*--message*, *-m* '<msg>'::\n    Send message to a running instance of yabai.\n\n*--config*, *-c* '<config_file>'::\n    Use the specified configuration file. +\n    Executes using `/usr/bin/env sh -c <config_file>` if the exec-bit is set. +\n    Interpreted using `/usr/bin/env sh <config_file>` if the exec-bit is unset.\n\n*--verbose*, *-V*::\n    Output debug information to stdout.\n\n*--version*, *-v*::\n    Print version to stdout and exit.\n\n*--help*, *-h*::\n    Print options to stdout and exit.\n\nDefinitions\n-----------\n\n[subs=+macros]\n----\nREGEX       := https://www.gnu.org/software/findutils/manual/html_node/find_html/posix_002dextended-regular-expression-syntax.html[POSIX extended regular expression syntax]\n\nLABEL       := arbitrary string/text used as an identifier\n\nLAYER       := below | normal | above | auto\n\nBOOL_SEL    := on | off\n\nFLOAT_SEL   := 0 < <value> <= 1.0\n\nRULE_SEL    := <index> | LABEL\n\nSIGNAL_SEL  := <index> | LABEL\n\nDIR_SEL     := north | east | south | west\n\nSTACK_SEL   := stack.prev | stack.next | stack.first | stack.last | stack.recent | stack.<index (1-based)>\n\nWINDOW_SEL  := prev | next | first | last | recent | mouse | largest | smallest | sibling | first_nephew | second_nephew | uncle | first_cousin | second_cousin | STACK_SEL | DIR_SEL | <window id>\n\nDISPLAY_SEL := prev | next | first | last | recent | mouse | DIR_SEL | <arrangement index (1-based)> | LABEL\n\nSPACE_SEL   := prev | next | first | last | recent | mouse | <mission-control index (1-based)> | LABEL\n\nEASING      := ease_in_sine  | ease_out_sine  | ease_in_out_sine  |\n               ease_in_quad  | ease_out_quad  | ease_in_out_quad  |\n               ease_in_cubic | ease_out_cubic | ease_in_out_cubic |\n               ease_in_quart | ease_out_quart | ease_in_out_quart |\n               ease_in_quint | ease_out_quint | ease_in_out_quint |\n               ease_in_expo  | ease_out_expo  | ease_in_out_expo  |\n               ease_in_circ  | ease_out_circ  | ease_in_out_circ\n----\n\nDomains\n-------\n\nConfig\n~~~~~~\n\nGeneral Syntax\n^^^^^^^^^^^^^^\n\nyabai -m config <global setting>::\n    Get or set the value of <global setting>.\n\nyabai -m config [--space '<SPACE_SEL>'] <space setting>::\n    Get or set the value of <space setting>.\n\nGlobal Settings\n^^^^^^^^^^^^^^^\n\n*debug_output* ['<BOOL_SEL>']::\n    Enable output of debug information to stdout.\n\n*external_bar* ['<main|all|off>:<top_padding>:<bottom_padding>']::\n    Specify top and bottom padding for a potential custom bar that you may be running. +\n    'main': Apply the given padding only to spaces located on the main display. +\n    'all':  Apply the given padding to all spaces regardless of their display. +\n    'off':  Do not apply any special padding.\n\n*menubar_opacity* ['<FLOAT_SEL>']::\n    Changes the transparency of the macOS menubar. +\n    If the value is 0.0, the menubar will no longer respond to mouse-events, effectively hiding the menubar permanently. +\n    The menubar will automatically become fully opaque upon entering a native-fullscreen space, and adjusted down afterwards.\n\n*mouse_follows_focus* ['<BOOL_SEL>']::\n    When focusing a window, put the mouse at its center.\n\n*focus_follows_mouse* ['autofocus|autoraise|off']::\n    Automatically focus the window under the mouse.\n\n*display_arrangement_order* ['default|vertical|horizontal']::\n    Specify how displays are ordered (determined by center point). +\n    'default': Native macOS ordering. +\n    'vertical': Order by y-coordinate (followed by x-coordinate when equal). +\n    'horizontal': Order by x-coordinate (followed by y-coordinate when equal).\n\n*window_origin_display* ['default|focused|cursor']::\n    Specify which display a newly created window should be managed in. +\n    'default': The display in which the window is created (standard macOS behaviour). +\n    'focused': The display that has focus when the window is created. +\n    'cursor': The display that currently holds the mouse cursor.\n\n*window_placement* ['first_child|second_child']::\n    Specify whether managed windows should become the first or second leaf-node.\n\n*window_insertion_point* ['focused|first|last']::\n    Specify where new managed windows will be inserted.\n\n*window_zoom_persist* ['<BOOL_SEL>']::\n    Windows will keep their zoom-state through layout changes.\n\n*window_shadow* ['<BOOL_SEL>|float']::\n    Draw shadow for windows. +\n    System Integrity Protection must be partially disabled.\n\n*window_opacity* ['<BOOL_SEL>']::\n    Enable opacity for windows. +\n    System Integrity Protection must be partially disabled.\n\n*window_opacity_duration* ['<FLOAT_SEL>']::\n    Duration of transition between active / normal opacity. +\n    System Integrity Protection must be partially disabled.\n\n*active_window_opacity* ['<FLOAT_SEL>']::\n    Opacity of the focused window. +\n    System Integrity Protection must be partially disabled.\n\n*normal_window_opacity* ['<FLOAT_SEL>']::\n    Opacity of an unfocused window. +\n    System Integrity Protection must be partially disabled.\n\n*window_animation_duration* ['<FLOAT_SEL>']::\n    Duration of window frame animation. +\n    If 0.0, the change in dimension is not animated. +\n    Requires Screen Recording permissions. +\n    System Integrity Protection must be partially disabled.\n\n*window_animation_easing* ['<EASING>']::\n    Easing function to use for window animations. +\n    See https://easings.net for details.\n\n*insert_feedback_color* ['0xAARRGGBB']::\n    Color of the *window --insert* message and mouse_drag selection. +\n    The purpose is to provide a visual preview of the new window frame.\n\n*split_ratio* ['<FLOAT_SEL>']::\n    Specify the size distribution when a window is split.\n\n*mouse_modifier* ['cmd|alt|shift|ctrl|fn']::\n    Keyboard modifier used for moving and resizing windows.\n\n*mouse_action1* ['move|resize']::\n    Action performed when pressing 'mouse_modifier' + 'button1'.\n\n*mouse_action2* ['move|resize']::\n    Action performed when pressing 'mouse_modifier' + 'button2'.\n\n*mouse_drop_action* ['swap|stack']::\n    Action performed when a bsp-managed window is dropped in the center of some other bsp-managed window.\n\nSpace Settings\n^^^^^^^^^^^^^^\n\n*layout* ['bsp|stack|float']::\n    Set the layout of the selected space.\n\n*split_type* ['vertical|horizontal|auto']::\n    Specify how a window should be split. +\n    'vertical': The window is split along the y-axis. +\n    'horizontal': The window is split along the x-axis. +\n    'auto': The axis is determined based on width/height ratio.\n\n*top_padding* ['<integer number>']::\n    Padding added at the upper side of the selected space.\n\n*bottom_padding* ['<integer number>']::\n    Padding added at the lower side of the selected space.\n\n*left_padding* ['<integer number>']::\n    Padding added at the left side of the selected space.\n\n*right_padding* ['<integer number>']::\n    Padding added at the right side of the selected space.\n\n*window_gap* ['<integer number>']::\n    Size of the gap that separates windows for the selected space.\n\n*auto_balance* ['<BOOL_SEL>|x-axis|y-axis']::\n    Balance the window tree upon change, so that all windows occupy an equally sized area.\n\nDisplay\n~~~~~~~\n\nGeneral Syntax\n^^^^^^^^^^^^^^\n\nyabai -m display ['<DISPLAY_SEL'>] '<COMMAND>'\n\nCOMMAND\n^^^^^^^\n\n*--focus* '<DISPLAY_SEL>'::\n    Focus the given display.\n\n*--space* '<SPACE_SEL>'::\n    The given space will become visible on the selected display, without changing focus. +\n    The given space must belong to the selected display. +\n    System Integrity Protection must be partially disabled.\n\n*--label* ['<LABEL>']::\n    Label the selected display, allowing that label to be used as an alias in commands that take a `DISPLAY_SEL` parameter. +\n    If the command is called without an argument it will try to remove a previously assigned label.\n\nSpace\n~~~~~\n\nGeneral Syntax\n^^^^^^^^^^^^^^\n\nyabai -m space ['<SPACE_SEL>'] '<COMMAND>'\n\nCOMMAND\n^^^^^^^\n\n*--focus* '<SPACE_SEL>'::\n    Focus the given space. +\n    System Integrity Protection must be partially disabled.\n\n*--switch* '<SPACE_SEL>'::\n    The selected space will always be the currently focused space. +\n    The given space substitutes the selected space, gaining focus. +\n    If the selected space and the given space belong to different displays, this behaves like '--swap'. +\n    If the selected space and the given space belong to the same display, this behaves like '--focus'. +\n    System Integrity Protection must be partially disabled.\n\n*--create*  ['<DISPLAY_SEL>']::\n    Create a new space on the given display. +\n    If none specified, use the display of the active space instead. +\n    System Integrity Protection must be partially disabled.\n\n*--destroy* ['<SPACE_SEL>']::\n    Remove the given space. +\n    If none specified, use the selected space instead. +\n    System Integrity Protection must be partially disabled.\n\n*--move* '<SPACE_SEL>'::\n    Move position of the selected space to the position of the given space. +\n    The selected space and given space must both belong to the same display. +\n    System Integrity Protection must be partially disabled.\n\n*--swap* '<SPACE_SEL>'::\n    Swap the selected space with the given space. +\n    If the selected space and given space belong to different displays, all the windows will swap. +\n    If the selected space and given space belong to the same display, the actual spaces will swap. +\n    System Integrity Protection must be partially disabled.\n\n*--display* '<DISPLAY_SEL>'::\n    Send the selected space to the given display. +\n    System Integrity Protection must be partially disabled.\n\n*--equalize* ['x-axis|y-axis']::\n    Reset the split ratios on the selected space to the default value along the given axis. +\n    If no axis is specified, use both.\n\n*--balance* ['x-axis|y-axis']::\n    Adjust the split ratios on the selected space so that all windows along the given axis occupy the same area. +\n    If no axis is specified, use both.\n\n*--mirror* 'x-axis|y-axis'::\n    Flip the tree of the selected space along the given axis.\n\n*--rotate* '90|180|270'::\n    Rotate the tree of the selected space.\n\n*--padding* 'abs|rel:<top>:<bottom>:<left>:<right>'::\n    Padding added at the sides of the selected space.\n\n*--gap* 'abs|rel:<gap>'::\n    Size of the gap that separates windows on the selected space.\n\n*--toggle* 'padding|gap|mission-control|show-desktop'::\n    Toggle space setting on or off for the selected space.\n\n*--layout* 'bsp|stack|float'::\n    Set the layout of the selected space.\n\n*--label* ['<LABEL>']::\n    Label the selected space, allowing that label to be used as an alias in commands that take a `SPACE_SEL` parameter. +\n    If the command is called without an argument it will try to remove a previously assigned label.\n\nWindow\n~~~~~~\n\nGeneral Syntax\n^^^^^^^^^^^^^^\n\nyabai -m window ['<WINDOW_SEL>'] '<COMMAND>'\n\nCOMMAND\n^^^^^^^\n\n*--focus* ['<WINDOW_SEL>']::\n    Focus the given window. +\n    If none specified, focus the selected window instead.\n\n*--close* ['<WINDOW_SEL>']::\n    Close the given window. +\n    If none specified, close the selected window instead. +\n    Only works on windows that provide a close button in its titlebar.\n\n*--minimize* ['<WINDOW_SEL>']::\n    Minimize the given window. +\n    If none specified, minimize the selected window instead. +\n    Only works on windows that provide a minimize button in its titlebar.\n\n*--deminimize* '<WINDOW_SEL>'::\n    Restore the given window if it is minimized. +\n    The window will only get focus if the owning application has focus. +\n    Note that you can also '--focus' a minimized window to restore it as the focused window.\n\n*--display* '<DISPLAY_SEL>'::\n    Send the selected window to the given display.\n\n*--space* '<SPACE_SEL>'::\n    Send the selected window to the given space.\n    System Integrity Protection must be partially disabled on macOS Monterey 12.7+, Ventura 13.6+, Sonoma 14.5+, and macOS Sequoia.\n\n*--swap* '<WINDOW_SEL>'::\n    Swap position of the selected window and the given window.\n\n*--warp* '<WINDOW_SEL>'::\n    Re-insert the selected window, splitting the given window.\n\n*--stack* '<WINDOW_SEL>'::\n    Stack the given window on top of the selected window. +\n    Any kind of warp operation performed on a stacked window will unstack it.\n\n*--insert* '<DIR_SEL>|stack'::\n    Set the splitting mode of the selected window. +\n    If the current splitting mode matches the selected mode, the action will be undone.\n\n*--grid* '<rows>:<cols>:<start-x>:<start-y>:<width>:<height>'::\n    Set the frame of the selected window based on a self-defined grid.\n\n*--move* 'abs|rel:<dx>:<dy>'::\n    If type is 'rel' the selected window is moved by 'dx' pixels horizontally and 'dy' pixels vertically. +\n    If type is 'abs' 'dx' and 'dy' will become the new position.\n\n*--resize* 'top|left|bottom|right|top_left|top_right|bottom_right|bottom_left|abs:<dx>:<dy>'::\n    Resize the selected window by moving the given handle 'dx' pixels horizontally and 'dy' pixels vertically. +\n    If handle is 'abs' the new size will be 'dx' width and 'dy' height and cannot be used on managed windows.\n\n*--ratio* 'rel|abs:<dr>'::\n    If type is 'rel' the split ratio of the selected window is changed by 'dr', otherwise 'dr' will become the new split ratio. +\n    A positive/negative delta will increase/decrease the size of the left-child.\n\n*--toggle* 'float|sticky|pip|shadow|split|zoom-parent|zoom-fullscreen|windowed-fullscreen|native-fullscreen|expose|<LABEL>'::\n    Toggle the given property of the selected window. +\n    The following properties require System Integrity Protection to be partially disabled: sticky, pip, shadow, LABEL (scratchpad identifier) .\n\n*--sub-layer* '<LAYER>'::\n    Set the stacking sub-layer of the selected window. +\n    The window will no longer be eligible for automatic change in sub-layer when managed/unmanaged. +\n    Specify the value 'auto' to reset back to normal and make it become automatically managed. +\n    System Integrity Protection must be partially disabled.\n\n*--opacity* '<FLOAT_SEL>'::\n    Set the opacity of the selected window. +\n    The window will no longer be eligible for automatic change in opacity upon focus change. +\n    Specify the value '0.0' to reset back to full opacity and make it become automatically managed. +\n    System Integrity Protection must be partially disabled.\n\n*--raise* ['<WINDOW_SEL>']::\n    Orders the selected window above the given window, or to the front within its layer. +\n    System Integrity Protection must be partially disabled.\n\n*--lower* ['<WINDOW_SEL>']::\n    Orders the selected window below the given window, or to the back within its layer. +\n    System Integrity Protection must be partially disabled.\n\n*--scratchpad* ['<LABEL>|recover']::\n    Unique identifier used to identify a window scratchpad. +\n    An identifier may only be assigned to a single window at any given time. +\n    A scratchpad window will automatically be treated as a (manage=off) floating window. +\n    If the scratchpad is already taken by another window, this assignment will fail. +\n    If the scratchpad is re-assigned, the previous identifier will become available. +\n    If no value is given, the window will seize to be a scratchpad window. +\n    The special value 'recover' can be used to forcefully bring all scratchpad windows to the front. +\n    This can be useful if windows become inaccessible due to a restart or crash. +\n    System Integrity Protection must be partially disabled.\n\nQuery\n~~~~~~\n\nGeneral Syntax\n^^^^^^^^^^^^^^\n\nyabai -m query '<COMMAND>' ['<PROPERTIES>'] ['<ARGUMENT>']\n\nCOMMAND\n^^^^^^^\n\n*--displays*::\n    Retrieve information about displays.\n\n*--spaces*::\n    Retrieve information about spaces.\n\n*--windows*::\n    Retrieve information about windows.\n\nARGUMENT\n^^^^^^^^\n\n*--display* ['<DISPLAY_SEL>']::\n    Constrain matches to the selected display.\n\n*--space* ['<SPACE_SEL>']::\n    Constrain matches to the selected space.\n\n*--window* ['<WINDOW_SEL>']::\n    Constrain matches to the selected window.\n\nPROPERTIES\n^^^^^^^^^^\n\nA comma-separated string containing the name of fields to include in the output. +\nThe name of the provided fields must be present in the dataformat of the corresponding entity.\n\nDATAFORMAT\n^^^^^^^^^^\n\nDISPLAY\n[subs=+macros]\n----\n{\n    \"id\": number,\n    \"uuid\": string,\n    \"index\": number,\n    \"label\": string,\n    \"frame\": object {\n        \"x\": number,\n        \"y\": number,\n        \"w\": number,\n        \"h\": number\n    },\n    \"spaces\": array of number,\n    \"has-focus\": bool\n}\n----\n\nSPACE\n[subs=+macros]\n----\n{\n    \"id\": number,\n    \"uuid\": string,\n    \"index\": number,\n    \"label\": string,\n    \"type\": string,\n    \"display\": number,\n    \"windows\": array of number,\n    \"first-window\": number,\n    \"last-window\": number,\n    \"has-focus\": bool,\n    \"is-visible\": bool,\n    \"is-native-fullscreen\": bool\n}\n----\n\nWINDOW\n[subs=+macros]\n----\n{\n    \"id\": number,\n    \"pid\": number,\n    \"app\": string,\n    \"title\": string,\n    \"scratchpad\": string,\n    \"frame\": object {\n        \"x\": number,\n        \"y\": number,\n        \"w\": number,\n        \"h\": number,\n    },\n    \"role\": string,\n    \"subrole\": string,\n    \"root-window\": bool,\n    \"display\": number,\n    \"space\": number,\n    \"level\": number,\n    \"sub-level\": number,\n    \"layer\": string,\n    \"sub-layer\": string,\n    \"opacity\": number,\n    \"split-type\": string,\n    \"split-child\": string,\n    \"stack-index\": number,\n    \"can-move\": bool,\n    \"can-resize\": bool,\n    \"has-focus\": bool,\n    \"has-shadow\": bool,\n    \"has-parent-zoom\": bool,\n    \"has-fullscreen-zoom\": bool,\n    \"has-ax-reference\": bool,\n    \"is-native-fullscreen\": bool,\n    \"is-visible\": bool,\n    \"is-minimized\": bool,\n    \"is-hidden\": bool,\n    \"is-floating\": bool,\n    \"is-sticky\": bool,\n    \"is-grabbed\": bool\n}\n----\n\nSome window properties are only accessible when yabai has a valid AX-reference for that window. +\nThis AX-reference can only be retrieved when the space that the window is visible on, is active. +\nIf windows are already opened on inactive spaces when yabai is launched, yabai will attempt to detect +\nthese using a workaround, and for most applications and windows this will work. Some windows are not +\ndetected using this method, and for those windows yabai will retrieve a limited amount of information, +\nuntil the window that space belongs to becomes active -- yabai window commands will NOT WORK for these windows. +\nThese windows can be identified by looking at the `has-ax-reference` property. Once the space that the window +\nbelongs to becomes active, yabai will automatically create an AX-reference. The queries will from that point +\nforwards contain complete information, and the window  can be used with yabai window commands.\n\nThe properties that contain incorrect information for windows with `has-ax-reference: false` are as follows:\n----\n{\n    \"role\": string,\n    \"subrole\": string,\n    \"can-move\": bool,\n    \"can-resize\": bool\n}\n----\n\nRule\n~~~~\n\nAll rules that match the given filter will be applied in the order they were registered. +\nIf multiple rules specify a value for the same property, the latter rule will end up overriding that value. +\nIf the display and space properties are both set, the space property will take precedence. +\nThe following properties require System Integrity Protection to be partially disabled: sticky, sub-layer, opacity, scratchpad.\n\nGeneral Syntax\n^^^^^^^^^^^^^^\n\nyabai -m rule '<COMMAND>'\n\nCOMMAND\n^^^^^^^\n\n*--add [--one-shot] ['<ARGUMENT>']*::\n    Add a new rule. Rules apply to windows that spawn after said rule has been added. +\n    If '--one-shot' is present it will apply once and automatically remove itself.\n\n*--apply ['<RULE_SEL>' | '<ARGUMENT>']*::\n    Apply a rule to currently known windows. +\n    If no argument is given, all existing rules will apply. +\n    If an index or label is given, that particular rule will apply. +\n    Arguments can also be provided directly, just like in the *--add* command. +\n    Existing `--one-shot` rules that have yet to apply will be ignored by this command.\n\n*--remove '<RULE_SEL>'*::\n    Remove an existing rule with the given index or label.\n\n*--list*::\n    Output list of registered rules.\n\nARGUMENT\n^^^^^^^^\n\n*label='<LABEL>'*::\n    Label used to identify the rule with a unique name\n\n*app[!]='<REGEX>'*::\n    Name of application. If '!' is present, invert the match.\n\n*title[!]='<REGEX>'*::\n    Title of window. If '!' is present, invert the match.\n\n*role[!]='<REGEX>'*::\n    https://developer.apple.com/documentation/applicationservices/carbon_accessibility/roles?language=objc[Accessibility role of window]. If '!' is present, invert the match.\n\n*subrole[!]='<REGEX>'*::\n    https://developer.apple.com/documentation/applicationservices/carbon_accessibility/subroles?language=objc[Accessibility subrole of window]. If '!' is present, invert the match.\n\n*display='[^]<DISPLAY_SEL>'*::\n    Send window to display. If '^' is present, follow focus.\n\n*space='[^]<SPACE_SEL>'*::\n    Send window to space. If '^' is present, follow focus.\n\n*manage='<BOOL_SEL>'*::\n    Window should be managed (tile vs float). +\n    Most windows will be managed automatically, so this should mainly be used to make a window float.\n\n*sticky='<BOOL_SEL>'*::\n    Window appears on all spaces. +\n    System Integrity Protection must be partially disabled.\n\n*mouse_follows_focus='<BOOL_SEL>'*::\n    When focusing the window, put the mouse at its center. Overrides the global *mouse_follows_focus* setting.\n\n*sub-layer='<LAYER>'*::\n    Window is ordered within the given stacking sub-layer. +\n    The window will no longer be eligible for automatic change in sub-layer when managed/unmanaged. +\n    Specify the value 'auto' to reset back to normal and make it become automatically managed. +\n    System Integrity Protection must be partially disabled.\n\n*opacity='<FLOAT_SEL>'*::\n    Set window opacity. +\n    The window will no longer be eligible for automatic change in opacity upon focus change. +\n    Specify the value '0.0' to reset back to full opacity and make it become automatically managed. +\n    System Integrity Protection must be partially disabled.\n\n*native-fullscreen='<BOOL_SEL>'*::\n    Window should enter native macOS fullscreen mode.\n\n*grid='<rows>:<cols>:<start-x>:<start-y>:<width>:<height>'*::\n    Set window frame based on a self-defined grid.\n\n*scratchpad='<LABEL>'*::\n    Unique identifier used to identify a window scratchpad. +\n    An identifier may only be assigned to a single window at any given time. +\n    A scratchpad window will automatically be treated as a (manage=off) floating window. +\n    If this rule matches multiple windows, only the first window that matched will be assigned this scratchpad identifier. +\n    System Integrity Protection must be partially disabled.\n\nDATAFORMAT\n^^^^^^^^^^\n\n[subs=+macros]\n----\n{\n    \"index\": number,\n    \"label\": string,\n    \"app\": string,\n    \"title\": string,\n    \"role\": string,\n    \"subrole\": string,\n    \"display\": number,\n    \"space\": number,\n    \"follow_space\": bool,\n    \"opacity\": number,\n    \"manage\": bool (optional),\n    \"sticky\": bool (optional),\n    \"mouse_follows_focus\": bool (optional),\n    \"sub-layer\": string,\n    \"native-fullscreen\": bool (optional),\n    \"grid\": string,\n    \"scratchpad\": string,\n    \"one-shot\": bool,\n    \"flags\": string\n}\n----\n\nSignal\n~~~~~~\n\nA signal is a simple way for the user to react to some event that has been processed. +\nArguments are passed through environment variables.\n\nGeneral Syntax\n^^^^^^^^^^^^^^\n\nyabai -m signal '<COMMAND>'\n\nCOMMAND\n^^^^^^^\n\n*--add event='<EVENT>' action='<ACTION>' [label='<LABEL>'] [app[!]='<REGEX>'] [title[!]='<REGEX>'] [active='yes|no']*::\n    Add an optionally labelled signal to execute an action after processing an event of the given type. +\n    Some signals can be specified to trigger based on the application name and/or window title, and its active/focused state.\n\n*--remove '<SIGNAL_SEL>'*::\n    Remove an existing signal with the given index or label.\n\n*--list*::\n    Output list of registered signals.\n\nEVENT\n^^^^^\n\n*application_launched*::\n    Triggered when a new application is launched. +\n    Eligible for *app* filter. +\n    Passes one argument: $YABAI_PROCESS_ID\n\n*application_terminated*::\n    Triggered when an application is terminated. +\n    Eligible for *app* and *active* filter. +\n    Passes one argument: $YABAI_PROCESS_ID\n\n*application_front_switched*::\n    Triggered when the front-most application changes. +\n    Passes two arguments: $YABAI_PROCESS_ID, $YABAI_RECENT_PROCESS_ID\n\n*application_activated*::\n    Triggered when an application is activated. +\n    Eligible for *app* filter. +\n    Passes one argument: $YABAI_PROCESS_ID\n\n*application_deactivated*::\n    Triggered when an application is deactivated. +\n    Eligible for *app* filter. +\n    Passes one argument: $YABAI_PROCESS_ID\n\n*application_visible*::\n    Triggered when an application is unhidden. +\n    Eligible for *app* filter. +\n    Passes one argument: $YABAI_PROCESS_ID\n\n*application_hidden*::\n    Triggered when an application is hidden. +\n    Eligible for *app* and *active* filter. +\n    Passes one argument: $YABAI_PROCESS_ID\n\n*window_created*::\n    Triggered when a window is created. +\n    Also applies to windows that are implicitly created at application launch. +\n    Eligible for *app* and *title* filter. +\n    Passes one argument: $YABAI_WINDOW_ID\n\n*window_destroyed*::\n    Triggered when a window is destroyed. +\n    Also applies to windows that are implicitly destroyed at application exit. +\n    Eligible for *app* and *active* filter. +\n    Passes one argument: $YABAI_WINDOW_ID\n\n*window_focused*::\n    Triggered when a window becomes the key-window. +\n    Eligible for *app* and *title* filter. +\n    Passes one argument: $YABAI_WINDOW_ID\n\n*window_moved*::\n    Triggered when a window changes position. +\n    Eligible for *app*, *title* and *active* filter. +\n    Passes one argument: $YABAI_WINDOW_ID\n\n*window_resized*::\n    Triggered when a window changes dimensions. +\n    Eligible for *app*, *title* and *active* filter. +\n    Passes one argument: $YABAI_WINDOW_ID\n\n*window_minimized*::\n    Triggered when a window has been minimized. +\n    Eligible for *app*, *title* and *active* filter. +\n    Passes one argument: $YABAI_WINDOW_ID\n\n*window_deminimized*::\n    Triggered when a window has been deminimized. +\n    Eligible for *app* and *title* filter. +\n    Passes one argument: $YABAI_WINDOW_ID\n\n*window_title_changed*::\n    Triggered when a window changes its title. +\n    Eligible for *app*, *title* and *active* filter. +\n    Passes one argument: $YABAI_WINDOW_ID\n\n*space_created*::\n    Triggered when a space is created. +\n    Passes two arguments: $YABAI_SPACE_ID, $YABAI_SPACE_INDEX\n\n*space_destroyed*::\n    Triggered when a space is destroyed. +\n    Passes one argument: $YABAI_SPACE_ID\n\n*space_changed*::\n    Triggered when the active space has changed. +\n    Passes four arguments: $YABAI_SPACE_ID, $YABAI_SPACE_INDEX, $YABAI_RECENT_SPACE_ID, $YABAI_RECENT_SPACE_INDEX\n\n*display_added*::\n    Triggered when a new display has been added. +\n    Passes two arguments: $YABAI_DISPLAY_ID, $YABAI_DISPLAY_INDEX\n\n*display_removed*::\n    Triggered when a display has been removed. +\n    Passes one argument: $YABAI_DISPLAY_ID\n\n*display_moved*::\n    Triggered when a change has been made to display arrangement. +\n    Passes two arguments: $YABAI_DISPLAY_ID, $YABAI_DISPLAY_INDEX\n\n*display_resized*::\n    Triggered when a display has changed resolution. +\n    Passes two arguments: $YABAI_DISPLAY_ID, $YABAI_DISPLAY_INDEX\n\n*display_changed*::\n    Triggered when the active display has changed. +\n    Passes four arguments: $YABAI_DISPLAY_ID, $YABAI_DISPLAY_INDEX, $YABAI_RECENT_DISPLAY_ID, $YABAI_RECENT_DISPLAY_INDEX\n\n*mission_control_enter*::\n    Triggered when mission-control activates. +\n    Passes one argument: $YABAI_MISSION_CONTROL_MODE\n\n*mission_control_exit*::\n    Triggered when mission-control deactivates. +\n    Passes one argument: $YABAI_MISSION_CONTROL_MODE\n\n*dock_did_change_pref*::\n    Triggered when the macOS Dock preferences changes.\n\n*dock_did_restart*::\n    Triggered when Dock.app restarts.\n\n*menu_bar_hidden_changed*::\n    Triggered when the macOS menubar 'autohide' setting changes.\n\n*system_woke*::\n    Triggered when macOS wakes from sleep.\n\nACTION\n^^^^^^\n\nArbitrary command executed through */usr/bin/env sh -c*\n\nDATAFORMAT\n^^^^^^^^^^\n\n[subs=+macros]\n----\n{\n    \"index\": number,\n    \"label\": string,\n    \"app\": string,\n    \"title\": string,\n    \"active\": bool (optional),\n    \"event\": string,\n    \"action\": string\n}\n----\n\nExit Codes\n----------\n\nIf *yabai* can't handle a message, it will return a non-zero exit code.\n\nAuthor\n------\n\nÅsmund Vikane <aasvi93 at gmail.com>\n"
  },
  {
    "path": "examples/skhdrc",
    "content": "# ################################################################ #\n# THE FOLLOWING IS AN EXPLANATION OF THE GRAMMAR THAT SKHD PARSES. #\n# FOR SIMPLE EXAMPLE MAPPINGS LOOK FURTHER DOWN THIS FILE..        #\n# ################################################################ #\n\n# A list of all built-in modifier and literal keywords can\n# be found at https://github.com/asmvik/skhd/issues/1\n#\n# A hotkey is written according to the following rules:\n#\n#   hotkey       = <mode> '<' <action> | <action>\n#\n#   mode         = 'name of mode' | <mode> ',' <mode>\n#\n#   action       = <keysym> '[' <proc_map_lst> ']' | <keysym> '->' '[' <proc_map_lst> ']'\n#                  <keysym> ':' <command>          | <keysym> '->' ':' <command>\n#                  <keysym> ';' <mode>             | <keysym> '->' ';' <mode>\n#\n#   keysym       = <mod> '-' <key> | <key>\n#\n#   mod          = 'modifier keyword' | <mod> '+' <mod>\n#\n#   key          = <literal> | <keycode>\n#\n#   literal      = 'single letter or built-in keyword'\n#\n#   keycode      = 'apple keyboard kVK_<Key> values (0x3C)'\n#\n#   proc_map_lst = * <proc_map>\n#\n#   proc_map     = <string> ':' <command> | <string>     '~' |\n#                  '*'      ':' <command> | '*'          '~'\n#\n#   string       = '\"' 'sequence of characters' '\"'\n#\n#   command      = command is executed through '$SHELL -c' and\n#                  follows valid shell syntax. if the $SHELL environment\n#                  variable is not set, it will default to '/bin/bash'.\n#                  when bash is used, the ';' delimeter can be specified\n#                  to chain commands.\n#\n#                  to allow a command to extend into multiple lines,\n#                  prepend '\\' at the end of the previous line.\n#\n#                  an EOL character signifies the end of the bind.\n#\n#   ->           = keypress is not consumed by skhd\n#\n#   *            = matches every application not specified in <proc_map_lst>\n#\n#   ~            = application is unbound and keypress is forwarded per usual, when specified in a <proc_map>\n#\n# A mode is declared according to the following rules:\n#\n#   mode_decl = '::' <name> '@' ':' <command> | '::' <name> ':' <command> |\n#               '::' <name> '@'               | '::' <name>\n#\n#   name      = desired name for this mode,\n#\n#   @         = capture keypresses regardless of being bound to an action\n#\n#   command   = command is executed through '$SHELL -c' and\n#               follows valid shell syntax. if the $SHELL environment\n#               variable is not set, it will default to '/bin/bash'.\n#               when bash is used, the ';' delimeter can be specified\n#               to chain commands.\n#\n#               to allow a command to extend into multiple lines,\n#               prepend '\\' at the end of the previous line.\n#\n#               an EOL character signifies the end of the bind.\n\n# ############################################################### #\n# THE FOLLOWING SECTION CONTAIN SIMPLE MAPPINGS DEMONSTRATING HOW #\n# TO INTERACT WITH THE YABAI WM. THESE ARE SUPPOSED TO BE USED AS #\n# A REFERENCE ONLY, WHEN MAKING YOUR OWN CONFIGURATION..          #\n# ############################################################### #\n\n# focus window\n# alt - h : yabai -m window --focus west\n\n# swap managed window\n# shift + alt - h : yabai -m window --swap north\n\n# move managed window\n# shift + cmd - h : yabai -m window --warp east\n\n# balance size of windows\n# shift + alt - 0 : yabai -m space --balance\n\n# make floating window fill screen\n# shift + alt - up     : yabai -m window --grid 1:1:0:0:1:1\n\n# make floating window fill left-half of screen\n# shift + alt - left   : yabai -m window --grid 1:2:0:0:1:1\n\n# create desktop, move window and follow focus - uses jq for parsing json (brew install jq)\n# shift + cmd - n : yabai -m space --create && \\\n#                   index=\"$(yabai -m query --spaces --display | jq 'map(select(.\"is-native-fullscreen\" == false))[-1].index')\" && \\\n#                   yabai -m window --space \"${index}\" && \\\n#                   yabai -m space --focus \"${index}\"\n\n# fast focus desktop\n# cmd + alt - x : yabai -m space --focus recent\n# cmd + alt - 1 : yabai -m space --focus 1\n\n# send window to desktop and follow focus\n# shift + cmd - z : yabai -m window --space next; yabai -m space --focus next\n# shift + cmd - 2 : yabai -m window --space  2; yabai -m space --focus 2\n\n# focus monitor\n# ctrl + alt - z  : yabai -m display --focus prev\n# ctrl + alt - 3  : yabai -m display --focus 3\n\n# send window to monitor and follow focus\n# ctrl + cmd - c  : yabai -m window --display next; yabai -m display --focus next\n# ctrl + cmd - 1  : yabai -m window --display 1; yabai -m display --focus 1\n\n# move floating window\n# shift + ctrl - a : yabai -m window --move rel:-20:0\n# shift + ctrl - s : yabai -m window --move rel:0:20\n\n# increase window size\n# shift + alt - a : yabai -m window --resize left:-20:0\n# shift + alt - w : yabai -m window --resize top:0:-20\n\n# decrease window size\n# shift + cmd - s : yabai -m window --resize bottom:0:-20\n# shift + cmd - w : yabai -m window --resize top:0:20\n\n# set insertion point in focused container\n# ctrl + alt - h : yabai -m window --insert west\n\n# toggle window zoom\n# alt - d : yabai -m window --toggle zoom-parent\n# alt - f : yabai -m window --toggle zoom-fullscreen\n\n# toggle window split type\n# alt - e : yabai -m window --toggle split\n\n# float / unfloat window and center on screen\n# alt - t : yabai -m window --toggle float --grid 4:4:1:1:2:2\n\n# toggle sticky(+float), picture-in-picture\n# alt - p : yabai -m window --toggle sticky --toggle pip\n"
  },
  {
    "path": "examples/yabairc",
    "content": "#!/usr/bin/env sh\n\n#\n# for this to work you must configure sudo such that\n# it will be able to run the command without password\n#\n# see this wiki page for information:\n#  - https://github.com/asmvik/yabai/wiki/Installing-yabai-(latest-release)#configure-scripting-addition\n#\n# yabai -m signal --add event=dock_did_restart action=\"sudo yabai --load-sa\"\n# sudo yabai --load-sa\n#\n\n# global settings\nyabai -m config                                 \\\n    external_bar                 off:40:0       \\\n    menubar_opacity              1.0            \\\n    mouse_follows_focus          off            \\\n    focus_follows_mouse          off            \\\n    display_arrangement_order    default        \\\n    window_origin_display        default        \\\n    window_placement             second_child   \\\n    window_insertion_point       focused        \\\n    window_zoom_persist          on             \\\n    window_shadow                on             \\\n    window_animation_duration    0.0            \\\n    window_animation_easing      ease_out_circ  \\\n    window_opacity_duration      0.0            \\\n    active_window_opacity        1.0            \\\n    normal_window_opacity        0.90           \\\n    window_opacity               off            \\\n    insert_feedback_color        0xffd75f5f     \\\n    split_ratio                  0.50           \\\n    split_type                   auto           \\\n    auto_balance                 off            \\\n    top_padding                  12             \\\n    bottom_padding               12             \\\n    left_padding                 12             \\\n    right_padding                12             \\\n    window_gap                   06             \\\n    layout                       bsp            \\\n    mouse_modifier               fn             \\\n    mouse_action1                move           \\\n    mouse_action2                resize         \\\n    mouse_drop_action            swap\n\necho \"yabai configuration loaded..\"\n"
  },
  {
    "path": "makefile",
    "content": "FRAMEWORK_PATH = -F/System/Library/PrivateFrameworks\nFRAMEWORK      = -framework Carbon -framework Cocoa -framework CoreServices -framework CoreVideo -framework SkyLight\nCLI_FLAGS      =\nBUILD_FLAGS    = -std=c11 -Wall -Wextra -g -O0 -fvisibility=hidden -mmacosx-version-min=11.0 -fno-objc-arc -arch x86_64 -arch arm64 -sectcreate __TEXT __info_plist $(INFO_PLIST)\nBUILD_PATH     = ./bin\nDOC_PATH       = ./doc\nSCRIPT_PATH    = ./scripts\nASSET_PATH     = ./assets\nSMP_PATH       = ./examples\nARCH_PATH      = ./archive\nOSAX_SRC       = ./src/osax/payload_bin.c ./src/osax/loader_bin.c\nYABAI_SRC      = ./src/manifest.m $(OSAX_SRC)\nOSAX_PATH      = ./src/osax\nINFO_PLIST     = $(ASSET_PATH)/Info.plist\nBINS           = $(BUILD_PATH)/yabai\n\n.PHONY: all asan tsan install man icon archive publish sign clean-build clean\n\nall: clean-build $(BINS)\n\nasan: BUILD_FLAGS=-std=c11 -Wall -Wextra -g -O0 -fvisibility=hidden -fsanitize=address,undefined -mmacosx-version-min=11.0 -fno-objc-arc -arch x86_64 -arch arm64 -sectcreate __TEXT __info_plist $(INFO_PLIST)\nasan: clean-build $(BINS)\n\ntsan: BUILD_FLAGS=-std=c11 -Wall -Wextra -g -O0 -fvisibility=hidden -fsanitize=thread,undefined -mmacosx-version-min=11.0 -fno-objc-arc -arch x86_64 -arch arm64 -sectcreate __TEXT __info_plist $(INFO_PLIST)\ntsan: clean-build $(BINS)\n\ninstall: BUILD_FLAGS=-std=c11 -Wall -Wextra -DNDEBUG -O3 -fvisibility=hidden -mmacosx-version-min=11.0 -fno-objc-arc -arch x86_64 -arch arm64 -sectcreate __TEXT __info_plist $(INFO_PLIST)\ninstall: clean-build $(BINS)\n\n$(OSAX_SRC): $(OSAX_PATH)/loader.m $(OSAX_PATH)/payload.m\n\txcrun clang $(OSAX_PATH)/payload.m -shared -fPIC -O3 -mmacosx-version-min=11.0 -arch x86_64 -arch arm64e -o $(OSAX_PATH)/payload $(FRAMEWORK_PATH) -framework SkyLight -framework Foundation -framework Carbon\n\txcrun clang $(OSAX_PATH)/loader.m -O3 -mmacosx-version-min=11.0 -arch x86_64 -arch arm64e -o $(OSAX_PATH)/loader -framework Cocoa\n\txxd -i -a $(OSAX_PATH)/payload $(OSAX_PATH)/payload_bin.c\n\txxd -i -a $(OSAX_PATH)/loader $(OSAX_PATH)/loader_bin.c\n\trm -f $(OSAX_PATH)/payload\n\trm -f $(OSAX_PATH)/loader\n\nman:\n\tasciidoctor -b manpage $(DOC_PATH)/yabai.asciidoc -o $(DOC_PATH)/yabai.1\n\nicon:\n\tpython3 $(SCRIPT_PATH)/seticon.py $(ASSET_PATH)/icon/2x/icon-512px@2x.png $(BUILD_PATH)/yabai\n\npublish:\n\tsed -i '' \"60s/^VERSION=.*/VERSION=\\\"$(shell $(BUILD_PATH)/yabai --version | cut -d \"v\" -f 2)\\\"/\" $(SCRIPT_PATH)/install.sh\n\tsed -i '' \"61s/^EXPECTED_HASH=.*/EXPECTED_HASH=\\\"$(shell shasum -a 256 $(BUILD_PATH)/$(shell $(BUILD_PATH)/yabai --version).tar.gz | cut -d \" \" -f 1)\\\"/\" $(SCRIPT_PATH)/install.sh\n\narchive: man install sign icon\n\trm -rf $(ARCH_PATH)\n\tmkdir -p $(ARCH_PATH)\n\tcp -r $(BUILD_PATH) $(ARCH_PATH)/\n\tcp -r $(DOC_PATH) $(ARCH_PATH)/\n\tcp -r $(SMP_PATH) $(ARCH_PATH)/\n\ttar -cvzf $(BUILD_PATH)/$(shell $(BUILD_PATH)/yabai --version).tar.gz $(ARCH_PATH)\n\trm -rf $(ARCH_PATH)\n\nsign:\n\tcodesign -fs \"yabai-cert\" $(BUILD_PATH)/yabai\n\nclean-build:\n\trm -rf $(BUILD_PATH)\n\nclean: clean-build\n\trm -f $(OSAX_SRC)\n\n$(BUILD_PATH)/yabai: $(YABAI_SRC)\n\tmkdir -p $(BUILD_PATH)\n\txcrun clang $^ $(BUILD_FLAGS) $(CLI_FLAGS) $(FRAMEWORK_PATH) $(FRAMEWORK) -o $@\n"
  },
  {
    "path": "scripts/codesign",
    "content": "#! /usr/bin/env bash\n\nidentities=\"$(security find-identity -v -p codesigning | sed '$d')\"\nid_count=\"$(echo \"${identities}\" | wc -l)\"\ntarget=\"$(command -v \"${1:-}\")\"\n\nfunction error() {\n\t{\n\t\techo \"$(tput bold)Error: ${@}$(tput sgr0)\"\n\t\techo\n\t\techo \"Usage: ./scripts/codesign <path/to/executable> [<certificate>]\"\n\t\techo \"Available codesigning certificates:\"\n\t\techo \"${identities}\"\n\t} >&2\n\texit 1\n}\n\nif [ \"${id_count}\" -lt 1 ]; then\n\t>&2 echo \"Unable to find a codesigning identity\"\n\texit 1\nelif [ \"${id_count}\" -eq 1 ]; then\n\tselection=\"1\"\nelif [ \"${id_count}\" -gt 1 ] && [ \"${#}\" -eq 2 ]; then\n\tselection=\"${2}\"\nelif [ -x \"${target}\" ]; then\n\terror \"Unable to auto-select codesigning certificate\"\nelse\n\terror \"Unable to find executable \\\"${target}\\\"\"\nfi\n\nif [[ \"${selection}\" =~ ^[0-9]+$ ]]; then\n\tcertificate=\"$(echo \"${identities}\" \\\n\t\t| awk \"NR==${selection} {print \\$2}\")\"\nelse\n\tcertificate=\"$(echo \"${identities}\" \\\n\t\t| awk 'BEGIN{FS=OFS=\"\\\"\"} {gsub(/ /,\"_\",$2)} 1' \\\n\t\t| awk \"\\$3 ~ /${selection// /_}/ {print \\$2}\")\"\nfi\n\nif [ -z \"${certificate}\" ]; then\n\terror \"Unable to find codesigning certificate \\\"${selection}\\\"\"\nelif [ \"$(echo \"${certificate}\" | wc -l)\" -ne 1 ]; then\n\terror \"Unable to uniquely identify codesigning certificate \\\"${selection}\\\"\"\nfi\n\ncommand codesign --deep --force --verbose --sign \"${certificate}\" \"${target}\"\n\n"
  },
  {
    "path": "scripts/install.sh",
    "content": "#!/usr/bin/env sh\n\n#\n# This script will install the latest pre-built yabai release from GitHub.\n# Depends on curl, shasum, tar, cp, cut.\n#\n# ARG1:   Directory in which to store the yabai binary; must be an absolutepath.\n#         Fallback: /usr/local/bin\n#\n# ARG2:   Directory in which to store the yabai man-page; must be an absolutepath.\n#         Fallback: /usr/local/man/man1\n#\n# Author: Åsmund Vikane\n#   Date: 2024-02-13\n#\n\nBIN_DIR=\"$1\"\nMAN_DIR=\"$2\"\n\nif [ -z \"$BIN_DIR\" ]; then\n    BIN_DIR=\"/usr/local/bin\"\nfi\n\nif [ -z \"$MAN_DIR\" ]; then\n    MAN_DIR=\"/usr/local/share/man/man1\"\nfi\n\nif [ \"${BIN_DIR%%/*}\" ]; then\n    echo \"Error: Binary target directory '${BIN_DIR}' is not an absolutepath.\"\n    exit 1\nfi\n\nif [ ! -d \"$BIN_DIR\" ]; then\n    echo \"Error: Binary target directory '${BIN_DIR}' does not exist.\"\n    exit 1\nfi\n\nif [ ! -w \"$BIN_DIR\" ]; then\n    echo \"Error: User does not have write permission for binary target directory '${BIN_DIR}'.\"\n    exit 1\nfi\n\nif [ \"${MAN_DIR%%/*}\" ]; then\n    echo \"Error: Man-page target directory '${MAN_DIR}' is not an absolutepath.\"\n    exit 1\nfi\n\nif [ ! -d \"$MAN_DIR\" ]; then\n    echo \"Error: Man-page target directory '${MAN_DIR}' does not exist.\"\n    exit 1\nfi\n\nif [ ! -w \"$MAN_DIR\" ]; then\n    echo \"Error: User does not have write permission for man-page target directory '${MAN_DIR}'.\"\n    exit 1\nfi\n\nAUTHOR=\"asmvik\"\nNAME=\"yabai\"\nVERSION=\"7.1.17\"\nEXPECTED_HASH=\"3a1d46a3c52811f092861c40ee31b1359976138b8b312b77340a002311786247\"\nTMP_DIR=\"./${AUTHOR}-${NAME}-v${VERSION}-installer\"\n\nmkdir $TMP_DIR\npushd $TMP_DIR\n\ncurl --location --remote-name https://github.com/${AUTHOR}/${NAME}/releases/download/v${VERSION}/${NAME}-v${VERSION}.tar.gz\nFILE_HASH=$(shasum -a 256 ./${NAME}-v${VERSION}.tar.gz | cut -d \" \" -f 1)\n\nif [ \"$FILE_HASH\" = \"$EXPECTED_HASH\" ]; then\n    echo \"Hash verified. Preparing files..\"\n    tar -xzvf ${NAME}-v${VERSION}.tar.gz\n    rm ${BIN_DIR}/${NAME}\n    rm ${MAN_DIR}/${NAME}.1\n    cp -v ./archive/bin/${NAME} ${BIN_DIR}/${NAME}\n    cp -v ./archive/doc/${NAME}.1 ${MAN_DIR}/${NAME}.1\n    echo \"Finished copying files..\"\n    echo \"\"\n    echo \"If you want yabai to be managed by launchd (start automatically upon login):\"\n    echo \"  yabai --start-service\"\n    echo \"\"\n    echo \"When running as a launchd service logs will be found in:\"\n    echo \"  /tmp/yabai_<user>.[out|err].log\"\n    echo \"\"\n    echo \"If you are using the scripting-addition; remember to update your sudoers file:\"\n    echo \"  sudo visudo -f /private/etc/sudoers.d/yabai\"\n    echo \"\"\n    echo \"Sudoers file configuration row:\"\n    echo \"  $(whoami) ALL=(root) NOPASSWD: sha256:$(shasum -a 256 ${BIN_DIR}/yabai | cut -d \" \" -f 1) ${BIN_DIR}/yabai --load-sa\"\n    echo \"\"\n    echo \"README: https://github.com/asmvik/yabai/wiki/Installing-yabai-(latest-release)#configure-scripting-addition\"\nelse\n    echo \"Hash does not match the expected value.. abort.\"\n    echo \"Expected hash: $EXPECTED_HASH\"\n    echo \"  Actual hash: $FILE_HASH\"\nfi\n\npopd\nrm -rf $TMP_DIR\n"
  },
  {
    "path": "scripts/seticon.py",
    "content": "#!/usr/bin/env python\n\nimport Cocoa\nimport sys\n\nimage = Cocoa.NSImage.alloc().initWithContentsOfFile_(sys.argv[1]);\nbinary = sys.argv[2];\noptions = 0;\n\nresult = Cocoa.NSWorkspace.sharedWorkspace().setIcon_forFile_options_(image, binary, options);\nif result == 0: print(\"could not set icon for file..\");\n"
  },
  {
    "path": "src/application.c",
    "content": "extern struct event_loop g_event_loop;\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wunused-parameter\"\nstatic OBSERVER_CALLBACK(application_notification_handler)\n{\n    if (CFEqual(notification, kAXCreatedNotification)) {\n        event_loop_post(&g_event_loop, WINDOW_CREATED, (void *) CFRetain(element), 0);\n    } else if (CFEqual(notification, kAXFocusedWindowChangedNotification)) {\n        event_loop_post(&g_event_loop, WINDOW_FOCUSED, (void *)(intptr_t) ax_window_id(element), 0);\n    } else if (CFEqual(notification, kAXWindowMovedNotification)) {\n        event_loop_post(&g_event_loop, WINDOW_MOVED, (void *)(intptr_t) ax_window_id(element), 0);\n    } else if (CFEqual(notification, kAXWindowResizedNotification)) {\n        event_loop_post(&g_event_loop, WINDOW_RESIZED, (void *)(intptr_t) ax_window_id(element), 0);\n    } else if (CFEqual(notification, kAXTitleChangedNotification)) {\n        event_loop_post(&g_event_loop, WINDOW_TITLE_CHANGED, (void *)(intptr_t) ax_window_id(element), 0);\n    } else if (CFEqual(notification, kAXMenuOpenedNotification)) {\n        event_loop_post(&g_event_loop, MENU_OPENED, (void *)(intptr_t) ax_window_id(element), 0);\n    } else if (CFEqual(notification, kAXMenuClosedNotification)) {\n        event_loop_post(&g_event_loop, MENU_CLOSED, NULL, 0);\n    } else if (CFEqual(notification, kAXWindowMiniaturizedNotification)) {\n        event_loop_post(&g_event_loop, WINDOW_MINIMIZED, context, 0);\n    } else if (CFEqual(notification, kAXWindowDeminiaturizedNotification)) {\n        event_loop_post(&g_event_loop, WINDOW_DEMINIMIZED, context, 0);\n    } else if (CFEqual(notification, kAXUIElementDestroyedNotification)) {\n        struct window *window = context;\n\n        //\n        // NOTE(asmvik): Flag events that are already queued, but not yet processed,\n        // so that they will be ignored; the memory we allocated is still valid and will\n        // be freed when this event is handled.\n        //\n\n        if (!__sync_bool_compare_and_swap(&window->id_ptr, &window->id, NULL)) return;\n\n        event_loop_post(&g_event_loop, WINDOW_DESTROYED, window, 0);\n    }\n}\n#pragma clang diagnostic pop\n\nbool application_observe(struct application *application)\n{\n    if (AXObserverCreate(application->pid, application_notification_handler, &application->observer_ref) == kAXErrorSuccess) {\n        for (int i = 0; i < array_count(ax_application_notification); ++i) {\n            AXError result = AXObserverAddNotification(application->observer_ref, application->ref, ax_application_notification[i], application);\n            if (result == kAXErrorSuccess || result == kAXErrorNotificationAlreadyRegistered) {\n                application->notification |= 1 << i;\n            } else {\n                if (result == kAXErrorCannotComplete) application->ax_retry = true;\n                debug(\"%s: error '%s' for application '%s' and notification '%s'\\n\", __FUNCTION__, ax_error_str[-result], application->name, ax_application_notification_str[i]);\n            }\n        }\n\n        application->is_observing = true;\n        CFRunLoopAddSource(CFRunLoopGetMain(), AXObserverGetRunLoopSource(application->observer_ref), kCFRunLoopDefaultMode);\n    }\n\n    return (application->notification & AX_APPLICATION_ALL) == AX_APPLICATION_ALL;\n}\n\nvoid application_unobserve(struct application *application)\n{\n    if (application->is_observing) {\n        for (int i = 0; i < array_count(ax_application_notification); ++i) {\n            if (!(application->notification & (1 << i))) continue;\n\n            AXObserverRemoveNotification(application->observer_ref, application->ref, ax_application_notification[i]);\n            application->notification &= ~(1 << i);\n        }\n\n        application->is_observing = false;\n        CFRunLoopSourceInvalidate(AXObserverGetRunLoopSource(application->observer_ref));\n        CFRelease(application->observer_ref);\n    }\n}\n\nuint32_t application_main_window(struct application *application)\n{\n    CFTypeRef window_ref = NULL;\n    AXUIElementCopyAttributeValue(application->ref, kAXMainWindowAttribute, &window_ref);\n    if (!window_ref) return 0;\n\n    uint32_t window_id = ax_window_id(window_ref);\n    CFRelease(window_ref);\n\n    return window_id;\n}\n\nuint32_t application_focused_window(struct application *application)\n{\n    CFTypeRef window_ref = NULL;\n    AXUIElementCopyAttributeValue(application->ref, kAXFocusedWindowAttribute, &window_ref);\n    if (!window_ref) return 0;\n\n    uint32_t window_id = ax_window_id(window_ref);\n    CFRelease(window_ref);\n\n    return window_id;\n}\n\nbool application_is_frontmost(struct application *application)\n{\n    ProcessSerialNumber psn = {0};\n    _SLPSGetFrontProcess(&psn);\n    return psn_equals(&psn, &application->psn);\n}\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wdeprecated-declarations\"\nbool application_is_hidden(struct application *application)\n{\n    return IsProcessVisible(&application->psn) == 0;\n}\n#pragma clang diagnostic pop\n\nCFArrayRef application_window_list(struct application *application)\n{\n    CFTypeRef window_list_ref = NULL;\n    AXUIElementCopyAttributeValue(application->ref, kAXWindowsAttribute, &window_list_ref);\n    return window_list_ref;\n}\n\nstruct application *application_create(struct process *process)\n{\n    struct application *application = malloc(sizeof(struct application));\n    memset(application, 0, sizeof(struct application));\n\n    application->ref = AXUIElementCreateApplication(process->pid);\n    application->psn = process->psn;\n    application->pid = process->pid;\n    application->name = process->name;\n    application->is_hidden = application_is_hidden(application);\n    SLSGetConnectionIDForPSN(g_connection, &application->psn, &application->connection);\n\n    return application;\n}\n\nvoid application_destroy(struct application *application)\n{\n    CFRelease(application->ref);\n    free(application);\n}\n"
  },
  {
    "path": "src/application.h",
    "content": "#ifndef APPLICATION_H\n#define APPLICATION_H\n\n#define OBSERVER_CALLBACK(name) void name(AXObserverRef observer, AXUIElementRef element, CFStringRef notification, void *context)\ntypedef OBSERVER_CALLBACK(observer_callback);\n\n#define AX_APPLICATION_WINDOW_CREATED_INDEX       0\n#define AX_APPLICATION_WINDOW_FOCUSED_INDEX       1\n#define AX_APPLICATION_WINDOW_MOVED_INDEX         2\n#define AX_APPLICATION_WINDOW_RESIZED_INDEX       3\n#define AX_APPLICATION_WINDOW_TITLE_CHANGED_INDEX 4\n#define AX_APPLICATION_WINDOW_MENU_OPENED_INDEX   5\n#define AX_APPLICATION_WINDOW_MENU_CLOSED_INDEX   6\n\n#define AX_APPLICATION_WINDOW_CREATED       (1 << AX_APPLICATION_WINDOW_CREATED_INDEX)\n#define AX_APPLICATION_WINDOW_FOCUSED       (1 << AX_APPLICATION_WINDOW_FOCUSED_INDEX)\n#define AX_APPLICATION_WINDOW_MOVED         (1 << AX_APPLICATION_WINDOW_MOVED_INDEX)\n#define AX_APPLICATION_WINDOW_RESIZED       (1 << AX_APPLICATION_WINDOW_RESIZED_INDEX)\n#define AX_APPLICATION_WINDOW_TITLE_CHANGED (1 << AX_APPLICATION_WINDOW_TITLE_CHANGED_INDEX)\n#define AX_APPLICATION_ALL                  (AX_APPLICATION_WINDOW_CREATED |\\\n                                             AX_APPLICATION_WINDOW_FOCUSED |\\\n                                             AX_APPLICATION_WINDOW_MOVED |\\\n                                             AX_APPLICATION_WINDOW_RESIZED |\\\n                                             AX_APPLICATION_WINDOW_TITLE_CHANGED)\n\nstatic const char *ax_error_str[] =\n{\n    [-kAXErrorSuccess]                           = \"kAXErrorSuccess\",\n    [-kAXErrorFailure]                           = \"kAXErrorFailure\",\n    [-kAXErrorIllegalArgument]                   = \"kAXErrorIllegalArgument\",\n    [-kAXErrorInvalidUIElement]                  = \"kAXErrorInvalidUIElement\",\n    [-kAXErrorInvalidUIElementObserver]          = \"kAXErrorInvalidUIElementObserver\",\n    [-kAXErrorCannotComplete]                    = \"kAXErrorCannotComplete\",\n    [-kAXErrorAttributeUnsupported]              = \"kAXErrorAttributeUnsupported\",\n    [-kAXErrorActionUnsupported]                 = \"kAXErrorActionUnsupported\",\n    [-kAXErrorNotificationUnsupported]           = \"kAXErrorNotificationUnsupported\",\n    [-kAXErrorNotImplemented]                    = \"kAXErrorNotImplemented\",\n    [-kAXErrorNotificationAlreadyRegistered]     = \"kAXErrorNotificationAlreadyRegistered\",\n    [-kAXErrorNotificationNotRegistered]         = \"kAXErrorNotificationNotRegistered\",\n    [-kAXErrorAPIDisabled]                       = \"kAXErrorAPIDisabled\",\n    [-kAXErrorNoValue]                           = \"kAXErrorNoValue\",\n    [-kAXErrorParameterizedAttributeUnsupported] = \"kAXErrorParameterizedAttributeUnsupported\",\n    [-kAXErrorNotEnoughPrecision]                = \"kAXErrorNotEnoughPrecision\"\n};\n\nstatic const char *ax_application_notification_str[] =\n{\n    [AX_APPLICATION_WINDOW_CREATED_INDEX]       = \"kAXCreatedNotification\",\n    [AX_APPLICATION_WINDOW_FOCUSED_INDEX]       = \"kAXFocusedWindowChangedNotification\",\n    [AX_APPLICATION_WINDOW_MOVED_INDEX]         = \"kAXWindowMovedNotification\",\n    [AX_APPLICATION_WINDOW_RESIZED_INDEX]       = \"kAXWindowResizedNotification\",\n    [AX_APPLICATION_WINDOW_TITLE_CHANGED_INDEX] = \"kAXTitleChangedNotification\",\n    [AX_APPLICATION_WINDOW_MENU_OPENED_INDEX]   = \"kAXMenuOpenedNotification\",\n    [AX_APPLICATION_WINDOW_MENU_CLOSED_INDEX]   = \"kAXMenuClosedNotification\"\n};\n\nstatic CFStringRef ax_application_notification[] =\n{\n    [AX_APPLICATION_WINDOW_CREATED_INDEX]       = kAXCreatedNotification,\n    [AX_APPLICATION_WINDOW_FOCUSED_INDEX]       = kAXFocusedWindowChangedNotification,\n    [AX_APPLICATION_WINDOW_MOVED_INDEX]         = kAXWindowMovedNotification,\n    [AX_APPLICATION_WINDOW_RESIZED_INDEX]       = kAXWindowResizedNotification,\n    [AX_APPLICATION_WINDOW_TITLE_CHANGED_INDEX] = kAXTitleChangedNotification,\n    [AX_APPLICATION_WINDOW_MENU_OPENED_INDEX]   = kAXMenuOpenedNotification,\n    [AX_APPLICATION_WINDOW_MENU_CLOSED_INDEX]   = kAXMenuClosedNotification\n};\n\nstruct application\n{\n    AXUIElementRef ref;\n    int connection;\n    ProcessSerialNumber psn;\n    pid_t pid;\n    char *name;\n    AXObserverRef observer_ref;\n    uint8_t notification;\n    bool is_observing;\n    bool is_hidden;\n    bool ax_retry;\n};\n\nbool application_is_frontmost(struct application *application);\nbool application_is_hidden(struct application *application);\nuint32_t application_main_window(struct application *application);\nuint32_t application_focused_window(struct application *application);\nCFArrayRef application_window_list(struct application *application);\nbool application_observe(struct application *application);\nvoid application_unobserve(struct application *application);\nstruct application *application_create(struct process *process);\nvoid application_destroy(struct application *application);\n\n#endif\n"
  },
  {
    "path": "src/display.c",
    "content": "extern struct event_loop g_event_loop;\nextern int g_connection;\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wunused-parameter\"\nstatic DISPLAY_EVENT_HANDLER(display_handler)\n{\n    if (flags & kCGDisplayAddFlag) {\n        event_loop_post(&g_event_loop, DISPLAY_ADDED, (void *)(intptr_t) did, 0);\n    } else if (flags & kCGDisplayRemoveFlag) {\n        event_loop_post(&g_event_loop, DISPLAY_REMOVED, (void *)(intptr_t) did, 0);\n    } else if (flags & kCGDisplayMovedFlag) {\n        event_loop_post(&g_event_loop, DISPLAY_MOVED, (void *)(intptr_t) did, 0);\n    } else if (flags & kCGDisplayDesktopShapeChangedFlag) {\n        event_loop_post(&g_event_loop, DISPLAY_RESIZED, (void *)(intptr_t) did, 0);\n    }\n}\n#pragma clang diagnostic pop\n\nvoid display_serialize(FILE *rsp, uint32_t did, uint64_t flags)\n{\n    TIME_FUNCTION;\n\n    if (flags == 0x0) flags |= ~flags;\n\n    bool did_output = false;\n    fprintf(rsp, \"{\\n\");\n\n    if (flags & DISPLAY_PROPERTY_ID) {\n        fprintf(rsp, \"\\t\\\"id\\\":%d\", did);\n        did_output = true;\n    }\n\n    if (flags & DISPLAY_PROPERTY_UUID) {\n        if (did_output) fprintf(rsp, \",\\n\");\n\n        char *uuid = NULL;\n        CFStringRef uuid_ref = display_uuid(did);\n        if (uuid_ref) {\n            uuid = ts_cfstring_copy(uuid_ref);\n            CFRelease(uuid_ref);\n        }\n\n        fprintf(rsp, \"\\t\\\"uuid\\\":\\\"%s\\\"\", uuid ? uuid : \"<unknown>\");\n        did_output = true;\n    }\n\n    if (flags & DISPLAY_PROPERTY_INDEX) {\n        if (did_output) fprintf(rsp, \",\\n\");\n\n        fprintf(rsp, \"\\t\\\"index\\\":%d\", display_manager_display_id_arrangement(did));\n        did_output = true;\n    }\n\n    if (flags & DISPLAY_PROPERTY_LABEL) {\n        if (did_output) fprintf(rsp, \",\\n\");\n\n        struct display_label *display_label = display_manager_get_label_for_display(&g_display_manager, did);\n        fprintf(rsp, \"\\t\\\"label\\\":\\\"%s\\\"\", display_label ? display_label->label : \"\");\n        did_output = true;\n    }\n\n    if (flags & DISPLAY_PROPERTY_FRAME) {\n        if (did_output) fprintf(rsp, \",\\n\");\n\n        CGRect frame = CGDisplayBounds(did);\n        fprintf(rsp, \"\\t\\\"frame\\\":{\\n\\t\\t\\\"x\\\":%.4f,\\n\\t\\t\\\"y\\\":%.4f,\\n\\t\\t\\\"w\\\":%.4f,\\n\\t\\t\\\"h\\\":%.4f\\n\\t}\", frame.origin.x, frame.origin.y, frame.size.width, frame.size.height);\n        did_output = true;\n    }\n\n    if (flags & DISPLAY_PROPERTY_SPACES) {\n        if (did_output) fprintf(rsp, \",\\n\");\n\n        int count;\n        uint64_t *space_list = display_space_list(did, &count);\n\n        fprintf(rsp, \"\\t\\\"spaces\\\":[\");\n        if (space_list) {\n            int first_mci = space_manager_mission_control_index(space_list[0]);\n            for (int i = 0; i < count; ++i) {\n                if (i < count - 1) {\n                    fprintf(rsp, \"%d, \", first_mci + i);\n                } else {\n                    fprintf(rsp, \"%d\", first_mci + i);\n                }\n            }\n        }\n        fprintf(rsp, \"]\");\n        did_output = true;\n    }\n\n    if (flags & DISPLAY_PROPERTY_HAS_FOCUS) {\n        if (did_output) fprintf(rsp, \",\\n\");\n\n        fprintf(rsp, \"\\t\\\"has-focus\\\":%s\", json_bool(did == g_display_manager.current_display_id));\n    }\n\n    fprintf(rsp, \"\\n}\");\n}\n\nCFStringRef display_uuid(uint32_t did)\n{\n    CFUUIDRef uuid_ref = CGDisplayCreateUUIDFromDisplayID(did);\n    if (!uuid_ref) return NULL;\n\n    CFStringRef uuid_str = CFUUIDCreateString(NULL, uuid_ref);\n    CFRelease(uuid_ref);\n\n    return uuid_str;\n}\n\nuint32_t display_id(CFStringRef uuid)\n{\n    CFUUIDRef uuid_ref = CFUUIDCreateFromString(NULL, uuid);\n    if (!uuid_ref) return 0;\n\n    uint32_t did = CGDisplayGetDisplayIDFromUUID(uuid_ref);\n    CFRelease(uuid_ref);\n\n    return did;\n}\n\nCGRect display_bounds_constrained(uint32_t did, bool ignore_external_bar)\n{\n    CGRect frame = CGDisplayBounds(did);\n    int effective_ext_top_padding = 0;\n\n    if (!ignore_external_bar) {\n        if ((g_display_manager.mode == EXTERNAL_BAR_MAIN &&\n             did == display_manager_main_display_id()) ||\n            (g_display_manager.mode == EXTERNAL_BAR_ALL)) {\n            effective_ext_top_padding = g_display_manager.top_padding;\n\n            frame.origin.y    += effective_ext_top_padding;\n            frame.size.height -= effective_ext_top_padding;\n            frame.size.height -= g_display_manager.bottom_padding;\n        }\n    }\n\n    if (display_manager_menu_bar_hidden()) {\n        int notch_height = workspace_display_notch_height(did);\n        if (notch_height > effective_ext_top_padding) {\n             frame.origin.y    += (notch_height - effective_ext_top_padding);\n             frame.size.height -= (notch_height - effective_ext_top_padding);\n        }\n    } else {\n        CGRect menu = display_manager_menu_bar_rect(did);\n        frame.origin.y    += menu.size.height;\n        frame.size.height -= menu.size.height;\n    }\n\n    if (!display_manager_dock_hidden()) {\n        if (did == display_manager_dock_display_id()) {\n            CGRect dock = display_manager_dock_rect();\n            switch (display_manager_dock_orientation()) {\n            case DOCK_ORIENTATION_LEFT: {\n                frame.origin.x   += dock.size.width;\n                frame.size.width -= dock.size.width;\n            } break;\n            case DOCK_ORIENTATION_RIGHT: {\n                frame.size.width -= dock.size.width;\n            } break;\n            case DOCK_ORIENTATION_BOTTOM: {\n                frame.size.height -= dock.size.height;\n            } break;\n            }\n        }\n    }\n\n    return frame;\n}\n\nCGPoint display_center(uint32_t did)\n{\n    CGRect bounds = CGDisplayBounds(did);\n    return (CGPoint) { bounds.origin.x + bounds.size.width/2, bounds.origin.y + bounds.size.height/2 };\n}\n\nuint64_t display_space_id(uint32_t did)\n{\n    CFStringRef uuid = display_uuid(did);\n    if (!uuid) return 0;\n\n    uint64_t sid = SLSManagedDisplayGetCurrentSpace(g_connection, uuid);\n    CFRelease(uuid);\n\n    return sid;\n}\n\nint display_space_count(uint32_t did)\n{\n    int space_count = 0;\n\n    CFStringRef uuid = display_uuid(did);\n    if (!uuid) goto out;\n\n    CFArrayRef display_spaces_ref = SLSCopyManagedDisplaySpaces(g_connection);\n    if (!display_spaces_ref) goto err;\n\n    int display_spaces_count = CFArrayGetCount(display_spaces_ref);\n    for (int i = 0; i < display_spaces_count; ++i) {\n        CFDictionaryRef display_ref = CFArrayGetValueAtIndex(display_spaces_ref, i);\n        CFStringRef identifier = CFDictionaryGetValue(display_ref, CFSTR(\"Display Identifier\"));\n        if (!CFEqual(uuid, identifier)) continue;\n\n        CFArrayRef spaces_ref = CFDictionaryGetValue(display_ref, CFSTR(\"Spaces\"));\n        space_count = CFArrayGetCount(spaces_ref);\n        break;\n    }\n\n    CFRelease(display_spaces_ref);\nerr:\n    CFRelease(uuid);\nout:\n    return space_count;\n}\n\nuint64_t *display_space_list(uint32_t did, int *count)\n{\n    uint64_t *space_list = NULL;\n\n    CFStringRef uuid = display_uuid(did);\n    if (!uuid) goto out;\n\n    CFArrayRef display_spaces_ref = SLSCopyManagedDisplaySpaces(g_connection);\n    if (!display_spaces_ref) goto err;\n\n    int display_spaces_count = CFArrayGetCount(display_spaces_ref);\n    for (int i = 0; i < display_spaces_count; ++i) {\n        CFDictionaryRef display_ref = CFArrayGetValueAtIndex(display_spaces_ref, i);\n        CFStringRef identifier = CFDictionaryGetValue(display_ref, CFSTR(\"Display Identifier\"));\n        if (!CFEqual(uuid, identifier)) continue;\n\n        CFArrayRef spaces_ref = CFDictionaryGetValue(display_ref, CFSTR(\"Spaces\"));\n        int spaces_count = CFArrayGetCount(spaces_ref);\n\n        space_list = ts_alloc_list(uint64_t, spaces_count);\n        *count = spaces_count;\n\n        for (int j = 0; j < spaces_count; ++j) {\n            CFDictionaryRef space_ref = CFArrayGetValueAtIndex(spaces_ref, j);\n            CFNumberRef sid_ref = CFDictionaryGetValue(space_ref, CFSTR(\"id64\"));\n            CFNumberGetValue(sid_ref, CFNumberGetType(sid_ref), &space_list[j]);\n        }\n    }\n\n    CFRelease(display_spaces_ref);\nerr:\n    CFRelease(uuid);\nout:\n    return space_list;\n}\n"
  },
  {
    "path": "src/display.h",
    "content": "#ifndef DISPLAY_H\n#define DISPLAY_H\n\n#define DISPLAY_EVENT_HANDLER(name) void name(uint32_t did, CGDisplayChangeSummaryFlags flags, void *context)\ntypedef DISPLAY_EVENT_HANDLER(display_callback);\n\n#define DISPLAY_PROPERTY_LIST \\\n    DISPLAY_PROPERTY_ENTRY(\"id\",        DISPLAY_PROPERTY_ID,        0x01) \\\n    DISPLAY_PROPERTY_ENTRY(\"uuid\",      DISPLAY_PROPERTY_UUID,      0x02) \\\n    DISPLAY_PROPERTY_ENTRY(\"index\",     DISPLAY_PROPERTY_INDEX,     0x04) \\\n    DISPLAY_PROPERTY_ENTRY(\"label\",     DISPLAY_PROPERTY_LABEL,     0x08) \\\n    DISPLAY_PROPERTY_ENTRY(\"frame\",     DISPLAY_PROPERTY_FRAME,     0x10) \\\n    DISPLAY_PROPERTY_ENTRY(\"spaces\",    DISPLAY_PROPERTY_SPACES,    0x20) \\\n    DISPLAY_PROPERTY_ENTRY(\"has-focus\", DISPLAY_PROPERTY_HAS_FOCUS, 0x40)\n\nenum display_property\n{\n#define DISPLAY_PROPERTY_ENTRY(n, p, v) p = v,\n    DISPLAY_PROPERTY_LIST\n#undef DISPLAY_PROPERTY_ENTRY\n};\n\nstatic uint64_t display_property_val[] =\n{\n#define DISPLAY_PROPERTY_ENTRY(n, p, v) p,\n    DISPLAY_PROPERTY_LIST\n#undef DISPLAY_PROPERTY_ENTRY\n};\n\nstatic char *display_property_str[] =\n{\n#define DISPLAY_PROPERTY_ENTRY(n, p, v) n,\n    DISPLAY_PROPERTY_LIST\n#undef DISPLAY_PROPERTY_ENTRY\n};\n\nvoid display_serialize(FILE *rsp, uint32_t did, uint64_t flags);\nCFStringRef display_uuid(uint32_t did);\nuint32_t display_id(CFStringRef uuid);\nCGRect display_bounds_constrained(uint32_t did, bool ignore_external_bar);\nCGPoint display_center(uint32_t did);\nuint64_t display_space_id(uint32_t did);\nint display_space_count(uint32_t did);\nuint64_t *display_space_list(uint32_t did, int *count);\n\n#endif\n"
  },
  {
    "path": "src/display_manager.c",
    "content": "extern struct display_manager g_display_manager;\nextern struct window_manager g_window_manager;\nextern int g_connection;\n\nbool display_manager_query_displays(FILE *rsp, uint64_t flags)\n{\n    TIME_FUNCTION;\n\n    int count;\n    uint32_t *display_list = display_manager_active_display_list(&count);\n    if (!display_list) return false;\n\n    fprintf(rsp, \"[\");\n    for (int i = 0; i < count; ++i) {\n        display_serialize(rsp, display_list[i], flags);\n        fprintf(rsp, \"%c\", i < count - 1 ? ',' : ']');\n    }\n    fprintf(rsp, \"\\n\");\n\n    return true;\n}\n\nstruct display_label *display_manager_get_label_for_display(struct display_manager *dm, uint32_t did)\n{\n    for (int i = 0; i < buf_len(dm->labels); ++i) {\n        struct display_label *display_label = &dm->labels[i];\n        if (display_label->did == did) {\n            return display_label;\n        }\n    }\n\n    return NULL;\n}\n\nstruct display_label *display_manager_get_display_for_label(struct display_manager *dm, char *label)\n{\n    for (int i = 0; i < buf_len(dm->labels); ++i) {\n        struct display_label *display_label = &dm->labels[i];\n        if (string_equals(label, display_label->label)) {\n            return display_label;\n        }\n    }\n\n    return NULL;\n}\n\nbool display_manager_remove_label_for_display(struct display_manager *dm, uint32_t did)\n{\n    for (int i = 0; i < buf_len(dm->labels); ++i) {\n        struct display_label *display_label = &dm->labels[i];\n        if (display_label->did == did) {\n            free(display_label->label);\n            buf_del(dm->labels, i);\n            return true;\n        }\n    }\n\n    return false;\n}\n\nvoid display_manager_set_label_for_display(struct display_manager *dm, uint32_t did, char *label)\n{\n    display_manager_remove_label_for_display(dm, did);\n\n    for (int i = 0; i < buf_len(dm->labels); ++i) {\n        struct display_label *display_label = &dm->labels[i];\n        if (string_equals(display_label->label, label)) {\n            free(display_label->label);\n            buf_del(dm->labels, i);\n            break;\n        }\n    }\n\n    buf_push(dm->labels, ((struct display_label) {\n        .did   = did,\n        .label = label\n    }));\n}\n\nCFStringRef display_manager_main_display_uuid(void)\n{\n    uint32_t did = display_manager_main_display_id();\n    return display_uuid(did);\n}\n\nuint32_t display_manager_main_display_id(void)\n{\n    return CGMainDisplayID();\n}\n\nCFStringRef display_manager_active_display_uuid(void)\n{\n    return SLSCopyActiveMenuBarDisplayIdentifier(g_connection);\n}\n\nuint32_t display_manager_active_display_id(void)\n{\n    CFStringRef uuid = display_manager_active_display_uuid();\n    assert(uuid);\n\n    uint32_t result = display_id(uuid);\n    CFRelease(uuid);\n\n    return result;\n}\n\nCFStringRef display_manager_dock_display_uuid(void)\n{\n    CGRect dock = display_manager_dock_rect();\n    return SLSCopyBestManagedDisplayForRect(g_connection, dock);\n}\n\nuint32_t display_manager_dock_display_id(void)\n{\n    CFStringRef uuid = display_manager_dock_display_uuid();\n    if (!uuid) return 0;\n\n    uint32_t result = display_id(uuid);\n    CFRelease(uuid);\n\n    return result;\n}\n\nCFStringRef display_manager_point_display_uuid(CGPoint point)\n{\n    return SLSCopyBestManagedDisplayForPoint(g_connection, point);\n}\n\nuint32_t display_manager_point_display_id(CGPoint point)\n{\n    CFStringRef uuid = display_manager_point_display_uuid(point);\n    if (!uuid) return 0;\n\n    uint32_t result = display_id(uuid);\n    CFRelease(uuid);\n\n    return result;\n}\n\nstatic CFComparisonResult display_manager_coordinate_comparator(CFTypeRef a, CFTypeRef b, void *context)\n{\n    enum display_arrangement_order axis = (enum display_arrangement_order)(uintptr_t) context;\n\n    uint32_t a_did = display_id(a);\n    uint32_t b_did = display_id(b);\n\n    CGPoint a_center = display_center(a_did);\n    CGPoint b_center = display_center(b_did);\n\n    float a_coord = axis == DISPLAY_ARRANGEMENT_ORDER_Y ? a_center.y : a_center.x;\n    float b_coord = axis == DISPLAY_ARRANGEMENT_ORDER_Y ? b_center.y : b_center.x;\n\n    if (a_coord < b_coord) return kCFCompareLessThan;\n    if (a_coord > b_coord) return kCFCompareGreaterThan;\n\n    a_coord = axis == DISPLAY_ARRANGEMENT_ORDER_Y ? a_center.x : a_center.y;\n    b_coord = axis == DISPLAY_ARRANGEMENT_ORDER_Y ? b_center.x : b_center.y;\n\n    if (a_coord < b_coord) return kCFCompareLessThan;\n    if (a_coord > b_coord) return kCFCompareGreaterThan;\n\n    return kCFCompareEqualTo;\n}\n\nint display_manager_display_id_arrangement(uint32_t did)\n{\n    int result = 0;\n\n    CFStringRef uuid = display_uuid(did);\n    if (!uuid) goto out;\n\n    CFArrayRef displays = SLSCopyManagedDisplays(g_connection);\n    if (!displays) goto err;\n\n    int count = CFArrayGetCount(displays);\n    if (!count) goto empty;\n\n    if (g_display_manager.order != DISPLAY_ARRANGEMENT_ORDER_DEFAULT) {\n        CFMutableArrayRef mut_displays = CFArrayCreateMutableCopy(NULL, count, displays);\n        CFArraySortValues(mut_displays, CFRangeMake(0, count), &display_manager_coordinate_comparator, (void *)(uintptr_t) g_display_manager.order);\n        CFRelease(displays); displays = mut_displays;\n    }\n\n    for (int i = 0; i < count; ++i) {\n        if (CFEqual(CFArrayGetValueAtIndex(displays, i), uuid)) {\n            result = i + 1;\n            break;\n        }\n    }\n\nempty:\n    CFRelease(displays);\nerr:\n    CFRelease(uuid);\nout:\n    return result;\n}\n\nCFStringRef display_manager_arrangement_display_uuid(int arrangement)\n{\n    CFStringRef result = NULL;\n    CFArrayRef displays = SLSCopyManagedDisplays(g_connection);\n\n    int count = CFArrayGetCount(displays);\n    int index = arrangement - 1;\n\n    if (in_range_ie(index, 0, count)) {\n        if (g_display_manager.order != DISPLAY_ARRANGEMENT_ORDER_DEFAULT) {\n            CFMutableArrayRef mut_displays = CFArrayCreateMutableCopy(NULL, count, displays);\n            CFArraySortValues(mut_displays, CFRangeMake(0, count), &display_manager_coordinate_comparator, (void *)(uintptr_t) g_display_manager.order);\n            CFRelease(displays); displays = mut_displays;\n        }\n\n        result = CFRetain(CFArrayGetValueAtIndex(displays, index));\n    }\n\n    CFRelease(displays);\n    return result;\n}\n\nuint32_t display_manager_arrangement_display_id(int arrangement)\n{\n    CFStringRef uuid = display_manager_arrangement_display_uuid(arrangement);\n    if (!uuid) return 0;\n\n    uint32_t result = display_id(uuid);\n    CFRelease(uuid);\n\n    return result;\n}\n\nuint32_t display_manager_cursor_display_id(void)\n{\n    CGPoint cursor;\n    SLSGetCurrentCursorLocation(g_connection, &cursor);\n    return display_manager_point_display_id(cursor);\n}\n\nuint32_t display_manager_prev_display_id(uint32_t did)\n{\n    int arrangement = display_manager_display_id_arrangement(did);\n    if (arrangement <= 1) return 0;\n\n    return display_manager_arrangement_display_id(arrangement - 1);\n}\n\nuint32_t display_manager_next_display_id(uint32_t did)\n{\n    int arrangement = display_manager_display_id_arrangement(did);\n    if (arrangement >= display_manager_active_display_count()) return 0;\n\n    return display_manager_arrangement_display_id(arrangement + 1);\n}\n\nuint32_t display_manager_first_display_id(void)\n{\n    return display_manager_arrangement_display_id(1);\n}\n\nuint32_t display_manager_last_display_id(void)\n{\n    int arrangement = display_manager_active_display_count();\n    return display_manager_arrangement_display_id(arrangement);\n}\n\nuint32_t display_manager_find_closest_display_in_direction(uint32_t source_did, int direction)\n{\n    int display_count;\n    uint32_t *display_list = display_manager_active_display_list(&display_count);\n    if (!display_list) return 0;\n\n    uint32_t best_did = 0;\n    int best_distance = INT_MAX;\n\n    struct area source_area = area_from_cgrect(CGDisplayBounds(source_did));\n    CGPoint source_area_max = area_max_point(source_area);\n\n    for (int i = 0; i < display_count; ++i) {\n        uint32_t did = display_list[i];\n        if (did == source_did) continue;\n\n        struct area target_area = area_from_cgrect(CGDisplayBounds(did));\n        CGPoint target_area_max = area_max_point(target_area);\n\n        if (area_is_in_direction(&source_area, source_area_max, &target_area, target_area_max, direction)) {\n            int distance = area_distance_in_direction(&source_area, source_area_max, &target_area, target_area_max, direction);\n            if (distance < best_distance) {\n                best_did = did;\n                best_distance = distance;\n            }\n        }\n    }\n\n    return best_did;\n}\n\nbool display_manager_menu_bar_hidden(void)\n{\n    int status = 0;\n    SLSGetMenuBarAutohideEnabled(g_connection, &status);\n    return status;\n}\n\nCGRect display_manager_menu_bar_rect(uint32_t did)\n{\n    CGRect bounds = {0};\n\n#ifdef __x86_64__\n    SLSGetRevealedMenuBarBounds(&bounds, g_connection, display_space_id(did));\n#elif __arm64__\n\n    //\n    // NOTE(asmvik): SLSGetRevealedMenuBarBounds is broken on Apple Silicon,\n    // but we expected it to return the full display bounds along with the menubar\n    // height. Combine this information ourselves using two separate functions..\n    //\n\n    uint32_t height = 0;\n    SLSGetDisplayMenubarHeight(did, &height);\n\n    bounds = CGDisplayBounds(did);\n    bounds.size.height = height;\n#endif\n\n    //\n    // NOTE(asmvik): Height needs to be offset by 1 because that is the actual\n    // position on the screen that windows can be positioned at..\n    //\n\n    bounds.size.height += 1;\n    return bounds;\n}\n\nbool display_manager_dock_hidden(void)\n{\n    return CoreDockGetAutoHideEnabled();\n}\n\nint display_manager_dock_orientation(void)\n{\n    int pinning = 0;\n    int orientation = 0;\n    CoreDockGetOrientationAndPinning(&orientation, &pinning);\n    return orientation;\n}\n\nCGRect display_manager_dock_rect(void)\n{\n    int reason = 0;\n    CGRect bounds = {0};\n    SLSGetDockRectWithReason(g_connection, &bounds, &reason);\n    return bounds;\n}\n\nbool display_manager_active_display_is_animating(void)\n{\n    CFStringRef uuid = display_manager_active_display_uuid();\n    assert(uuid);\n\n    bool result = SLSManagedDisplayIsAnimating(g_connection, uuid);\n    CFRelease(uuid);\n\n    return result;\n}\n\nbool display_manager_display_is_animating(uint32_t did)\n{\n    CFStringRef uuid = display_uuid(did);\n    if (!uuid) return false;\n\n    bool result = SLSManagedDisplayIsAnimating(g_connection, uuid);\n    CFRelease(uuid);\n\n    return result;\n}\n\nint display_manager_active_display_count(void)\n{\n    uint32_t count;\n    CGGetActiveDisplayList(0, NULL, &count);\n    return (int)count;\n}\n\nuint32_t *display_manager_active_display_list(int *count)\n{\n    int display_count = display_manager_active_display_count();\n    uint32_t *result = ts_alloc_list(uint32_t, display_count);\n    CGGetActiveDisplayList(display_count, result, (uint32_t*)count);\n    return result;\n}\n\nstatic AXUIElementRef display_manager_find_element_at_point(CGPoint point)\n{\n    CFTypeRef role;\n    CFTypeRef window_ref;\n    AXUIElementRef element_ref;\n\n    AXUIElementCopyElementAtPosition(g_window_manager.system_element, point.x, point.y, &element_ref);\n    if (!element_ref) return NULL;\n\n    AXUIElementCopyAttributeValue(element_ref, kAXRoleAttribute, &role);\n    if (CFEqual(role, kAXWindowRole)) {\n        window_ref = element_ref;\n    } else {\n        AXUIElementCopyAttributeValue(element_ref, kAXWindowAttribute, &window_ref);\n        CFRelease(element_ref);\n    }\n\n    CFRelease(role);\n    return window_ref;\n}\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wdeprecated-declarations\"\nuint32_t display_manager_focus_display_with_window_at_point(CGPoint point)\n{\n    int element_connection;\n    ProcessSerialNumber element_psn;\n\n    AXUIElementRef element_ref = display_manager_find_element_at_point(point);\n    if (!element_ref) goto out;\n\n    uint32_t element_id = ax_window_id(element_ref);\n    if (!element_id) goto err_ref;\n\n    SLSGetWindowOwner(g_connection, element_id, &element_connection);\n    SLSGetConnectionPSN(element_connection, &element_psn);\n    window_manager_focus_window_with_raise(&element_psn, element_id, element_ref);\n    CFRelease(element_ref);\n    return element_id;\n\nerr_ref:\n    CFRelease(element_ref);\nout:\n    return 0;\n}\n#pragma clang diagnostic pop\n\nvoid display_manager_set_active_display_id(uint32_t did)\n{\n    CFStringRef uuid = display_uuid(did);\n    SLSSetActiveMenuBarDisplayIdentifier(g_connection, uuid, uuid);\n    CFRelease(uuid);\n}\n\nvoid display_manager_focus_display(uint32_t did, uint64_t sid)\n{\n    struct window *window = window_manager_find_window_on_space_by_rank_filtering_window(&g_window_manager, sid, 1, 0);\n    if (window) {\n        window_manager_focus_window_with_raise(&window->application->psn, window->id, window->ref);\n        window_manager_center_mouse(&g_window_manager, window);\n        display_manager_set_active_display_id(did);\n    } else {\n        CGWarpMouseCursorPosition(display_center(did));\n        display_manager_set_active_display_id(did);\n    }\n}\n\nenum space_op_error display_manager_focus_space(uint32_t did, uint64_t sid)\n{\n    bool is_in_mc = mission_control_is_active();\n    if (is_in_mc) return SPACE_OP_ERROR_IN_MISSION_CONTROL;\n\n    bool is_animating = display_manager_display_is_animating(did);\n    if (is_animating) return SPACE_OP_ERROR_DISPLAY_IS_ANIMATING;\n\n    uint32_t space_did = space_display_id(sid);\n    if (space_did != did) return SPACE_OP_ERROR_SAME_DISPLAY;\n\n    return scripting_addition_focus_space(sid) ? SPACE_OP_ERROR_SUCCESS : SPACE_OP_ERROR_SCRIPTING_ADDITION;\n}\n\nbool display_manager_begin(struct display_manager *dm)\n{\n    dm->current_display_id = display_manager_active_display_id();\n    dm->last_display_id = dm->current_display_id;\n    dm->order = DISPLAY_ARRANGEMENT_ORDER_DEFAULT;\n    dm->mode = EXTERNAL_BAR_OFF;\n    dm->top_padding = 0;\n    dm->bottom_padding = 0;\n    return CGDisplayRegisterReconfigurationCallback(display_handler, NULL) == kCGErrorSuccess;\n}\n"
  },
  {
    "path": "src/display_manager.h",
    "content": "#ifndef DISPLAY_MANAGER_H\n#define DISPLAY_MANAGER_H\n\n#define DOCK_ORIENTATION_BOTTOM 2\n#define DOCK_ORIENTATION_LEFT   3\n#define DOCK_ORIENTATION_RIGHT  4\n\nenum display_arrangement_order\n{\n    DISPLAY_ARRANGEMENT_ORDER_DEFAULT,\n    DISPLAY_ARRANGEMENT_ORDER_X,\n    DISPLAY_ARRANGEMENT_ORDER_Y\n};\n\nstatic const char *display_arrangement_order_str[] =\n{\n    \"default\",\n    \"horizontal\",\n    \"vertical\"\n};\n\nenum external_bar_mode\n{\n    EXTERNAL_BAR_OFF,\n    EXTERNAL_BAR_MAIN,\n    EXTERNAL_BAR_ALL\n};\n\nstatic const char *external_bar_mode_str[] =\n{\n    \"off\",\n    \"main\",\n    \"all\"\n};\n\nstruct display_label\n{\n    uint32_t did;\n    char *label;\n};\n\nstruct display_manager\n{\n    uint32_t current_display_id;\n    uint32_t last_display_id;\n\n    int top_padding;\n    int bottom_padding;\n\n    enum display_arrangement_order order;\n    enum external_bar_mode mode;\n\n    struct display_label *labels;\n};\n\nstruct display_label *display_manager_get_label_for_display(struct display_manager *dm, uint32_t did);\nstruct display_label *display_manager_get_display_for_label(struct display_manager *dm, char *label);\nbool display_manager_remove_label_for_display(struct display_manager *dm, uint32_t did);\nvoid display_manager_set_label_for_display(struct display_manager *dm, uint32_t did, char *label);\nbool display_manager_query_displays(FILE *rsp, uint64_t flags);\nCFStringRef display_manager_main_display_uuid(void);\nuint32_t display_manager_main_display_id(void);\nCFStringRef display_manager_active_display_uuid(void);\nuint32_t display_manager_active_display_id(void);\nCFStringRef display_manager_dock_display_uuid(void);\nuint32_t display_manager_dock_display_id(void);\nCFStringRef display_manager_point_display_uuid(CGPoint point);\nuint32_t display_manager_point_display_id(CGPoint point);\nuint32_t display_manager_cursor_display_id(void);\nint display_manager_display_id_arrangement(uint32_t did);\nCFStringRef display_manager_arrangement_display_uuid(int arrangement);\nuint32_t display_manager_arrangement_display_id(int arrangement);\nuint32_t display_manager_prev_display_id(uint32_t did);\nuint32_t display_manager_next_display_id(uint32_t did);\nuint32_t display_manager_first_display_id(void);\nuint32_t display_manager_last_display_id(void);\nuint32_t display_manager_find_closest_display_in_direction(uint32_t acting_did, int direction);\nbool display_manager_menu_bar_hidden(void);\nCGRect display_manager_menu_bar_rect(uint32_t did);\nbool display_manager_dock_hidden(void);\nint display_manager_dock_orientation(void);\nCGRect display_manager_dock_rect(void);\nbool display_manager_active_display_is_animating(void);\nbool display_manager_display_is_animating(uint32_t did);\nint display_manager_active_display_count(void);\nuint32_t *display_manager_active_display_list(int *count);\nuint32_t display_manager_focus_display_with_window_at_point(CGPoint point);\nvoid display_manager_set_active_display_id(uint32_t did);\nvoid display_manager_focus_display(uint32_t did, uint64_t sid);\nenum space_op_error display_manager_focus_space(uint32_t did, uint64_t sid);\nbool display_manager_begin(struct display_manager *dm);\n\n#endif\n"
  },
  {
    "path": "src/event_loop.c",
    "content": "extern struct event_loop g_event_loop;\nextern struct process_manager g_process_manager;\nextern struct display_manager g_display_manager;\nextern struct space_manager g_space_manager;\nextern struct window_manager g_window_manager;\nextern struct mouse_state g_mouse_state;\nextern enum mission_control_mode g_mission_control_mode;\nextern int g_connection;\nextern void *g_workspace_context;\nextern int g_layer_below_window_level;\n\nstatic void update_window_notifications(void)\n{\n    int window_count = 0;\n    uint32_t window_list[1024] = {0};\n\n    if (workspace_is_macos_sequoia() || workspace_is_macos_tahoe()) {\n        // NOTE(asmvik): Subscribe to all windows because of window_destroyed (and ordered) notifications\n        table_for (struct window *window, g_window_manager.window, {\n            window_list[window_count++] = window->id;\n        })\n    } else {\n        // NOTE(asmvik): Subscribe to windows that have a feedback_border because of window_ordered notifications\n        table_for (struct window_node *node, g_window_manager.insert_feedback, {\n            window_list[window_count++] = node->window_order[0];\n        })\n    }\n\n    SLSRequestNotificationsForWindows(g_connection, window_list, window_count);\n}\n\nstatic void window_did_receive_focus(struct window_manager *wm, struct mouse_state *ms, struct window *window)\n{\n    struct window *focused_window = window_manager_find_window(wm, wm->focused_window_id);\n    if (focused_window && focused_window != window && window_space(focused_window->id) == window_space(window->id)) {\n        window_manager_set_window_opacity(wm, focused_window, g_window_manager.normal_window_opacity);\n    }\n\n    window_manager_set_window_opacity(wm, window, wm->active_window_opacity);\n\n    if (wm->focused_window_id != window->id) {\n        if (ms->ffm_window_id != window->id) {\n            window_manager_center_mouse(wm, window);\n        }\n\n        wm->last_window_id = wm->focused_window_id;\n    }\n\n    wm->focused_window_id = window->id;\n    wm->focused_window_psn = window->application->psn;\n    ms->ffm_window_id = 0;\n\n    struct view *view = window_manager_find_managed_window(&g_window_manager, window);\n    if (!view) return;\n\n    struct window_node *node = view_find_window_node(view, window->id);\n    if (node->window_count <= 1) return;\n\n    for (int i = 0; i < node->window_count; ++i) {\n        if (node->window_order[i] != window->id) continue;\n\n        memmove(node->window_order + 1, node->window_order, sizeof(uint32_t) * i);\n        node->window_order[0] = window->id;\n\n        break;\n    }\n}\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wunused-parameter\"\nstatic EVENT_HANDLER(APPLICATION_LAUNCHED)\n{\n    struct process *process = context;\n\n    if (__atomic_load_n(&process->terminated, __ATOMIC_RELAXED)) {\n        debug(\"%s: %s (%d) terminated during launch\\n\", __FUNCTION__, process->name, process->pid);\n        window_manager_remove_lost_front_switched_event(&g_window_manager, process->pid);\n        return;\n    }\n\n    if (!__atomic_load_n(&process->ns_application, __ATOMIC_RELAXED)) {\n        debug(\"%s: %s (%d) missing ns_application. fetching..\\n\", __FUNCTION__, process->name, process->pid);\n        __atomic_store_n(&process->ns_application, workspace_application_create_running_ns_application(process), __ATOMIC_RELEASE);\n\n        if (!__atomic_load_n(&process->ns_application, __ATOMIC_RELAXED)) {\n            debug(\"%s: %s (%d) unable to fetch ns_application..\\n\", __FUNCTION__, process->name, process->pid);\n\n            __block ProcessSerialNumber psn = process->psn;\n            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.1f * NSEC_PER_SEC), dispatch_get_main_queue(), ^{\n                struct process *_process = process_manager_find_process(&g_process_manager, &psn);\n                if (_process) event_loop_post(&g_event_loop, APPLICATION_LAUNCHED, _process, 0);\n            });\n\n            return;\n        }\n    }\n\n    if (!workspace_application_is_finished_launching(process)) {\n        debug(\"%s: %s (%d) is not finished launching, subscribing to finishedLaunching changes\\n\", __FUNCTION__, process->name, process->pid);\n        workspace_application_observe_finished_launching(g_workspace_context, process);\n\n        //\n        // NOTE(asmvik): Do this again in case of race-conditions between the previous check and key-value observation subscription.\n        // Not actually sure if this can happen in practice..\n        //\n\n        if (workspace_application_is_finished_launching(process)) {\n            @try {\n                NSRunningApplication *application = __atomic_load_n(&process->ns_application, __ATOMIC_RELAXED);\n                if (application && [application observationInfo]) {\n                    [application removeObserver:g_workspace_context forKeyPath:@\"finishedLaunching\" context:process];\n                }\n            } @catch (NSException * __unused exception) {}\n        } else { return; }\n    }\n\n    if (!workspace_application_is_observable(process)) {\n        debug(\"%s: %s (%d) is not observable, subscribing to activationPolicy changes\\n\", __FUNCTION__, process->name, process->pid);\n        workspace_application_observe_activation_policy(g_workspace_context, process);\n\n        //\n        // NOTE(asmvik): Do this again in case of race-conditions between the previous check and key-value observation subscription.\n        // Not actually sure if this can happen in practice..\n        //\n\n        if (workspace_application_is_observable(process)) {\n            @try {\n                NSRunningApplication *application = __atomic_load_n(&process->ns_application, __ATOMIC_RELAXED);\n                if (application && [application observationInfo]) {\n                    [application removeObserver:g_workspace_context forKeyPath:@\"activationPolicy\" context:process];\n                }\n            } @catch (NSException * __unused exception) {}\n        } else { return; }\n    }\n\n    //\n    // NOTE(asmvik): If we somehow receive a duplicate launched event due to the subscription-timing-mess above,\n    // simply ignore the event..\n    //\n\n    struct application *application = window_manager_find_application(&g_window_manager, process->pid);\n    if (application) { return; } else { application = application_create(process); }\n\n    if (!application_observe(application)) {\n        bool ax_retry = application->ax_retry;\n\n        application_unobserve(application);\n        application_destroy(application);\n        debug(\"%s: could not observe notifications for %s (%d) (%d)\\n\", __FUNCTION__, process->name, process->pid, ax_retry);\n\n        if (ax_retry) {\n            __block ProcessSerialNumber psn = process->psn;\n            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.1f * NSEC_PER_SEC), dispatch_get_main_queue(), ^{\n                struct process *_process = process_manager_find_process(&g_process_manager, &psn);\n                if (_process) event_loop_post(&g_event_loop, APPLICATION_LAUNCHED, _process, 0);\n            });\n        }\n\n        return;\n    }\n\n    if (window_manager_find_lost_front_switched_event(&g_window_manager, process->pid)) {\n        event_loop_post(&g_event_loop, APPLICATION_FRONT_SWITCHED, process, 0);\n        window_manager_remove_lost_front_switched_event(&g_window_manager, process->pid);\n    }\n\n    debug(\"%s: %s (%d)\\n\", __FUNCTION__, process->name, process->pid);\n    window_manager_add_application(&g_window_manager, application);\n    event_signal_push(SIGNAL_APPLICATION_LAUNCHED, application);\n\n    int window_count;\n    struct window **window_list = window_manager_add_application_windows(&g_space_manager, &g_window_manager, application, &window_count);\n    uint32_t prev_window_id = g_window_manager.focused_window_id;\n\n    uint64_t sid;\n    bool default_origin = g_window_manager.window_origin_mode == WINDOW_ORIGIN_DEFAULT;\n\n    if (!default_origin) {\n        if (g_window_manager.window_origin_mode == WINDOW_ORIGIN_FOCUSED) {\n            sid = g_space_manager.current_space_id;\n        } else /* if (g_window_manager.window_origin_mode == WINDOW_ORIGIN_CURSOR) */ {\n            sid = space_manager_cursor_space();\n        }\n    }\n\n    int view_count = 0;\n    struct view **view_list = ts_alloc_list(struct view *, window_count);\n\n    for (int i = 0; i < window_count; ++i) {\n        struct window *window = window_list[i];\n\n        if (window_manager_should_manage_window(window) && !window_manager_find_managed_window(&g_window_manager, window)) {\n            if (default_origin) sid = window_space(window->id);\n\n            struct view *view = space_manager_find_view(&g_space_manager, sid);\n            if (view->layout != VIEW_FLOAT) {\n                //\n                // @cleanup\n                //\n                // :AXBatching\n                //\n                // NOTE(asmvik): Batch all operations and mark the view as dirty so that we can perform a single flush,\n                // making sure that each window is only moved and resized a single time, when the final layout has been computed.\n                // This is necessary to make sure that we do not call the AX API for each modification to the tree.\n                //\n\n                window_manager_adjust_layer(window, LAYER_BELOW);\n                view_add_window_node_with_insertion_point(view, window, prev_window_id);\n                window_manager_add_managed_window(&g_window_manager, window, view);\n\n                view_set_flag(view, VIEW_IS_DIRTY);\n                view_list[view_count++] = view;\n\n                prev_window_id = window->id;\n            }\n        }\n\n        if (window_manager_is_window_eligible(window)) {\n            event_signal_push(SIGNAL_WINDOW_CREATED, window);\n        }\n    }\n\n    //\n    // @cleanup\n    //\n    // :AXBatching\n    //\n    // NOTE(asmvik): Flush previously batched operations if the view is marked as dirty.\n    // This is necessary to make sure that we do not call the AX API for each modification to the tree.\n    //\n\n    for (int i = 0; i < view_count; ++i) {\n        struct view *view = view_list[i];\n        if (!space_is_visible(view->sid)) continue;\n        if (!view_is_dirty(view))         continue;\n\n        window_node_flush(view->root);\n        view_clear_flag(view, VIEW_IS_DIRTY);\n    }\n\n    if (workspace_is_macos_sequoia() || workspace_is_macos_tahoe()) {\n        update_window_notifications();\n    }\n}\n\nstatic EVENT_HANDLER(APPLICATION_TERMINATED)\n{\n    struct process *process = context;\n    struct application *application = window_manager_find_application(&g_window_manager, process->pid);\n\n    if (!application) {\n        debug(\"%s: %s (%d) (not observed)\\n\", __FUNCTION__, process->name, process->pid);\n        goto out;\n    }\n\n    debug(\"%s: %s (%d)\\n\", __FUNCTION__, process->name, process->pid);\n    event_signal_push(SIGNAL_APPLICATION_TERMINATED, application);\n    window_manager_remove_application(&g_window_manager, application->pid);\n\n    for (int i = 0; i < buf_len(g_window_manager.applications_to_refresh); ++i) {\n        if (application == g_window_manager.applications_to_refresh[i]) {\n            buf_del(g_window_manager.applications_to_refresh, i);\n            break;\n        }\n    }\n\n    int window_count;\n    struct window **window_list = window_manager_find_application_windows(&g_window_manager, application, &window_count);\n\n    int view_count = 0;\n    struct view **view_list = ts_alloc_list(struct view *, window_count);\n\n    for (int i = 0; i < window_count; ++i) {\n        struct window *window = window_list[i];\n\n        if (!__sync_bool_compare_and_swap(&window->id_ptr, &window->id, NULL)) {\n            window->application = NULL;\n            continue;\n        }\n\n        struct view *view = window_manager_find_managed_window(&g_window_manager, window);\n        if (view) {\n\n            //\n            // @cleanup\n            //\n            // :AXBatching\n            //\n            // NOTE(asmvik): Batch all operations and mark the view as dirty so that we can perform a single flush,\n            // making sure that each window is only moved and resized a single time, when the final layout has been computed.\n            // This is necessary to make sure that we do not call the AX API for each modification to the tree.\n            //\n\n            view_remove_window_node(view, window);\n            window_manager_remove_managed_window(&g_window_manager, window->id);\n\n            view_set_flag(view, VIEW_IS_DIRTY);\n            view_list[view_count++] = view;\n        }\n\n        if (g_mouse_state.window == window) g_mouse_state.window = NULL;\n\n        if (window->is_eligible) {\n            event_signal_push(SIGNAL_WINDOW_DESTROYED, window);\n        }\n\n        window_manager_remove_scratchpad_for_window(&g_window_manager, window, false);\n        window_manager_remove_window(&g_window_manager, window->id);\n        window_unobserve(window);\n        window_destroy(window);\n    }\n\n    application_unobserve(application);\n    application_destroy(application);\n\n    //\n    // @cleanup\n    //\n    // :AXBatching\n    //\n    // NOTE(asmvik): Flush previously batched operations if the view is marked as dirty.\n    // This is necessary to make sure that we do not call the AX API for each modification to the tree.\n    //\n\n    for (int i = 0; i < view_count; ++i) {\n        struct view *view = view_list[i];\n        if (!space_is_visible(view->sid)) continue;\n        if (!view_is_dirty(view))         continue;\n\n        window_node_flush(view->root);\n        view_clear_flag(view, VIEW_IS_DIRTY);\n    }\n\n    if (workspace_is_macos_sequoia() || workspace_is_macos_tahoe()) {\n        update_window_notifications();\n    }\n\nout:\n    process_destroy(process);\n}\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wdeprecated-declarations\"\nstatic EVENT_HANDLER(APPLICATION_FRONT_SWITCHED)\n{\n    struct process *process = context;\n    struct application *application = window_manager_find_application(&g_window_manager, process->pid);\n\n    if (!application) {\n        window_manager_add_lost_front_switched_event(&g_window_manager, process->pid);\n        return;\n    }\n\n    struct application *deactivated_application = window_manager_find_application(&g_window_manager, g_process_manager.front_pid);\n    if (deactivated_application) event_signal_push(SIGNAL_APPLICATION_DEACTIVATED, deactivated_application);\n\n    debug(\"%s: %s (%d)\\n\", __FUNCTION__, process->name, process->pid);\n    event_signal_push(SIGNAL_APPLICATION_ACTIVATED, application);\n    g_process_manager.switch_event_time = GetCurrentEventTime();\n    g_process_manager.last_front_pid = g_process_manager.front_pid;\n    g_process_manager.front_pid = process->pid;\n    event_signal_push(SIGNAL_APPLICATION_FRONT_SWITCHED, NULL);\n\n    for (int i = 0; i < buf_len(g_window_manager.applications_to_refresh); ++i) {\n        if (application == g_window_manager.applications_to_refresh[i]) {\n            debug(\"%s: %s has windows that are not yet resolved\\n\", __FUNCTION__, application->name);\n            window_manager_add_existing_application_windows(&g_space_manager, &g_window_manager, application, i);\n            break;\n        }\n    }\n\n    uint32_t application_focused_window_id = application_focused_window(application);\n    if (!application_focused_window_id) {\n        struct window *focused_window = window_manager_find_window(&g_window_manager, g_window_manager.focused_window_id);\n        if (focused_window) {\n            window_manager_set_window_opacity(&g_window_manager, focused_window, g_window_manager.normal_window_opacity);\n        }\n\n        g_window_manager.last_window_id = g_window_manager.focused_window_id;\n        g_window_manager.focused_window_id = 0;\n        g_window_manager.focused_window_psn = application->psn;\n        g_mouse_state.ffm_window_id = 0;\n        return;\n    }\n\n    struct window *window = window_manager_find_window(&g_window_manager, application_focused_window_id);\n    if (!window) {\n        struct window *focused_window = window_manager_find_window(&g_window_manager, g_window_manager.focused_window_id);\n        if (focused_window) {\n            window_manager_set_window_opacity(&g_window_manager, focused_window, g_window_manager.normal_window_opacity);\n        }\n\n        window_manager_add_lost_focused_event(&g_window_manager, application_focused_window_id);\n        return;\n    }\n\n    window_did_receive_focus(&g_window_manager, &g_mouse_state, window);\n    event_signal_push(SIGNAL_WINDOW_FOCUSED, window);\n}\n#pragma clang diagnostic pop\n\nstatic EVENT_HANDLER(APPLICATION_VISIBLE)\n{\n    struct application *application = window_manager_find_application(&g_window_manager, (pid_t)(intptr_t) context);\n    if (!application) return;\n\n    debug(\"%s: %s\\n\", __FUNCTION__, application->name);\n    application->is_hidden = false;\n\n    int window_count;\n    struct window **window_list = window_manager_find_application_windows(&g_window_manager, application, &window_count);\n    uint32_t prev_window_id = g_window_manager.last_window_id;\n\n    int view_count = 0;\n    struct view **view_list = ts_alloc_list(struct view *, window_count);\n\n    for (int i = 0; i < window_count; ++i) {\n        struct window *window = window_list[i];\n\n        if (window_manager_should_manage_window(window) && !window_manager_find_managed_window(&g_window_manager, window)) {\n            struct view *view = space_manager_find_view(&g_space_manager, window_space(window->id));\n            if (view->layout == VIEW_FLOAT) continue;\n\n            //\n            // @cleanup\n            //\n            // :AXBatching\n            //\n            // NOTE(asmvik): Batch all operations and mark the view as dirty so that we can perform a single flush,\n            // making sure that each window is only moved and resized a single time, when the final layout has been computed.\n            // This is necessary to make sure that we do not call the AX API for each modification to the tree.\n            //\n\n            window_manager_adjust_layer(window, LAYER_BELOW);\n            view_add_window_node_with_insertion_point(view, window, prev_window_id);\n            window_manager_add_managed_window(&g_window_manager, window, view);\n\n            view_set_flag(view, VIEW_IS_DIRTY);\n            view_list[view_count++] = view;\n\n            prev_window_id = window->id;\n        }\n    }\n\n    //\n    // @cleanup\n    //\n    // :AXBatching\n    //\n    // NOTE(asmvik): Flush previously batched operations if the view is marked as dirty.\n    // This is necessary to make sure that we do not call the AX API for each modification to the tree.\n    //\n\n    for (int i = 0; i < view_count; ++i) {\n        struct view *view = view_list[i];\n        if (!space_is_visible(view->sid)) continue;\n        if (!view_is_dirty(view))         continue;\n\n        window_node_flush(view->root);\n        view_clear_flag(view, VIEW_IS_DIRTY);\n    }\n\n    event_signal_push(SIGNAL_APPLICATION_VISIBLE, application);\n}\n\nstatic EVENT_HANDLER(APPLICATION_HIDDEN)\n{\n    struct application *application = window_manager_find_application(&g_window_manager, (pid_t)(intptr_t) context);\n    if (!application) return;\n\n    debug(\"%s: %s\\n\", __FUNCTION__, application->name);\n    application->is_hidden = true;\n\n    int window_count;\n    struct window **window_list = window_manager_find_application_windows(&g_window_manager, application, &window_count);\n\n    int view_count = 0;\n    struct view **view_list = ts_alloc_list(struct view *, window_count);\n\n    for (int i = 0; i < window_count; ++i) {\n        struct window *window = window_list[i];\n\n        struct view *view = window_manager_find_managed_window(&g_window_manager, window);\n        if (view) {\n\n            //\n            // @cleanup\n            //\n            // :AXBatching\n            //\n            // NOTE(asmvik): Batch all operations and mark the view as dirty so that we can perform a single flush,\n            // making sure that each window is only moved and resized a single time, when the final layout has been computed.\n            // This is necessary to make sure that we do not call the AX API for each modification to the tree.\n            //\n\n            window_manager_adjust_layer(window, LAYER_NORMAL);\n            view_remove_window_node(view, window);\n            window_manager_remove_managed_window(&g_window_manager, window->id);\n            window_manager_purify_window(&g_window_manager, window);\n\n            view_set_flag(view, VIEW_IS_DIRTY);\n            view_list[view_count++] = view;\n        }\n    }\n\n    //\n    // @cleanup\n    //\n    // :AXBatching\n    //\n    // NOTE(asmvik): Flush previously batched operations if the view is marked as dirty.\n    // This is necessary to make sure that we do not call the AX API for each modification to the tree.\n    //\n\n    for (int i = 0; i < view_count; ++i) {\n        struct view *view = view_list[i];\n        if (!space_is_visible(view->sid)) continue;\n        if (!view_is_dirty(view))         continue;\n\n        window_node_flush(view->root);\n        view_clear_flag(view, VIEW_IS_DIRTY);\n    }\n\n    event_signal_push(SIGNAL_APPLICATION_HIDDEN, application);\n}\n\nstatic EVENT_HANDLER(WINDOW_CREATED)\n{\n    uint32_t window_id = ax_window_id(context);\n    if (!window_id) { CFRelease(context); return; }\n\n    struct window *existing_window = window_manager_find_window(&g_window_manager, window_id);\n    if (existing_window) { CFRelease(context); return; }\n\n    pid_t window_pid = ax_window_pid(context);\n    if (!window_pid) { CFRelease(context); return; }\n\n    struct application *application = window_manager_find_application(&g_window_manager, window_pid);\n    if (!application) { CFRelease(context); return; }\n\n    struct window *window = window_manager_create_and_add_window(&g_space_manager, &g_window_manager, application, context, window_id, true);\n    if (!window) return;\n\n    int rule_len = buf_len(g_window_manager.rules);\n    for (int i = 0; i < rule_len; ++i) {\n        if (rule_check_flag(&g_window_manager.rules[i], RULE_ONE_SHOT_REMOVE)) {\n            rule_destroy(&g_window_manager.rules[i]);\n            if (buf_del(g_window_manager.rules, i)) {\n                --i;\n                --rule_len;\n            }\n        }\n    }\n\n    if (window_manager_should_manage_window(window) && !window_manager_find_managed_window(&g_window_manager, window)) {\n        uint64_t sid;\n\n        if (g_window_manager.window_origin_mode == WINDOW_ORIGIN_DEFAULT) {\n            sid = window_space(window->id);\n        } else if (g_window_manager.window_origin_mode == WINDOW_ORIGIN_FOCUSED) {\n            sid = g_space_manager.current_space_id;\n        } else /* if (g_window_manager.window_origin_mode == WINDOW_ORIGIN_CURSOR) */ {\n            sid = space_manager_cursor_space();\n        }\n\n        struct view *view = space_manager_tile_window_on_space(&g_space_manager, window, sid);\n        window_manager_add_managed_window(&g_window_manager, window, view);\n    }\n\n    if (window_manager_is_window_eligible(window)) {\n        event_signal_push(SIGNAL_WINDOW_CREATED, window);\n    }\n\n    if (workspace_is_macos_sequoia() || workspace_is_macos_tahoe()) {\n        update_window_notifications();\n    }\n}\n\nstatic EVENT_HANDLER(WINDOW_DESTROYED)\n{\n    struct window *window = context;\n    if (!window || window->id == 0) {\n        debug(\"%s: window has already been destroyed, ignoring event..\\n\", __FUNCTION__);\n        return;\n    }\n\n    debug(\"%s: %s %d\\n\", __FUNCTION__, window->application ? window->application->name : \"<unknown>\", window->id);\n\n    struct view *view = window_manager_find_managed_window(&g_window_manager, window);\n    if (view) {\n        space_manager_untile_window(view, window);\n        window_manager_remove_managed_window(&g_window_manager, window->id);\n    }\n\n    if (g_mouse_state.window == window) g_mouse_state.window = NULL;\n\n    if (window->is_eligible) {\n        event_signal_push(SIGNAL_WINDOW_DESTROYED, window);\n    }\n\n    window_manager_remove_scratchpad_for_window(&g_window_manager, window, false);\n    window_manager_remove_window(&g_window_manager, window->id);\n    window_unobserve(window);\n    window_destroy(window);\n\n    if (workspace_is_macos_sequoia() || workspace_is_macos_tahoe()) {\n        update_window_notifications();\n    }\n}\n\nstatic EVENT_HANDLER(WINDOW_FOCUSED)\n{\n    uint32_t window_id = (uint32_t)(intptr_t) context;\n    struct window *window = window_manager_find_window(&g_window_manager, window_id);\n\n    if (!window) {\n        window_manager_add_lost_focused_event(&g_window_manager, window_id);\n        return;\n    }\n\n    if (!__sync_bool_compare_and_swap(&window->id_ptr, &window->id, &window->id)) {\n        debug(\"%s: %d has been marked invalid by the system, ignoring event..\\n\", __FUNCTION__, window_id);\n        return;\n    }\n\n    if (window_check_flag(window, WINDOW_MINIMIZE)) {\n        window_manager_add_lost_focused_event(&g_window_manager, window->id);\n        return;\n    }\n\n    if (!application_is_frontmost(window->application)) {\n        return;\n    }\n\n    debug(\"%s: %s %d\\n\", __FUNCTION__, window->application->name, window->id);\n    window_did_receive_focus(&g_window_manager, &g_mouse_state, window);\n    event_signal_push(SIGNAL_WINDOW_FOCUSED, window);\n}\n\nstatic EVENT_HANDLER(WINDOW_MOVED)\n{\n    uint32_t window_id = (uint32_t)(intptr_t) context;\n    struct window *window = window_manager_find_window(&g_window_manager, window_id);\n    if (!window) return;\n\n    if (!__sync_bool_compare_and_swap(&window->id_ptr, &window->id, &window->id)) {\n        debug(\"%s: %d has been marked invalid by the system, ignoring event..\\n\", __FUNCTION__, window_id);\n        return;\n    }\n\n    if (window->application->is_hidden) {\n        debug(\"%s: %d was moved while the application is hidden, ignoring event..\\n\", __FUNCTION__, window_id);\n        return;\n    }\n\n    CGPoint new_origin = window_ax_origin(window);\n    if (CGPointEqualToPoint(new_origin, window->frame.origin)) {\n        debug(\"%s:DEBOUNCED %s %d\\n\", __FUNCTION__, window->application->name, window->id);\n        return;\n    }\n\n    debug(\"%s: %s %d\\n\", __FUNCTION__, window->application->name, window->id);\n    event_signal_push(SIGNAL_WINDOW_MOVED, window);\n    bool windowed_fullscreen = CGRectEqualToRect(window->windowed_frame, window->frame);\n    window->frame.origin = new_origin;\n\n    if (!windowed_fullscreen) {\n        window_clear_flag(window, WINDOW_WINDOWED);\n\n        if (!g_mouse_state.window || g_mouse_state.window != window) {\n            struct view *view = window_manager_find_managed_window(&g_window_manager, window);\n            if (view) {\n                struct window_node *node = view_find_window_node(view, window->id);\n                if (node && (AX_DIFF(node->area.x, new_origin.x) ||\n                             AX_DIFF(node->area.y, new_origin.y))\n                         &&\n                   (!node->zoom || AX_DIFF(node->zoom->area.x, new_origin.x) ||\n                                   AX_DIFF(node->zoom->area.y, new_origin.y))) {\n                    if (space_is_visible(view->sid)) {\n                        window_node_flush(node);\n                    } else {\n                        view_set_flag(view, VIEW_IS_DIRTY);\n                    }\n                }\n            }\n        }\n    }\n}\n\nstatic EVENT_HANDLER(WINDOW_RESIZED)\n{\n    uint32_t window_id = (uint32_t)(intptr_t) context;\n    struct window *window = window_manager_find_window(&g_window_manager, window_id);\n    if (!window) return;\n\n    if (!__sync_bool_compare_and_swap(&window->id_ptr, &window->id, &window->id)) {\n        debug(\"%s: %d has been marked invalid by the system, ignoring event..\\n\", __FUNCTION__, window_id);\n        return;\n    }\n\n    if (window->application->is_hidden) {\n        debug(\"%s: %d was resized while the application is hidden, ignoring event..\\n\", __FUNCTION__, window_id);\n        return;\n    }\n\n    CGRect new_frame = window_ax_frame(window);\n    if (CGRectEqualToRect(new_frame, window->frame)) {\n        debug(\"%s:DEBOUNCED %s %d\\n\", __FUNCTION__, window->application->name, window->id);\n        return;\n    }\n\n    debug(\"%s: %s %d\\n\", __FUNCTION__, window->application->name, window->id);\n    event_signal_push(SIGNAL_WINDOW_RESIZED, window);\n\n    bool was_fullscreen = window_check_flag(window, WINDOW_FULLSCREEN);\n\n    bool is_fullscreen = window_is_fullscreen(window);\n    if (is_fullscreen) {\n        window_set_flag(window, WINDOW_FULLSCREEN);\n    } else {\n        window_clear_flag(window, WINDOW_FULLSCREEN);\n    }\n\n    if (was_fullscreen != is_fullscreen) {\n        if (window_ax_can_move(window)) {\n            window_set_flag(window, WINDOW_MOVABLE);\n        } else {\n            window_clear_flag(window, WINDOW_MOVABLE);\n        }\n\n        if (window_ax_can_resize(window)) {\n            window_set_flag(window, WINDOW_RESIZABLE);\n        } else {\n            window_clear_flag(window, WINDOW_RESIZABLE);\n        }\n\n        if (window->role) CFRelease(window->role);\n        window->role = window_ax_role(window);\n\n        if (window->subrole) CFRelease(window->subrole);\n        window->subrole = window_ax_subrole(window);\n    }\n\n    bool windowed_fullscreen = CGRectEqualToRect(window->windowed_frame, window->frame);\n    window->frame = new_frame;\n\n    if (!was_fullscreen && is_fullscreen) {\n        struct view *view = window_manager_find_managed_window(&g_window_manager, window);\n        if (view) {\n            space_manager_untile_window(view, window);\n            window_manager_remove_managed_window(&g_window_manager, window->id);\n            window_manager_purify_window(&g_window_manager, window);\n        }\n    } else if (was_fullscreen && !is_fullscreen) {\n        window_manager_wait_for_native_fullscreen_transition(window);\n\n        if (window_manager_should_manage_window(window) && !window_manager_find_managed_window(&g_window_manager, window)) {\n            struct view *view = space_manager_tile_window_on_space(&g_space_manager, window, window_space(window->id));\n            window_manager_add_managed_window(&g_window_manager, window, view);\n        }\n    } else if (!was_fullscreen == !is_fullscreen) {\n        if (g_mouse_state.current_action == MOUSE_MODE_MOVE && g_mouse_state.window == window) {\n            g_mouse_state.window_frame.size = g_mouse_state.window->frame.size;\n        }\n\n        if (!windowed_fullscreen) {\n            window_clear_flag(window, WINDOW_WINDOWED);\n\n            if (!g_mouse_state.window || g_mouse_state.window != window) {\n                struct view *view = window_manager_find_managed_window(&g_window_manager, window);\n                if (view) {\n                    struct window_node *node = view_find_window_node(view, window->id);\n                    if (node && (AX_DIFF(node->area.x, new_frame.origin.x)   ||\n                                 AX_DIFF(node->area.y, new_frame.origin.y)   ||\n                                 AX_DIFF(node->area.w, new_frame.size.width) ||\n                                 AX_DIFF(node->area.h, new_frame.size.height))\n                             &&\n                       (!node->zoom || AX_DIFF(node->zoom->area.x, new_frame.origin.x)   ||\n                                       AX_DIFF(node->zoom->area.y, new_frame.origin.y)   ||\n                                       AX_DIFF(node->zoom->area.w, new_frame.size.width) ||\n                                       AX_DIFF(node->zoom->area.h, new_frame.size.height))) {\n                        if (space_is_visible(view->sid)) {\n                            window_node_flush(node);\n                        } else {\n                            view_set_flag(view, VIEW_IS_DIRTY);\n                        }\n                    }\n                }\n            }\n        }\n    }\n}\n\nstatic EVENT_HANDLER(WINDOW_MINIMIZED)\n{\n    struct window *window = context;\n\n    if (!__sync_bool_compare_and_swap(&window->id_ptr, &window->id, &window->id)) {\n        debug(\"%s: %d has been marked invalid by the system, ignoring event..\\n\", __FUNCTION__, window->id);\n        return;\n    }\n\n    debug(\"%s: %s %d\\n\", __FUNCTION__, window->application->name, window->id);\n    window_set_flag(window, WINDOW_MINIMIZE);\n\n    if (window_ax_can_move(window)) {\n        window_set_flag(window, WINDOW_MOVABLE);\n    } else {\n        window_clear_flag(window, WINDOW_MOVABLE);\n    }\n\n    if (window_ax_can_resize(window)) {\n        window_set_flag(window, WINDOW_RESIZABLE);\n    } else {\n        window_clear_flag(window, WINDOW_RESIZABLE);\n    }\n\n    if (window->role) CFRelease(window->role);\n    window->role = window_ax_role(window);\n\n    if (window->subrole) CFRelease(window->subrole);\n    window->subrole = window_ax_subrole(window);\n\n    if (window->id == g_window_manager.last_window_id) {\n        g_window_manager.last_window_id = g_window_manager.focused_window_id;\n    }\n\n    struct view *view = window_manager_find_managed_window(&g_window_manager, window);\n    if (view) {\n        space_manager_untile_window(view, window);\n        window_manager_remove_managed_window(&g_window_manager, window->id);\n        window_manager_purify_window(&g_window_manager, window);\n    }\n\n    event_signal_push(SIGNAL_WINDOW_MINIMIZED, window);\n}\n\nstatic EVENT_HANDLER(WINDOW_DEMINIMIZED)\n{\n    struct window *window = context;\n\n    if (!__sync_bool_compare_and_swap(&window->id_ptr, &window->id, &window->id)) {\n        debug(\"%s: %d has been marked invalid by the system, ignoring event..\\n\", __FUNCTION__, window->id);\n        window_manager_remove_lost_focused_event(&g_window_manager, window->id);\n        return;\n    }\n\n    window_clear_flag(window, WINDOW_MINIMIZE);\n\n    if (window_ax_can_move(window)) {\n        window_set_flag(window, WINDOW_MOVABLE);\n    } else {\n        window_clear_flag(window, WINDOW_MOVABLE);\n    }\n\n    if (window_ax_can_resize(window)) {\n        window_set_flag(window, WINDOW_RESIZABLE);\n    } else {\n        window_clear_flag(window, WINDOW_RESIZABLE);\n    }\n\n    if (window->role) CFRelease(window->role);\n    window->role = window_ax_role(window);\n\n    if (window->subrole) CFRelease(window->subrole);\n    window->subrole = window_ax_subrole(window);\n\n    uint64_t sid = space_manager_active_space();\n    if (space_manager_is_window_on_space(sid, window)) {\n        debug(\"%s: window %s %d is deminimized on active space\\n\", __FUNCTION__, window->application->name, window->id);\n        if (window_manager_should_manage_window(window) && !window_manager_find_managed_window(&g_window_manager, window)) {\n            struct window *last_window = window_manager_find_window(&g_window_manager, g_window_manager.last_window_id);\n            uint32_t insertion_point = last_window && last_window->application->pid != window->application->pid ? last_window->id : 0;\n            struct view *view = space_manager_tile_window_on_space_with_insertion_point(&g_space_manager, window, sid, insertion_point);\n            window_manager_add_managed_window(&g_window_manager, window, view);\n        }\n    } else {\n        debug(\"%s: window %s %d is deminimized on inactive space\\n\", __FUNCTION__, window->application->name, window->id);\n    }\n\n    if (window_manager_find_lost_focused_event(&g_window_manager, window->id)) {\n        event_loop_post(&g_event_loop, WINDOW_FOCUSED, (void *)(intptr_t) window->id, 0);\n        window_manager_remove_lost_focused_event(&g_window_manager, window->id);\n    }\n\n    event_signal_push(SIGNAL_WINDOW_DEMINIMIZED, window);\n}\n\nstatic EVENT_HANDLER(WINDOW_TITLE_CHANGED)\n{\n    uint32_t window_id = (uint32_t)(intptr_t) context;\n    struct window *window = window_manager_find_window(&g_window_manager, window_id);\n    if (!window) return;\n\n    if (!__sync_bool_compare_and_swap(&window->id_ptr, &window->id, &window->id)) {\n        debug(\"%s: %d has been marked invalid by the system, ignoring event..\\n\", __FUNCTION__, window_id);\n        return;\n    }\n\n    debug(\"%s: %s %d\\n\", __FUNCTION__, window->application->name, window->id);\n\n    if (window->title) CFRelease(window->title);\n\n    window->title = window_title(window);\n\n    event_signal_push(SIGNAL_WINDOW_TITLE_CHANGED, window);\n}\n\nstatic EVENT_HANDLER(SLS_WINDOW_ORDERED)\n{\n    uint32_t wid = (uint64_t)(intptr_t) context;\n    debug(\"%s: %d\\n\", __FUNCTION__, wid);\n    struct window_node *node = table_find(&g_window_manager.insert_feedback, &wid);\n    if (node) SLSOrderWindow(g_connection, node->feedback_window.id, 1, node->window_order[0]);\n}\n\nstatic EVENT_HANDLER(SLS_WINDOW_DESTROYED)\n{\n    uint32_t wid = (uint64_t)(intptr_t) context;\n    debug(\"%s: %d\\n\", __FUNCTION__, wid);\n\n    struct window *window = window_manager_find_window(&g_window_manager, wid);\n    if (!window) return;\n\n    if (!__sync_bool_compare_and_swap(&window->id_ptr, &window->id, &window->id)) {\n        debug(\"%s: %d has been marked invalid by the system, ignoring event..\\n\", __FUNCTION__, wid);\n        return;\n    }\n\n    EVENT_HANDLER_WINDOW_DESTROYED(window, 0);\n}\n\nstatic EVENT_HANDLER(SLS_SPACE_CREATED)\n{\n    uint64_t sid = (uint64_t)(intptr_t) context;\n    int type = SLSSpaceGetType(g_connection, sid);\n\n    if (type == 0 || type == 4) {\n        debug(\"%s: %lld, %d\\n\", __FUNCTION__, sid, type);\n        space_manager_find_view(&g_space_manager, sid);\n        event_signal_push(SIGNAL_SPACE_CREATED, context);\n    }\n}\n\nstatic EVENT_HANDLER(SLS_SPACE_DESTROYED)\n{\n    uint64_t sid = (uint64_t)(intptr_t) context;\n    struct view *view = table_find(&g_space_manager.view, &sid);\n    if (view) {\n        debug(\"%s: %lld\\n\", __FUNCTION__, sid);\n        space_manager_remove_label_for_space(&g_space_manager, sid);\n        table_remove(&g_space_manager.view, &sid);\n        view_destroy(view);\n        free(view);\n        event_signal_push(SIGNAL_SPACE_DESTROYED, context);\n    }\n}\n\nstatic EVENT_HANDLER(SPACE_CHANGED)\n{\n    g_space_manager.last_space_id = g_space_manager.current_space_id;\n    g_space_manager.current_space_id = space_manager_active_space();\n\n    if (g_window_manager.menubar_opacity != 1.0f) {\n        float alpha = space_is_fullscreen(g_space_manager.current_space_id) ? 1.0f : g_window_manager.menubar_opacity;\n        SLSSetMenuBarInsetAndAlpha(g_connection, 0, 1, alpha);\n    }\n\n    debug(\"%s: %lld\\n\", __FUNCTION__, g_space_manager.current_space_id);\n    struct view *view = space_manager_find_view(&g_space_manager, g_space_manager.current_space_id);\n\n    if (space_manager_refresh_application_windows(&g_space_manager)) {\n        struct window *focused_window = window_manager_focused_window(&g_window_manager);\n        if (focused_window && window_manager_find_lost_focused_event(&g_window_manager, focused_window->id)) {\n            window_did_receive_focus(&g_window_manager, &g_mouse_state, focused_window);\n            window_manager_remove_lost_focused_event(&g_window_manager, focused_window->id);\n        }\n    }\n\n    if (!mission_control_is_active() && space_is_user(g_space_manager.current_space_id)) {\n        window_manager_validate_and_check_for_windows_on_space(&g_space_manager, &g_window_manager, g_space_manager.current_space_id);\n\n        if (view_is_invalid(view)) {\n            view_update(view);\n        }\n\n        if (view_is_dirty(view)) {\n            window_node_flush(view->root);\n            view_clear_flag(view, VIEW_IS_DIRTY);\n        }\n    }\n\n    event_signal_push(SIGNAL_SPACE_CHANGED, NULL);\n}\n\nstatic EVENT_HANDLER(DISPLAY_CHANGED)\n{\n    uint32_t new_did = display_manager_active_display_id();\n    if (g_display_manager.current_display_id == new_did) {\n        debug(\"%s: newly activated display %d was already active (%d)! ignoring event..\\n\", __FUNCTION__, g_display_manager.current_display_id, new_did);\n        return;\n    }\n\n    g_display_manager.last_display_id = g_display_manager.current_display_id;\n    g_display_manager.current_display_id = new_did;\n\n    g_space_manager.last_space_id = g_space_manager.current_space_id;\n    g_space_manager.current_space_id = display_space_id(g_display_manager.current_display_id);\n\n    uint32_t expected_display_id = space_display_id(g_space_manager.current_space_id);\n    if (g_display_manager.current_display_id != expected_display_id) {\n        debug(\"%s: %d %lld did not match %d! ignoring event..\\n\", __FUNCTION__, g_display_manager.current_display_id, g_space_manager.current_space_id, expected_display_id);\n        return;\n    }\n\n    if (g_window_manager.menubar_opacity != 1.0f) {\n        float alpha = space_is_fullscreen(g_space_manager.current_space_id) ? 1.0f : g_window_manager.menubar_opacity;\n        SLSSetMenuBarInsetAndAlpha(g_connection, 0, 1, alpha);\n    }\n\n    debug(\"%s: %d %lld\\n\", __FUNCTION__, g_display_manager.current_display_id, g_space_manager.current_space_id);\n    struct view *view = space_manager_find_view(&g_space_manager, g_space_manager.current_space_id);\n\n    if (space_manager_refresh_application_windows(&g_space_manager)) {\n        struct window *focused_window = window_manager_focused_window(&g_window_manager);\n        if (focused_window && window_manager_find_lost_focused_event(&g_window_manager, focused_window->id)) {\n            window_did_receive_focus(&g_window_manager, &g_mouse_state, focused_window);\n            window_manager_remove_lost_focused_event(&g_window_manager, focused_window->id);\n        }\n    }\n\n    if (!mission_control_is_active() && space_is_user(g_space_manager.current_space_id)) {\n        window_manager_validate_and_check_for_windows_on_space(&g_space_manager, &g_window_manager, g_space_manager.current_space_id);\n\n        if (view_is_invalid(view)) {\n            view_update(view);\n        }\n\n        if (view_is_dirty(view)) {\n            window_node_flush(view->root);\n            view_clear_flag(view, VIEW_IS_DIRTY);\n        }\n    }\n\n    event_signal_push(SIGNAL_DISPLAY_CHANGED, NULL);\n}\n\nstatic EVENT_HANDLER(DISPLAY_ADDED)\n{\n    uint32_t did = (uint32_t)(intptr_t) context;\n    debug(\"%s: %d\\n\", __FUNCTION__, did);\n    space_manager_handle_display_add(&g_space_manager, did);\n    window_manager_handle_display_add_and_remove(&g_space_manager, &g_window_manager, did);\n    event_signal_push(SIGNAL_DISPLAY_ADDED, context);\n}\n\nstatic EVENT_HANDLER(DISPLAY_REMOVED)\n{\n    uint32_t did = (uint32_t)(intptr_t) context;\n    debug(\"%s: %d\\n\", __FUNCTION__, did);\n    display_manager_remove_label_for_display(&g_display_manager, did);\n    window_manager_handle_display_add_and_remove(&g_space_manager, &g_window_manager, display_manager_main_display_id());\n    event_signal_push(SIGNAL_DISPLAY_REMOVED, context);\n}\n\nstatic EVENT_HANDLER(DISPLAY_MOVED)\n{\n    uint32_t did = (uint32_t)(intptr_t) context;\n    debug(\"%s: %d\\n\", __FUNCTION__, did);\n    space_manager_mark_spaces_invalid(&g_space_manager);\n    event_signal_push(SIGNAL_DISPLAY_MOVED, context);\n}\n\nstatic EVENT_HANDLER(DISPLAY_RESIZED)\n{\n    uint32_t did = (uint32_t)(intptr_t) context;\n    debug(\"%s: %d\\n\", __FUNCTION__, did);\n    space_manager_mark_spaces_invalid_for_display(&g_space_manager, did);\n    event_signal_push(SIGNAL_DISPLAY_RESIZED, context);\n}\n\nstatic EVENT_HANDLER(MOUSE_DOWN)\n{\n    if (mission_control_is_active())                     goto out;\n    if (g_mouse_state.current_action != MOUSE_MODE_NONE) goto out;\n\n    CGPoint point = CGEventGetLocation(context);\n    debug(\"%s: %.2f, %.2f\\n\", __FUNCTION__, point.x, point.y);\n\n    struct window *window = window_manager_find_window_at_point(&g_window_manager, point);\n    if (!window || window_check_flag(window, WINDOW_FULLSCREEN)) goto out;\n\n    g_mouse_state.window = window;\n    g_mouse_state.window_frame = g_mouse_state.window->frame;\n    g_mouse_state.down_location = point;\n    g_mouse_state.direction = 0;\n\n    int64_t button = CGEventGetIntegerValueField(context, kCGMouseEventButtonNumber);\n    uint8_t mod = (uint8_t) param1;\n\n    if (button == kCGMouseButtonLeft && g_mouse_state.modifier == mod) {\n        g_mouse_state.current_action = g_mouse_state.action1;\n    } else if (button == kCGMouseButtonRight && g_mouse_state.modifier == mod) {\n        g_mouse_state.current_action = g_mouse_state.action2;\n    }\n\n    if (g_mouse_state.current_action == MOUSE_MODE_RESIZE) {\n        CGPoint frame_mid = { CGRectGetMidX(g_mouse_state.window_frame), CGRectGetMidY(g_mouse_state.window_frame) };\n        if (point.x < frame_mid.x) g_mouse_state.direction |= HANDLE_LEFT;\n        if (point.y < frame_mid.y) g_mouse_state.direction |= HANDLE_TOP;\n        if (point.x > frame_mid.x) g_mouse_state.direction |= HANDLE_RIGHT;\n        if (point.y > frame_mid.y) g_mouse_state.direction |= HANDLE_BOTTOM;\n    }\n\nout:\n    CFRelease(context);\n}\n\nstatic EVENT_HANDLER(MOUSE_UP)\n{\n    if (mission_control_is_active()) goto out;\n    if (!g_mouse_state.window)       goto res;\n\n    if (!__sync_bool_compare_and_swap(&g_mouse_state.window->id_ptr, &g_mouse_state.window->id, &g_mouse_state.window->id)) {\n        debug(\"%s: %d has been marked invalid by the system, ignoring event..\\n\", __FUNCTION__, g_mouse_state.window->id);\n        goto err;\n    }\n\n    if (window_check_flag(g_mouse_state.window, WINDOW_FULLSCREEN)) {\n        debug(\"%s: %d is transitioning into native-fullscreen mode, ignoring event..\\n\", __FUNCTION__, g_mouse_state.window->id);\n        goto err;\n    }\n\n    CGPoint point = CGEventGetLocation(context);\n    debug(\"%s: %.2f, %.2f\\n\", __FUNCTION__, point.x, point.y);\n\n    struct view *src_view = window_manager_find_managed_window(&g_window_manager, g_mouse_state.window);\n    if (!src_view) goto err;\n\n    struct mouse_window_info info;\n    mouse_window_info_populate(&g_mouse_state, &info);\n\n    if (info.changed_position && !info.changed_size) {\n        uint64_t cursor_sid = display_space_id(display_manager_point_display_id(point));\n        struct view *dst_view = space_manager_find_view(&g_space_manager, cursor_sid);\n\n        struct window *window = window_manager_find_window_at_point_filtering_window(&g_window_manager, point, g_mouse_state.window->id);\n        if (!window) window = window_manager_find_window_at_point(&g_window_manager, point);\n        if (window == g_mouse_state.window) window = NULL;\n\n        struct window_node *a_node = view_find_window_node(src_view, g_mouse_state.window->id);\n        struct window_node *b_node = window ? view_find_window_node(dst_view, window->id) : NULL;\n\n        if (a_node && b_node && a_node != b_node) {\n            if (g_mouse_state.feedback_node) {\n                g_mouse_state.feedback_node->insert_dir = 0;\n                insert_feedback_destroy(g_mouse_state.feedback_node);\n                g_mouse_state.feedback_node = NULL;\n            }\n\n            enum mouse_drop_action drop_action = mouse_determine_drop_action(&g_mouse_state, a_node, window, point);\n            switch (drop_action) {\n            case MOUSE_DROP_ACTION_STACK: {\n                mouse_drop_action_stack(&g_window_manager, src_view, g_mouse_state.window, dst_view, window);\n            } break;\n            case MOUSE_DROP_ACTION_SWAP: {\n                mouse_drop_action_swap(&g_window_manager, src_view, a_node, g_mouse_state.window, dst_view, b_node, window);\n            } break;\n            case MOUSE_DROP_ACTION_WARP_TOP: {\n                mouse_drop_action_warp(&g_window_manager, src_view, a_node, g_mouse_state.window, dst_view, b_node, window, SPLIT_X, CHILD_FIRST);\n            } break;\n            case MOUSE_DROP_ACTION_WARP_RIGHT: {\n                mouse_drop_action_warp(&g_window_manager, src_view, a_node, g_mouse_state.window, dst_view, b_node, window, SPLIT_Y, CHILD_SECOND);\n            } break;\n            case MOUSE_DROP_ACTION_WARP_BOTTOM: {\n                mouse_drop_action_warp(&g_window_manager, src_view, a_node, g_mouse_state.window, dst_view, b_node, window, SPLIT_X, CHILD_SECOND);\n            } break;\n            case MOUSE_DROP_ACTION_WARP_LEFT: {\n                mouse_drop_action_warp(&g_window_manager, src_view, a_node, g_mouse_state.window, dst_view, b_node, window, SPLIT_Y, CHILD_FIRST);\n            } break;\n            case MOUSE_DROP_ACTION_NONE: {\n                /* silence compiler warning.. */\n            } break;\n            }\n        } else if (a_node) {\n            mouse_drop_no_target(&g_space_manager, &g_window_manager, src_view, dst_view, g_mouse_state.window, a_node);\n        }\n    } else if (info.changed_position || info.changed_size) {\n        mouse_drop_try_adjust_bsp_grid(&g_window_manager, src_view, g_mouse_state.window, &info);\n    }\n\nerr:\n    g_mouse_state.window = NULL;\nres:\n    g_mouse_state.current_action = MOUSE_MODE_NONE;\nout:\n    CFRelease(context);\n}\n\nstatic EVENT_HANDLER(MOUSE_DRAGGED)\n{\n    if (mission_control_is_active()) goto out;\n    if (!g_mouse_state.window)       goto out;\n\n    if (!__sync_bool_compare_and_swap(&g_mouse_state.window->id_ptr, &g_mouse_state.window->id, &g_mouse_state.window->id)) {\n        debug(\"%s: %d has been marked invalid by the system, ignoring event..\\n\", __FUNCTION__, g_mouse_state.window->id);\n        g_mouse_state.window = NULL;\n        g_mouse_state.current_action = MOUSE_MODE_NONE;\n        CFRelease(context);\n        return;\n    }\n\n    CGPoint point = CGEventGetLocation(context);\n    debug(\"%s: %.2f, %.2f\\n\", __FUNCTION__, point.x, point.y);\n\n    if (g_mouse_state.current_action == MOUSE_MODE_MOVE) {\n        CGPoint new_point = { g_mouse_state.window_frame.origin.x + (point.x - g_mouse_state.down_location.x),\n                              g_mouse_state.window_frame.origin.y + (point.y - g_mouse_state.down_location.y) };\n\n        uint32_t did = display_manager_point_display_id(new_point);\n        if (did) {\n            CGRect bounds = display_bounds_constrained(did, false);\n            if (new_point.y < bounds.origin.y) new_point.y = bounds.origin.y;\n        }\n\n        if (!scripting_addition_move_window(g_mouse_state.window->id, new_point.x, new_point.y)) {\n            window_manager_move_window(g_mouse_state.window, new_point.x, new_point.y);\n        }\n    } else if (g_mouse_state.current_action == MOUSE_MODE_RESIZE) {\n        uint64_t event_time = read_os_timer();\n        float dt = ((float) event_time - g_mouse_state.last_moved_time) * (1000.0f / (float)read_os_freq());\n        if (dt < 67.67f) goto out;\n\n        int dx = point.x - g_mouse_state.down_location.x;\n        int dy = point.y - g_mouse_state.down_location.y;\n\n        window_manager_resize_window_relative_internal(g_mouse_state.window, g_mouse_state.window->frame, g_mouse_state.direction, dx, dy, false);\n\n        g_mouse_state.last_moved_time = event_time;\n        g_mouse_state.down_location = point;\n    }\n\n    struct view *src_view = window_manager_find_managed_window(&g_window_manager, g_mouse_state.window);\n    if (!src_view) goto out;\n\n    struct mouse_window_info info;\n    mouse_window_info_populate(&g_mouse_state, &info);\n\n    if (info.changed_position && !info.changed_size) {\n        uint64_t cursor_sid = display_space_id(display_manager_point_display_id(point));\n        struct view *dst_view = space_manager_find_view(&g_space_manager, cursor_sid);\n\n        struct window *window = window_manager_find_window_at_point_filtering_window(&g_window_manager, point, g_mouse_state.window->id);\n        if (!window) window = window_manager_find_window_at_point(&g_window_manager, point);\n        if (window == g_mouse_state.window) window = NULL;\n\n        struct window_node *a_node = view_find_window_node(src_view, g_mouse_state.window->id);\n        struct window_node *b_node = window ? view_find_window_node(dst_view, window->id) : NULL;\n\n        if (a_node && b_node && a_node != b_node) {\n            if (g_mouse_state.feedback_node && g_mouse_state.feedback_node != b_node) {\n                g_mouse_state.feedback_node->insert_dir = 0;\n                insert_feedback_destroy(g_mouse_state.feedback_node);\n            }\n\n            int insert_dir = 0;\n            enum mouse_drop_action drop_action = mouse_determine_drop_action(&g_mouse_state, a_node, window, point);\n            switch (drop_action) {\n            case MOUSE_DROP_ACTION_STACK: {\n                insert_dir = STACK;\n            } break;\n            case MOUSE_DROP_ACTION_SWAP: {\n                insert_dir = STACK;\n            } break;\n            case MOUSE_DROP_ACTION_WARP_TOP: {\n                insert_dir = DIR_NORTH;\n            } break;\n            case MOUSE_DROP_ACTION_WARP_RIGHT: {\n                insert_dir = DIR_EAST;\n            } break;\n            case MOUSE_DROP_ACTION_WARP_BOTTOM: {\n                insert_dir = DIR_SOUTH;\n            } break;\n            case MOUSE_DROP_ACTION_WARP_LEFT: {\n                insert_dir = DIR_WEST;\n            } break;\n            case MOUSE_DROP_ACTION_NONE: {\n                /* silence compiler warning.. */\n            } break;\n            }\n\n            if (b_node->insert_dir != insert_dir) {\n                b_node->insert_dir = insert_dir;\n                insert_feedback_show(b_node);\n                g_mouse_state.feedback_node = b_node;\n            }\n        } else if (!b_node) {\n            if (g_mouse_state.feedback_node) {\n                g_mouse_state.feedback_node->insert_dir = 0;\n                insert_feedback_destroy(g_mouse_state.feedback_node);\n                g_mouse_state.feedback_node = NULL;\n            }\n        }\n    }\n\nout:\n    CFRelease(context);\n}\n\nstatic EVENT_HANDLER(MOUSE_MOVED)\n{\n    if (g_window_manager.ffm_mode == FFM_DISABLED) goto out;\n    if (mission_control_is_active())               goto out;\n    if (g_mouse_state.ffm_window_id)               goto out;\n\n    CGPoint point = CGEventGetLocation(context);\n    struct window *window = window_manager_find_window_at_point(&g_window_manager, point);\n\n    if (window) {\n        if (window->id == g_window_manager.focused_window_id) goto out;\n        if (!window_manager_is_window_eligible(window))       goto out;\n\n        if (g_window_manager.ffm_mode == FFM_AUTOFOCUS) {\n\n            //\n            // NOTE(asmvik): Look for a window with role AXSheet or AXDrawer\n            // and forward focus to it because we are not allowed to focus the main\n            // window in these cases.\n            //\n\n            CFArrayRef window_list = SLSCopyAssociatedWindows(g_connection, window->id);\n            int window_count = CFArrayGetCount(window_list);\n\n            uint32_t child_wid;\n            for (int i = 0; i < window_count; ++i) {\n                CFNumberGetValue(CFArrayGetValueAtIndex(window_list, i), kCFNumberSInt32Type, &child_wid);\n                struct window *child = window_manager_find_window(&g_window_manager, child_wid);\n                if (!child) continue;\n\n                CFTypeRef role = window_role(child);\n                if (!role) continue;\n\n                bool valid = CFEqual(role, kAXSheetRole) || CFEqual(role, kAXDrawerRole);\n                CFRelease(role);\n\n                if (valid) {\n                    window = child;\n                    break;\n                }\n            }\n\n            CFRelease(window_list);\n            window_manager_focus_window_without_raise(&window->application->psn, window->id);\n            g_mouse_state.ffm_window_id = window->id;\n        } else if (g_window_manager.ffm_mode == FFM_AUTORAISE) {\n\n            //\n            // NOTE(asmvik): If any **floating** window would be fully occluded by\n            // autoraising the window below the cursor we do not actually perform the\n            // focus change, as it is likely that the user is trying to reach for the\n            // smaller window that sits on top of the window we would otherwise raise.\n            //\n\n            bool occludes_window = false;\n\n            int window_count;\n            uint32_t *window_list = space_window_list(g_space_manager.current_space_id, &window_count, false);\n\n            if (window_list) {\n                for (int i = 0; i < window_count; ++i) {\n                    uint32_t wid = window_list[i];\n                    if (wid == window->id) break;\n\n                    struct window *sub_window = window_manager_find_window(&g_window_manager, wid);\n                    if (!sub_window) continue;\n\n                    if (!window_check_flag(sub_window, WINDOW_FLOAT))                     continue;\n                    if (window_level(window->id) != window_level(sub_window->id))         continue;\n                    if (window_sub_level(window->id) != window_sub_level(sub_window->id)) continue;\n\n                    if (CGRectContainsRect(window->frame, sub_window->frame)) {\n                        occludes_window = true;\n                        break;\n                    }\n                }\n            }\n\n            if (!occludes_window) {\n                window_manager_focus_window_with_raise(&window->application->psn, window->id, window->ref);\n                g_mouse_state.ffm_window_id = window->id;\n            }\n        }\n    } else {\n        uint32_t cursor_did = display_manager_point_display_id(point);\n        if (g_display_manager.current_display_id == cursor_did) goto out;\n\n        CGRect bounds = display_bounds_constrained(cursor_did, false);\n        if (!cgrect_contains_point(bounds, point)) goto out;\n\n        uint32_t wid = display_manager_focus_display_with_window_at_point(point);\n        if (!wid) display_manager_set_active_display_id(cursor_did);\n        g_mouse_state.ffm_window_id = wid;\n    }\n\nout:\n    CFRelease(context);\n}\n\nstatic EVENT_HANDLER(MISSION_CONTROL_SHOW_ALL_WINDOWS)\n{\n    debug(\"%s:\\n\", __FUNCTION__);\n    g_mission_control_mode = MISSION_CONTROL_MODE_SHOW_ALL_WINDOWS;\n    event_signal_push(SIGNAL_MISSION_CONTROL_ENTER, (void*)(uintptr_t)g_mission_control_mode);\n}\n\nstatic EVENT_HANDLER(MISSION_CONTROL_SHOW_FRONT_WINDOWS)\n{\n    debug(\"%s:\\n\", __FUNCTION__);\n    g_mission_control_mode = MISSION_CONTROL_MODE_SHOW_FRONT_WINDOWS;\n    event_signal_push(SIGNAL_MISSION_CONTROL_ENTER, (void*)(uintptr_t)g_mission_control_mode);\n}\n\nstatic EVENT_HANDLER(MISSION_CONTROL_SHOW_DESKTOP)\n{\n    debug(\"%s:\\n\", __FUNCTION__);\n    g_mission_control_mode = MISSION_CONTROL_MODE_SHOW_DESKTOP;\n    event_signal_push(SIGNAL_MISSION_CONTROL_ENTER, (void*)(uintptr_t)g_mission_control_mode);\n}\n\nstatic EVENT_HANDLER(MISSION_CONTROL_ENTER)\n{\n    debug(\"%s:\\n\", __FUNCTION__);\n    g_mission_control_mode = MISSION_CONTROL_MODE_SHOW;\n\n    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.1f * NSEC_PER_SEC), dispatch_get_main_queue(), ^{\n        event_loop_post(&g_event_loop, MISSION_CONTROL_CHECK_FOR_EXIT, NULL, 0);\n    });\n\n    event_signal_push(SIGNAL_MISSION_CONTROL_ENTER, (void*)(uintptr_t)g_mission_control_mode);\n}\n\nstatic EVENT_HANDLER(MISSION_CONTROL_CHECK_FOR_EXIT)\n{\n    if (!mission_control_is_active()) return;\n\n    CFArrayRef window_list = CGWindowListCopyWindowInfo(kCGWindowListOptionOnScreenOnly, 0);\n    int window_count = CFArrayGetCount(window_list);\n    bool found = false;\n\n    for (int i = 0; i < window_count; ++i) {\n        CFDictionaryRef dictionary = CFArrayGetValueAtIndex(window_list, i);\n\n        CFStringRef name = CFDictionaryGetValue(dictionary, kCGWindowName);\n        if (name) continue;\n\n        CFStringRef owner = CFDictionaryGetValue(dictionary, kCGWindowOwnerName);\n        if (!owner) continue;\n\n        CFNumberRef layer_ref = CFDictionaryGetValue(dictionary, kCGWindowLayer);\n        if (!layer_ref) continue;\n\n        uint64_t layer = 0;\n        CFNumberGetValue(layer_ref, CFNumberGetType(layer_ref), &layer);\n        if (layer != 18) continue;\n\n        if (CFEqual(CFSTR(\"Dock\"), owner)) {\n            found = true;\n            break;\n        }\n    }\n\n    if (found) {\n        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.1f * NSEC_PER_SEC), dispatch_get_main_queue(), ^{\n            event_loop_post(&g_event_loop, MISSION_CONTROL_CHECK_FOR_EXIT, NULL, 0);\n        });\n    } else {\n        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.0f), dispatch_get_main_queue(), ^{\n            event_loop_post(&g_event_loop, MISSION_CONTROL_EXIT, NULL, 0);\n        });\n    }\n\n    CFRelease(window_list);\n}\n\nstatic EVENT_HANDLER(MISSION_CONTROL_EXIT)\n{\n    debug(\"%s:\\n\", __FUNCTION__);\n\n    if (g_window_manager.menubar_opacity != 1.0f) {\n        float alpha = space_is_fullscreen(g_space_manager.current_space_id) ? 1.0f : g_window_manager.menubar_opacity;\n        SLSSetMenuBarInsetAndAlpha(g_connection, 0, 1, alpha);\n    }\n\n    if (g_mission_control_mode == MISSION_CONTROL_MODE_SHOW || g_mission_control_mode == MISSION_CONTROL_MODE_SHOW_ALL_WINDOWS) {\n        window_manager_correct_for_mission_control_changes(&g_space_manager, &g_window_manager);\n    }\n\n    event_signal_push(SIGNAL_MISSION_CONTROL_EXIT, (void*)(uintptr_t)g_mission_control_mode);\n    g_mission_control_mode = MISSION_CONTROL_MODE_INACTIVE;\n}\n\nstatic EVENT_HANDLER(DOCK_DID_RESTART)\n{\n    debug(\"%s:\\n\", __FUNCTION__);\n\n    if (workspace_is_macos_monterey() ||\n        workspace_is_macos_ventura() ||\n        workspace_is_macos_sonoma() ||\n        workspace_is_macos_sequoia() ||\n        workspace_is_macos_tahoe()) {\n        mission_control_unobserve();\n        mission_control_observe();\n    }\n\n    event_signal_push(SIGNAL_DOCK_DID_RESTART, NULL);\n}\n\nstatic enum ffm_mode ffm_value;\nstatic int is_menu_open = 0;\n\nstatic EVENT_HANDLER(MENU_OPENED)\n{\n    debug(\"%s\\n\", __FUNCTION__);\n    ++is_menu_open;\n\n    if (is_menu_open == 1) {\n        ffm_value = g_window_manager.ffm_mode;\n        g_window_manager.ffm_mode = FFM_DISABLED;\n    }\n}\n\nstatic EVENT_HANDLER(MENU_CLOSED)\n{\n    debug(\"%s\\n\", __FUNCTION__);\n    --is_menu_open;\n\n    if (is_menu_open < 0) {\n        is_menu_open = 0;\n    }\n\n    if (is_menu_open == 0) {\n        g_window_manager.ffm_mode = ffm_value;\n    }\n}\n\nstatic EVENT_HANDLER(MENU_BAR_HIDDEN_CHANGED)\n{\n    debug(\"%s:\\n\", __FUNCTION__);\n    space_manager_mark_spaces_invalid(&g_space_manager);\n    event_signal_push(SIGNAL_MENU_BAR_HIDDEN_CHANGED, NULL);\n}\n\nstatic EVENT_HANDLER(DOCK_DID_CHANGE_PREF)\n{\n    debug(\"%s:\\n\", __FUNCTION__);\n    space_manager_mark_spaces_invalid(&g_space_manager);\n    event_signal_push(SIGNAL_DOCK_DID_CHANGE_PREF, NULL);\n}\n\nstatic EVENT_HANDLER(SYSTEM_WOKE)\n{\n    debug(\"%s:\\n\", __FUNCTION__);\n\n    struct window *focused_window = window_manager_find_window(&g_window_manager, g_window_manager.focused_window_id);\n    if (focused_window) {\n        window_manager_set_window_opacity(&g_window_manager, focused_window, g_window_manager.active_window_opacity);\n        window_manager_center_mouse(&g_window_manager, focused_window);\n    }\n\n    event_signal_push(SIGNAL_SYSTEM_WOKE, NULL);\n}\n\nstatic EVENT_HANDLER(DAEMON_MESSAGE)\n{\n    TIME_FUNCTION;\n\n    FILE *rsp         = NULL;\n    int bytes_read    = 0;\n    int bytes_to_read = 0;\n\n    if (read(param1, &bytes_to_read, sizeof(int)) == sizeof(int)) {\n        char *message = ts_alloc_unaligned(bytes_to_read);\n\n        do {\n            int cur_read = read(param1, message+bytes_read, bytes_to_read-bytes_read);\n            if (cur_read <= 0) break;\n\n            bytes_read += cur_read;\n        } while (bytes_read < bytes_to_read);\n\n        if ((bytes_read == bytes_to_read) && (rsp = fdopen(param1, \"w\"))) {\n            debug_message(__FUNCTION__, message);\n            handle_message(rsp, message);\n\n            fflush(rsp);\n            fclose(rsp);\n\n            return;\n        }\n    }\n\n    socket_close(param1);\n}\n#pragma clang diagnostic pop\n\nstatic void *event_loop_run(void *context)\n{\n    struct event *head, *next;\n    struct event_loop *event_loop = context;\n\n    while (event_loop->is_running) {\n        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];\n\n        for (;;) {\n            profile_begin();\n\n            do {\n                head = __atomic_load_n(&event_loop->head, __ATOMIC_RELAXED);\n                next = __atomic_load_n(&head->next, __ATOMIC_RELAXED);\n                if (!next) goto empty;\n            } while (!__sync_bool_compare_and_swap(&event_loop->head, head, next));\n\n            switch (__atomic_load_n(&next->type, __ATOMIC_RELAXED)) {\n#define EVENT_TYPE_ENTRY(value) case value: EVENT_HANDLER_##value(__atomic_load_n(&next->context, __ATOMIC_RELAXED), __atomic_load_n(&next->param1, __ATOMIC_RELAXED)); break;\n                EVENT_TYPE_LIST\n#undef EVENT_TYPE_ENTRY\n            }\n\n            event_signal_flush();\n            ts_reset();\n\n            profile_end_and_print();\n        }\n\nempty:\n        [pool drain];\n        sem_wait(event_loop->semaphore);\n    }\n\n    return NULL;\n}\n\nvoid event_loop_post(struct event_loop *event_loop, enum event_type type, void *context, int param1)\n{\n    bool success;\n    struct event *tail, *new_tail;\n\n    new_tail = memory_pool_push(&event_loop->pool, sizeof(struct event));\n    __atomic_store_n(&new_tail->type, type, __ATOMIC_RELEASE);\n    __atomic_store_n(&new_tail->param1, param1, __ATOMIC_RELEASE);\n    __atomic_store_n(&new_tail->context, context, __ATOMIC_RELEASE);\n    __atomic_store_n(&new_tail->next, NULL, __ATOMIC_RELEASE);\n    __asm__ __volatile__ (\"\" ::: \"memory\");\n\n    do {\n        tail = __atomic_load_n(&event_loop->tail, __ATOMIC_RELAXED);\n        success = __sync_bool_compare_and_swap(&tail->next, NULL, new_tail);\n    } while (!success);\n    __sync_bool_compare_and_swap(&event_loop->tail, tail, new_tail);\n\n    sem_post(event_loop->semaphore);\n}\n\nbool event_loop_begin(struct event_loop *event_loop)\n{\n    if (!memory_pool_init(&event_loop->pool, KILOBYTES(512))) return false;\n\n    event_loop->semaphore = sem_open(\"yabai_event_loop_semaphore\", O_CREAT, 0600, 0);\n    sem_unlink(\"yabai_event_loop_semaphore\");\n    if (event_loop->semaphore == SEM_FAILED) return false;\n\n    event_loop->head = memory_pool_push(&event_loop->pool, sizeof(struct event));\n    event_loop->head->next = NULL;\n    event_loop->tail = event_loop->head;\n\n    event_loop->is_running = true;\n    pthread_create(&event_loop->thread, NULL, &event_loop_run, event_loop);\n\n    return true;\n}\n"
  },
  {
    "path": "src/event_loop.h",
    "content": "#ifndef EVENT_LOOP_H\n#define EVENT_LOOP_H\n\n#define EVENT_HANDLER(event_type) void EVENT_HANDLER_##event_type(void *context, int param1)\n\n#define EVENT_TYPE_LIST \\\n    EVENT_TYPE_ENTRY(APPLICATION_LAUNCHED) \\\n    EVENT_TYPE_ENTRY(APPLICATION_TERMINATED) \\\n    EVENT_TYPE_ENTRY(APPLICATION_FRONT_SWITCHED) \\\n    EVENT_TYPE_ENTRY(APPLICATION_VISIBLE) \\\n    EVENT_TYPE_ENTRY(APPLICATION_HIDDEN) \\\n    EVENT_TYPE_ENTRY(WINDOW_CREATED) \\\n    EVENT_TYPE_ENTRY(WINDOW_DESTROYED) \\\n    EVENT_TYPE_ENTRY(WINDOW_FOCUSED) \\\n    EVENT_TYPE_ENTRY(WINDOW_MOVED) \\\n    EVENT_TYPE_ENTRY(WINDOW_RESIZED) \\\n    EVENT_TYPE_ENTRY(WINDOW_MINIMIZED) \\\n    EVENT_TYPE_ENTRY(WINDOW_DEMINIMIZED) \\\n    EVENT_TYPE_ENTRY(WINDOW_TITLE_CHANGED) \\\n    EVENT_TYPE_ENTRY(SLS_WINDOW_ORDERED) \\\n    EVENT_TYPE_ENTRY(SLS_WINDOW_DESTROYED) \\\n    EVENT_TYPE_ENTRY(SLS_SPACE_CREATED) \\\n    EVENT_TYPE_ENTRY(SLS_SPACE_DESTROYED) \\\n    EVENT_TYPE_ENTRY(SPACE_CHANGED) \\\n    EVENT_TYPE_ENTRY(DISPLAY_ADDED) \\\n    EVENT_TYPE_ENTRY(DISPLAY_REMOVED) \\\n    EVENT_TYPE_ENTRY(DISPLAY_MOVED) \\\n    EVENT_TYPE_ENTRY(DISPLAY_RESIZED) \\\n    EVENT_TYPE_ENTRY(DISPLAY_CHANGED) \\\n    EVENT_TYPE_ENTRY(MOUSE_DOWN) \\\n    EVENT_TYPE_ENTRY(MOUSE_UP) \\\n    EVENT_TYPE_ENTRY(MOUSE_DRAGGED) \\\n    EVENT_TYPE_ENTRY(MOUSE_MOVED) \\\n    EVENT_TYPE_ENTRY(MISSION_CONTROL_SHOW_ALL_WINDOWS) \\\n    EVENT_TYPE_ENTRY(MISSION_CONTROL_SHOW_FRONT_WINDOWS) \\\n    EVENT_TYPE_ENTRY(MISSION_CONTROL_SHOW_DESKTOP) \\\n    EVENT_TYPE_ENTRY(MISSION_CONTROL_ENTER) \\\n    EVENT_TYPE_ENTRY(MISSION_CONTROL_CHECK_FOR_EXIT) \\\n    EVENT_TYPE_ENTRY(MISSION_CONTROL_EXIT) \\\n    EVENT_TYPE_ENTRY(DOCK_DID_RESTART) \\\n    EVENT_TYPE_ENTRY(MENU_OPENED) \\\n    EVENT_TYPE_ENTRY(MENU_CLOSED) \\\n    EVENT_TYPE_ENTRY(MENU_BAR_HIDDEN_CHANGED) \\\n    EVENT_TYPE_ENTRY(DOCK_DID_CHANGE_PREF) \\\n    EVENT_TYPE_ENTRY(SYSTEM_WOKE) \\\n    EVENT_TYPE_ENTRY(DAEMON_MESSAGE)\n\nenum event_type\n{\n#define EVENT_TYPE_ENTRY(value) value,\n    EVENT_TYPE_LIST\n#undef EVENT_TYPE_ENTRY\n};\n\nstruct event\n{\n    enum event_type type;\n    int param1;\n    void *context;\n    struct event *next;\n};\n\nstruct event_loop\n{\n    bool is_running;\n    pthread_t thread;\n    sem_t *semaphore;\n    struct memory_pool pool;\n    struct event *head;\n    struct event *tail;\n};\n\nbool event_loop_begin(struct event_loop *event_loop);\nvoid event_loop_post(struct event_loop *event_loop, enum event_type type, void *context, int param1);\n\n#endif\n"
  },
  {
    "path": "src/event_signal.c",
    "content": "extern struct signal *g_signal_event[SIGNAL_TYPE_COUNT];\nextern struct memory_pool g_signal_storage;\nextern struct process_manager g_process_manager;\nextern struct display_manager g_display_manager;\nextern struct space_manager g_space_manager;\nextern struct window_manager g_window_manager;\n\nstatic bool event_signal_filter(struct event_signal *es, struct signal *signal)\n{\n    switch (es->type) {\n    default: return false;\n\n    case SIGNAL_APPLICATION_LAUNCHED:\n    case SIGNAL_APPLICATION_ACTIVATED:\n    case SIGNAL_APPLICATION_DEACTIVATED:\n    case SIGNAL_APPLICATION_VISIBLE: {\n        int regex_match_app = signal->app_regex_exclude ? REGEX_MATCH_YES : REGEX_MATCH_NO;\n        return regex_match(signal->app_regex_valid, &signal->app_regex, es->app) == regex_match_app;\n    } break;\n    case SIGNAL_APPLICATION_TERMINATED:\n    case SIGNAL_APPLICATION_HIDDEN:\n    case SIGNAL_WINDOW_DESTROYED: {\n        int regex_match_app = signal->app_regex_exclude ? REGEX_MATCH_YES : REGEX_MATCH_NO;\n        bool app_no_match = regex_match(signal->app_regex_valid, &signal->app_regex, es->app) == regex_match_app;\n\n        bool active = signal->active == SIGNAL_PROP_UD;\n        if (!active) active = es->active == (signal->active == SIGNAL_PROP_YES);\n\n        return app_no_match || !active;\n    } break;\n    case SIGNAL_WINDOW_CREATED:\n    case SIGNAL_WINDOW_FOCUSED:\n    case SIGNAL_WINDOW_DEMINIMIZED: {\n        int regex_match_app = signal->app_regex_exclude ? REGEX_MATCH_YES : REGEX_MATCH_NO;\n        bool app_no_match = regex_match(signal->app_regex_valid, &signal->app_regex, es->app) == regex_match_app;\n\n        int regex_match_title = signal->title_regex_exclude ? REGEX_MATCH_YES : REGEX_MATCH_NO;\n        bool title_no_match = regex_match(signal->title_regex_valid, &signal->title_regex, es->title) == regex_match_title;\n\n        return app_no_match || title_no_match;\n    } break;\n    case SIGNAL_WINDOW_MOVED:\n    case SIGNAL_WINDOW_RESIZED:\n    case SIGNAL_WINDOW_MINIMIZED:\n    case SIGNAL_WINDOW_TITLE_CHANGED: {\n        int regex_match_app = signal->app_regex_exclude ? REGEX_MATCH_YES : REGEX_MATCH_NO;\n        bool app_no_match = regex_match(signal->app_regex_valid, &signal->app_regex, es->app) == regex_match_app;\n\n        int regex_match_title = signal->title_regex_exclude ? REGEX_MATCH_YES : REGEX_MATCH_NO;\n        bool title_no_match = regex_match(signal->title_regex_valid, &signal->title_regex, es->title) == regex_match_title;\n\n        bool active = signal->active == SIGNAL_PROP_UD;\n        if (!active) active = es->active == (signal->active == SIGNAL_PROP_YES);\n\n        return app_no_match || title_no_match || !active;\n    } break;\n    }\n}\n\nvoid event_signal_flush(void)\n{\n    if (!g_signal_storage.used) return;\n\n    pid_t pid = fork();\n    if (pid) {\n        g_signal_storage.used = 0;\n        return;\n    }\n\n    int size  = sizeof(struct event_signal);\n    int count = g_signal_storage.used / size;\n\n    for (int i = 0; i < count; ++i) {\n        struct event_signal *es = g_signal_storage.memory + (i * size);\n\n        int signal_count = buf_len(g_signal_event[es->type]);\n        debug(\"%s: transmitting %s to %d subscriber(s)\\n\", __FUNCTION__, signal_type_str[es->type], signal_count);\n\n        for (int j = 0; j < signal_count; ++j) {\n            struct signal *signal = &g_signal_event[es->type][j];\n            if (event_signal_filter(es, signal)) continue;\n\n            int pid = fork();\n            if (pid) continue;\n\n            if (es->arg_name[0]) setenv(es->arg_name[0], es->arg_value[0], 1);\n            if (es->arg_name[1]) setenv(es->arg_name[1], es->arg_value[1], 1);\n            if (es->arg_name[2]) setenv(es->arg_name[2], es->arg_value[2], 1);\n            if (es->arg_name[3]) setenv(es->arg_name[3], es->arg_value[3], 1);\n\n            char *exec[] = { \"/usr/bin/env\", \"sh\", \"-c\", signal->command, NULL};\n            exit(execvp(exec[0], exec));\n        }\n    }\n\n    exit(EXIT_SUCCESS);\n}\n\nvoid event_signal_push(enum signal_type type, void *context)\n{\n    int signal_count = buf_len(g_signal_event[type]);\n    if (!signal_count) return;\n\n    uint64_t arg_size = 128;\n    uint64_t size = sizeof(struct event_signal);\n\n    uint64_t used = __sync_fetch_and_add(&g_signal_storage.used, size);\n    struct event_signal *es = g_signal_storage.memory + used;\n\n    es->type         = type;\n    es->arg_name[0]  = NULL;\n    es->arg_name[1]  = NULL;\n    es->arg_name[2]  = NULL;\n    es->arg_name[3]  = NULL;\n    es->arg_value[0] = NULL;\n    es->arg_value[1] = NULL;\n    es->arg_value[2] = NULL;\n    es->arg_value[3] = NULL;\n\n    switch (type) {\n    default: break;\n\n    case SIGNAL_APPLICATION_LAUNCHED:\n    case SIGNAL_APPLICATION_ACTIVATED:\n    case SIGNAL_APPLICATION_DEACTIVATED:\n    case SIGNAL_APPLICATION_VISIBLE: {\n        struct application *application = context;\n\n        es->arg_name[0]  = ts_alloc_unaligned(arg_size);\n        es->arg_value[0] = ts_alloc_unaligned(arg_size);\n\n        snprintf(es->arg_name[0],  arg_size, \"%s\", \"YABAI_PROCESS_ID\");\n        snprintf(es->arg_value[0], arg_size, \"%d\", application->pid);\n\n        es->app = application->name;\n    } break;\n    case SIGNAL_APPLICATION_TERMINATED: {\n        struct application *application = context;\n\n        es->arg_name[0]  = ts_alloc_unaligned(arg_size);\n        es->arg_value[0] = ts_alloc_unaligned(arg_size);\n\n        snprintf(es->arg_name[0],  arg_size, \"%s\", \"YABAI_PROCESS_ID\");\n        snprintf(es->arg_value[0], arg_size, \"%d\", application->pid);\n\n        es->app = ts_string_copy(application->name);\n\n        //\n        // NOTE(asmvik): We always receive an application_front_switched event *before* an application_terminated\n        // event. We need to know the difference between a front_switched + application_terminated sequence and a regular\n        // application switch followed by a user-initiated termination of the previously focused application. The system\n        // events are triggered within an interval that appear to be impossible to match even with a user automated sequence.\n        // The dt threshold below is triple the average interval computed, to allow for some leeway.\n        //\n\n        EventTime dt = GetCurrentEventTime() - g_process_manager.switch_event_time;\n        if (dt >= 0.05f) {\n            es->active = g_process_manager.front_pid == application->pid;\n        } else {\n            es->active = g_process_manager.last_front_pid == application->pid;\n        }\n    } break;\n    case SIGNAL_APPLICATION_FRONT_SWITCHED: {\n        es->arg_name[0]  = ts_alloc_unaligned(arg_size);\n        es->arg_value[0] = ts_alloc_unaligned(arg_size);\n        es->arg_name[1]  = ts_alloc_unaligned(arg_size);\n        es->arg_value[1] = ts_alloc_unaligned(arg_size);\n\n        snprintf(es->arg_name[0],  arg_size, \"%s\", \"YABAI_PROCESS_ID\");\n        snprintf(es->arg_value[0], arg_size, \"%d\", g_process_manager.front_pid);\n        snprintf(es->arg_name[1],  arg_size, \"%s\", \"YABAI_RECENT_PROCESS_ID\");\n        snprintf(es->arg_value[1], arg_size, \"%d\", g_process_manager.last_front_pid);\n    } break;\n    case SIGNAL_APPLICATION_HIDDEN: {\n        struct application *application = context;\n\n        es->arg_name[0]  = ts_alloc_unaligned(arg_size);\n        es->arg_value[0] = ts_alloc_unaligned(arg_size);\n\n        snprintf(es->arg_name[0],  arg_size, \"%s\", \"YABAI_PROCESS_ID\");\n        snprintf(es->arg_value[0], arg_size, \"%d\", application->pid);\n\n        es->app = application->name;\n        es->active = g_process_manager.front_pid == application->pid;\n    } break;\n    case SIGNAL_WINDOW_CREATED:\n    case SIGNAL_WINDOW_FOCUSED:\n    case SIGNAL_WINDOW_DEMINIMIZED: {\n        struct window *window = context;\n\n        es->arg_name[0]  = ts_alloc_unaligned(arg_size);\n        es->arg_value[0] = ts_alloc_unaligned(arg_size);\n\n        snprintf(es->arg_name[0],  arg_size, \"%s\", \"YABAI_WINDOW_ID\");\n        snprintf(es->arg_value[0], arg_size, \"%d\", window->id);\n\n        es->app   = window->application->name;\n        es->title = window_title_ts(window);\n    } break;\n    case SIGNAL_WINDOW_DESTROYED: {\n        struct window *window = context;\n\n        es->arg_name[0]  = ts_alloc_unaligned(arg_size);\n        es->arg_value[0] = ts_alloc_unaligned(arg_size);\n\n        snprintf(es->arg_name[0],  arg_size, \"%s\", \"YABAI_WINDOW_ID\");\n        snprintf(es->arg_value[0], arg_size, \"%d\", window->id);\n\n        es->app = window->application ? ts_string_copy(window->application->name) : \"<unknown>\";\n        es->active = g_window_manager.focused_window_id == window->id;\n    } break;\n    case SIGNAL_WINDOW_MOVED:\n    case SIGNAL_WINDOW_RESIZED:\n    case SIGNAL_WINDOW_MINIMIZED:\n    case SIGNAL_WINDOW_TITLE_CHANGED: {\n        struct window *window = context;\n\n        es->arg_name[0]  = ts_alloc_unaligned(arg_size);\n        es->arg_value[0] = ts_alloc_unaligned(arg_size);\n\n        snprintf(es->arg_name[0],  arg_size, \"%s\", \"YABAI_WINDOW_ID\");\n        snprintf(es->arg_value[0], arg_size, \"%d\", window->id);\n\n        es->app   = window->application->name;\n        es->title = window_title_ts(window);\n        es->active = g_window_manager.focused_window_id == window->id;\n    } break;\n    case SIGNAL_SPACE_CREATED: {\n        uint64_t sid = (uint64_t)(uintptr_t) context;\n        int index    = space_manager_mission_control_index(sid);\n\n        es->arg_name[0]  = ts_alloc_unaligned(arg_size);\n        es->arg_value[0] = ts_alloc_unaligned(arg_size);\n        es->arg_name[1]  = ts_alloc_unaligned(arg_size);\n        es->arg_value[1] = ts_alloc_unaligned(arg_size);\n\n        snprintf(es->arg_name[0],  arg_size, \"%s\",   \"YABAI_SPACE_ID\");\n        snprintf(es->arg_value[0], arg_size, \"%lld\", sid);\n        snprintf(es->arg_name[1],  arg_size, \"%s\",   \"YABAI_SPACE_INDEX\");\n        snprintf(es->arg_value[1], arg_size, \"%d\",   index);\n    } break;\n    case SIGNAL_SPACE_DESTROYED: {\n        uint64_t sid = (uint64_t)(uintptr_t) context;\n\n        es->arg_name[0]  = ts_alloc_unaligned(arg_size);\n        es->arg_value[0] = ts_alloc_unaligned(arg_size);\n\n        snprintf(es->arg_name[0],  arg_size, \"%s\",   \"YABAI_SPACE_ID\");\n        snprintf(es->arg_value[0], arg_size, \"%lld\", sid);\n    } break;\n    case SIGNAL_SPACE_CHANGED: {\n        uint64_t sid        = g_space_manager.current_space_id;\n        uint64_t recent_sid = g_space_manager.last_space_id;\n\n        int index        = space_manager_mission_control_index(sid);\n        int recent_index = space_manager_mission_control_index(recent_sid);\n\n        es->arg_name[0]  = ts_alloc_unaligned(arg_size);\n        es->arg_value[0] = ts_alloc_unaligned(arg_size);\n        es->arg_name[1]  = ts_alloc_unaligned(arg_size);\n        es->arg_value[1] = ts_alloc_unaligned(arg_size);\n\n        es->arg_name[2]  = ts_alloc_unaligned(arg_size);\n        es->arg_value[2] = ts_alloc_unaligned(arg_size);\n        es->arg_name[3]  = ts_alloc_unaligned(arg_size);\n        es->arg_value[3] = ts_alloc_unaligned(arg_size);\n\n        snprintf(es->arg_name[0],  arg_size, \"%s\",   \"YABAI_SPACE_ID\");\n        snprintf(es->arg_value[0], arg_size, \"%lld\", sid);\n        snprintf(es->arg_name[1],  arg_size, \"%s\",   \"YABAI_RECENT_SPACE_ID\");\n        snprintf(es->arg_value[1], arg_size, \"%lld\", recent_sid);\n\n        snprintf(es->arg_name[2],  arg_size, \"%s\", \"YABAI_SPACE_INDEX\");\n        snprintf(es->arg_value[2], arg_size, \"%d\", index);\n        snprintf(es->arg_name[3],  arg_size, \"%s\", \"YABAI_RECENT_SPACE_INDEX\");\n        snprintf(es->arg_value[3], arg_size, \"%d\", recent_index);\n    } break;\n    case SIGNAL_DISPLAY_ADDED:\n    case SIGNAL_DISPLAY_MOVED:\n    case SIGNAL_DISPLAY_RESIZED: {\n        uint32_t did = (uint32_t)(uintptr_t) context;\n        int index    = display_manager_display_id_arrangement(did);\n\n        es->arg_name[0]  = ts_alloc_unaligned(arg_size);\n        es->arg_value[0] = ts_alloc_unaligned(arg_size);\n        es->arg_name[1]  = ts_alloc_unaligned(arg_size);\n        es->arg_value[1] = ts_alloc_unaligned(arg_size);\n\n        snprintf(es->arg_name[0],  arg_size, \"%s\", \"YABAI_DISPLAY_ID\");\n        snprintf(es->arg_value[0], arg_size, \"%d\", did);\n        snprintf(es->arg_name[1],  arg_size, \"%s\", \"YABAI_DISPLAY_INDEX\");\n        snprintf(es->arg_value[1], arg_size, \"%d\", index);\n    } break;\n    case SIGNAL_DISPLAY_REMOVED: {\n        uint32_t did = (uint32_t)(uintptr_t) context;\n\n        es->arg_name[0]  = ts_alloc_unaligned(arg_size);\n        es->arg_value[0] = ts_alloc_unaligned(arg_size);\n\n        snprintf(es->arg_name[0],  arg_size, \"%s\", \"YABAI_DISPLAY_ID\");\n        snprintf(es->arg_value[0], arg_size, \"%d\", did);\n    } break;\n    case SIGNAL_DISPLAY_CHANGED: {\n        uint32_t did        = g_display_manager.current_display_id;\n        uint32_t recent_did = g_display_manager.last_display_id;\n\n        int index        = display_manager_display_id_arrangement(did);\n        int recent_index = display_manager_display_id_arrangement(recent_did);\n\n        es->arg_name[0]  = ts_alloc_unaligned(arg_size);\n        es->arg_value[0] = ts_alloc_unaligned(arg_size);\n        es->arg_name[1]  = ts_alloc_unaligned(arg_size);\n        es->arg_value[1] = ts_alloc_unaligned(arg_size);\n\n        es->arg_name[2]  = ts_alloc_unaligned(arg_size);\n        es->arg_value[2] = ts_alloc_unaligned(arg_size);\n        es->arg_name[3]  = ts_alloc_unaligned(arg_size);\n        es->arg_value[3] = ts_alloc_unaligned(arg_size);\n\n        snprintf(es->arg_name[0],  arg_size, \"%s\", \"YABAI_DISPLAY_ID\");\n        snprintf(es->arg_value[0], arg_size, \"%d\", did);\n        snprintf(es->arg_name[1],  arg_size, \"%s\", \"YABAI_RECENT_DISPLAY_ID\");\n        snprintf(es->arg_value[1], arg_size, \"%d\", recent_did);\n\n        snprintf(es->arg_name[2],  arg_size, \"%s\", \"YABAI_DISPLAY_INDEX\");\n        snprintf(es->arg_value[2], arg_size, \"%d\", index);\n        snprintf(es->arg_name[3],  arg_size, \"%s\", \"YABAI_RECENT_DISPLAY_INDEX\");\n        snprintf(es->arg_value[3], arg_size, \"%d\", recent_index);\n    } break;\n    case SIGNAL_MISSION_CONTROL_ENTER:\n    case SIGNAL_MISSION_CONTROL_EXIT: {\n        enum mission_control_mode mode = (enum mission_control_mode)(uintptr_t) context;\n\n        es->arg_name[0]  = ts_alloc_unaligned(arg_size);\n        es->arg_value[0] = ts_alloc_unaligned(arg_size);\n\n        snprintf(es->arg_name[0],  arg_size, \"%s\", \"YABAI_MISSION_CONTROL_MODE\");\n        snprintf(es->arg_value[0], arg_size, \"%s\", mission_control_mode_str[mode]);\n    } break;\n    }\n}\n\nenum signal_type signal_type_from_string(const char *str)\n{\n    for (int i = SIGNAL_APPLICATION_LAUNCHED; i < SIGNAL_TYPE_COUNT; ++i) {\n        if (string_equals(str, signal_type_str[i])) return i;\n    }\n\n    return SIGNAL_TYPE_UNKNOWN;\n}\n\nvoid event_signal_add(enum signal_type type, struct signal *signal)\n{\n    if (signal->label) event_signal_remove(signal->label);\n    buf_push(g_signal_event[type], *signal);\n}\n\nvoid event_signal_destroy(struct signal *signal)\n{\n    if (signal->app_regex_valid)   regfree(&signal->app_regex);\n    if (signal->title_regex_valid) regfree(&signal->title_regex);\n    if (signal->command) free(signal->command);\n    if (signal->label)   free(signal->label);\n    if (signal->app)     free(signal->app);\n    if (signal->title)   free(signal->title);\n}\n\nbool event_signal_remove_by_index(int index)\n{\n    int signal_index = 0;\n    for (int i = SIGNAL_APPLICATION_LAUNCHED; i < SIGNAL_TYPE_COUNT; ++i) {\n        for (int j = 0; j < buf_len(g_signal_event[i]); ++j) {\n            if (signal_index == index) {\n                event_signal_destroy(&g_signal_event[i][j]);\n                buf_del(g_signal_event[i], j);\n                return true;\n            }\n            ++signal_index;\n        }\n    }\n\n    return false;\n}\n\nbool event_signal_remove(char *label)\n{\n    for (int i = SIGNAL_APPLICATION_LAUNCHED; i < SIGNAL_TYPE_COUNT; ++i) {\n        for (int j = 0; j < buf_len(g_signal_event[i]); ++j) {\n            if (string_equals(label, g_signal_event[i][j].label)) {\n                event_signal_destroy(&g_signal_event[i][j]);\n                buf_del(g_signal_event[i], j);\n                return true;\n            }\n        }\n    }\n\n    return false;\n}\n\nstatic void event_signal_serialize(FILE *rsp, struct signal *signal, enum signal_type type, int index)\n{\n    TIME_FUNCTION;\n\n    char *app   = signal->app;\n    char *title = signal->title;\n    char *cmd   = signal->command;\n\n    char *escaped_app   = app   ? ts_string_escape(app)   : NULL;\n    char *escaped_title = title ? ts_string_escape(title) : NULL;\n    char *escaped_cmd   = cmd   ? ts_string_escape(cmd)   : NULL;\n\n    fprintf(rsp,\n            \"{\\n\"\n            \"\\t\\\"index\\\":%d,\\n\"\n            \"\\t\\\"label\\\":\\\"%s\\\",\\n\"\n            \"\\t\\\"app\\\":\\\"%s\\\",\\n\"\n            \"\\t\\\"title\\\":\\\"%s\\\",\\n\"\n            \"\\t\\\"active\\\":%s,\\n\"\n            \"\\t\\\"event\\\":\\\"%s\\\",\\n\"\n            \"\\t\\\"action\\\":\\\"%s\\\"\\n\"\n            \"}\",\n            index,\n            signal->label ? signal->label : \"\",\n            escaped_app ? escaped_app : app ? app : \"\",\n            escaped_title ? escaped_title : title ? title : \"\",\n            json_optional_bool(signal->active),\n            signal_type_str[type],\n            escaped_cmd ? escaped_cmd : cmd ? cmd : \"\");\n}\n\nvoid event_signal_list(FILE *rsp)\n{\n    TIME_FUNCTION;\n\n    fprintf(rsp, \"[\");\n    int signal_index = 0;\n    bool event_did_output = false;\n    for (int i = SIGNAL_APPLICATION_LAUNCHED; i < SIGNAL_TYPE_COUNT; ++i) {\n        int count = buf_len(g_signal_event[i]);\n\n        if (count > 0 && event_did_output) {\n            fprintf(rsp, \",\");\n        }\n\n        for (int j = 0; j < count; ++j) {\n            event_signal_serialize(rsp, &g_signal_event[i][j], i, signal_index);\n            if (j < buf_len(g_signal_event[i]) - 1) fprintf(rsp, \",\");\n            ++signal_index;\n        }\n\n        if (!event_did_output) event_did_output = count > 0;\n    }\n    fprintf(rsp, \"]\\n\");\n}\n"
  },
  {
    "path": "src/event_signal.h",
    "content": "#ifndef EVENT_SIGNAL_H\n#define EVENT_SIGNAL_H\n\nenum signal_type\n{\n    SIGNAL_TYPE_UNKNOWN,\n\n    SIGNAL_APPLICATION_LAUNCHED,\n    SIGNAL_APPLICATION_TERMINATED,\n    SIGNAL_APPLICATION_FRONT_SWITCHED,\n    SIGNAL_APPLICATION_ACTIVATED,\n    SIGNAL_APPLICATION_DEACTIVATED,\n    SIGNAL_APPLICATION_VISIBLE,\n    SIGNAL_APPLICATION_HIDDEN,\n\n    SIGNAL_WINDOW_CREATED,\n    SIGNAL_WINDOW_DESTROYED,\n    SIGNAL_WINDOW_FOCUSED,\n    SIGNAL_WINDOW_MOVED,\n    SIGNAL_WINDOW_RESIZED,\n    SIGNAL_WINDOW_MINIMIZED,\n    SIGNAL_WINDOW_DEMINIMIZED,\n    SIGNAL_WINDOW_TITLE_CHANGED,\n\n    SIGNAL_SPACE_CREATED,\n    SIGNAL_SPACE_DESTROYED,\n    SIGNAL_SPACE_CHANGED,\n\n    SIGNAL_DISPLAY_ADDED,\n    SIGNAL_DISPLAY_REMOVED,\n    SIGNAL_DISPLAY_MOVED,\n    SIGNAL_DISPLAY_RESIZED,\n    SIGNAL_DISPLAY_CHANGED,\n\n    SIGNAL_MISSION_CONTROL_ENTER,\n    SIGNAL_MISSION_CONTROL_EXIT,\n\n    SIGNAL_DOCK_DID_CHANGE_PREF,\n    SIGNAL_DOCK_DID_RESTART,\n\n    SIGNAL_MENU_BAR_HIDDEN_CHANGED,\n    SIGNAL_SYSTEM_WOKE,\n\n    SIGNAL_TYPE_COUNT\n};\n\nstatic const char *signal_type_str[] =\n{\n    [SIGNAL_TYPE_UNKNOWN]                   = \"signal_type_unknown\",\n\n    [SIGNAL_APPLICATION_LAUNCHED]           = \"application_launched\",\n    [SIGNAL_APPLICATION_TERMINATED]         = \"application_terminated\",\n    [SIGNAL_APPLICATION_FRONT_SWITCHED]     = \"application_front_switched\",\n    [SIGNAL_APPLICATION_ACTIVATED]          = \"application_activated\",\n    [SIGNAL_APPLICATION_DEACTIVATED]        = \"application_deactivated\",\n    [SIGNAL_APPLICATION_VISIBLE]            = \"application_visible\",\n    [SIGNAL_APPLICATION_HIDDEN]             = \"application_hidden\",\n\n    [SIGNAL_WINDOW_CREATED]                 = \"window_created\",\n    [SIGNAL_WINDOW_DESTROYED]               = \"window_destroyed\",\n    [SIGNAL_WINDOW_FOCUSED]                 = \"window_focused\",\n    [SIGNAL_WINDOW_MOVED]                   = \"window_moved\",\n    [SIGNAL_WINDOW_RESIZED]                 = \"window_resized\",\n    [SIGNAL_WINDOW_MINIMIZED]               = \"window_minimized\",\n    [SIGNAL_WINDOW_DEMINIMIZED]             = \"window_deminimized\",\n    [SIGNAL_WINDOW_TITLE_CHANGED]           = \"window_title_changed\",\n\n    [SIGNAL_SPACE_CREATED]                  = \"space_created\",\n    [SIGNAL_SPACE_DESTROYED]                = \"space_destroyed\",\n    [SIGNAL_SPACE_CHANGED]                  = \"space_changed\",\n\n    [SIGNAL_DISPLAY_ADDED]                  = \"display_added\",\n    [SIGNAL_DISPLAY_REMOVED]                = \"display_removed\",\n    [SIGNAL_DISPLAY_MOVED]                  = \"display_moved\",\n    [SIGNAL_DISPLAY_RESIZED]                = \"display_resized\",\n    [SIGNAL_DISPLAY_CHANGED]                = \"display_changed\",\n\n    [SIGNAL_MISSION_CONTROL_ENTER]          = \"mission_control_enter\",\n    [SIGNAL_MISSION_CONTROL_EXIT]           = \"mission_control_exit\",\n\n    [SIGNAL_DOCK_DID_CHANGE_PREF]           = \"dock_did_change_pref\",\n    [SIGNAL_DOCK_DID_RESTART]               = \"dock_did_restart\",\n\n    [SIGNAL_MENU_BAR_HIDDEN_CHANGED]        = \"menu_bar_hidden_changed\",\n    [SIGNAL_SYSTEM_WOKE]                    = \"system_woke\",\n\n    [SIGNAL_TYPE_COUNT]                     = \"signal_type_count\"\n};\n\n#define SIGNAL_PROP_UD  0\n#define SIGNAL_PROP_YES 1\n#define SIGNAL_PROP_NO  2\n\nstruct event_signal\n{\n    enum signal_type type;\n    char *arg_name[4];\n    char *arg_value[4];\n    char *app;\n    char *title;\n    int active;\n};\n\nstruct signal\n{\n    char *app;\n    char *title;\n    bool app_regex_valid;\n    bool title_regex_valid;\n    bool app_regex_exclude;\n    bool title_regex_exclude;\n    regex_t app_regex;\n    regex_t title_regex;\n    int active;\n    char *command;\n    char *label;\n};\n\nvoid event_signal_push(enum signal_type type, void *context);\nvoid event_signal_flush(void);\n\nvoid event_signal_add(enum signal_type type, struct signal *signal);\nvoid event_signal_destroy(struct signal *signal);\nbool event_signal_remove_by_index(int index);\nbool event_signal_remove(char *label);\nvoid event_signal_list(FILE *rsp);\nenum signal_type signal_type_from_string(const char *str);\n\n#endif\n"
  },
  {
    "path": "src/manifest.m",
    "content": "#include <Carbon/Carbon.h>\n#include <Cocoa/Cocoa.h>\n#include <CoreVideo/CoreVideo.h>\n#include <mach/mach_time.h>\n#include <mach-o/dyld.h>\n#include <mach-o/swap.h>\n#include <bootstrap.h>\n\n#ifdef __x86_64__\n#include <emmintrin.h>\n#elif __arm64__\n#include <arm_neon.h>\n#endif\n\n#include <stdio.h>\n#include <stddef.h>\n#include <stdlib.h>\n#include <stdint.h>\n#include <string.h>\n#include <dirent.h>\n#include <stdbool.h>\n#include <assert.h>\n#include <fcntl.h>\n#include <regex.h>\n#include <execinfo.h>\n#include <signal.h>\n#include <unistd.h>\n#include <sys/wait.h>\n#include <sys/stat.h>\n#include <sys/types.h>\n#include <sys/sysctl.h>\n#include <sys/socket.h>\n#include <sys/un.h>\n#include <netinet/in.h>\n#include <arpa/inet.h>\n#include <netdb.h>\n#include <poll.h>\n#include <semaphore.h>\n#include <pthread.h>\n#include <pwd.h>\n#include <spawn.h>\n#include <libproc.h>\n\n#include \"misc/extern.h\"\n#include \"misc/macros.h\"\n#include \"misc/memory_pool.h\"\n#include \"misc/ts.h\"\n//#include \"misc/autorelease.h\"\n#include \"misc/notify.h\"\n#include \"misc/log.h\"\n#include \"misc/helpers.h\"\n#include \"misc/timer.h\"\n#include \"misc/macho_dlsym.h\"\n#include \"misc/sbuffer.h\"\n#define HASHTABLE_IMPLEMENTATION\n#include \"misc/hashtable.h\"\n#undef HASHTABLE_IMPLEMENTATION\n#include \"misc/service.h\"\n\n#include \"osax/common.h\"\n\n#include \"view.h\"\n#include \"sa.h\"\n#include \"event_loop.h\"\n#include \"event_signal.h\"\n#include \"workspace.h\"\n#include \"rule.h\"\n#include \"message.h\"\n#include \"display.h\"\n#include \"space.h\"\n#include \"window.h\"\n#include \"process_manager.h\"\n#include \"application.h\"\n#include \"display_manager.h\"\n#include \"space_manager.h\"\n#include \"window_manager.h\"\n#include \"mouse_handler.h\"\n\n#include \"sa.m\"\n#include \"mission_control.c\"\n#include \"event_loop.c\"\n#include \"event_signal.c\"\n#include \"workspace.m\"\n#include \"rule.c\"\n#include \"message.c\"\n#include \"display.c\"\n#include \"space.c\"\n#include \"view.c\"\n#include \"window.c\"\n#include \"process_manager.c\"\n#include \"application.c\"\n#include \"display_manager.c\"\n#include \"space_manager.c\"\n#include \"window_manager.c\"\n#include \"mouse_handler.c\"\n#include \"yabai.c\"\n"
  },
  {
    "path": "src/message.c",
    "content": "static struct {\n    int sockfd;\n    bool is_running;\n    pthread_t thread;\n} g_message_loop;\n\nextern struct event_loop g_event_loop;\nextern struct display_manager g_display_manager;\nextern struct space_manager g_space_manager;\nextern struct window_manager g_window_manager;\nextern struct mouse_state g_mouse_state;\nextern bool g_verbose;\n\n#define DOMAIN_CONFIG  \"config\"\n#define DOMAIN_DISPLAY \"display\"\n#define DOMAIN_SPACE   \"space\"\n#define DOMAIN_WINDOW  \"window\"\n#define DOMAIN_QUERY   \"query\"\n#define DOMAIN_RULE    \"rule\"\n#define DOMAIN_SIGNAL  \"signal\"\n\n/* --------------------------------DOMAIN CONFIG-------------------------------- */\n#define COMMAND_CONFIG_DEBUG_OUTPUT          \"debug_output\"\n#define COMMAND_CONFIG_MFF                   \"mouse_follows_focus\"\n#define COMMAND_CONFIG_FFM                   \"focus_follows_mouse\"\n#define COMMAND_CONFIG_DISPLAY_ORDER         \"display_arrangement_order\"\n#define COMMAND_CONFIG_WINDOW_ORIGIN         \"window_origin_display\"\n#define COMMAND_CONFIG_WINDOW_PLACEMENT      \"window_placement\"\n#define COMMAND_CONFIG_WINDOW_INSERT_POINT   \"window_insertion_point\"\n#define COMMAND_CONFIG_WINDOW_ZOOM_PERSIST   \"window_zoom_persist\"\n#define COMMAND_CONFIG_OPACITY               \"window_opacity\"\n#define COMMAND_CONFIG_OPACITY_DURATION      \"window_opacity_duration\"\n#define COMMAND_CONFIG_ANIMATION_DURATION    \"window_animation_duration\"\n#define COMMAND_CONFIG_ANIMATION_EASING      \"window_animation_easing\"\n#define COMMAND_CONFIG_SHADOW                \"window_shadow\"\n#define COMMAND_CONFIG_MENUBAR_OPACITY       \"menubar_opacity\"\n#define COMMAND_CONFIG_ACTIVE_WINDOW_OPACITY \"active_window_opacity\"\n#define COMMAND_CONFIG_NORMAL_WINDOW_OPACITY \"normal_window_opacity\"\n#define COMMAND_CONFIG_INSERT_FEEDBACK_COLOR \"insert_feedback_color\"\n#define COMMAND_CONFIG_TOP_PADDING           \"top_padding\"\n#define COMMAND_CONFIG_BOTTOM_PADDING        \"bottom_padding\"\n#define COMMAND_CONFIG_LEFT_PADDING          \"left_padding\"\n#define COMMAND_CONFIG_RIGHT_PADDING         \"right_padding\"\n#define COMMAND_CONFIG_LAYOUT                \"layout\"\n#define COMMAND_CONFIG_WINDOW_GAP            \"window_gap\"\n#define COMMAND_CONFIG_SPLIT_RATIO           \"split_ratio\"\n#define COMMAND_CONFIG_SPLIT_TYPE            \"split_type\"\n#define COMMAND_CONFIG_AUTO_BALANCE          \"auto_balance\"\n#define COMMAND_CONFIG_MOUSE_MOD             \"mouse_modifier\"\n#define COMMAND_CONFIG_MOUSE_ACTION1         \"mouse_action1\"\n#define COMMAND_CONFIG_MOUSE_ACTION2         \"mouse_action2\"\n#define COMMAND_CONFIG_MOUSE_DROP_ACTION     \"mouse_drop_action\"\n#define COMMAND_CONFIG_EXTERNAL_BAR          \"external_bar\"\n\n#define SELECTOR_CONFIG_SPACE                \"--space\"\n\n#define ARGUMENT_CONFIG_FFM_AUTOFOCUS         \"autofocus\"\n#define ARGUMENT_CONFIG_FFM_AUTORAISE         \"autoraise\"\n#define ARGUMENT_CONFIG_DISPLAY_ORDER_DEFAULT \"default\"\n#define ARGUMENT_CONFIG_DISPLAY_ORDER_X       \"horizontal\"\n#define ARGUMENT_CONFIG_DISPLAY_ORDER_Y       \"vertical\"\n#define ARGUMENT_CONFIG_WINDOW_ORIGIN_DEFAULT \"default\"\n#define ARGUMENT_CONFIG_WINDOW_ORIGIN_FOCUSED \"focused\"\n#define ARGUMENT_CONFIG_WINDOW_ORIGIN_CURSOR  \"cursor\"\n#define ARGUMENT_CONFIG_WINDOW_PLACEMENT_FST  \"first_child\"\n#define ARGUMENT_CONFIG_WINDOW_PLACEMENT_SND  \"second_child\"\n#define ARGUMENT_CONFIG_WINDOW_INSERT_FOCUSED \"focused\"\n#define ARGUMENT_CONFIG_WINDOW_INSERT_FIRST   \"first\"\n#define ARGUMENT_CONFIG_WINDOW_INSERT_LAST    \"last\"\n#define ARGUMENT_CONFIG_SHADOW_FLT            \"float\"\n#define ARGUMENT_CONFIG_LAYOUT_BSP            \"bsp\"\n#define ARGUMENT_CONFIG_LAYOUT_STACK          \"stack\"\n#define ARGUMENT_CONFIG_LAYOUT_FLOAT          \"float\"\n#define ARGUMENT_CONFIG_SPLIT_TYPE_Y          \"vertical\"\n#define ARGUMENT_CONFIG_SPLIT_TYPE_X          \"horizontal\"\n#define ARGUMENT_CONFIG_SPLIT_TYPE_AUTO       \"auto\"\n#define ARGUMENT_CONFIG_MOUSE_MOD_ALT         \"alt\"\n#define ARGUMENT_CONFIG_MOUSE_MOD_SHIFT       \"shift\"\n#define ARGUMENT_CONFIG_MOUSE_MOD_CMD         \"cmd\"\n#define ARGUMENT_CONFIG_MOUSE_MOD_CTRL        \"ctrl\"\n#define ARGUMENT_CONFIG_MOUSE_MOD_FN          \"fn\"\n#define ARGUMENT_CONFIG_MOUSE_ACTION_MOVE     \"move\"\n#define ARGUMENT_CONFIG_MOUSE_ACTION_RESIZE   \"resize\"\n#define ARGUMENT_CONFIG_MOUSE_ACTION_SWAP     \"swap\"\n#define ARGUMENT_CONFIG_MOUSE_ACTION_STACK    \"stack\"\n#define ARGUMENT_CONFIG_EXTERNAL_BAR_MAIN     \"main\"\n#define ARGUMENT_CONFIG_EXTERNAL_BAR_ALL      \"all\"\n#define ARGUMENT_CONFIG_EXTERNAL_BAR          \"%5[^:]:%d:%d\"\n/* ----------------------------------------------------------------------------- */\n\n/* --------------------------------DOMAIN DISPLAY------------------------------- */\n#define COMMAND_DISPLAY_FOCUS \"--focus\"\n#define COMMAND_DISPLAY_SPACE \"--space\"\n#define COMMAND_DISPLAY_LABEL \"--label\"\n/* ----------------------------------------------------------------------------- */\n\n/* --------------------------------DOMAIN SPACE--------------------------------- */\n#define COMMAND_SPACE_FOCUS    \"--focus\"\n#define COMMAND_SPACE_SWITCH   \"--switch\"\n#define COMMAND_SPACE_CREATE   \"--create\"\n#define COMMAND_SPACE_DESTROY  \"--destroy\"\n#define COMMAND_SPACE_MOVE     \"--move\"\n#define COMMAND_SPACE_SWAP     \"--swap\"\n#define COMMAND_SPACE_DISPLAY  \"--display\"\n#define COMMAND_SPACE_EQUALIZE \"--equalize\"\n#define COMMAND_SPACE_BALANCE  \"--balance\"\n#define COMMAND_SPACE_MIRROR   \"--mirror\"\n#define COMMAND_SPACE_ROTATE   \"--rotate\"\n#define COMMAND_SPACE_PADDING  \"--padding\"\n#define COMMAND_SPACE_GAP      \"--gap\"\n#define COMMAND_SPACE_TOGGLE   \"--toggle\"\n#define COMMAND_SPACE_LAYOUT   \"--layout\"\n#define COMMAND_SPACE_LABEL    \"--label\"\n\n#define ARGUMENT_SPACE_ROTATE_90    \"90\"\n#define ARGUMENT_SPACE_ROTATE_180   \"180\"\n#define ARGUMENT_SPACE_ROTATE_270   \"270\"\n#define ARGUMENT_SPACE_PADDING      \"%255[^:]:%d:%d:%d:%d\"\n#define ARGUMENT_SPACE_GAP          \"%255[^:]:%d\"\n#define ARGUMENT_SPACE_TGL_PADDING  \"padding\"\n#define ARGUMENT_SPACE_TGL_GAP      \"gap\"\n#define ARGUMENT_SPACE_TGL_MC       \"mission-control\"\n#define ARGUMENT_SPACE_TGL_SD       \"show-desktop\"\n#define ARGUMENT_SPACE_LAYOUT_BSP   \"bsp\"\n#define ARGUMENT_SPACE_LAYOUT_STACK \"stack\"\n#define ARGUMENT_SPACE_LAYOUT_FLT   \"float\"\n/* ----------------------------------------------------------------------------- */\n\n/* --------------------------------DOMAIN WINDOW-------------------------------- */\n#define COMMAND_WINDOW_FOCUS      \"--focus\"\n#define COMMAND_WINDOW_CLOSE      \"--close\"\n#define COMMAND_WINDOW_MINIMIZE   \"--minimize\"\n#define COMMAND_WINDOW_DEMINIMIZE \"--deminimize\"\n#define COMMAND_WINDOW_DISPLAY    \"--display\"\n#define COMMAND_WINDOW_SPACE      \"--space\"\n#define COMMAND_WINDOW_SWAP       \"--swap\"\n#define COMMAND_WINDOW_WARP       \"--warp\"\n#define COMMAND_WINDOW_STACK      \"--stack\"\n#define COMMAND_WINDOW_INSERT     \"--insert\"\n#define COMMAND_WINDOW_GRID       \"--grid\"\n#define COMMAND_WINDOW_MOVE       \"--move\"\n#define COMMAND_WINDOW_RESIZE     \"--resize\"\n#define COMMAND_WINDOW_RATIO      \"--ratio\"\n#define COMMAND_WINDOW_SUB_LAYER  \"--sub-layer\"\n#define COMMAND_WINDOW_OPACITY    \"--opacity\"\n#define COMMAND_WINDOW_RAISE      \"--raise\"\n#define COMMAND_WINDOW_LOWER      \"--lower\"\n#define COMMAND_WINDOW_TOGGLE     \"--toggle\"\n#define COMMAND_WINDOW_SCRATCHPAD \"--scratchpad\"\n\n#define ARGUMENT_WINDOW_SEL_LARGEST     \"largest\"\n#define ARGUMENT_WINDOW_SEL_SMALLEST    \"smallest\"\n#define ARGUMENT_WINDOW_SEL_SIBLING     \"sibling\"\n#define ARGUMENT_WINDOW_SEL_FNEPHEW     \"first_nephew\"\n#define ARGUMENT_WINDOW_SEL_SNEPHEW     \"second_nephew\"\n#define ARGUMENT_WINDOW_SEL_UNCLE       \"uncle\"\n#define ARGUMENT_WINDOW_SEL_FCOUSIN     \"first_cousin\"\n#define ARGUMENT_WINDOW_SEL_SCOUSIN     \"second_cousin\"\n#define ARGUMENT_WINDOW_GRID            \"%d:%d:%d:%d:%d:%d\"\n#define ARGUMENT_WINDOW_MOVE            \"%255[^:]:%f:%f\"\n#define ARGUMENT_WINDOW_RESIZE          \"%255[^:]:%f:%f\"\n#define ARGUMENT_WINDOW_RATIO           \"%255[^:]:%f\"\n#define ARGUMENT_WINDOW_LAYER_BELOW     \"below\"\n#define ARGUMENT_WINDOW_LAYER_NORMAL    \"normal\"\n#define ARGUMENT_WINDOW_LAYER_ABOVE     \"above\"\n#define ARGUMENT_WINDOW_LAYER_AUTO      \"auto\"\n#define ARGUMENT_WINDOW_TOGGLE_FLOAT    \"float\"\n#define ARGUMENT_WINDOW_TOGGLE_STICKY   \"sticky\"\n#define ARGUMENT_WINDOW_TOGGLE_SHADOW   \"shadow\"\n#define ARGUMENT_WINDOW_TOGGLE_SPLIT    \"split\"\n#define ARGUMENT_WINDOW_TOGGLE_PARENT   \"zoom-parent\"\n#define ARGUMENT_WINDOW_TOGGLE_FULLSC   \"zoom-fullscreen\"\n#define ARGUMENT_WINDOW_TOGGLE_WINDOWED \"windowed-fullscreen\"\n#define ARGUMENT_WINDOW_TOGGLE_NATIVE   \"native-fullscreen\"\n#define ARGUMENT_WINDOW_TOGGLE_EXPOSE   \"expose\"\n#define ARGUMENT_WINDOW_TOGGLE_PIP      \"pip\"\n\n#define ARGUMENT_WINDOW_SCRATCHPAD_RECOVER \"recover\"\n/* ----------------------------------------------------------------------------- */\n\n/* --------------------------------DOMAIN QUERY--------------------------------- */\n#define COMMAND_QUERY_DISPLAYS \"--displays\"\n#define COMMAND_QUERY_SPACES   \"--spaces\"\n#define COMMAND_QUERY_WINDOWS  \"--windows\"\n\n#define ARGUMENT_QUERY_DISPLAY \"--display\"\n#define ARGUMENT_QUERY_SPACE   \"--space\"\n#define ARGUMENT_QUERY_WINDOW  \"--window\"\n/* ----------------------------------------------------------------------------- */\n\n/* --------------------------------DOMAIN RULE---------------------------------- */\n#define COMMAND_RULE_ADD     \"--add\"\n#define COMMAND_RULE_REM     \"--remove\"\n#define COMMAND_RULE_APPLY   \"--apply\"\n#define COMMAND_RULE_LS      \"--list\"\n\n#define ARGUMENT_RULE_ONE_SHOT       \"--one-shot\"\n#define ARGUMENT_RULE_KEY_APP        \"app\"\n#define ARGUMENT_RULE_KEY_TITLE      \"title\"\n#define ARGUMENT_RULE_KEY_ROLE       \"role\"\n#define ARGUMENT_RULE_KEY_SUBROLE    \"subrole\"\n#define ARGUMENT_RULE_KEY_DISPLAY    \"display\"\n#define ARGUMENT_RULE_KEY_SPACE      \"space\"\n#define ARGUMENT_RULE_KEY_OPACITY    \"opacity\"\n#define ARGUMENT_RULE_KEY_MANAGE     \"manage\"\n#define ARGUMENT_RULE_KEY_STICKY     \"sticky\"\n#define ARGUMENT_RULE_KEY_MFF        \"mouse_follows_focus\"\n#define ARGUMENT_RULE_KEY_SUB_LAYER  \"sub-layer\"\n#define ARGUMENT_RULE_KEY_FULLSCR    \"native-fullscreen\"\n#define ARGUMENT_RULE_KEY_GRID       \"grid\"\n#define ARGUMENT_RULE_KEY_LABEL      \"label\"\n#define ARGUMENT_RULE_KEY_SCRATCHPAD \"scratchpad\"\n\n#define ARGUMENT_RULE_VALUE_SPACE '^'\n#define ARGUMENT_RULE_VALUE_GRID  \"%d:%d:%d:%d:%d:%d\"\n/* ----------------------------------------------------------------------------- */\n\n/* --------------------------------DOMAIN SIGNAL-------------------------------- */\n#define COMMAND_SIGNAL_ADD \"--add\"\n#define COMMAND_SIGNAL_REM \"--remove\"\n#define COMMAND_SIGNAL_LS  \"--list\"\n\n#define ARGUMENT_SIGNAL_KEY_APP      \"app\"\n#define ARGUMENT_SIGNAL_KEY_TITLE    \"title\"\n#define ARGUMENT_SIGNAL_KEY_ACTIVE   \"active\"\n#define ARGUMENT_SIGNAL_KEY_EVENT    \"event\"\n#define ARGUMENT_SIGNAL_KEY_ACTION   \"action\"\n#define ARGUMENT_SIGNAL_KEY_LABEL    \"label\"\n\n#define ARGUMENT_SIGNAL_VALUE_YES    \"yes\"\n#define ARGUMENT_SIGNAL_VALUE_NO     \"no\"\n/* ----------------------------------------------------------------------------- */\n\n/* --------------------------------COMMON ARGUMENTS----------------------------- */\n#define ARGUMENT_COMMON_VAL_ON           \"on\"\n#define ARGUMENT_COMMON_VAL_OFF          \"off\"\n#define ARGUMENT_COMMON_SEL_PREV         \"prev\"\n#define ARGUMENT_COMMON_SEL_NEXT         \"next\"\n#define ARGUMENT_COMMON_SEL_FIRST        \"first\"\n#define ARGUMENT_COMMON_SEL_LAST         \"last\"\n#define ARGUMENT_COMMON_SEL_RECENT       \"recent\"\n#define ARGUMENT_COMMON_SEL_NORTH        \"north\"\n#define ARGUMENT_COMMON_SEL_EAST         \"east\"\n#define ARGUMENT_COMMON_SEL_SOUTH        \"south\"\n#define ARGUMENT_COMMON_SEL_WEST         \"west\"\n#define ARGUMENT_COMMON_SEL_MOUSE        \"mouse\"\n#define ARGUMENT_COMMON_SEL_STACK        \"stack\"\n#define ARGUMENT_COMMON_SEL_STACK_PREFIX \"stack.\"\n#define ARGUMENT_COMMON_VAL_AXIS_X       \"x-axis\"\n#define ARGUMENT_COMMON_VAL_AXIS_Y       \"y-axis\"\n/* ----------------------------------------------------------------------------- */\n\nstruct token\n{\n    char *text;\n    int length;\n};\n\nenum token_type\n{\n    TOKEN_TYPE_INVALID,\n    TOKEN_TYPE_UNKNOWN,\n    TOKEN_TYPE_INT,\n    TOKEN_TYPE_FLOAT,\n    TOKEN_TYPE_U32,\n    TOKEN_TYPE_STRING\n};\n\nstruct token_value\n{\n    struct token token;\n    enum token_type type;\n\n    union {\n        int int_value;\n        float float_value;\n        uint32_t u32_value;\n        char *string_value;\n    };\n};\n\nstatic const int token_char_int_table[] =\n{\n    ['0'] = 0x0, ['1'] = 0x1,\n    ['2'] = 0x2, ['3'] = 0x3,\n    ['4'] = 0x4, ['5'] = 0x5,\n    ['6'] = 0x6, ['7'] = 0x7,\n    ['8'] = 0x8, ['9'] = 0x9,\n    ['a'] = 0xA, ['A'] = 0xA,\n    ['b'] = 0xB, ['B'] = 0xB,\n    ['c'] = 0xC, ['C'] = 0xC,\n    ['d'] = 0xD, ['D'] = 0xD,\n    ['e'] = 0xE, ['E'] = 0xE,\n    ['f'] = 0xF, ['F'] = 0xF,\n};\n\nstatic struct token get_token(char **message)\n{\n    struct token token;\n\n    token.text = *message;\n    while (**message) {\n        ++(*message);\n    }\n    token.length = *message - token.text;\n\n    if ((*message)[0] == '\\0' && (*message)[1] != '\\0') {\n        ++(*message);\n    } else {\n        // NOTE(asmvik): don't go past the null-terminator\n    }\n\n    return token;\n}\n\nstatic bool token_prefix(struct token token, char *match)\n{\n    char *at = match;\n    for (int i = 0; i < token.length; ++i, ++at) {\n        if (*at == 0)             return true;\n        if (token.text[i] != *at) return false;\n    }\n    return *at == 0;\n}\n\nstatic bool token_equals(struct token token, char *match)\n{\n    char *at = match;\n    for (int i = 0; i < token.length; ++i, ++at) {\n        if ((*at == 0) || (token.text[i] != *at)) {\n            return false;\n        }\n    }\n    return *at == 0;\n}\n\nstatic inline bool token_is_valid(struct token token)\n{\n    return token.text && token.length > 0;\n}\n\nstatic bool token_is_positive_integer(struct token token, int *value)\n{\n    *value = 0;\n\n    for (int i = 0; i < token.length; ++i) {\n        char c = token.text[i];\n        if (!(c >= '0' && c <= '9')) {\n            return false;\n        }\n        *value = *value * 10 + token_char_int_table[(int)c];\n    }\n\n    return true;\n}\n\nstatic bool token_is_hexadecimal(struct token token, uint32_t *value)\n{\n    *value = 0;\n\n    if (token.length <= 2) return false;\n\n    if (!(token.text[0] == '0' &&\n         (token.text[1] == 'x' ||\n          token.text[1] == 'X'))) {\n        return false;\n    }\n\n    for (int i = 2; i < token.length; ++i) {\n        char c = token.text[i];\n        if (!((c >= '0' && c <= '9') ||\n              (c >= 'a' && c <= 'f') ||\n              (c >= 'A' && c <= 'F'))) {\n            return false;\n        }\n        *value = *value * 16 + (uint32_t)token_char_int_table[(int)c];\n    }\n\n    return true;\n}\n\nstatic bool token_is_float(struct token token, float *value)\n{\n    char *end = NULL;\n    float v = strtof(token.text, &end);\n\n    if (!end || *end) {\n        *value = 0.0f;\n        return false;\n    } else {\n        *value = v;\n        return true;\n    }\n}\n\nstatic struct token_value token_to_value(struct token token)\n{\n    struct token_value value = { .token = token, .type = TOKEN_TYPE_INVALID };\n\n    if (token_is_valid(token)) {\n        if (token_is_positive_integer(token, &value.int_value)) {\n            value.type = TOKEN_TYPE_INT;\n        } else if (token_is_hexadecimal(token, &value.u32_value)) {\n            value.type = TOKEN_TYPE_U32;\n        } else if (token_is_float(token, &value.float_value)) {\n            value.type = TOKEN_TYPE_FLOAT;\n        } else if ((value.string_value = token.text)) {\n            value.type = TOKEN_TYPE_STRING;\n        } else {\n            value.type = TOKEN_TYPE_UNKNOWN;\n        }\n    }\n\n    return value;\n}\n\nstatic inline void daemon_fail(FILE *rsp, char *fmt, ...)\n{\n    if (!rsp) return;\n\n    va_list ap;\n    va_start(ap, fmt);\n    fprintf(rsp, FAILURE_MESSAGE);\n    vfprintf(rsp, fmt, ap);\n    va_end(ap);\n}\n\n__unused static inline void daemon_deprecated(FILE *rsp, char *fmt, ...)\n{\n    if (!rsp) return;\n\n    va_list ap;\n    va_start(ap, fmt);\n    fprintf(rsp, \"deprecation warning: \");\n    vfprintf(rsp, fmt, ap);\n    va_end(ap);\n}\n\nstatic void parse_key_value_pair(char *token, char **key, char **value, bool *exclusion)\n{\n    *key = token;\n\n    while (*token) {\n        char fst = token[0];\n        char snd = token[1];\n\n        if (fst == '!' && snd == '=') {\n            break;\n        } else if (fst == '=') {\n            break;\n        }\n\n        ++token;\n    }\n\n    int index = (token[0] == '!' && token[1] == '=') ? 2 : 1;\n    char check = (index == 2) ? '!' : '=';\n\n    if (*token != check) {\n        *key = NULL;\n        *value = NULL;\n    } else if (token[index]) {\n        *token = '\\0';\n        *value = token+index;\n        *exclusion = index == 2;\n    } else {\n        *value = NULL;\n    }\n}\n\nstatic uint8_t parse_value_type(char *type)\n{\n    if (string_equals(type, \"abs\")) {\n        return TYPE_ABS;\n    } else if (string_equals(type, \"rel\")) {\n        return TYPE_REL;\n    } else {\n        return 0;\n    }\n}\n\nstatic uint8_t parse_resize_handle(char *handle)\n{\n    if (string_equals(handle, \"top\")) {\n        return HANDLE_TOP;\n    } else if (string_equals(handle, \"bottom\")) {\n        return HANDLE_BOTTOM;\n    } else if (string_equals(handle, \"left\")) {\n        return HANDLE_LEFT;\n    } else if (string_equals(handle, \"right\")) {\n        return HANDLE_RIGHT;\n    } else if (string_equals(handle, \"top_left\")) {\n        return HANDLE_TOP | HANDLE_LEFT;\n    } else if (string_equals(handle, \"top_right\")) {\n        return HANDLE_TOP | HANDLE_RIGHT;\n    } else if (string_equals(handle, \"bottom_left\")) {\n        return HANDLE_BOTTOM | HANDLE_LEFT;\n    } else if (string_equals(handle, \"bottom_right\")) {\n        return HANDLE_BOTTOM | HANDLE_RIGHT;\n    } else if (string_equals(handle, \"abs\")) {\n        return HANDLE_ABS;\n    } else {\n        return 0;\n    }\n}\n\nenum label_type\n{\n    LABEL_DISPLAY,\n    LABEL_SPACE,\n    LABEL_WINDOW\n};\n\nstatic char *reserved_display_identifiers[] =\n{\n    ARGUMENT_COMMON_SEL_NORTH,\n    ARGUMENT_COMMON_SEL_EAST,\n    ARGUMENT_COMMON_SEL_SOUTH,\n    ARGUMENT_COMMON_SEL_WEST,\n    ARGUMENT_COMMON_SEL_PREV,\n    ARGUMENT_COMMON_SEL_NEXT,\n    ARGUMENT_COMMON_SEL_FIRST,\n    ARGUMENT_COMMON_SEL_LAST,\n    ARGUMENT_COMMON_SEL_RECENT,\n    ARGUMENT_COMMON_SEL_MOUSE\n};\n\nstatic char *reserved_space_identifiers[] =\n{\n    ARGUMENT_COMMON_SEL_PREV,\n    ARGUMENT_COMMON_SEL_NEXT,\n    ARGUMENT_COMMON_SEL_FIRST,\n    ARGUMENT_COMMON_SEL_LAST,\n    ARGUMENT_COMMON_SEL_RECENT,\n    ARGUMENT_COMMON_SEL_MOUSE\n};\n\nstatic char *reserved_window_identifiers[] =\n{\n    ARGUMENT_WINDOW_TOGGLE_FLOAT,\n    ARGUMENT_WINDOW_TOGGLE_STICKY,\n    ARGUMENT_WINDOW_TOGGLE_SHADOW,\n    ARGUMENT_WINDOW_TOGGLE_SPLIT,\n    ARGUMENT_WINDOW_TOGGLE_PARENT,\n    ARGUMENT_WINDOW_TOGGLE_FULLSC,\n    ARGUMENT_WINDOW_TOGGLE_WINDOWED,\n    ARGUMENT_WINDOW_TOGGLE_NATIVE,\n    ARGUMENT_WINDOW_TOGGLE_EXPOSE,\n    ARGUMENT_WINDOW_TOGGLE_PIP,\n    ARGUMENT_WINDOW_SCRATCHPAD_RECOVER\n};\n\nstatic bool parse_label(FILE *rsp, struct token token, enum label_type type, char **label)\n{\n    struct token_value value = token_to_value(token);\n\n    if (value.type == TOKEN_TYPE_INVALID) {\n        *label = NULL;\n        return true;\n    }\n\n    if (value.type != TOKEN_TYPE_STRING) {\n        daemon_fail(rsp, \"'%.*s' cannot be used as a label.\\n\", token.length, token.text);\n        return false;\n    }\n\n    switch (type) {\n    default: break;\n    case LABEL_DISPLAY: {\n        for (int i = 0; i < array_count(reserved_display_identifiers); ++i) {\n            if (token_equals(token, reserved_display_identifiers[i])) {\n                daemon_fail(rsp, \"'%.*s' is a reserved keyword and cannot be used as a label.\\n\", token.length, token.text);\n                return false;\n            }\n        }\n    } break;\n    case LABEL_SPACE: {\n        for (int i = 0; i < array_count(reserved_space_identifiers); ++i) {\n            if (token_equals(token, reserved_space_identifiers[i])) {\n                daemon_fail(rsp, \"'%.*s' is a reserved keyword and cannot be used as a label.\\n\", token.length, token.text);\n                return false;\n            }\n        }\n    } break;\n    case LABEL_WINDOW: {\n        for (int i = 0; i < array_count(reserved_window_identifiers); ++i) {\n            if (token_equals(token, reserved_window_identifiers[i])) {\n                daemon_fail(rsp, \"'%.*s' is a reserved keyword and cannot be used as a scratchpad.\\n\", token.length, token.text);\n                return false;\n            }\n        }\n    } break;\n    }\n\n    *label = malloc(token.length + 1);\n    if (!(*label)) return false;\n\n    memcpy(*label, token.text, token.length);\n    (*label)[token.length] = '\\0';\n\n    return true;\n}\n\nstruct properties\n{\n    struct token token;\n    bool did_parse;\n    bool did_error;\n    uint64_t flags;\n};\n\nstatic inline bool parse_property(struct properties *properties, char *property, uint64_t *property_val, char **property_str, int property_count)\n{\n    for (int i = 0; i < property_count; ++i) {\n        if (string_equals(property, property_str[i])) {\n            properties->flags |= property_val[i];\n            return true;\n        }\n    }\n\n    return false;\n}\n\nstatic struct properties parse_properties(FILE *rsp, struct token token, uint64_t *property_val, char **property_str, int property_count)\n{\n    struct properties result = { .token = token, .did_error = false };\n\n    if ((result.did_parse = token_is_valid(token) && !token_prefix(token, \"--\"))) {\n        for (int i = 0, cursor = 0; i < token.length; ++i) {\n            if (i+1 == token.length) {\n                if (!parse_property(&result, token.text+cursor, property_val, property_str, property_count)) {\n                    daemon_fail(rsp, \"'%.*s' is not a valid property.\\n\", i-cursor+1, token.text+cursor);\n                    result.did_error = true;\n                }\n            } else if (token.text[i] == ',') {\n                token.text[i] = '\\0';\n\n                if (!parse_property(&result, token.text+cursor, property_val, property_str, property_count)) {\n                    daemon_fail(rsp, \"'%.*s' is not a valid property.\\n\", i-cursor+1, token.text+cursor);\n                    result.did_error = true;\n                }\n\n                cursor = i+1;\n            }\n        }\n    }\n\n    return result;\n}\n\nstruct selector\n{\n    struct token token;\n    bool did_parse;\n\n    union {\n        int dir;\n        uint32_t did;\n        uint64_t sid;\n        struct window *window;\n    };\n};\n\nstatic struct selector parse_display_selector(FILE *rsp, char **message, uint32_t acting_did, bool optional)\n{\n    TIME_FUNCTION;\n\n    struct selector result = { .token = get_token(message), .did_parse = true };\n\n    struct token_value value = token_to_value(result.token);\n    if (value.type == TOKEN_TYPE_INT) {\n        uint32_t did = display_manager_arrangement_display_id(value.int_value);\n        if (did) {\n            result.did = did;\n        } else {\n            daemon_fail(rsp, \"could not locate display with arrangement index '%d'.\\n\", value.int_value);\n        }\n    } else if (value.type == TOKEN_TYPE_STRING) {\n        if (token_equals(result.token, ARGUMENT_COMMON_SEL_NORTH)) {\n            if (acting_did) {\n                uint32_t did = display_manager_find_closest_display_in_direction(acting_did, DIR_NORTH);\n                if (did) {\n                    result.did = did;\n                } else {\n                    daemon_fail(rsp, \"could not locate a northward display.\\n\");\n                }\n            } else {\n                daemon_fail(rsp, \"could not locate the selected display.\\n\");\n            }\n        } else if (token_equals(result.token, ARGUMENT_COMMON_SEL_EAST)) {\n            if (acting_did) {\n                uint32_t did = display_manager_find_closest_display_in_direction(acting_did, DIR_EAST);\n                if (did) {\n                    result.did = did;\n                } else {\n                    daemon_fail(rsp, \"could not locate a eastward display.\\n\");\n                }\n            } else {\n                daemon_fail(rsp, \"could not locate the selected display.\\n\");\n            }\n        } else if (token_equals(result.token, ARGUMENT_COMMON_SEL_SOUTH)) {\n            if (acting_did) {\n                uint32_t did = display_manager_find_closest_display_in_direction(acting_did, DIR_SOUTH);\n                if (did) {\n                    result.did = did;\n                } else {\n                    daemon_fail(rsp, \"could not locate a southward display.\\n\");\n                }\n            } else {\n                daemon_fail(rsp, \"could not locate the selected display.\\n\");\n            }\n        } else if (token_equals(result.token, ARGUMENT_COMMON_SEL_WEST)) {\n            if (acting_did) {\n                uint32_t did = display_manager_find_closest_display_in_direction(acting_did, DIR_WEST);\n                if (did) {\n                    result.did = did;\n                } else {\n                    daemon_fail(rsp, \"could not locate a westward display.\\n\");\n                }\n            } else {\n                daemon_fail(rsp, \"could not locate the selected display.\\n\");\n            }\n        } else if (token_equals(result.token, ARGUMENT_COMMON_SEL_PREV)) {\n            if (acting_did) {\n                uint32_t did = display_manager_prev_display_id(acting_did);\n                if (did) {\n                    result.did = did;\n                } else {\n                    daemon_fail(rsp, \"could not locate the previous display.\\n\");\n                }\n            } else {\n                daemon_fail(rsp, \"could not locate the selected display.\\n\");\n            }\n        } else if (token_equals(result.token, ARGUMENT_COMMON_SEL_NEXT)) {\n            if (acting_did) {\n                uint32_t did = display_manager_next_display_id(acting_did);\n                if (did) {\n                    result.did = did;\n                } else {\n                    daemon_fail(rsp, \"could not locate the next display.\\n\");\n                }\n            } else {\n                daemon_fail(rsp, \"could not locate the selected display.\\n\");\n            }\n        } else if (token_equals(result.token, ARGUMENT_COMMON_SEL_FIRST)) {\n            uint32_t did = display_manager_first_display_id();\n            if (did) {\n                result.did = did;\n            } else {\n                daemon_fail(rsp, \"could not locate the first display.\\n\");\n            }\n        } else if (token_equals(result.token, ARGUMENT_COMMON_SEL_LAST)) {\n            uint32_t did = display_manager_last_display_id();\n            if (did) {\n                result.did = did;\n            } else {\n                daemon_fail(rsp, \"could not locate the last display.\\n\");\n            }\n        } else if (token_equals(result.token, ARGUMENT_COMMON_SEL_RECENT)) {\n            result.did = g_display_manager.last_display_id;\n        } else if (token_equals(result.token, ARGUMENT_COMMON_SEL_MOUSE)) {\n            uint32_t did = display_manager_cursor_display_id();\n            if (did) {\n                result.did = did;\n            } else {\n                daemon_fail(rsp, \"could not locate display containing cursor.\\n\");\n            }\n        } else {\n            struct display_label *display_label = display_manager_get_display_for_label(&g_display_manager, value.string_value);\n            if (display_label) {\n                result.did_parse = true;\n                result.did = display_label->did;\n            } else {\n                result.did_parse = false;\n                daemon_fail(rsp, \"value '%.*s' is not a valid option for DISPLAY_SEL\\n\", result.token.length, result.token.text);\n            }\n        }\n    } else if (value.type == TOKEN_TYPE_INVALID) {\n        result.did_parse = false;\n        if (!optional) daemon_fail(rsp, \"value '%.*s' is not a valid option for DISPLAY_SEL\\n\", result.token.length, result.token.text);\n    } else {\n        result.did_parse = false;\n        daemon_fail(rsp, \"value '%.*s' is not a valid option for DISPLAY_SEL\\n\", result.token.length, result.token.text);\n    }\n\n    return result;\n}\n\nstatic struct selector parse_space_selector(FILE *rsp, char **message, uint64_t acting_sid, bool optional)\n{\n    TIME_FUNCTION;\n\n    struct selector result = { .token = get_token(message), .did_parse = true };\n\n    struct token_value value = token_to_value(result.token);\n    if (value.type == TOKEN_TYPE_INT) {\n        uint64_t sid = space_manager_mission_control_space(value.int_value);\n        if (sid) {\n            result.sid = sid;\n        } else {\n            daemon_fail(rsp, \"could not locate space with mission-control index '%d'.\\n\", value.int_value);\n        }\n    } else if (value.type == TOKEN_TYPE_STRING) {\n        if (token_equals(result.token, ARGUMENT_COMMON_SEL_PREV)) {\n            if (acting_sid) {\n                uint64_t sid = space_manager_prev_space(acting_sid);\n                if (sid) {\n                    result.sid = sid;\n                } else {\n                    daemon_fail(rsp, \"could not locate the previous space.\\n\");\n                }\n            } else {\n                daemon_fail(rsp, \"could not locate the selected space.\\n\");\n            }\n        } else if (token_equals(result.token, ARGUMENT_COMMON_SEL_NEXT)) {\n            if (acting_sid) {\n                uint64_t sid = space_manager_next_space(acting_sid);\n                if (sid) {\n                    result.sid = sid;\n                } else {\n                    daemon_fail(rsp, \"could not locate the next space.\\n\");\n                }\n            } else {\n                daemon_fail(rsp, \"could not locate the selected space.\\n\");\n            }\n        } else if (token_equals(result.token, ARGUMENT_COMMON_SEL_FIRST)) {\n            uint64_t sid = space_manager_first_space();\n            if (sid) {\n                result.sid = sid;\n            } else {\n                daemon_fail(rsp, \"could not locate the first space.\\n\");\n            }\n        } else if (token_equals(result.token, ARGUMENT_COMMON_SEL_LAST)) {\n            uint64_t sid = space_manager_last_space();\n            if (sid) {\n                result.sid = sid;\n            } else {\n                daemon_fail(rsp, \"could not locate the last space.\\n\");\n            }\n        } else if (token_equals(result.token, ARGUMENT_COMMON_SEL_RECENT)) {\n            result.sid = g_space_manager.last_space_id;\n        } else if (token_equals(result.token, ARGUMENT_COMMON_SEL_MOUSE)) {\n            uint64_t sid = space_manager_cursor_space();\n            if (sid) {\n                result.sid = sid;\n            } else {\n                daemon_fail(rsp, \"could not locate space containing cursor.\\n\");\n            }\n        } else {\n            struct space_label *space_label = space_manager_get_space_for_label(&g_space_manager, value.string_value);\n            if (space_label) {\n                result.did_parse = true;\n                result.sid = space_label->sid;\n            } else {\n                result.did_parse = false;\n                daemon_fail(rsp, \"value '%.*s' is not a valid option for SPACE_SEL\\n\", result.token.length, result.token.text);\n            }\n        }\n    } else if (value.type == TOKEN_TYPE_INVALID) {\n        result.did_parse = false;\n        if (!optional) daemon_fail(rsp, \"value '%.*s' is not a valid option for SPACE_SEL\\n\", result.token.length, result.token.text);\n    } else {\n        result.did_parse = false;\n        daemon_fail(rsp, \"value '%.*s' is not a valid option for SPACE_SEL\\n\", result.token.length, result.token.text);\n    }\n\n    return result;\n}\n\nstatic struct selector parse_window_selector(FILE *rsp, char **message, struct window *acting_window, bool optional)\n{\n    TIME_FUNCTION;\n\n    struct selector result = { .token = get_token(message), .did_parse = true };\n\n    struct token_value value = token_to_value(result.token);\n    if (value.type == TOKEN_TYPE_INT) {\n        struct window *window = window_manager_find_window(&g_window_manager, value.int_value);\n        if (window) {\n            result.window = window;\n        } else {\n            daemon_fail(rsp, \"could not locate window with the specified id '%d'.\\n\", value.int_value);\n        }\n    } else if (value.type == TOKEN_TYPE_STRING) {\n        if (token_equals(result.token, ARGUMENT_COMMON_SEL_NORTH)) {\n            if (acting_window) {\n                struct window *closest_window = window_manager_find_closest_managed_window_in_direction(&g_window_manager, acting_window, DIR_NORTH);\n                if (closest_window) {\n                    result.window = closest_window;\n                } else {\n                    daemon_fail(rsp, \"could not locate a northward managed window.\\n\");\n                }\n            } else {\n                daemon_fail(rsp, \"could not locate the selected window.\\n\");\n            }\n        } else if (token_equals(result.token, ARGUMENT_COMMON_SEL_EAST)) {\n            if (acting_window) {\n                struct window *closest_window = window_manager_find_closest_managed_window_in_direction(&g_window_manager, acting_window, DIR_EAST);\n                if (closest_window) {\n                    result.window = closest_window;\n                } else {\n                    daemon_fail(rsp, \"could not locate a eastward managed window.\\n\");\n                }\n            } else {\n                daemon_fail(rsp, \"could not locate the selected window.\\n\");\n            }\n        } else if (token_equals(result.token, ARGUMENT_COMMON_SEL_SOUTH)) {\n            if (acting_window) {\n                struct window *closest_window = window_manager_find_closest_managed_window_in_direction(&g_window_manager, acting_window, DIR_SOUTH);\n                if (closest_window) {\n                    result.window = closest_window;\n                } else {\n                    daemon_fail(rsp, \"could not locate a southward managed window.\\n\");\n                }\n            } else {\n                daemon_fail(rsp, \"could not locate the selected window.\\n\");\n            }\n        } else if (token_equals(result.token, ARGUMENT_COMMON_SEL_WEST)) {\n            if (acting_window) {\n                struct window *closest_window = window_manager_find_closest_managed_window_in_direction(&g_window_manager, acting_window, DIR_WEST);\n                if (closest_window) {\n                    result.window = closest_window;\n                } else {\n                    daemon_fail(rsp, \"could not locate a westward managed window.\\n\");\n                }\n            } else {\n                daemon_fail(rsp, \"could not locate the selected window.\\n\");\n            }\n        } else if (token_equals(result.token, ARGUMENT_COMMON_SEL_MOUSE)) {\n            struct window *mouse_window = window_manager_find_window_below_cursor(&g_window_manager);\n            if (mouse_window) {\n                result.window = mouse_window;\n            } else {\n                daemon_fail(rsp, \"could not locate a window below the cursor.\\n\");\n            }\n        } else if (token_equals(result.token, ARGUMENT_WINDOW_SEL_LARGEST)) {\n            struct window *area_window = window_manager_find_largest_managed_window(&g_space_manager, &g_window_manager);\n            if (area_window) {\n                result.window = area_window;\n            } else {\n                daemon_fail(rsp, \"could not locate window with the largest area.\\n\");\n            }\n        } else if (token_equals(result.token, ARGUMENT_WINDOW_SEL_SMALLEST)) {\n            struct window *area_window = window_manager_find_smallest_managed_window(&g_space_manager, &g_window_manager);\n            if (area_window) {\n                result.window = area_window;\n            } else {\n                daemon_fail(rsp, \"could not locate window with the smallest area.\\n\");\n            }\n        } else if (token_equals(result.token, ARGUMENT_WINDOW_SEL_SIBLING)) {\n            if (acting_window) {\n                struct window *sibling_window = window_manager_find_sibling_for_managed_window(&g_window_manager, acting_window);\n                if (sibling_window) {\n                    result.window = sibling_window;\n                } else {\n                    daemon_fail(rsp, \"could not locate sibling of window.\\n\");\n                }\n            } else {\n                daemon_fail(rsp, \"could not locate the selected window.\\n\");\n            }\n        } else if (token_equals(result.token, ARGUMENT_WINDOW_SEL_FNEPHEW)) {\n            if (acting_window) {\n                struct window *nephew_window = window_manager_find_first_nephew_for_managed_window(&g_window_manager, acting_window);\n                if (nephew_window) {\n                    result.window = nephew_window;\n                } else {\n                    daemon_fail(rsp, \"could not locate first nephew of window.\\n\");\n                }\n            } else {\n                daemon_fail(rsp, \"could not locate the selected window.\\n\");\n            }\n        } else if (token_equals(result.token, ARGUMENT_WINDOW_SEL_SNEPHEW)) {\n            if (acting_window) {\n                struct window *nephew_window = window_manager_find_second_nephew_for_managed_window(&g_window_manager, acting_window);\n                if (nephew_window) {\n                    result.window = nephew_window;\n                } else {\n                    daemon_fail(rsp, \"could not locate second nephew of window.\\n\");\n                }\n            } else {\n                daemon_fail(rsp, \"could not locate the selected window.\\n\");\n            }\n        } else if (token_equals(result.token, ARGUMENT_WINDOW_SEL_UNCLE)) {\n            if (acting_window) {\n                struct window *uncle_window = window_manager_find_uncle_for_managed_window(&g_window_manager, acting_window);\n                if (uncle_window) {\n                    result.window = uncle_window;\n                } else {\n                    daemon_fail(rsp, \"could not locate uncle of window.\\n\");\n                }\n            } else {\n                daemon_fail(rsp, \"could not locate the selected window.\\n\");\n            }\n        } else if (token_equals(result.token, ARGUMENT_WINDOW_SEL_FCOUSIN)) {\n            if (acting_window) {\n                struct window *cousin_window = window_manager_find_first_cousin_for_managed_window(&g_window_manager, acting_window);\n                if (cousin_window) {\n                    result.window = cousin_window;\n                } else {\n                    daemon_fail(rsp, \"could not locate first cousin of window.\\n\");\n                }\n            } else {\n                daemon_fail(rsp, \"could not locate the selected window.\\n\");\n            }\n        } else if (token_equals(result.token, ARGUMENT_WINDOW_SEL_SCOUSIN)) {\n            if (acting_window) {\n                struct window *cousin_window = window_manager_find_second_cousin_for_managed_window(&g_window_manager, acting_window);\n                if (cousin_window) {\n                    result.window = cousin_window;\n                } else {\n                    daemon_fail(rsp, \"could not locate second cousin of window.\\n\");\n                }\n            } else {\n                daemon_fail(rsp, \"could not locate the selected window.\\n\");\n            }\n        } else if (token_equals(result.token, ARGUMENT_COMMON_SEL_PREV)) {\n            if (acting_window) {\n                struct window *prev_window = window_manager_find_prev_managed_window(&g_space_manager, &g_window_manager, acting_window);\n                if (prev_window) {\n                    result.window = prev_window;\n                } else {\n                    daemon_fail(rsp, \"could not locate the prev managed window.\\n\");\n                }\n            } else {\n                daemon_fail(rsp, \"could not locate the selected window.\\n\");\n            }\n        } else if (token_equals(result.token, ARGUMENT_COMMON_SEL_NEXT)) {\n            if (acting_window) {\n                struct window *next_window = window_manager_find_next_managed_window(&g_space_manager, &g_window_manager, acting_window);\n                if (next_window) {\n                    result.window = next_window;\n                } else {\n                    daemon_fail(rsp, \"could not locate the next managed window.\\n\");\n                }\n            } else {\n                daemon_fail(rsp, \"could not locate the selected window.\\n\");\n            }\n        } else if (token_equals(result.token, ARGUMENT_COMMON_SEL_FIRST)) {\n            struct window *first_window = window_manager_find_first_managed_window(&g_space_manager, &g_window_manager);\n            if (first_window) {\n                result.window = first_window;\n            } else {\n                daemon_fail(rsp, \"could not locate the first managed window.\\n\");\n            }\n        } else if (token_equals(result.token, ARGUMENT_COMMON_SEL_LAST)) {\n            struct window *last_window = window_manager_find_last_managed_window(&g_space_manager, &g_window_manager);\n            if (last_window) {\n                result.window = last_window;\n            } else {\n                daemon_fail(rsp, \"could not locate the last managed window.\\n\");\n            }\n        } else if (token_equals(result.token, ARGUMENT_COMMON_SEL_RECENT)) {\n            struct window *recent_window = window_manager_find_recent_managed_window(&g_window_manager);\n            if (recent_window) {\n                result.window = recent_window;\n            } else {\n                daemon_fail(rsp, \"could not locate the most recently focused window.\\n\");\n            }\n        } else if (token_prefix(result.token, ARGUMENT_COMMON_SEL_STACK_PREFIX)) {\n            if (acting_window) {\n                int index;\n                result.token.text   += strlen(ARGUMENT_COMMON_SEL_STACK_PREFIX);\n                result.token.length -= strlen(ARGUMENT_COMMON_SEL_STACK_PREFIX);\n\n                if (token_equals(result.token, ARGUMENT_COMMON_SEL_PREV)) {\n                    struct window *prev_window = window_manager_find_prev_window_in_stack(&g_space_manager, &g_window_manager, acting_window);\n                    if (prev_window) {\n                        result.window = prev_window;\n                    } else {\n                        daemon_fail(rsp, \"could not locate the prev stacked window.\\n\");\n                    }\n                } else if (token_equals(result.token, ARGUMENT_COMMON_SEL_NEXT)) {\n                    struct window *next_window = window_manager_find_next_window_in_stack(&g_space_manager, &g_window_manager, acting_window);\n                    if (next_window) {\n                        result.window = next_window;\n                    } else {\n                        daemon_fail(rsp, \"could not locate the next stacked window.\\n\");\n                    }\n                } else if (token_equals(result.token, ARGUMENT_COMMON_SEL_FIRST)) {\n                    struct window *first_window = window_manager_find_first_window_in_stack(&g_space_manager, &g_window_manager, acting_window);\n                    if (first_window) {\n                        result.window = first_window;\n                    } else {\n                        daemon_fail(rsp, \"could not locate the first stacked window.\\n\");\n                    }\n                } else if (token_equals(result.token, ARGUMENT_COMMON_SEL_LAST)) {\n                    struct window *last_window = window_manager_find_last_window_in_stack(&g_space_manager, &g_window_manager, acting_window);\n                    if (last_window) {\n                        result.window = last_window;\n                    } else {\n                        daemon_fail(rsp, \"could not locate the last stacked window.\\n\");\n                    }\n                } else if (token_equals(result.token, ARGUMENT_COMMON_SEL_RECENT)) {\n                    struct window *recent_window = window_manager_find_recent_window_in_stack(&g_space_manager, &g_window_manager, acting_window);\n                    if (recent_window) {\n                        result.window = recent_window;\n                    } else {\n                        daemon_fail(rsp, \"could not locate the recent stacked window.\\n\");\n                    }\n                } else if (token_is_valid(result.token) && token_is_positive_integer(result.token, &index) && index > 0) {\n                    struct window *index_window = window_manager_find_window_in_stack(&g_space_manager, &g_window_manager, acting_window, index);\n                    if (index_window) {\n                        result.window = index_window;\n                    } else {\n                        daemon_fail(rsp, \"could not locate the stacked window in position %d.\\n\", index);\n                    }\n                } else {\n                    result.did_parse = false;\n                    daemon_fail(rsp, \"value '%s%.*s' is not a valid option for WINDOW_SEL\\n\", ARGUMENT_COMMON_SEL_STACK_PREFIX, result.token.length, result.token.text);\n                }\n            } else {\n                daemon_fail(rsp, \"could not locate the selected window.\\n\");\n            }\n        } else {\n            result.did_parse = false;\n            daemon_fail(rsp, \"value '%.*s' is not a valid option for WINDOW_SEL\\n\", result.token.length, result.token.text);\n        }\n    } else if (value.type == TOKEN_TYPE_INVALID) {\n        result.did_parse = false;\n        if (!optional) daemon_fail(rsp, \"value '%.*s' is not a valid option for WINDOW_SEL\\n\", result.token.length, result.token.text);\n    } else {\n        result.did_parse = false;\n        daemon_fail(rsp, \"value '%.*s' is not a valid option for WINDOW_SEL\\n\", result.token.length, result.token.text);\n    }\n\n    return result;\n}\n\nstatic struct selector parse_insert_selector(FILE *rsp, char **message)\n{\n    struct selector result = { .token = get_token(message), .did_parse = true };\n\n    if (token_equals(result.token, ARGUMENT_COMMON_SEL_NORTH)) {\n        result.dir = DIR_NORTH;\n    } else if (token_equals(result.token, ARGUMENT_COMMON_SEL_EAST)) {\n        result.dir = DIR_EAST;\n    } else if (token_equals(result.token, ARGUMENT_COMMON_SEL_SOUTH)) {\n        result.dir = DIR_SOUTH;\n    } else if (token_equals(result.token, ARGUMENT_COMMON_SEL_WEST)) {\n        result.dir = DIR_WEST;\n    } else if (token_equals(result.token, ARGUMENT_COMMON_SEL_STACK)) {\n        result.dir = STACK;\n    } else {\n        result.did_parse = false;\n        daemon_fail(rsp, \"value '%.*s' is not a valid option for DIR_SEL\\n\", result.token.length, result.token.text);\n    }\n\n    return result;\n}\n\nstatic void handle_domain_config(FILE *rsp, struct token domain, char *message)\n{\n    TIME_FUNCTION;\n\n    uint64_t sel_sid = 0;\n    struct token selector = get_token(&message);\n    struct token command  = selector;\n\n    bool found_selector = token_equals(selector, SELECTOR_CONFIG_SPACE);\n    if (found_selector) {\n        struct selector space_selector = parse_space_selector(rsp, &message, 0, false);\n        if (!space_selector.did_parse || !space_selector.sid) return;\n\n        sel_sid = space_selector.sid;\n        command = get_token(&message);\n    }\n\n    for (; token_is_valid(command); command = get_token(&message)) {\n        if (token_equals(command, COMMAND_CONFIG_DEBUG_OUTPUT)) {\n            struct token value = get_token(&message);\n            if (!token_is_valid(value)) {\n                fprintf(rsp, \"%s\\n\", bool_str[g_verbose]);\n            } else if (token_equals(value, ARGUMENT_COMMON_VAL_OFF)) {\n                g_verbose = false;\n            } else if (token_equals(value, ARGUMENT_COMMON_VAL_ON)) {\n                g_verbose = true;\n            } else {\n                daemon_fail(rsp, \"unknown value '%.*s' given to command '%.*s' for domain '%.*s'\\n\", value.length, value.text, command.length, command.text, domain.length, domain.text);\n            }\n        } else if (token_equals(command, COMMAND_CONFIG_MFF)) {\n            struct token value = get_token(&message);\n            if (!token_is_valid(value)) {\n                fprintf(rsp, \"%s\\n\", bool_str[g_window_manager.enable_mff]);\n            } else if (token_equals(value, ARGUMENT_COMMON_VAL_OFF)) {\n                g_window_manager.enable_mff = false;\n            } else if (token_equals(value, ARGUMENT_COMMON_VAL_ON)) {\n                g_window_manager.enable_mff = true;\n            } else {\n                daemon_fail(rsp, \"unknown value '%.*s' given to command '%.*s' for domain '%.*s'\\n\", value.length, value.text, command.length, command.text, domain.length, domain.text);\n            }\n        } else if (token_equals(command, COMMAND_CONFIG_FFM)) {\n            struct token value = get_token(&message);\n            if (!token_is_valid(value)) {\n                fprintf(rsp, \"%s\\n\", ffm_mode_str[g_window_manager.ffm_mode]);\n            } else if (token_equals(value, ARGUMENT_COMMON_VAL_OFF)) {\n                window_manager_set_focus_follows_mouse(&g_window_manager, FFM_DISABLED);\n            } else if (token_equals(value, ARGUMENT_CONFIG_FFM_AUTOFOCUS)) {\n                window_manager_set_focus_follows_mouse(&g_window_manager, FFM_AUTOFOCUS);\n            } else if (token_equals(value, ARGUMENT_CONFIG_FFM_AUTORAISE)) {\n                window_manager_set_focus_follows_mouse(&g_window_manager, FFM_AUTORAISE);\n            } else {\n                daemon_fail(rsp, \"unknown value '%.*s' given to command '%.*s' for domain '%.*s'\\n\", value.length, value.text, command.length, command.text, domain.length, domain.text);\n            }\n        } else if (token_equals(command, COMMAND_CONFIG_DISPLAY_ORDER)) {\n            struct token value = get_token(&message);\n            if (!token_is_valid(value)) {\n                fprintf(rsp, \"%s\\n\", display_arrangement_order_str[g_display_manager.order]);\n            } else if (token_equals(value, ARGUMENT_CONFIG_DISPLAY_ORDER_DEFAULT)) {\n                g_display_manager.order = DISPLAY_ARRANGEMENT_ORDER_DEFAULT;\n            } else if (token_equals(value, ARGUMENT_CONFIG_DISPLAY_ORDER_X)) {\n                g_display_manager.order = DISPLAY_ARRANGEMENT_ORDER_X;\n            } else if (token_equals(value, ARGUMENT_CONFIG_DISPLAY_ORDER_Y)) {\n                g_display_manager.order = DISPLAY_ARRANGEMENT_ORDER_Y;\n            } else {\n                daemon_fail(rsp, \"unknown value '%.*s' given to command '%.*s' for domain '%.*s'\\n\", value.length, value.text, command.length, command.text, domain.length, domain.text);\n            }\n        } else if (token_equals(command, COMMAND_CONFIG_WINDOW_ORIGIN)) {\n            struct token value = get_token(&message);\n            if (!token_is_valid(value)) {\n                fprintf(rsp, \"%s\\n\", window_origin_mode_str[g_window_manager.window_origin_mode]);\n            } else if (token_equals(value, ARGUMENT_CONFIG_WINDOW_ORIGIN_DEFAULT)) {\n                g_window_manager.window_origin_mode = WINDOW_ORIGIN_DEFAULT;\n            } else if (token_equals(value, ARGUMENT_CONFIG_WINDOW_ORIGIN_FOCUSED)) {\n                g_window_manager.window_origin_mode = WINDOW_ORIGIN_FOCUSED;\n            } else if (token_equals(value, ARGUMENT_CONFIG_WINDOW_ORIGIN_CURSOR)) {\n                g_window_manager.window_origin_mode = WINDOW_ORIGIN_CURSOR;\n            } else {\n                daemon_fail(rsp, \"unknown value '%.*s' given to command '%.*s' for domain '%.*s'\\n\", value.length, value.text, command.length, command.text, domain.length, domain.text);\n            }\n        } else if (token_equals(command, COMMAND_CONFIG_WINDOW_PLACEMENT)) {\n            struct token value = get_token(&message);\n            if (!token_is_valid(value)) {\n                fprintf(rsp, \"%s\\n\", window_node_child_str[g_space_manager.window_placement]);\n            } else if (token_equals(value, ARGUMENT_CONFIG_WINDOW_PLACEMENT_FST)) {\n                g_space_manager.window_placement = CHILD_FIRST;\n            } else if (token_equals(value, ARGUMENT_CONFIG_WINDOW_PLACEMENT_SND)) {\n                g_space_manager.window_placement = CHILD_SECOND;\n            } else {\n                daemon_fail(rsp, \"unknown value '%.*s' given to command '%.*s' for domain '%.*s'\\n\", value.length, value.text, command.length, command.text, domain.length, domain.text);\n            }\n        } else if (token_equals(command, COMMAND_CONFIG_WINDOW_INSERT_POINT)) {\n            struct token value = get_token(&message);\n            if (!token_is_valid(value)) {\n                fprintf(rsp, \"%s\\n\", window_insertion_point_str[g_space_manager.window_insertion_point]);\n            } else if (token_equals(value, ARGUMENT_CONFIG_WINDOW_INSERT_FOCUSED)) {\n                g_space_manager.window_insertion_point = INSERT_FOCUSED;\n            } else if (token_equals(value, ARGUMENT_CONFIG_WINDOW_INSERT_FIRST)) {\n                g_space_manager.window_insertion_point = INSERT_FIRST;\n            } else if (token_equals(value, ARGUMENT_CONFIG_WINDOW_INSERT_LAST)) {\n                g_space_manager.window_insertion_point = INSERT_LAST;\n            } else {\n                daemon_fail(rsp, \"unknown value '%.*s' given to command '%.*s' for domain '%.*s'\\n\", value.length, value.text, command.length, command.text, domain.length, domain.text);\n            }\n        } else if (token_equals(command, COMMAND_CONFIG_WINDOW_ZOOM_PERSIST)) {\n            struct token value = get_token(&message);\n            if (!token_is_valid(value)) {\n                fprintf(rsp, \"%s\\n\", bool_str[g_space_manager.window_zoom_persist]);\n            } else if (token_equals(value, ARGUMENT_COMMON_VAL_OFF)) {\n                g_space_manager.window_zoom_persist = false;\n            } else if (token_equals(value, ARGUMENT_COMMON_VAL_ON)) {\n                g_space_manager.window_zoom_persist = true;\n            } else {\n                daemon_fail(rsp, \"unknown value '%.*s' given to command '%.*s' for domain '%.*s'\\n\", value.length, value.text, command.length, command.text, domain.length, domain.text);\n            }\n        } else if (token_equals(command, COMMAND_CONFIG_OPACITY)) {\n            struct token value = get_token(&message);\n            if (!token_is_valid(value)) {\n                fprintf(rsp, \"%s\\n\", bool_str[g_window_manager.enable_window_opacity]);\n            } else if (token_equals(value, ARGUMENT_COMMON_VAL_OFF)) {\n                window_manager_set_window_opacity_enabled(&g_window_manager, false);\n            } else if (token_equals(value, ARGUMENT_COMMON_VAL_ON)) {\n                window_manager_set_window_opacity_enabled(&g_window_manager, true);\n            } else {\n                daemon_fail(rsp, \"unknown value '%.*s' given to command '%.*s' for domain '%.*s'\\n\", value.length, value.text, command.length, command.text, domain.length, domain.text);\n            }\n        } else if (token_equals(command, COMMAND_CONFIG_OPACITY_DURATION)) {\n            struct token_value value = token_to_value(get_token(&message));\n            if (value.type == TOKEN_TYPE_INVALID) {\n                fprintf(rsp, \"%f\\n\", g_window_manager.window_opacity_duration);\n            } else if (value.type == TOKEN_TYPE_FLOAT) {\n                g_window_manager.window_opacity_duration = value.float_value;\n            } else {\n                daemon_fail(rsp, \"unknown value '%.*s' given to command '%.*s' for domain '%.*s'\\n\", value.token.length, value.token.text, command.length, command.text, domain.length, domain.text);\n            }\n        } else if (token_equals(command, COMMAND_CONFIG_ANIMATION_DURATION)) {\n            struct token_value value = token_to_value(get_token(&message));\n            if (value.type == TOKEN_TYPE_INVALID) {\n                fprintf(rsp, \"%f\\n\", g_window_manager.window_animation_duration);\n            } else if (value.type == TOKEN_TYPE_FLOAT) {\n                if (value.float_value == 0.0f) {\n                    g_window_manager.window_animation_duration = value.float_value;\n                } else if (!scripting_addition_is_sip_friendly()) {\n                    daemon_fail(rsp, \"command '%.*s' for domain '%.*s' requires System Integrity Protection to be partially disabled! ignoring request..\\n\", command.length, command.text, domain.length, domain.text);\n                } else if (CGPreflightScreenCaptureAccess()) {\n                    g_window_manager.window_animation_duration = value.float_value;\n                } else {\n                    daemon_fail(rsp, \"command '%.*s' for domain '%.*s' requires Screen Recording permissions! ignoring request..\\n\", command.length, command.text, domain.length, domain.text);\n                    CGRequestScreenCaptureAccess();\n                }\n            } else {\n                daemon_fail(rsp, \"unknown value '%.*s' given to command '%.*s' for domain '%.*s'\\n\", value.token.length, value.token.text, command.length, command.text, domain.length, domain.text);\n            }\n        } else if (token_equals(command, COMMAND_CONFIG_ANIMATION_EASING)) {\n            struct token value = get_token(&message);\n            if (!token_is_valid(value)) {\n                fprintf(rsp, \"%s\\n\", animation_easing_type_str[g_window_manager.window_animation_easing]);\n            } else {\n                bool match = false;\n                for (int i = 0; i < EASING_TYPE_COUNT; ++i) {\n                    if (token_equals(value, animation_easing_type_str[i])) {\n                        g_window_manager.window_animation_easing = i;\n                        match = true;\n                        break;\n                    }\n                }\n                if (!match) daemon_fail(rsp, \"unknown value '%.*s' given to command '%.*s' for domain '%.*s'\\n\", value.length, value.text, command.length, command.text, domain.length, domain.text);\n            }\n        } else if (token_equals(command, COMMAND_CONFIG_SHADOW)) {\n            struct token value = get_token(&message);\n            if (!token_is_valid(value)) {\n                fprintf(rsp, \"%s\\n\", purify_mode_str[g_window_manager.purify_mode]);\n            } else if (token_equals(value, ARGUMENT_COMMON_VAL_OFF)) {\n                window_manager_set_purify_mode(&g_window_manager, PURIFY_ALWAYS);\n            } else if (token_equals(value, ARGUMENT_CONFIG_SHADOW_FLT)) {\n                window_manager_set_purify_mode(&g_window_manager, PURIFY_MANAGED);\n            } else if (token_equals(value, ARGUMENT_COMMON_VAL_ON)) {\n                window_manager_set_purify_mode(&g_window_manager, PURIFY_DISABLED);\n            } else {\n                daemon_fail(rsp, \"unknown value '%.*s' given to command '%.*s' for domain '%.*s'\\n\", value.length, value.text, command.length, command.text, domain.length, domain.text);\n            }\n        } else if (token_equals(command, COMMAND_CONFIG_MENUBAR_OPACITY)) {\n            struct token_value value = token_to_value(get_token(&message));\n            if (value.type == TOKEN_TYPE_INVALID) {\n                fprintf(rsp, \"%.4f\\n\", g_window_manager.menubar_opacity);\n            } else if (value.type == TOKEN_TYPE_FLOAT && in_range_ii(value.float_value, 0.0f, 1.0f)) {\n                window_manager_set_menubar_opacity(&g_window_manager, value.float_value);\n            } else {\n                daemon_fail(rsp, \"unknown value '%.*s' given to command '%.*s' for domain '%.*s'\\n\", value.token.length, value.token.text, command.length, command.text, domain.length, domain.text);\n            }\n        } else if (token_equals(command, COMMAND_CONFIG_ACTIVE_WINDOW_OPACITY)) {\n            struct token_value value = token_to_value(get_token(&message));\n            if (value.type == TOKEN_TYPE_INVALID) {\n                fprintf(rsp, \"%.4f\\n\", g_window_manager.active_window_opacity);\n            } else if (value.type == TOKEN_TYPE_FLOAT && in_range_ei(value.float_value, 0.0f, 1.0f)) {\n                window_manager_set_active_window_opacity(&g_window_manager, value.float_value);\n            } else {\n                daemon_fail(rsp, \"unknown value '%.*s' given to command '%.*s' for domain '%.*s'\\n\", value.token.length, value.token.text, command.length, command.text, domain.length, domain.text);\n            }\n        } else if (token_equals(command, COMMAND_CONFIG_NORMAL_WINDOW_OPACITY)) {\n            struct token_value value = token_to_value(get_token(&message));\n            if (value.type == TOKEN_TYPE_INVALID) {\n                fprintf(rsp, \"%.4f\\n\", g_window_manager.normal_window_opacity);\n            } else if (value.type == TOKEN_TYPE_FLOAT && in_range_ei(value.float_value, 0.0f, 1.0f)) {\n                window_manager_set_normal_window_opacity(&g_window_manager, value.float_value);\n            } else {\n                daemon_fail(rsp, \"unknown value '%.*s' given to command '%.*s' for domain '%.*s'\\n\", value.token.length, value.token.text, command.length, command.text, domain.length, domain.text);\n            }\n        } else if (token_equals(command, COMMAND_CONFIG_INSERT_FEEDBACK_COLOR)) {\n            struct token_value value = token_to_value(get_token(&message));\n            if (value.type == TOKEN_TYPE_INVALID) {\n                fprintf(rsp, \"0x%x\\n\", g_window_manager.insert_feedback_color.p);\n            } else if (value.type == TOKEN_TYPE_U32 && value.u32_value) {\n                g_window_manager.insert_feedback_color = rgba_color_from_hex(value.u32_value);\n            } else {\n                daemon_fail(rsp, \"unknown value '%.*s' given to command '%.*s' for domain '%.*s'\\n\", value.token.length, value.token.text, command.length, command.text, domain.length, domain.text);\n            }\n        } else if (token_equals(command, COMMAND_CONFIG_TOP_PADDING)) {\n            struct token_value value = token_to_value(get_token(&message));\n            if (sel_sid) {\n                struct view *view = space_manager_find_view(&g_space_manager, sel_sid);\n                if (value.type == TOKEN_TYPE_INVALID) {\n                    fprintf(rsp, \"%d\\n\", view->top_padding);\n                } else if (value.type == TOKEN_TYPE_INT) {\n                    view_set_flag(view, VIEW_TOP_PADDING);\n                    view->top_padding = value.int_value;\n                    view_update(view);\n                    view_flush(view);\n                } else {\n                    daemon_fail(rsp, \"unknown value '%.*s' given to command '%.*s' for domain '%.*s'\\n\", value.token.length, value.token.text, command.length, command.text, domain.length, domain.text);\n                }\n            } else {\n                if (value.type == TOKEN_TYPE_INVALID) {\n                    fprintf(rsp, \"%d\\n\", g_space_manager.top_padding);\n                } else if (value.type == TOKEN_TYPE_INT) {\n                    space_manager_set_top_padding_for_all_spaces(&g_space_manager, value.int_value);\n                } else {\n                    daemon_fail(rsp, \"unknown value '%.*s' given to command '%.*s' for domain '%.*s'\\n\", value.token.length, value.token.text, command.length, command.text, domain.length, domain.text);\n                }\n            }\n        } else if (token_equals(command, COMMAND_CONFIG_BOTTOM_PADDING)) {\n            struct token_value value = token_to_value(get_token(&message));\n            if (sel_sid) {\n                struct view *view = space_manager_find_view(&g_space_manager, sel_sid);\n                if (value.type == TOKEN_TYPE_INVALID) {\n                    fprintf(rsp, \"%d\\n\", view->bottom_padding);\n                } else if (value.type == TOKEN_TYPE_INT) {\n                    view_set_flag(view, VIEW_BOTTOM_PADDING);\n                    view->bottom_padding = value.int_value;\n                    view_update(view);\n                    view_flush(view);\n                } else {\n                    daemon_fail(rsp, \"unknown value '%.*s' given to command '%.*s' for domain '%.*s'\\n\", value.token.length, value.token.text, command.length, command.text, domain.length, domain.text);\n                }\n            } else {\n                if (value.type == TOKEN_TYPE_INVALID) {\n                    fprintf(rsp, \"%d\\n\", g_space_manager.bottom_padding);\n                } else if (value.type == TOKEN_TYPE_INT) {\n                    space_manager_set_bottom_padding_for_all_spaces(&g_space_manager, value.int_value);\n                } else {\n                    daemon_fail(rsp, \"unknown value '%.*s' given to command '%.*s' for domain '%.*s'\\n\", value.token.length, value.token.text, command.length, command.text, domain.length, domain.text);\n                }\n            }\n        } else if (token_equals(command, COMMAND_CONFIG_LEFT_PADDING)) {\n            struct token_value value = token_to_value(get_token(&message));\n            if (sel_sid) {\n                struct view *view = space_manager_find_view(&g_space_manager, sel_sid);\n                if (value.type == TOKEN_TYPE_INVALID) {\n                    fprintf(rsp, \"%d\\n\", view->left_padding);\n                } else if (value.type == TOKEN_TYPE_INT) {\n                    view_set_flag(view, VIEW_LEFT_PADDING);\n                    view->left_padding = value.int_value;\n                    view_update(view);\n                    view_flush(view);\n                } else {\n                    daemon_fail(rsp, \"unknown value '%.*s' given to command '%.*s' for domain '%.*s'\\n\", value.token.length, value.token.text, command.length, command.text, domain.length, domain.text);\n                }\n            } else {\n                if (value.type == TOKEN_TYPE_INVALID) {\n                    fprintf(rsp, \"%d\\n\", g_space_manager.left_padding);\n                } else if (value.type == TOKEN_TYPE_INT) {\n                    space_manager_set_left_padding_for_all_spaces(&g_space_manager, value.int_value);\n                } else {\n                    daemon_fail(rsp, \"unknown value '%.*s' given to command '%.*s' for domain '%.*s'\\n\", value.token.length, value.token.text, command.length, command.text, domain.length, domain.text);\n                }\n            }\n        } else if (token_equals(command, COMMAND_CONFIG_RIGHT_PADDING)) {\n            struct token_value value = token_to_value(get_token(&message));\n            if (sel_sid) {\n                struct view *view = space_manager_find_view(&g_space_manager, sel_sid);\n                if (value.type == TOKEN_TYPE_INVALID) {\n                    fprintf(rsp, \"%d\\n\", view->right_padding);\n                } else if (value.type == TOKEN_TYPE_INT) {\n                    view_set_flag(view, VIEW_RIGHT_PADDING);\n                    view->right_padding = value.int_value;\n                    view_update(view);\n                    view_flush(view);\n                } else {\n                    daemon_fail(rsp, \"unknown value '%.*s' given to command '%.*s' for domain '%.*s'\\n\", value.token.length, value.token.text, command.length, command.text, domain.length, domain.text);\n                }\n            } else {\n                if (value.type == TOKEN_TYPE_INVALID) {\n                    fprintf(rsp, \"%d\\n\", g_space_manager.right_padding);\n                } else if (value.type == TOKEN_TYPE_INT) {\n                    space_manager_set_right_padding_for_all_spaces(&g_space_manager, value.int_value);\n                } else {\n                    daemon_fail(rsp, \"unknown value '%.*s' given to command '%.*s' for domain '%.*s'\\n\", value.token.length, value.token.text, command.length, command.text, domain.length, domain.text);\n                }\n            }\n        } else if (token_equals(command, COMMAND_CONFIG_WINDOW_GAP)) {\n            struct token_value value = token_to_value(get_token(&message));\n            if (sel_sid) {\n                struct view *view = space_manager_find_view(&g_space_manager, sel_sid);\n                if (value.type == TOKEN_TYPE_INVALID) {\n                    fprintf(rsp, \"%d\\n\", view->window_gap);\n                } else if (value.type == TOKEN_TYPE_INT) {\n                    view_set_flag(view, VIEW_WINDOW_GAP);\n                    view->window_gap = value.int_value;\n                    view_update(view);\n                    view_flush(view);\n                } else {\n                    daemon_fail(rsp, \"unknown value '%.*s' given to command '%.*s' for domain '%.*s'\\n\", value.token.length, value.token.text, command.length, command.text, domain.length, domain.text);\n                }\n            } else {\n                if (value.type == TOKEN_TYPE_INVALID) {\n                    fprintf(rsp, \"%d\\n\", g_space_manager.window_gap);\n                } else if (value.type == TOKEN_TYPE_INT) {\n                    space_manager_set_window_gap_for_all_spaces(&g_space_manager, value.int_value);\n                } else {\n                    daemon_fail(rsp, \"unknown value '%.*s' given to command '%.*s' for domain '%.*s'\\n\", value.token.length, value.token.text, command.length, command.text, domain.length, domain.text);\n                }\n            }\n        } else if (token_equals(command, COMMAND_CONFIG_LAYOUT)) {\n            struct token value = get_token(&message);\n            if (sel_sid) {\n                struct view *view = space_manager_find_view(&g_space_manager, sel_sid);\n                if (!token_is_valid(value)) {\n                    fprintf(rsp, \"%s\\n\", view_type_str[view->layout]);\n                } else if (token_equals(value, ARGUMENT_CONFIG_LAYOUT_BSP)) {\n                    if (space_is_user(sel_sid)) {\n                        view_set_flag(view, VIEW_LAYOUT);\n                        view->layout = VIEW_BSP;\n                        view_clear(view);\n                        window_manager_validate_and_check_for_windows_on_space(&g_space_manager, &g_window_manager, sel_sid);\n                    } else {\n                        daemon_fail(rsp, \"cannot set layout for a macOS fullscreen space!\\n\");\n                    }\n                } else if (token_equals(value, ARGUMENT_CONFIG_LAYOUT_STACK)) {\n                    if (space_is_user(sel_sid)) {\n                        view_set_flag(view, VIEW_LAYOUT);\n                        view->layout = VIEW_STACK;\n                        view_clear(view);\n                        window_manager_validate_and_check_for_windows_on_space(&g_space_manager, &g_window_manager, sel_sid);\n                    } else {\n                        daemon_fail(rsp, \"cannot set layout for a macOS fullscreen space!\\n\");\n                    }\n                } else if (token_equals(value, ARGUMENT_CONFIG_LAYOUT_FLOAT)) {\n                    if (space_is_user(sel_sid)) {\n                        view_set_flag(view, VIEW_LAYOUT);\n                        view->layout = VIEW_FLOAT;\n                        view_clear(view);\n                    } else {\n                        daemon_fail(rsp, \"cannot set layout for a macOS fullscreen space!\\n\");\n                    }\n                } else {\n                    daemon_fail(rsp, \"unknown value '%.*s' given to command '%.*s' for domain '%.*s'\\n\", value.length, value.text, command.length, command.text, domain.length, domain.text);\n                }\n            } else {\n                if (!token_is_valid(value)) {\n                    fprintf(rsp, \"%s\\n\", view_type_str[g_space_manager.layout]);\n                } else if (token_equals(value, ARGUMENT_CONFIG_LAYOUT_BSP)) {\n                    space_manager_set_layout_for_all_spaces(&g_space_manager, VIEW_BSP);\n                } else if (token_equals(value, ARGUMENT_CONFIG_LAYOUT_STACK)) {\n                    space_manager_set_layout_for_all_spaces(&g_space_manager, VIEW_STACK);\n                } else if (token_equals(value, ARGUMENT_CONFIG_LAYOUT_FLOAT)) {\n                    space_manager_set_layout_for_all_spaces(&g_space_manager, VIEW_FLOAT);\n                } else {\n                    daemon_fail(rsp, \"unknown value '%.*s' given to command '%.*s' for domain '%.*s'\\n\", value.length, value.text, command.length, command.text, domain.length, domain.text);\n                }\n            }\n        } else if (token_equals(command, COMMAND_CONFIG_SPLIT_RATIO)) {\n            struct token_value value = token_to_value(get_token(&message));\n            if (value.type == TOKEN_TYPE_INVALID) {\n                fprintf(rsp, \"%.4f\\n\", g_space_manager.split_ratio);\n            } else if (value.type == TOKEN_TYPE_FLOAT && in_range_ii(value.float_value, 0.1f, 0.9f)) {\n                g_space_manager.split_ratio = value.float_value;\n            } else {\n                daemon_fail(rsp, \"unknown value '%.*s' given to command '%.*s' for domain '%.*s'\\n\", value.token.length, value.token.text, command.length, command.text, domain.length, domain.text);\n            }\n        } else if (token_equals(command, COMMAND_CONFIG_SPLIT_TYPE)) {\n            struct token value = get_token(&message);\n            if (sel_sid) {\n                struct view *view = space_manager_find_view(&g_space_manager, sel_sid);\n                if (!token_is_valid(value)) {\n                    fprintf(rsp, \"%s\\n\", window_node_split_str[view->split_type]);\n                } else if (token_equals(value, ARGUMENT_CONFIG_SPLIT_TYPE_Y)) {\n                    view_set_flag(view, VIEW_SPLIT_TYPE);\n                    view->split_type = SPLIT_Y;\n                } else if (token_equals(value, ARGUMENT_CONFIG_SPLIT_TYPE_X)) {\n                    view_set_flag(view, VIEW_SPLIT_TYPE);\n                    view->split_type = SPLIT_X;\n                } else if (token_equals(value, ARGUMENT_CONFIG_SPLIT_TYPE_AUTO)) {\n                    view_set_flag(view, VIEW_SPLIT_TYPE);\n                    view->split_type = SPLIT_AUTO;\n                } else {\n                    daemon_fail(rsp, \"unknown value '%.*s' given to command '%.*s' for domain '%.*s'\\n\", value.length, value.text, command.length, command.text, domain.length, domain.text);\n                }\n            } else {\n                if (!token_is_valid(value)) {\n                    fprintf(rsp, \"%s\\n\", window_node_split_str[g_space_manager.split_type]);\n                } else if (token_equals(value, ARGUMENT_CONFIG_SPLIT_TYPE_Y)) {\n                    space_manager_set_split_type_for_all_spaces(&g_space_manager, SPLIT_Y);\n                } else if (token_equals(value, ARGUMENT_CONFIG_SPLIT_TYPE_X)) {\n                    space_manager_set_split_type_for_all_spaces(&g_space_manager, SPLIT_X);\n                } else if (token_equals(value, ARGUMENT_CONFIG_SPLIT_TYPE_AUTO)) {\n                    space_manager_set_split_type_for_all_spaces(&g_space_manager, SPLIT_AUTO);\n                } else {\n                    daemon_fail(rsp, \"unknown value '%.*s' given to command '%.*s' for domain '%.*s'\\n\", value.length, value.text, command.length, command.text, domain.length, domain.text);\n                }\n            }\n        } else if (token_equals(command, COMMAND_CONFIG_AUTO_BALANCE)) {\n            struct token value = get_token(&message);\n            if (sel_sid) {\n                struct view *view = space_manager_find_view(&g_space_manager, sel_sid);\n                if (!token_is_valid(value)) {\n                    fprintf(rsp, \"%s\\n\", auto_balance_str[view->auto_balance]);\n                } else if (token_equals(value, ARGUMENT_COMMON_VAL_OFF)) {\n                    view_set_flag(view, VIEW_AUTO_BALANCE);\n                    view->auto_balance = SPLIT_NONE;\n                } else if (token_equals(value, ARGUMENT_COMMON_VAL_ON)) {\n                    view_set_flag(view, VIEW_AUTO_BALANCE);\n                    view->auto_balance = SPLIT_X | SPLIT_Y;\n                } else if (token_equals(value, ARGUMENT_COMMON_VAL_AXIS_X)) {\n                    view_set_flag(view, VIEW_AUTO_BALANCE);\n                    view->auto_balance = SPLIT_X;\n                } else if (token_equals(value, ARGUMENT_COMMON_VAL_AXIS_Y)) {\n                    view_set_flag(view, VIEW_AUTO_BALANCE);\n                    view->auto_balance = SPLIT_Y;\n                } else {\n                    daemon_fail(rsp, \"unknown value '%.*s' given to command '%.*s' for domain '%.*s'\\n\", value.length, value.text, command.length, command.text, domain.length, domain.text);\n                }\n            } else {\n                if (!token_is_valid(value)) {\n                    fprintf(rsp, \"%s\\n\", auto_balance_str[g_space_manager.auto_balance]);\n                } else if (token_equals(value, ARGUMENT_COMMON_VAL_OFF)) {\n                    space_manager_set_auto_balance_for_all_spaces(&g_space_manager, SPLIT_NONE);\n                } else if (token_equals(value, ARGUMENT_COMMON_VAL_ON)) {\n                    space_manager_set_auto_balance_for_all_spaces(&g_space_manager, SPLIT_X | SPLIT_Y);\n                } else if (token_equals(value, ARGUMENT_COMMON_VAL_AXIS_X)) {\n                    space_manager_set_auto_balance_for_all_spaces(&g_space_manager, SPLIT_X);\n                } else if (token_equals(value, ARGUMENT_COMMON_VAL_AXIS_Y)) {\n                    space_manager_set_auto_balance_for_all_spaces(&g_space_manager, SPLIT_Y);\n                } else {\n                    daemon_fail(rsp, \"unknown value '%.*s' given to command '%.*s' for domain '%.*s'\\n\", value.length, value.text, command.length, command.text, domain.length, domain.text);\n                }\n            }\n        } else if (token_equals(command, COMMAND_CONFIG_MOUSE_MOD)) {\n            struct token value = get_token(&message);\n            if (!token_is_valid(value)) {\n                fprintf(rsp, \"%s\\n\", mouse_mod_str[g_mouse_state.modifier]);\n            } else if (token_equals(value, ARGUMENT_CONFIG_MOUSE_MOD_ALT)) {\n                g_mouse_state.modifier = MOUSE_MOD_ALT;\n            } else if (token_equals(value, ARGUMENT_CONFIG_MOUSE_MOD_SHIFT)) {\n                g_mouse_state.modifier = MOUSE_MOD_SHIFT;\n            } else if (token_equals(value, ARGUMENT_CONFIG_MOUSE_MOD_CMD)) {\n                g_mouse_state.modifier = MOUSE_MOD_CMD;\n            } else if (token_equals(value, ARGUMENT_CONFIG_MOUSE_MOD_CTRL)) {\n                g_mouse_state.modifier = MOUSE_MOD_CTRL;\n            } else if (token_equals(value, ARGUMENT_CONFIG_MOUSE_MOD_FN)) {\n                g_mouse_state.modifier = MOUSE_MOD_FN;\n            } else {\n                daemon_fail(rsp, \"unknown value '%.*s' given to command '%.*s' for domain '%.*s'\\n\", value.length, value.text, command.length, command.text, domain.length, domain.text);\n            }\n        } else if (token_equals(command, COMMAND_CONFIG_MOUSE_ACTION1)) {\n            struct token value = get_token(&message);\n            if (!token_is_valid(value)) {\n                fprintf(rsp, \"%s\\n\", mouse_mode_str[g_mouse_state.action1]);\n            } else if (token_equals(value, ARGUMENT_CONFIG_MOUSE_ACTION_MOVE)) {\n                g_mouse_state.action1 = MOUSE_MODE_MOVE;\n            } else if (token_equals(value, ARGUMENT_CONFIG_MOUSE_ACTION_RESIZE)) {\n                g_mouse_state.action1 = MOUSE_MODE_RESIZE;\n            } else {\n                daemon_fail(rsp, \"unknown value '%.*s' given to command '%.*s' for domain '%.*s'\\n\", value.length, value.text, command.length, command.text, domain.length, domain.text);\n            }\n        } else if (token_equals(command, COMMAND_CONFIG_MOUSE_ACTION2)) {\n            struct token value = get_token(&message);\n            if (!token_is_valid(value)) {\n                fprintf(rsp, \"%s\\n\", mouse_mode_str[g_mouse_state.action2]);\n            } else if (token_equals(value, ARGUMENT_CONFIG_MOUSE_ACTION_MOVE)) {\n                g_mouse_state.action2 = MOUSE_MODE_MOVE;\n            } else if (token_equals(value, ARGUMENT_CONFIG_MOUSE_ACTION_RESIZE)) {\n                g_mouse_state.action2 = MOUSE_MODE_RESIZE;\n            } else {\n                daemon_fail(rsp, \"unknown value '%.*s' given to command '%.*s' for domain '%.*s'\\n\", value.length, value.text, command.length, command.text, domain.length, domain.text);\n            }\n        } else if (token_equals(command, COMMAND_CONFIG_MOUSE_DROP_ACTION)) {\n            struct token value = get_token(&message);\n            if (!token_is_valid(value)) {\n                fprintf(rsp, \"%s\\n\", mouse_mode_str[g_mouse_state.drop_action]);\n            } else if (token_equals(value, ARGUMENT_CONFIG_MOUSE_ACTION_SWAP)) {\n                g_mouse_state.drop_action = MOUSE_MODE_SWAP;\n            } else if (token_equals(value, ARGUMENT_CONFIG_MOUSE_ACTION_STACK)) {\n                g_mouse_state.drop_action = MOUSE_MODE_STACK;\n            } else {\n                daemon_fail(rsp, \"unknown value '%.*s' given to command '%.*s' for domain '%.*s'\\n\", value.length, value.text, command.length, command.text, domain.length, domain.text);\n            }\n        } else if (token_equals(command, COMMAND_CONFIG_EXTERNAL_BAR)) {\n            int t, b;\n            char mode[6];\n            struct token value = get_token(&message);\n            if ((sscanf(value.text, ARGUMENT_CONFIG_EXTERNAL_BAR, mode, &t, &b) == 3)) {\n                if (string_equals(mode, ARGUMENT_CONFIG_EXTERNAL_BAR_MAIN)) {\n                    g_display_manager.mode = EXTERNAL_BAR_MAIN;\n                    g_display_manager.top_padding = t;\n                    g_display_manager.bottom_padding = b;\n                    space_manager_mark_spaces_invalid(&g_space_manager);\n                } else if (string_equals(mode, ARGUMENT_CONFIG_EXTERNAL_BAR_ALL)) {\n                    g_display_manager.mode = EXTERNAL_BAR_ALL;\n                    g_display_manager.top_padding = t;\n                    g_display_manager.bottom_padding = b;\n                    space_manager_mark_spaces_invalid(&g_space_manager);\n                } else if (string_equals(mode, ARGUMENT_COMMON_VAL_OFF)) {\n                    g_display_manager.mode = EXTERNAL_BAR_OFF;\n                    g_display_manager.top_padding = t;\n                    g_display_manager.bottom_padding = b;\n                    space_manager_mark_spaces_invalid(&g_space_manager);\n                } else {\n                    daemon_fail(rsp, \"unknown mode '%s' specified in value '%.*s' given to command '%.*s' for domain '%.*s'\\n\", mode, value.length, value.text, command.length, command.text, domain.length, domain.text);\n                }\n            } else {\n                fprintf(rsp, \"%s:%d:%d\\n\", external_bar_mode_str[g_display_manager.mode], g_display_manager.top_padding, g_display_manager.bottom_padding);\n            }\n        } else {\n            daemon_fail(rsp, \"unknown command '%.*s' for domain '%.*s'\\n\", command.length, command.text, domain.length, domain.text);\n        }\n    }\n}\n\nstatic void handle_domain_display(FILE *rsp, struct token domain, char *message)\n{\n    TIME_FUNCTION;\n\n    struct token command;\n    uint32_t acting_did = display_manager_active_display_id();\n    struct selector selector = parse_display_selector(NULL, &message, acting_did, true);\n\n    if (selector.did_parse) {\n        acting_did = selector.did;\n        command = get_token(&message);\n    } else {\n        command = selector.token;\n    }\n\n    if (!acting_did) {\n        daemon_fail(rsp, \"could not locate the display to act on!\\n\");\n        return;\n    }\n\n    if (token_equals(command, COMMAND_DISPLAY_FOCUS)) {\n        struct selector selector = parse_display_selector(rsp, &message, acting_did, false);\n        if (selector.did_parse && selector.did) {\n            if (acting_did != selector.did) {\n                display_manager_focus_display(selector.did, display_space_id(selector.did));\n            } else {\n                daemon_fail(rsp, \"cannot focus an already focused display.\\n\");\n            }\n        }\n    } else if (token_equals(command, COMMAND_DISPLAY_SPACE)) {\n        struct selector selector = parse_space_selector(rsp, &message, display_space_id(acting_did), false);\n        if (selector.did_parse && selector.sid) {\n            enum space_op_error result = display_manager_focus_space(acting_did, selector.sid);\n            if (result == SPACE_OP_ERROR_SAME_DISPLAY) {\n                daemon_fail(rsp, \"acting display does not contain the given space.\\n\");\n            } else if (result == SPACE_OP_ERROR_DISPLAY_IS_ANIMATING) {\n                daemon_fail(rsp, \"cannot focus space because the display is in the middle of an animation.\\n\");\n            } else if (result == SPACE_OP_ERROR_IN_MISSION_CONTROL) {\n                daemon_fail(rsp, \"cannot focus space because mission-control is active.\\n\");\n            } else if (result == SPACE_OP_ERROR_SCRIPTING_ADDITION) {\n                daemon_fail(rsp, \"cannot focus space due to an error with the scripting-addition.\\n\");\n            }\n        }\n    } else if (token_equals(command, COMMAND_DISPLAY_LABEL)) {\n        char *label;\n        if (parse_label(rsp, get_token(&message), LABEL_DISPLAY, &label)) {\n            if (label) {\n                display_manager_set_label_for_display(&g_display_manager, acting_did, label);\n            } else {\n                if (!display_manager_remove_label_for_display(&g_display_manager, acting_did)) {\n                    daemon_fail(rsp, \"the selected display was not associated with a label!\\n\");\n                }\n            }\n        }\n    } else {\n        daemon_fail(rsp, \"unknown command '%.*s' for domain '%.*s'\\n\", command.length, command.text, domain.length, domain.text);\n    }\n}\n\nstatic void handle_domain_space(FILE *rsp, struct token domain, char *message)\n{\n    TIME_FUNCTION;\n\n    struct token command;\n    uint64_t acting_sid = space_manager_active_space();\n    struct selector selector = parse_space_selector(NULL, &message, acting_sid, true);\n\n    if (selector.did_parse) {\n        acting_sid = selector.sid;\n        command = get_token(&message);\n    } else {\n        command = selector.token;\n    }\n\n    if (!acting_sid) {\n        daemon_fail(rsp, \"could not locate the space to act on!\\n\");\n        return;\n    }\n\n    for (; token_is_valid(command); command = get_token(&message)) {\n        if (token_equals(command, COMMAND_SPACE_FOCUS)) {\n            struct selector selector = parse_space_selector(rsp, &message, acting_sid, false);\n            if (selector.did_parse && selector.sid) {\n                enum space_op_error result = space_manager_focus_space(selector.sid);\n                if (result == SPACE_OP_ERROR_SAME_SPACE) {\n                    daemon_fail(rsp, \"cannot focus an already focused space.\\n\");\n                } else if (result == SPACE_OP_ERROR_DISPLAY_IS_ANIMATING) {\n                    daemon_fail(rsp, \"cannot focus space because the display is in the middle of an animation.\\n\");\n                } else if (result == SPACE_OP_ERROR_IN_MISSION_CONTROL) {\n                    daemon_fail(rsp, \"cannot focus space because mission-control is active.\\n\");\n                } else if (result == SPACE_OP_ERROR_SCRIPTING_ADDITION) {\n                    daemon_fail(rsp, \"cannot focus space due to an error with the scripting-addition.\\n\");\n                }\n            }\n        } else if (token_equals(command, COMMAND_SPACE_SWITCH)) {\n            struct selector selector = parse_space_selector(rsp, &message, acting_sid, false);\n            if (selector.did_parse && selector.sid) {\n                enum space_op_error result = space_manager_switch_space(selector.sid);\n                if (result == SPACE_OP_ERROR_SAME_SPACE) {\n                    daemon_fail(rsp, \"cannot focus an already focused space.\\n\");\n                } else if (result == SPACE_OP_ERROR_DISPLAY_IS_ANIMATING) {\n                    daemon_fail(rsp, \"cannot focus space because the display is in the middle of an animation.\\n\");\n                } else if (result == SPACE_OP_ERROR_IN_MISSION_CONTROL) {\n                    daemon_fail(rsp, \"cannot focus space because mission-control is active.\\n\");\n                } else if (result == SPACE_OP_ERROR_SCRIPTING_ADDITION) {\n                    daemon_fail(rsp, \"cannot focus space due to an error with the scripting-addition.\\n\");\n                }\n            }\n        } else if (token_equals(command, COMMAND_SPACE_MOVE)) {\n            struct selector selector = parse_space_selector(rsp, &message, acting_sid, false);\n            if (selector.did_parse && selector.sid) {\n                enum space_op_error result = space_manager_move_space_to_space(acting_sid, selector.sid);\n                if (result == SPACE_OP_ERROR_SAME_SPACE) {\n                    daemon_fail(rsp, \"cannot move space to itself.\\n\");\n                } else if (result == SPACE_OP_ERROR_SAME_DISPLAY) {\n                    daemon_fail(rsp, \"cannot move space across display boundaries. use --display instead.\\n\");\n                } else if (result == SPACE_OP_ERROR_DISPLAY_IS_ANIMATING) {\n                    daemon_fail(rsp, \"cannot move space because the display is in the middle of an animation.\\n\");\n                } else if (result == SPACE_OP_ERROR_IN_MISSION_CONTROL) {\n                    daemon_fail(rsp, \"cannot move space because mission-control is active.\\n\");\n                } else if (result == SPACE_OP_ERROR_SCRIPTING_ADDITION) {\n                    daemon_fail(rsp, \"cannot move space due to an error with the scripting-addition.\\n\");\n                }\n            }\n        } else if (token_equals(command, COMMAND_SPACE_SWAP)) {\n            struct selector selector = parse_space_selector(rsp, &message, acting_sid, false);\n            if (selector.did_parse && selector.sid) {\n                enum space_op_error result = space_manager_swap_space_with_space(acting_sid, selector.sid);\n                if (result == SPACE_OP_ERROR_SAME_SPACE) {\n                    daemon_fail(rsp, \"cannot swap space with itself.\\n\");\n                } else if (result == SPACE_OP_ERROR_DISPLAY_IS_ANIMATING) {\n                    daemon_fail(rsp, \"cannot swap space because the display is in the middle of an animation.\\n\");\n                } else if (result == SPACE_OP_ERROR_IN_MISSION_CONTROL) {\n                    daemon_fail(rsp, \"cannot swap space because mission-control is active.\\n\");\n                } else if (result == SPACE_OP_ERROR_SCRIPTING_ADDITION) {\n                    daemon_fail(rsp, \"cannot swap space due to an error with the scripting-addition.\\n\");\n                }\n            }\n        } else if (token_equals(command, COMMAND_SPACE_DISPLAY)) {\n            struct selector selector = parse_display_selector(rsp, &message, display_manager_active_display_id(), false);\n            if (selector.did_parse && selector.did) {\n                enum space_op_error result = space_manager_move_space_to_display(&g_space_manager, acting_sid, selector.did);\n                if (result == SPACE_OP_ERROR_MISSING_SRC) {\n                    daemon_fail(rsp, \"could not locate the space to act on.\\n\");\n                } else if (result == SPACE_OP_ERROR_MISSING_DST) {\n                    daemon_fail(rsp, \"could not locate the active space of the given display.\\n\");\n                } else if (result == SPACE_OP_ERROR_INVALID_SRC) {\n                    daemon_fail(rsp, \"acting space is the last user-space on the source display and cannot be moved.\\n\");\n                } else if (result == SPACE_OP_ERROR_INVALID_DST) {\n                    daemon_fail(rsp, \"acting space is already located on the given display.\\n\");\n                } else if (result == SPACE_OP_ERROR_DISPLAY_IS_ANIMATING) {\n                    daemon_fail(rsp, \"cannot send space to display because it is in the middle of an animation.\\n\");\n                } else if (result == SPACE_OP_ERROR_IN_MISSION_CONTROL) {\n                    daemon_fail(rsp, \"cannot send space to display because mission-control is active.\\n\");\n                } else if (result == SPACE_OP_ERROR_SCRIPTING_ADDITION) {\n                    daemon_fail(rsp, \"cannot send space to display due to an error with the scripting-addition.\\n\");\n                }\n            }\n        } else if (token_equals(command, COMMAND_SPACE_CREATE)) {\n            struct selector selector = parse_display_selector(rsp, &message, display_manager_active_display_id(), true);\n\n            if (token_is_valid(selector.token)) {\n                if (selector.did_parse && selector.did) {\n                    acting_sid = display_space_id(selector.did);\n                } else {\n                    return;\n                }\n            }\n\n            enum space_op_error result = space_manager_add_space(acting_sid);\n            if (result == SPACE_OP_ERROR_MISSING_SRC) {\n                daemon_fail(rsp, \"could not locate the space to act on.\\n\");\n            } else if (result == SPACE_OP_ERROR_DISPLAY_IS_ANIMATING) {\n                daemon_fail(rsp, \"cannot create space because the display is in the middle of an animation.\\n\");\n            } else if (result == SPACE_OP_ERROR_IN_MISSION_CONTROL) {\n                daemon_fail(rsp, \"cannot create space because mission-control is active.\\n\");\n            } else if (result == SPACE_OP_ERROR_SCRIPTING_ADDITION) {\n                daemon_fail(rsp, \"cannot create space due to an error with the scripting-addition.\\n\");\n            }\n        } else if (token_equals(command, COMMAND_SPACE_DESTROY)) {\n            struct selector selector = parse_space_selector(rsp, &message, acting_sid, true);\n\n            if (token_is_valid(selector.token)) {\n                if (selector.did_parse && selector.sid) {\n                    acting_sid = selector.sid;\n                } else {\n                    return;\n                }\n            }\n\n            enum space_op_error result = space_manager_destroy_space(acting_sid);\n            if (result == SPACE_OP_ERROR_MISSING_SRC) {\n                daemon_fail(rsp, \"could not locate the space to act on.\\n\");\n            } else if (result == SPACE_OP_ERROR_INVALID_SRC) {\n                daemon_fail(rsp, \"acting space is the last user-space on the source display and cannot be destroyed.\\n\");\n            } else if (result == SPACE_OP_ERROR_INVALID_TYPE) {\n                daemon_fail(rsp, \"cannot destroy a macOS fullscreen space.\\n\");\n            } else if (result == SPACE_OP_ERROR_DISPLAY_IS_ANIMATING) {\n                daemon_fail(rsp, \"cannot destroy space because the display is in the middle of an animation.\\n\");\n            } else if (result == SPACE_OP_ERROR_IN_MISSION_CONTROL) {\n                daemon_fail(rsp, \"cannot destroy space because mission-control is active.\\n\");\n            } else if (result == SPACE_OP_ERROR_SCRIPTING_ADDITION) {\n                daemon_fail(rsp, \"cannot destroy space due to an error with the scripting-addition.\\n\");\n            }\n        } else if (token_equals(command, COMMAND_SPACE_EQUALIZE)) {\n            struct token value = get_token(&message);\n            if (!token_is_valid(value)) {\n                if (!space_manager_equalize_space(&g_space_manager, acting_sid, SPLIT_X | SPLIT_Y)) {\n                    daemon_fail(rsp, \"cannot equalize a non-managed space.\\n\");\n                }\n            } else if (token_equals(value, ARGUMENT_COMMON_VAL_AXIS_X)) {\n                if (!space_manager_equalize_space(&g_space_manager, acting_sid, SPLIT_X)) {\n                    daemon_fail(rsp, \"cannot equalize a non-managed space.\\n\");\n                }\n            } else if (token_equals(value, ARGUMENT_COMMON_VAL_AXIS_Y)) {\n                if (!space_manager_equalize_space(&g_space_manager, acting_sid, SPLIT_Y)) {\n                    daemon_fail(rsp, \"cannot equalize a non-managed space.\\n\");\n                }\n            } else {\n                daemon_fail(rsp, \"unknown value '%.*s' given to command '%.*s' for domain '%.*s'\\n\", value.length, value.text, command.length, command.text, domain.length, domain.text);\n            }\n        } else if (token_equals(command, COMMAND_SPACE_BALANCE)) {\n            struct token value = get_token(&message);\n            if (!token_is_valid(value)) {\n                if (!space_manager_balance_space(&g_space_manager, acting_sid, SPLIT_X | SPLIT_Y)) {\n                    daemon_fail(rsp, \"cannot balance a non-managed space.\\n\");\n                }\n            } else if (token_equals(value, ARGUMENT_COMMON_VAL_AXIS_X)) {\n                if (!space_manager_balance_space(&g_space_manager, acting_sid, SPLIT_X)) {\n                    daemon_fail(rsp, \"cannot balance a non-managed space.\\n\");\n                }\n            } else if (token_equals(value, ARGUMENT_COMMON_VAL_AXIS_Y)) {\n                if (!space_manager_balance_space(&g_space_manager, acting_sid, SPLIT_Y)) {\n                    daemon_fail(rsp, \"cannot balance a non-managed space.\\n\");\n                }\n            } else {\n                daemon_fail(rsp, \"unknown value '%.*s' given to command '%.*s' for domain '%.*s'\\n\", value.length, value.text, command.length, command.text, domain.length, domain.text);\n            }\n        } else if (token_equals(command, COMMAND_SPACE_MIRROR)) {\n            struct token value = get_token(&message);\n            if (token_equals(value, ARGUMENT_COMMON_VAL_AXIS_X)) {\n                if (!space_manager_mirror_space(&g_space_manager, acting_sid, SPLIT_X)) {\n                    daemon_fail(rsp, \"cannot mirror a non-managed space.\\n\");\n                }\n            } else if (token_equals(value, ARGUMENT_COMMON_VAL_AXIS_Y)) {\n                if (!space_manager_mirror_space(&g_space_manager, acting_sid, SPLIT_Y)) {\n                    daemon_fail(rsp, \"cannot mirror a non-managed space.\\n\");\n                }\n            } else {\n                daemon_fail(rsp, \"unknown value '%.*s' given to command '%.*s' for domain '%.*s'\\n\", value.length, value.text, command.length, command.text, domain.length, domain.text);\n            }\n        } else if (token_equals(command, COMMAND_SPACE_ROTATE)) {\n            struct token value = get_token(&message);\n            if (token_equals(value, ARGUMENT_SPACE_ROTATE_90)) {\n                if (!space_manager_rotate_space(&g_space_manager, acting_sid, 90)) {\n                    daemon_fail(rsp, \"cannot rotate a non-managed space.\\n\");\n                }\n            } else if (token_equals(value, ARGUMENT_SPACE_ROTATE_180)) {\n                if (!space_manager_rotate_space(&g_space_manager, acting_sid, 180)) {\n                    daemon_fail(rsp, \"cannot rotate a non-managed space.\\n\");\n                }\n            } else if (token_equals(value, ARGUMENT_SPACE_ROTATE_270)) {\n                if (!space_manager_rotate_space(&g_space_manager, acting_sid, 270)) {\n                    daemon_fail(rsp, \"cannot rotate a non-managed space.\\n\");\n                }\n            } else {\n                daemon_fail(rsp, \"unknown value '%.*s' given to command '%.*s' for domain '%.*s'\\n\", value.length, value.text, command.length, command.text, domain.length, domain.text);\n            }\n        } else if (token_equals(command, COMMAND_SPACE_PADDING)) {\n            int t, b, l, r;\n            char type[MAXLEN];\n            struct token value = get_token(&message);\n            if ((sscanf(value.text, ARGUMENT_SPACE_PADDING, type, &t, &b, &l, &r) == 5)) {\n                if (!space_manager_set_padding_for_space(&g_space_manager, acting_sid, parse_value_type(type), t, b, l, r)) {\n                    daemon_fail(rsp, \"cannot set padding for a non-managed space.\\n\");\n                }\n            } else {\n                daemon_fail(rsp, \"unknown value '%.*s' given to command '%.*s' for domain '%.*s'\\n\", value.length, value.text, command.length, command.text, domain.length, domain.text);\n            }\n        } else if (token_equals(command, COMMAND_SPACE_GAP)) {\n            int gap;\n            char type[MAXLEN];\n            struct token value = get_token(&message);\n            if ((sscanf(value.text, ARGUMENT_SPACE_GAP, type, &gap) == 2)) {\n                if (!space_manager_set_gap_for_space(&g_space_manager, acting_sid, parse_value_type(type), gap)) {\n                    daemon_fail(rsp, \"cannot set gap for a non-managed space.\\n\");\n                }\n            } else {\n                daemon_fail(rsp, \"unknown value '%.*s' given to command '%.*s' for domain '%.*s'\\n\", value.length, value.text, command.length, command.text, domain.length, domain.text);\n            }\n        } else if (token_equals(command, COMMAND_SPACE_TOGGLE)) {\n            struct token value = get_token(&message);\n            if (token_equals(value, ARGUMENT_SPACE_TGL_PADDING)) {\n                if (!space_manager_toggle_padding_for_space(&g_space_manager, acting_sid)) {\n                    daemon_fail(rsp, \"cannot toggle padding for a non-managed space.\\n\");\n                }\n            } else if (token_equals(value, ARGUMENT_SPACE_TGL_GAP)) {\n                if (!space_manager_toggle_gap_for_space(&g_space_manager, acting_sid)) {\n                    daemon_fail(rsp, \"cannot toggle gap for a non-managed space.\\n\");\n                }\n            } else if (token_equals(value, ARGUMENT_SPACE_TGL_MC)) {\n                space_manager_toggle_mission_control(acting_sid);\n            } else if (token_equals(value, ARGUMENT_SPACE_TGL_SD)) {\n                space_manager_toggle_show_desktop(acting_sid);\n            } else {\n                daemon_fail(rsp, \"unknown value '%.*s' given to command '%.*s' for domain '%.*s'\\n\", value.length, value.text, command.length, command.text, domain.length, domain.text);\n            }\n        } else if (token_equals(command, COMMAND_SPACE_LAYOUT)) {\n            struct token value = get_token(&message);\n            if (token_equals(value, ARGUMENT_SPACE_LAYOUT_BSP)) {\n                if (space_is_user(acting_sid)) {\n                    space_manager_set_layout_for_space(&g_space_manager, acting_sid, VIEW_BSP);\n                } else {\n                    daemon_fail(rsp, \"cannot set layout for a macOS fullscreen space!\\n\");\n                }\n            } else if (token_equals(value, ARGUMENT_SPACE_LAYOUT_STACK)) {\n                if (space_is_user(acting_sid)) {\n                    space_manager_set_layout_for_space(&g_space_manager, acting_sid, VIEW_STACK);\n                } else {\n                    daemon_fail(rsp, \"cannot set layout for a macOS fullscreen space!\\n\");\n                }\n            } else if (token_equals(value, ARGUMENT_SPACE_LAYOUT_FLT)) {\n                if (space_is_user(acting_sid)) {\n                    space_manager_set_layout_for_space(&g_space_manager, acting_sid, VIEW_FLOAT);\n                } else {\n                    daemon_fail(rsp, \"cannot set layout for a macOS fullscreen space!\\n\");\n                }\n            } else {\n                daemon_fail(rsp, \"unknown value '%.*s' given to command '%.*s' for domain '%.*s'\\n\", value.length, value.text, command.length, command.text, domain.length, domain.text);\n            }\n        } else if (token_equals(command, COMMAND_SPACE_LABEL)) {\n            char *label;\n            if (parse_label(rsp, get_token(&message), LABEL_SPACE, &label)) {\n                if (label) {\n                    space_manager_set_label_for_space(&g_space_manager, acting_sid, label);\n                } else {\n                    if (!space_manager_remove_label_for_space(&g_space_manager, acting_sid)) {\n                        daemon_fail(rsp, \"the selected space was not associated with a label!\\n\");\n                    }\n                }\n            }\n        } else {\n            daemon_fail(rsp, \"unknown command '%.*s' for domain '%.*s'\\n\", command.length, command.text, domain.length, domain.text);\n        }\n    }\n}\n\nstatic void handle_domain_window(FILE *rsp, struct token domain, char *message)\n{\n    TIME_FUNCTION;\n\n    struct token command;\n    struct window *acting_window = window_manager_focused_window(&g_window_manager);\n    struct selector selector = parse_window_selector(NULL, &message, acting_window, true);\n\n    if (selector.did_parse) {\n        acting_window = selector.window;\n        command = get_token(&message);\n    } else {\n        command = selector.token;\n    }\n\n    for (; token_is_valid(command); command = get_token(&message)) {\n        if (!acting_window &&\n            !token_equals(command, COMMAND_WINDOW_FOCUS) &&\n            !token_equals(command, COMMAND_WINDOW_CLOSE) &&\n            !token_equals(command, COMMAND_WINDOW_MINIMIZE) &&\n            !token_equals(command, COMMAND_WINDOW_DEMINIMIZE) &&\n            !token_equals(command, COMMAND_WINDOW_TOGGLE)) {\n            daemon_fail(rsp, \"could not locate the window to act on!\\n\");\n            return;\n        }\n\n        if (token_equals(command, COMMAND_WINDOW_FOCUS)) {\n            struct selector selector = parse_window_selector(rsp, &message, acting_window, true);\n\n            if (token_is_valid(selector.token)) {\n                if (selector.did_parse && selector.window) {\n                    acting_window = selector.window;\n                } else {\n                    return;\n                }\n            }\n\n            if (acting_window) {\n                window_manager_focus_window_with_raise(&acting_window->application->psn, acting_window->id, acting_window->ref);\n            } else {\n                daemon_fail(rsp, \"could not locate the window to act on!\\n\");\n            }\n        } else if (token_equals(command, COMMAND_WINDOW_CLOSE)) {\n            struct selector selector = parse_window_selector(rsp, &message, acting_window, true);\n\n            if (token_is_valid(selector.token)) {\n                if (selector.did_parse && selector.window) {\n                    acting_window = selector.window;\n                } else {\n                    return;\n                }\n            }\n\n            if (acting_window) {\n                if (!window_manager_close_window(acting_window)) {\n                    daemon_fail(rsp, \"could not close window with id '%d'.\\n\", acting_window->id);\n                }\n            } else {\n                daemon_fail(rsp, \"could not locate the window to act on!\\n\");\n            }\n        } else if (token_equals(command, COMMAND_WINDOW_MINIMIZE)) {\n            struct selector selector = parse_window_selector(rsp, &message, acting_window, true);\n\n            if (token_is_valid(selector.token)) {\n                if (selector.did_parse && selector.window) {\n                    acting_window = selector.window;\n                } else {\n                    return;\n                }\n            }\n\n            if (acting_window) {\n                enum window_op_error result = window_manager_minimize_window(acting_window);\n                if (result == WINDOW_OP_ERROR_CANT_MINIMIZE) {\n                    daemon_fail(rsp, \"window with id '%d' does not support the minimize operation.\\n\", acting_window->id);\n                } else if (result == WINDOW_OP_ERROR_ALREADY_MINIMIZED) {\n                    daemon_fail(rsp, \"window with id '%d' is already minimized.\\n\", acting_window->id);\n                } else if (result == WINDOW_OP_ERROR_MINIMIZE_FAILED) {\n                    daemon_fail(rsp, \"could not minimize window with id '%d'.\\n\", acting_window->id);\n                }\n            } else {\n                daemon_fail(rsp, \"could not locate the window to act on!\\n\");\n            }\n        } else if (token_equals(command, COMMAND_WINDOW_DEMINIMIZE)) {\n            struct selector selector = parse_window_selector(rsp, &message, acting_window, false);\n            if (selector.did_parse && selector.window) {\n                enum window_op_error result = window_manager_deminimize_window(selector.window);\n                if (result == WINDOW_OP_ERROR_NOT_MINIMIZED) {\n                    daemon_fail(rsp, \"window with id '%d' is not minimized.\\n\", selector.window->id);\n                } else if (result == WINDOW_OP_ERROR_DEMINIMIZE_FAILED) {\n                    daemon_fail(rsp, \"could not deminimize window with id '%d'.\\n\", selector.window->id);\n                }\n            }\n        } else if (token_equals(command, COMMAND_WINDOW_DISPLAY)) {\n            struct selector selector = parse_display_selector(rsp, &message, display_manager_active_display_id(), false);\n            if (selector.did_parse && selector.did) {\n                uint64_t sid = display_space_id(selector.did);\n                if (space_is_fullscreen(sid)) {\n                    daemon_fail(rsp, \"can not move window to a macOS fullscreen space!\\n\");\n                } else {\n                    window_manager_send_window_to_space(&g_space_manager, &g_window_manager, acting_window, sid, false);\n                }\n            }\n        } else if (token_equals(command, COMMAND_WINDOW_SPACE)) {\n            struct selector selector = parse_space_selector(rsp, &message, space_manager_active_space(), false);\n            if (selector.did_parse && selector.sid) {\n                if (space_is_fullscreen(selector.sid)) {\n                    daemon_fail(rsp, \"can not move window to a macOS fullscreen space!\\n\");\n                } else {\n                    window_manager_send_window_to_space(&g_space_manager, &g_window_manager, acting_window, selector.sid, false);\n                }\n            }\n        } else if (token_equals(command, COMMAND_WINDOW_SWAP)) {\n            struct selector selector = parse_window_selector(rsp, &message, acting_window, false);\n            if (selector.did_parse && selector.window) {\n                enum window_op_error result = window_manager_swap_window(&g_space_manager, &g_window_manager, acting_window, selector.window);\n                if (result == WINDOW_OP_ERROR_INVALID_SRC_VIEW) {\n                    daemon_fail(rsp, \"the acting window is not within a bsp space.\\n\");\n                } else if (result == WINDOW_OP_ERROR_INVALID_DST_VIEW) {\n                    daemon_fail(rsp, \"the selected window is not within a bsp space.\\n\");\n                } else if (result == WINDOW_OP_ERROR_INVALID_SRC_NODE) {\n                    daemon_fail(rsp, \"the acting window is not managed.\\n\");\n                } else if (result == WINDOW_OP_ERROR_INVALID_DST_NODE) {\n                    daemon_fail(rsp, \"the selected window is not managed.\\n\");\n                } else if (result == WINDOW_OP_ERROR_SAME_STACK) {\n                    daemon_fail(rsp, \"cannot swap a window with a window in the same stack.\\n\");\n                } else if (result == WINDOW_OP_ERROR_SAME_WINDOW) {\n                    daemon_fail(rsp, \"cannot swap a window with itself.\\n\");\n                }\n            }\n        } else if (token_equals(command, COMMAND_WINDOW_WARP)) {\n            struct selector selector = parse_window_selector(rsp, &message, acting_window, false);\n            if (selector.did_parse && selector.window) {\n                enum window_op_error result = window_manager_warp_window(&g_space_manager, &g_window_manager, acting_window, selector.window);\n                if (result == WINDOW_OP_ERROR_INVALID_SRC_VIEW) {\n                    daemon_fail(rsp, \"the acting window is not within a bsp space.\\n\");\n                } else if (result == WINDOW_OP_ERROR_INVALID_DST_VIEW) {\n                    daemon_fail(rsp, \"the selected window is not within a bsp space.\\n\");\n                } else if (result == WINDOW_OP_ERROR_INVALID_SRC_NODE) {\n                    daemon_fail(rsp, \"the acting window is not managed.\\n\");\n                } else if (result == WINDOW_OP_ERROR_INVALID_DST_NODE) {\n                    daemon_fail(rsp, \"the selected window is not managed.\\n\");\n                } else if (result == WINDOW_OP_ERROR_SAME_STACK) {\n                    daemon_fail(rsp, \"cannot warp a window with a window in the same stack.\\n\");\n                } else if (result == WINDOW_OP_ERROR_SAME_WINDOW) {\n                    daemon_fail(rsp, \"cannot warp a window onto itself.\\n\");\n                }\n            }\n        } else if (token_equals(command, COMMAND_WINDOW_STACK)) {\n            struct selector selector = parse_window_selector(rsp, &message, acting_window, false);\n            if (selector.did_parse && selector.window) {\n                enum window_op_error result = window_manager_stack_window(&g_space_manager, &g_window_manager, acting_window, selector.window);\n                if (result == WINDOW_OP_ERROR_INVALID_SRC_NODE) {\n                    daemon_fail(rsp, \"the acting window is not managed.\\n\");\n                } else if (result == WINDOW_OP_ERROR_MAX_STACK) {\n                    daemon_fail(rsp, \"cannot stack window, max capacity of %d reached.\\n\", NODE_MAX_WINDOW_COUNT);\n                } else if (result == WINDOW_OP_ERROR_SAME_WINDOW) {\n                    daemon_fail(rsp, \"cannot stack a window onto itself.\\n\");\n                }\n            }\n        } else if (token_equals(command, COMMAND_WINDOW_INSERT)) {\n            struct selector selector = parse_insert_selector(rsp, &message);\n            if (selector.did_parse && selector.dir) {\n                enum window_op_error result = window_manager_set_window_insertion(&g_space_manager, acting_window, selector.dir);\n                if (result == WINDOW_OP_ERROR_INVALID_SRC_VIEW) {\n                    daemon_fail(rsp, \"the acting window is not within a bsp space.\\n\");\n                } else if (result == WINDOW_OP_ERROR_INVALID_SRC_NODE) {\n                    daemon_fail(rsp, \"the acting window is not managed.\\n\");\n                }\n            }\n        } else if (token_equals(command, COMMAND_WINDOW_GRID)) {\n            unsigned r, c, x, y, w, h;\n            struct token value = get_token(&message);\n            if ((sscanf(value.text, ARGUMENT_WINDOW_GRID, &r, &c, &x, &y, &w, &h) == 6)) {\n                enum window_op_error result = window_manager_apply_grid(&g_space_manager, &g_window_manager, acting_window, r, c, x, y, w, h);\n                if (result == WINDOW_OP_ERROR_INVALID_SRC_VIEW) {\n                    daemon_fail(rsp, \"cannot apply grid layout to a managed window.\\n\");\n                }\n            } else {\n                daemon_fail(rsp, \"unknown value '%.*s' given to command '%.*s' for domain '%.*s'\\n\", value.length, value.text, command.length, command.text, domain.length, domain.text);\n            }\n        } else if (token_equals(command, COMMAND_WINDOW_MOVE)) {\n            float x, y;\n            char type[MAXLEN];\n            struct token value = get_token(&message);\n            if ((sscanf(value.text, ARGUMENT_WINDOW_MOVE, type, &x, &y) == 3)) {\n                enum window_op_error result = window_manager_move_window_relative(&g_window_manager, acting_window, parse_value_type(type), x, y);\n                if (result == WINDOW_OP_ERROR_INVALID_SRC_VIEW) {\n                    daemon_fail(rsp, \"cannot move a managed window.\\n\");\n                }\n            } else {\n                daemon_fail(rsp, \"unknown value '%.*s' given to command '%.*s' for domain '%.*s'\\n\", value.length, value.text, command.length, command.text, domain.length, domain.text);\n            }\n        } else if (token_equals(command, COMMAND_WINDOW_RESIZE)) {\n            float w, h;\n            char handle[MAXLEN];\n            struct token value = get_token(&message);\n            if ((sscanf(value.text, ARGUMENT_WINDOW_RESIZE, handle, &w, &h) == 3)) {\n                enum window_op_error result = window_manager_resize_window_relative(&g_window_manager, acting_window, parse_resize_handle(handle), w, h, true);\n                if (result == WINDOW_OP_ERROR_INVALID_SRC_NODE) {\n                    daemon_fail(rsp, \"cannot locate bsp node for the managed window.\\n\");\n                } else if (result == WINDOW_OP_ERROR_INVALID_DST_NODE) {\n                    daemon_fail(rsp, \"cannot locate a bsp node fence.\\n\");\n                } else if (result == WINDOW_OP_ERROR_INVALID_OPERATION) {\n                    daemon_fail(rsp, \"cannot use absolute resizing on a managed window.\\n\");\n                }\n            } else {\n                daemon_fail(rsp, \"unknown value '%.*s' given to command '%.*s' for domain '%.*s'\\n\", value.length, value.text, command.length, command.text, domain.length, domain.text);\n            }\n        } else if (token_equals(command, COMMAND_WINDOW_RATIO)) {\n            float r;\n            char type[MAXLEN];\n            struct token value = get_token(&message);\n            if ((sscanf(value.text, ARGUMENT_WINDOW_RATIO, type, &r) == 2)) {\n                enum window_op_error result = window_manager_adjust_window_ratio(&g_window_manager, acting_window, parse_value_type(type), r);\n                if (result == WINDOW_OP_ERROR_INVALID_SRC_VIEW) {\n                    daemon_fail(rsp, \"cannot adjust ratio of a non-managed window.\\n\");\n                } else if (result == WINDOW_OP_ERROR_INVALID_SRC_NODE) {\n                    daemon_fail(rsp, \"cannot adjust ratio of a root node.\\n\");\n                }\n            } else {\n                daemon_fail(rsp, \"unknown value '%.*s' given to command '%.*s' for domain '%.*s'\\n\", value.length, value.text, command.length, command.text, domain.length, domain.text);\n            }\n        } else if (token_equals(command, COMMAND_WINDOW_TOGGLE)) {\n            struct token value = get_token(&message);\n            if (token_equals(value, ARGUMENT_WINDOW_TOGGLE_FLOAT)) {\n                if (acting_window) {\n                    window_manager_make_window_floating(&g_space_manager, &g_window_manager, acting_window, !window_check_flag(acting_window, WINDOW_FLOAT), false);\n                } else {\n                    daemon_fail(rsp, \"could not locate the window to act on!\\n\");\n                }\n            } else if (token_equals(value, ARGUMENT_WINDOW_TOGGLE_STICKY)) {\n                if (acting_window) {\n                    window_manager_make_window_sticky(&g_space_manager, &g_window_manager, acting_window, !window_check_flag(acting_window, WINDOW_STICKY));\n                } else {\n                    daemon_fail(rsp, \"could not locate the window to act on!\\n\");\n                }\n            } else if (token_equals(value, ARGUMENT_WINDOW_TOGGLE_SHADOW)) {\n                if (acting_window) {\n                    window_manager_toggle_window_shadow(acting_window);\n                } else {\n                    daemon_fail(rsp, \"could not locate the window to act on!\\n\");\n                }\n            } else if (token_equals(value, ARGUMENT_WINDOW_TOGGLE_SPLIT)) {\n                if (acting_window) {\n                    space_manager_toggle_window_split(&g_space_manager, acting_window);\n                } else {\n                    daemon_fail(rsp, \"could not locate the window to act on!\\n\");\n                }\n            } else if (token_equals(value, ARGUMENT_WINDOW_TOGGLE_PARENT)) {\n                if (acting_window) {\n                    window_manager_toggle_window_zoom_parent(&g_window_manager, acting_window);\n                } else {\n                    daemon_fail(rsp, \"could not locate the window to act on!\\n\");\n                }\n            } else if (token_equals(value, ARGUMENT_WINDOW_TOGGLE_FULLSC)) {\n                if (acting_window) {\n                    window_manager_toggle_window_zoom_fullscreen(&g_window_manager, acting_window);\n                } else {\n                    daemon_fail(rsp, \"could not locate the window to act on!\\n\");\n                }\n            } else if (token_equals(value, ARGUMENT_WINDOW_TOGGLE_WINDOWED)) {\n                if (acting_window) {\n                    window_manager_toggle_window_windowed_fullscreen(acting_window);\n                } else {\n                    daemon_fail(rsp, \"could not locate the window to act on!\\n\");\n                }\n            } else if (token_equals(value, ARGUMENT_WINDOW_TOGGLE_NATIVE)) {\n                if (acting_window) {\n                    window_manager_toggle_window_native_fullscreen(acting_window);\n                } else {\n                    daemon_fail(rsp, \"could not locate the window to act on!\\n\");\n                }\n            } else if (token_equals(value, ARGUMENT_WINDOW_TOGGLE_EXPOSE)) {\n                if (acting_window) {\n                    window_manager_toggle_window_expose(acting_window);\n                } else {\n                    daemon_fail(rsp, \"could not locate the window to act on!\\n\");\n                }\n            } else if (token_equals(value, ARGUMENT_WINDOW_TOGGLE_PIP)) {\n                if (acting_window) {\n                    window_manager_toggle_window_pip(&g_space_manager, acting_window);\n                } else {\n                    daemon_fail(rsp, \"could not locate the window to act on!\\n\");\n                }\n            } else if (!window_manager_toggle_scratchpad_window_by_label(&g_window_manager, value.text)) {\n                daemon_fail(rsp, \"unknown value '%.*s' given to command '%.*s' for domain '%.*s'\\n\", value.length, value.text, command.length, command.text, domain.length, domain.text);\n            }\n        } else if (token_equals(command, COMMAND_WINDOW_SUB_LAYER)) {\n            struct token value = get_token(&message);\n            if (token_equals(value, ARGUMENT_WINDOW_LAYER_BELOW)) {\n                if (!window_manager_set_window_layer(acting_window, LAYER_BELOW)) {\n                    daemon_fail(rsp, \"could not change sub-layer of window with id '%d' due to an error with the scripting-addition.\\n\", acting_window->id);\n                }\n            } else if (token_equals(value, ARGUMENT_WINDOW_LAYER_NORMAL)) {\n                if (!window_manager_set_window_layer(acting_window, LAYER_NORMAL)) {\n                    daemon_fail(rsp, \"could not change sub-layer of window with id '%d' due to an error with the scripting-addition.\\n\", acting_window->id);\n                }\n            } else if (token_equals(value, ARGUMENT_WINDOW_LAYER_ABOVE)) {\n                if (!window_manager_set_window_layer(acting_window, LAYER_ABOVE)) {\n                    daemon_fail(rsp, \"could not change sub-layer of window with id '%d' due to an error with the scripting-addition.\\n\", acting_window->id);\n                }\n            } else if (token_equals(value, ARGUMENT_WINDOW_LAYER_AUTO)) {\n                if (!window_manager_set_window_layer(acting_window, LAYER_AUTO)) {\n                    daemon_fail(rsp, \"could not change sub-layer of window with id '%d' due to an error with the scripting-addition.\\n\", acting_window->id);\n                }\n            } else {\n                daemon_fail(rsp, \"unknown value '%.*s' given to command '%.*s' for domain '%.*s'\\n\", value.length, value.text, command.length, command.text, domain.length, domain.text);\n            }\n        } else if (token_equals(command, COMMAND_WINDOW_OPACITY)) {\n            struct token_value value = token_to_value(get_token(&message));\n            if (value.type == TOKEN_TYPE_FLOAT && in_range_ii(value.float_value, 0.0f, 1.0f)) {\n                if (window_manager_set_opacity(&g_window_manager, acting_window, value.float_value)) {\n                    acting_window->opacity = value.float_value;\n                } else {\n                    daemon_fail(rsp, \"could not change opacity of window with id '%d' due to an error with the scripting-addition.\\n\", acting_window->id);\n                }\n            } else {\n                daemon_fail(rsp, \"unknown value '%.*s' given to command '%.*s' for domain '%.*s'\\n\", value.token.length, value.token.text, command.length, command.text, domain.length, domain.text);\n            }\n        } else if (token_equals(command, COMMAND_WINDOW_RAISE)) {\n            struct selector selector = parse_window_selector(rsp, &message, acting_window, true);\n            uint32_t selector_wid = 0;\n\n            if (token_is_valid(selector.token)) {\n                if (selector.did_parse && selector.window) {\n                    selector_wid = selector.window->id;\n                } else {\n                    return;\n                }\n            }\n\n            if (!scripting_addition_order_window(acting_window->id, 1, selector_wid)) {\n                daemon_fail(rsp, \"could not raise window with id '%d' due to an error with the scripting-addition.\\n\", acting_window->id);\n            }\n        } else if (token_equals(command, COMMAND_WINDOW_LOWER)) {\n            struct selector selector = parse_window_selector(rsp, &message, acting_window, true);\n            uint32_t selector_wid = 0;\n\n            if (token_is_valid(selector.token)) {\n                if (selector.did_parse && selector.window) {\n                    selector_wid = selector.window->id;\n                } else {\n                    return;\n                }\n            }\n\n            if (!scripting_addition_order_window(acting_window->id, -1, selector_wid)) {\n                daemon_fail(rsp, \"could not lower window with id '%d' due to an error with the scripting-addition.\\n\", acting_window->id);\n            }\n        } else if (token_equals(command, COMMAND_WINDOW_SCRATCHPAD)) {\n            char *label;\n            struct token token = get_token(&message);\n            if (token_is_valid(token) && token_equals(token, ARGUMENT_WINDOW_SCRATCHPAD_RECOVER)) {\n                window_manager_scratchpad_recover_windows();\n            } else if (parse_label(rsp, token, LABEL_WINDOW, &label)) {\n                if (label) {\n                    if (!window_manager_set_scratchpad_for_window(&g_window_manager, acting_window, label)) {\n                        daemon_fail(rsp, \"the given scratchpad is already assigned to a different window!\\n\");\n                    }\n                } else {\n                    if (!window_manager_remove_scratchpad_for_window(&g_window_manager, acting_window, true)) {\n                        daemon_fail(rsp, \"the selected window was not assigned to a scratchpad!\\n\");\n                    }\n                }\n            }\n        } else {\n            daemon_fail(rsp, \"unknown command '%.*s' for domain '%.*s'\\n\", command.length, command.text, domain.length, domain.text);\n        }\n    }\n}\n\nstatic void handle_domain_query(FILE *rsp, struct token domain, char *message)\n{\n    TIME_FUNCTION;\n\n    struct token command = get_token(&message);\n    if (token_equals(command, COMMAND_QUERY_DISPLAYS)) {\n        struct properties properties = parse_properties(rsp, get_token(&message), display_property_val, display_property_str, array_count(display_property_str));\n        if (properties.did_error) return;\n\n        struct token option = properties.did_parse ? get_token(&message) : properties.token;\n        if (token_equals(option, ARGUMENT_QUERY_DISPLAY)) {\n            uint32_t acting_did = display_manager_active_display_id();\n            struct selector selector = parse_display_selector(rsp, &message, acting_did, true);\n\n            if (token_is_valid(selector.token)) {\n                if (selector.did_parse && selector.did) {\n                    acting_did = selector.did;\n                } else {\n                    return;\n                }\n            }\n\n            display_serialize(rsp, acting_did, properties.flags);\n            fprintf(rsp, \"\\n\");\n        } else if (token_equals(option, ARGUMENT_QUERY_SPACE)) {\n            uint64_t acting_sid = space_manager_active_space();\n            struct selector selector = parse_space_selector(rsp, &message, acting_sid, true);\n\n            if (token_is_valid(selector.token)) {\n                if (selector.did_parse && selector.sid) {\n                    acting_sid = selector.sid;\n                } else {\n                    return;\n                }\n            }\n\n            display_serialize(rsp, space_display_id(acting_sid), properties.flags);\n            fprintf(rsp, \"\\n\");\n        } else if (token_equals(option, ARGUMENT_QUERY_WINDOW)) {\n            struct window *acting_window = window_manager_focused_window(&g_window_manager);\n            struct selector selector = parse_window_selector(rsp, &message, acting_window, true);\n\n            if (token_is_valid(selector.token)) {\n                if (selector.did_parse && selector.window) {\n                    acting_window = selector.window;\n                } else {\n                    return;\n                }\n            }\n\n            if (acting_window) {\n                display_serialize(rsp, window_display_id(acting_window->id), properties.flags);\n                fprintf(rsp, \"\\n\");\n            } else {\n                daemon_fail(rsp, \"could not find window to retrieve display details.\\n\");\n            }\n        } else if (token_is_valid(option)) {\n            daemon_fail(rsp, \"unknown option '%.*s' given to command '%.*s' for domain '%.*s'\\n\", option.length, option.text, command.length, command.text, domain.length, domain.text);\n        } else {\n            display_manager_query_displays(rsp, properties.flags);\n        }\n    } else if (token_equals(command, COMMAND_QUERY_SPACES)) {\n        struct properties properties = parse_properties(rsp, get_token(&message), space_property_val, space_property_str, array_count(space_property_str));\n        if (properties.did_error) return;\n\n        struct token option = properties.did_parse ? get_token(&message) : properties.token;\n        if (token_equals(option, ARGUMENT_QUERY_DISPLAY)) {\n            uint32_t acting_did = display_manager_active_display_id();\n            struct selector selector = parse_display_selector(rsp, &message, acting_did, true);\n\n            if (token_is_valid(selector.token)) {\n                if (selector.did_parse && selector.did) {\n                    acting_did = selector.did;\n                } else {\n                    return;\n                }\n            }\n\n            if (!space_manager_query_spaces_for_display(rsp, acting_did, properties.flags)) {\n                daemon_fail(rsp, \"could not retrieve spaces for display.\\n\");\n            }\n        } else if (token_equals(option, ARGUMENT_QUERY_SPACE)) {\n            uint64_t acting_sid = space_manager_active_space();\n            struct selector selector = parse_space_selector(rsp, &message, acting_sid, true);\n\n            if (token_is_valid(selector.token)) {\n                if (selector.did_parse && selector.sid) {\n                    acting_sid = selector.sid;\n                } else {\n                    return;\n                }\n            }\n\n            if (!space_manager_query_space(rsp, acting_sid, properties.flags)) {\n                daemon_fail(rsp, \"could not retrieve space details.\\n\");\n            }\n        } else if (token_equals(option, ARGUMENT_QUERY_WINDOW)) {\n            struct window *acting_window = window_manager_focused_window(&g_window_manager);\n            struct selector selector = parse_window_selector(rsp, &message, acting_window, true);\n\n            if (token_is_valid(selector.token)) {\n                if (selector.did_parse && selector.window) {\n                    acting_window = selector.window;\n                } else {\n                    return;\n                }\n            }\n\n            if (acting_window) {\n                space_manager_query_spaces_for_window(rsp, acting_window, properties.flags);\n            } else {\n                daemon_fail(rsp, \"could not find window to retrieve space details.\\n\");\n            }\n        } else if (token_is_valid(option)) {\n            daemon_fail(rsp, \"unknown option '%.*s' given to command '%.*s' for domain '%.*s'\\n\", option.length, option.text, command.length, command.text, domain.length, domain.text);\n        } else if (!space_manager_query_spaces_for_displays(rsp, properties.flags)) {\n            daemon_fail(rsp, \"could not retrieve spaces for displays.\\n\");\n        }\n    } else if (token_equals(command, COMMAND_QUERY_WINDOWS)) {\n        struct properties properties = parse_properties(rsp, get_token(&message), window_property_val, window_property_str, array_count(window_property_str));\n        if (properties.did_error) return;\n\n        struct token option = properties.did_parse ? get_token(&message) : properties.token;\n        if (token_equals(option, ARGUMENT_QUERY_DISPLAY)) {\n            uint32_t acting_did = display_manager_active_display_id();\n            struct selector selector = parse_display_selector(rsp, &message, acting_did, true);\n\n            if (token_is_valid(selector.token)) {\n                if (selector.did_parse && selector.did) {\n                    acting_did = selector.did;\n                } else {\n                    return;\n                }\n            }\n\n            window_manager_query_windows_for_display(rsp, acting_did, properties.flags);\n        } else if (token_equals(option, ARGUMENT_QUERY_SPACE)) {\n            uint64_t acting_sid = space_manager_active_space();\n            struct selector selector = parse_space_selector(rsp, &message, acting_sid, true);\n\n            if (token_is_valid(selector.token)) {\n                if (selector.did_parse && selector.sid) {\n                    acting_sid = selector.sid;\n                } else {\n                    return;\n                }\n            }\n\n            window_manager_query_windows_for_spaces(rsp, &acting_sid, 1, properties.flags);\n        } else if (token_equals(option, ARGUMENT_QUERY_WINDOW)) {\n            struct window *acting_window = window_manager_focused_window(&g_window_manager);\n            struct selector selector = parse_window_selector(rsp, &message, acting_window, true);\n\n            if (token_is_valid(selector.token)) {\n                if (selector.did_parse && selector.window) {\n                    acting_window = selector.window;\n                } else {\n                    return;\n                }\n            }\n\n            if (acting_window) {\n                window_serialize(rsp, acting_window, properties.flags);\n                fprintf(rsp, \"\\n\");\n            } else {\n                daemon_fail(rsp, \"could not retrieve window details.\\n\");\n            }\n        } else if (token_is_valid(option)) {\n            daemon_fail(rsp, \"unknown option '%.*s' given to command '%.*s' for domain '%.*s'\\n\", option.length, option.text, command.length, command.text, domain.length, domain.text);\n        } else {\n            window_manager_query_windows_for_displays(rsp, properties.flags);\n        }\n    } else {\n        daemon_fail(rsp, \"unknown command '%.*s' for domain '%.*s'\\n\", command.length, command.text, domain.length, domain.text);\n    }\n}\n\nstatic bool parse_rule(FILE *rsp, char **message, struct rule *rule, struct token token)\n{\n    TIME_FUNCTION;\n\n    char *unsupported_exclusion = NULL;\n    bool did_parse = true;\n    bool has_filter = false;\n\n    for (; token_is_valid(token); token = get_token(message)) {\n        char *key = NULL;\n        char *value = NULL;\n        bool exclusion = false;\n        parse_key_value_pair(token.text, &key, &value, &exclusion);\n\n        if (!key || !value) {\n            daemon_fail(rsp, \"invalid key-value pair '%s'\\n\", token.text);\n            did_parse = false;\n            continue;\n        }\n\n        if (string_equals(key, ARGUMENT_RULE_KEY_LABEL)) {\n            if (exclusion) unsupported_exclusion = key;\n            rule->label = string_copy(value);\n        } else if (string_equals(key, ARGUMENT_RULE_KEY_SCRATCHPAD)) {\n            if (exclusion) unsupported_exclusion = key;\n\n            bool valid = true;\n            for (int i = 0; i < array_count(reserved_window_identifiers); ++i) {\n                if (string_equals(value, reserved_window_identifiers[i])) {\n                    valid = false;\n                    break;\n                }\n            }\n\n            if (valid) {\n                rule->effects.scratchpad = string_copy(value);\n                rule->effects.manage = RULE_PROP_OFF;\n            } else {\n                daemon_fail(rsp, \"invalid value '%s' for key '%s'\\n\", value, key);\n                did_parse = false;\n            }\n        } else if (string_equals(key, ARGUMENT_RULE_KEY_APP)) {\n            has_filter = true;\n            rule->app = string_copy(value);\n            if (exclusion) rule_set_flag(rule, RULE_APP_EXCLUDE);\n            if (regcomp(&rule->app_regex, value, REG_EXTENDED) == 0) {\n                rule_set_flag(rule, RULE_APP_VALID);\n            } else {\n                daemon_fail(rsp, \"invalid regex pattern '%s' for key '%s'\\n\", value, key);\n                did_parse = false;\n            }\n        } else if (string_equals(key, ARGUMENT_RULE_KEY_TITLE)) {\n            has_filter = true;\n            rule->title = string_copy(value);\n            if (exclusion) rule_set_flag(rule, RULE_TITLE_EXCLUDE);\n            if (regcomp(&rule->title_regex, value, REG_EXTENDED) == 0) {\n                rule_set_flag(rule, RULE_TITLE_VALID);\n            } else {\n                daemon_fail(rsp, \"invalid regex pattern '%s' for key '%s'\\n\", value, key);\n                did_parse = false;\n            }\n        } else if (string_equals(key, ARGUMENT_RULE_KEY_ROLE)) {\n            has_filter = true;\n            rule->role = string_copy(value);\n            if (exclusion) rule_set_flag(rule, RULE_ROLE_EXCLUDE);\n            if (regcomp(&rule->role_regex, value, REG_EXTENDED) == 0) {\n                rule_set_flag(rule, RULE_ROLE_VALID);\n            } else {\n                daemon_fail(rsp, \"invalid regex pattern '%s' for key '%s'\\n\", value, key);\n                did_parse = false;\n            }\n        } else if (string_equals(key, ARGUMENT_RULE_KEY_SUBROLE)) {\n            has_filter = true;\n            rule->subrole = string_copy(value);\n            if (exclusion) rule_set_flag(rule, RULE_SUBROLE_EXCLUDE);\n            if (regcomp(&rule->subrole_regex, value, REG_EXTENDED) == 0) {\n                rule_set_flag(rule, RULE_SUBROLE_VALID);\n            } else {\n                daemon_fail(rsp, \"invalid regex pattern '%s' for key '%s'\\n\", value, key);\n                did_parse = false;\n            }\n        } else if (string_equals(key, ARGUMENT_RULE_KEY_DISPLAY)) {\n            if (exclusion) unsupported_exclusion = key;\n\n            if (value[0] == ARGUMENT_RULE_VALUE_SPACE) {\n                ++value;\n                rule_effects_set_flag(&rule->effects, RULE_FOLLOW_SPACE);\n            }\n\n            struct selector selector = parse_display_selector(rsp, &value, display_manager_active_display_id(), false);\n            if (selector.did_parse && selector.did) {\n                rule->effects.did = selector.did;\n            } else {\n                did_parse = false;\n            }\n        } else if (string_equals(key, ARGUMENT_RULE_KEY_SPACE)) {\n            if (exclusion) unsupported_exclusion = key;\n\n            if (value[0] == ARGUMENT_RULE_VALUE_SPACE) {\n                ++value;\n                rule_effects_set_flag(&rule->effects, RULE_FOLLOW_SPACE);\n            }\n\n            struct selector selector = parse_space_selector(rsp, &value, space_manager_active_space(), false);\n            if (selector.did_parse && selector.sid) {\n                rule->effects.sid = selector.sid;\n            } else {\n                did_parse = false;\n            }\n        } else if (string_equals(key, ARGUMENT_RULE_KEY_GRID)) {\n            if (exclusion) unsupported_exclusion = key;\n\n            if ((sscanf(value, ARGUMENT_RULE_VALUE_GRID,\n                        &rule->effects.grid[0], &rule->effects.grid[1],\n                        &rule->effects.grid[2], &rule->effects.grid[3],\n                        &rule->effects.grid[4], &rule->effects.grid[5]) != 6)) {\n                daemon_fail(rsp, \"invalid value '%s' for key '%s'\\n\", value, key);\n                did_parse = false;\n            }\n        } else if (string_equals(key, ARGUMENT_RULE_KEY_OPACITY)) {\n            if (exclusion) unsupported_exclusion = key;\n\n            if ((sscanf(value, \"%f\", &rule->effects.opacity) == 1) && (in_range_ii(rule->effects.opacity, 0.0f, 1.0f))) {\n                rule_effects_set_flag(&rule->effects, RULE_OPACITY);\n            } else {\n                daemon_fail(rsp, \"invalid value '%s' for key '%s'\\n\", value, key);\n                did_parse = false;\n            }\n        } else if (string_equals(key, ARGUMENT_RULE_KEY_MANAGE)) {\n            if (exclusion) unsupported_exclusion = key;\n\n            if (string_equals(value, ARGUMENT_COMMON_VAL_ON)) {\n                rule->effects.manage = RULE_PROP_ON;\n            } else if (string_equals(value, ARGUMENT_COMMON_VAL_OFF)) {\n                rule->effects.manage = RULE_PROP_OFF;\n            } else {\n                daemon_fail(rsp, \"invalid value '%s' for key '%s'\\n\", value, key);\n                did_parse = false;\n            }\n        } else if (string_equals(key, ARGUMENT_RULE_KEY_STICKY)) {\n            if (exclusion) unsupported_exclusion = key;\n\n            if (string_equals(value, ARGUMENT_COMMON_VAL_ON)) {\n                rule->effects.sticky = RULE_PROP_ON;\n            } else if (string_equals(value, ARGUMENT_COMMON_VAL_OFF)) {\n                rule->effects.sticky = RULE_PROP_OFF;\n            } else {\n                daemon_fail(rsp, \"invalid value '%s' for key '%s'\\n\", value, key);\n                did_parse = false;\n            }\n        } else if (string_equals(key, ARGUMENT_RULE_KEY_MFF)) {\n            if (exclusion) unsupported_exclusion = key;\n\n            if (string_equals(value, ARGUMENT_COMMON_VAL_ON)) {\n                rule->effects.mff = RULE_PROP_ON;\n            } else if (string_equals(value, ARGUMENT_COMMON_VAL_OFF)) {\n                rule->effects.mff = RULE_PROP_OFF;\n            } else {\n                daemon_fail(rsp, \"invalid value '%s' for key '%s'\\n\", value, key);\n                did_parse = false;\n            }\n        } else if (string_equals(key, ARGUMENT_RULE_KEY_SUB_LAYER)) {\n            if (exclusion) unsupported_exclusion = key;\n\n            if (string_equals(value, ARGUMENT_WINDOW_LAYER_BELOW)) {\n                rule->effects.layer = LAYER_BELOW;\n                rule_effects_set_flag(&rule->effects, RULE_LAYER);\n            } else if (string_equals(value, ARGUMENT_WINDOW_LAYER_NORMAL)) {\n                rule->effects.layer = LAYER_NORMAL;\n                rule_effects_set_flag(&rule->effects, RULE_LAYER);\n            } else if (string_equals(value, ARGUMENT_WINDOW_LAYER_ABOVE)) {\n                rule->effects.layer = LAYER_ABOVE;\n                rule_effects_set_flag(&rule->effects, RULE_LAYER);\n            } else if (string_equals(value, ARGUMENT_WINDOW_LAYER_AUTO)) {\n                rule->effects.layer = LAYER_AUTO;\n                rule_effects_set_flag(&rule->effects, RULE_LAYER);\n            } else {\n                daemon_fail(rsp, \"invalid value '%s' for key '%s'\\n\", value, key);\n                did_parse = false;\n            }\n        } else if (string_equals(key, ARGUMENT_RULE_KEY_FULLSCR)) {\n            if (exclusion) unsupported_exclusion = key;\n\n            if (string_equals(value, ARGUMENT_COMMON_VAL_ON)) {\n                rule->effects.fullscreen = RULE_PROP_ON;\n            } else if (string_equals(value, ARGUMENT_COMMON_VAL_OFF)) {\n                rule->effects.fullscreen = RULE_PROP_OFF;\n            } else {\n                daemon_fail(rsp, \"invalid value '%s' for key '%s'\\n\", value, key);\n                did_parse = false;\n            }\n        } else {\n            daemon_fail(rsp, \"unknown key '%s'\\n\", key);\n            did_parse = false;\n        }\n    }\n\n    if (!has_filter) {\n        daemon_fail(rsp, \"missing required key-value pair 'app[!]=..' or 'title[!]=..'\\n\");\n        did_parse = false;\n    }\n\n    if (unsupported_exclusion) {\n        daemon_fail(rsp, \"unsupported token '!' (exclusion) given for key '%s'\\n\", unsupported_exclusion);\n        did_parse = false;\n    }\n\n    return did_parse;\n}\n\nstatic void handle_domain_rule(FILE *rsp, struct token domain, char *message)\n{\n    TIME_FUNCTION;\n\n    struct token command = get_token(&message);\n    if (token_equals(command, COMMAND_RULE_ADD)) {\n        struct rule rule = {0};\n\n        struct token token = get_token(&message);\n        if (token_equals(token, ARGUMENT_RULE_ONE_SHOT)) {\n            rule_set_flag(&rule, RULE_ONE_SHOT);\n            token = get_token(&message);\n        }\n\n        if (parse_rule(rsp, &message, &rule, token)) {\n            rule_add(&rule);\n        } else {\n            rule_destroy(&rule);\n        }\n    } else if (token_equals(command, COMMAND_RULE_APPLY)) {\n        struct token_value value = token_to_value(get_token(&message));\n        if (value.type == TOKEN_TYPE_INT) {\n            if (!rule_reapply_by_index(value.int_value)) {\n                daemon_fail(rsp, \"rule with index '%d' not found.\\n\", value.int_value);\n            }\n        } else if (value.type == TOKEN_TYPE_STRING) {\n            if (!rule_reapply_by_label(value.string_value)) {\n                struct rule rule = {0};\n                if (parse_rule(rsp, &message, &rule, value.token)) {\n                    rule_apply(&rule);\n                }\n                rule_destroy(&rule);\n            }\n        } else if (value.type == TOKEN_TYPE_INVALID) {\n            rule_reapply_all();\n        } else {\n            daemon_fail(rsp, \"value '%.*s' is not a valid option for RULE_SEL\\n\", value.token.length, value.token.text);\n        }\n    } else if (token_equals(command, COMMAND_RULE_REM)) {\n        struct token_value value = token_to_value(get_token(&message));\n        if (value.type == TOKEN_TYPE_INT) {\n            if (!rule_remove_by_index(value.int_value)) {\n                daemon_fail(rsp, \"rule with index '%d' not found.\\n\", value.int_value);\n            }\n        } else if (value.type == TOKEN_TYPE_STRING) {\n            if (!rule_remove_by_label(value.string_value)) {\n                daemon_fail(rsp, \"rule with label '%s' not found.\\n\", value.string_value);\n            }\n        } else {\n            daemon_fail(rsp, \"value '%.*s' is not a valid option for RULE_SEL\\n\", value.token.length, value.token.text);\n        }\n    } else if (token_equals(command, COMMAND_RULE_LS)) {\n        window_manager_query_window_rules(rsp);\n    } else {\n        daemon_fail(rsp, \"unknown command '%.*s' for domain '%.*s'\\n\", command.length, command.text, domain.length, domain.text);\n    }\n}\n\nstatic void handle_domain_signal(FILE *rsp, struct token domain, char *message)\n{\n    TIME_FUNCTION;\n\n    struct token command = get_token(&message);\n    if (token_equals(command, COMMAND_SIGNAL_ADD)) {\n        char *unsupported_exclusion = NULL;\n        bool did_parse = true;\n        bool has_command = false;\n        bool has_signal_type = false;\n        enum signal_type signal_type = SIGNAL_TYPE_UNKNOWN;\n        struct signal signal = {0};\n\n        for (struct token token = get_token(&message); token_is_valid(token); token = get_token(&message)) {\n            char *key = NULL;\n            char *value = NULL;\n            bool exclusion = false;\n            parse_key_value_pair(token.text, &key, &value, &exclusion);\n\n            if (!key || !value) {\n                daemon_fail(rsp, \"invalid key-value pair '%s'\\n\", token.text);\n                did_parse = false;\n                continue;\n            }\n\n            if (string_equals(key, ARGUMENT_SIGNAL_KEY_LABEL)) {\n                if (exclusion) unsupported_exclusion = key;\n                signal.label = string_copy(value);\n            } else if (string_equals(key, ARGUMENT_SIGNAL_KEY_APP)) {\n                signal.app = string_copy(value);\n                signal.app_regex_exclude = exclusion;\n                signal.app_regex_valid = regcomp(&signal.app_regex, value, REG_EXTENDED) == 0;\n                if (!signal.app_regex_valid) {\n                    daemon_fail(rsp, \"invalid regex pattern '%s' for key '%s'\\n\", value, key);\n                    did_parse = false;\n                }\n            } else if (string_equals(key, ARGUMENT_SIGNAL_KEY_TITLE)) {\n                signal.title = string_copy(value);\n                signal.title_regex_exclude = exclusion;\n                signal.title_regex_valid = regcomp(&signal.title_regex, value, REG_EXTENDED) == 0;\n                if (!signal.title_regex_valid) {\n                    daemon_fail(rsp, \"invalid regex pattern '%s' for key '%s'\\n\", value, key);\n                    did_parse = false;\n                }\n            } else if (string_equals(key, ARGUMENT_SIGNAL_KEY_ACTIVE)) {\n                if (exclusion) unsupported_exclusion = key;\n\n                if (string_equals(value, ARGUMENT_SIGNAL_VALUE_YES)) {\n                    signal.active = SIGNAL_PROP_YES;\n                } else if (string_equals(value, ARGUMENT_SIGNAL_VALUE_NO)) {\n                    signal.active = SIGNAL_PROP_NO;\n                } else {\n                    daemon_fail(rsp, \"invalid value '%s' for key '%s'\\n\", value, key);\n                    did_parse = false;\n                }\n            } else if (string_equals(key, ARGUMENT_SIGNAL_KEY_ACTION)) {\n                if (exclusion) unsupported_exclusion = key;\n\n                has_command = true;\n                signal.command = string_copy(value);\n            } else if (string_equals(key, ARGUMENT_SIGNAL_KEY_EVENT)) {\n                if (exclusion) unsupported_exclusion = key;\n\n                has_signal_type = true;\n                signal_type = signal_type_from_string(value);\n                if (signal_type == SIGNAL_TYPE_UNKNOWN) {\n                    daemon_fail(rsp, \"invalid value '%s' for key '%s'\\n\", value, key);\n                    did_parse = false;\n                }\n            } else {\n                daemon_fail(rsp, \"unknown key '%s'\\n\", key);\n                did_parse = false;\n            }\n        }\n\n        if (!has_signal_type) {\n            daemon_fail(rsp, \"missing required key-value pair 'event=..'\\n\");\n            did_parse = false;\n        }\n\n        if (!has_command) {\n            daemon_fail(rsp, \"missing required key-value pair 'action=..'\\n\");\n            did_parse = false;\n        }\n\n        if (unsupported_exclusion) {\n            daemon_fail(rsp, \"unsupported token '!' (exclusion) given for key '%s'\\n\", unsupported_exclusion);\n            did_parse = false;\n        }\n\n        if (did_parse) {\n            event_signal_add(signal_type, &signal);\n        } else {\n            event_signal_destroy(&signal);\n        }\n    } else if (token_equals(command, COMMAND_SIGNAL_REM)) {\n        struct token_value value = token_to_value(get_token(&message));\n        if (value.type == TOKEN_TYPE_INT) {\n            if (!event_signal_remove_by_index(value.int_value)) {\n                daemon_fail(rsp, \"signal with index '%d' not found.\\n\", value.int_value);\n            }\n        } else if (value.type == TOKEN_TYPE_STRING) {\n            if (!event_signal_remove(value.string_value)) {\n                daemon_fail(rsp, \"signal with label '%s' not found.\\n\", value.string_value);\n            }\n        } else {\n            daemon_fail(rsp, \"value '%.*s' is not a valid option for SIGNAL_SEL\\n\", value.token.length, value.token.text);\n        }\n    } else if (token_equals(command, COMMAND_SIGNAL_LS)) {\n        event_signal_list(rsp);\n    } else {\n        daemon_fail(rsp, \"unknown command '%.*s' for domain '%.*s'\\n\", command.length, command.text, domain.length, domain.text);\n    }\n}\n\nvoid handle_message(FILE *rsp, char *message)\n{\n    struct token domain = get_token(&message);\n    if (token_equals(domain, DOMAIN_CONFIG)) {\n        handle_domain_config(rsp, domain, message);\n    } else if (token_equals(domain, DOMAIN_DISPLAY)) {\n        handle_domain_display(rsp, domain, message);\n    } else if (token_equals(domain, DOMAIN_SPACE)) {\n        handle_domain_space(rsp, domain, message);\n    } else if (token_equals(domain, DOMAIN_WINDOW)) {\n        handle_domain_window(rsp, domain, message);\n    } else if (token_equals(domain, DOMAIN_QUERY)) {\n        handle_domain_query(rsp, domain, message);\n    } else if (token_equals(domain, DOMAIN_RULE)) {\n        handle_domain_rule(rsp, domain, message);\n    } else if (token_equals(domain, DOMAIN_SIGNAL)) {\n        handle_domain_signal(rsp, domain, message);\n    } else {\n        daemon_fail(rsp, \"unknown domain '%.*s'\\n\", domain.length, domain.text);\n    }\n}\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wunused-parameter\"\nstatic void *message_loop_run(void *context)\n{\n    while (g_message_loop.is_running) {\n        int sockfd = accept(g_message_loop.sockfd, NULL, 0);\n        if (sockfd == -1) continue;\n\n        event_loop_post(&g_event_loop, DAEMON_MESSAGE, NULL, sockfd);\n    }\n\n    return NULL;\n}\n#pragma clang diagnostic pop\n\nbool message_loop_begin(char *socket_path)\n{\n    struct sockaddr_un socket_address;\n    socket_address.sun_family = AF_UNIX;\n    snprintf(socket_address.sun_path, sizeof(socket_address.sun_path), \"%s\", socket_path);\n    unlink(socket_path);\n\n    if ((g_message_loop.sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {\n        return false;\n    }\n\n    if (bind(g_message_loop.sockfd, (struct sockaddr *) &socket_address, sizeof(socket_address)) == -1) {\n        return false;\n    }\n\n    if (chmod(socket_path, 0600) != 0) {\n        return false;\n    }\n\n    if (listen(g_message_loop.sockfd, SOMAXCONN) == -1) {\n        return false;\n    }\n\n    fcntl(g_message_loop.sockfd, F_SETFD, FD_CLOEXEC | fcntl(g_message_loop.sockfd, F_GETFD));\n\n    g_message_loop.is_running = true;\n    pthread_create(&g_message_loop.thread, NULL, &message_loop_run, NULL);\n\n    return true;\n}\n"
  },
  {
    "path": "src/message.h",
    "content": "#ifndef MESSAGE_H\n#define MESSAGE_H\n\nvoid handle_message(FILE *rsp, char *message);\nbool message_loop_begin(char *socket_path);\n\n#endif\n"
  },
  {
    "path": "src/misc/autorelease.h",
    "content": "#include <objc/runtime.h>\n\nIMP g_nsobject_autorelease;\nIMP g_nsautoreleasepool_drain;\nIMP g_nsautoreleasepool_release;\n\n@implementation NSObject(swizzle)\n- (NSObject *)fake_autorelease\n{\n    void *addr[40];\n    int frame_count = backtrace(addr, sizeof(addr)/sizeof(*addr));\n    if (frame_count > 1) {\n        char **syms = backtrace_symbols(addr, frame_count);\n        for (int f = 0; f < frame_count; ++f) {\n            printf(\"%s caller: %s\\n\", __FUNCTION__, syms[f]);\n        }\n        printf(\"\\n\");\n        free(syms);\n    } else {\n        printf(\"%s: *** Failed to generate backtrace.\", __FUNCTION__);\n    }\n\n    ((void(*)(id))g_nsobject_autorelease)(self);\n\n    return self;\n}\n@end\n\n@implementation NSAutoreleasePool(swizzle)\n- (void)fake_drain\n{\n    void *addr[40];\n    int frame_count = backtrace(addr, sizeof(addr)/sizeof(*addr));\n    if (frame_count > 1) {\n        char **syms = backtrace_symbols(addr, frame_count);\n        for (int f = 0; f < frame_count; ++f) {\n            printf(\"%s caller: %s\\n\", __FUNCTION__, syms[f]);\n        }\n        printf(\"\\n\");\n        free(syms);\n    } else {\n        printf(\"%s: *** Failed to generate backtrace.\", __FUNCTION__);\n    }\n\n    ((void(*)(id))g_nsautoreleasepool_drain)(self);\n}\n\n- (void)fake_release\n{\n    void *addr[40];\n    int frame_count = backtrace(addr, sizeof(addr)/sizeof(*addr));\n    if (frame_count > 1) {\n        char **syms = backtrace_symbols(addr, frame_count);\n        for (int f = 0; f < frame_count; ++f) {\n            printf(\"%s caller: %s\\n\", __FUNCTION__, syms[f]);\n        }\n        printf(\"\\n\");\n        free(syms);\n    } else {\n        printf(\"%s: *** Failed to generate backtrace.\", __FUNCTION__);\n    }\n\n    ((void(*)(id))g_nsautoreleasepool_release)(self);\n}\n@end\n\nstatic bool hook_nsobject_autorelease(void)\n{\n    Class c = objc_getClass(\"NSObject\");\n    if (!c) return false;\n\n    Method m = class_getInstanceMethod(c, @selector(autorelease));\n    g_nsobject_autorelease = method_setImplementation(m, (IMP)method_getImplementation(class_getInstanceMethod(c, @selector(fake_autorelease))));\n\n    return true;\n}\n\nstatic bool hook_autoreleasepool_drain(void)\n{\n    Class c = objc_getClass(\"NSAutoreleasePool\");\n    if (!c) return false;\n\n    Method m = class_getInstanceMethod(c, @selector(drain));\n    g_nsautoreleasepool_drain = method_setImplementation(m, (IMP)method_getImplementation(class_getInstanceMethod(c, @selector(fake_drain))));\n\n    return true;\n}\n\nstatic bool hook_autoreleasepool_release(void)\n{\n    Class c = objc_getClass(\"NSAutoreleasePool\");\n    if (!c) return false;\n\n    Method m = class_getInstanceMethod(c, @selector(release));\n    g_nsautoreleasepool_release = method_setImplementation(m, (IMP)method_getImplementation(class_getInstanceMethod(c, @selector(fake_release))));\n\n    return true;\n}\n"
  },
  {
    "path": "src/misc/extern.h",
    "content": "#define CONNECTION_CALLBACK(name) void name(uint32_t type, void *data, size_t data_length, void *context, int cid)\ntypedef CONNECTION_CALLBACK(connection_callback);\n\nstatic mach_port_t (* CGSGetConnectionPortById)(int);\nextern mach_port_t mig_get_special_reply_port(void);\nextern AXUIElementRef _AXUIElementCreateWithRemoteToken(CFDataRef data);\nextern AXError _AXUIElementGetWindow(AXUIElementRef ref, uint32_t *wid);\nextern int SLSMainConnectionID(void);\nextern CGError SLSNewConnection(int zero, int *cid);\nextern CGError SLSReleaseConnection(int cid);\nextern CGError SLSRegisterConnectionNotifyProc(int cid, connection_callback *handler, uint32_t event, void *context);\nextern CGError SLSGetWindowBounds(int cid, uint32_t wid, CGRect *frame);\nextern CGError SLSGetWindowLevel(int cid, uint32_t wid, int *level);\nextern int SLSGetWindowSubLevel(int cid, uint32_t wid);\nextern CGError SLSGetWindowAlpha(int cid, uint32_t wid, float *alpha);\nextern CGError SLSSetWindowAlpha(int cid, uint32_t wid, float alpha);\nextern CGError SLSSetWindowResolution(int cid, uint32_t wid, double resolution);\nextern CGError SLSCopyWindowProperty(int cid, uint32_t wid, CFStringRef property, CFTypeRef *value);\nextern CFStringRef SLSCopyManagedDisplayForWindow(int cid, uint32_t wid);\nextern CFStringRef SLSCopyBestManagedDisplayForRect(int cid, CGRect rect);\nextern CFArrayRef SLSCopySpacesForWindows(int cid, int selector, CFArrayRef window_list);\nextern CGError SLSDisableUpdate(int cid);\nextern CGError SLSReenableUpdate(int cid);\nextern CGError SLSNewWindow(int cid, int type, float x, float y, CFTypeRef region, uint32_t *wid);\nextern CGError SLSNewWindowWithOpaqueShapeAndContext(int cid, int type, CFTypeRef region, CFTypeRef opaque_shape, int options, uint64_t *tags, float x, float y, int tag_size, uint32_t *wid, void *context);\nextern CGError SLSReleaseWindow(int cid, uint32_t wid);\nextern CGError SLSSetWindowTags(int cid, uint32_t wid, uint64_t *tags, int tag_size);\nextern CGError SLSClearWindowTags(int cid, uint32_t wid, uint64_t *tags, int tag_size);\nextern CGError SLSSetWindowShape(int cid, uint32_t wid, float x_offset, float y_offset, CFTypeRef shape);\nextern CGError SLSSetWindowOpacity(int cid, uint32_t wid, bool opaque);\nextern CGError SLSSetWindowBackgroundBlurRadiusStyle(int cid, uint32_t wid, int radius, int style);\nextern CGError SLSOrderWindow(int cid, uint32_t wid, int mode, uint32_t rel_wid);\nextern CGError SLSWindowIsOrderedIn(int cid, uint32_t wid, uint8_t *value);\nextern CGError SLSSetWindowLevel(int cid, uint32_t wid, int level);\nextern CGError SLSSetWindowSubLevel(int cid, uint32_t wid, int sub_level);\nextern CGContextRef SLWindowContextCreate(int cid, uint32_t wid, CFDictionaryRef options);\nextern CFTypeRef CGRegionCreateEmptyRegion(void);\nextern CGError CGSNewRegionWithRect(CGRect *rect, CFTypeRef *region);\nextern CFUUIDRef CGDisplayCreateUUIDFromDisplayID(uint32_t did);\nextern CFArrayRef SLSCopyManagedDisplays(int cid);\nextern uint64_t SLSManagedDisplayGetCurrentSpace(int cid, CFStringRef uuid);\nextern CFStringRef SLSCopyActiveMenuBarDisplayIdentifier(int cid);\nextern CGError SLSSetActiveMenuBarDisplayIdentifier(int cid, CFStringRef uuid, CFStringRef repeat_uuid);\nextern CFStringRef SLSCopyBestManagedDisplayForPoint(int cid, CGPoint point);\nextern bool SLSManagedDisplayIsAnimating(int cid, CFStringRef uuid);\nextern CGError SLSSetMenuBarInsetAndAlpha(int cid, double unused1, double unused2, float alpha);\nextern CGError SLSGetMenuBarAutohideEnabled(int cid, int *enabled);\nextern CGError SLSGetRevealedMenuBarBounds(CGRect *rect, int cid, uint64_t sid);\nextern CGError SLSGetDisplayMenubarHeight(uint32_t did, uint32_t *height);\nextern CGError SLSGetDockRectWithReason(int cid, CGRect *rect, int *reason);\nextern Boolean CoreDockGetAutoHideEnabled(void);\nextern void CoreDockGetOrientationAndPinning(int *orientation, int *pinning);\nextern CFStringRef SLSCopyManagedDisplayForSpace(int cid, uint64_t sid);\nextern int SLSSpaceGetType(int cid, uint64_t sid);\nextern CFStringRef SLSSpaceCopyName(int cid, uint64_t sid);\nextern CFArrayRef SLSCopyWindowsWithOptionsAndTags(int cid, uint32_t owner, CFArrayRef spaces, uint32_t options, uint64_t *set_tags, uint64_t *clear_tags);\nextern int SLSGetSpaceManagementMode(int cid);\nextern CFArrayRef SLSCopyManagedDisplaySpaces(int cid);\nextern CGError SLSProcessAssignToSpace(int cid, pid_t pid, uint64_t sid);\nextern CGError SLSProcessAssignToAllSpaces(int cid, pid_t pid);\nextern void SLSMoveWindowsToManagedSpace(int cid, CFArrayRef window_list, uint64_t sid);\nextern CGError CoreDockSendNotification(CFStringRef notification, int unknown);\nextern CGError SLSMoveWindow(int cid, uint32_t wid, CGPoint *point);\nextern CFArrayRef SLSCopyAssociatedWindows(int cid, uint32_t wid);\nextern CFTypeRef SLSWindowQueryWindows(int cid, CFArrayRef windows, int count);\nextern CFTypeRef SLSWindowQueryResultCopyWindows(CFTypeRef window_query);\nextern int SLSWindowIteratorGetCount(CFTypeRef iterator);\nextern bool SLSWindowIteratorAdvance(CFTypeRef iterator);\nextern uint32_t SLSWindowIteratorGetParentID(CFTypeRef iterator);\nextern uint32_t SLSWindowIteratorGetWindowID(CFTypeRef iterator);\nextern uint64_t SLSWindowIteratorGetTags(CFTypeRef iterator);\nextern uint64_t SLSWindowIteratorGetAttributes(CFTypeRef iterator);\nextern int SLSWindowIteratorGetLevel(CFTypeRef iterator);\nextern OSStatus _SLPSGetFrontProcess(ProcessSerialNumber *psn);\nextern CGError SLSGetWindowOwner(int cid, uint32_t wid, int *wcid);\nextern CGError SLSGetConnectionPSN(int cid, ProcessSerialNumber *psn);\nextern CGError SLSConnectionGetPID(int cid, pid_t *pid);\nextern CGError SLSGetConnectionIDForPSN(int cid, ProcessSerialNumber *psn, int *psn_cid);\nextern CGError _SLPSSetFrontProcessWithOptions(ProcessSerialNumber *psn, uint32_t wid, uint32_t mode);\nextern CGError SLPSPostEventRecordTo(ProcessSerialNumber *psn, uint8_t *bytes);\nextern OSStatus SLSFindWindowAndOwner(int cid, int zero, int one, int zero_again, CGPoint *screen_point, CGPoint *window_point, uint32_t *wid, int *wcid);\nextern CGError SLSGetCurrentCursorLocation(int cid, CGPoint *point);\nextern CGError SLSWindowSetShadowProperties(uint32_t wid, CFDictionaryRef options);\nextern CGError SLSRequestNotificationsForWindows(int cid, uint32_t *window_list, int window_count);\nextern CGError SLSSetWindowTransform(int cid, uint32_t wid, CGAffineTransform t);\nextern CFTypeRef SLSTransactionCreate(int cid);\nextern CGError SLSTransactionCommit(CFTypeRef transaction, int synchronous);\nextern CGError SLSTransactionSetWindowTransform(CFTypeRef transaction, uint32_t wid, int unknown, int unknown2, CGAffineTransform t);\nextern CGError SLSTransactionOrderWindow(CFTypeRef transaction, uint32_t wid, int order, uint32_t rel_wid);\nextern CGError SLSTransactionOrderWindowGroup(CFTypeRef transaction, uint32_t wid, int order, uint32_t rel_wid);\nextern CGError SLSTransactionSetWindowAlpha(CFTypeRef transaction, uint32_t wid, float alpha);\nextern CGError SLSTransactionSetWindowSystemAlpha(CFTypeRef transaction, uint32_t wid, float alpha);\nextern CFArrayRef SLSHWCaptureWindowList(int cid, uint32_t *window_list, int window_count, uint32_t options);\nextern CGError SLSSpaceSetCompatID(int cid, uint64_t sid, int workspace);\nextern CGError SLSSetWindowListWorkspace(int cid, uint32_t *window_list, int window_count, int workspace);\n"
  },
  {
    "path": "src/misc/hashtable.h",
    "content": "#ifndef HASHTABLE_H\n#define HASHTABLE_H\n\n#define TABLE_HASH_FUNC(name) unsigned long name(void *key)\ntypedef TABLE_HASH_FUNC(table_hash_func);\n\n#define TABLE_COMPARE_FUNC(name) int name(void *key_a, void *key_b)\ntypedef TABLE_COMPARE_FUNC(table_compare_func);\n\nstruct bucket\n{\n    void *key;\n    void *value;\n    struct bucket *next;\n};\nstruct table\n{\n    int count;\n    int capacity;\n    float max_load;\n    table_hash_func *hash;\n    table_compare_func *cmp;\n    struct bucket **buckets;\n};\n\nvoid table_init(struct table *table, int capacity, table_hash_func hash, table_compare_func cmp);\nvoid table_free(struct table *table);\n\n#define table_add(table, key, value) _table_add(table, key, sizeof(*key), value)\nvoid _table_add(struct table *table, void *key, int key_size, void *value);\nvoid table_remove(struct table *table, void *key);\nvoid *table_find(struct table *table, void *key);\n\n#define table_for(it, table, code) \\\n    for (int i = 0; i < table.capacity; ++i) { \\\n        for (struct bucket *bucket = table.buckets[i]; bucket; bucket = bucket->next) { \\\n            if (!bucket->value) continue; \\\n            it = bucket->value; \\\n            code; \\\n        } \\\n    }\n\n#endif\n\n#ifdef HASHTABLE_IMPLEMENTATION\nvoid table_init(struct table *table, int capacity, table_hash_func hash, table_compare_func cmp)\n{\n    table->count = 0;\n    table->capacity = capacity;\n    table->max_load = 0.75f;\n    table->hash = hash;\n    table->cmp = cmp;\n    table->buckets = malloc(sizeof(struct bucket *) * capacity);\n    memset(table->buckets, 0, sizeof(struct bucket *) * capacity);\n}\n\nvoid table_free(struct table *table)\n{\n    for (int i = 0; i < table->capacity; ++i) {\n        struct bucket *next, *bucket = table->buckets[i];\n        while (bucket) {\n            next = bucket->next;\n            free(bucket->key);\n            free(bucket);\n            bucket = next;\n        }\n    }\n\n    if (table->buckets) {\n        free(table->buckets);\n        table->buckets = NULL;\n    }\n}\n\nstatic struct bucket **\ntable_get_bucket(struct table *table, void *key)\n{\n    struct bucket **bucket = table->buckets + (table->hash(key) % table->capacity);\n    while (*bucket) {\n        if (table->cmp((*bucket)->key, key)) {\n            break;\n        }\n        bucket = &(*bucket)->next;\n    }\n    return bucket;\n}\n\nstatic void\ntable_rehash(struct table *table)\n{\n    struct bucket **old_buckets = table->buckets;\n    int old_capacity = table->capacity;\n\n    table->count = 0;\n    table->capacity = 2 * table->capacity;\n    table->buckets = malloc(sizeof(struct bucket *) * table->capacity);\n    memset(table->buckets, 0, sizeof(struct bucket *) * table->capacity);\n\n    for (int i = 0; i < old_capacity; ++i) {\n        struct bucket *next_bucket, *old_bucket = old_buckets[i];\n        while (old_bucket) {\n            struct bucket **new_bucket = table_get_bucket(table, old_bucket->key);\n            *new_bucket = malloc(sizeof(struct bucket));\n            (*new_bucket)->key = old_bucket->key;\n            (*new_bucket)->value = old_bucket->value;\n            (*new_bucket)->next = NULL;\n            ++table->count;\n            next_bucket = old_bucket->next;\n            free(old_bucket);\n            old_bucket = next_bucket;\n        }\n    }\n\n    free(old_buckets);\n}\n\nvoid _table_add(struct table *table, void *key, int key_size, void *value)\n{\n    struct bucket **bucket = table_get_bucket(table, key);\n    if (*bucket) {\n        if (!(*bucket)->value) {\n            (*bucket)->value = value;\n        }\n    } else {\n        *bucket = malloc(sizeof(struct bucket));\n        (*bucket)->key = malloc(key_size);\n        (*bucket)->value = value;\n        memcpy((*bucket)->key, key, key_size);\n        (*bucket)->next = NULL;\n        ++table->count;\n\n        float load = (1.0f * table->count) / table->capacity;\n        if (load > table->max_load) {\n            table_rehash(table);\n        }\n    }\n}\n\nvoid table_remove(struct table *table, void *key)\n{\n    struct bucket *next, **bucket = table_get_bucket(table, key);\n    if (*bucket) {\n        free((*bucket)->key);\n        next = (*bucket)->next;\n        free(*bucket);\n        *bucket = next;\n        --table->count;\n    }\n}\n\nvoid *table_find(struct table *table, void *key)\n{\n    struct bucket *bucket = *table_get_bucket(table, key);\n    return bucket ? bucket->value : NULL;\n}\n#endif\n"
  },
  {
    "path": "src/misc/helpers.h",
    "content": "#ifndef HELPERS_H\n#define HELPERS_H\n\n#define ANIMATION_EASING_TYPE_LIST \\\n    ANIMATION_EASING_TYPE_ENTRY(ease_in_sine) \\\n    ANIMATION_EASING_TYPE_ENTRY(ease_out_sine) \\\n    ANIMATION_EASING_TYPE_ENTRY(ease_in_out_sine) \\\n    ANIMATION_EASING_TYPE_ENTRY(ease_in_quad) \\\n    ANIMATION_EASING_TYPE_ENTRY(ease_out_quad) \\\n    ANIMATION_EASING_TYPE_ENTRY(ease_in_out_quad) \\\n    ANIMATION_EASING_TYPE_ENTRY(ease_in_cubic) \\\n    ANIMATION_EASING_TYPE_ENTRY(ease_out_cubic) \\\n    ANIMATION_EASING_TYPE_ENTRY(ease_in_out_cubic) \\\n    ANIMATION_EASING_TYPE_ENTRY(ease_in_quart) \\\n    ANIMATION_EASING_TYPE_ENTRY(ease_out_quart) \\\n    ANIMATION_EASING_TYPE_ENTRY(ease_in_out_quart) \\\n    ANIMATION_EASING_TYPE_ENTRY(ease_in_quint) \\\n    ANIMATION_EASING_TYPE_ENTRY(ease_out_quint) \\\n    ANIMATION_EASING_TYPE_ENTRY(ease_in_out_quint) \\\n    ANIMATION_EASING_TYPE_ENTRY(ease_in_expo) \\\n    ANIMATION_EASING_TYPE_ENTRY(ease_out_expo) \\\n    ANIMATION_EASING_TYPE_ENTRY(ease_in_out_expo) \\\n    ANIMATION_EASING_TYPE_ENTRY(ease_in_circ) \\\n    ANIMATION_EASING_TYPE_ENTRY(ease_out_circ) \\\n    ANIMATION_EASING_TYPE_ENTRY(ease_in_out_circ)\n\nenum animation_easing_type\n{\n#define ANIMATION_EASING_TYPE_ENTRY(value) value##_type,\n    ANIMATION_EASING_TYPE_LIST\n#undef ANIMATION_EASING_TYPE_ENTRY\n    EASING_TYPE_COUNT\n};\n\nstatic char *animation_easing_type_str[] =\n{\n#define ANIMATION_EASING_TYPE_ENTRY(value) [value##_type] = #value,\n    ANIMATION_EASING_TYPE_LIST\n#undef ANIMATION_EASING_TYPE_ENTRY\n};\n\nstatic inline float ease_in_sine(float t)\n{\n    return 1.0f - cosf((t * M_PI) / 2.0f);\n}\n\nstatic inline float ease_out_sine(float t)\n{\n    return sinf((t * M_PI) / 2.0f);\n}\n\nstatic inline float ease_in_out_sine(float t)\n{\n    return -(cosf(M_PI * t) - 1.0f) / 2.0f;\n}\n\nstatic inline float ease_in_quad(float t)\n{\n    return t * t;\n}\n\nstatic inline float ease_out_quad(float t)\n{\n    return 1.0f - (1.0f - t) * (1.0f - t);\n}\n\nstatic inline float ease_in_out_quad(float t)\n{\n    return t < 0.5f ? 2.0f * t * t : 1.0f - powf(-2.0f * t + 2.0f, 2.0f) / 2.0f;\n}\n\nstatic inline float ease_in_cubic(float t)\n{\n    return t * t * t;\n}\n\nstatic inline float ease_out_cubic(float t)\n{\n    return 1.0f - powf(1.0f - t, 3);\n}\n\nstatic inline float ease_in_out_cubic(float t)\n{\n    return t < 0.5f ? 4.0f * t * t * t : 1.0f - powf(-2.0f * t + 2.0f, 3.0f) / 2.0f;\n}\n\nstatic inline float ease_in_quart(float t)\n{\n    return t * t * t * t;\n}\n\nstatic inline float ease_out_quart(float t)\n{\n    return 1.0f - powf(1.0f - t, 4);\n}\n\nstatic inline float ease_in_out_quart(float t)\n{\n    return t < 0.5f ? 8.0f * t * t * t * t : 1.0f - powf(-2.0f * t + 2.0f, 4.0f) / 2.0f;\n}\n\nstatic inline float ease_in_quint(float t)\n{\n    return t * t * t * t * t;\n}\n\nstatic inline float ease_out_quint(float t)\n{\n    return 1.0f - powf(1.0f - t, 5);\n}\n\nstatic inline float ease_in_out_quint(float t)\n{\n    return t < 0.5f ? 16.0f * t * t * t * t * t : 1.0f - powf(-2.0f * t + 2.0f, 5.0f) / 2.0f;\n}\n\nstatic inline float ease_in_expo(float t)\n{\n    return t == 0.0f ? 0.0f : powf(2.0f, 10.0f * t - 10.0f);\n}\n\nstatic inline float ease_out_expo(float t)\n{\n    return t == 1.0f ? 1.0f : 1.0f - powf(2.0f, -10.0f * t);\n}\n\nstatic inline float ease_in_out_expo(float t)\n{\n    return t == 0.0f ? 0.0f : t == 1.0f ? 1.0f : t < 0.5f ? powf(2.0f, 20.0f * t - 10.0f) / 2.0f : (2.0f - powf(2.0f, -20.0f * t + 10.0f)) / 2.0f;\n}\n\nstatic inline float ease_in_circ(float t)\n{\n    return 1.0f - sqrtf(1.0f - powf(t, 2.0f));\n}\n\nstatic inline float ease_out_circ(float t)\n{\n    return sqrtf(1.0f - powf(t - 1.0f, 2.0f));\n}\n\nstatic inline float ease_in_out_circ(float t)\n{\n    return t < 0.5f ? (1.0f - sqrtf(1.0f - powf(2.0f * t, 2.0f))) / 2.0f : (sqrtf(1.0f - powf(-2.0f * t + 2.0f, 2.0f)) + 1.0f) / 2.0f;\n}\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wdeprecated-declarations\"\nstatic inline uint64_t read_os_timer(void)\n{\n    uint64_t result = mach_absolute_time();\n    Nanoseconds nano = AbsoluteToNanoseconds(*(AbsoluteTime *) &result);\n    return *(uint64_t *) &nano;\n}\n#pragma clang diagnostic pop\n\nstatic inline uint64_t read_os_freq(void)\n{\n    return 1000000000;\n}\n\nstruct rgba_color\n{\n    uint32_t p;\n    float r;\n    float g;\n    float b;\n    float a;\n};\n\nstatic const CFStringRef kAXEnhancedUserInterface = CFSTR(\"AXEnhancedUserInterface\");\n\nstatic const char *bool_str[] = { \"off\", \"on\" };\n\nstatic const char *layer_str[] =\n{\n    [LAYER_AUTO]   = \"auto\",\n    [LAYER_BELOW]  = \"below\",\n    [LAYER_NORMAL] = \"normal\",\n    [LAYER_ABOVE]  = \"above\"\n};\n\nstatic inline bool socket_open(int *sockfd)\n{\n    *sockfd = socket(AF_UNIX, SOCK_STREAM, 0);\n    return *sockfd != -1;\n}\n\nstatic inline bool socket_connect(int sockfd, char *socket_path)\n{\n    struct sockaddr_un socket_address;\n    socket_address.sun_family = AF_UNIX;\n\n    snprintf(socket_address.sun_path, sizeof(socket_address.sun_path), \"%s\", socket_path);\n    return connect(sockfd, (struct sockaddr *) &socket_address, sizeof(socket_address)) != -1;\n}\n\nstatic inline void socket_close(int sockfd)\n{\n    shutdown(sockfd, SHUT_RDWR);\n    close(sockfd);\n}\n\nstatic inline void mach_send(mach_port_t port, void *data, uint32_t size)\n{\n    struct {\n        mach_msg_header_t header;\n        mach_msg_size_t descriptor_count;\n        mach_msg_ool_descriptor_t descriptor;\n    } msg = {0};\n\n    msg.header.msgh_bits        = MACH_MSGH_BITS_SET(MACH_MSG_TYPE_COPY_SEND & MACH_MSGH_BITS_REMOTE_MASK, 0, 0, MACH_MSGH_BITS_COMPLEX);\n    msg.header.msgh_size        = sizeof(msg);\n    msg.header.msgh_remote_port = port;\n    msg.descriptor_count        = 1;\n    msg.descriptor.address      = data;\n    msg.descriptor.size         = size;\n    msg.descriptor.copy         = MACH_MSG_VIRTUAL_COPY;\n    msg.descriptor.deallocate   = false;\n    msg.descriptor.type         = MACH_MSG_OOL_DESCRIPTOR;\n\n    mach_msg(&msg.header, MACH_SEND_MSG, sizeof(msg), 0, 0, 0, 0);\n}\n\nstatic inline char *json_optional_bool(int value)\n{\n    if (value == 0) return \"null\";\n    if (value == 1) return \"true\";\n\n    return \"false\";\n}\n\nstatic inline char *json_bool(bool value)\n{\n    return value ? \"true\" : \"false\";\n}\n\nstatic inline struct rgba_color rgba_color_from_hex(uint32_t color)\n{\n    struct rgba_color result;\n    result.p = color;\n    result.r = ((color >> 0x10) & 0xff) / 255.0f;\n    result.g = ((color >> 0x08) & 0xff) / 255.0f;\n    result.b = ((color >> 0x00) & 0xff) / 255.0f;\n    result.a = ((color >> 0x18) & 0xff) / 255.0f;\n    return result;\n}\n\nstatic inline bool is_root(void)\n{\n    return getuid() == 0 || geteuid() == 0;\n}\n\nstatic inline bool string_equals(const char *a, const char *b)\n{\n    return a && b && strcmp(a, b) == 0;\n}\n\nstatic inline char *ts_string_escape(char *s)\n{\n    char *cursor = s;\n    int num_replacements = 0;\n\n    while (*cursor) {\n        if ((*cursor == '\"') ||\n            (*cursor == '\\\\') ||\n            (*cursor == '\\b') ||\n            (*cursor == '\\f') ||\n            (*cursor == '\\n') ||\n            (*cursor == '\\r') ||\n            (*cursor == '\\t')) {\n            ++num_replacements;\n        } else if (*cursor >= 0x00 && *cursor <= 0x1f) {\n            num_replacements += 5;\n        }\n\n        ++cursor;\n    }\n\n    if (num_replacements == 0) return NULL;\n\n    int size_in_bytes = (int)(cursor - s) + num_replacements;\n    char *result = ts_alloc_unaligned(sizeof(char) * (size_in_bytes+1));\n    result[size_in_bytes] = '\\0';\n\n    for (char *dst = result, *cursor = s; *cursor; ++cursor) {\n        if (*cursor == '\"') {\n            *dst++ = '\\\\';\n            *dst++ = '\"';\n        } else if (*cursor == '\\\\') {\n            *dst++ = '\\\\';\n            *dst++ = '\\\\';\n        } else if (*cursor == '\\b') {\n            *dst++ = '\\\\';\n            *dst++ = 'b';\n        } else if (*cursor == '\\f') {\n            *dst++ = '\\\\';\n            *dst++ = 'f';\n        } else if (*cursor == '\\n') {\n            *dst++ = '\\\\';\n            *dst++ = 'n';\n        } else if (*cursor == '\\r') {\n            *dst++ = '\\\\';\n            *dst++ = 'r';\n        } else if (*cursor == '\\t') {\n            *dst++ = '\\\\';\n            *dst++ = 't';\n        } else if (*cursor >= 0x00 && *cursor <= 0x1f) {\n            *dst++ = '\\\\';\n            *dst++ = 'u';\n            sprintf(dst, \"%04x\", (int)*cursor);\n            dst += 4;\n        } else {\n            *dst++ = *cursor;\n        }\n    }\n\n    return result;\n}\n\nstatic inline CFStringRef CFSTRINGNUM32(int32_t num)\n{\n    char num_str[255] = {0};\n    snprintf(num_str, sizeof(num_str), \"%d\", num);\n    return CFStringCreateWithCString(NULL, num_str, kCFStringEncodingMacRoman);\n}\n\nstatic inline CFNumberRef CFNUM32(int32_t num)\n{\n    return CFNumberCreate(NULL, kCFNumberSInt32Type, &num);\n}\n\nstatic inline void sls_window_disable_shadow(uint32_t id)\n{\n    CFNumberRef density = CFNUM32(0);\n    const void *keys[1] = { CFSTR(\"com.apple.WindowShadowDensity\") };\n    const void *values[1] = { density };\n    CFDictionaryRef options = CFDictionaryCreate(NULL, keys, values, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);\n    SLSWindowSetShadowProperties(id, options);\n    CFRelease(density);\n    CFRelease(options);\n}\n\nstatic inline CFArrayRef cfarray_of_cfnumbers(void *values, size_t size, int count, CFNumberType type)\n{\n    CFNumberRef temp[count];\n\n    for (int i = 0; i < count; ++i) {\n        temp[i] = CFNumberCreate(NULL, type, ((char *)values) + (size * i));\n    }\n\n    CFArrayRef result = CFArrayCreate(NULL, (const void **)temp, count, &kCFTypeArrayCallBacks);\n\n    for (int i = 0; i < count; ++i) {\n        CFRelease(temp[i]);\n    }\n\n    return result;\n}\n\nstatic inline char *ts_cfstring_copy(CFStringRef string)\n{\n    CFIndex num_bytes = CFStringGetMaximumSizeForEncoding(CFStringGetLength(string), kCFStringEncodingUTF8);\n    char *result = ts_alloc_unaligned(num_bytes + 1);\n\n    if (!CFStringGetCString(string, result, num_bytes + 1, kCFStringEncodingUTF8)) {\n        result = NULL;\n    }\n\n    return result;\n}\n\nstatic inline char *cfstring_copy(CFStringRef string)\n{\n    CFIndex num_bytes = CFStringGetMaximumSizeForEncoding(CFStringGetLength(string), kCFStringEncodingUTF8);\n    char *result = malloc(num_bytes + 1);\n    if (!result) return NULL;\n\n    if (!CFStringGetCString(string, result, num_bytes + 1, kCFStringEncodingUTF8)) {\n        free(result);\n        result = NULL;\n    }\n\n    return result;\n}\n\nstatic inline char *ts_string_copy(char *s)\n{\n    int length = strlen(s);\n    char *result = ts_alloc_unaligned(length + 1);\n\n    memcpy(result, s, length);\n    result[length] = '\\0';\n    return result;\n}\n\nstatic inline char *string_copy(char *s)\n{\n    int length = strlen(s);\n    char *result = malloc(length + 1);\n    if (!result) return NULL;\n\n    memcpy(result, s, length);\n    result[length] = '\\0';\n    return result;\n}\n\nstatic inline bool directory_exists(char *filename)\n{\n    struct stat buffer;\n\n    if (stat(filename, &buffer) != 0) {\n        return false;\n    }\n\n    return S_ISDIR(buffer.st_mode);\n}\n\nstatic inline bool file_exists(char *filename)\n{\n    struct stat buffer;\n\n    if (stat(filename, &buffer) != 0) {\n        return false;\n    }\n\n    if (buffer.st_mode & S_IFDIR) {\n        return false;\n    }\n\n    return true;\n}\n\nstatic inline bool file_can_execute(char *filename)\n{\n    struct stat buffer;\n\n    if (stat(filename, &buffer) != 0) {\n        return false;\n    }\n\n    return (buffer.st_mode & S_IXUSR);\n}\n\nstatic bool get_config_file(char *restrict filename, char *restrict buffer, int buffer_size)\n{\n    char *xdg_home = getenv(\"XDG_CONFIG_HOME\");\n    if (xdg_home && *xdg_home) {\n        snprintf(buffer, buffer_size, \"%s/yabai/%s\", xdg_home, filename);\n        if (file_exists(buffer)) return true;\n    }\n\n    char *home = getenv(\"HOME\");\n    if (!home) return false;\n\n    snprintf(buffer, buffer_size, \"%s/.config/yabai/%s\", home, filename);\n    if (file_exists(buffer)) return true;\n\n    snprintf(buffer, buffer_size, \"%s/.%s\", home, filename);\n    return file_exists(buffer);\n}\n\nstatic void exec_config_file(char *config_file, int config_file_size)\n{\n    if (config_file[0] == '\\0' && !get_config_file(\"yabairc\", config_file, config_file_size)) {\n        warn(\"yabai: could not locate config file..\\n\");\n        notify(\"configuration\", \"could not locate config file..\");\n        return;\n    }\n\n    if (!file_exists(config_file)) {\n        warn(\"yabai: configuration file '%s' does not exist..\\n\", config_file);\n        notify(\"configuration\", \"file '%s' does not exist..\", config_file);\n        return;\n    }\n\n    int pid = fork();\n    if (pid == 0) {\n        char **exec = file_can_execute(config_file)\n                    ? (char*[]){ \"/usr/bin/env\", \"sh\", \"-c\", config_file, NULL}\n                    : (char*[]){ \"/usr/bin/env\", \"sh\", config_file, NULL};\n        exit(execvp(exec[0], exec));\n    } else if (pid == -1) {\n        warn(\"yabai: failed to load config file '%s'\\n\", config_file);\n        notify(\"configuration\", \"failed to load file '%s'\", config_file);\n    }\n}\n\nstatic inline bool ax_privilege(void)\n{\n    const void *keys[] = { kAXTrustedCheckOptionPrompt };\n    const void *values[] = { kCFBooleanTrue };\n    CFDictionaryRef options = CFDictionaryCreate(NULL, keys, values, array_count(keys), &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);\n    bool result = AXIsProcessTrustedWithOptions(options);\n    CFRelease(options);\n    return result;\n}\n\nstatic inline uint32_t ax_window_id(AXUIElementRef ref)\n{\n    uint32_t wid = 0;\n    _AXUIElementGetWindow(ref, &wid);\n    return wid;\n}\n\nstatic inline pid_t ax_window_pid(AXUIElementRef ref)\n{\n    return *(pid_t *)((void *) ref + 0x10);\n}\n\nstatic inline bool ax_enhanced_userinterface(AXUIElementRef ref)\n{\n    Boolean result = 0;\n    CFTypeRef value;\n\n    if (AXUIElementCopyAttributeValue(ref, kAXEnhancedUserInterface, &value) == kAXErrorSuccess) {\n        result = CFBooleanGetValue(value);\n        CFRelease(value);\n    }\n\n    return result;\n}\n\n#define AX_ENHANCED_UI_WORKAROUND(r, c) \\\n{\\\n    bool eui = ax_enhanced_userinterface(r); \\\n    if (eui) AXUIElementSetAttributeValue(r, kAXEnhancedUserInterface, kCFBooleanFalse); \\\n    c \\\n    if (eui) AXUIElementSetAttributeValue(r, kAXEnhancedUserInterface, kCFBooleanTrue); \\\n}\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wdeprecated-declarations\"\nstatic inline bool psn_equals(ProcessSerialNumber *a, ProcessSerialNumber *b)\n{\n    Boolean result;\n    SameProcess(a, b, &result);\n    return result == 1;\n}\n#pragma clang diagnostic pop\n\nstatic inline float cgrect_clamp_x_radius(CGRect frame, float radius)\n{\n    if (radius * 2 > CGRectGetWidth(frame)) {\n        radius = CGRectGetWidth(frame) / 2;\n    }\n    return radius;\n}\n\nstatic inline float cgrect_clamp_y_radius(CGRect frame, float radius)\n{\n    if (radius * 2 > CGRectGetHeight(frame)) {\n        radius = CGRectGetHeight(frame) / 2;\n    }\n    return radius;\n}\n\nstatic inline bool cgrect_contains_point(CGRect r, CGPoint p)\n{\n    return p.x >= r.origin.x && p.x <= r.origin.x + r.size.width &&\n           p.y >= r.origin.y && p.y <= r.origin.y + r.size.height;\n}\n\nstatic inline bool triangle_contains_point(CGPoint t[3], CGPoint p)\n{\n    float l1 = (p.x - t[0].x) * (t[2].y - t[0].y) - (t[2].x - t[0].x) * (p.y - t[0].y);\n    float l2 = (p.x - t[1].x) * (t[0].y - t[1].y) - (t[0].x - t[1].x) * (p.y - t[1].y);\n    float l3 = (p.x - t[2].x) * (t[1].y - t[2].y) - (t[1].x - t[2].x) * (p.y - t[2].y);\n\n    return (l1 > 0.0f && l2 > 0.0f && l3 > 0.0f) || (l1 < 0.0f && l2 < 0.0f && l3 < 0.0f);\n}\n\nstatic inline int regex_match(bool valid, regex_t *regex, const char *match)\n{\n    if (!valid) return REGEX_MATCH_UD;\n\n    int result = regexec(regex, match, 0, NULL, 0);\n    return result == 0 ? REGEX_MATCH_YES : REGEX_MATCH_NO;\n}\n\nstatic inline float clampf_range(float value, float min, float max)\n{\n    if (value < min) return min;\n    if (value > max) return max;\n    return value;\n}\n\nstatic CGImageRef cgimage_restore_alpha(CGImageRef image)\n{\n    int width     = CGImageGetWidth(image);\n    int height    = CGImageGetHeight(image);\n    int pitch     = width * 4;\n    uint8_t *data = (uint8_t *) calloc(height * pitch, 1);\n\n    CGColorSpaceRef color_space = CGColorSpaceCreateDeviceRGB();\n    CGContextRef context = CGBitmapContextCreate(data, width, height, 8, pitch, color_space, kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedLast);\n    CGColorSpaceRelease(color_space);\n    CGContextDrawImage(context, CGRectMake(0, 0, width, height), image);\n\n#ifdef __x86_64__\n    __m128      inv255 = _mm_set1_ps(1.0f / 255.0f);\n    __m128      one255 = _mm_set1_ps(255.0f);\n    __m128        zero = _mm_set1_ps(0.0f);\n    __m128i    mask_ff = _mm_set1_epi32(0xff);\n#elif __arm64__\n    float32x4_t inv255 = vdupq_n_f32(1.0f / 255.0f);\n    float32x4_t one255 = vdupq_n_f32(255.0f);\n    float32x4_t   zero = vdupq_n_f32(0.0f);\n    int32x4_t  mask_ff = vdupq_n_s32(0xff);\n#endif\n\n    uint32_t *pixel = (uint32_t *) data;\n    for (int i = 0; i < height*width; i += 4) {\n#ifdef __x86_64__\n        __m128i source = _mm_loadu_si128((__m128i *) pixel);\n        __m128 r = _mm_cvtepi32_ps(_mm_and_si128(source, mask_ff));\n        __m128 g = _mm_cvtepi32_ps(_mm_and_si128(_mm_srli_epi32(source,  8), mask_ff));\n        __m128 b = _mm_cvtepi32_ps(_mm_and_si128(_mm_srli_epi32(source, 16), mask_ff));\n        __m128 a = _mm_cvtepi32_ps(_mm_and_si128(_mm_srli_epi32(source, 24), mask_ff));\n        __m128i mask = _mm_castps_si128(_mm_cmpgt_ps(a, zero));\n\n        r = _mm_mul_ps(one255, _mm_div_ps(r, a));\n        g = _mm_mul_ps(one255, _mm_div_ps(g, a));\n        b = _mm_mul_ps(one255, _mm_div_ps(b, a));\n\n        a = one255;\n\n        r = _mm_mul_ps(inv255, _mm_mul_ps(r, a));\n        g = _mm_mul_ps(inv255, _mm_mul_ps(g, a));\n        b = _mm_mul_ps(inv255, _mm_mul_ps(b, a));\n\n        __m128i sr = _mm_cvtps_epi32(r);\n        __m128i sg = _mm_slli_epi32(_mm_cvtps_epi32(g),  8);\n        __m128i sb = _mm_slli_epi32(_mm_cvtps_epi32(b), 16);\n        __m128i sa = _mm_slli_epi32(_mm_cvtps_epi32(a), 24);\n\n        __m128i color = _mm_or_si128(_mm_or_si128(_mm_or_si128(sr, sg), sb), sa);\n        __m128i masked_color = _mm_or_si128(_mm_and_si128(mask, color), _mm_andnot_si128(mask, source));\n        _mm_storeu_si128((__m128i *) pixel, masked_color);\n#elif __arm64__\n        int32x4_t source = vld1q_s32((int32_t *) pixel);\n        float32x4_t r = vcvtq_f32_s32(vandq_s32(source, mask_ff));\n        float32x4_t g = vcvtq_f32_s32(vandq_s32(vshlq_u32(source, vdupq_n_s32(-8)),  mask_ff));\n        float32x4_t b = vcvtq_f32_s32(vandq_s32(vshlq_u32(source, vdupq_n_s32(-16)), mask_ff));\n        float32x4_t a = vcvtq_f32_s32(vandq_s32(vshlq_u32(source, vdupq_n_s32(-24)), mask_ff));\n        int32x4_t mask = vreinterpretq_s32_f32(vcgtq_f32(a, zero));\n\n        r = vmulq_f32(one255, vdivq_f32(r, a));\n        g = vmulq_f32(one255, vdivq_f32(g, a));\n        b = vmulq_f32(one255, vdivq_f32(b, a));\n\n        a = one255;\n\n        r = vmulq_f32(inv255, vmulq_f32(r, a));\n        g = vmulq_f32(inv255, vmulq_f32(g, a));\n        b = vmulq_f32(inv255, vmulq_f32(b, a));\n\n        int32x4_t sr = vcvtnq_s32_f32(r);\n        int32x4_t sg = vshlq_s32(vcvtnq_s32_f32(g), vdupq_n_s32(8));\n        int32x4_t sb = vshlq_s32(vcvtnq_s32_f32(b), vdupq_n_s32(16));\n        int32x4_t sa = vshlq_s32(vcvtnq_s32_f32(a), vdupq_n_s32(24));\n\n        int32x4_t color = vorrq_s32(vorrq_s32(vorrq_s32(sr, sg), sb), sa);\n        int32x4_t masked_color = vorrq_s32(vandq_s32(color, mask), vbicq_s32(source, mask));\n        vst1q_s32((int32_t *) pixel, masked_color);\n#endif\n        pixel += 4;\n    }\n\n    CGImageRef result = CGBitmapContextCreateImage(context);\n    CGContextRelease(context);\n\n    free(data);\n    return result;\n}\n\n#endif\n"
  },
  {
    "path": "src/misc/log.h",
    "content": "#ifndef LOG_H\n#define LOG_H\n\nextern bool g_verbose;\n\nstatic inline void\ndebug(const char *format, ...)\n{\n    if (!g_verbose) return;\n\n    va_list args;\n    va_start(args, format);\n    vfprintf(stdout, format, args);\n    va_end(args);\n}\n\nstatic inline void\nwarn(const char *format, ...)\n{\n    va_list args;\n    va_start(args, format);\n    vfprintf(stderr, format, args);\n    va_end(args);\n}\n\nstatic inline void\nerror(const char *format, ...)\n{\n    va_list args;\n    va_start(args, format);\n    vfprintf(stderr, format, args);\n    va_end(args);\n\n    exit(EXIT_FAILURE);\n}\n\nstatic inline void\nrequire(const char *format, ...)\n{\n    va_list args;\n    va_start(args, format);\n    vfprintf(stderr, format, args);\n    va_end(args);\n\n    exit(EXIT_SUCCESS);\n}\n\nstatic inline void\ndebug_message(const char *prefix, char *message)\n{\n    if (!g_verbose) return;\n\n    fprintf(stdout, \"%s:\", prefix);\n\n    for (;*message;) {\n        message += fprintf(stdout, \" %s\", message);\n    }\n\n    putc('\\n', stdout);\n    fflush(stdout);\n}\n\n#endif\n"
  },
  {
    "path": "src/misc/macho_dlsym.h",
    "content": "static struct mach_header_64 *macho_find_image_header(char *target_name, uint64_t *slide)\n{\n    int image_count = _dyld_image_count();\n\n    for (int i = 0; i < image_count; ++i) {\n        const char *image_name = _dyld_get_image_name(i);\n        if (!image_name) continue;\n\n        if (string_equals(image_name, target_name)) {\n            *slide = _dyld_get_image_vmaddr_slide(i);\n            return (struct mach_header_64 *) _dyld_get_image_header(i);\n        }\n    }\n\n    return NULL;\n}\n\nstatic struct segment_command_64 *macho_find_linkedit_segment(struct mach_header_64 *header)\n{\n    uint64_t offset = sizeof(struct mach_header_64);\n\n    for (int i = 0; i < (int)header->ncmds; ++i) {\n        struct load_command *cmd = (struct load_command *)(((uint8_t *) header) + offset);\n\n        if (cmd->cmd == LC_SEGMENT_64) {\n            struct segment_command_64 *segment = (struct segment_command_64 *) cmd;\n            if (string_equals(segment->segname, SEG_LINKEDIT)) {\n                return segment;\n            }\n        }\n\n        offset += cmd->cmdsize;\n    }\n\n    return NULL;\n}\n\nstatic struct symtab_command *macho_find_symtab_command(struct mach_header_64 *header)\n{\n    uint64_t offset = sizeof(struct mach_header_64);\n\n    for (int i = 0; i < (int)header->ncmds; ++i) {\n        struct load_command *cmd = (struct load_command *)(((uint8_t *) header) + offset);\n\n        if (cmd->cmd == LC_SYMTAB) {\n            return (struct symtab_command *) cmd;\n        }\n\n        offset += cmd->cmdsize;\n    }\n\n    return NULL;\n}\n\nvoid *macho_find_symbol(char *target_image, char *target_symbol)\n{\n    uint64_t slide = 0;\n    struct mach_header_64 *header = macho_find_image_header(target_image, &slide);\n    if (!header) return NULL;\n\n    struct segment_command_64 *linkedit_segment = macho_find_linkedit_segment(header);\n    if (!linkedit_segment) return NULL;\n\n    struct symtab_command *symtab_command = macho_find_symtab_command(header);\n    if (!symtab_command) return NULL;\n\n    int symbol_count = symtab_command->nsyms;\n    void *symbol_str = (void *)(linkedit_segment->vmaddr - linkedit_segment->fileoff) + symtab_command->stroff + slide;\n    void *symbol_sym = (void *)(linkedit_segment->vmaddr - linkedit_segment->fileoff) + symtab_command->symoff + slide;\n\n    for (int i = 0; i < symbol_count; ++i) {\n        struct nlist_64 *list = (void *) symbol_sym + (i * sizeof(struct nlist_64));\n        char *symbol_name = (char *) symbol_str + list->n_un.n_strx;\n        if (string_equals(symbol_name, target_symbol)) {\n            return (void *)(list->n_value + slide);\n        }\n    }\n\n    return NULL;\n}\n"
  },
  {
    "path": "src/misc/macros.h",
    "content": "#ifndef MACROS_H\n#define MACROS_H\n\n#define KILOBYTES(value) ((value) * 1024ULL)\n#define MEGABYTES(value) (KILOBYTES(value) * 1024ULL)\n#define GIGABYTES(value) (MEGABYTES(value) * 1024ULL)\n\n#define array_count(a) (int)(sizeof((a)) / sizeof(*(a)))\n#define min(a, b) ((a) < (b) ? (a) : (b))\n#define max(a, b) ((a) > (b) ? (a) : (b))\n#define add_and_clamp_to_zero(a, b) (((a) + (b) <= 0) ? 0 : (a) + (b))\n#define in_range_ii(a, b, c) (((a) >= (b)) && ((a) <= (c)))\n#define in_range_ie(a, b, c) (((a) >= (b)) && ((a) <  (c)))\n#define in_range_ei(a, b, c) (((a) >  (b)) && ((a) <= (c)))\n#define in_range_ee(a, b, c) (((a) >  (b)) && ((a) <  (c)))\n#define lerp(a, t, b) (((1.0-t)*a) + (t*b))\n\n#define FAILURE_MESSAGE \"\\x07\"\n\n#define MAXLEN 512\n\n#define REGEX_MATCH_UD  0\n#define REGEX_MATCH_YES 1\n#define REGEX_MATCH_NO  2\n\n#define DIR_NORTH 360\n#define DIR_EAST   90\n#define DIR_SOUTH 180\n#define DIR_WEST  270\n\n#define STACK     111\n\n#define TYPE_ABS 0x1\n#define TYPE_REL 0x2\n\n#define HANDLE_TOP    0x01\n#define HANDLE_BOTTOM 0x02\n#define HANDLE_LEFT   0x04\n#define HANDLE_RIGHT  0x08\n#define HANDLE_ABS    0x10\n\n#define LAYER_AUTO    0\n#define LAYER_BELOW   kCGBackstopMenuLevelKey\n#define LAYER_NORMAL  kCGNormalWindowLevelKey\n#define LAYER_ABOVE   kCGFloatingWindowLevelKey\n\n#endif\n"
  },
  {
    "path": "src/misc/memory_pool.h",
    "content": "#ifndef MEMORY_POOL_H\n#define MEMORY_POOL_H\n\nstruct memory_pool\n{\n    void *memory;\n    uint64_t size;\n    volatile uint64_t used;\n};\n\nbool memory_pool_init(struct memory_pool *pool, uint64_t size)\n{\n    int page_size = getpagesize();\n\n    uint64_t num_pages = size / page_size;\n    uint64_t remainder = size % page_size;\n    if (remainder) num_pages++;\n\n    pool->used = 0;\n    pool->size = num_pages * page_size;\n    pool->memory = mmap(0, pool->size + page_size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);\n\n    bool result = pool->memory != MAP_FAILED;\n    if (result) mprotect(pool->memory + pool->size, page_size, PROT_NONE);\n\n    return result;\n}\n\nvoid *memory_pool_push(struct memory_pool *pool, uint64_t size)\n{\n    for (;;) {\n        uint64_t used = __atomic_load_n(&pool->used, __ATOMIC_RELAXED);\n        uint64_t new_used = used + size;\n\n        if (new_used < pool->size) {\n            if (__sync_bool_compare_and_swap(&pool->used, used, new_used)) {\n                return pool->memory + used;\n            }\n        } else {\n            if (__sync_bool_compare_and_swap(&pool->used, used, size)) {\n                return pool->memory;\n            }\n        }\n    }\n}\n\n#endif\n"
  },
  {
    "path": "src/misc/notify.h",
    "content": "#import <Foundation/Foundation.h>\n#import <objc/runtime.h>\n\nstatic bool g_notify_init;\nstatic NSImage *g_notify_img;\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wdeprecated-declarations\"\n\n@interface NotifyDelegate : NSObject <NSUserNotificationCenterDelegate>\n@end\n\n@implementation NotifyDelegate\n- (BOOL)userNotificationCenter:(NSUserNotificationCenter *)center shouldPresentNotification:(NSUserNotification *)notification\n{\n  return YES;\n}\n@end\n\nstatic bool notify_init(void)\n{\n    [[NSUserNotificationCenter defaultUserNotificationCenter] setDelegate:[NotifyDelegate alloc]];\n    g_notify_img = [[[NSWorkspace sharedWorkspace] iconForFile:[[[NSBundle mainBundle] executablePath] stringByResolvingSymlinksInPath]] retain];\n    g_notify_init = true;\n\n    return true;\n}\n\nstatic void notify(const char *subtitle, const char *format, ...)\n{\n    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];\n\n    if (!g_notify_init) notify_init();\n\n    va_list args;\n    va_start(args, format);\n    NSUserNotification *notification = [[NSUserNotification alloc] init];\n    notification.title = @\"yabai\";\n    notification.subtitle = [NSString stringWithUTF8String:subtitle];\n    notification.informativeText = [[[NSString alloc] initWithFormat:[NSString stringWithUTF8String:format] arguments:args] autorelease];\n    [notification setValue:g_notify_img forKey:@\"_identityImage\"];\n    [notification setValue:@(false) forKey:@\"_identityImageHasBorder\"];\n    [[NSUserNotificationCenter defaultUserNotificationCenter] deliverNotification:notification];\n    [notification release];\n    va_end(args);\n\n    [pool drain];\n}\n\n#pragma clang diagnostic pop\n"
  },
  {
    "path": "src/misc/sbuffer.h",
    "content": "#ifndef SBUFFER_H\n#define SBUFFER_H\n\nstruct buf_hdr\n{\n    int len;\n    int cap;\n    char buf[0];\n};\n\n#define buf__hdr(b) ((struct buf_hdr *)((char *)(b) - offsetof(struct buf_hdr, buf)))\n#define buf__should_grow(b, n) (buf_len(b) + (n) >= buf_cap(b))\n#define buf__fit(b, n) (buf__should_grow(b, n) ? ((b) = buf__grow_f(b, buf_len(b) + (n), sizeof(*(b)))) : 0)\n\n#define buf_len(b) ((b) ? buf__hdr(b)->len : 0)\n#define buf_cap(b) ((b) ? buf__hdr(b)->cap : 0)\n#define buf_last(b) ((b)[buf_len(b)-1])\n#define buf_push(b, x) (buf__fit(b, 1), (b)[buf_len(b)] = (x), buf__hdr(b)->len++)\n#define buf_del(b, x) ((b) ? (b)[x] = (b)[buf_len(b)-1], buf__hdr(b)->len-- : 0)\n#define buf_free(b) ((b) ? free(buf__hdr(b)) : 0)\n\nstatic void *buf__grow_f(const void *buf, int new_len, int elem_size)\n{\n    int new_cap = max(1 + 2*buf_cap(buf), new_len);\n    int new_size = offsetof(struct buf_hdr, buf) + new_cap*elem_size;\n    struct buf_hdr *new_hdr = realloc(buf ? buf__hdr(buf) : 0, new_size);\n    new_hdr->cap = new_cap;\n    if (!buf) {\n        new_hdr->len = 0;\n    }\n    return new_hdr->buf;\n}\n\nstruct ts_buf_hdr\n{\n    int len;\n    int cap;\n    char buf[0];\n};\n\n#define ts_buf__hdr(b) ((struct ts_buf_hdr *)((char *)(b) - offsetof(struct ts_buf_hdr, buf)))\n#define ts_buf__should_grow(b, n) (ts_buf_len(b) + (n) >= ts_buf_cap(b))\n#define ts_buf__fit(b, n) (ts_buf__should_grow(b, n) ? ((b) = ts_buf__grow_f(b, ts_buf_len(b) + (n), sizeof(*(b)))) : 0)\n\n#define ts_buf_len(b) ((b) ? ts_buf__hdr(b)->len : 0)\n#define ts_buf_cap(b) ((b) ? ts_buf__hdr(b)->cap : 0)\n#define ts_buf_last(b) ((b)[ts_buf_len(b)-1])\n#define ts_buf_push(b, x) (ts_buf__fit(b, 1), (b)[ts_buf_len(b)] = (x), ts_buf__hdr(b)->len++)\n#define ts_buf_del(b, x) ((b) ? (b)[x] = (b)[ts_buf_len(b)-1], ts_buf__hdr(b)->len-- : 0)\n\nstatic void *ts_buf__grow_f(const void *buf, int new_len, int elem_size)\n{\n    struct ts_buf_hdr *new_hdr;\n    int new_cap = max(1 + 2*ts_buf_cap(buf), new_len);\n    int new_size = offsetof(struct ts_buf_hdr, buf) + new_cap*elem_size;\n\n    if (buf) {\n        __sync_fetch_and_add(&g_temp_storage.used, new_size);\n        new_hdr = ts_buf__hdr(buf);\n    } else {\n        new_hdr = ts_alloc_aligned(8, new_size);\n    }\n\n    new_hdr->cap = new_cap;\n    if (!buf) {\n        new_hdr->len = 0;\n    }\n    return new_hdr->buf;\n}\n\n#endif\n"
  },
  {
    "path": "src/misc/service.h",
    "content": "#ifndef SERVICE_H\n#define SERVICE_H\n\n#define _PATH_LAUNCHCTL   \"/bin/launchctl\"\n#define _NAME_YABAI_PLIST \"com.asmvik.yabai\"\n#define _PATH_YABAI_PLIST \"%s/Library/LaunchAgents/\"_NAME_YABAI_PLIST\".plist\"\n\n#define _YABAI_PLIST \\\n    \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\"?>\\n\" \\\n    \"<!DOCTYPE plist PUBLIC \\\"-//Apple//DTD PLIST 1.0//EN\\\" \\\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\\\">\\n\" \\\n    \"<plist version=\\\"1.0\\\">\\n\" \\\n    \"<dict>\\n\" \\\n    \"    <key>Label</key>\\n\" \\\n    \"    <string>\"_NAME_YABAI_PLIST\"</string>\\n\" \\\n    \"    <key>ProgramArguments</key>\\n\" \\\n    \"    <array>\\n\" \\\n    \"        <string>%s</string>\\n\" \\\n    \"    </array>\\n\" \\\n    \"    <key>EnvironmentVariables</key>\\n\" \\\n    \"    <dict>\\n\" \\\n    \"        <key>PATH</key>\\n\" \\\n    \"        <string>%s</string>\\n\" \\\n    \"    </dict>\\n\" \\\n    \"    <key>RunAtLoad</key>\\n\" \\\n    \"    <true/>\\n\" \\\n    \"    <key>KeepAlive</key>\\n\" \\\n    \"    <dict>\\n\" \\\n    \"        <key>SuccessfulExit</key>\\n\" \\\n    \" \t     <false/>\\n\" \\\n    \" \t     <key>Crashed</key>\\n\" \\\n    \" \t     <true/>\\n\" \\\n    \"    </dict>\\n\" \\\n    \"    <key>StandardOutPath</key>\\n\" \\\n    \"    <string>/tmp/yabai_%s.out.log</string>\\n\" \\\n    \"    <key>StandardErrorPath</key>\\n\" \\\n    \"    <string>/tmp/yabai_%s.err.log</string>\\n\" \\\n    \"    <key>ProcessType</key>\\n\" \\\n    \"    <string>Interactive</string>\\n\" \\\n    \"    <key>Nice</key>\\n\" \\\n    \"    <integer>-20</integer>\\n\" \\\n    \"</dict>\\n\" \\\n    \"</plist>\"\n\n//\n// NOTE(asmvik): A launchd service has the following states:\n//\n//          1. Installed / Uninstalled\n//          2. Active (Enable / Disable)\n//          3. Bootstrapped (Load / Unload)\n//          4. Running (Start / Stop)\n//\n\nstatic int safe_exec(char *const argv[], bool suppress_output)\n{\n    pid_t pid;\n    posix_spawn_file_actions_t actions;\n    posix_spawn_file_actions_init(&actions);\n\n    if (suppress_output) {\n        posix_spawn_file_actions_addopen(&actions, STDOUT_FILENO, \"/dev/null\", O_WRONLY|O_APPEND, 0);\n        posix_spawn_file_actions_addopen(&actions, STDERR_FILENO, \"/dev/null\", O_WRONLY|O_APPEND, 0);\n    }\n\n    int status = posix_spawn(&pid, argv[0], &actions, NULL, argv, NULL);\n    if (status) return 1;\n\n    while ((waitpid(pid, &status, 0) == -1) && (errno == EINTR)) {\n        usleep(1000);\n    }\n\n    if (WIFSIGNALED(status)) {\n        return 1;\n    } else if (WIFSTOPPED(status)) {\n        return 1;\n    } else {\n        return WEXITSTATUS(status);\n    }\n}\n\nstatic char *populate_plist_path(void)\n{\n    CFStringRef home_ref = (__bridge CFStringRef) NSHomeDirectoryForUser(NULL);\n    char *home = home_ref ? cfstring_copy(home_ref) : NULL;\n\n    if (!home) {\n        error(\"yabai: unable to retrieve home directory! abort..\\n\");\n    }\n\n    int size = strlen(_PATH_YABAI_PLIST)-2 + strlen(home) + 1;\n    char *result = malloc(size);\n    if (!result) {\n        error(\"yabai: could not allocate memory for plist path! abort..\\n\");\n    }\n\n    memset(result, 0, size);\n    snprintf(result, size, _PATH_YABAI_PLIST, home);\n\n    return result;\n}\n\nstatic char *populate_plist(int *length)\n{\n    char *user = getenv(\"USER\");\n    if (!user) {\n        error(\"yabai: 'env USER' not set! abort..\\n\");\n    }\n\n    char *path_env = getenv(\"PATH\");\n    if (!path_env) {\n        error(\"yabai: 'env PATH' not set! abort..\\n\");\n    }\n\n    char exe_path[4096];\n    unsigned int exe_path_size = sizeof(exe_path);\n    if (_NSGetExecutablePath(exe_path, &exe_path_size) < 0) {\n        error(\"yabai: unable to retrieve path of executable! abort..\\n\");\n    }\n\n    int size = strlen(_YABAI_PLIST)-8 + strlen(exe_path) + strlen(path_env) + (2*strlen(user)) + 1;\n    char *result = malloc(size);\n    if (!result) {\n        error(\"yabai: could not allocate memory for plist contents! abort..\\n\");\n    }\n\n    memset(result, 0, size);\n    snprintf(result, size, _YABAI_PLIST, exe_path, path_env, user, user);\n    *length = size-1;\n\n    return result;\n}\n\nstatic inline void ensure_directory_exists(char *yabai_plist_path)\n{\n    //\n    // NOTE(asmvik): Temporarily remove filename.\n    // We know the filepath will contain a slash, as\n    // it is controlled by us, so don't bother checking\n    // the result..\n    //\n\n    char *last_slash = strrchr(yabai_plist_path, '/');\n    *last_slash = '\\0';\n\n    if (!directory_exists(yabai_plist_path)) {\n        mkdir(yabai_plist_path, 0755);\n    }\n\n    //\n    // NOTE(asmvik): Restore original filename.\n    //\n\n    *last_slash = '/';\n}\n\nstatic int service_install_internal(char *yabai_plist_path)\n{\n    int yabai_plist_length;\n    char *yabai_plist = populate_plist(&yabai_plist_length);\n    ensure_directory_exists(yabai_plist_path);\n\n    FILE *handle = fopen(yabai_plist_path, \"w\");\n    if (!handle) return 1;\n\n    size_t bytes = fwrite(yabai_plist, yabai_plist_length, 1, handle);\n    int result = bytes == 1 ? 0 : 1;\n    fclose(handle);\n\n    return result;\n}\n\nstatic int service_install(void)\n{\n    char *yabai_plist_path = populate_plist_path();\n\n    if (file_exists(yabai_plist_path)) {\n        error(\"yabai: service file '%s' is already installed! abort..\\n\", yabai_plist_path);\n    }\n\n    return service_install_internal(yabai_plist_path);\n}\n\nstatic int service_uninstall(void)\n{\n    char *yabai_plist_path = populate_plist_path();\n\n    if (!file_exists(yabai_plist_path)) {\n        error(\"yabai: service file '%s' is not installed! abort..\\n\", yabai_plist_path);\n    }\n\n    return unlink(yabai_plist_path) == 0 ? 0 : 1;\n}\n\nstatic int service_start(void)\n{\n    char *yabai_plist_path = populate_plist_path();\n    if (!file_exists(yabai_plist_path)) {\n        warn(\"yabai: service file '%s' is not installed! attempting installation..\\n\", yabai_plist_path);\n\n        int result = service_install_internal(yabai_plist_path);\n        if (result) {\n            error(\"yabai: service file '%s' could not be installed! abort..\\n\", yabai_plist_path);\n        }\n    }\n\n    char service_target[MAXLEN];\n    snprintf(service_target, sizeof(service_target), \"gui/%d/%s\", getuid(), _NAME_YABAI_PLIST);\n\n    char domain_target[MAXLEN];\n    snprintf(domain_target, sizeof(domain_target), \"gui/%d\", getuid());\n\n    //\n    // NOTE(asmvik): Check if service is bootstrapped\n    //\n\n    const char *const args[] = { _PATH_LAUNCHCTL, \"print\", service_target, NULL };\n    int is_bootstrapped = safe_exec((char *const*)args, true);\n\n    if (is_bootstrapped != 0) {\n\n        //\n        // NOTE(asmvik): Service is not bootstrapped and could be disabled.\n        // There is no way to query if the service is disabled, and we cannot\n        // bootstrap a disabled service. Try to enable the service. This will be\n        // a no-op if the service is already enabled.\n        //\n\n        const char *const args[] = { _PATH_LAUNCHCTL, \"enable\", service_target, NULL };\n        safe_exec((char *const*)args, false);\n\n        //\n        // NOTE(asmvik): Bootstrap service into the target domain.\n        // This will also start the program **iff* RunAtLoad is set to true.\n        //\n\n        const char *const args2[] = { _PATH_LAUNCHCTL, \"bootstrap\", domain_target, yabai_plist_path, NULL };\n        return safe_exec((char *const*)args2, false);\n    } else {\n\n        //\n        // NOTE(asmvik): The service has already been bootstrapped.\n        // Tell the bootstrapped service to launch immediately; it is an\n        // error to bootstrap a service that has already been bootstrapped.\n        //\n\n        const char *const args[] = { _PATH_LAUNCHCTL, \"kickstart\", service_target, NULL };\n        return safe_exec((char *const*)args, false);\n    }\n}\n\nstatic int service_restart(void)\n{\n    char *yabai_plist_path = populate_plist_path();\n    if (!file_exists(yabai_plist_path)) {\n        error(\"yabai: service file '%s' is not installed! abort..\\n\", yabai_plist_path);\n    }\n\n    char service_target[MAXLEN];\n    snprintf(service_target, sizeof(service_target), \"gui/%d/%s\", getuid(), _NAME_YABAI_PLIST);\n\n    const char *const args[] = { _PATH_LAUNCHCTL, \"kickstart\", \"-k\", service_target, NULL };\n    return safe_exec((char *const*)args, false);\n}\n\nstatic int service_stop(void)\n{\n    char *yabai_plist_path = populate_plist_path();\n    if (!file_exists(yabai_plist_path)) {\n        error(\"yabai: service file '%s' is not installed! abort..\\n\", yabai_plist_path);\n    }\n\n    char service_target[MAXLEN];\n    snprintf(service_target, sizeof(service_target), \"gui/%d/%s\", getuid(), _NAME_YABAI_PLIST);\n\n    char domain_target[MAXLEN];\n    snprintf(domain_target, sizeof(domain_target), \"gui/%d\", getuid());\n\n    //\n    // NOTE(asmvik): Check if service is bootstrapped\n    //\n\n    const char *const args[] = { _PATH_LAUNCHCTL, \"print\", service_target, NULL };\n    int is_bootstrapped = safe_exec((char *const*)args, true);\n\n    if (is_bootstrapped != 0) {\n\n        //\n        // NOTE(asmvik): Service is not bootstrapped, but the program\n        // could still be running an instance that was started **while the service\n        // was bootstrapped**, so we tell it to stop said service.\n        //\n\n        const char *const args[] = { _PATH_LAUNCHCTL, \"kill\", \"SIGTERM\", service_target, NULL };\n        return safe_exec((char *const*)args, false);\n    } else {\n\n        //\n        // NOTE(asmvik): Service is bootstrapped; we stop a potentially\n        // running instance of the program and unload the service, making it\n        // not trigger automatically in the future.\n        //\n        // This is NOT the same as disabling the service, which will prevent\n        // it from being boostrapped in the future (without explicitly re-enabling\n        // it first).\n        //\n\n        const char *const args[] = { _PATH_LAUNCHCTL, \"bootout\", domain_target, yabai_plist_path, NULL };\n        safe_exec((char *const*)args, false);\n\n        const char *const args2[] = { _PATH_LAUNCHCTL, \"disable\", service_target, NULL };\n        return safe_exec((char *const*)args2, false);\n    }\n}\n\n#endif\n"
  },
  {
    "path": "src/misc/timer.h",
    "content": "#ifndef TIMER_H\n#define TIMER_H\n\n#if PROFILE >= 1\n#include <stdint.h>\n#include <stdio.h>\n\nstruct profile_anchor\n{\n    uint64_t tsc_elapsed_exclusive;\n    uint64_t tsc_elapsed_inclusive;\n    uint64_t hit_count;\n    char const *label;\n};\n\nstatic struct\n{\n    uint64_t begin_tsc;\n    uint64_t end_tsc;\n    struct profile_anchor anchors[4096];\n    uint32_t parent;\n} g_profiler;\n\nstatic inline uint64_t read_cpu_timer(void)\n{\n#ifdef __x86_64__\n    return __rdtsc();\n#elif __arm64__\n    uint64_t value;\n    __asm__ __volatile__ (\"mrs %0, cntvct_el0\" : \"=r\" (value));\n    return value;\n#endif\n}\n\nstatic inline uint64_t read_cpu_freq(void)\n{\n#ifdef __x86_64__\n    static uint64_t cpu_freq;\n    if (cpu_freq == 0) {\n        uint64_t ms_to_wait   = 100;\n        uint64_t os_freq      = read_os_freq();\n        uint64_t cpu_start    = read_cpu_timer();\n        uint64_t os_start     = read_os_timer();\n        uint64_t os_end       = 0;\n        uint64_t os_elapsed   = 0;\n        uint64_t os_wait_time = os_freq * ms_to_wait / 1000;\n\n        while (os_elapsed < os_wait_time) {\n            os_end     = read_os_timer();\n            os_elapsed = os_end - os_start;\n        }\n\n        uint64_t cpu_end     = read_cpu_timer();\n        uint64_t cpu_elapsed = cpu_end - cpu_start;\n\n        cpu_freq = os_freq * cpu_elapsed / os_elapsed;\n    }\n    return cpu_freq;\n#elif __arm64__\n    uint64_t value;\n    __asm__ __volatile__ (\"mrs %0, cntfrq_el0\" : \"=r\" (value));\n    return value;\n#endif\n}\n\nstatic void profile_begin(void)\n{\n    memset(&g_profiler, 0, sizeof(g_profiler));\n    g_profiler.begin_tsc = read_cpu_timer();\n}\n\nstatic void profile_end_and_print(void)\n{\n    g_profiler.end_tsc = read_cpu_timer();\n    uint64_t timer_freq = read_cpu_freq();\n\n    uint64_t total_tsc_elapsed = g_profiler.end_tsc - g_profiler.begin_tsc;\n    printf(\"Total time: %0.4fms (timer freq %llu)\\n\", 1000.0 * (double)total_tsc_elapsed / (double)timer_freq, timer_freq);\n\n    for (int i = 0; i < array_count(g_profiler.anchors); ++i) {\n        struct profile_anchor *anchor = g_profiler.anchors + i;\n        if (anchor->tsc_elapsed_inclusive) {\n            double percent = 100.0 * ((double)anchor->tsc_elapsed_exclusive / (double)total_tsc_elapsed);\n            printf(\"    %s[%llu]: %llu (%.2f%%\", anchor->label, anchor->hit_count, anchor->tsc_elapsed_exclusive, percent);\n            if (anchor->tsc_elapsed_inclusive != anchor->tsc_elapsed_exclusive) {\n                double percent_with_children = 100.0 * ((double)anchor->tsc_elapsed_inclusive / (double)total_tsc_elapsed);\n                printf(\", %.2f%% w/children\", percent_with_children);\n            }\n            printf(\")\\n\");\n        }\n    }\n}\n\n#if PROFILE >= 2\nstruct time_block\n{\n    char const *label;\n    uint64_t old_tsc_elapsed_inclusive;\n    uint64_t begin_tsc;\n    uint32_t parent_index;\n    uint32_t anchor_index;\n};\n\nstatic void BEGIN_TIME_BLOCK(struct time_block *tb, const char *label, uint32_t anchor_index)\n{\n    tb->parent_index = g_profiler.parent;\n\n    tb->anchor_index = anchor_index;\n    tb->label = label;\n\n    struct profile_anchor *anchor = g_profiler.anchors + anchor_index;\n    tb->old_tsc_elapsed_inclusive = anchor->tsc_elapsed_inclusive;\n\n    g_profiler.parent = anchor_index;\n    tb->begin_tsc = read_cpu_timer();\n}\n\nstatic void END_TIME_BLOCK(void *context)\n{\n    struct time_block *tb = context;\n\n    uint64_t elapsed = read_cpu_timer() - tb->begin_tsc;\n    g_profiler.parent = tb->parent_index;\n\n    struct profile_anchor *parent = g_profiler.anchors + tb->parent_index;\n    struct profile_anchor *anchor = g_profiler.anchors + tb->anchor_index;\n\n    parent->tsc_elapsed_exclusive -= elapsed;\n    anchor->tsc_elapsed_exclusive += elapsed;\n    anchor->tsc_elapsed_inclusive = tb->old_tsc_elapsed_inclusive + elapsed;\n    ++anchor->hit_count;\n\n    anchor->label = tb->label;\n}\n\n#define TIME_FUNCTION \\\n    __attribute((cleanup(END_TIME_BLOCK))) struct time_block tb_##__FUNCTION__;\\\n    BEGIN_TIME_BLOCK(&tb_##__FUNCTION__, __FUNCTION__, __COUNTER__ + 1)\n\n#define TIME_BLOCK(label) \\\n    __attribute((cleanup(END_TIME_BLOCK))) struct time_block tb_##label;\\\n    BEGIN_TIME_BLOCK(&tb_##label, #label, __COUNTER__ + 1)\n\n#define TIME_BODY(label, c) \\\ndo {\\\n    TIME_BLOCK(label);\\\n    c \\\n} while (0)\n#define PROFILER_END_TRANSLATION_UNIT _Static_assert(__COUNTER__ < array_count(g_profiler.anchors), \"Number of profile points exceeds size of profiler::anchors array!\");\n#else\n#define TIME_FUNCTION\n#define TIME_BLOCK(label)\n#define TIME_BODY(label, c) c\n#define PROFILER_END_TRANSLATION_UNIT\n#endif\n#else\n#define profile_begin();\n#define profile_end_and_print();\n#define TIME_FUNCTION\n#define TIME_BLOCK(label)\n#define TIME_BODY(label, c) c\n#define PROFILER_END_TRANSLATION_UNIT\n#endif\n\n#endif\n"
  },
  {
    "path": "src/misc/ts.h",
    "content": "#ifndef TS_H\n#define TS_H\n\nstatic struct {\n    void *memory;\n    uint64_t size;\n    volatile uint64_t used;\n} g_temp_storage;\n\nbool ts_init(uint64_t size)\n{\n    int page_size = getpagesize();\n\n    uint64_t num_pages = size / page_size;\n    uint64_t remainder = size % page_size;\n    if (remainder) num_pages++;\n\n    g_temp_storage.used = 0;\n    g_temp_storage.size = num_pages * page_size;\n    g_temp_storage.memory = mmap(0, g_temp_storage.size + page_size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);\n\n    bool result = g_temp_storage.memory != MAP_FAILED;\n    if (result) mprotect(g_temp_storage.memory + g_temp_storage.size, page_size, PROT_NONE);\n\n    return result;\n}\n\nstatic inline void ts_assert_within_bounds(uint64_t size)\n{\n    if (size > g_temp_storage.size) {\n        fprintf(stderr, \"fatal error: temporary_storage exceeded amount of allocated memory. requested %lld, but allocated size is %lld\\n\", size, g_temp_storage.size);\n        exit(EXIT_FAILURE);\n    }\n}\n\nstatic inline uint64_t ts_align(uint64_t used, uint64_t align)\n{\n    assert((align & (align-1)) == 0);\n\n    uintptr_t ptr   = (uintptr_t) (g_temp_storage.memory + used);\n    uintptr_t a_ptr = (uintptr_t) align;\n    uintptr_t mod   = ptr & (a_ptr - 1);\n\n    if (mod != 0) ptr += a_ptr - mod;\n\n    return ptr - (uintptr_t) g_temp_storage.memory;\n}\n\n#define ts_alloc_list(elem_type, elem_count) \\\n    ts_alloc_aligned(__alignof__(elem_type), sizeof(elem_type) * elem_count)\n\nstatic inline void *ts_alloc_aligned(uint64_t alignment, uint64_t size)\n{\n    for (;;) {\n        uint64_t used = __atomic_load_n(&g_temp_storage.used, __ATOMIC_RELAXED);\n        uint64_t aligned = ts_align(used, alignment);\n        uint64_t new_used = aligned + size;\n\n        if (__sync_bool_compare_and_swap(&g_temp_storage.used, used, new_used)) {\n            ts_assert_within_bounds(new_used);\n            return g_temp_storage.memory + aligned;\n        }\n    }\n}\n\nstatic inline void *ts_alloc_unaligned(uint64_t size)\n{\n    uint64_t used = __sync_fetch_and_add(&g_temp_storage.used, size);\n    ts_assert_within_bounds(used+size);\n    return g_temp_storage.memory + used;\n}\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wunused-parameter\"\nstatic inline void *ts_expand(void *ptr, uint64_t old_size, uint64_t increment)\n{\n    if (ptr) {\n        assert(ptr == g_temp_storage.memory + g_temp_storage.used - old_size);\n        uint64_t used = __sync_fetch_and_add(&g_temp_storage.used, increment);\n        ts_assert_within_bounds(used+increment);\n    } else {\n        ptr = ts_alloc_unaligned(increment);\n    }\n\n    return ptr;\n}\n#pragma clang diagnostic pop\n\nstatic inline void *ts_resize(void *ptr, uint64_t old_size, uint64_t new_size)\n{\n    assert(ptr == g_temp_storage.memory + g_temp_storage.used - old_size);\n    if (new_size > old_size) {\n        __sync_fetch_and_add(&g_temp_storage.used, new_size - old_size);\n    } else if (new_size < old_size) {\n        __sync_fetch_and_sub(&g_temp_storage.used, old_size - new_size);\n    }\n    return ptr;\n}\n\nstatic inline void ts_reset(void)\n{\n    g_temp_storage.used = 0;\n}\n\n#endif\n"
  },
  {
    "path": "src/mission_control.c",
    "content": "extern struct event_loop g_event_loop;\nextern enum mission_control_mode g_mission_control_mode;\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wunused-parameter\"\nstatic CONNECTION_CALLBACK(connection_handler)\n{\n    if (type == 1204) {\n        event_loop_post(&g_event_loop, MISSION_CONTROL_ENTER, NULL, 0);\n    } else if (type == 1327) {\n        uint64_t sid; memcpy(&sid, data, sizeof(uint64_t));\n        event_loop_post(&g_event_loop, SLS_SPACE_CREATED, (void *) (intptr_t) sid , 0);\n    } else if (type == 1328) {\n        uint64_t sid; memcpy(&sid, data, sizeof(uint64_t));\n        event_loop_post(&g_event_loop, SLS_SPACE_DESTROYED, (void *) (intptr_t) sid, 0);\n    } else if (type == 808) {\n        uint32_t wid; memcpy(&wid, data, sizeof(uint32_t));\n        event_loop_post(&g_event_loop, SLS_WINDOW_ORDERED, (void *) (intptr_t) wid, 0);\n    } else if (type == 804) {\n        uint32_t wid; memcpy(&wid, data, sizeof(uint32_t));\n        event_loop_post(&g_event_loop, SLS_WINDOW_DESTROYED, (void *) (intptr_t) wid, 0);\n    }\n}\n#pragma clang diagnostic pop\n\nenum mission_control_mode\n{\n    MISSION_CONTROL_MODE_INACTIVE           = 0,\n    MISSION_CONTROL_MODE_SHOW               = 1,\n    MISSION_CONTROL_MODE_SHOW_ALL_WINDOWS   = 2,\n    MISSION_CONTROL_MODE_SHOW_FRONT_WINDOWS = 3,\n    MISSION_CONTROL_MODE_SHOW_DESKTOP       = 4\n};\n\nstatic const char *mission_control_mode_str[] = {\n    [MISSION_CONTROL_MODE_INACTIVE]           = \"inactive\",\n    [MISSION_CONTROL_MODE_SHOW]               = \"show\",\n    [MISSION_CONTROL_MODE_SHOW_ALL_WINDOWS]   = \"show-all-windows\",\n    [MISSION_CONTROL_MODE_SHOW_FRONT_WINDOWS] = \"show-front-windows\",\n    [MISSION_CONTROL_MODE_SHOW_DESKTOP]       = \"show-desktop\"\n};\n\nstatic struct {\n    AXUIElementRef ref;\n    AXObserverRef observer_ref;\n    bool is_observing;\n} g_mission_control_observer;\n\nstatic CFStringRef kAXExposeShowAllWindows   = CFSTR(\"AXExposeShowAllWindows\");\nstatic CFStringRef kAXExposeShowFrontWindows = CFSTR(\"AXExposeShowFrontWindows\");\nstatic CFStringRef kAXExposeShowDesktop      = CFSTR(\"AXExposeShowDesktop\");\nstatic CFStringRef kAXExposeExit             = CFSTR(\"AXExposeExit\");\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wunused-parameter\"\nstatic OBSERVER_CALLBACK(mission_control_notification_handler)\n{\n    if (CFEqual(notification, kAXExposeShowAllWindows)) {\n        event_loop_post(&g_event_loop, MISSION_CONTROL_SHOW_ALL_WINDOWS, NULL, 0);\n    } else if (CFEqual(notification, kAXExposeShowFrontWindows)) {\n        event_loop_post(&g_event_loop, MISSION_CONTROL_SHOW_FRONT_WINDOWS, NULL, 0);\n    } else if (CFEqual(notification, kAXExposeShowDesktop)) {\n        event_loop_post(&g_event_loop, MISSION_CONTROL_SHOW_DESKTOP, NULL, 0);\n    } else if (CFEqual(notification, kAXExposeExit)) {\n        event_loop_post(&g_event_loop, MISSION_CONTROL_EXIT, NULL, 0);\n    }\n}\n#pragma clang diagnostic pop\n\nvoid mission_control_observe(void)\n{\n    if (!g_mission_control_observer.is_observing) {\n        uint32_t pid = workspace_get_dock_pid();\n        g_mission_control_observer.ref = AXUIElementCreateApplication(pid);\n\n        if (pid && g_mission_control_observer.ref) {\n            if (AXObserverCreate(pid, mission_control_notification_handler, &g_mission_control_observer.observer_ref) == kAXErrorSuccess) {\n                AXObserverAddNotification(g_mission_control_observer.observer_ref, g_mission_control_observer.ref, kAXExposeShowAllWindows, NULL);\n                AXObserverAddNotification(g_mission_control_observer.observer_ref, g_mission_control_observer.ref, kAXExposeShowFrontWindows, NULL);\n                AXObserverAddNotification(g_mission_control_observer.observer_ref, g_mission_control_observer.ref, kAXExposeShowDesktop, NULL);\n                AXObserverAddNotification(g_mission_control_observer.observer_ref, g_mission_control_observer.ref, kAXExposeExit, NULL);\n\n                g_mission_control_observer.is_observing = true;\n                CFRunLoopAddSource(CFRunLoopGetMain(), AXObserverGetRunLoopSource(g_mission_control_observer.observer_ref), kCFRunLoopDefaultMode);\n            }\n        }\n    }\n}\n\nvoid mission_control_unobserve(void)\n{\n    if (g_mission_control_observer.is_observing) {\n        AXObserverRemoveNotification(g_mission_control_observer.observer_ref, g_mission_control_observer.ref, kAXExposeShowAllWindows);\n        AXObserverRemoveNotification(g_mission_control_observer.observer_ref, g_mission_control_observer.ref, kAXExposeShowFrontWindows);\n        AXObserverRemoveNotification(g_mission_control_observer.observer_ref, g_mission_control_observer.ref, kAXExposeShowDesktop);\n        AXObserverRemoveNotification(g_mission_control_observer.observer_ref, g_mission_control_observer.ref, kAXExposeExit);\n\n        g_mission_control_observer.is_observing = false;\n        CFRunLoopSourceInvalidate(AXObserverGetRunLoopSource(g_mission_control_observer.observer_ref));\n        CFRelease(g_mission_control_observer.observer_ref);\n        CFRelease(g_mission_control_observer.ref);\n    }\n}\n\nstatic inline bool mission_control_is_active(void)\n{\n    return g_mission_control_mode != MISSION_CONTROL_MODE_INACTIVE;\n}\n"
  },
  {
    "path": "src/mouse_handler.c",
    "content": "extern struct event_loop g_event_loop;\n\nstatic inline uint8_t mouse_mod_from_cgflags(uint32_t cgflags)\n{\n    uint8_t flags = 0;\n\n    if ((cgflags & kCGEventFlagMaskAlternate)   == kCGEventFlagMaskAlternate)   flags |= MOUSE_MOD_ALT;\n    if ((cgflags & kCGEventFlagMaskShift)       == kCGEventFlagMaskShift)       flags |= MOUSE_MOD_SHIFT;\n    if ((cgflags & kCGEventFlagMaskCommand)     == kCGEventFlagMaskCommand)     flags |= MOUSE_MOD_CMD;\n    if ((cgflags & kCGEventFlagMaskControl)     == kCGEventFlagMaskControl)     flags |= MOUSE_MOD_CTRL;\n    if ((cgflags & kCGEventFlagMaskSecondaryFn) == kCGEventFlagMaskSecondaryFn) flags |= MOUSE_MOD_FN;\n\n    return flags;\n}\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wswitch\"\n#pragma clang diagnostic ignored \"-Wdeprecated-declarations\"\nstatic MOUSE_HANDLER(mouse_handler)\n{\n    struct mouse_state *mouse_state = context;\n\n    switch (type) {\n    case kCGEventTapDisabledByTimeout:\n    case kCGEventTapDisabledByUserInput: {\n        CFMachPortRef handle = __atomic_load_n(&mouse_state->handle, __ATOMIC_RELAXED);\n        if (handle) CGEventTapEnable(handle, true);\n    } break;\n    case kCGEventLeftMouseDown:\n    case kCGEventRightMouseDown: {\n        uint8_t mod = mouse_mod_from_cgflags(CGEventGetFlags(event));\n        event_loop_post(&g_event_loop, MOUSE_DOWN, (void *) CFRetain(event), mod);\n\n        if (mod == mouse_state->modifier) {\n            mouse_state->consume_mouse_click = true;\n            mouse_state->consumed_event = (CGEventRef) CFRetain(event);\n            return NULL;\n        }\n    } break;\n    case kCGEventLeftMouseUp:\n    case kCGEventRightMouseUp: {\n        event_loop_post(&g_event_loop, MOUSE_UP, (void *) CFRetain(event), 0);\n\n        if (mouse_state->consume_mouse_click) {\n            if (!mouse_state->drag_detected) {\n                CGEventTapPostEvent(proxy, mouse_state->consumed_event);\n                CGEventTapPostEvent(proxy, event);\n            }\n\n            mouse_state->drag_detected = false;\n            mouse_state->consume_mouse_click = false;\n            CFRelease(mouse_state->consumed_event);\n            return NULL;\n        }\n    } break;\n    case kCGEventLeftMouseDragged:\n    case kCGEventRightMouseDragged: {\n        mouse_state->drag_detected = true;\n        event_loop_post(&g_event_loop, MOUSE_DRAGGED, (void *) CFRetain(event), 0);\n    } break;\n    case kCGEventMouseMoved: {\n        uint8_t mod = mouse_mod_from_cgflags(CGEventGetFlags(event));\n        if (mod == mouse_state->modifier) return event;\n\n        event_loop_post(&g_event_loop, MOUSE_MOVED, (void *) CFRetain(event), mod);\n    } break;\n    }\n\n    return event;\n}\n#pragma clang diagnostic pop\n\nvoid mouse_window_info_populate(struct mouse_state *ms, struct mouse_window_info *info)\n{\n    CGRect frame = ms->window->frame;\n\n    info->dx = frame.origin.x    - ms->window_frame.origin.x;\n    info->dy = frame.origin.y    - ms->window_frame.origin.y;\n    info->dw = frame.size.width  - ms->window_frame.size.width;\n    info->dh = frame.size.height - ms->window_frame.size.height;\n\n    info->changed_x = info->dx != 0.0f;\n    info->changed_y = info->dy != 0.0f;\n    info->changed_w = info->dw != 0.0f;\n    info->changed_h = info->dh != 0.0f;\n\n    info->changed_position = info->changed_x || info->changed_y;\n    info->changed_size     = info->changed_w || info->changed_h;\n}\n\nenum mouse_drop_action mouse_determine_drop_action(struct mouse_state *ms, struct window_node *src_node, struct window *dst_window, CGPoint point)\n{\n    CGRect  f    = dst_window->frame;\n    CGPoint wp   = { point.x - f.origin.x, point.y - f.origin.y };\n    CGRect  c    = {{ 0.25f * f.size.width, 0.25f * f.size.height }, { 0.50f * f.size.width, 0.50f * f.size.height }};\n    CGPoint t[3] = {{ 0.0f, 0.0f}, { 0.5f * f.size.width, 0.5f * f.size.height }, { f.size.width, 0.0f }};\n    CGPoint r[3] = {{ f.size.width, 0.0f }, { 0.5f * f.size.width, 0.5f * f.size.height }, { f.size.width, f.size.height }};\n    CGPoint b[3] = {{ f.size.width, f.size.height }, { 0.5f * f.size.width, 0.5f * f.size.height }, { 0.0f, f.size.height }};\n    CGPoint l[3] = {{ 0.0f, f.size.height }, { 0.5f * f.size.width, 0.5f * f.size.height }, { 0.0f, 0.0f }};\n\n    if ((CGRectContainsPoint(c, wp)) && (src_node->window_count == 1)) {\n        return ms->drop_action == MOUSE_MODE_STACK ? MOUSE_DROP_ACTION_STACK : MOUSE_DROP_ACTION_SWAP;\n    } else if (triangle_contains_point(t, wp)) {\n        return MOUSE_DROP_ACTION_WARP_TOP;\n    } else if (triangle_contains_point(r, wp)) {\n        return MOUSE_DROP_ACTION_WARP_RIGHT;\n    } else if (triangle_contains_point(b, wp)) {\n        return MOUSE_DROP_ACTION_WARP_BOTTOM;\n    } else if (triangle_contains_point(l, wp)) {\n        return MOUSE_DROP_ACTION_WARP_LEFT;\n    }\n\n    return MOUSE_DROP_ACTION_NONE;\n}\n\nvoid mouse_drop_action_stack(struct window_manager *wm, struct view *src_view, struct window *src_window, struct view *dst_view, struct window *dst_window)\n{\n    space_manager_untile_window(src_view, src_window);\n    window_manager_remove_managed_window(wm, src_window->id);\n\n    struct window_node *dst_node = view_find_window_node(dst_view, dst_window->id);\n    if (dst_node->window_count+1 < NODE_MAX_WINDOW_COUNT) {\n        view_stack_window_node(dst_node, src_window);\n        window_manager_add_managed_window(wm, src_window, dst_view);\n        window_manager_adjust_layer(src_window, LAYER_BELOW);\n        scripting_addition_order_window(src_window->id, 1, dst_node->window_order[1]);\n\n        if (dst_node->zoom) {\n            window_manager_animate_window((struct window_capture) { src_window, dst_node->zoom->area.x, dst_node->zoom->area.y, dst_node->zoom->area.w, dst_node->zoom->area.h });\n        } else {\n            window_manager_animate_window((struct window_capture) { src_window, dst_node->area.x, dst_node->area.y, dst_node->area.w, dst_node->area.h });\n        }\n    }\n}\n\nvoid mouse_drop_action_swap(struct window_manager *wm, struct view *src_view, struct window_node *src_node, struct window *src_window, struct view *dst_view, struct window_node *dst_node, struct window *dst_window)\n{\n    if (window_node_contains_window(src_node, src_view->insertion_point)) {\n        src_view->insertion_point = dst_window->id;\n    } else if (window_node_contains_window(dst_node, dst_view->insertion_point)) {\n        dst_view->insertion_point = src_window->id;\n    }\n\n    window_node_swap_window_list(src_node, dst_node);\n\n    if (src_view->sid != dst_view->sid) {\n        for (int i = 0; i < src_node->window_count; ++i) {\n            window_manager_remove_managed_window(wm, src_node->window_list[i]);\n            window_manager_add_managed_window(wm, window_manager_find_window(wm, src_node->window_list[i]), src_view);\n        }\n\n        for (int i = 0; i < dst_node->window_count; ++i) {\n            window_manager_remove_managed_window(wm, dst_node->window_list[i]);\n            window_manager_add_managed_window(wm, window_manager_find_window(wm, dst_node->window_list[i]), dst_view);\n        }\n    }\n\n    struct window_capture *window_list = NULL;\n    window_node_capture_windows(src_node, &window_list);\n    window_node_capture_windows(dst_node, &window_list);\n    window_manager_animate_window_list(window_list, ts_buf_len(window_list));\n}\n\nvoid mouse_drop_action_warp(struct window_manager *wm, struct view *src_view, struct window_node *src_node, struct window *src_window, struct view *dst_view, struct window_node *dst_node, struct window *dst_window, enum window_node_split split, enum window_node_child child)\n{\n    if ((src_node->parent && dst_node->parent) &&\n        (src_node->parent == dst_node->parent) &&\n        (src_node->window_count == 1)) {\n        if (dst_node->parent->split == split) {\n            mouse_drop_action_swap(wm, src_view, src_node, src_window, dst_view, dst_node, dst_window);\n            return;\n        } else {\n            dst_node->parent->split = split;\n            dst_node->parent->child = child;\n        }\n    } else {\n        dst_node->split = split;\n        dst_node->child = child;\n    }\n\n    struct window_node *src_node_rm = view_remove_window_node(src_view, src_window);\n    window_manager_remove_managed_window(wm, src_window->id);\n    window_manager_purify_window(wm, src_window);\n\n    struct window_node *src_node_add = view_add_window_node_with_insertion_point(dst_view, src_window, dst_window->id);\n    window_manager_add_managed_window(wm, src_window, dst_view);\n\n    struct window_capture *window_list = NULL;\n\n    if (src_node_rm) {\n        window_node_capture_windows(src_node_rm, &window_list);\n    }\n\n    if (src_node_rm != src_node_add && src_node_rm != src_node_add->parent) {\n        window_node_capture_windows(src_node_add, &window_list);\n    }\n\n    window_manager_animate_window_list(window_list, ts_buf_len(window_list));\n}\n\nvoid mouse_drop_no_target(struct space_manager *sm, struct window_manager *wm, struct view *src_view, struct view *dst_view, struct window *window, struct window_node *node)\n{\n    if (src_view->sid == dst_view->sid) {\n        window_node_flush(node);\n    } else {\n        space_manager_untile_window(src_view, window);\n        window_manager_remove_managed_window(wm, window->id);\n        window_manager_purify_window(wm, window);\n\n        struct view *view = space_manager_tile_window_on_space(sm, window, dst_view->sid);\n        window_manager_add_managed_window(wm, window, view);\n    }\n}\n\nvoid mouse_drop_try_adjust_bsp_grid(struct window_manager *wm, struct view *view, struct window *window, struct mouse_window_info *info)\n{\n    bool success = true;\n\n    if (view->layout != VIEW_BSP) {\n        success = false;\n        goto end;\n    }\n\n    if (info->changed_position) {\n        uint8_t direction = 0;\n        if (info->changed_x) direction |= HANDLE_LEFT;\n        if (info->changed_y) direction |= HANDLE_TOP;\n        if (window_manager_resize_window_relative(wm, window, direction, info->dx, info->dy, true) == WINDOW_OP_ERROR_INVALID_DST_NODE) {\n            success = false;\n        }\n    }\n\n    if (info->changed_size) {\n        uint8_t direction = 0;\n        if (info->changed_w && !info->changed_x) direction |= HANDLE_RIGHT;\n        if (info->changed_h && !info->changed_y) direction |= HANDLE_BOTTOM;\n        if (window_manager_resize_window_relative(wm, window, direction, info->dw, info->dh, true) == WINDOW_OP_ERROR_INVALID_DST_NODE) {\n            success = false;\n        }\n    }\n\nend:\n    if (!success) {\n        struct window_node *node = view_find_window_node(view, window->id);\n        if (node) window_node_flush(node);\n    }\n}\n\nvoid mouse_state_init(struct mouse_state *state)\n{\n    state->modifier    = MOUSE_MOD_FN;\n    state->action1     = MOUSE_MODE_MOVE;\n    state->action2     = MOUSE_MODE_RESIZE;\n    state->drop_action = MOUSE_MODE_SWAP;\n}\n\nbool mouse_handler_begin(struct mouse_state *mouse_state, uint32_t mask)\n{\n    if (mouse_state->handle) return true;\n\n    mouse_state->handle = CGEventTapCreate(kCGHIDEventTap, kCGHeadInsertEventTap, kCGEventTapOptionDefault, mask, mouse_handler, mouse_state);\n    if (!mouse_state->handle) return false;\n\n    if (!CGEventTapIsEnabled(mouse_state->handle)) {\n        CFMachPortInvalidate(mouse_state->handle);\n        CFRelease(mouse_state->handle);\n        return false;\n    }\n\n    mouse_state->runloop_source = CFMachPortCreateRunLoopSource(NULL, mouse_state->handle, 0);\n    CFRunLoopAddSource(CFRunLoopGetMain(), mouse_state->runloop_source, kCFRunLoopCommonModes);\n\n    return true;\n}\n\nvoid mouse_handler_end(struct mouse_state *mouse_state)\n{\n    if (!mouse_state->handle) return;\n\n    CGEventTapEnable(mouse_state->handle, false);\n    CFMachPortInvalidate(mouse_state->handle);\n    CFRunLoopRemoveSource(CFRunLoopGetMain(), mouse_state->runloop_source, kCFRunLoopCommonModes);\n    CFRelease(mouse_state->runloop_source);\n    CFRelease(mouse_state->handle);\n    __atomic_store_n(&mouse_state->handle, NULL, __ATOMIC_RELEASE);\n}\n"
  },
  {
    "path": "src/mouse_handler.h",
    "content": "#ifndef MOUSE_H\n#define MOUSE_H\n\n#define MOUSE_EVENT_MASK_FFM (1 << kCGEventMouseMoved) | \\\n                             (1 << kCGEventLeftMouseDown) | \\\n                             (1 << kCGEventLeftMouseUp) | \\\n                             (1 << kCGEventLeftMouseDragged) | \\\n                             (1 << kCGEventRightMouseDown) | \\\n                             (1 << kCGEventRightMouseUp) | \\\n                             (1 << kCGEventRightMouseDragged)\n\n#define MOUSE_EVENT_MASK     (1 << kCGEventLeftMouseDown) | \\\n                             (1 << kCGEventLeftMouseUp) | \\\n                             (1 << kCGEventLeftMouseDragged) | \\\n                             (1 << kCGEventRightMouseDown) | \\\n                             (1 << kCGEventRightMouseUp) | \\\n                             (1 << kCGEventRightMouseDragged)\n\n#define MOUSE_HANDLER(name) CGEventRef name(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *context)\n\nenum mouse_drop_action\n{\n    MOUSE_DROP_ACTION_NONE,\n    MOUSE_DROP_ACTION_STACK,\n    MOUSE_DROP_ACTION_SWAP,\n    MOUSE_DROP_ACTION_WARP_TOP,\n    MOUSE_DROP_ACTION_WARP_RIGHT,\n    MOUSE_DROP_ACTION_WARP_BOTTOM,\n    MOUSE_DROP_ACTION_WARP_LEFT\n};\n\nenum mouse_mod\n{\n    MOUSE_MOD_NONE  = 0x01,\n    MOUSE_MOD_ALT   = 0x02,\n    MOUSE_MOD_SHIFT = 0x04,\n    MOUSE_MOD_CMD   = 0x08,\n    MOUSE_MOD_CTRL  = 0x10,\n    MOUSE_MOD_FN    = 0x20\n};\n\nenum mouse_mode\n{\n    MOUSE_MODE_NONE,\n    MOUSE_MODE_MOVE,\n    MOUSE_MODE_RESIZE,\n    MOUSE_MODE_SWAP,\n    MOUSE_MODE_STACK\n};\n\nstruct mouse_window_info\n{\n    float dx, dy, dw, dh;\n    bool changed_x, changed_y;\n    bool changed_w, changed_h;\n    bool changed_position;\n    bool changed_size;\n};\n\nstruct mouse_state\n{\n    CFMachPortRef handle;\n    CFRunLoopSourceRef runloop_source;\n    bool consume_mouse_click;\n    bool drag_detected;\n    CGEventRef consumed_event;\n    enum mouse_mode action1;\n    enum mouse_mode action2;\n    volatile uint8_t modifier;\n    enum mouse_mode drop_action;\n    enum mouse_mode current_action;\n    CGPoint down_location;\n    uint64_t last_moved_time;\n    struct window *window;\n    CGRect window_frame;\n    uint32_t ffm_window_id;\n    uint8_t direction;\n    struct window_node *feedback_node;\n};\n\nstatic char *mouse_mod_str[] =\n{\n    [MOUSE_MOD_NONE]  = \"none\",\n    [MOUSE_MOD_ALT]   = \"alt\",\n    [MOUSE_MOD_SHIFT] = \"shift\",\n    [MOUSE_MOD_CMD]   = \"cmd\",\n    [MOUSE_MOD_CTRL]  = \"ctrl\",\n    [MOUSE_MOD_FN]    = \"fn\",\n};\n\nstatic char *mouse_mode_str[] =\n{\n    [MOUSE_MODE_NONE]   = \"none\",\n    [MOUSE_MODE_MOVE]   = \"move\",\n    [MOUSE_MODE_RESIZE] = \"resize\",\n    [MOUSE_MODE_SWAP]   = \"swap\",\n    [MOUSE_MODE_STACK]  = \"stack\"\n};\n\nvoid mouse_window_info_populate(struct mouse_state *ms, struct mouse_window_info *info);\nenum mouse_drop_action mouse_determine_drop_action(struct mouse_state *ms, struct window_node *src_node, struct window *dst_window, CGPoint point);\nvoid mouse_drop_action_stack(struct window_manager *wm, struct view *src_view, struct window *src_window, struct view *dst_view, struct window *dst_window);\nvoid mouse_drop_action_swap(struct window_manager *wm, struct view *src_view, struct window_node *src_node, struct window *src_window, struct view *dst_view, struct window_node *dst_node, struct window *dst_window);\nvoid mouse_drop_action_warp(struct window_manager *wm, struct view *src_view, struct window_node *src_node, struct window *src_window, struct view *dst_view, struct window_node *dst_node, struct window *dst_window, enum window_node_split split, enum window_node_child child);\nvoid mouse_drop_no_target(struct space_manager *sm, struct window_manager *wm, struct view *src_view, struct view *dst_view, struct window *window, struct window_node *node);\nvoid mouse_drop_try_adjust_bsp_grid(struct window_manager *wm, struct view *view, struct window *window, struct mouse_window_info *info);\n\nvoid mouse_state_init(struct mouse_state *mouse_state);\nbool mouse_handler_begin(struct mouse_state *mouse_state, uint32_t mask);\nvoid mouse_handler_end(struct mouse_state *mouse_state);\n\n#endif\n"
  },
  {
    "path": "src/osax/arm64_payload.m",
    "content": "#define asm__call_add_space(v0,v1,func) \\\n    __asm__(\"mov x0, %0\\n\"\"mov x20, %1\\n\" : :\"r\"(v0), \"r\"(v1) :\"x0\", \"x20\"); ((void (*)())(func))();\n\n#define asm__call_move_space(v0,v1,v2,v3,func) \\\n    __asm__(\"mov x0, %0\\n\"\"mov x1, %1\\n\"\"mov x2, %2\\n\"\"mov x20, %3\\n\" : :\"r\"(v0), \"r\"(v1), \"r\"(v2), \"r\"(v3) :\"x0\", \"x1\", \"x2\", \"x20\"); ((void (*)())(func))();\n\nuint64_t get_dock_spaces_offset(NSOperatingSystemVersion os_version) {\n    if (os_version.majorVersion == 26) {\n        return 0x30000;\n    } else if (os_version.majorVersion == 15) {\n        return os_version.minorVersion >= 4 ? 0x1f0000 : 0x200000;\n    } else if (os_version.majorVersion == 14) {\n        return 0x114000;\n    } else if (os_version.majorVersion == 13) {\n        return 0x118000;\n    } else if (os_version.majorVersion == 12) {\n        return 0x8000;\n    }\n\n    return 0;\n}\n\nuint64_t get_dppm_offset(NSOperatingSystemVersion os_version) {\n    if (os_version.majorVersion == 26) {\n        return 0x70000;\n    } else if (os_version.majorVersion == 15) {\n        return 0x250000;\n    } else if (os_version.majorVersion == 14) {\n        return os_version.minorVersion > 0 ? 0x1d2000 : 0x9000;\n    } else if (os_version.majorVersion == 13) {\n        return 0x9000;\n    } else if (os_version.majorVersion == 12) {\n        return 0x7000;\n    }\n\n    return 0;\n}\n\nuint64_t get_fix_animation_offset(NSOperatingSystemVersion os_version) {\n    if (os_version.majorVersion == 26) {\n        return 0x250000;\n    } else if (os_version.majorVersion == 15) {\n        return 0x250000;\n    } else if (os_version.majorVersion == 14) {\n        return 0x1D0000;\n    } else if (os_version.majorVersion == 13) {\n        return 0x1E0000;\n    } else if (os_version.majorVersion == 12) {\n        return 0x230000;\n    }\n\n    return 0;\n}\n\nuint64_t get_add_space_offset(NSOperatingSystemVersion os_version) {\n    if (os_version.majorVersion == 26) {\n        return 0x250000;\n    } else if (os_version.majorVersion == 15) {\n        return 0x250000;\n    } else if (os_version.majorVersion == 14) {\n        return 0x1D0000;\n    } else if (os_version.majorVersion == 13) {\n        return 0x1E0000;\n    } else if (os_version.majorVersion == 12) {\n        return 0x220000;\n    }\n\n    return 0;\n}\n\nuint64_t get_remove_space_offset(NSOperatingSystemVersion os_version) {\n    if (os_version.majorVersion == 26) {\n        return 0x1e0000;\n    } else if (os_version.majorVersion == 15) {\n        return 0x1c0000;\n    } else if (os_version.majorVersion == 14) {\n        return 0x280000;\n    } else if (os_version.majorVersion == 13) {\n        return 0x2A0000;\n    } else if (os_version.majorVersion == 12) {\n        return 0x2E0000;\n    }\n\n    return 0;\n}\n\nuint64_t get_move_space_offset(NSOperatingSystemVersion os_version) {\n    if (os_version.majorVersion == 26) {\n        return 0x1c0000;\n    } else if (os_version.majorVersion == 15) {\n        return 0x1c0000;\n    } else if (os_version.majorVersion == 14) {\n        return 0x280000;\n    } else if (os_version.majorVersion == 13) {\n        return 0x290000;\n    } else if (os_version.majorVersion == 12) {\n        return 0x2D0000;\n    }\n\n    return 0;\n}\n\nuint64_t get_set_front_window_offset(NSOperatingSystemVersion os_version) {\n    if (os_version.majorVersion == 26) {\n        return 0x10000;\n    } else if (os_version.majorVersion == 15) {\n        return 0x35000;\n    } else if (os_version.majorVersion == 14) {\n        return 0x42000;\n    } else if (os_version.majorVersion == 13) {\n        return 0x47000;\n    } else if (os_version.majorVersion == 12) {\n        return 0x4D000;\n    }\n\n    return 0;\n}\n\nconst char *get_dock_spaces_pattern(NSOperatingSystemVersion os_version) {\n    if (os_version.majorVersion == 26) {\n        // Pulling out of doBindingCommand:display (search decompiled text in ghidra) function.\n        return \"?8 ?? ?? ?? 08 ?? ?? 91 00 01 40 F9 E2 03 13 AA ?? ?? ?? 94 ?? ?? ?? ?? 08\";\n    } else if (os_version.majorVersion == 15) {\n        return \"?? 12 00 ?? ?? ?? ?? 91 ?? 02 40 F9 ?? ?? 00 B4 ?? ?? ?? ??\";\n    } else if (os_version.majorVersion == 14) {\n        if (os_version.minorVersion > 0) {\n            return \"36 16 00 ?? D6 ?? ?? 91 ?? 02 40 F9 ?? ?? 00 B4 ?? 03 14 AA\";\n        }\n        return \"97 18 00 B0 F7 02 0F 91 E0 02 40 F9 E2 03 14 AA 1A 09 08 94 FD 03 1D AA 3C EF 07 94 F6 03 00 AA 00 01 00 B5 E0 02 40 F9 E2 03 14 AA 3B 0F 08 94 FD 03 1D AA 35 EF 07 94 F6 03 00 AA E0 00 00 B4 E0 03 15 AA E2 03 13 AA E3 03 16 AA F3 F3 07 94 E0 03 16 AA 1D EF 07 94 E0 03 14 AA\";\n    } else if (os_version.majorVersion == 13) {\n        return \"?? 17 00 ?? 73 ?? ?? 91 60 02 40 F9 E2 03 17 AA ?? ?? 07 94 FD 03 1D AA ?? ?? 07 94 E0 07 00 F9 ?? 16 00 ?? 00 ?? ?? F9 ?? ?? 07 94 02 00 80 D2 ?? ?? 07 94 E0 13 00 F9 60 02 40 F9 FC 1F 00 F9 E2 03 1C AA ?? ?? 07 94 FD 03 1D AA ?? ?? 07 94 F5 03 00 AA ?? 16 00 ?? ?? ?? ?? F9\";\n    } else if (os_version.majorVersion == 12) {\n        return \"55 21 00 ?? B5 ?? ?? 91 A0 02 40 F9 ?? 1F 00 ?? 01 ?? ?? F9 E2 03 1B AA ?? ?? 0C 94 FD 03 1D AA ?? ?? 0C 94 E0 13 00 F9 ?? 20 00 ?? 00 ?? ?? F9 ?? ?? 0C 94 E8 1F 00 ?? 13 ?? ?? F9 E1 03 13 AA 02 00 80 D2 ?? ?? 0C 94 E0 27 00 F9 A0 02 40 F9 08 20 00 ?? 01 ?? ?? F9\";\n    }\n\n    return NULL;\n}\n\nconst char *get_dppm_pattern(NSOperatingSystemVersion os_version) {\n    if (os_version.majorVersion == 26) {\n        //Pulling from function 'DPRemoteConnection::_handleEvent:'\n        return \"?? 20 00 ?? 08 ?? ?? 91 00 01 40 F9 E2 03 16 AA E3 03 19 AA ?? ?? ?? 94\";\n    } else if (os_version.majorVersion == 15) {\n        return \"?? 0F 00 ?? ?? ?? ?? 91 ?? 0E 00 ?? ?? ?? ?? F8 ?? 03 40 F9 ?? ?? ??\";\n    } else if (os_version.majorVersion == 14) {\n        if (os_version.minorVersion > 0) {\n            return \"?? 10 00 ?? ?? ?? ?? 91 ?? 0F 00 D0 ?? ?? ?? F8 ?? 03 40 F9 ?? ?? ??\";\n        }\n        return \"E0 20 00 90 00 ?? ?? 91 E1 03 13 AA ?? ?? 0C 94 73 2D 00 B4 E1 20 00 90 21 ?? ?? 91 00 00 80 D2 D9 13 0C 94 A8 1F 00 F0 00 79 43 F9 A2 38 0C 94 FD 03 1D AA 1C 1E 0C 94 F4 03 00 AA BF 7F 37 A9\";\n    } else if (os_version.majorVersion == 13) {\n        return \"00 20 00 D0 00 ?? ?? 91 E1 03 13 AA ?? ?? 0B 94 13 2E 00 B4 16 20 00 D0 D6 ?? ?? 91 00 00 80 D2 E1 03 16 AA ?? ?? 0B 94 E8 1E 00 D0 00 ?? ?? F9 ?? ?? 0B 94 FD 03 1D AA ?? ?? 0B 94 F4 03 00 AA\";\n    } else if (os_version.majorVersion == 12) {\n        return \"?? 21 00 ?? 00 ?? ?? 91 E1 03 13 AA ?? ?? 0C 94 ?? ?? 00 B4 ?? 20 00 ?? 00 ?? ?? F9 ?? ?? 00 ?? 19 ?? ?? F9 E1 03 19 AA ?? ?? 0C 94 FD 03 1D AA ?? ?? 0C 94 F4 03 00 AA ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 00 ?? ?? ?? 00 ?? ?? ?? ?? ??\";\n    }\n\n    return NULL;\n}\n\nconst char *get_fix_animation_pattern(NSOperatingSystemVersion os_version) {\n    if (os_version.majorVersion == 26) {\n        return \"00 10 6A 1E A8 ?? ?? D1 ?? 01 ?? F8\";\n    } else if (os_version.majorVersion == 15) {\n        return \"00 10 6A 1E A8 ?? ?? D1 ?? 01 ?? F8\";\n    } else if (os_version.majorVersion == 14) {\n        return \"00 10 6A 1E E0 03 14 AA ?? 03 ?? AA\";\n    } else if (os_version.majorVersion == 13) {\n        return \"00 10 6A 1E E0 03 14 AA E1 03 18 AA E2 03 17 AA A8 43 01 D1\";\n    } else if (os_version.majorVersion == 12) {\n        return \"00 10 6A 1E E0 03 14 AA E2 03 13 AA A8 43 01 D1 04 01 50 B8\";\n    }\n\n    return NULL;\n}\n\nconst char *get_add_space_pattern(NSOperatingSystemVersion os_version) {\n    if (os_version.majorVersion == 26) {\n        return \"7F 23 03 D5 FF C3 01 D1 E1 03 1E AA ?? ?? 00 94 FE 03 01 AA FD 7B 06 A9 FD 83 01 91 F3 03\";\n    } else if (os_version.majorVersion == 15) {\n        return \"7F 23 03 D5 FF C3 01 D1 E1 03 1E AA ?? ?? 00 94 FE 03 01 AA FD 7B 06 A9 FD 83 01 91 F3 03\";\n    } else if (os_version.majorVersion == 14) {\n        return \"7F 23 03 D5 FF C3 01 D1 E1 03 1E AA ?? ?? 00 94 FE 03 01 AA FD 7B 06 A9 FD 83 01 91 F5 03\";\n    } else if (os_version.majorVersion == 13) {\n        return \"7F 23 03 D5 FF C3 01 D1 E1 03 1E AA ?? ?? 00 94 FE 03 01 AA FD 7B 06 A9 FD 83 01 91 F5 03 14 AA F3 03 00 AA 89 E2 40 39 96 16 40 F9 C8 FE 7E D3 3F 05 00 71 A1 00 00 54 ?? 14 00 B5 C8 E2 7D 92 17 09 40 F9 ?? 00 00 14 ?? ?? 00 B5 C8 E2 7D 92 17 09 40 F9 ?? ?? 00 94 ?? ?? 00 B4 F8 06 00 F1 ?? 15 00 54 DA 0A 42 F2 E1 17 9F 1A E0 03 18 AA E2 03 16 AA ?? ?? ?? 97 ?? 14 00 B5 C8 0E 18 8B ?? ?? 00 94 F4 03 00 AA\";\n    } else if (os_version.majorVersion == 12) {\n        return \"7F 23 03 D5 FF C3 01 D1 E1 03 1E AA ?? ?? 00 94 FE 03 01 AA FD 7B 06 A9 FD 83 01 91 F5 03 14 AA F3 03 00 AA 89 E2 40 39 96 16 40 F9 C8 FE 7E D3 3F 05 00 71 A1 00 00 54 ?? 14 00 B5 C8 E2 7D 92 17 09 40 F9 ?? 00 00 14 ?? ?? 00 B5 C8 E2 7D 92 17 09 40 F9 ?? ?? 00 94 ?? ?? 00 B4 F8 06 00 F1 ?? 15 00 54 DA 0A 42 F2 E1 17 9F 1A E0 03 18 AA E2 03 16 AA ?? ?? FD 97 ?? 14 00 B5 C8 0E 18 8B ?? ?? 00 94 F4 03 00 AA\";\n    }\n\n    return NULL;\n}\n\nconst char *get_remove_space_pattern(NSOperatingSystemVersion os_version) {\n    if (os_version.majorVersion == 26) {\n        return \"7F 23 03 D5 FF ?? ?? D1 FC ?? ?? A9 FA ?? ?? A9 F8 ?? ?? A9 F6 ?? ?? A9 F4 ?? ?? A9 FD ?? ?? A9 FD ?? ?? 91 ?? 03 03 AA F5 03 02 AA F4 03 01 AA\";\n    } else if (os_version.majorVersion == 15) {\n        return \"7F 23 03 D5 FF 83 ?? D1 FC 6F ?? A9 FA 67 ?? A9 F8 5F ?? A9 F6 57 ?? A9 F4 4F ?? A9 FD 7B ?? A9 FD 43 ?? 91 ?? 03 03 AA ?? 03 02 AA ?? 03 01 AA ?? 03 00 AA ?? ?? ?? AA\";\n    } else if (os_version.majorVersion == 14) {\n        return \"7F 23 03 D5 FF 83 ?? D1 FC 6F ?? A9 FA 67 ?? A9 F8 5F ?? A9 F6 57 ?? A9 F4 4F ?? A9 FD 7B ?? A9 FD 43 ?? 91 ?? 03 03 AA ?? 03 02 AA ?? 03 01 AA ?? 03 00 AA ?? ?? ?? 97 FC 03 00 AA 08 FC 7E D3 ?? ?? 00 B5 88 E3 7D 92 00\";\n    } else if (os_version.majorVersion == 13) {\n        return \"7F 23 03 D5 FF 83 ?? D1 FC 6F ?? A9 FA 67 ?? A9 F8 5F ?? A9 F6 57 ?? A9 F4 4F ?? A9 FD 7B ?? A9 FD 43 ?? 91 ?? 03 03 AA ?? 03 02 AA ?? 03 01 AA F3 03 00 AA ?? ?? FD 97 FC 03 00 AA 08 FC 7E D3 ?? 20 00 B5 88 E3 7D 92 00 09 40 F9 1F 08 00 F1 2B 0F 00 54 F5 53 01 A9 C8 0A 00 B0 1F 20 03 D5 08 ?? ?? F9 68 02 08 8B 14 55 40 A9 48 0B 00 F0 1F 20 03 D5 00 ?? ?? F9 28 0A 00 B0 01 ?? ?? F9 F3 13 00 F9\";\n    } else if (os_version.majorVersion == 12) {\n        return \"7F 23 03 D5 FF 83 03 D1 FC 6F 08 A9 FA 67 09 A9 F8 5F 0A A9 F6 57 0B A9 F4 4F 0C A9 FD 7B 0D A9 FD 43 03 91 F7 03 03 AA F6 03 02 AA F5 03 01 AA F3 03 00 AA F4 03 01 AA ?? ?? FD 97 F4 03 00 AA 08 FC 7E D3 ?? ?? 00 B5 88 E2 7D 92 00 09 40 F9 1F 08 00 F1 ?? 0E 00 54 ?? ?? ?? ?? F5 ?? ?? ?? ?? ?? 00 ?? 1F 20 03 D5 08 ?? ?? F9 68 02 08 8B 14 69 40 A9 ?? 0A 00 ?? 1F 20 03 D5 00 ?? ?? F9 48 09 00 ?? 01 ?? ?? F9 F3 ?? 00 F9 E2 03 13 AA\";\n    }\n\n    return NULL;\n}\n\nconst char *get_move_space_pattern(NSOperatingSystemVersion os_version) {\n    if (os_version.majorVersion == 26) {\n        return \"7F 23 03 D5 E3 03 1E AA ?? ?? ?? 97 FE 03 03 AA FD 7B ?? A9 FD ?? ?? 91 F6 03 14 AA\";\n    } else if (os_version.majorVersion == 15) {\n        return \"7F 23 03 D5 E3 03 1E AA ?? ?? FF 97 FE 03 03 AA FD 7B 06 A9 FD 83 01 91 F6 03 14 AA F4 03 02 AA FB 03 01 AA FA 03 00 AA ?? 13 00 ?? E8 ?? ?? F9 19 68 68 F8 E0 03 19 AA E1 03 16 AA\";\n    } else if (os_version.majorVersion == 14) {\n        return \"7F 23 03 D5 FF C3 01 D1 E3 03 1E AA ?? ?? 00 94 FE 03 03 AA FD 7B 06 A9 FD 83 01 91 F6 03 14 AA F4 03 02 AA FA 03 01 AA FB 03 00 AA ?? ?? 00 ?? F7 ?? ?? 91 E8 02 40 F9 19 68 68 F8 E0 03 19 AA E1 03 16 AA ?? 25 00 94 ?? ?? 00 B4 ?? 03 00 AA ?? 03 01 AA\";\n    } else if (os_version.majorVersion == 13) {\n        if (os_version.minorVersion >= 3) {\n            return \"7F 23 03 D5 FF C3 01 D1 E3 03 1E AA EB 55 00 94 FE 03 03 AA FD 7B 06 A9 FD 83 01 91 F6 03 14 AA F4 03 02 AA FA 03 01 AA FB 03 00 AA 37 0B 00 D0 F7 82 19 91 E8 02 40 F9 19 68 68 F8 E0 03 19 AA E1 03 16 AA 42 25 00 94 80 01 00 B4 F5 03 00 AA F3 03 01 AA C8 0B 00 90 08 A1 1D 91 08 01 40 39 1F 05 00 71 E1 00 00 54 62 58 00 94 ED 9C 01 94 1F 58 00 94 C7 00 00 14 14 00 80 52 CA 00 00 14 1A 01 00 B4 E8 02 40 F9 40 6B 68 F8 E1 03 16 AA\";\n        } else {\n            return \"7F 23 03 D5 E3 03 1E AA ?? ?? 00 94 FE 03 03 AA FD 7B 06 A9 FD 83 01 91 ?? 03 14 AA ?? 03 02 AA FA 03 01 AA FB 03 00 AA ?? ?? 00 ?? ?? ?? ?? 91 ?? ?? 40 F9 ?? 68 68 F8 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 03 ?? AA ?? 03 ?? AA ?? ?? ?? ?? ?? ?? ?? ?? ?? 01 ?? ?? ?? ?? 00 ?? ?? ?? ?? ?? ?? ?? 00 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 00 ?? ?? 00 ?? ?? ?? ?? 00 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 00 ??\";\n        }\n    } else if (os_version.majorVersion == 12) {\n        return \"7F 23 03 D5 E3 03 1E AA ?? ?? 00 94 FE 03 03 AA FD 7B 06 A9 FD 83 01 91 ?? 03 14 AA ?? 03 02 AA FA 03 01 AA FB 03 00 AA ?? 0A 00 ?? ?? ?? ?? 91 ?? ?? 40 F9 ?? 68 68 F8 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 03 ?? AA ?? 03 ?? AA ?? ?? ?? ?? ?? ?? ?? ?? ?? 01 ?? ?? ?? ?? 00 ?? ?? ?? ?? ?? ?? ?? 00 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 00 ?? ?? 00 ?? ?? ?? ?? 00 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 00 ??\";\n    }\n\n    return NULL;\n}\n\nconst char *get_set_front_window_pattern(NSOperatingSystemVersion os_version) {\n    if (os_version.majorVersion == 26) {\n        return \"21 ?? ?? 34 7F 23 03 D5 FF ?? 01 D1 F6 ?? 04 A9 F4 ?? 05 A9 FD ?? 06 A9 FD ?? 01 91\";\n    } else if (os_version.majorVersion == 15) {\n        return \"7F 23 03 D5 FF ?? 02 D1 F6 57 ?? A9 F4 4F ?? A9 FD 7B ?? A9 FD ?? 02 91 ?? ?? 00 ?? 08 ?? ?? F9\";\n    } else if (os_version.majorVersion == 14) {\n        return \"7F 23 03 D5 FF ?? 02 D1 F6 57 ?? A9 F4 4F ?? A9 FD 7B ?? A9 FD ?? 02 91 ?? ?? 00 ?? 08 ?? ?? F9 08 01 40 F9 A8 83 1D F8 ?? ?? 00 ?? ?? ?? ?? ?? ?? 03 ?? AA ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 00 ?? ?? ?? 00 ?? ?? ?? 00 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? E8 ?? 06 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 00 ?? ?? ?? 00 ?? ?? ?? ?? ?? ?? ?? ?? ??\";\n    } else if (os_version.majorVersion == 13) {\n        return \"7F 23 03 D5 FF ?? 02 D1 F6 57 ?? A9 F4 4F ?? A9 FD 7B ?? A9 FD ?? 02 91 ?? 1A 00 ?? 08 ?? ?? F9 08 01 40 F9 A8 83 1D F8 ?? ?? 00 ?? ?? ?? ?? ?? ?? 03 ?? AA ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 00 ?? ?? ?? 00 ?? ?? ?? 00 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? E8 ?? 06 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 00 ?? ?? ?? 00 ?? ?? ?? ?? ?? ?? ?? ?? ??\";\n    } else if (os_version.majorVersion == 12) {\n        return \"7F 23 03 D5 FF ?? 02 D1 F6 57 ?? A9 F4 4F ?? A9 FD 7B ?? A9 FD ?? 02 91 ?? 1A 00 ?? 08 ?? 44 F9 08 01 40 F9 A8 83 1D F8 ?? ?? 00 ?? ?? ?? ?? ?? ?? 03 ?? AA ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 00 ?? ?? ?? 00 ?? ?? ?? 00 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? E8 ?? 06 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 00 ?? ?? ?? 00 ?? ?? ?? ?? ?? ?? ?? ?? ??\";\n    }\n\n    return NULL;\n}\n"
  },
  {
    "path": "src/osax/common.h",
    "content": "#ifndef SA_COMMON_H\n#define SA_COMMON_H\n\n#define SA_SOCKET_PATH_FMT \"/tmp/yabai-sa_%s.socket\"\n#define SA_SOCKET_BUFF_LEN 0x1000\n\n#define OSAX_VERSION                \"2.1.26\"\n\n#define OSAX_ATTRIB_DOCK_SPACES     0x01\n#define OSAX_ATTRIB_DPPM            0x02\n#define OSAX_ATTRIB_ADD_SPACE       0x04\n#define OSAX_ATTRIB_REM_SPACE       0x08\n#define OSAX_ATTRIB_MOV_SPACE       0x10\n#define OSAX_ATTRIB_SET_WINDOW      0x20\n#define OSAX_ATTRIB_ANIM_TIME       0x40\n\n#define OSAX_ATTRIB_ALL             (OSAX_ATTRIB_DOCK_SPACES | \\\n                                     OSAX_ATTRIB_DPPM | \\\n                                     OSAX_ATTRIB_ADD_SPACE | \\\n                                     OSAX_ATTRIB_REM_SPACE | \\\n                                     OSAX_ATTRIB_MOV_SPACE | \\\n                                     OSAX_ATTRIB_SET_WINDOW | \\\n                                     OSAX_ATTRIB_ANIM_TIME)\n\nenum sa_opcode\n{\n    SA_OPCODE_HANDSHAKE             = 0x01,\n    SA_OPCODE_SPACE_FOCUS           = 0x02,\n    SA_OPCODE_SPACE_CREATE          = 0x03,\n    SA_OPCODE_SPACE_DESTROY         = 0x04,\n    SA_OPCODE_SPACE_MOVE            = 0x05,\n    SA_OPCODE_WINDOW_MOVE           = 0x06,\n    SA_OPCODE_WINDOW_OPACITY        = 0x07,\n    SA_OPCODE_WINDOW_OPACITY_FADE   = 0x08,\n    SA_OPCODE_WINDOW_LAYER          = 0x09,\n    SA_OPCODE_WINDOW_STICKY         = 0x0A,\n    SA_OPCODE_WINDOW_SHADOW         = 0x0B,\n    SA_OPCODE_WINDOW_FOCUS          = 0x0C,\n    SA_OPCODE_WINDOW_SCALE          = 0x0D,\n    SA_OPCODE_WINDOW_SWAP_PROXY_IN  = 0x0E,\n    SA_OPCODE_WINDOW_SWAP_PROXY_OUT = 0x0F,\n    SA_OPCODE_WINDOW_ORDER          = 0x10,\n    SA_OPCODE_WINDOW_ORDER_IN       = 0x11,\n    SA_OPCODE_WINDOW_LIST_TO_SPACE  = 0x12,\n    SA_OPCODE_WINDOW_TO_SPACE       = 0x13,\n};\n\n#endif\n"
  },
  {
    "path": "src/osax/loader.m",
    "content": "#include <Cocoa/Cocoa.h>\n#include <mach/mach.h>\n#include <mach/mach_vm.h>\n#include <dlfcn.h>\n#include <stdio.h>\n#include <unistd.h>\n\n#ifdef __arm64__\n#include <ptrauth.h>\nkern_return_t (*_thread_convert_thread_state)(thread_act_t thread, int direction, thread_state_flavor_t flavor, thread_state_t in_state, mach_msg_type_number_t in_stateCnt, thread_state_t out_state, mach_msg_type_number_t *out_stateCnt);\n#endif\n\nstatic char *payload_path = \"/Library/ScriptingAdditions/yabai.osax/Contents/Resources/payload.bundle/Contents/MacOS/payload\";\n\n//\n// :Attribution\n//\n// The arm64e injection path is based on work by Jeremy Legendre (https://github.com/jslegendre)\n//\n\nstatic char shell_code[] =\n#ifdef __x86_64__\n\"\\x55\"                             // push       rbp\n\"\\x48\\x89\\xE5\"                     // mov        rbp, rsp\n\"\\x48\\x83\\xEC\\x10\"                 // sub        rsp, 0x10\n\"\\x48\\x8D\\x7D\\xF8\"                 // lea        rdi, qword [rbp+var_8]\n\"\\x31\\xC0\"                         // xor        eax, eax\n\"\\x89\\xC1\"                         // mov        ecx, eax\n\"\\x48\\x8D\\x15\\x1E\\x00\\x00\\x00\"     // lea        rdx, qword ptr [rip+0x1E]\n\"\\x48\\x89\\xCE\"                     // mov        rsi, rcx\n\"\\x48\\xB8\"                         // movabs     rax, pthread_create_from_mach_thread\n\"\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\" //\n\"\\xFF\\xD0\"                         // call       rax\n\"\\x48\\x83\\xC4\\x10\"                 // add        rsp, 0x10\n\"\\x5D\"                             // pop        rbp\n\"\\x48\\xC7\\xC0\\x65\\x62\\x61\\x79\"     // mov        rax, 0x79616265\n\"\\xEB\\xFE\"                         // jmp        0x0\n\"\\xC3\"                             // ret\n\"\\x55\"                             // push       rbp\n\"\\x48\\x89\\xE5\"                     // mov        rbp, rsp\n\"\\xBE\\x01\\x00\\x00\\x00\"             // mov        esi, 0x1\n\"\\x48\\x8D\\x3D\\x16\\x00\\x00\\x00\"     // lea        rdi, qword ptr [rip+0x16]\n\"\\x48\\xB8\"                         // movabs     rax, dlopen\n\"\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\" //\n\"\\xFF\\xD0\"                         // call       rax\n\"\\x31\\xF6\"                         // xor        esi, esi\n\"\\x89\\xF7\"                         // mov        edi, esi\n\"\\x48\\x89\\xF8\"                     // mov        rax, rdi\n\"\\x5D\"                             // pop        rbp\n\"\\xC3\"                             // ret\n#elif __arm64__\n\"\\xFF\\xC3\\x00\\xD1\"                 // sub        sp, sp, #0x30\n\"\\xFD\\x7B\\x02\\xA9\"                 // stp        x29, x30, [sp, #0x20]\n\"\\xFD\\x83\\x00\\x91\"                 // add        x29, sp, #0x20\n\"\\xA0\\xC3\\x1F\\xB8\"                 // stur       w0, [x29, #-0x4]\n\"\\xE1\\x0B\\x00\\xF9\"                 // str        x1, [sp, #0x10]\n\"\\xE0\\x23\\x00\\x91\"                 // add        x0, sp, #0x8\n\"\\x08\\x00\\x80\\xD2\"                 // mov        x8, #0\n\"\\xE8\\x07\\x00\\xF9\"                 // str        x8, [sp, #0x8]\n\"\\xE1\\x03\\x08\\xAA\"                 // mov        x1, x8\n\"\\xE2\\x01\\x00\\x10\"                 // adr        x2, #0x3C\n\"\\xE2\\x23\\xC1\\xDA\"                 // paciza     x2\n\"\\xE3\\x03\\x08\\xAA\"                 // mov        x3, x8\n\"\\x49\\x01\\x00\\x10\"                 // adr        x9, #0x28 ; pthread_create_from_mach_thread\n\"\\x29\\x01\\x40\\xF9\"                 // ldr        x9, [x9]\n\"\\x20\\x01\\x3F\\xD6\"                 // blr        x9\n\"\\xA0\\x4C\\x8C\\xD2\"                 // movz       x0, #0x6265\n\"\\x20\\x2C\\xAF\\xF2\"                 // movk       x0, #0x7961, lsl #16\n\"\\x09\\x00\\x00\\x10\"                 // adr        x9, #0\n\"\\x20\\x01\\x1F\\xD6\"                 // br         x9\n\"\\xFD\\x7B\\x42\\xA9\"                 // ldp        x29, x30, [sp, #0x20]\n\"\\xFF\\xC3\\x00\\x91\"                 // add        sp, sp, #0x30\n\"\\xC0\\x03\\x5F\\xD6\"                 // ret\n\"\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\" //\n\"\\x7F\\x23\\x03\\xD5\"                 // pacibsp\n\"\\xFF\\xC3\\x00\\xD1\"                 // sub        sp, sp, #0x30\n\"\\xFD\\x7B\\x02\\xA9\"                 // stp        x29, x30, [sp, #0x20]\n\"\\xFD\\x83\\x00\\x91\"                 // add        x29, sp, #0x20\n\"\\xA0\\xC3\\x1F\\xB8\"                 // stur       w0, [x29, #-0x4]\n\"\\xE1\\x0B\\x00\\xF9\"                 // str        x1, [sp, #0x10]\n\"\\x21\\x00\\x80\\xD2\"                 // mov        x1, #1\n\"\\x60\\x01\\x00\\x10\"                 // adr        x0, #0x2c ; payload_path\n\"\\x09\\x01\\x00\\x10\"                 // adr        x9, #0x20 ; dlopen\n\"\\x29\\x01\\x40\\xF9\"                 // ldr        x9, [x9]\n\"\\x20\\x01\\x3F\\xD6\"                 // blr        x9\n\"\\x09\\x00\\x80\\x52\"                 // mov        w9, #0\n\"\\xE0\\x03\\x09\\xAA\"                 // mov        x0, x9\n\"\\xFD\\x7B\\x42\\xA9\"                 // ldp        x29, x30, [sp, #0x20]\n\"\\xFF\\xC3\\x00\\x91\"                 // add        sp, sp, #0x30\n\"\\xFF\\x0F\\x5F\\xD6\"                 // retab\n\"\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\" //\n#endif\n\"\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\" // empty space for payload_path\n\"\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\"\n\"\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\"\n\"\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\"\n\"\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\"\n\"\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\"\n\"\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\"\n\"\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\"\n\"\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\"\n\"\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\"\n\"\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\"\n\"\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\"\n\"\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\";\n\nstatic pid_t get_dock_pid(void)\n{\n    NSArray *list = [NSRunningApplication runningApplicationsWithBundleIdentifier:@\"com.apple.dock\"];\n\n    if (list.count == 1) {\n        NSRunningApplication *dock = list[0];\n        if ([dock isFinishedLaunching] == YES) {\n            return [dock processIdentifier];\n        }\n    }\n\n    return 0;\n}\n\nint main(int argc, char **argv)\n{\n    int result = 0;\n    mach_port_t task = 0;\n    thread_act_t thread = 0;\n    mach_vm_address_t code = 0;\n    mach_vm_address_t stack = 0;\n    vm_size_t stack_size = 16 * 1024;\n    uint64_t stack_contents = 0x00000000CAFEBABE;\n    pid_t pid = get_dock_pid();\n\n    if (!pid) {\n        fprintf(stderr, \"could not locate Dock.app pid\\n\");\n        return 1;\n    }\n\n    if (task_for_pid(mach_task_self(), pid, &task) != KERN_SUCCESS) {\n        fprintf(stderr, \"could not retrieve task port for pid: %d\\n\", pid);\n        return 1;\n    }\n\n    if (mach_vm_allocate(task, &stack, stack_size, VM_FLAGS_ANYWHERE) != KERN_SUCCESS) {\n        fprintf(stderr, \"could not allocate stack segment\\n\");\n        return 1;\n    }\n\n    if (mach_vm_write(task, stack, (vm_address_t) &stack_contents, sizeof(uint64_t)) != KERN_SUCCESS) {\n        fprintf(stderr, \"could not copy dummy return address into stack segment\\n\");\n        return 1;\n    }\n\n    if (vm_protect(task, stack, stack_size, 1, VM_PROT_READ | VM_PROT_WRITE) != KERN_SUCCESS) {\n        fprintf(stderr, \"could not change protection for stack segment\\n\");\n        return 1;\n    }\n\n    if (mach_vm_allocate(task, &code, sizeof(shell_code), VM_FLAGS_ANYWHERE) != KERN_SUCCESS) {\n        fprintf(stderr, \"could not allocate code segment\\n\");\n        return 1;\n    }\n\n#ifdef __x86_64__\n    uint64_t pcfmt_address = (uint64_t) dlsym(RTLD_DEFAULT, \"pthread_create_from_mach_thread\");\n    uint64_t dlopen_address = (uint64_t) dlsym(RTLD_DEFAULT, \"dlopen\");\n\n    memcpy(shell_code + 28, &pcfmt_address, sizeof(uint64_t));\n    memcpy(shell_code + 71, &dlopen_address, sizeof(uint64_t));\n    memcpy(shell_code + 90, payload_path, strlen(payload_path));\n#elif __arm64__\n    uint64_t pcfmt_address = (uint64_t) ptrauth_strip(dlsym(RTLD_DEFAULT, \"pthread_create_from_mach_thread\"), ptrauth_key_function_pointer);\n    uint64_t dlopen_address = (uint64_t) ptrauth_strip(dlsym(RTLD_DEFAULT, \"dlopen\"), ptrauth_key_function_pointer);\n\n    memcpy(shell_code + 88, &pcfmt_address, sizeof(uint64_t));\n    memcpy(shell_code + 160, &dlopen_address, sizeof(uint64_t));\n    memcpy(shell_code + 168, payload_path, strlen(payload_path));\n#endif\n\n    if (mach_vm_write(task, code, (vm_address_t) shell_code, sizeof(shell_code)) != KERN_SUCCESS) {\n        fprintf(stderr, \"could not copy shellcode into code segment\\n\");\n        return 1;\n    }\n\n    if (vm_protect(task, code, sizeof(shell_code), 0, VM_PROT_EXECUTE | VM_PROT_READ) != KERN_SUCCESS) {\n        fprintf(stderr, \"could not change protection for code segment\\n\");\n        return 1;\n    }\n\n#ifdef __x86_64__\n    x86_thread_state64_t thread_state = {};\n    thread_state_flavor_t thread_flavor = x86_THREAD_STATE64;\n    mach_msg_type_number_t thread_flavor_count = x86_THREAD_STATE64_COUNT;\n\n    thread_state.__rip = (uint64_t) code;\n    thread_state.__rsp = (uint64_t) stack + (stack_size / 2);\n\n    kern_return_t error = thread_create_running(task, thread_flavor, (thread_state_t)&thread_state, thread_flavor_count, &thread);\n    if (error != KERN_SUCCESS) {\n        fprintf(stderr, \"could not spawn remote thread: %s\\n\", mach_error_string(error));\n        return 1;\n    }\n#elif __arm64__\n    void *handle = dlopen(\"/usr/lib/system/libsystem_kernel.dylib\", RTLD_GLOBAL | RTLD_LAZY);\n    if (handle) {\n        _thread_convert_thread_state = dlsym(handle, \"thread_convert_thread_state\");\n        dlclose(handle);\n    }\n\n    if (!_thread_convert_thread_state) {\n        fprintf(stderr, \"could not load symbol: thread_convert_thread_state\\n\");\n        return 1;\n    }\n\n    arm_thread_state64_t thread_state = {}, machine_thread_state = {};\n    thread_state_flavor_t thread_flavor = ARM_THREAD_STATE64;\n    mach_msg_type_number_t thread_flavor_count = ARM_THREAD_STATE64_COUNT, machine_thread_flavor_count = ARM_THREAD_STATE64_COUNT;\n\n    __darwin_arm_thread_state64_set_pc_fptr(thread_state, ptrauth_sign_unauthenticated((void *) code, ptrauth_key_asia, 0));\n    __darwin_arm_thread_state64_set_sp(thread_state, stack + (stack_size / 2));\n\n    kern_return_t error = thread_create(task, &thread);\n    if (error != KERN_SUCCESS) {\n        fprintf(stderr, \"could not create remote thread: %s\\n\", mach_error_string(error));\n        return 1;\n    }\n\n    error = _thread_convert_thread_state(thread, 2, thread_flavor, (thread_state_t) &thread_state, thread_flavor_count, (thread_state_t) &machine_thread_state, &machine_thread_flavor_count);\n    if (error != KERN_SUCCESS) {\n        fprintf(stderr, \"could not convert thread state: %s\\n\", mach_error_string(error));\n        return 1;\n    }\n\n    NSOperatingSystemVersion os_version = [[NSProcessInfo processInfo] operatingSystemVersion];\n    if ((os_version.majorVersion == 14 && os_version.minorVersion >= 4) ||\n        (os_version.majorVersion >= 15)) {\n        thread_terminate(thread);\n        error = thread_create_running(task, thread_flavor, (thread_state_t)&machine_thread_state, machine_thread_flavor_count, &thread);\n        if (error != KERN_SUCCESS) {\n            fprintf(stderr, \"could not spawn remote thread: %s\\n\", mach_error_string(error));\n            return 1;\n        }\n    } else {\n        error = thread_set_state(thread, thread_flavor, (thread_state_t)&machine_thread_state, machine_thread_flavor_count);\n        if (error != KERN_SUCCESS) {\n            fprintf(stderr, \"could not set thread state: %s\\n\", mach_error_string(error));\n            return 1;\n        }\n\n        error = thread_resume(thread);\n        if (error != KERN_SUCCESS) {\n            fprintf(stderr, \"could not resume remote thread: %s\\n\", mach_error_string(error));\n            return 1;\n        }\n    }\n#endif\n\n    usleep(10000);\n\n    for (int i = 0; i < 10; ++i) {\n        kern_return_t error = thread_get_state(thread, thread_flavor, (thread_state_t)&thread_state, &thread_flavor_count);\n\n        if (error != KERN_SUCCESS) {\n            result = 1;\n            goto terminate;\n        }\n\n#ifdef __x86_64__\n        if (thread_state.__rax == 0x79616265) {\n#elif __arm64__\n        if (thread_state.__x[0] == 0x79616265) {\n#endif\n            result = 0;\n            goto terminate;\n        }\n\n        usleep(20000);\n    }\n\nterminate:\n    error = thread_terminate(thread);\n    if (error != KERN_SUCCESS) {\n        fprintf(stderr, \"failed to terminate remote thread: %s\\n\", mach_error_string(error));\n    }\n\n    return result;\n}\n"
  },
  {
    "path": "src/osax/payload.m",
    "content": "#include <Foundation/Foundation.h>\n\n#include <mach-o/getsect.h>\n#include <mach-o/dyld.h>\n#include <mach/mach.h>\n#include <mach/mach_vm.h>\n#include <mach/vm_map.h>\n#include <mach/vm_page_size.h>\n#include <objc/message.h>\n#include <objc/runtime.h>\n\n#include <CoreGraphics/CoreGraphics.h>\n#include <sys/types.h>\n#include <sys/stat.h>\n#include <sys/socket.h>\n#include <arpa/inet.h>\n#include <sys/un.h>\n#include <unistd.h>\n#include <netdb.h>\n#include <dlfcn.h>\n\n#include <pthread.h>\n#include <stdlib.h>\n#include <string.h>\n#include <stdio.h>\n\n#include \"common.h\"\n\n#ifdef __x86_64__\n#include \"x64_payload.m\"\n#elif __arm64__\n#include \"arm64_payload.m\"\n#include <ptrauth.h>\n#endif\n\n#define HASHTABLE_IMPLEMENTATION\n#include \"../misc/hashtable.h\"\n#undef HASHTABLE_IMPLEMENTATION\n\n#define page_align(addr) (vm_address_t)((uintptr_t)(addr) & (~(vm_page_size - 1)))\n#define unpack(v) memcpy(&v, message, sizeof(v)); message += sizeof(v)\n#define lerp(a, t, b) (((1.0-t)*a) + (t*b))\n\nextern int SLSMainConnectionID(void);\nextern CGError SLSGetConnectionPSN(int cid, ProcessSerialNumber *psn);\nextern CGError SLSGetWindowAlpha(int cid, uint32_t wid, float *alpha);\nextern CGError SLSSetWindowAlpha(int cid, uint32_t wid, float alpha);\nextern OSStatus SLSMoveWindowWithGroup(int cid, uint32_t wid, CGPoint *point);\nextern CGError SLSReassociateWindowsSpacesByGeometry(int cid, CFArrayRef window_list);\nextern CGError SLSGetWindowOwner(int cid, uint32_t wid, int *window_cid);\nextern CGError SLSSetWindowTags(int cid, uint32_t wid, uint64_t *tags, size_t tag_size);\nextern CGError SLSClearWindowTags(int cid, uint32_t wid, uint64_t *tags, size_t tag_size);\nextern CGError SLSGetWindowBounds(int cid, uint32_t wid, CGRect *frame);\nextern CGError SLSGetWindowTransform(int cid, uint32_t wid, CGAffineTransform *t);\nextern CGError SLSSetWindowTransform(int cid, uint32_t wid, CGAffineTransform t);\nextern CGError SLSOrderWindow(int cid, uint32_t wid, int order, uint32_t rel_wid);\nextern void SLSManagedDisplaySetCurrentSpace(int cid, CFStringRef display_ref, uint64_t sid);\nextern uint64_t SLSManagedDisplayGetCurrentSpace(int cid, CFStringRef display_ref);\nextern CFStringRef SLSCopyManagedDisplayForSpace(int cid, uint64_t sid);\nextern void SLSMoveWindowsToManagedSpace(int cid, CFArrayRef window_list, uint64_t sid);\nextern void SLSShowSpaces(int cid, CFArrayRef space_list);\nextern void SLSHideSpaces(int cid, CFArrayRef space_list);\nextern CFTypeRef SLSTransactionCreate(int cid);\nextern CGError SLSTransactionCommit(CFTypeRef transaction, int synchronous);\nextern CGError SLSTransactionOrderWindowGroup(CFTypeRef transaction, uint32_t wid, int order, uint32_t rel_wid);\nextern CGError SLSTransactionSetWindowSystemAlpha(CFTypeRef transaction, uint32_t wid, float alpha);\nextern CGError SLSSetWindowSubLevel(int cid, uint32_t wid, int level);\n\nstruct window_fade_context\n{\n    pthread_t thread;\n    uint32_t wid;\n    volatile float alpha;\n    volatile float duration;\n    volatile bool skip;\n};\n\npthread_mutex_t window_fade_lock;\nstruct table window_fade_table;\n\nstatic id dock_spaces;\nstatic id dp_desktop_picture_manager;\nstatic uint64_t add_space_fp;\nstatic uint64_t remove_space_fp;\nstatic uint64_t move_space_fp;\nstatic uint64_t set_front_window_fp;\nstatic uint64_t animation_time_addr;\nstatic bool macOSSequoia;\n\nstatic pthread_t daemon_thread;\nstatic int daemon_sockfd;\n\nstatic void dump_class_info(Class c)\n{\n    const char *name = class_getName(c);\n    unsigned int count = 0;\n\n    Ivar *ivar_list = class_copyIvarList(c, &count);\n    for (int i = 0; i < count; i++) {\n        Ivar ivar = ivar_list[i];\n        const char *ivar_name = ivar_getName(ivar);\n        NSLog(@\"%s ivar: %s\", name, ivar_name);\n    }\n    if (ivar_list) free(ivar_list);\n\n    objc_property_t *property_list = class_copyPropertyList(c, &count);\n    for (int i = 0; i < count; i++) {\n        objc_property_t property = property_list[i];\n        const char *prop_name = property_getName(property);\n        NSLog(@\"%s property: %s\", name, prop_name);\n    }\n    if (property_list) free(property_list);\n\n    Method *method_list = class_copyMethodList(c, &count);\n    for (int i = 0; i < count; i++) {\n        Method method = method_list[i];\n        const char *method_name = sel_getName(method_getName(method));\n        NSLog(@\"%s method: %s\", name, method_name);\n    }\n    if (method_list) free(method_list);\n}\n\nstatic Class dump_class_info_by_name(const char *name)\n{\n    Class c = objc_getClass(name);\n    if (c != nil) {\n        dump_class_info(c);\n    }\n    return c;\n}\n\nstatic uint64_t static_base_address(void)\n{\n    const struct segment_command_64 *command = getsegbyname(\"__TEXT\");\n    uint64_t addr = command->vmaddr;\n    return addr;\n}\n\nstatic uint64_t image_slide(void)\n{\n    char path[1024];\n    uint32_t size = sizeof(path);\n\n    if (_NSGetExecutablePath(path, &size) != 0) {\n        return -1;\n    }\n\n    for (uint32_t i = 0; i < _dyld_image_count(); i++) {\n        if (strcmp(_dyld_get_image_name(i), path) == 0) {\n            return _dyld_get_image_vmaddr_slide(i);\n        }\n    }\n\n    return 0;\n}\n\nstatic uint64_t hex_find_seq(uint64_t baddr, const char *c_pattern)\n{\n    if (!baddr || !c_pattern) return 0;\n\n    uint64_t addr = baddr;\n    uint64_t pattern_length = (strlen(c_pattern) + 1) / 3;\n    char buffer_a[pattern_length];\n    char buffer_b[pattern_length];\n    memset(buffer_a, 0, sizeof(buffer_a));\n    memset(buffer_b, 0, sizeof(buffer_b));\n\n    char *pattern = (char *) c_pattern + 1;\n    for (int i = 0; i < pattern_length; ++i) {\n        char c = pattern[-1];\n        if (c == '?') {\n            buffer_b[i] = 1;\n        } else {\n            int temp = c <= '9' ? 0 : 9;\n            temp = (temp + c) << 0x4;\n            c = pattern[0];\n            int temp2 = c <= '9' ? 0xd0 : 0xc9;\n            buffer_a[i] = temp2 + c + temp;\n        }\n        pattern += 3;\n    }\n\nloop:\n    for (int counter = 0; counter < pattern_length; ++counter) {\n        if ((buffer_b[counter] == 0) && (((char *)addr)[counter] != buffer_a[counter])) {\n            addr = (uint64_t)((char *)addr + 1);\n            if (addr - baddr < 0x1286a0) {\n                goto loop;\n            } else {\n                return 0;\n            }\n        }\n    }\n\n    return addr;\n}\n\n#if __arm64__\nuint64_t decode_adrp_add(uint64_t addr, uint64_t offset)\n{\n    uint32_t adrp_instr = *(uint32_t *) addr;\n\n    uint32_t immlo = (0x60000000 & adrp_instr) >> 29;\n    uint32_t immhi = (0xffffe0 & adrp_instr) >> 3;\n\n    int32_t value = (immhi | immlo) << 12;\n    int64_t value_64 = value;\n\n    uint32_t add_instr = *(uint32_t *) (addr + 4);\n    uint64_t imm12 = (add_instr & 0x3ffc00) >> 10;\n\n    if (add_instr & 0xc00000) {\n        imm12 <<= 12;\n    }\n\n    return (offset & 0xfffffffffffff000) + value_64 + imm12;\n}\n#endif\n\nstatic bool verify_os_version(NSOperatingSystemVersion os_version)\n{\n    NSLog(@\"[yabai-sa] checking for macOS %ld.%ld.%ld compatibility!\", os_version.majorVersion, os_version.minorVersion, os_version.patchVersion);\n\n#ifdef __x86_64__\n    if (os_version.majorVersion == 11) {\n        return true; // Big Sur 11.0\n    } else if (os_version.majorVersion == 12) {\n        return true; // Monterey 12.0\n    } else if (os_version.majorVersion == 13) {\n        return true; // Ventura 13.0\n    } else if (os_version.majorVersion == 14) {\n        return true; // Sonoma 14.0\n    } else if (os_version.majorVersion == 15) {\n        macOSSequoia = true;\n        return true; // Sequoia 15.0\n    } else if (os_version.majorVersion == 26) {\n\n        NSLog(@\"[yabai-sa] Detected Tahoe Preview... flagging 'macOSSequoia=true.'\");\n        macOSSequoia = true;\n        return true; // Tahoe preview\n    }\n\n    NSLog(@\"[yabai-sa] spaces functionality is only supported on macOS Big Sur 11.0.0+, Monterey 12.0.0+, Ventura 13.0.0+, Sonoma 14.0.0+, and Sequoia 15.0\");\n#elif __arm64__\n    if (os_version.majorVersion == 12) {\n        return true; // Monterey 12.0\n    } else if (os_version.majorVersion == 13) {\n        return true; // Ventura 13.0\n    } else if (os_version.majorVersion == 14) {\n        return true; // Sonoma 14.0\n    } else if (os_version.majorVersion == 15) {\n        macOSSequoia = true;\n        return true; // Sequoia 15.0\n    } else if (os_version.majorVersion == 26) {\n\n        NSLog(@\"[yabai-sa] Detected Tahoe Preview... flagging 'macOSSequoia=true.'\");\n        macOSSequoia = true;\n        return true; // Tahoe preview\n    }\n\n    NSLog(@\"[yabai-sa] spaces functionality is only supported on macOS Monterey 12.0.0+, and Ventura 13.0.0+, Sonoma 14.0.0+, and Sequoia 15.0\");\n#endif\n\n    return false;\n}\n\nstatic void init_instances()\n{\n    NSOperatingSystemVersion os_version = [[NSProcessInfo processInfo] operatingSystemVersion];\n    if (!verify_os_version(os_version)) return;\n\n    uint64_t baseaddr = static_base_address() + image_slide();\n\n    uint64_t dock_spaces_addr = hex_find_seq(baseaddr + get_dock_spaces_offset(os_version), get_dock_spaces_pattern(os_version));\n    if (dock_spaces_addr == 0) {\n        dock_spaces = nil;\n        NSLog(@\"[yabai-sa] could not locate pointer to dock.spaces! spaces functionality will not work!\");\n    } else {\n#ifdef __x86_64__\n        uint32_t dock_spaces_offset = *(int32_t *)dock_spaces_addr;\n        NSLog(@\"[yabai-sa] (0x%llx) dock.spaces found at address 0x%llX (0x%llx)\", baseaddr, dock_spaces_addr, dock_spaces_addr - baseaddr);\n        dock_spaces = [(*(id *)(dock_spaces_addr + dock_spaces_offset + 0x4)) retain];\n#elif __arm64__\n        uint64_t dock_spaces_offset = decode_adrp_add(dock_spaces_addr, dock_spaces_addr - baseaddr);\n        NSLog(@\"[yabai-sa] (0x%llx) dock.spaces found at address 0x%llX (0x%llx)\", baseaddr, dock_spaces_offset, dock_spaces_offset - baseaddr);\n        dock_spaces = [(*(id *)(baseaddr + dock_spaces_offset)) retain];\n#endif\n    }\n\n    uint64_t dppm_addr = hex_find_seq(baseaddr + get_dppm_offset(os_version), get_dppm_pattern(os_version));\n    if (dppm_addr == 0) {\n        dp_desktop_picture_manager = nil;\n        NSLog(@\"[yabai-sa] could not locate pointer to dppm! moving spaces will not work!\");\n    } else {\n#ifdef __x86_64__\n        uint32_t dppm_offset = *(int32_t *)dppm_addr;\n        NSLog(@\"[yabai-sa] (0x%llx) dppm found at address 0x%llX (0x%llx)\", baseaddr, dppm_addr, dppm_addr - baseaddr);\n        dp_desktop_picture_manager = [(*(id *)(dppm_addr + dppm_offset + 0x4)) retain];\n#elif __arm64__\n        uint64_t dppm_offset = decode_adrp_add(dppm_addr, dppm_addr - baseaddr);\n        NSLog(@\"[yabai-sa] (0x%llx) dppm found at address 0x%llX (0x%llx)\", baseaddr, dppm_offset, dppm_offset - baseaddr);\n        dp_desktop_picture_manager = [(*(id *)(baseaddr + dppm_offset)) retain];\n#endif\n\n        //\n        // @hack\n        //\n        // NOTE(asmvik): For whatever reason, in Sonoma, DPDesktopPictureManager is initialized and swapped\n        // to an alternate storage location instead of where it used to be stored in previous macOS versions..\n        //\n        // This alternate storage location resides 8-bytes before the usual location, so we simply do\n        // the subtract to arrive at the correct location in cases where the usual location is null.\n        //\n\n#ifdef __x86_64__\n        if (dp_desktop_picture_manager == nil) {\n            dp_desktop_picture_manager = [(*(id *)(dppm_addr + dppm_offset + 0x4 - 0x8)) retain];\n        }\n#elif __arm64__\n        if (dp_desktop_picture_manager == nil) {\n            dp_desktop_picture_manager = [(*(id *)(baseaddr + dppm_offset - 0x8)) retain];\n        }\n#endif\n    }\n\n    uint64_t add_space_addr = hex_find_seq(baseaddr + get_add_space_offset(os_version), get_add_space_pattern(os_version));\n    if (add_space_addr == 0x0) {\n        NSLog(@\"[yabai-sa] failed to get pointer to addSpace function..\");\n        add_space_fp = 0;\n    } else {\n        NSLog(@\"[yabai-sa] (0x%llx) addSpace found at address 0x%llX (0x%llx)\", baseaddr, add_space_addr, add_space_addr - baseaddr);\n#ifdef __x86_64__\n        add_space_fp = add_space_addr;\n#elif __arm64__\n        add_space_fp = (uint64_t) ptrauth_sign_unauthenticated((void *) add_space_addr, ptrauth_key_asia, 0);\n#endif\n    }\n\n    uint64_t remove_space_addr = hex_find_seq(baseaddr + get_remove_space_offset(os_version), get_remove_space_pattern(os_version));\n    if (remove_space_addr == 0x0) {\n        NSLog(@\"[yabai-sa] failed to get pointer to removeSpace function..\");\n        remove_space_fp = 0;\n    } else {\n        NSLog(@\"[yabai-sa] (0x%llx) removeSpace found at address 0x%llX (0x%llx)\", baseaddr, remove_space_addr, remove_space_addr - baseaddr);\n#ifdef __x86_64__\n        remove_space_fp = remove_space_addr;\n#elif __arm64__\n        remove_space_fp = (uint64_t) ptrauth_sign_unauthenticated((void *) remove_space_addr, ptrauth_key_asia, 0);\n#endif\n    }\n\n    uint64_t move_space_addr = hex_find_seq(baseaddr + get_move_space_offset(os_version), get_move_space_pattern(os_version));\n    if (move_space_addr == 0x0) {\n        NSLog(@\"[yabai-sa] failed to get pointer to moveSpace function..\");\n        move_space_fp = 0;\n    } else {\n        NSLog(@\"[yabai-sa] (0x%llx) moveSpace found at address 0x%llX (0x%llx)\", baseaddr, move_space_addr, move_space_addr - baseaddr);\n#ifdef __x86_64__\n        move_space_fp = move_space_addr;\n#elif __arm64__\n        move_space_fp = (uint64_t) ptrauth_sign_unauthenticated((void *) move_space_addr, ptrauth_key_asia, 0);\n#endif\n    }\n\n    uint64_t set_front_window_addr = hex_find_seq(baseaddr + get_set_front_window_offset(os_version), get_set_front_window_pattern(os_version));\n    if (set_front_window_addr == 0x0) {\n        NSLog(@\"[yabai-sa] failed to get pointer to setFrontWindow function..\");\n        set_front_window_fp = 0;\n    } else {\n        NSLog(@\"[yabai-sa] (0x%llx) setFrontWindow found at address 0x%llX (0x%llx)\", baseaddr, set_front_window_addr, set_front_window_addr - baseaddr);\n#ifdef __x86_64__\n        set_front_window_fp = set_front_window_addr;\n#elif __arm64__\n        set_front_window_fp = (uint64_t) ptrauth_sign_unauthenticated((void *) set_front_window_addr, ptrauth_key_asia, 0);\n#endif\n    }\n\n    animation_time_addr = hex_find_seq(baseaddr + get_fix_animation_offset(os_version), get_fix_animation_pattern(os_version));\n    if (animation_time_addr == 0x0) {\n        NSLog(@\"[yabai-sa] failed to get pointer to animation-time..\");\n    } else {\n        NSLog(@\"[yabai-sa] (0x%llx) animation_time_addr found at address 0x%llX (0x%llx)\", baseaddr, animation_time_addr, animation_time_addr - baseaddr);\n        if (vm_protect(mach_task_self(), page_align(animation_time_addr), vm_page_size, 0, VM_PROT_READ | VM_PROT_WRITE | VM_PROT_COPY) == KERN_SUCCESS) {\n#ifdef __x86_64__\n            *(uint64_t *) animation_time_addr = 0x660fefc0660fefc0;\n#elif __arm64__\n            *(uint32_t *) animation_time_addr = 0x2f00e400;\n#endif\n            vm_protect(mach_task_self(), page_align(animation_time_addr), vm_page_size, 0, VM_PROT_READ | VM_PROT_EXECUTE);\n        } else {\n            NSLog(@\"[yabai-sa] animation_time_addr vm_protect failed; unable to patch instruction!\");\n        }\n    }\n}\n\nstatic inline id get_ivar_value(id instance, const char *name)\n{\n    id result = nil;\n    object_getInstanceVariable(instance, name, (void **) &result);\n    return result;\n}\n\nstatic inline void set_ivar_value(id instance, const char *name, id value)\n{\n    object_setInstanceVariable(instance, name, value);\n}\n\nstatic inline uint64_t get_space_id(id space)\n{\n    return ((uint64_t (*)(id, SEL)) objc_msgSend)(space, @selector(spid));\n}\n\nstatic inline id space_for_display_with_id(CFStringRef display_uuid, uint64_t space_id)\n{\n    NSArray *spaces_for_display = ((NSArray *(*)(id, SEL, CFStringRef)) objc_msgSend)(dock_spaces, @selector(spacesForDisplay:), display_uuid);\n    for (id space in spaces_for_display) {\n        if (space_id == get_space_id(space)) {\n            return space;\n        }\n    }\n    return nil;\n}\n\nstatic inline id display_space_for_display_uuid(CFStringRef display_uuid)\n{\n    id result = nil;\n\n    NSArray *display_spaces = get_ivar_value(dock_spaces, \"_displaySpaces\");\n    if (display_spaces != nil) {\n        for (id display_space in display_spaces) {\n            id display_source_space = get_ivar_value(display_space, \"_currentSpace\");\n            uint64_t sid = get_space_id(display_source_space);\n            CFStringRef uuid = SLSCopyManagedDisplayForSpace(SLSMainConnectionID(), sid);\n            bool match = CFEqual(uuid, display_uuid);\n            CFRelease(uuid);\n            if (match) {\n                result = display_space;\n                break;\n            }\n        }\n    }\n\n    return result;\n}\n\nstatic inline id display_space_for_space_with_id(uint64_t space_id)\n{\n    NSArray *display_spaces = get_ivar_value(dock_spaces, \"_displaySpaces\");\n    if (display_spaces != nil) {\n        for (id display_space in display_spaces) {\n            id display_source_space = get_ivar_value(display_space, \"_currentSpace\");\n            if (get_space_id(display_source_space) == space_id) {\n                return display_space;\n            }\n        }\n    }\n    return nil;\n}\n\nstatic void do_space_move(char *message)\n{\n    if (dock_spaces == nil || dp_desktop_picture_manager == nil || move_space_fp == 0) return;\n\n    uint64_t source_space_id, dest_space_id, source_prev_space_id;\n    unpack(source_space_id);\n    unpack(dest_space_id);\n    unpack(source_prev_space_id);\n\n    bool focus_dest_space;\n    unpack(focus_dest_space);\n\n    CFStringRef source_display_uuid = SLSCopyManagedDisplayForSpace(SLSMainConnectionID(), source_space_id);\n    id source_space = space_for_display_with_id(source_display_uuid, source_space_id);\n    id source_display_space = display_space_for_display_uuid(source_display_uuid);\n\n    CFStringRef dest_display_uuid = SLSCopyManagedDisplayForSpace(SLSMainConnectionID(), dest_space_id);\n    id dest_space = space_for_display_with_id(dest_display_uuid, dest_space_id);\n    unsigned dest_display_id = ((unsigned (*)(id, SEL, id)) objc_msgSend)(dock_spaces, @selector(displayIDForSpace:), dest_space);\n    id dest_display_space = display_space_for_display_uuid(dest_display_uuid);\n\n    if (source_prev_space_id) {\n        NSArray *ns_source_space = @[ @(source_space_id) ];\n        NSArray *ns_dest_space = @[ @(source_prev_space_id) ];\n        id new_source_space = space_for_display_with_id(source_display_uuid, source_prev_space_id);\n        SLSShowSpaces(SLSMainConnectionID(), (__bridge CFArrayRef) ns_dest_space);\n        SLSHideSpaces(SLSMainConnectionID(), (__bridge CFArrayRef) ns_source_space);\n        SLSManagedDisplaySetCurrentSpace(SLSMainConnectionID(), source_display_uuid, source_prev_space_id);\n        set_ivar_value(source_display_space, \"_currentSpace\", [new_source_space retain]);\n        [ns_dest_space release];\n        [ns_source_space release];\n    }\n\n    asm__call_move_space(source_space, dest_space, dest_display_uuid, dock_spaces, move_space_fp);\n\n    dispatch_sync(dispatch_get_main_queue(), ^{\n        ((void (*)(id, SEL, id, unsigned, CFStringRef)) objc_msgSend)(dp_desktop_picture_manager, @selector(moveSpace:toDisplay:displayUUID:), source_space, dest_display_id, dest_display_uuid);\n    });\n\n    if (focus_dest_space) {\n        uint64_t new_source_space_id = SLSManagedDisplayGetCurrentSpace(SLSMainConnectionID(), source_display_uuid);\n        id new_source_space = space_for_display_with_id(source_display_uuid, new_source_space_id);\n        set_ivar_value(source_display_space, \"_currentSpace\", [new_source_space retain]);\n\n        NSArray *ns_dest_monitor_space = @[ @(dest_space_id) ];\n        SLSHideSpaces(SLSMainConnectionID(), (__bridge CFArrayRef) ns_dest_monitor_space);\n        SLSManagedDisplaySetCurrentSpace(SLSMainConnectionID(), dest_display_uuid, source_space_id);\n        set_ivar_value(dest_display_space, \"_currentSpace\", [source_space retain]);\n        [ns_dest_monitor_space release];\n    }\n\n    CFRelease(source_display_uuid);\n    CFRelease(dest_display_uuid);\n}\n\ntypedef void (*remove_space_call)(id space, id display_space, id dock_spaces, uint64_t space_id1, uint64_t space_id2);\nstatic void do_space_destroy(char *message)\n{\n    if (dock_spaces == nil || remove_space_fp == 0) return;\n\n    uint64_t space_id;\n    unpack(space_id);\n\n    CFStringRef display_uuid = SLSCopyManagedDisplayForSpace(SLSMainConnectionID(), space_id);\n    uint64_t active_space_id = SLSManagedDisplayGetCurrentSpace(SLSMainConnectionID(), display_uuid);\n\n    id space = space_for_display_with_id(display_uuid, space_id);\n    id display_space = display_space_for_display_uuid(display_uuid);\n\n    dispatch_sync(dispatch_get_main_queue(), ^{\n        ((remove_space_call) remove_space_fp)(space, display_space, dock_spaces, space_id, space_id);\n    });\n\n    if (active_space_id == space_id) {\n        uint64_t dest_space_id = SLSManagedDisplayGetCurrentSpace(SLSMainConnectionID(), display_uuid);\n        id dest_space = space_for_display_with_id(display_uuid, dest_space_id);\n        set_ivar_value(display_space, \"_currentSpace\", [dest_space retain]);\n    }\n\n    CFRelease(display_uuid);\n}\n\nstatic void do_space_create(char *message)\n{\n    if (dock_spaces == nil || add_space_fp == 0) return;\n\n    uint64_t space_id;\n    unpack(space_id);\n\n    CFStringRef __block display_uuid = SLSCopyManagedDisplayForSpace(SLSMainConnectionID(), space_id);\n    dispatch_sync(dispatch_get_main_queue(), ^{\n        id new_space = macOSSequoia\n                     ? [[objc_getClass(\"ManagedSpace\") alloc] init]\n                     : [[objc_getClass(\"Dock.ManagedSpace\") alloc] init];\n        id display_space = display_space_for_display_uuid(display_uuid);\n        asm__call_add_space(new_space, display_space, add_space_fp);\n        CFRelease(display_uuid);\n    });\n}\n\nstatic void do_space_focus(char *message)\n{\n    if (dock_spaces == nil) return;\n\n    uint64_t dest_space_id;\n    unpack(dest_space_id);\n\n    if (dest_space_id) {\n        CFStringRef dest_display = SLSCopyManagedDisplayForSpace(SLSMainConnectionID(), dest_space_id);\n        id source_space = macOSSequoia\n                        ? ((id (*)(id, SEL, CFStringRef)) objc_msgSend)(dock_spaces, @selector(currentSpaceForDisplayUUID:), dest_display)\n                        : ((id (*)(id, SEL, CFStringRef)) objc_msgSend)(dock_spaces, @selector(currentSpaceforDisplayUUID:), dest_display);\n        uint64_t source_space_id = get_space_id(source_space);\n\n        if (source_space_id != dest_space_id) {\n            id dest_space = space_for_display_with_id(dest_display, dest_space_id);\n            if (dest_space != nil) {\n                id display_space = display_space_for_space_with_id(source_space_id);\n                if (display_space != nil) {\n                    NSArray *ns_source_space = @[ @(source_space_id) ];\n                    NSArray *ns_dest_space = @[ @(dest_space_id) ];\n                    SLSShowSpaces(SLSMainConnectionID(), (__bridge CFArrayRef) ns_dest_space);\n                    SLSHideSpaces(SLSMainConnectionID(), (__bridge CFArrayRef) ns_source_space);\n                    SLSManagedDisplaySetCurrentSpace(SLSMainConnectionID(), dest_display, dest_space_id);\n                    set_ivar_value(display_space, \"_currentSpace\", [dest_space retain]);\n                    [ns_dest_space release];\n                    [ns_source_space release];\n                }\n            }\n        }\n\n        CFRelease(dest_display);\n    }\n}\n\nstatic void do_window_scale(char *message)\n{\n    uint32_t wid;\n    unpack(wid);\n    if (!wid) return;\n\n    CGRect frame = {};\n    SLSGetWindowBounds(SLSMainConnectionID(), wid, &frame);\n    CGAffineTransform original_transform = CGAffineTransformMakeTranslation(-frame.origin.x, -frame.origin.y);\n\n    CGAffineTransform current_transform;\n    SLSGetWindowTransform(SLSMainConnectionID(), wid, &current_transform);\n\n    if (CGAffineTransformEqualToTransform(current_transform, original_transform)) {\n        float dx, dy, dw, dh;\n        unpack(dx);\n        unpack(dy);\n        unpack(dw);\n        unpack(dh);\n\n        int target_width  = dw / 4;\n        int target_height = target_width / (frame.size.width/frame.size.height);\n\n        float x_scale = frame.size.width/target_width;\n        float y_scale = frame.size.height/target_height;\n\n        CGFloat transformed_x = -(dx+dw) + (frame.size.width * (1/x_scale));\n        CGFloat transformed_y = -dy;\n\n        CGAffineTransform scale = CGAffineTransformConcat(CGAffineTransformIdentity, CGAffineTransformMakeScale(x_scale, y_scale));\n        CGAffineTransform transform = CGAffineTransformTranslate(scale, transformed_x, transformed_y);\n        SLSSetWindowTransform(SLSMainConnectionID(), wid, transform);\n    } else {\n        SLSSetWindowTransform(SLSMainConnectionID(), wid, original_transform);\n    }\n}\n\nstatic void do_window_move(char *message)\n{\n    uint32_t wid;\n    unpack(wid);\n    if (!wid) return;\n\n    int x, y;\n    unpack(x);\n    unpack(y);\n\n    CGPoint point = CGPointMake(x, y);\n    SLSMoveWindowWithGroup(SLSMainConnectionID(), wid, &point);\n\n    NSArray *window_list = @[ @(wid) ];\n    SLSReassociateWindowsSpacesByGeometry(SLSMainConnectionID(), (__bridge CFArrayRef) window_list);\n    [window_list release];\n}\n\nstatic void do_window_opacity(char *message)\n{\n    uint32_t wid;\n    unpack(wid);\n    if (!wid) return;\n\n    float alpha;\n    unpack(alpha);\n\n    pthread_mutex_lock(&window_fade_lock);\n    struct window_fade_context *context = table_find(&window_fade_table, &wid);\n\n    if (context) {\n        context->alpha = alpha;\n        context->duration = 0.0f;\n        __asm__ __volatile__ (\"\" ::: \"memory\");\n\n        context->skip = true;\n        pthread_mutex_unlock(&window_fade_lock);\n    } else {\n        SLSSetWindowAlpha(SLSMainConnectionID(), wid, alpha);\n        pthread_mutex_unlock(&window_fade_lock);\n    }\n}\n\nstatic void *window_fade_thread_proc(void *data)\n{\nentry:;\n    struct window_fade_context *context = (struct window_fade_context *) data;\n    context->skip  = false;\n\n    float start_alpha;\n    float end_alpha = context->alpha;\n    SLSGetWindowAlpha(SLSMainConnectionID(), context->wid, &start_alpha);\n\n    int frame_duration = 8;\n    int total_duration = (int)(context->duration * 1000.0f);\n    int frame_count = (int)(((float) total_duration / (float) frame_duration) + 1.0f);\n\n    for (int frame_index = 1; frame_index <= frame_count; ++frame_index) {\n        if (context->skip) goto entry;\n\n        float t = (float) frame_index / (float) frame_count;\n        if (t < 0.0f) t = 0.0f;\n        if (t > 1.0f) t = 1.0f;\n\n        float alpha = lerp(start_alpha, t, end_alpha);\n        SLSSetWindowAlpha(SLSMainConnectionID(), context->wid, alpha);\n\n        usleep(frame_duration*1000);\n    }\n\n    pthread_mutex_lock(&window_fade_lock);\n    if (!context->skip) {\n        table_remove(&window_fade_table, &context->wid);\n        pthread_mutex_unlock(&window_fade_lock);\n        free(context);\n        return NULL;\n    }\n    pthread_mutex_unlock(&window_fade_lock);\n\n    goto entry;\n}\n\nstatic void do_window_opacity_fade(char *message)\n{\n    uint32_t wid;\n    unpack(wid);\n    if (!wid) return;\n\n    float alpha, duration;\n    unpack(alpha);\n    unpack(duration);\n\n    pthread_mutex_lock(&window_fade_lock);\n    struct window_fade_context *context = table_find(&window_fade_table, &wid);\n\n    if (context) {\n        context->alpha = alpha;\n        context->duration = duration;\n        __asm__ __volatile__ (\"\" ::: \"memory\");\n\n        context->skip = true;\n        pthread_mutex_unlock(&window_fade_lock);\n    } else {\n        context = malloc(sizeof(struct window_fade_context));\n        context->wid = wid;\n        context->alpha = alpha;\n        context->duration = duration;\n        context->skip = false;\n        __asm__ __volatile__ (\"\" ::: \"memory\");\n\n        table_add(&window_fade_table, &wid, context);\n        pthread_mutex_unlock(&window_fade_lock);\n        pthread_create(&context->thread, NULL, &window_fade_thread_proc, context);\n        pthread_detach(context->thread);\n    }\n}\n\nstatic void do_window_layer(char *message)\n{\n    uint32_t wid;\n    unpack(wid);\n    if (!wid) return;\n\n    int layer;\n    unpack(layer);\n\n    SLSSetWindowSubLevel(SLSMainConnectionID(), wid, CGWindowLevelForKey(layer));\n}\n\nstatic void do_window_sticky(char *message)\n{\n    uint32_t wid;\n    unpack(wid);\n    if (!wid) return;\n\n    bool value;\n    unpack(value);\n\n    uint64_t tags = (1 << 11);\n    if (value == 1) {\n        SLSSetWindowTags(SLSMainConnectionID(), wid, &tags, 64);\n    } else {\n        SLSClearWindowTags(SLSMainConnectionID(), wid, &tags, 64);\n    }\n}\n\ntypedef void (*focus_window_call)(ProcessSerialNumber psn, uint32_t wid);\nstatic void do_window_focus(char *message)\n{\n    if (set_front_window_fp == 0) return;\n\n    int window_connection;\n    ProcessSerialNumber window_psn;\n\n    uint32_t wid;\n    unpack(wid);\n\n    SLSGetWindowOwner(SLSMainConnectionID(), wid, &window_connection);\n    SLSGetConnectionPSN(SLSMainConnectionID(), &window_psn);\n\n    ((focus_window_call) set_front_window_fp)(window_psn, wid);\n}\n\nstatic void do_window_shadow(char *message)\n{\n    uint32_t wid;\n    unpack(wid);\n    if (!wid) return;\n\n    bool value;\n    unpack(value);\n\n    uint64_t tags = (1 << 3);\n    if (value == 1) {\n        SLSClearWindowTags(SLSMainConnectionID(), wid, &tags, 64);\n    } else {\n        SLSSetWindowTags(SLSMainConnectionID(), wid, &tags, 64);\n    }\n}\n\nstatic void do_window_swap_proxy_in(char *message)\n{\n    int count = 0;\n    unpack(count);\n    if (!count) return;\n\n    CFTypeRef transaction = SLSTransactionCreate(SLSMainConnectionID());\n    for (int i = 0; i < count; ++i) {\n        uint32_t wid;\n        unpack(wid);\n        if (!wid) continue;\n\n        uint32_t proxy_wid;\n        unpack(proxy_wid);\n\n        SLSTransactionOrderWindowGroup(transaction, proxy_wid, 1, wid);\n        SLSTransactionSetWindowSystemAlpha(transaction, wid, 0);\n    }\n    SLSTransactionCommit(transaction, 0);\n    CFRelease(transaction);\n}\n\nstatic void do_window_swap_proxy_out(char *message)\n{\n    int count = 0;\n    unpack(count);\n    if (!count) return;\n\n    CFTypeRef transaction = SLSTransactionCreate(SLSMainConnectionID());\n    for (int i = 0; i < count; ++i) {\n        uint32_t wid;\n        unpack(wid);\n        if (!wid) continue;\n\n        uint32_t proxy_wid;\n        unpack(proxy_wid);\n\n        SLSTransactionSetWindowSystemAlpha(transaction, wid, 1.0f);\n        SLSTransactionOrderWindowGroup(transaction, proxy_wid, 0, wid);\n    }\n    SLSTransactionCommit(transaction, 0);\n    CFRelease(transaction);\n}\n\nstatic void do_window_order(char *message)\n{\n    uint32_t a_wid;\n    unpack(a_wid);\n    if (!a_wid) return;\n\n    int order;\n    unpack(order);\n\n    uint32_t b_wid;\n    unpack(b_wid);\n\n    SLSOrderWindow(SLSMainConnectionID(), a_wid, order, b_wid);\n}\n\nstatic void do_window_order_in(char *message)\n{\n    int count = 0;\n    unpack(count);\n    if (!count) return;\n\n    CFTypeRef transaction = SLSTransactionCreate(SLSMainConnectionID());\n    for (int i = 0; i < count; ++i) {\n        uint32_t wid;\n        unpack(wid);\n        if (!wid) continue;\n\n        SLSTransactionOrderWindowGroup(transaction, wid, 1, 0);\n    }\n    SLSTransactionCommit(transaction, 0);\n    CFRelease(transaction);\n}\n\nstatic inline CFArrayRef cfarray_of_cfnumbers(void *values, size_t size, int count, CFNumberType type)\n{\n    CFNumberRef temp[count];\n\n    for (int i = 0; i < count; ++i) {\n        temp[i] = CFNumberCreate(NULL, type, ((char *)values) + (size * i));\n    }\n\n    CFArrayRef result = CFArrayCreate(NULL, (const void **)temp, count, &kCFTypeArrayCallBacks);\n\n    for (int i = 0; i < count; ++i) {\n        CFRelease(temp[i]);\n    }\n\n    return result;\n}\n\nstatic void do_window_list_move_to_space(char *message)\n{\n    uint64_t sid;\n    unpack(sid);\n\n    int count = 0;\n    unpack(count);\n\n    CFArrayRef window_list_ref = cfarray_of_cfnumbers((uint32_t*)message, sizeof(uint32_t), count, kCFNumberSInt32Type);\n    SLSMoveWindowsToManagedSpace(SLSMainConnectionID(), window_list_ref, sid);\n    CFRelease(window_list_ref);\n}\n\nstatic void do_window_move_to_space(char *message)\n{\n    uint64_t sid;\n    unpack(sid);\n\n    uint32_t wid;\n    unpack(wid);\n\n    CFArrayRef window_list_ref = cfarray_of_cfnumbers(&wid, sizeof(uint32_t), 1, kCFNumberSInt32Type);\n    SLSMoveWindowsToManagedSpace(SLSMainConnectionID(), window_list_ref, sid);\n    CFRelease(window_list_ref);\n}\n\nstatic void do_handshake(int sockfd)\n{\n    uint32_t attrib = 0;\n\n    if (dock_spaces != nil)                attrib |= OSAX_ATTRIB_DOCK_SPACES;\n    if (dp_desktop_picture_manager != nil) attrib |= OSAX_ATTRIB_DPPM;\n    if (add_space_fp)                      attrib |= OSAX_ATTRIB_ADD_SPACE;\n    if (remove_space_fp)                   attrib |= OSAX_ATTRIB_REM_SPACE;\n    if (move_space_fp)                     attrib |= OSAX_ATTRIB_MOV_SPACE;\n    if (set_front_window_fp)               attrib |= OSAX_ATTRIB_SET_WINDOW;\n    if (animation_time_addr)               attrib |= OSAX_ATTRIB_ANIM_TIME;\n\n    char bytes[BUFSIZ] = {};\n    int version_length = strlen(OSAX_VERSION);\n    int attrib_length = sizeof(uint32_t);\n    int bytes_length = version_length + 1 + attrib_length;\n\n    memcpy(bytes, OSAX_VERSION, version_length);\n    memcpy(bytes + version_length + 1, &attrib, attrib_length);\n    bytes[version_length] = '\\0';\n    bytes[bytes_length] = '\\n';\n\n    send(sockfd, bytes, bytes_length+1, 0);\n}\n\nstatic void handle_message(int sockfd, char *message)\n{\n    enum sa_opcode op = *message++;\n    switch (op) {\n    case SA_OPCODE_HANDSHAKE: {\n        do_handshake(sockfd);\n    } break;\n    case SA_OPCODE_SPACE_FOCUS: {\n        do_space_focus(message);\n    } break;\n    case SA_OPCODE_SPACE_CREATE: {\n        do_space_create(message);\n    } break;\n    case SA_OPCODE_SPACE_DESTROY: {\n        do_space_destroy(message);\n    } break;\n    case SA_OPCODE_SPACE_MOVE: {\n        do_space_move(message);\n    } break;\n    case SA_OPCODE_WINDOW_MOVE: {\n        do_window_move(message);\n    } break;\n    case SA_OPCODE_WINDOW_OPACITY: {\n        do_window_opacity(message);\n    } break;\n    case SA_OPCODE_WINDOW_OPACITY_FADE: {\n        do_window_opacity_fade(message);\n    } break;\n    case SA_OPCODE_WINDOW_LAYER: {\n        do_window_layer(message);\n    } break;\n    case SA_OPCODE_WINDOW_STICKY: {\n        do_window_sticky(message);\n    } break;\n    case SA_OPCODE_WINDOW_SHADOW: {\n        do_window_shadow(message);\n    } break;\n    case SA_OPCODE_WINDOW_FOCUS: {\n        do_window_focus(message);\n    } break;\n    case SA_OPCODE_WINDOW_SCALE: {\n        do_window_scale(message);\n    } break;\n    case SA_OPCODE_WINDOW_SWAP_PROXY_IN: {\n        do_window_swap_proxy_in(message);\n    } break;\n    case SA_OPCODE_WINDOW_SWAP_PROXY_OUT: {\n        do_window_swap_proxy_out(message);\n    } break;\n    case SA_OPCODE_WINDOW_ORDER: {\n        do_window_order(message);\n    } break;\n    case SA_OPCODE_WINDOW_ORDER_IN: {\n        do_window_order_in(message);\n    } break;\n    case SA_OPCODE_WINDOW_LIST_TO_SPACE: {\n        do_window_list_move_to_space(message);\n    } break;\n    case SA_OPCODE_WINDOW_TO_SPACE: {\n        do_window_move_to_space(message);\n    } break;\n    }\n}\n\nstatic inline bool read_message(int sockfd, char *message)\n{\n    int bytes_read    = 0;\n    int bytes_to_read = 0;\n\n    if (read(sockfd, &bytes_to_read, sizeof(int16_t)) == sizeof(int16_t)) {\n        if (bytes_to_read >= SA_SOCKET_BUFF_LEN) return false;\n        if (bytes_to_read <= 0)                  return false;\n\n        do {\n            int cur_read = read(sockfd, message+bytes_read, bytes_to_read-bytes_read);\n            if (cur_read <= 0) break;\n\n            bytes_read += cur_read;\n        } while (bytes_read < bytes_to_read);\n\n        return bytes_read == bytes_to_read;\n    }\n\n    return false;\n}\n\nstatic void *handle_connection(void *unused)\n{\n    for (;;) {\n        int sockfd = accept(daemon_sockfd, NULL, 0);\n        if (sockfd == -1) continue;\n\n        char message[SA_SOCKET_BUFF_LEN];\n        if (read_message(sockfd, message)) {\n            handle_message(sockfd, message);\n        }\n\n        shutdown(sockfd, SHUT_RDWR);\n        close(sockfd);\n    }\n\n    return NULL;\n}\n\nstatic TABLE_HASH_FUNC(hash_wid)\n{\n    return *(uint32_t *) key;\n}\n\nstatic TABLE_COMPARE_FUNC(compare_wid)\n{\n    return *(uint32_t *) key_a == *(uint32_t *) key_b;\n}\n\nstatic bool start_daemon(char *socket_path)\n{\n    struct sockaddr_un socket_address;\n    socket_address.sun_family = AF_UNIX;\n    snprintf(socket_address.sun_path, sizeof(socket_address.sun_path), \"%s\", socket_path);\n    unlink(socket_path);\n\n    if ((daemon_sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {\n        return false;\n    }\n\n    if (bind(daemon_sockfd, (struct sockaddr *) &socket_address, sizeof(socket_address)) == -1) {\n        return false;\n    }\n\n    if (chmod(socket_path, 0600) != 0) {\n        return false;\n    }\n\n    if (listen(daemon_sockfd, SOMAXCONN) == -1) {\n        return false;\n    }\n\n    init_instances();\n    pthread_mutex_init(&window_fade_lock, NULL);\n    table_init(&window_fade_table, 150, hash_wid, compare_wid);\n    pthread_create(&daemon_thread, NULL, &handle_connection, NULL);\n\n    return true;\n}\n\n__attribute__((constructor))\nvoid load_payload(void)\n{\n    NSLog(@\"[yabai-sa] loaded payload..\");\n\n    const char *user = getenv(\"USER\");\n    if (!user) {\n        NSLog(@\"[yabai-sa] could not get 'env USER'! abort..\");\n        return;\n    }\n\n    char socket_file[255];\n    snprintf(socket_file, sizeof(socket_file), SA_SOCKET_PATH_FMT, user);\n\n    if (start_daemon(socket_file)) {\n        NSLog(@\"[yabai-sa] now listening..\");\n    } else {\n        NSLog(@\"[yabai-sa] failed to spawn thread..\");\n    }\n}\n"
  },
  {
    "path": "src/osax/x64_payload.m",
    "content": "#define asm__call_add_space(v0,v1,func) \\\n    __asm__(\"movq %0, %%rdi;\"\"movq %1, %%r13;\"\"callq *%2;\" : :\"r\"(v0), \"r\"(v1), \"r\"(func) :\"%rdi\", \"%r13\");\n\n#define asm__call_move_space(v0,v1,v2,v3,func) \\\n    __asm__(\"movq %0, %%rdi;\"\"movq %1, %%rsi;\"\"movq %2, %%rdx;\"\"movq %3, %%r13;\"\"callq *%4;\" : :\"r\"(v0), \"r\"(v1), \"r\"(v2), \"r\"(v3), \"r\"(func) :\"%rdi\", \"%rsi\", \"%rdx\", \"%r13\");\n\nuint64_t get_dock_spaces_offset(NSOperatingSystemVersion os_version) {\n    if (os_version.majorVersion == 26) {\n        return 0x90000;\n    } else if (os_version.majorVersion == 15) {\n        return 0xA0000;\n    } else if (os_version.majorVersion == 14) {\n        return os_version.minorVersion > 0 ? 0xD5000 : 0x140000;\n    } else if (os_version.majorVersion == 13) {\n        return 0x140000;\n    } else if (os_version.majorVersion == 12) {\n        return 0x9000;\n    } else if ((os_version.majorVersion == 11) || (os_version.majorVersion == 10 && os_version.minorVersion == 16)) {\n        return 0x8d00;\n    }\n\n    return 0;\n}\n\nuint64_t get_dppm_offset(NSOperatingSystemVersion os_version) {\n    if (os_version.majorVersion == 26) {\n        return 0x140000;\n    } else if (os_version.majorVersion == 15) {\n        return 0x13b000;\n    } else if (os_version.majorVersion == 14) {\n        return os_version.minorVersion > 0 ? 0x12ce00 : 0x8000;\n    } else if (os_version.majorVersion == 13) {\n        return 0x8000;\n    } else if (os_version.majorVersion == 12) {\n        return 0x7000;\n    } else if ((os_version.majorVersion == 11) || (os_version.majorVersion == 10 && os_version.minorVersion == 16)) {\n        return 0x7000;\n    }\n\n    return 0;\n}\n\nuint64_t get_fix_animation_offset(NSOperatingSystemVersion os_version) {\n    if (os_version.majorVersion == 26) {\n        return 0x2A0000;\n    } else if (os_version.majorVersion == 15) {\n        return os_version.minorVersion >= 4 ? 0x270000 : 0x280000;\n    } else if (os_version.majorVersion == 14) {\n        return os_version.minorVersion > 0 ? 0x1f0000 : 0x210000;\n    } else if (os_version.majorVersion == 13) {\n        return 0x210000;\n    } else if (os_version.majorVersion == 12) {\n        return 0x230000;\n    } else if ((os_version.majorVersion == 11) || (os_version.majorVersion == 10 && os_version.minorVersion == 16)) {\n        return 0x232000;\n    }\n\n    return 0;\n}\n\nuint64_t get_add_space_offset(NSOperatingSystemVersion os_version) {\n\n    if (os_version.majorVersion == 26) {\n        return 0x2A5000;\n    } else if (os_version.majorVersion == 15) {\n        return os_version.minorVersion >= 4 ? 0x270000 : 0x280000;\n    } else if (os_version.majorVersion == 14) {\n        return os_version.minorVersion > 0 ? 0x1f0000 : 0x217000;\n    } else if (os_version.majorVersion == 13) {\n        return 0x213000;\n    } else if (os_version.majorVersion == 12) {\n        return 0x230000;\n    } else if ((os_version.majorVersion == 11) || (os_version.majorVersion == 10 && os_version.minorVersion == 16)) {\n        return 0x230000;\n    }\n\n    return 0;\n}\n\nuint64_t get_remove_space_offset(NSOperatingSystemVersion os_version) {\n    if (os_version.majorVersion == 26) {\n        return 0x211000;\n    } else if (os_version.majorVersion == 15) {\n        return 0x1e0000;\n    } else if (os_version.majorVersion == 14) {\n        return os_version.minorVersion > 0 ? 0x2B0000 : 0x2D0000;\n    } else if (os_version.majorVersion == 13) {\n        return 0x2C0000;\n    } else if (os_version.majorVersion == 12) {\n        return 0x2E0000;\n    } else if ((os_version.majorVersion == 11) || (os_version.majorVersion == 10 && os_version.minorVersion == 16)) {\n        return 0x2E0000;\n    }\n\n    return 0;\n}\n\nuint64_t get_move_space_offset(NSOperatingSystemVersion os_version) {\n    if (os_version.majorVersion == 26) {\n        return 0x210000;\n    } else if (os_version.majorVersion == 15) {\n        return 0x1e0000;\n    } else if (os_version.majorVersion == 14) {\n        return os_version.minorVersion > 0 ? 0x2A0000 : 0x2C0000;\n    } else if (os_version.majorVersion == 13) {\n        return 0x2B0000;\n    } else if (os_version.majorVersion == 12) {\n        return 0x2D0000;\n    } else if ((os_version.majorVersion == 11) || (os_version.majorVersion == 10 && os_version.minorVersion == 16)) {\n        return 0x2D0000;\n    }\n\n    return 0;\n}\n\nuint64_t get_set_front_window_offset(NSOperatingSystemVersion os_version) {\n    if (os_version.majorVersion == 26) {\n        return 0x22000;\n    } else if (os_version.majorVersion == 15) {\n        return 0x3d000;\n    } else if (os_version.majorVersion == 14) {\n        return os_version.minorVersion > 0 ? 0x4a000 : 0x51BBE;\n    } else if (os_version.majorVersion == 13) {\n        return 0x52000;\n    } else if (os_version.majorVersion == 12) {\n        return 0x51000;\n    } else if ((os_version.majorVersion == 11) || (os_version.majorVersion == 10 && os_version.minorVersion == 16)) {\n        return 0x51000;\n    }\n\n    return 0;\n}\n\nconst char *get_dock_spaces_pattern(NSOperatingSystemVersion os_version) {\n    if (os_version.majorVersion == 26 || os_version.majorVersion == 15) {\n        return \"?? ?? ?? 00 48 8B 38 48 8B 35 ?? ?? ?? 00 89 DA 41 FF D5 48 89 C7 E8 ?? ?? ?? 00 49 89 C7 48 8B 35 ?? ?? ?? 00 48 89\";\n    } else if (os_version.majorVersion == 14) {\n        if (os_version.minorVersion > 0) {\n            return \"?? ?? ?? 00 48 8B 38 48 8B 35 ?? ?? ?? 00 89 DA 41 FF D5 48 89 C7 E8 ?? ?? ?? 00 49 89 C7 48 8B 35 ?? ?? ?? 00 48 89\";\n        }\n        return \"?? ?? ?? 00 49 8B 3E 48 8B 35 A0 DD 2B 00 44 89 A5 78 FE FF FF 44 89 E2 49 89 DC FF D3 48 89 C7 E8 C5 66 1E 00 48 89 85 F8 FD FF FF 48 8B 3D FB 19 2C 00 E8 0A 66 1E 00 48 8B 1D 2F EA 2B 00 48 89 C7 48 89 DE 31 D2 41 FF D4 48 89 85 38 FE FF FF 49\";\n    } else if (os_version.majorVersion == 13) {\n        return \"?? ?? ?? 00 49 8B 7D 00 48 8B 35 ?? ?? ?? 00 44 89 BD ?? FE FF FF 44 89 FA 41 FF D4 48 89 C7 E8 ?? ?? ?? 00 48 89 85 E8 FD FF FF 48 8B 3D ?? ?? ?? 00 E8 ?? ?? ?? 00 48 8B 35 ?? ?? ?? 00 48 89 C7 31 D2 41 FF D4 48 89 85 ?? FE FF FF 49 8B 7D 00 48\";\n    } else if (os_version.majorVersion == 12) {\n        return \"?? ?? ?? 00 49 8B ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 89 ?? 31 D2 41 FF ?? 48 89 85 ?? FE FF FF 49 8B ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? FF ?? ?? 89\";\n    } else if ((os_version.majorVersion == 11) || (os_version.majorVersion == 10 && os_version.minorVersion == 16)) {\n        return \"?? ?? ?? 00 49 8B 7D 00 48 8B 35 ?? ?? ?? 00 44 89 BD 38 FE FF FF 44 89 FA 41 FF D4 48 89 C7 E8 ?? ?? ?? 00 48 89 85 E8 FD FF FF 48 8B 3D ?? ?? ?? 00 E8 ?? ?? ?? 00 48 8B 35 ?? ?? ?? 00 48 89 C7 31 D2 41 FF D4 48 89 85 28 FE FF FF 49 8B 7D 00 48\";\n    }\n\n    return NULL;\n}\n\nconst char *get_dppm_pattern(NSOperatingSystemVersion os_version) {\n    if (os_version.majorVersion == 26 || os_version.majorVersion == 15) {\n        return \"?? ?? ?? 00 31 FF 5D E9 ?? ??\";\n    } else if (os_version.majorVersion == 14) {\n        if (os_version.minorVersion > 0) {\n            return \"?? ?? ?? 00 31 FF 5D E9 ?? ?? 1C 00\";\n        }\n        return \"?? ?? ?? 00 4C 89 FE E8 ?? ?? ?? 00 4D 85 FF 0F 84 ?? 06 00 00 48 8D 35 ?? ?? 42 00 31 FF E8 ?? ?? 31 00 48 8B 3D ?? ?? 3F 00 48 8B 35 ?? ?? 3F 00 FF 15 ?? ?? 39 00 48 89 C7 E8 ?? ?? 31 00 48 89 85 10 FF FF FF C7 85 1C FF FF FF 00 00 00 00 E8 ?? ?? 31 00 48 8D 75 B0 89 C7 E8\";\n    } else if (os_version.majorVersion == 13) {\n        return \"?? ?? ?? 00 48 89 C6 E8 ?? ?? ?? 00 4D 85 FF 0F 84 ?? 06 00 00 48 8D 35 ?? ?? 41 00 31 FF E8 ?? ?? 30 00 48 8B 3D ?? ?? 3E 00 48 8B 35 ?? ?? 3E 00 FF 15 ?? ?? 37 00 48 89 C7 E8 ?? ?? 30 00 48 89 85 08 FF FF FF C7 85 1C FF FF FF 00 00 00 00 E8 ?? ?? 30 00 48 8D 75 B0 89 C7 E8\";\n    } else if (os_version.majorVersion == 12) {\n        return \"?? ?? ?? 00 48 89 C6 E8 ?? ?? 31 00 4D 85 FF 0F 84 ?? 06 00 00 48 8B 3D ?? ?? 40 00 48 8B 35 ?? ?? 3F 00 FF 15 ?? ?? 38 00 48 89 C7 E8 ?? ?? 31 00 48 89 85 08 FF FF FF C7 85 1C FF FF FF 00 00 00 00 E8 ?? ?? 31 00 48 8D 75 B0 89 C7 E8 ?? ?? 31 00 85 C0 75 22 48 8D 35 ?? ?? 35 00 48 8D\";\n    } else if ((os_version.majorVersion == 11) || (os_version.majorVersion == 10 && os_version.minorVersion == 16)) {\n        return \"?? ?? ?? 00 48 89 C6 E8 ?? ?? ?? 00 4D 85 ?? 0F 84 ?? 06 00 00 48 8B 3D ?? ?? ?? 00 48 8B 35 ?? ?? ?? 00 FF 15 ?? ?? ?? 00 48 89 C7 E8 ?? ?? ?? 00 48 89 85 08 FF FF FF C7 85 1C FF FF FF 00 00 00 00 E8 ?? ?? ?? 00 48 8D 75 B0 89 C7 E8 ?? ?? ?? ??\";\n    }\n\n    return NULL;\n}\n\n\nconst char *get_fix_animation_pattern(NSOperatingSystemVersion os_version) {\n    if (os_version.majorVersion == 26) {\n        // This pattern is pulled from a different spot with a MOVSD referencing\n        // the same 'global.' This pattern also works on 15, let's not change it.\n        return \"F2 0F 10 ?? ?? ?? ?? ?? 48 89 ?? 48 89 ?? 4C 8B ?? ?? E8\";\n    } else if (os_version.majorVersion == 15) {\n        if (os_version.minorVersion >= 4) {\n            return \"F2 0F 10 05 DB 13 0B 00 4C 89 F7 48 89 DE\";\n        }\n        return \"F2 0F 10 05 ?? ?? ?? 00 48 8B ?? ?? 48 ?? ??\";\n    } else if (os_version.majorVersion == 14) {\n        return \"F2 0F 10 05 ?? ?? ?? 00 4C 89 ?? 48 89 DE\";\n    } else if (os_version.majorVersion == 13) {\n        return \"F2 0F 10 05 ?? ?? ?? 00 4C 89 ?? 48 8B 75 ?? ?? 89 ?? 44 8B 85 ?? FF FF FF 4C 8B 8D ?? FF FF FF 4C 8B 6D ?? 50 56 6A 01 ?? ?? ?? ?? ?? ??\";\n    } else if (os_version.majorVersion == 12) {\n        return \"F2 0F 10 05 ?? ?? ?? 00 4C 89 ?? 48 8B 75 ?? ?? 89 ?? 44 8B 85 ?? FF FF FF 4C 8B 8D ?? FF FF FF 4C 8B 6D ?? 50 56 6A 01 ?? ?? ?? ?? ?? ??\";\n    } else if ((os_version.majorVersion == 11) || (os_version.majorVersion == 10 && os_version.minorVersion == 16)) {\n        return \"F2 0F 10 05 ?? ?? 0F 00 4C 89 EF 48 8B 75 B8 4C 89 F2 44 8B 45 A8 4C 8B 8D 28 FF FF FF 4C 8B 6D 98 50 56 6A 01 49 89 DF 53 41 54 E8 ?? ?? 08 00 48 83 C4 30 48 89 45 98\";\n    }\n\n    return NULL;\n}\n\nconst char *get_add_space_pattern(NSOperatingSystemVersion os_version) {\n    // Find this one as the function prologue where the function\n    // references string 'addSpace:forDisplayUUID:'\n    if (os_version.majorVersion == 26) {\n        return \"55 48 89 E5 41 57 41 56 41 55 41 54 53 48 83 EC ?? 48 89 7D ?? 4D 8D 75 ??\";\n    } else if (os_version.majorVersion == 15) {\n        if (os_version.minorVersion >= 4) {\n            return \"55 48 89 E5 41 57 41 56 41 55 41 54 53 48 83 EC 28 4D 89 EE 48 89 7D B8\";\n        }\n        return \"55 48 89 E5 41 57 41 56 41 55 41 54 53 48 83 EC 28 48 BA 01 00 00 00 00\";\n    } else if (os_version.majorVersion == 14) {\n        if (os_version.minorVersion >= 4) {\n            return \"55 48 89 E5 41 57 41 56 41 55 41 54 53 48 83 EC 28 48 89 7D C8 49 BE 01 00 00 00 00 00 00 40 49 BC F8 FF FF FF FF FF FF 00 49 8D 45 28 48 89 45 D0 4D 8B 7D 28 4C 89 6D B8 41 80 7D 38 01 75 15 4D 85 F7 0F 85 4D 03 00 00 4D 21 E7 49 8B 5F 10 E9 96 01 00 00 4D 85 F7 0F 85 68 03 00 00 4C 89 F8 4C 21 E0 48 8B 58 10 4C 89 FF E8 ?? ?? 10 00 48 85 DB 0F 84 24 01 00 00 49 89 DC 49 FF CC 0F 80 67 03 00 00 49 BE 03 00 00 00 00 00\";\n        }\n        return \"55 48 89 E5 41 57 41 56 41 55 41 54 53 48 83 EC 28 48 89 7D C0 48 B8 01 00 00 00 00 00 00 40 48 BB F8 FF FF FF FF FF FF 00 4D 8B 65 28 41 80 7D 38 01 75 1A 49 85 C4 0F 85 7F 03 00 00 49 21 DC 49 8B 4C 24 10 48 89 4D D0 E9 9A 01 00 00 49 85 C4 4C 89 6D C8 0F 85 9C 03 00 00 4C 89 E0 48 21 D8 48 8B 58 10 4C 89 E7 E8 ?? ?? 10 00 48 85 DB 0F 84 10 01 00 00 49 89 DF 49 FF CF 0F 80 9E 03 00 00 49 BE 03 00 00 00 00 00 00 C0 31\";\n    } else if (os_version.majorVersion == 13) {\n        return \"55 48 89 E5 41 57 41 56 41 55 41 54 53 48 83 EC 18 48 89 7D D0 48 B8 01 00 00 00 00 00 00 40 49 BF F8 FF FF FF FF FF FF 00 4D 8B 65 28 4C 89 6D C8 41 80 7D 38 01 75 16 49 85 C4 0F 85 ?? 03 00 00 4D 21 FC 4D 8B 74 24 10 E9 ?? 01 00 00 49 85 C4 0F 85 ?? 03 00 00 4C 89 E0 4C 21 F8 4C 8B 70 10 4C 89 E7 E8 ?? ?? ?? 00 4D 85 F6 0F 84 ?? 01 00 00 4D 89 F7 49 FF CF 0F 80 ?? 03 00 00 48 BB 03 00 00 00 00 00 00 C0 31\";\n    } else if (os_version.majorVersion == 12) {\n        return \"55 48 89 E5 41 57 41 56 41 55 41 54 53 48 83 EC 18 48 89 7D D0 48 B8 01 00 00 00 00 00 00 40 49 BF F8 FF FF FF FF FF FF 00 4D 8B 65 28 4C 89 6D C8 41 80 7D 38 01 75 16 49 85 C4 0F 85 ?? 03 00 00 4D 21 FC 4D 8B 74 24 10 E9 ?? 01 00 00 49 85 C4 0F 85 ?? 03 00 00 4C 89 E0 4C 21 F8 4C 8B 70 10 4C 89 E7 E8 ?? ?? 0E 00 4D 85 F6 0F 84 ?? 01 00 00 4D 89 F7 49 FF CF 0F 80 ?? 03 00 00 48 BB 03 00 00 00 00 00 00 C0 31\";\n    } else if ((os_version.majorVersion == 11) || (os_version.majorVersion == 10 && os_version.minorVersion == 16)) {\n        if (os_version.majorVersion == 11 && os_version.minorVersion >= 2) {\n            return \"55 48 89 E5 41 57 41 56 41 55 41 54 53 48 83 EC ?? 48 BA 01 00 00 00 00 00 00 40 48 B9 F8 FF FF FF FF FF FF 00 49 8D 45 28 48 89 45 C8 4D 8B 7D 28 41 80 7D 38 01 48 89 7D D0 4C 89 6D ?? 75 2E 49 89 FC 49 85 D7 74 ?? 4C 89 FB 48 21 CB 41 F6 C7 01 49 0F 45 DF 4C 89 FF E8 ?? ?? ?? 00 48 89 DF E8 ??\";\n        }\n        return \"55 48 89 E5 41 57 41 56 41 55 41 54 53 48 83 EC 18 4C 89 6D C0 48 BA 01 00 00 00 00 00 00 40 48 B9 F8 FF FF FF FF FF FF 00 49 8D 45 28 48 89 45 D0 4D 8B 7D 28 41 80 7D 38 01 48 89 7D C8 75 2E 49 89 FC 49 85 D7 74 59 4C 89 FB 48 21 CB 41 F6 C7 01 49 0F 45 DF 4C 89 FF E8 ?? ?? 0F 00 48 89 DF E8 ??\";\n    }\n\n    return NULL;\n}\n\nconst char *get_remove_space_pattern(NSOperatingSystemVersion os_version) {\n    // Here a regex search over decompiled text;\n    // _objc_msgSend\\(.*,\"removeSpace:\"\n    // and the function with four parameters.\n\n    if (os_version.majorVersion == 26) {\n        return \"55 48 89 E5 41 57 41 56 41 55 41 54 53 48 83 EC ?? 48 89 CB 49 89 D6 49 89 F5 49\";\n    } else if (os_version.majorVersion == 15) {\n        return \"55 48 89 E5 41 57 41 56 41 55 41 54 53 48 83 EC ?? 49 89 ?? 49 89 D6 49 89 F5 ?? 89 ??\";\n    } else if (os_version.majorVersion == 14) {\n        return \"55 48 89 E5 41 57 41 56 41 55 41 54 53 48 83 EC 68 48 89 4D ?? 49 89 D7 49 89 F5 49 89 FC 48 BB F8 FF FF FF FF FF FF 00 E8 ?? ?? ?? FF 49 89 C6 48 B8 01 00 00 00 00 00 00 40 4C 21 F3 49 85 C6 0F 85 ?? 02 00 00 48 8B 43 10 48 83 F8 02 0F 8C ?? 02 00 00 4C 89 6D ?? 4C 89 75 A0 48 8D 05 ?? ?? ?? 00 48 8B 00 49 8B 1C 04 4D 8B 74 04 08 48 8D 05 ?? ?? ?? 00 48 8B 38 48 8B 35 ?? ?? ??\";\n    } else if (os_version.majorVersion == 13) {\n        return \"55 48 89 E5 41 57 41 56 41 55 41 54 53 48 83 EC 68 48 89 4D 88 49 89 D6 49 89 F5 49 89 FF E8 ?? ?? F4 FF 48 89 C3 48 B8 01 00 00 00 00 00 00 40 48 85 C3 0F 85 ?? 04 00 00 48 B8 F8 FF FF FF FF FF FF 00 48 21 D8 48 8B 40 10 48 83 F8 02 0F 8C ?? 02 00 00 4C 89 6D 90 48 89 5D A8 48 8D 05 ?? ?? 13 00 48 8B 00 4C 89 F3 4D 8B 34 07 4D 8B 64 07 08 48 8D 05 ?? ?? ?? 00 48 8B 38 48 8B 35 ?? ?? 12 00 4C 89 7D A0 4C 89\";\n    } else if (os_version.majorVersion == 12) {\n        if (os_version.minorVersion >= 3) {\n            return \"55 48 89 E5 41 57 41 56 41 55 41 54 53 48 81 EC A8 00 00 00 48 89 4D 90 49 89 D7 49 89 F5 49 89 FE E8 CD 71 F4 FF 48 89 C3 48 B8 01 00 00 00 00 00 00 40 48 BF F8 FF FF FF FF FF FF 00 48 21 DF 48 85 C3 0F 85 14 06 00 00 48 8B 47 10 48 83 F8 02 0F 8C 22 02 00 00 4C 89 AD 60 FF FF FF 48 89 5D A8 48 8D 05 B3 7D 13 00 48 8B 00 4D 8B 2C 06 49 8B 44 06 08 48 89 45 B8 48 8D 05 B4 7C 14 00 48 8B 38 48 8B 35 C2 BB 11 00\";\n        }\n        return \"55 48 89 E5 41 57 41 56 41 55 41 54 53 48 81 EC A8 00 00 00 49 89 CC 49 89 D7 49 89 F5 49 89 FE E8 ?? ?? F4 FF 48 89 C3 48 B8 01 00 00 00 00 00 00 40 48 BF F8 FF FF FF FF FF FF 00 48 21 DF 48 85 C3 0F 85 35 06 00 00 48 8B 47 10 48 83 F8 02 0F 8C 29 02 00 00 4C 89 65 90 4C 89 AD 60 FF FF FF 48 89 5D A0 48 8D 05 ?? ?? 13 00 48 8B 00 4D 8B 2C 06 49 8B 44 06 08 48 89 45 B8 48 8D 05 ?? ?? 14 00 48 8B 38 48 8B 35 ??\";\n    } else if ((os_version.majorVersion == 11) || (os_version.majorVersion == 10 && os_version.minorVersion == 16)) {\n        if (os_version.majorVersion == 11 && os_version.minorVersion >= 3) {\n            return \"55 48 89 E5 41 57 41 56 41 55 41 54 53 48 81 EC C8 00 00 00 49 89 CC 49 89 D7 49 89 F5 49 89 FE E8 ?? ?? F4 FF 48 89 C3 48 B8 01 00 00 00 00 00 00 40 48 BF F8 FF FF FF FF FF FF 00 48 21 DF 48 85 C3 0F 85 0C 06 00 00 48 8B 47 10 48 83 F8 02 0F 8C 36 02 00 00 4C 89 65 A8 4C 89 AD 68 FF FF FF 48 89 5D A0 48 8D 05 ?? ?? 13 00 48 8B 00 4D\";\n        }\n        return \"55 48 89 E5 41 57 41 56 41 55 41 54 53 48 83 EC 68 48 89 4D 98 49 89 D4 49 89 F6 49 89 FF 49 89 F5 E8 ?? ?? F3 FF 49 89 C5 48 B8 01 00 00 00 00 00 00 40 49 85 C5 0F 85 DE 03 00 00 48 B8 F8 FF FF FF FF FF FF 00 4C 21 E8 48 8B 58 10 48 83 FB 02 0F 8C CD 01 00 00 4C 89 75 A0 48 8D 05 ?? ?? ?? 00 48 8B 00 4D 8B 34 07 4C 89 E3 4D 8B 64 07\";\n    }\n\n    return NULL;\n}\n\nconst char *get_move_space_pattern(NSOperatingSystemVersion os_version) {\n    // Searching decompiled text for regex;\n    // _objc_msgSend\\(.*,\"moveSpace:toDisplay:displayUUID:\"\n    // two parameter function.\n    if (os_version.majorVersion == 26) {\n        return \"55 48 89 E5 41 57 41 56 41 55 41 54 53 48 83 EC 38 4D 89 EC 41 89 D5 49 89 F7 48 8B 05\";\n    } else if (os_version.majorVersion == 15) {\n        return \"55 48 89 E5 41 57 41 56 41 55 41 54 53 48 83 EC 38 4C 89 E9 41 89 D5 49 89 F7 49 89 FC 48 8B 05 ?? ?? 25\";\n    } else if (os_version.majorVersion == 14) {\n        return \"55 48 89 E5 41 57 41 56 41 55 41 54 53 48 83 EC 48 4C 89 E9 41 89 D5 49 89 ?? 49 89 FF ?? 8D ?? ?? ?? ?? 00 ?? 8B ?? ?? 8B ?? 07 ?? 89 ?? 48 89 4D A0 48 89 CE E8 ?? ?? 00 00 48 89 55 D0 48 89 45 C8 48 85 C0 74 3F 48 8D 05 ?? ?? ?? 00 80 38 01 75 ?? ?? 8B ?? D0 ?? 89 ?? 49 83 C5 28 4C 8B 7D C8 4C 89 FF E8 ?? ?? ?? FF 48 89 C7 FF 15 ?? ?? 0C 00\";\n    } else if (os_version.majorVersion == 13) {\n        return \"55 48 89 E5 41 57 41 56 41 55 41 54 53 48 83 EC 48 4C 89 E9 41 89 D5 49 89 F6 49 89 FF 48 8D 1D ?? ?? 14 00 48 8B 03 4C 8B 24 07 4C 89 E7 48 89 4D A0 48 89 CE E8 ?? ?? 00 00 48 89 55 D0 48 89 45 C8 48 85 C0 74 3F 48 8D 05 ?? ?? 15 00 80 38 01 75 3A 4C 8B 65 D0 4D 89 E5 49 83 C5 28 4C 8B 7D C8 4C 89 FF E8 ?? ?? F5 FF 48 89 C7 FF 15 ?? ?? 0C 00\";\n    } else if (os_version.majorVersion == 12) {\n        if (os_version.minorVersion >= 3) {\n            return \"55 48 89 E5 41 57 41 56 41 55 41 54 53 48 83 EC 48 41 89 D6 48 89 75 C8 48 89 FB 4C 8D 3D 7F 64 14 00 49 8B 07 48 8B 3C 07 48 8D 35 E3 F7 00 00 45 31 E4 48 89 7D C0 31 D2 4C 89 6D A8 E8 C6 A9 00 00 48 89 55 D0 48 85 C0 0F 84 B6 04 00 00 48 8D 0D B3 5F 15 00 80 39 01 48 89 45 B0 75 33 4C 8B 7D D0 4D 89 FD 49 83 C5 28 48 89 C3 48 89 C7 E8 7C 8F\";\n        }\n        return \"55 48 89 E5 41 57 41 56 41 55 41 54 53 48 83 EC 48 4C 89 E9 41 89 D5 49 89 F6 49 89 FF 48 8D 1D ?? ?? 14 00 48 8B 03 4C 8B 24 07 4C 89 E7 48 89 4D A0 48 89 CE E8 47 B8 00 00 48 85 C0 74 45 48 8D 0D ?? ?? 15 00 80 39 01 48 89 55 C8 48 89 45 A8 75 38 49 89 D5 49 83 C5 28 48 89 C3 48 89 C7 49 89 D7 E8 ?? ?? F5 FF 48 89 C7 FF 15 ?? ?? 0B 00 48 89\";\n    } else if ((os_version.majorVersion == 11) || (os_version.majorVersion == 10 && os_version.minorVersion == 16)) {\n        if (os_version.majorVersion == 11 && os_version.minorVersion >= 3) {\n            return \"55 48 89 E5 41 57 41 56 41 55 41 54 53 48 83 EC 48 4C 89 E9 41 89 D5 49 89 F6 49 89 FF 48 8D 1D ?? ?? ?? 00 48 8B 03 4C 8B 24 07 4C 89 E7 48 89 4D A0 48 89 CE E8 ?? ?? 00 00 48 85 C0 74 ?? 48 8D 0D ?? ?? ?? 00 80 39 01 48 89 55 C8 48 89 45 A8 75 38 49 89 D5 49 83 C5 28 48 89 C3 48 89 C7\";\n        }\n        return \"55 48 89 E5 41 57 41 56 41 55 41 54 53 48 83 EC 48 4C 89 E9 41 89 D5 49 89 F6 49 89 FF 48 8D 1D ?? ?? ?? 00 48 8B 03 4C 8B 24 07 4C 89 E7 48 89 4D A0 48 89 CE E8 ?? ?? 00 00 48 85 C0 74 27 48 8D 0D ?? ?? ?? 00 80 39 01 48 89 55 C8 48 89 45 A8 75 1A 48 89 C7 4C 89 F6 49 89 D5 E8 ?? ?? F4\";\n    }\n\n    return NULL;\n}\n\nconst char *get_set_front_window_pattern(NSOperatingSystemVersion os_version) {\n    // references to string \"com.apple.window_proxies.startup\" -\n    // two parameter function\n    if (os_version.majorVersion == 26) {\n        return \"85 F6 0F 84 ?? ?? ?? ?? 55 48 89 E5 41 57 41 56 41 54 53 48 83 EC 40\";\n    } else if (os_version.majorVersion == 15) {\n        return \"55 48 89 E5 41 57 41 56 41 54 53 48 83 EC 60 48 8B 05 ?? ?? ?? 00 48 8B 00 48 89 45 D8 85 F6 0F 84 ?? 02 00 00 89 F3 49 89 FE 49 89 FC 49 C1 ?? 20 ?? 8D ?? AF 41 C6 07 00 4C 89 FE E8 ?? ?? 06 00 48 8B\";\n    } else if (os_version.majorVersion == 14) {\n        return \"55 48 89 E5 41 57 41 56 41 54 53 48 83 EC 60 48 8B 05 ?? ?? ?? 00 48 8B 00 48 89 45 D8 85 F6 0F 84 ?? 02 00 00 89 F3 49 89 FE 49 89 FF 49 C1 EF 20 48 8D 75 AF C6 06 00 E8 ?? ?? 02 00 48 8B 3D ?? ?? ?? 00 BE 01 00 00 00 E8 ?? ?? ?? 00 84 C0 74 5A 44 0F B6 65 AF 4C 8D 45 B0 41 C7 00 00 04 00 04 45 89 70 04 66 B8 00 04 66 41 89 40 08 45 89 78 0A 66 41 89 40 0E 41 89 58 10 66 41 89 40\";\n    } else if (os_version.majorVersion == 13) {\n        return \"55 48 89 E5 41 57 41 56 41 55 41 54 53 48 83 EC 58 48 8B 05 ?? ?? ?? 00 48 8B 00 48 89 45 D0 85 F6 0F 84 00 02 00 00 41 89 F6 49 89 FD 49 89 FF 49 C1 EF 20 48 8D 75 AF C6 06 00 E8 ?? ?? 02 00 48 8B 3D ?? ?? ?? 00 BE 01 00 00 00 E8 ?? ?? 2C 00 84 C0 74 59 0F B6 5D AF 4C 8D 45 B0 41 C7 00 00 04 00 04 45 89 68 04 66 B8 00 04 66 41 89 40 08 45 89 78 0A 66 41 89 40 0E 45 89 70 10 66 41\";\n    } else if (os_version.majorVersion == 12) {\n        return \"55 48 89 E5 41 57 41 56 41 55 41 54 53 48 83 EC 58 48 8B 05 ?? ?? ?? 00 48 8B 00 48 89 45 D0 85 F6 0F 84 00 02 00 00 41 89 F6 49 89 FD 49 89 FF 49 C1 EF 20 48 8D 75 AF C6 06 00 E8 ?? ?? 02 00 48 8B 3D ?? ?? ?? 00 BE 01 00 00 00 E8 ?? ?? 2C 00 84 C0 74 59 0F B6 5D AF 4C 8D 45 B0 41 C7 00 00 04 00 04 45 89 68 04 66 B8 00 04 66 41 89 40 08 45 89 78 0A 66 41 89 40 0E 45 89 70 10 66 41\";\n    } else if ((os_version.majorVersion == 11) || (os_version.majorVersion == 10 && os_version.minorVersion == 16)) {\n        return \"55 48 89 E5 41 57 41 56 41 55 41 54 53 48 83 EC 58 48 8B 05 ?? ?? ?? 00 48 8B 00 48 89 45 D0 85 F6 0F 84 ?? 02 00 00 41 89 F5 49 89 FF 49 89 FE 49 C1 EE 20 48 8D 75 AF C6 06 00 E8 ?? ?? 02 00 48 8B 3D ?? ?? ?? 00 BE 01 00 00 00 E8 ?? ?? ?? 00 84 C0 74 59 0F B6 5D AF 4C 8D 45\";\n    }\n\n    return NULL;\n}\n"
  },
  {
    "path": "src/process_manager.c",
    "content": "extern struct event_loop g_event_loop;\nextern void *g_workspace_context;\n\nstatic TABLE_HASH_FUNC(hash_psn)\n{\n    return ((ProcessSerialNumber *) key)->lowLongOfPSN;\n}\n\nstatic TABLE_COMPARE_FUNC(compare_psn)\n{\n    return psn_equals(key_a, key_b);\n}\n\nstatic const char *process_name_blacklist[] =\n{\n    \"Übersicht\",\n    \"Slack Helper (Plugin)\",\n    \"Google Chrome Helper (Plugin)\",\n    \"qlmanage\",\n};\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wdeprecated-declarations\"\nstatic inline pid_t process_pid_for_psn(ProcessSerialNumber psn)\n{\n    pid_t pid = 0;\n    GetProcessPID(&psn, &pid);\n    return pid;\n}\n\nstatic struct process *process_create(ProcessSerialNumber psn, pid_t pid)\n{\n    ProcessInfoRec process_info = { .processInfoLength = sizeof(ProcessInfoRec) };\n    GetProcessInformation(&psn, &process_info);\n\n    CFStringRef process_name_ref = NULL;\n    CopyProcessName(&psn, &process_name_ref);\n\n    if (!process_name_ref) {\n        debug(\"%s: could not retrieve process name! ignoring..\\n\", __FUNCTION__);\n        return NULL;\n    }\n\n    char *process_name = cfstring_copy(process_name_ref);\n    CFRelease(process_name_ref);\n\n    if (process_info.processType == 'XPC!') {\n        debug(\"%s: xpc service '%s' detected! ignoring..\\n\", __FUNCTION__, process_name);\n        free(process_name);\n        return NULL;\n    }\n\n    for (int i = 0; i < array_count(process_name_blacklist); ++i) {\n        if (string_equals(process_name, process_name_blacklist[i])) {\n            debug(\"%s: %s is blacklisted! ignoring..\\n\", __FUNCTION__, process_name);\n            free(process_name);\n            return NULL;\n        }\n    }\n\n    struct process *process = malloc(sizeof(struct process));\n    process->psn = psn;\n    process->pid = pid;\n    process->name = process_name;\n    __atomic_store_n(&process->terminated, false, __ATOMIC_RELEASE);\n    __atomic_store_n(&process->ns_application, workspace_application_create_running_ns_application(process), __ATOMIC_RELEASE);\n    return process;\n}\n\nstatic bool process_is_being_debugged(pid_t pid)\n{\n    struct kinfo_proc info;\n    info.kp_proc.p_flag = 0;\n\n    size_t size = sizeof(info);\n    int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, pid };\n\n    sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, NULL, 0);\n    return ((info.kp_proc.p_flag & P_TRACED) != 0);\n}\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wunused-parameter\"\nstatic PROCESS_EVENT_HANDLER(process_handler)\n{\n    struct process_manager *pm = context;\n\n    ProcessSerialNumber psn;\n    if (GetEventParameter(event, kEventParamProcessID, typeProcessSerialNumber, NULL, sizeof(psn), NULL, &psn) != noErr) {\n        return -1;\n    }\n\n    switch (GetEventKind(event)) {\n    case kEventAppLaunched: {\n        if (process_manager_find_process(pm, &psn)) {\n\n            //\n            // NOTE(asmvik): Some garbage applications (e.g Steam) are reported twice with the same PID and PSN for some hecking reason.\n            // It is by definition NOT possible for two processes to exist at the same time with the same PID and PSN.\n            // If we detect such a scenario we simply discard the dupe notification..\n            //\n\n            return noErr;\n        }\n\n        pid_t pid = process_pid_for_psn(psn);\n        if (process_is_being_debugged(pid)) {\n            debug(\"%s: process with pid %d is running under a debugger! ignoring..\\n\", __FUNCTION__, pid);\n            return noErr;\n        }\n\n        struct process *process = process_create(psn, pid);\n        if (!process) return noErr;\n\n        table_add(&pm->process, &process->psn, process);\n        event_loop_post(&g_event_loop, APPLICATION_LAUNCHED, process, 0);\n    } break;\n    case kEventAppTerminated: {\n        struct process *process = process_manager_find_process(pm, &psn);\n        if (!process) return noErr;\n\n        __atomic_store_n(&process->terminated, true, __ATOMIC_RELEASE);\n        table_remove(&pm->process, &psn);\n        workspace_application_unobserve(g_workspace_context, process);\n        __asm__ __volatile__ (\"\" ::: \"memory\");\n\n        event_loop_post(&g_event_loop, APPLICATION_TERMINATED, process, 0);\n    } break;\n    case kEventAppFrontSwitched: {\n        struct process *process = process_manager_find_process(pm, &psn);\n        if (!process) return noErr;\n\n        event_loop_post(&g_event_loop, APPLICATION_FRONT_SWITCHED, process, 0);\n    } break;\n    }\n\n    return noErr;\n}\n#pragma clang diagnostic pop\n\nstatic void process_manager_add_running_processes(struct process_manager *pm)\n{\n    ProcessSerialNumber psn = { kNoProcess, kNoProcess };\n    while (GetNextProcess(&psn) == noErr) {\n        pid_t pid = process_pid_for_psn(psn);\n        if (process_is_being_debugged(pid)) {\n            debug(\"%s: process with pid %d is running under a debugger! ignoring..\\n\", __FUNCTION__, pid);\n            continue;\n        }\n\n        struct process *process = process_create(psn, pid);\n        if (!process) continue;\n\n        if (string_equals(process->name, \"Finder\")) {\n            debug(\"%s: %s (%d) was found! caching psn..\\n\", __FUNCTION__, process->name, process->pid);\n            pm->finder_psn = psn;\n        }\n\n        table_add(&pm->process, &process->psn, process);\n    }\n}\n\nbool process_manager_begin(struct process_manager *pm)\n{\n    pm->target = GetApplicationEventTarget();\n    pm->handler = NewEventHandlerUPP(process_handler);\n    pm->type[0].eventClass = kEventClassApplication;\n    pm->type[0].eventKind  = kEventAppLaunched;\n    pm->type[1].eventClass = kEventClassApplication;\n    pm->type[1].eventKind  = kEventAppTerminated;\n    pm->type[2].eventClass = kEventClassApplication;\n    pm->type[2].eventKind  = kEventAppFrontSwitched;\n    table_init(&pm->process, 125, hash_psn, compare_psn);\n\n    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];\n    process_manager_add_running_processes(pm);\n    [pool drain];\n\n    ProcessSerialNumber front_psn;\n    _SLPSGetFrontProcess(&front_psn);\n    GetProcessPID(&front_psn, &pm->front_pid);\n    pm->last_front_pid = pm->front_pid;\n    pm->switch_event_time = GetCurrentEventTime();\n    return InstallEventHandler(pm->target, pm->handler, 3, pm->type, pm, &pm->ref) == noErr;\n}\n#pragma clang diagnostic pop\n\nstruct process *process_manager_find_process(struct process_manager *pm, ProcessSerialNumber *psn)\n{\n    return table_find(&pm->process, psn);\n}\n\nvoid process_destroy(struct process *process)\n{\n    workspace_application_destroy_running_ns_application(g_workspace_context, process);\n    free(process->name);\n    free(process);\n}\n"
  },
  {
    "path": "src/process_manager.h",
    "content": "#ifndef PROCESS_MANAGER_H\n#define PROCESS_MANAGER_H\n\n#define PROCESS_EVENT_HANDLER(name) OSStatus name(EventHandlerCallRef ref, EventRef event, void *context)\ntypedef PROCESS_EVENT_HANDLER(process_event_handler);\n\nstruct process\n{\n    ProcessSerialNumber psn;\n    pid_t pid;\n    char *name;\n    void *ns_application;\n    int policy;\n    bool volatile terminated;\n};\n\nstruct process_manager\n{\n    struct table process;\n    EventTargetRef target;\n    EventHandlerUPP handler;\n    EventTypeSpec type[3];\n    EventHandlerRef ref;\n    pid_t front_pid;\n    pid_t last_front_pid;\n    EventTime switch_event_time;\n    ProcessSerialNumber finder_psn;\n};\n\nvoid process_destroy(struct process *process);\nstruct process *process_manager_find_process(struct process_manager *pm, ProcessSerialNumber *psn);\nbool process_manager_begin(struct process_manager *pm);\n\n#endif\n"
  },
  {
    "path": "src/rule.c",
    "content": "extern struct space_manager g_space_manager;\nextern struct window_manager g_window_manager;\n\nvoid rule_serialize(FILE *rsp, struct rule *rule, int index)\n{\n    TIME_FUNCTION;\n\n    char *app   = rule->app;\n    char *title = rule->title;\n    char *role  = rule->role;\n    char *srole = rule->subrole;\n\n    char *escaped_app   = app   ? ts_string_escape(app)   : NULL;\n    char *escaped_title = title ? ts_string_escape(title) : NULL;\n    char *escaped_role  = role  ? ts_string_escape(role)  : NULL;\n    char *escaped_srole = srole ? ts_string_escape(srole) : NULL;\n\n    fprintf(rsp,\n            \"{\\n\"\n            \"\\t\\\"index\\\":%d,\\n\"\n            \"\\t\\\"label\\\":\\\"%s\\\",\\n\"\n            \"\\t\\\"app\\\":\\\"%s\\\",\\n\"\n            \"\\t\\\"title\\\":\\\"%s\\\",\\n\"\n            \"\\t\\\"role\\\":\\\"%s\\\",\\n\"\n            \"\\t\\\"subrole\\\":\\\"%s\\\",\\n\"\n            \"\\t\\\"display\\\":%d,\\n\"\n            \"\\t\\\"space\\\":%d,\\n\"\n            \"\\t\\\"follow_space\\\":%s,\\n\"\n            \"\\t\\\"opacity\\\":%.4f,\\n\"\n            \"\\t\\\"manage\\\":%s,\\n\"\n            \"\\t\\\"sticky\\\":%s,\\n\"\n            \"\\t\\\"mouse_follows_focus\\\":%s,\\n\"\n            \"\\t\\\"sub-layer\\\":\\\"%s\\\",\\n\"\n            \"\\t\\\"native-fullscreen\\\":%s,\\n\"\n            \"\\t\\\"grid\\\":\\\"%d:%d:%d:%d:%d:%d\\\",\\n\"\n            \"\\t\\\"scratchpad\\\":\\\"%s\\\",\\n\"\n            \"\\t\\\"one-shot\\\":%s,\\n\"\n            \"\\t\\\"flags\\\":\\\"0x%08x\\\"\\n\"\n            \"}\",\n            index,\n            rule->label ? rule->label : \"\",\n            escaped_app ? escaped_app : app ? app : \"\",\n            escaped_title ? escaped_title : title ? title : \"\",\n            escaped_role ? escaped_role : role ? role : \"\",\n            escaped_srole ? escaped_srole : srole ? srole : \"\",\n            rule->effects.did ? display_manager_display_id_arrangement(rule->effects.did) : 0,\n            rule->effects.sid ? space_manager_mission_control_index(rule->effects.sid) : 0,\n            json_bool(rule_effects_check_flag(&rule->effects, RULE_FOLLOW_SPACE)),\n            rule->effects.opacity,\n            json_optional_bool(rule->effects.manage),\n            json_optional_bool(rule->effects.sticky),\n            json_optional_bool(rule->effects.mff),\n            rule_effects_check_flag(&rule->effects, RULE_LAYER) ? layer_str[rule->effects.layer] : \"\",\n            json_optional_bool(rule->effects.fullscreen),\n            rule->effects.grid[0], rule->effects.grid[1],\n            rule->effects.grid[2], rule->effects.grid[3],\n            rule->effects.grid[4], rule->effects.grid[5],\n            rule->effects.scratchpad ? rule->effects.scratchpad : \"\",\n            json_bool(rule_check_flag(rule, RULE_ONE_SHOT)),\n            (uint32_t)(rule->effects.flags << 16) | (uint32_t)rule->flags);\n}\n\nvoid rule_combine_effects(struct rule_effects *effects, struct rule_effects *result)\n{\n    if (effects->did) {\n        result->did = effects->did;\n        if (rule_effects_check_flag(effects, RULE_FOLLOW_SPACE)) {\n            rule_effects_set_flag(result, RULE_FOLLOW_SPACE);\n        } else {\n            rule_effects_clear_flag(result, RULE_FOLLOW_SPACE);\n        }\n    }\n\n    if (effects->sid) {\n        result->sid = effects->sid;\n        if (rule_effects_check_flag(effects, RULE_FOLLOW_SPACE)) {\n            rule_effects_set_flag(result, RULE_FOLLOW_SPACE);\n        } else {\n            rule_effects_clear_flag(result, RULE_FOLLOW_SPACE);\n        }\n    }\n\n    if (rule_effects_check_flag(effects, RULE_OPACITY) && in_range_ii(effects->opacity, 0.0f, 1.0f)) {\n        result->opacity = effects->opacity;\n        rule_effects_set_flag(result, RULE_OPACITY);\n    }\n\n    if (rule_effects_check_flag(effects, RULE_LAYER)) {\n        result->layer = effects->layer;\n        rule_effects_set_flag(result, RULE_LAYER);\n    }\n\n    if (effects->scratchpad) {\n        if (result->scratchpad) free(result->scratchpad);\n        result->scratchpad = string_copy(effects->scratchpad);\n    }\n\n    if (effects->manage     != RULE_PROP_UD) result->manage     = effects->manage;\n    if (effects->sticky     != RULE_PROP_UD) result->sticky     = effects->sticky;\n    if (effects->mff        != RULE_PROP_UD) result->mff        = effects->mff;\n    if (effects->fullscreen != RULE_PROP_UD) result->fullscreen = effects->fullscreen;\n\n    if (effects->grid[0] != 0 && effects->grid[1] != 0) {\n        result->grid[0] = effects->grid[0];\n        result->grid[1] = effects->grid[1];\n        result->grid[2] = effects->grid[2];\n        result->grid[3] = effects->grid[3];\n        result->grid[4] = effects->grid[4];\n        result->grid[5] = effects->grid[5];\n    }\n}\n\nvoid rule_reapply_all(void)\n{\n    table_for (struct window *window, g_window_manager.window, {\n        if (window->is_root) {\n            char *window_title = window_title_ts(window);\n            char *window_role = window_role_ts(window);\n            char *window_subrole = window_subrole_ts(window);\n\n            window_manager_apply_manage_rules_to_window(&g_space_manager, &g_window_manager, window, window_title, window_role, window_subrole, false);\n\n            if (window_manager_is_window_eligible(window)) {\n                window->is_eligible = true;\n                window_manager_apply_rules_to_window(&g_space_manager, &g_window_manager, window, window_title, window_role, window_subrole, false);\n            }\n        }\n    })\n}\n\nbool rule_reapply_by_index(int index)\n{\n    for (int i = 0; i < buf_len(g_window_manager.rules); ++i) {\n        if (i == index) {\n            if (!rule_check_flag(&g_window_manager.rules[i], RULE_ONE_SHOT)) {\n                rule_apply(&g_window_manager.rules[i]);\n            }\n            return true;\n        }\n    }\n\n    return false;\n}\n\nbool rule_reapply_by_label(char *label)\n{\n    for (int i = 0; i < buf_len(g_window_manager.rules); ++i) {\n        if (string_equals(g_window_manager.rules[i].label, label)) {\n            if (!rule_check_flag(&g_window_manager.rules[i], RULE_ONE_SHOT)) {\n                rule_apply(&g_window_manager.rules[i]);\n            }\n            return true;\n        }\n    }\n\n    return false;\n}\n\nvoid rule_apply(struct rule *rule)\n{\n    table_for (struct window *window, g_window_manager.window, {\n        if (window->is_root) {\n            if (window_manager_rule_matches_window(rule, window, window_title_ts(window), window_role_ts(window), window_subrole_ts(window))) {\n                window_manager_apply_manage_rule_effects_to_window(&g_space_manager, &g_window_manager, window, &rule->effects);\n\n                if (window_manager_is_window_eligible(window)) {\n                    window->is_eligible = true;\n                    window_manager_apply_rule_effects_to_window(&g_space_manager, &g_window_manager, window, &rule->effects);\n                }\n            }\n        }\n    })\n}\n\nvoid rule_add(struct rule *rule)\n{\n    if (rule->label) rule_remove_by_label(rule->label);\n    buf_push(g_window_manager.rules, *rule);\n}\n\nbool rule_remove_by_index(int index)\n{\n    for (int i = 0; i < buf_len(g_window_manager.rules); ++i) {\n        if (i == index) {\n            rule_destroy(&g_window_manager.rules[i]);\n            buf_del(g_window_manager.rules, i);\n            return true;\n        }\n    }\n\n    return false;\n}\n\nbool rule_remove_by_label(char *label)\n{\n    for (int i = 0; i < buf_len(g_window_manager.rules); ++i) {\n        if (string_equals(g_window_manager.rules[i].label, label)) {\n            rule_destroy(&g_window_manager.rules[i]);\n            buf_del(g_window_manager.rules, i);\n            return true;\n        }\n    }\n\n    return false;\n}\n\nvoid rule_destroy(struct rule *rule)\n{\n    if (rule_check_flag(rule, RULE_APP_VALID))     regfree(&rule->app_regex);\n    if (rule_check_flag(rule, RULE_TITLE_VALID))   regfree(&rule->title_regex);\n    if (rule_check_flag(rule, RULE_ROLE_VALID))    regfree(&rule->role_regex);\n    if (rule_check_flag(rule, RULE_SUBROLE_VALID)) regfree(&rule->subrole_regex);\n\n    if (rule->label)   free(rule->label);\n    if (rule->app)     free(rule->app);\n    if (rule->title)   free(rule->title);\n    if (rule->role)    free(rule->role);\n    if (rule->subrole) free(rule->subrole);\n\n    if (rule->effects.scratchpad) free(rule->effects.scratchpad);\n}\n"
  },
  {
    "path": "src/rule.h",
    "content": "#ifndef RULE_H\n#define RULE_H\n\n#define RULE_PROP_UD  0\n#define RULE_PROP_ON  1\n#define RULE_PROP_OFF 2\n\nenum rule_flag\n{\n    RULE_APP_VALID       = 0x001,\n    RULE_TITLE_VALID     = 0x002,\n    RULE_ROLE_VALID      = 0x004,\n    RULE_SUBROLE_VALID   = 0x008,\n    RULE_APP_EXCLUDE     = 0x010,\n    RULE_TITLE_EXCLUDE   = 0x020,\n    RULE_ROLE_EXCLUDE    = 0x040,\n    RULE_SUBROLE_EXCLUDE = 0x080,\n    RULE_ONE_SHOT        = 0x100,\n    RULE_ONE_SHOT_REMOVE = 0x200\n};\n\nenum rule_effects_flag\n{\n    RULE_FOLLOW_SPACE = 0x01,\n    RULE_OPACITY      = 0x02,\n    RULE_LAYER        = 0x04\n};\n\nstruct rule_effects\n{\n    uint32_t did;\n    uint64_t sid;\n    float opacity;\n    int manage;\n    int sticky;\n    int mff;\n    int layer;\n    int fullscreen;\n    unsigned grid[6];\n    char *scratchpad;\n    uint16_t flags;\n};\n\nstruct rule\n{\n    char *label;\n    char *app;\n    char *title;\n    char *role;\n    char *subrole;\n    regex_t app_regex;\n    regex_t title_regex;\n    regex_t role_regex;\n    regex_t subrole_regex;\n    struct rule_effects effects;\n    uint16_t flags;\n};\n\nstatic inline bool rule_check_flag(struct rule *r, enum rule_flag x) { return r->flags & x; }\nstatic inline void rule_clear_flag(struct rule *r, enum rule_flag x) { r->flags &= ~x; }\nstatic inline void rule_set_flag(struct rule *r, enum rule_flag x) { r->flags |= x; }\n\nstatic inline bool rule_effects_check_flag(struct rule_effects *e, enum rule_effects_flag x) { return e->flags & x; }\nstatic inline void rule_effects_clear_flag(struct rule_effects *e, enum rule_effects_flag x) { e->flags &= ~x; }\nstatic inline void rule_effects_set_flag(struct rule_effects *e, enum rule_effects_flag x) { e->flags |= x; }\n\nvoid rule_serialize(FILE *rsp, struct rule *rule, int index);\nvoid rule_combine_effects(struct rule_effects *rule_effects, struct rule_effects *result);\nvoid rule_reapply_all(void);\nbool rule_reapply_by_index(int index);\nbool rule_reapply_by_label(char *label);\nvoid rule_apply(struct rule *rule);\nvoid rule_add(struct rule *rule);\nbool rule_remove_by_index(int index);\nbool rule_remove_by_label(char *label);\nvoid rule_destroy(struct rule *rule);\n\n#endif\n"
  },
  {
    "path": "src/sa.h",
    "content": "#ifndef SA_H\n#define SA_H\n\nextern unsigned char __src_osax_payload[];\nextern unsigned int __src_osax_payload_len;\nextern unsigned char __src_osax_loader[];\nextern unsigned int __src_osax_loader_len;\n\nint scripting_addition_load(void);\nint scripting_addition_uninstall(void);\n\nbool scripting_addition_create_space(uint64_t sid);\nbool scripting_addition_destroy_space(uint64_t sid);\nbool scripting_addition_focus_space(uint64_t sid);\nbool scripting_addition_move_space_to_display(uint64_t src_sid, uint64_t dst_sid, uint64_t src_prev_sid, bool focus);\nbool scripting_addition_move_space_after_space(uint64_t src_sid, uint64_t dst_sid, bool focus);\nbool scripting_addition_move_window(uint32_t wid, int x, int y);\nbool scripting_addition_set_opacity(uint32_t wid, float opacity, float duration);\nbool scripting_addition_set_layer(uint32_t wid, int layer);\nbool scripting_addition_set_sticky(uint32_t wid, bool sticky);\nbool scripting_addition_set_shadow(uint32_t wid, bool shadow);\nbool scripting_addition_focus_window(uint32_t wid);\nbool scripting_addition_scale_window(uint32_t wid, float x, float y, float w, float h);\nbool scripting_addition_swap_window_proxy_in(struct window_animation *animation_list, int animation_count);\nbool scripting_addition_swap_window_proxy_out(struct window_animation *animation_list, int animation_count);\nbool scripting_addition_order_window(uint32_t a_wid, int order, uint32_t b_wid);\nbool scripting_addition_order_window_in(uint32_t *window_list, int window_count);\nbool scripting_addition_move_window_list_to_space(uint64_t sid, uint32_t *window_list, int window_count);\nbool scripting_addition_move_window_to_space(uint64_t sid, uint32_t wid);\n\n#endif\n"
  },
  {
    "path": "src/sa.m",
    "content": "#include \"sa.h\"\n\nextern int csr_get_active_config(uint32_t *config);\n#define CSR_ALLOW_UNRESTRICTED_FS 0x02\n#define CSR_ALLOW_TASK_FOR_PID    0x04\n\nextern char g_sa_socket_file[MAXLEN];\n\nstatic char osax_base_dir[MAXLEN];\nstatic char osax_contents_dir[MAXLEN];\nstatic char osax_contents_macos_dir[MAXLEN];\nstatic char osax_contents_res_dir[MAXLEN];\nstatic char osax_info_plist[MAXLEN];\nstatic char osax_payload_dir[MAXLEN];\nstatic char osax_payload_contents_dir[MAXLEN];\nstatic char osax_payload_contents_macos_dir[MAXLEN];\nstatic char osax_payload_plist[MAXLEN];\nstatic char osax_bin_payload[MAXLEN];\nstatic char osax_bin_loader[MAXLEN];\n\nstatic char sa_plist[] =\n    \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\"?>\\n\"\n    \"<!DOCTYPE plist PUBLIC \\\"-//Apple//DTD PLIST 1.0//EN\\\" \\\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\\\">\\n\"\n    \"<plist version=\\\"1.0\\\">\\n\"\n    \"<dict>\\n\"\n    \"<key>CFBundleDevelopmentRegion</key>\\n\"\n    \"<string>en</string>\\n\"\n    \"<key>CFBundleExecutable</key>\\n\"\n    \"<string>loader</string>\\n\"\n    \"<key>CFBundleIdentifier</key>\\n\"\n    \"<string>com.asmvik.yabai-osax</string>\\n\"\n    \"<key>CFBundleInfoDictionaryVersion</key>\\n\"\n    \"<string>6.0</string>\\n\"\n    \"<key>CFBundleName</key>\\n\"\n    \"<string>yabai</string>\\n\"\n    \"<key>CFBundlePackageType</key>\\n\"\n    \"<string>osax</string>\\n\"\n    \"<key>CFBundleShortVersionString</key>\\n\"\n    \"<string>\"OSAX_VERSION\"</string>\\n\"\n    \"<key>CFBundleVersion</key>\\n\"\n    \"<string>\"OSAX_VERSION\"</string>\\n\"\n    \"<key>NSHumanReadableCopyright</key>\\n\"\n    \"<string>Copyright © 2019 Åsmund Vikane. All rights reserved.</string>\\n\"\n    \"<key>OSAXHandlers</key>\\n\"\n    \"<dict>\\n\"\n    \"</dict>\\n\"\n    \"</dict>\\n\"\n    \"</plist>\";\n\nstatic char sa_bundle_plist[] =\n    \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\"?>\\n\"\n    \"<!DOCTYPE plist PUBLIC \\\"-//Apple//DTD PLIST 1.0//EN\\\" \\\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\\\">\\n\"\n    \"<plist version=\\\"1.0\\\">\\n\"\n    \"<dict>\\n\"\n    \"<key>CFBundleDevelopmentRegion</key>\\n\"\n    \"<string>en</string>\\n\"\n    \"<key>CFBundleExecutable</key>\\n\"\n    \"<string>payload</string>\\n\"\n    \"<key>CFBundleIdentifier</key>\\n\"\n    \"<string>com.asmvik.yabai-sa</string>\\n\"\n    \"<key>CFBundleInfoDictionaryVersion</key>\\n\"\n    \"<string>6.0</string>\\n\"\n    \"<key>CFBundleName</key>\\n\"\n    \"<string>payload</string>\\n\"\n    \"<key>CFBundlePackageType</key>\\n\"\n    \"<string>BNDL</string>\\n\"\n    \"<key>CFBundleShortVersionString</key>\\n\"\n    \"<string>\"OSAX_VERSION\"</string>\\n\"\n    \"<key>CFBundleVersion</key>\\n\"\n    \"<string>\"OSAX_VERSION\"</string>\\n\"\n    \"<key>NSHumanReadableCopyright</key>\\n\"\n    \"<string>Copyright © 2019 Åsmund Vikane. All rights reserved.</string>\\n\"\n    \"<key>NSPrincipalClass</key>\\n\"\n    \"<string></string>\\n\"\n    \"</dict>\\n\"\n    \"</plist>\";\n\nstatic void scripting_addition_set_path(void)\n{\n    snprintf(osax_base_dir, sizeof(osax_base_dir), \"%s\", \"/Library/ScriptingAdditions/yabai.osax\");\n\n    snprintf(osax_contents_dir, sizeof(osax_contents_dir), \"%s/%s\", osax_base_dir, \"Contents\");\n    snprintf(osax_contents_macos_dir, sizeof(osax_contents_macos_dir), \"%s/%s\", osax_contents_dir, \"MacOS\");\n    snprintf(osax_contents_res_dir, sizeof(osax_contents_res_dir), \"%s/%s\", osax_contents_dir, \"Resources\");\n    snprintf(osax_info_plist, sizeof(osax_info_plist), \"%s/%s\", osax_contents_dir, \"Info.plist\");\n\n    snprintf(osax_payload_dir, sizeof(osax_payload_dir), \"%s/%s\", osax_contents_res_dir, \"payload.bundle\");\n    snprintf(osax_payload_contents_dir, sizeof(osax_payload_contents_dir), \"%s/%s\", osax_payload_dir, \"Contents\");\n    snprintf(osax_payload_contents_macos_dir, sizeof(osax_payload_contents_macos_dir), \"%s/%s\", osax_payload_contents_dir, \"MacOS\");\n    snprintf(osax_payload_plist, sizeof(osax_payload_plist), \"%s/%s\", osax_payload_contents_dir, \"Info.plist\");\n\n    snprintf(osax_bin_loader, sizeof(osax_bin_loader), \"%s/%s\", osax_contents_macos_dir, \"loader\");\n    snprintf(osax_bin_payload, sizeof(osax_bin_payload), \"%s/%s\", osax_payload_contents_macos_dir, \"payload\");\n}\n\nstatic bool scripting_addition_create_directory(void)\n{\n    if (mkdir(osax_base_dir, 0755))                   goto err;\n    if (mkdir(osax_contents_dir, 0755))               goto err;\n    if (mkdir(osax_contents_macos_dir, 0755))         goto err;\n    if (mkdir(osax_contents_res_dir, 0755))           goto err;\n    if (mkdir(osax_payload_dir, 0755))                goto err;\n    if (mkdir(osax_payload_contents_dir, 0755))       goto err;\n    if (mkdir(osax_payload_contents_macos_dir, 0755)) goto err;\n    return true;\nerr:\n    return false;\n}\n\nstatic bool scripting_addition_write_file(char *buffer, unsigned int size, char *file, char *file_mode)\n{\n    FILE *handle = fopen(file, file_mode);\n    if (!handle) return false;\n\n    size_t bytes = fwrite(buffer, size, 1, handle);\n    bool result = bytes == 1;\n    fclose(handle);\n\n    return result;\n}\n\nstatic void scripting_addition_prepare_binaries(void)\n{\n    char cmd[MAXLEN];\n\n    snprintf(cmd, sizeof(cmd), \"%s %s\", \"chmod +x\", osax_bin_loader);\n    system(cmd);\n\n    snprintf(cmd, sizeof(cmd), \"%s %s %s\", \"codesign -f -s -\", osax_bin_loader, \"2>/dev/null\");\n    system(cmd);\n\n    snprintf(cmd, sizeof(cmd), \"%s %s\", \"chmod +x\", osax_bin_payload);\n    system(cmd);\n\n    snprintf(cmd, sizeof(cmd), \"%s %s %s\", \"codesign -f -s -\", osax_bin_payload, \"2>/dev/null\");\n    system(cmd);\n}\n\nstatic void scripting_addition_restart_dock(void)\n{\n    NSArray *dock = [NSRunningApplication runningApplicationsWithBundleIdentifier:@\"com.apple.dock\"];\n    [dock makeObjectsPerformSelector:@selector(terminate)];\n}\n\nstatic bool scripting_addition_set_socket_path(void)\n{\n    const char *sudo_uid = getenv(\"SUDO_UID\");\n\n    uid_t uid = getuid();\n    assert(uid == 0);\n\n    if (sudo_uid == NULL)                  return false;\n    if (sscanf(sudo_uid, \"%u\", &uid) != 1) return false;\n\n    struct passwd *pw = getpwuid(uid);\n    if (!pw) return false;\n\n    snprintf(g_sa_socket_file, sizeof(g_sa_socket_file), SA_SOCKET_PATH_FMT, pw->pw_name);\n    return true;\n}\n\nstatic bool scripting_addition_is_installed(void)\n{\n    if (osax_base_dir[0] == 0) scripting_addition_set_path();\n\n    DIR *dir = opendir(osax_base_dir);\n    if (!dir) return false;\n\n    closedir(dir);\n    return true;\n}\n\nstatic int scripting_addition_check(void)\n{\n    bool result = 0;\n    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];\n\n    if (scripting_addition_is_installed()) {\n        NSString *payload_path = [NSString stringWithUTF8String:osax_payload_dir];\n        NSBundle *payload_bundle = [NSBundle bundleWithPath:payload_path];\n        NSString *ns_version = [payload_bundle objectForInfoDictionaryKey:@\"CFBundleVersion\"];\n\n        bool status = string_equals([ns_version UTF8String], OSAX_VERSION);\n        result = status ? 0 : 1;\n    } else {\n        result = 1;\n    }\n\n    [pool drain];\n    return result;\n}\n\nstatic bool scripting_addition_remove(void)\n{\n    char cmd[MAXLEN];\n    snprintf(cmd, sizeof(cmd), \"%s %s %s\", \"rm -rf\", osax_base_dir, \"2>/dev/null\");\n\n    int code = system(cmd);\n    return code == 0;\n}\n\nstatic int scripting_addition_install(void)\n{\n    umask(S_IWGRP | S_IWOTH);\n\n    if ((scripting_addition_is_installed()) && (!scripting_addition_remove())) {\n        return 1;\n    }\n\n    if (!scripting_addition_create_directory()) {\n        goto cleanup;\n    }\n\n    if (!scripting_addition_write_file(sa_plist, strlen(sa_plist), osax_info_plist, \"w\")) {\n        goto cleanup;\n    }\n\n    if (!scripting_addition_write_file(sa_bundle_plist, strlen(sa_bundle_plist), osax_payload_plist, \"w\")) {\n        goto cleanup;\n    }\n\n    if (!scripting_addition_write_file((char *) __src_osax_loader, __src_osax_loader_len, osax_bin_loader, \"wb\")) {\n        goto cleanup;\n    }\n\n    if (!scripting_addition_write_file((char *) __src_osax_payload, __src_osax_payload_len, osax_bin_payload, \"wb\")) {\n        goto cleanup;\n    }\n\n    scripting_addition_prepare_binaries();\n    scripting_addition_restart_dock();\n    return 0;\n\ncleanup:\n    scripting_addition_remove();\n    return 2;\n}\n\nstatic bool scripting_addition_request_handshake(char *version, uint32_t *attrib)\n{\n    int sockfd;\n    bool result = false;\n    char rsp[BUFSIZ] = {0};\n    char bytes[SA_SOCKET_BUFF_LEN] = { 0x01, 0x00, SA_OPCODE_HANDSHAKE };\n\n    if (socket_open(&sockfd)) {\n        if (socket_connect(sockfd, g_sa_socket_file)) {\n            if (send(sockfd, bytes, 3, 0) != -1) {\n                int length = recv(sockfd, rsp, sizeof(rsp)-1, 0);\n                if (length <= 0) goto out;\n\n                char *zero = rsp;\n                while (*zero != '\\0') ++zero;\n\n                assert(*zero == '\\0');\n                memcpy(version, rsp, zero - rsp + 1);\n                memcpy(attrib, zero+1, sizeof(uint32_t));\n\n                result = true;\n            }\n        }\n\nout:\n        socket_close(sockfd);\n    }\n\n    return result;\n}\n\nstatic int scripting_addition_perform_validation(void)\n{\n    uint32_t attrib = 0;\n    char version[SA_SOCKET_BUFF_LEN] = {0};\n    bool is_latest_version_installed = scripting_addition_check() == 0;\n\n    if (!scripting_addition_request_handshake(version, &attrib)) {\n        notify(\"scripting-addition\", \"connection failed!\");\n        return 1;\n    }\n\n    if (string_equals(version, OSAX_VERSION)) {\n        if ((attrib & OSAX_ATTRIB_ALL) == OSAX_ATTRIB_ALL) {\n            notify(\"scripting-addition\", \"payload v%s\", version);\n            return 0;\n        }\n\n        notify(\"scripting-addition\", \"payload (0x%X) doesn't support this macOS version!\", attrib);\n        return 1;\n    }\n\n    if (!is_latest_version_installed) {\n        notify(\"scripting-addition\", \"payload is outdated, updating..\");\n        return scripting_addition_install();\n    }\n\n    notify(\"scripting-addition\", \"payload is outdated, restarting Dock.app..\");\n    scripting_addition_restart_dock();\n    return 0;\n}\n\nstatic bool scripting_addition_is_sip_friendly(void)\n{\n    uint32_t config = 0;\n    csr_get_active_config(&config);\n\n    if (!(config & CSR_ALLOW_UNRESTRICTED_FS)) {\n        return false;\n    }\n\n    if (!(config & CSR_ALLOW_TASK_FOR_PID)) {\n        return false;\n    }\n\n    return true;\n}\n\n#ifdef __arm64__\nstatic bool scripting_addition_is_arm64e_enabled(void)\n{\n    char bootargs[2048];\n    size_t len = sizeof(bootargs) - 1;\n\n    if (sysctlbyname(\"kern.bootargs\", bootargs, &len, NULL, 0) == 0) {\n        if (strnstr(bootargs, \"-arm64e_preview_abi\", len)) {\n            return true;\n        }\n    }\n\n    return false;\n}\n#endif\n\nstatic bool mach_loader_inject_payload(void)\n{\n    FILE *handle = popen(\"/Library/ScriptingAdditions/yabai.osax/Contents/MacOS/loader\", \"r\");\n    if (!handle) return false;\n\n    int result = pclose(handle);\n    if (WIFEXITED(result)) {\n        return WEXITSTATUS(result) == 0;\n    } else if (WIFSIGNALED(result)) {\n        return false;\n    } else if (WIFSTOPPED(result)) {\n        return false;\n    }\n\n    return false;\n}\n\nint scripting_addition_uninstall(void)\n{\n    if (!scripting_addition_is_sip_friendly()) {\n        warn(\"yabai: System Integrity Protection: Filesystem Protections and Debugging Restrictions must be disabled!\\n\");\n        notify(\"scripting-addition\", \"System Integrity Protection: Filesystem Protections and Debugging Restrictions must be disabled!\");\n        return 1;\n    }\n\n    if (!is_root()) {\n        warn(\"yabai: scripting-addition must be uninstalled as root!\\n\");\n        notify(\"scripting-addition\", \"must be uninstalled as root!\");\n        return 1;\n    }\n\n    if (!scripting_addition_is_installed()) return  0;\n    if (!scripting_addition_remove())       return -1;\n    return 0;\n}\n\nint scripting_addition_load(void)\n{\n    int result = 0;\n    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];\n\n    if (!is_root()) {\n        warn(\"yabai: scripting-addition must be loaded as root!\\n\");\n        notify(\"scripting-addition\", \"must be loaded as root!\");\n        result = 1;\n        goto out;\n    }\n\n    if (!scripting_addition_is_sip_friendly()) {\n        warn(\"yabai: System Integrity Protection: Filesystem Protections and Debugging Restrictions must be disabled!\\n\");\n        notify(\"scripting-addition\", \"System Integrity Protection: Filesystem Protections and Debugging Restrictions must be disabled!\");\n        result = 1;\n        goto out;\n    }\n\n    if (scripting_addition_check() != 0) {\n        result = scripting_addition_install();\n        goto out;\n    }\n\n#ifdef __arm64__\n    if (!scripting_addition_is_arm64e_enabled()) {\n        warn(\"yabai: missing required nvram boot-arg '-arm64e_preview_abi'!\\n\");\n        notify(\"scripting-addition\", \"missing required nvram boot-arg '-arm64e_preview_abi'!\");\n        result = 1;\n        goto out;\n    }\n#endif\n\n    if (!mach_loader_inject_payload()) {\n        warn(\"yabai: scripting-addition failed to inject payload into Dock.app!\\n\");\n        notify(\"scripting-addition\", \"failed to inject payload into Dock.app!\");\n        result = 1;\n        goto out;\n    }\n\n    if (scripting_addition_set_socket_path()) {\n        result = scripting_addition_perform_validation();\n    }\n\nout:\n    [pool drain];\n    return result;\n}\n\n#define sa_payload_init() char bytes[SA_SOCKET_BUFF_LEN]; int16_t length = 1+sizeof(length)\n#define pack(v) memcpy(bytes+length, &v, sizeof(v)); length += sizeof(v)\n#define sa_payload_send(op) *(int16_t*)bytes = length-sizeof(length), bytes[sizeof(length)] = op, scripting_addition_send_bytes(bytes, length)\n\nstatic bool scripting_addition_send_bytes(char *bytes, int length)\n{\n    int sockfd;\n    char dummy;\n    bool result = false;\n\n    if (socket_open(&sockfd)) {\n        if (socket_connect(sockfd, g_sa_socket_file)) {\n            if (send(sockfd, bytes, length, 0) != -1) {\n                recv(sockfd, &dummy, 1, 0);\n                result = true;\n            }\n        }\n\n        socket_close(sockfd);\n    }\n\n    return result;\n}\n\nbool scripting_addition_focus_space(uint64_t sid)\n{\n    sa_payload_init();\n    pack(sid);\n    return sa_payload_send(SA_OPCODE_SPACE_FOCUS);\n}\n\nbool scripting_addition_create_space(uint64_t sid)\n{\n    sa_payload_init();\n    pack(sid);\n    return sa_payload_send(SA_OPCODE_SPACE_CREATE);\n}\n\nbool scripting_addition_destroy_space(uint64_t sid)\n{\n    sa_payload_init();\n    pack(sid);\n    return sa_payload_send(SA_OPCODE_SPACE_DESTROY);\n}\n\nbool scripting_addition_move_space_to_display(uint64_t src_sid, uint64_t dst_sid, uint64_t src_prev_sid, bool focus)\n{\n    sa_payload_init();\n    pack(src_sid);\n    pack(dst_sid);\n    pack(src_prev_sid);\n    pack(focus);\n    return sa_payload_send(SA_OPCODE_SPACE_MOVE);\n}\n\nbool scripting_addition_move_space_after_space(uint64_t src_sid, uint64_t dst_sid, bool focus)\n{\n    uint64_t dummy_sid = 0;\n    sa_payload_init();\n    pack(src_sid);\n    pack(dst_sid);\n    pack(dummy_sid);\n    pack(focus);\n    return sa_payload_send(SA_OPCODE_SPACE_MOVE);\n}\n\nbool scripting_addition_move_window(uint32_t wid, int x, int y)\n{\n    sa_payload_init();\n    pack(wid);\n    pack(x);\n    pack(y);\n    return sa_payload_send(SA_OPCODE_WINDOW_MOVE);\n}\n\nbool scripting_addition_set_opacity(uint32_t wid, float opacity, float duration)\n{\n    sa_payload_init();\n    pack(wid);\n    pack(opacity);\n    pack(duration);\n    return sa_payload_send(duration > 0.0f ? SA_OPCODE_WINDOW_OPACITY_FADE : SA_OPCODE_WINDOW_OPACITY);\n}\n\nbool scripting_addition_set_layer(uint32_t wid, int layer)\n{\n    sa_payload_init();\n    pack(wid);\n    pack(layer);\n    return sa_payload_send(SA_OPCODE_WINDOW_LAYER);\n}\n\nbool scripting_addition_set_sticky(uint32_t wid, bool sticky)\n{\n    sa_payload_init();\n    pack(wid);\n    pack(sticky);\n    return sa_payload_send(SA_OPCODE_WINDOW_STICKY);\n}\n\nbool scripting_addition_set_shadow(uint32_t wid, bool shadow)\n{\n    sa_payload_init();\n    pack(wid);\n    pack(shadow);\n    return sa_payload_send(SA_OPCODE_WINDOW_SHADOW);\n}\n\nbool scripting_addition_focus_window(uint32_t wid)\n{\n    sa_payload_init();\n    pack(wid);\n    return sa_payload_send(SA_OPCODE_WINDOW_FOCUS);\n}\n\nbool scripting_addition_scale_window(uint32_t wid, float x, float y, float w, float h)\n{\n    sa_payload_init();\n    pack(wid);\n    pack(x);\n    pack(y);\n    pack(w);\n    pack(h);\n    return sa_payload_send(SA_OPCODE_WINDOW_SCALE);\n}\n\nbool scripting_addition_swap_window_proxy_in(struct window_animation *animation_list, int animation_count)\n{\n    uint32_t dummy_wid = 0;\n    sa_payload_init();\n    pack(animation_count);\n    for (int i = 0; i < animation_count; ++i) {\n        if (__atomic_load_n(&animation_list[i].skip, __ATOMIC_RELAXED)) {\n            pack(dummy_wid);\n        } else {\n            pack(animation_list[i].wid);\n            pack(animation_list[i].proxy.id);\n        }\n    }\n    return sa_payload_send(SA_OPCODE_WINDOW_SWAP_PROXY_IN);\n}\n\nbool scripting_addition_swap_window_proxy_out(struct window_animation *animation_list, int animation_count)\n{\n    uint32_t dummy_wid = 0;\n    sa_payload_init();\n    pack(animation_count);\n    for (int i = 0; i < animation_count; ++i) {\n        if (__atomic_load_n(&animation_list[i].skip, __ATOMIC_RELAXED)) {\n            pack(dummy_wid);\n        } else {\n            pack(animation_list[i].wid);\n            pack(animation_list[i].proxy.id);\n        }\n    }\n    return sa_payload_send(SA_OPCODE_WINDOW_SWAP_PROXY_OUT);\n}\n\nbool scripting_addition_order_window(uint32_t a_wid, int order, uint32_t b_wid)\n{\n    sa_payload_init();\n    pack(a_wid);\n    pack(order);\n    pack(b_wid);\n    return sa_payload_send(SA_OPCODE_WINDOW_ORDER);\n}\n\nextern int g_connection;\nbool scripting_addition_order_window_in(uint32_t *window_list, int window_count)\n{\n    uint32_t dummy_wid = 0;\n    uint8_t ordered_in = 0;\n\n    sa_payload_init();\n    pack(window_count);\n    for (int i = 0; i < window_count; ++i) {\n        SLSWindowIsOrderedIn(g_connection, window_list[i], &ordered_in);\n        if (ordered_in) {\n            pack(dummy_wid);\n        } else {\n            pack(window_list[i]);\n        }\n    }\n    return sa_payload_send(SA_OPCODE_WINDOW_ORDER_IN);\n}\n\nbool scripting_addition_move_window_list_to_space(uint64_t sid, uint32_t *window_list, int window_count)\n{\n    sa_payload_init();\n    pack(sid);\n    pack(window_count);\n    for (int i = 0; i < window_count; ++i) {\n        pack(window_list[i]);\n    }\n    return sa_payload_send(SA_OPCODE_WINDOW_LIST_TO_SPACE);\n}\n\nbool scripting_addition_move_window_to_space(uint64_t sid, uint32_t wid)\n{\n    sa_payload_init();\n    pack(sid);\n    pack(wid);\n    return sa_payload_send(SA_OPCODE_WINDOW_TO_SPACE);\n}\n\n#undef sa_payload_init\n#undef pack\n#undef sa_payload_send\n"
  },
  {
    "path": "src/space.c",
    "content": "extern int g_connection;\n\nuint32_t space_display_id(uint64_t sid)\n{\n    CFStringRef uuid_string = SLSCopyManagedDisplayForSpace(g_connection, sid);\n    if (!uuid_string) return 0;\n\n    CFUUIDRef uuid = CFUUIDCreateFromString(NULL, uuid_string);\n    uint32_t id = CGDisplayGetDisplayIDFromUUID(uuid);\n\n    CFRelease(uuid);\n    CFRelease(uuid_string);\n\n    return id;\n}\n\nuint32_t *space_window_list_for_connection(uint64_t *space_list, int space_count, int cid, int *count, bool include_minimized)\n{\n    uint32_t *window_list = NULL;\n    uint64_t set_tags = 0;\n    uint64_t clear_tags = 0;\n    uint32_t options = include_minimized ? 0x7 : 0x2;\n\n    CFArrayRef space_list_ref = cfarray_of_cfnumbers(space_list, sizeof(uint64_t), space_count, kCFNumberSInt64Type);\n    CFArrayRef window_list_ref = SLSCopyWindowsWithOptionsAndTags(g_connection, cid, space_list_ref, options, &set_tags, &clear_tags);\n    if (!window_list_ref) goto err;\n\n    *count = CFArrayGetCount(window_list_ref);\n    if (!*count) goto out;\n\n    CFTypeRef query = SLSWindowQueryWindows(g_connection, window_list_ref, *count);\n    CFTypeRef iterator = SLSWindowQueryResultCopyWindows(query);\n\n    int window_count = 0;\n    window_list = ts_alloc_list(uint32_t, *count);\n\n    while (SLSWindowIteratorAdvance(iterator)) {\n        uint64_t tags = SLSWindowIteratorGetTags(iterator);\n        uint64_t attributes = SLSWindowIteratorGetAttributes(iterator);\n        uint32_t parent_wid = SLSWindowIteratorGetParentID(iterator);\n        uint32_t wid = SLSWindowIteratorGetWindowID(iterator);\n        int level = SLSWindowIteratorGetLevel(iterator);\n\n        if (include_minimized) {\n            struct window *window = window_manager_find_window(&g_window_manager, wid);\n            if (window) {\n                window_list[window_count++] = wid;\n            } else if (parent_wid == 0) {\n                if (level == 0 || level == 3 || level == 8) {\n                    if (((attributes & 0x2) || (tags & 0x400000000000000)) && (((tags & 0x1)) || ((tags & 0x2) && (tags & 0x80000000)))) {\n                        window_list[window_count++] = wid;\n                    } else if ((attributes == 0x0 || attributes == 0x1) && ((tags & 0x1000000000000000) || (tags & 0x300000000000000)) && (((tags & 0x1)) || ((tags & 0x2) && (tags & 0x80000000)))) {\n                        window_list[window_count++] = wid;\n                    }\n                }\n            }\n        } else {\n            struct window *window = window_manager_find_window(&g_window_manager, wid);\n            if (window && !window_check_flag(window, WINDOW_MINIMIZE)) {\n                window_list[window_count++] = wid;\n            } else if (parent_wid == 0) {\n                if (level == 0 || level == 3 || level == 8) {\n                    if (((attributes & 0x2) || (tags & 0x400000000000000)) && (((tags & 0x1)) || ((tags & 0x2) && (tags & 0x80000000)))) {\n                        window_list[window_count++] = wid;\n                    }\n                }\n            }\n        }\n    }\n\n    window_list = ts_resize(window_list, sizeof(uint32_t) * *count, sizeof(uint32_t) * window_count);\n    *count = window_count;\n\n    CFRelease(query);\n    CFRelease(iterator);\nout:\n    CFRelease(window_list_ref);\nerr:\n    CFRelease(space_list_ref);\n    return window_list;\n}\n\nuint32_t *space_window_list(uint64_t sid, int *count, bool include_minimized)\n{\n    return space_window_list_for_connection(&sid, 1, 0, count, include_minimized);\n}\n\nbool space_is_user(uint64_t sid)\n{\n    return SLSSpaceGetType(g_connection, sid) == 0;\n}\n\nbool space_is_fullscreen(uint64_t sid)\n{\n    return SLSSpaceGetType(g_connection, sid) == 4;\n}\n\nbool space_is_system(uint64_t sid)\n{\n    return SLSSpaceGetType(g_connection, sid) == 2;\n}\n\nbool space_is_visible(uint64_t sid)\n{\n    return sid == display_space_id(space_display_id(sid));\n}\n"
  },
  {
    "path": "src/space.h",
    "content": "#ifndef SPACE_H\n#define SPACE_H\n\nuint32_t space_display_id(uint64_t sid);\nuint32_t *space_window_list_for_connection(uint64_t *space_list, int space_count, int cid, int *count, bool include_minimized);\nuint32_t *space_window_list(uint64_t sid, int *count, bool include_minimized);\nbool space_is_user(uint64_t sid);\nbool space_is_system(uint64_t sid);\nbool space_is_fullscreen(uint64_t sid);\nbool space_is_visible(uint64_t sid);\n\n#endif\n"
  },
  {
    "path": "src/space_manager.c",
    "content": "extern struct window_manager g_window_manager;\nextern int g_connection;\n\nstatic TABLE_HASH_FUNC(hash_view)\n{\n    return *(uint64_t *) key;\n}\n\nstatic TABLE_COMPARE_FUNC(compare_view)\n{\n    return *(uint64_t *) key_a == *(uint64_t *) key_b;\n}\n\nbool space_manager_query_space(FILE *rsp, uint64_t sid, uint64_t flags)\n{\n    TIME_FUNCTION;\n\n    struct view *view = space_manager_query_view(&g_space_manager, sid);\n    if (!view) return false;\n\n    view_serialize(rsp, view, flags);\n    fprintf(rsp, \"\\n\");\n    return true;\n}\n\nbool space_manager_query_spaces_for_window(FILE *rsp, struct window *window, uint64_t flags)\n{\n    TIME_FUNCTION;\n\n    int space_count;\n    uint64_t *space_list = window_space_list(window->id, &space_count);\n    if (!space_list) return false;\n\n    fprintf(rsp, \"[\");\n    for (int i = 0; i < space_count; ++i) {\n        struct view *view = space_manager_query_view(&g_space_manager, space_list[i]);\n        if (!view) continue;\n\n        view_serialize(rsp, view, flags);\n        fprintf(rsp, \"%c\", i < space_count - 1 ? ',' : ']');\n    }\n    fprintf(rsp, \"\\n\");\n\n    return true;\n}\n\nbool space_manager_query_spaces_for_display(FILE *rsp, uint32_t did, uint64_t flags)\n{\n    TIME_FUNCTION;\n\n    int space_count;\n    uint64_t *space_list = display_space_list(did, &space_count);\n    if (!space_list) return false;\n\n    fprintf(rsp, \"[\");\n    for (int i = 0; i < space_count; ++i) {\n        struct view *view = space_manager_query_view(&g_space_manager, space_list[i]);\n        if (!view) continue;\n\n        view_serialize(rsp, view, flags);\n        fprintf(rsp, \"%c\", i < space_count - 1 ? ',' : ']');\n    }\n    fprintf(rsp, \"\\n\");\n\n    return true;\n}\n\nbool space_manager_query_spaces_for_displays(FILE *rsp, uint64_t flags)\n{\n    TIME_FUNCTION;\n\n    int display_count;\n    uint32_t *display_list = display_manager_active_display_list(&display_count);\n    if (!display_list) return false;\n\n    fprintf(rsp, \"[\");\n    for (int i = 0; i < display_count; ++i) {\n        int space_count;\n        uint64_t *space_list = display_space_list(display_list[i], &space_count);\n        if (!space_list) continue;\n\n        for (int j = 0; j < space_count; ++j) {\n            struct view *view = space_manager_query_view(&g_space_manager, space_list[j]);\n            if (!view) continue;\n\n            view_serialize(rsp, view, flags);\n            if (j < space_count - 1) fprintf(rsp, \",\");\n        }\n\n        fprintf(rsp, \"%c\", i < display_count - 1 ? ',' : ']');\n    }\n    fprintf(rsp, \"\\n\");\n\n    return true;\n}\n\nstruct view *space_manager_query_view(struct space_manager *sm, uint64_t sid)\n{\n    if (sm->did_begin) return space_manager_find_view(sm, sid);\n    return table_find(&sm->view, &sid);\n}\n\nstruct view *space_manager_find_view(struct space_manager *sm, uint64_t sid)\n{\n    struct view *view = table_find(&sm->view, &sid);\n    if (!view) {\n        view = view_create(sid);\n        table_add(&sm->view, &sid, view);\n    }\n    return view;\n}\n\nvoid space_manager_refresh_view(struct space_manager *sm, uint64_t sid)\n{\n    struct view *view = space_manager_find_view(sm, sid);\n    if (view->layout == VIEW_FLOAT) return;\n\n    view_update(view);\n    view_flush(view);\n}\n\nvoid space_manager_mark_view_invalid(struct space_manager *sm,  uint64_t sid)\n{\n    struct view *view = space_manager_find_view(sm, sid);\n    if (view->layout == VIEW_FLOAT) return;\n\n    view_clear_flag(view, VIEW_IS_VALID);\n}\n\nvoid space_manager_untile_window(struct view *view, struct window *window)\n{\n    if (view->layout == VIEW_FLOAT) return;\n\n    window_manager_adjust_layer(window, LAYER_NORMAL);\n    struct window_node *node = view_remove_window_node(view, window);\n    if (!node) return;\n\n    if (space_is_visible(view->sid)) {\n        window_node_flush(node);\n    } else {\n        view_set_flag(view, VIEW_IS_DIRTY);\n    }\n}\n\nstruct space_label *space_manager_get_label_for_space(struct space_manager *sm, uint64_t sid)\n{\n    for (int i = 0; i < buf_len(sm->labels); ++i) {\n        struct space_label *space_label = &sm->labels[i];\n        if (space_label->sid == sid) {\n            return space_label;\n        }\n    }\n\n    return NULL;\n}\n\nstruct space_label *space_manager_get_space_for_label(struct space_manager *sm, char *label)\n{\n    for (int i = 0; i < buf_len(sm->labels); ++i) {\n        struct space_label *space_label = &sm->labels[i];\n        if (string_equals(label, space_label->label)) {\n            return space_label;\n        }\n    }\n\n    return NULL;\n}\n\nbool space_manager_remove_label_for_space(struct space_manager *sm, uint64_t sid)\n{\n    for (int i = 0; i < buf_len(sm->labels); ++i) {\n        struct space_label *space_label = &sm->labels[i];\n        if (space_label->sid == sid) {\n            free(space_label->label);\n            buf_del(sm->labels, i);\n            return true;\n        }\n    }\n\n    return false;\n}\n\nvoid space_manager_set_label_for_space(struct space_manager *sm, uint64_t sid, char *label)\n{\n    space_manager_remove_label_for_space(sm, sid);\n\n    for (int i = 0; i < buf_len(sm->labels); ++i) {\n        struct space_label *space_label = &sm->labels[i];\n        if (string_equals(space_label->label, label)) {\n            free(space_label->label);\n            buf_del(sm->labels, i);\n            break;\n        }\n    }\n\n    buf_push(sm->labels, ((struct space_label) {\n        .sid   = sid,\n        .label = label\n    }));\n}\n\nvoid space_manager_set_layout_for_space(struct space_manager *sm, uint64_t sid, enum view_type layout)\n{\n    struct view *view = space_manager_find_view(sm, sid);\n    view->layout = layout;\n    view_clear(view);\n\n    if (view->layout != VIEW_FLOAT) {\n        window_manager_validate_and_check_for_windows_on_space(sm, &g_window_manager, sid);\n    }\n}\n\nbool space_manager_set_gap_for_space(struct space_manager *sm, uint64_t sid, int type, int gap)\n{\n    struct view *view = space_manager_find_view(sm, sid);\n    if (view->layout == VIEW_FLOAT) return false;\n\n    if (type == TYPE_ABS) {\n        view->window_gap = gap;\n    } else if (type == TYPE_REL) {\n        view->window_gap = add_and_clamp_to_zero(view->window_gap, gap);\n    }\n\n    view_update(view);\n    view_flush(view);\n\n    return true;\n}\n\nbool space_manager_toggle_gap_for_space(struct space_manager *sm, uint64_t sid)\n{\n    struct view *view = space_manager_find_view(sm, sid);\n    if (view->layout == VIEW_FLOAT) return false;\n\n    if (view_check_flag(view, VIEW_ENABLE_GAP)) {\n        view_clear_flag(view, VIEW_ENABLE_GAP);\n    } else {\n        view_set_flag(view, VIEW_ENABLE_GAP);\n    }\n\n    view_update(view);\n    view_flush(view);\n\n    return true;\n}\n\nvoid space_manager_toggle_mission_control(uint64_t sid)\n{\n    space_manager_focus_space(sid);\n    CoreDockSendNotification(CFSTR(\"com.apple.expose.awake\"), 0);\n}\n\nvoid space_manager_toggle_show_desktop(uint64_t sid)\n{\n    space_manager_focus_space(sid);\n    CoreDockSendNotification(CFSTR(\"com.apple.showdesktop.awake\"), 0);\n}\n\nvoid space_manager_set_layout_for_all_spaces(struct space_manager *sm, enum view_type layout)\n{\n    sm->layout = layout;\n    table_for (struct view *view, sm->view, {\n        if (!view_check_flag(view, VIEW_LAYOUT)) {\n            if (space_is_user(view->sid)) {\n                view->layout = layout;\n                view_clear(view);\n\n                if (view->layout != VIEW_FLOAT) {\n                    window_manager_validate_and_check_for_windows_on_space(sm, &g_window_manager, view->sid);\n                }\n            }\n        }\n    })\n}\n\nvoid space_manager_set_window_gap_for_all_spaces(struct space_manager *sm, int window_gap)\n{\n    sm->window_gap = window_gap;\n    table_for (struct view *view, sm->view, {\n        if (!view_check_flag(view, VIEW_WINDOW_GAP)) {\n            view->window_gap = window_gap;\n            view_update(view);\n            view_flush(view);\n        }\n    })\n}\n\nvoid space_manager_set_top_padding_for_all_spaces(struct space_manager *sm, int top_padding)\n{\n    sm->top_padding = top_padding;\n    table_for (struct view *view, sm->view, {\n        if (!view_check_flag(view, VIEW_TOP_PADDING)) {\n            view->top_padding = top_padding;\n            view_update(view);\n            view_flush(view);\n        }\n    })\n}\n\nvoid space_manager_set_bottom_padding_for_all_spaces(struct space_manager *sm, int bottom_padding)\n{\n    sm->bottom_padding = bottom_padding;\n    table_for (struct view *view, sm->view, {\n        if (!view_check_flag(view, VIEW_BOTTOM_PADDING)) {\n            view->bottom_padding = bottom_padding;\n            view_update(view);\n            view_flush(view);\n        }\n    })\n}\n\nvoid space_manager_set_left_padding_for_all_spaces(struct space_manager *sm, int left_padding)\n{\n    sm->left_padding = left_padding;\n    table_for (struct view *view, sm->view, {\n        if (!view_check_flag(view, VIEW_LEFT_PADDING)) {\n            view->left_padding = left_padding;\n            view_update(view);\n            view_flush(view);\n        }\n    })\n}\n\nvoid space_manager_set_right_padding_for_all_spaces(struct space_manager *sm, int right_padding)\n{\n    sm->right_padding = right_padding;\n    table_for (struct view *view, sm->view, {\n        if (!view_check_flag(view, VIEW_RIGHT_PADDING)) {\n            view->right_padding = right_padding;\n            view_update(view);\n            view_flush(view);\n        }\n    })\n}\n\nvoid space_manager_set_split_type_for_all_spaces(struct space_manager *sm, enum window_node_split split_type)\n{\n    sm->split_type = split_type;\n    table_for (struct view *view, sm->view, {\n        if (!view_check_flag(view, VIEW_SPLIT_TYPE)) {\n            view->split_type = split_type;\n        }\n    })\n}\n\nvoid space_manager_set_auto_balance_for_all_spaces(struct space_manager *sm, uint32_t auto_balance)\n{\n    sm->auto_balance = auto_balance;\n    table_for (struct view *view, sm->view, {\n        if (!view_check_flag(view, VIEW_AUTO_BALANCE)) {\n            view->auto_balance = auto_balance;\n        }\n    })\n}\n\nbool space_manager_set_padding_for_space(struct space_manager *sm, uint64_t sid, int type, int top, int bottom, int left, int right)\n{\n    struct view *view = space_manager_find_view(sm, sid);\n    if (view->layout == VIEW_FLOAT) return false;\n\n    if (type == TYPE_ABS) {\n        view->top_padding    = top;\n        view->bottom_padding = bottom;\n        view->left_padding   = left;\n        view->right_padding  = right;\n    } else if (type == TYPE_REL) {\n        view->top_padding    = add_and_clamp_to_zero(view->top_padding, top);\n        view->bottom_padding = add_and_clamp_to_zero(view->bottom_padding, bottom);\n        view->left_padding   = add_and_clamp_to_zero(view->left_padding, left);\n        view->right_padding  = add_and_clamp_to_zero(view->right_padding, right);\n    }\n\n    view_update(view);\n    view_flush(view);\n\n    return true;\n}\n\nbool space_manager_toggle_padding_for_space(struct space_manager *sm, uint64_t sid)\n{\n    struct view *view = space_manager_find_view(sm, sid);\n    if (view->layout == VIEW_FLOAT) return false;\n\n    if (view_check_flag(view, VIEW_ENABLE_PADDING)) {\n        view_clear_flag(view, VIEW_ENABLE_PADDING);\n    } else {\n        view_set_flag(view, VIEW_ENABLE_PADDING);\n    }\n\n    view_update(view);\n    view_flush(view);\n\n    return true;\n}\n\nbool space_manager_rotate_space(struct space_manager *sm, uint64_t sid, int degrees)\n{\n    struct view *view = space_manager_find_view(sm, sid);\n    if (view->layout != VIEW_BSP) return false;\n\n    window_node_rotate(view->root, degrees);\n    view_update(view);\n    view_flush(view);\n\n    return true;\n}\n\nbool space_manager_mirror_space(struct space_manager *sm, uint64_t sid, enum window_node_split axis)\n{\n    struct view *view = space_manager_find_view(sm, sid);\n    if (view->layout != VIEW_BSP) return false;\n\n    window_node_mirror(view->root, axis);\n    view_update(view);\n    view_flush(view);\n\n    return true;\n}\n\nbool space_manager_equalize_space(struct space_manager *sm, uint64_t sid, uint32_t axis_flag)\n{\n    struct view *view = space_manager_find_view(sm, sid);\n    if (view->layout != VIEW_BSP) return false;\n\n    window_node_equalize(view->root, axis_flag);\n    view_update(view);\n    view_flush(view);\n\n    return true;\n}\n\nbool space_manager_balance_space(struct space_manager *sm, uint64_t sid, uint32_t axis_flag)\n{\n    struct view *view = space_manager_find_view(sm, sid);\n    if (view->layout != VIEW_BSP) return false;\n\n    window_node_balance(view->root, axis_flag);\n    view_update(view);\n    view_flush(view);\n\n    return true;\n}\n\nstruct view *space_manager_tile_window_on_space_with_insertion_point(struct space_manager *sm, struct window *window, uint64_t sid, uint32_t insertion_point)\n{\n    struct view *view = space_manager_find_view(sm, sid);\n    if (view->layout == VIEW_FLOAT) return view;\n\n    window_manager_adjust_layer(window, LAYER_BELOW);\n    struct window_node *node = view_add_window_node_with_insertion_point(view, window, insertion_point);\n    assert(node);\n\n    if (space_is_visible(view->sid)) {\n        window_node_flush(node);\n    } else {\n        view_set_flag(view, VIEW_IS_DIRTY);\n    }\n\n    return view;\n}\n\nstruct view *space_manager_tile_window_on_space(struct space_manager *sm, struct window *window, uint64_t sid)\n{\n    return space_manager_tile_window_on_space_with_insertion_point(sm, window, sid, 0);\n}\n\nvoid space_manager_toggle_window_split(struct space_manager *sm, struct window *window)\n{\n    struct view *view = space_manager_find_view(sm, window_space(window->id));\n    if (view->layout != VIEW_BSP) return;\n\n    struct window_node *node = view_find_window_node(view, window->id);\n    if (node && window_node_is_intermediate(node)) {\n        node->parent->split = node->parent->split == SPLIT_Y ? SPLIT_X : SPLIT_Y;\n\n        if (view->auto_balance != SPLIT_NONE) {\n            window_node_balance(view->root, view->auto_balance);\n            view_update(view);\n            view_flush(view);\n        } else {\n            window_node_update(view, node->parent);\n            if (space_is_visible(view->sid)) {\n                window_node_flush(node->parent);\n            } else {\n                view_set_flag(view, VIEW_IS_DIRTY);\n            }\n        }\n    }\n}\n\nint space_manager_mission_control_index(uint64_t sid)\n{\n    uint64_t result = 0;\n    int desktop_cnt = 1;\n\n    CFArrayRef display_spaces_ref = SLSCopyManagedDisplaySpaces(g_connection);\n    int display_spaces_count = CFArrayGetCount(display_spaces_ref);\n\n    for (int i = 0; i < display_spaces_count; ++i) {\n        CFDictionaryRef display_ref = CFArrayGetValueAtIndex(display_spaces_ref, i);\n        CFArrayRef spaces_ref = CFDictionaryGetValue(display_ref, CFSTR(\"Spaces\"));\n        int spaces_count = CFArrayGetCount(spaces_ref);\n\n        for (int j = 0; j < spaces_count; ++j) {\n            CFDictionaryRef space_ref = CFArrayGetValueAtIndex(spaces_ref, j);\n            CFNumberRef sid_ref = CFDictionaryGetValue(space_ref, CFSTR(\"id64\"));\n            CFNumberGetValue(sid_ref, CFNumberGetType(sid_ref), &result);\n            if (sid == result) goto out;\n\n            ++desktop_cnt;\n        }\n    }\n\n    desktop_cnt = 0;\nout:\n    CFRelease(display_spaces_ref);\n    return desktop_cnt;\n}\n\nuint64_t space_manager_mission_control_space(int desktop_id)\n{\n    uint64_t result = 0;\n    int desktop_cnt = 1;\n\n    CFArrayRef display_spaces_ref = SLSCopyManagedDisplaySpaces(g_connection);\n    int display_spaces_count = CFArrayGetCount(display_spaces_ref);\n\n    for (int i = 0; i < display_spaces_count; ++i) {\n        CFDictionaryRef display_ref = CFArrayGetValueAtIndex(display_spaces_ref, i);\n        CFArrayRef spaces_ref = CFDictionaryGetValue(display_ref, CFSTR(\"Spaces\"));\n        int spaces_count = CFArrayGetCount(spaces_ref);\n\n        for (int j = 0; j < spaces_count; ++j) {\n            CFDictionaryRef space_ref = CFArrayGetValueAtIndex(spaces_ref, j);\n            CFNumberRef sid_ref = CFDictionaryGetValue(space_ref, CFSTR(\"id64\"));\n            CFNumberGetValue(sid_ref, CFNumberGetType(sid_ref), &result);\n            if (desktop_cnt == desktop_id) goto out;\n\n            ++desktop_cnt;\n        }\n    }\n\n    result = 0;\nout:\n    CFRelease(display_spaces_ref);\n    return result;\n}\n\nuint64_t space_manager_cursor_space(void)\n{\n    uint32_t did = display_manager_cursor_display_id();\n    return display_space_id(did);\n}\n\nuint64_t space_manager_prev_space(uint64_t sid)\n{\n    uint64_t p_sid = 0;\n    uint64_t n_sid = 0;\n\n    CFArrayRef display_spaces_ref = SLSCopyManagedDisplaySpaces(g_connection);\n    int display_spaces_count = CFArrayGetCount(display_spaces_ref);\n\n    for (int i = 0; i < display_spaces_count; ++i) {\n        CFDictionaryRef display_ref = CFArrayGetValueAtIndex(display_spaces_ref, i);\n        CFArrayRef spaces_ref = CFDictionaryGetValue(display_ref, CFSTR(\"Spaces\"));\n        int spaces_count = CFArrayGetCount(spaces_ref);\n\n        for (int j = 0; j < spaces_count; ++j) {\n            CFDictionaryRef space_ref = CFArrayGetValueAtIndex(spaces_ref, j);\n            CFNumberRef sid_ref = CFDictionaryGetValue(space_ref, CFSTR(\"id64\"));\n            CFNumberGetValue(sid_ref, CFNumberGetType(sid_ref), &n_sid);\n            if (n_sid == sid) goto out;\n\n            p_sid = n_sid;\n        }\n    }\n\nout:\n    CFRelease(display_spaces_ref);\n    return p_sid != sid ? p_sid : 0;\n}\n\nuint64_t space_manager_next_space(uint64_t sid)\n{\n    uint64_t n_sid = 0;\n    bool found_sid = false;\n\n    CFArrayRef display_spaces_ref = SLSCopyManagedDisplaySpaces(g_connection);\n    int display_spaces_count = CFArrayGetCount(display_spaces_ref);\n\n    for (int i = 0; i < display_spaces_count; ++i) {\n        CFDictionaryRef display_ref = CFArrayGetValueAtIndex(display_spaces_ref, i);\n        CFArrayRef spaces_ref = CFDictionaryGetValue(display_ref, CFSTR(\"Spaces\"));\n        int spaces_count = CFArrayGetCount(spaces_ref);\n\n        for (int j = 0; j < spaces_count; ++j) {\n            CFDictionaryRef space_ref = CFArrayGetValueAtIndex(spaces_ref, j);\n            CFNumberRef sid_ref = CFDictionaryGetValue(space_ref, CFSTR(\"id64\"));\n            CFNumberGetValue(sid_ref, CFNumberGetType(sid_ref), &n_sid);\n            if (found_sid) goto out;\n\n            found_sid = n_sid == sid;\n        }\n    }\n\nout:\n    CFRelease(display_spaces_ref);\n    return n_sid != sid ? n_sid : 0;\n}\n\nuint64_t space_manager_first_space(void)\n{\n    uint64_t sid = 0;\n\n    CFArrayRef display_spaces_ref = SLSCopyManagedDisplaySpaces(g_connection);\n    CFDictionaryRef display_ref = CFArrayGetValueAtIndex(display_spaces_ref, 0);\n    CFArrayRef spaces_ref = CFDictionaryGetValue(display_ref, CFSTR(\"Spaces\"));\n\n    CFDictionaryRef space_ref = CFArrayGetValueAtIndex(spaces_ref, 0);\n    CFNumberRef sid_ref = CFDictionaryGetValue(space_ref, CFSTR(\"id64\"));\n    CFNumberGetValue(sid_ref, CFNumberGetType(sid_ref), &sid);\n\n    CFRelease(display_spaces_ref);\n    return sid;\n}\n\nuint64_t space_manager_last_space(void)\n{\n    uint64_t sid = 0;\n\n    CFArrayRef display_spaces_ref = SLSCopyManagedDisplaySpaces(g_connection);\n    int display_spaces_count = CFArrayGetCount(display_spaces_ref);\n\n    CFDictionaryRef display_ref = CFArrayGetValueAtIndex(display_spaces_ref, display_spaces_count-1);\n    CFArrayRef spaces_ref = CFDictionaryGetValue(display_ref, CFSTR(\"Spaces\"));\n    int spaces_count = CFArrayGetCount(spaces_ref);\n\n    CFDictionaryRef space_ref = CFArrayGetValueAtIndex(spaces_ref, spaces_count-1);\n    CFNumberRef sid_ref = CFDictionaryGetValue(space_ref, CFSTR(\"id64\"));\n    CFNumberGetValue(sid_ref, CFNumberGetType(sid_ref), &sid);\n\n    CFRelease(display_spaces_ref);\n    return sid;\n}\n\nuint64_t space_manager_active_space(void)\n{\n    uint32_t did = 0;\n    struct window *window = window_manager_focused_window(&g_window_manager);\n\n    if (window) did = window_display_id(window->id);\n    if (!did)   did = display_manager_active_display_id();\n    if (!did)   return 0;\n\n    return display_space_id(did);\n}\n\nvoid space_manager_move_window_list_to_space(uint64_t sid, uint32_t *window_list, int window_count)\n{\n    if (!workspace_use_macos_space_workaround()) {\n        CFArrayRef window_list_ref = cfarray_of_cfnumbers(window_list, sizeof(uint32_t), window_count, kCFNumberSInt32Type);\n        SLSMoveWindowsToManagedSpace(g_connection, window_list_ref, sid);\n        CFRelease(window_list_ref);\n    } else if (!scripting_addition_move_window_list_to_space(sid, window_list, window_count)) {\n        SLSSpaceSetCompatID(g_connection, sid, 0x79616265);\n        SLSSetWindowListWorkspace(g_connection, window_list, window_count, 0x79616265);\n        SLSSpaceSetCompatID(g_connection, sid, 0x0);\n    }\n}\n\nvoid space_manager_move_window_to_space(uint64_t sid, struct window *window)\n{\n    if (!workspace_use_macos_space_workaround()) {\n        CFArrayRef window_list_ref = cfarray_of_cfnumbers(&window->id, sizeof(uint32_t), 1, kCFNumberSInt32Type);\n        SLSMoveWindowsToManagedSpace(g_connection, window_list_ref, sid);\n        CFRelease(window_list_ref);\n    } else if (!scripting_addition_move_window_to_space(sid, window->id)) {\n        SLSSpaceSetCompatID(g_connection, sid, 0x79616265);\n        SLSSetWindowListWorkspace(g_connection, &window->id, 1, 0x79616265);\n        SLSSpaceSetCompatID(g_connection, sid, 0x0);\n    }\n}\n\nstatic inline uint64_t space_manager_find_first_user_space_for_display(uint32_t did)\n{\n    int count;\n    uint64_t *space_list = display_space_list(did, &count);\n    if (!space_list) return 0;\n\n    for (int i = 0; i < count; ++i) {\n        uint64_t sid = space_list[i];\n\n        if (space_is_user(sid)) {\n            return sid;\n        }\n    }\n\n    return 0;\n}\n\nstatic inline bool space_manager_is_space_last_user_space(uint64_t sid)\n{\n    bool result = true;\n\n    int count;\n    uint64_t *space_list = display_space_list(space_display_id(sid), &count);\n    if (!space_list) return true;\n\n    for (int i = 0; i < count; ++i) {\n        uint64_t c_sid = space_list[i];\n        if (sid == c_sid) continue;\n\n        if (space_is_user(c_sid)) {\n            result = false;\n            break;\n        }\n    }\n\n    return result;\n}\n\nstatic enum space_op_error space_manager_swap_space_with_space_on_display(uint32_t a_did, uint64_t a_sid, uint32_t b_did, uint64_t b_sid)\n{\n    if (display_manager_display_is_animating(a_did)) return SPACE_OP_ERROR_DISPLAY_IS_ANIMATING;\n    if (display_manager_display_is_animating(b_did)) return SPACE_OP_ERROR_DISPLAY_IS_ANIMATING;\n\n    float window_animation_duration = g_window_manager.window_animation_duration;\n    g_window_manager.window_animation_duration = 0.0f;\n    __asm__ __volatile__ (\"\" ::: \"memory\");\n\n    int a_window_list_count = 0;\n    uint32_t *a_window_list = space_window_list(a_sid, &a_window_list_count, true);\n\n    int b_window_list_count = 0;\n    uint32_t *b_window_list = space_window_list(b_sid, &b_window_list_count, true);\n\n    struct view *a_view = table_find(&g_space_manager.view, &a_sid);\n    struct view *b_view = table_find(&g_space_manager.view, &b_sid);\n\n    table_remove(&g_space_manager.view, &a_sid);\n    table_remove(&g_space_manager.view, &b_sid);\n\n    a_view->sid = b_sid;\n    b_view->sid = a_sid;\n\n    CFStringRef tmp = a_view->uuid;\n    a_view->uuid    = b_view->uuid;\n    b_view->uuid    = tmp;\n\n    table_add(&g_space_manager.view, &a_sid, b_view);\n    table_add(&g_space_manager.view, &b_sid, a_view);\n\n    if (a_window_list_count) {\n        space_manager_move_window_list_to_space(b_sid, a_window_list, a_window_list_count);\n    }\n\n    if (b_window_list_count) {\n        space_manager_move_window_list_to_space(a_sid, b_window_list, b_window_list_count);\n    }\n\n    for (int i = 0; i < buf_len(g_space_manager.labels); ++i) {\n        struct space_label *label = &g_space_manager.labels[i];\n        if      (label->sid == a_sid) label->sid = b_sid;\n        else if (label->sid == b_sid) label->sid = a_sid;\n    }\n\n    view_update(a_view);\n    view_update(b_view);\n\n    view_flush(a_view);\n    view_flush(b_view);\n\n    __asm__ __volatile__ (\"\" ::: \"memory\");\n    g_window_manager.window_animation_duration = window_animation_duration;\n    return SPACE_OP_ERROR_SUCCESS;\n}\n\nenum space_op_error space_manager_swap_space_with_space(uint64_t acting_sid, uint64_t selector_sid)\n{\n    bool is_in_mc = mission_control_is_active();\n    if (is_in_mc) return SPACE_OP_ERROR_IN_MISSION_CONTROL;\n\n    uint32_t acting_did = space_display_id(acting_sid);\n    uint32_t selector_did = space_display_id(selector_sid);\n\n    if (acting_sid == selector_sid) return SPACE_OP_ERROR_SAME_SPACE;\n    if (acting_did != selector_did) return space_manager_swap_space_with_space_on_display(acting_did, acting_sid, selector_did, selector_sid);\n\n    bool is_animating = display_manager_display_is_animating(acting_did);\n    if (is_animating) return SPACE_OP_ERROR_DISPLAY_IS_ANIMATING;\n\n    uint64_t acting_prev_sid = space_manager_prev_space(acting_sid);\n    uint64_t selector_prev_sid = space_manager_prev_space(selector_sid);\n\n    uint32_t acting_prev_did = acting_prev_sid ? space_display_id(acting_prev_sid) : 0;\n    uint32_t selector_prev_did = selector_prev_sid ? space_display_id(selector_prev_sid) : 0;\n\n    bool acting_sid_is_first = !acting_prev_sid || acting_prev_did != acting_did;\n    bool selector_sid_is_first = !selector_prev_sid || selector_prev_did != selector_did;\n\n    int acting_mci = space_manager_mission_control_index(acting_sid);\n    int selector_mci = space_manager_mission_control_index(selector_sid);\n    bool success = true;\n\n    if (acting_sid_is_first && !selector_sid_is_first && selector_mci - acting_mci == 1) {\n        success = scripting_addition_move_space_after_space(acting_sid, selector_sid, acting_sid == space_manager_active_space());\n    } else if (!acting_sid_is_first && selector_sid_is_first && acting_mci - selector_mci == 1) {\n        success = scripting_addition_move_space_after_space(selector_sid, acting_sid, selector_sid == space_manager_active_space());\n    } else if (acting_sid_is_first && !selector_sid_is_first) {\n        success  = scripting_addition_move_space_after_space(selector_sid, acting_sid, false);\n        success &= scripting_addition_move_space_after_space(acting_sid, selector_prev_sid, acting_sid == space_manager_active_space());\n    } else if (!acting_sid_is_first && selector_sid_is_first) {\n        success  = scripting_addition_move_space_after_space(acting_sid, selector_sid, acting_sid == space_manager_active_space());\n        success &= scripting_addition_move_space_after_space(selector_sid, acting_prev_sid, false);\n    } else if (!acting_sid_is_first && !selector_sid_is_first) {\n        if (acting_mci > selector_mci) {\n            success  = scripting_addition_move_space_after_space(selector_sid, acting_sid, false);\n            success &= scripting_addition_move_space_after_space(acting_sid, selector_prev_sid, acting_sid == space_manager_active_space());\n        } else {\n            success  = scripting_addition_move_space_after_space(acting_sid, selector_sid, acting_sid == space_manager_active_space());\n            success &= scripting_addition_move_space_after_space(selector_sid, acting_prev_sid, false);\n        }\n    }\n\n    return success ? SPACE_OP_ERROR_SUCCESS : SPACE_OP_ERROR_SCRIPTING_ADDITION;\n}\n\nenum space_op_error space_manager_move_space_to_space(uint64_t acting_sid, uint64_t selector_sid)\n{\n    bool is_in_mc = mission_control_is_active();\n    if (is_in_mc) return SPACE_OP_ERROR_IN_MISSION_CONTROL;\n\n    uint32_t acting_did = space_display_id(acting_sid);\n    uint32_t selector_did = space_display_id(selector_sid);\n\n    if (acting_sid == selector_sid) return SPACE_OP_ERROR_SAME_SPACE;\n    if (acting_did != selector_did) return SPACE_OP_ERROR_SAME_DISPLAY;\n\n    bool is_animating = display_manager_display_is_animating(acting_did);\n    if (is_animating) return SPACE_OP_ERROR_DISPLAY_IS_ANIMATING;\n\n    uint64_t acting_prev_sid = space_manager_prev_space(acting_sid);\n    uint64_t selector_prev_sid = space_manager_prev_space(selector_sid);\n\n    uint32_t acting_prev_did = acting_prev_sid ? space_display_id(acting_prev_sid) : 0;\n    uint32_t selector_prev_did = selector_prev_sid ? space_display_id(selector_prev_sid) : 0;\n\n    bool acting_sid_is_first = !acting_prev_sid || acting_prev_did != acting_did;\n    bool selector_sid_is_first = !selector_prev_sid || selector_prev_did != selector_did;\n    bool success = true;\n\n    if (acting_sid_is_first && !selector_sid_is_first) {\n        success = scripting_addition_move_space_after_space(acting_sid, selector_sid, acting_sid == space_manager_active_space());\n    } else if (!acting_sid_is_first && selector_sid_is_first) {\n        success  = scripting_addition_move_space_after_space(acting_sid, selector_sid, acting_sid == space_manager_active_space());\n        success &= scripting_addition_move_space_after_space(selector_sid, acting_sid, false);\n    } else if (!acting_sid_is_first && !selector_sid_is_first) {\n        if (space_manager_mission_control_index(acting_sid) > space_manager_mission_control_index(selector_sid)) {\n            success = scripting_addition_move_space_after_space(acting_sid, selector_prev_sid, acting_sid == space_manager_active_space());\n        } else {\n            success = scripting_addition_move_space_after_space(acting_sid, selector_sid, acting_sid == space_manager_active_space());\n        }\n    }\n\n    return success ? SPACE_OP_ERROR_SUCCESS : SPACE_OP_ERROR_SCRIPTING_ADDITION;\n}\n\nenum space_op_error space_manager_move_space_to_display(struct space_manager *sm, uint64_t sid, uint32_t did)\n{\n    bool is_in_mc = mission_control_is_active();\n    if (is_in_mc) return SPACE_OP_ERROR_IN_MISSION_CONTROL;\n    if (!sid)     return SPACE_OP_ERROR_MISSING_SRC;\n\n    uint32_t s_did = space_display_id(sid);\n    if (s_did == did) return SPACE_OP_ERROR_INVALID_DST;\n\n    bool is_src_animating = display_manager_display_is_animating(s_did);\n    if (is_src_animating) return SPACE_OP_ERROR_DISPLAY_IS_ANIMATING;\n\n    bool last_space = space_manager_is_space_last_user_space(sid);\n    if (last_space) return SPACE_OP_ERROR_INVALID_SRC;\n\n    bool is_dst_animating = display_manager_display_is_animating(did);\n    if (is_dst_animating) return SPACE_OP_ERROR_DISPLAY_IS_ANIMATING;\n\n    uint64_t d_sid = display_space_id(did);\n    if (!d_sid) return SPACE_OP_ERROR_MISSING_DST;\n\n    bool focus_space = sid == space_manager_active_space();\n\n    if (scripting_addition_move_space_to_display(sid, d_sid,  focus_space ? space_manager_prev_space(sid) : 0, focus_space ? 1 : 0)) {\n        space_manager_mark_view_invalid(sm, sid);\n        if (focus_space) {\n            space_manager_focus_space(sid);\n        }\n        return SPACE_OP_ERROR_SUCCESS;\n    }\n\n    return SPACE_OP_ERROR_SCRIPTING_ADDITION;\n}\n\nenum space_op_error space_manager_focus_space(uint64_t sid)\n{\n    bool is_in_mc = mission_control_is_active();\n    if (is_in_mc) return SPACE_OP_ERROR_IN_MISSION_CONTROL;\n\n    uint64_t cur_sid = space_manager_active_space();\n    if (cur_sid == sid) return SPACE_OP_ERROR_SAME_SPACE;\n\n    uint32_t cur_did = space_display_id(cur_sid);\n    uint32_t new_did = space_display_id(sid);\n    bool focus_display = cur_did != new_did;\n\n    bool is_animating = display_manager_display_is_animating(new_did);\n    if (is_animating) return SPACE_OP_ERROR_DISPLAY_IS_ANIMATING;\n\n    if (scripting_addition_focus_space(sid)) {\n        if (focus_display) {\n            display_manager_focus_display(new_did, sid);\n        }\n    } else {\n        return SPACE_OP_ERROR_SCRIPTING_ADDITION;\n    }\n\n    return SPACE_OP_ERROR_SUCCESS;\n}\n\nenum space_op_error space_manager_switch_space(uint64_t sid)\n{\n    bool is_in_mc = mission_control_is_active();\n    if (is_in_mc) return SPACE_OP_ERROR_IN_MISSION_CONTROL;\n\n    uint64_t cur_sid = space_manager_active_space();\n    if (cur_sid == sid) return SPACE_OP_ERROR_SAME_SPACE;\n\n    uint32_t cur_did = space_display_id(cur_sid);\n    uint32_t did     = space_display_id(sid);\n\n    bool is_src_animating = display_manager_display_is_animating(cur_did);\n    if (is_src_animating) return SPACE_OP_ERROR_DISPLAY_IS_ANIMATING;\n\n    bool is_dst_animating = display_manager_display_is_animating(did);\n    if (is_dst_animating) return SPACE_OP_ERROR_DISPLAY_IS_ANIMATING;\n\n    if (cur_did != did) {\n        space_manager_swap_space_with_space_on_display(cur_did, cur_sid, did, sid);\n        display_manager_focus_display(cur_did, cur_sid);\n        return SPACE_OP_ERROR_SUCCESS;\n    }\n\n    return scripting_addition_focus_space(sid) ? SPACE_OP_ERROR_SUCCESS : SPACE_OP_ERROR_SCRIPTING_ADDITION;\n}\n\nenum space_op_error space_manager_destroy_space(uint64_t sid)\n{\n    bool is_in_mc = mission_control_is_active();\n    if (is_in_mc) return SPACE_OP_ERROR_IN_MISSION_CONTROL;\n\n    if (!sid) return SPACE_OP_ERROR_MISSING_SRC;\n    if (!space_is_user(sid)) return SPACE_OP_ERROR_INVALID_TYPE;\n    if (space_manager_is_space_last_user_space(sid)) return SPACE_OP_ERROR_INVALID_SRC;\n\n    uint32_t did = space_display_id(sid);\n    uint64_t first_sid = space_manager_find_first_user_space_for_display(did);\n\n    bool is_animating = display_manager_display_is_animating(did);\n    if (is_animating) return SPACE_OP_ERROR_DISPLAY_IS_ANIMATING;\n\n    bool success = scripting_addition_destroy_space(sid);\n    if (!success) return SPACE_OP_ERROR_SCRIPTING_ADDITION;\n\n    if (first_sid) {\n        window_manager_validate_and_check_for_windows_on_space(&g_space_manager, &g_window_manager, first_sid);\n    }\n\n    return SPACE_OP_ERROR_SUCCESS;\n}\n\nenum space_op_error space_manager_add_space(uint64_t sid)\n{\n    bool is_in_mc = mission_control_is_active();\n    if (is_in_mc) return SPACE_OP_ERROR_IN_MISSION_CONTROL;\n    if (!sid)     return SPACE_OP_ERROR_MISSING_SRC;\n\n    bool is_animating = display_manager_display_is_animating(space_display_id(sid));\n    if (is_animating) return SPACE_OP_ERROR_DISPLAY_IS_ANIMATING;\n\n    return scripting_addition_create_space(sid) ? SPACE_OP_ERROR_SUCCESS : SPACE_OP_ERROR_SCRIPTING_ADDITION;\n}\n\nvoid space_manager_assign_process_to_space(pid_t pid, uint64_t sid)\n{\n    SLSProcessAssignToSpace(g_connection, pid, sid);\n}\n\nvoid space_manager_assign_process_to_all_spaces(pid_t pid)\n{\n    SLSProcessAssignToAllSpaces(g_connection, pid);\n}\n\nbool space_manager_is_window_on_active_space(struct window *window)\n{\n    uint64_t sid = space_manager_active_space();\n    bool result = space_manager_is_window_on_space(sid, window);\n    return result;\n}\n\nbool space_manager_is_window_on_space(uint64_t sid, struct window *window)\n{\n    int space_count;\n    uint64_t *space_list = window_space_list(window->id, &space_count);\n    if (!space_list) return false;\n\n    for (int i = 0; i < space_count; ++i) {\n        if (sid == space_list[i]) {\n            return true;\n        }\n    }\n\n    return false;\n}\n\nvoid space_manager_mark_spaces_invalid_for_display(struct space_manager *sm, uint32_t did)\n{\n    int space_count;\n    uint64_t *space_list = display_space_list(did, &space_count);\n    if (!space_list) return;\n\n    uint64_t sid = display_space_id(did);\n    for (int i = 0; i < space_count; ++i) {\n        if (space_list[i] == sid) {\n            space_manager_refresh_view(sm, sid);\n        } else {\n            space_manager_mark_view_invalid(sm, space_list[i]);\n        }\n    }\n}\n\nvoid space_manager_mark_spaces_invalid(struct space_manager *sm)\n{\n    int display_count;\n    uint32_t *display_list = display_manager_active_display_list(&display_count);\n    if (!display_list) return;\n\n    for (int i = 0; i < display_count; ++i) {\n        space_manager_mark_spaces_invalid_for_display(sm, display_list[i]);\n    }\n}\n\nbool space_manager_refresh_application_windows(struct space_manager *sm)\n{\n    int refresh_count = buf_len(g_window_manager.applications_to_refresh);\n    if (!refresh_count) return false;\n    int window_count = g_window_manager.window.count;\n    for (int i = 0; i < refresh_count; ++i) {\n        struct application *application = g_window_manager.applications_to_refresh[i];\n        debug(\"%s: %s has windows that are not yet resolved\\n\", __FUNCTION__, application->name);\n        bool result = window_manager_add_existing_application_windows(sm, &g_window_manager, application, i);\n        if (result) {\n            --refresh_count;\n            --i;\n        }\n    }\n    return window_count != g_window_manager.window.count;\n}\n\nvoid space_manager_handle_display_add(struct space_manager *sm, uint32_t did)\n{\n    int space_count;\n    uint64_t *space_list = display_space_list(did, &space_count);\n    if (!space_list) return;\n\n    int list_count = 0;\n    struct view *view_list[sm->view.count];\n    CFStringRef uuid_list[sm->view.count];\n\n    table_for (struct view *view, sm->view, {\n        view_list[list_count] = view;\n        uuid_list[list_count] = view->uuid;\n        ++list_count;\n    })\n\n    for (int i = 0; i < space_count; ++i) {\n        uint64_t sid = space_list[i];\n        CFStringRef uuid = SLSSpaceCopyName(g_connection, sid);\n        if (!uuid) continue;\n\n        for (int j = 0; j < list_count; ++j) {\n            CFStringRef view_uuid = uuid_list[j];\n            if (!view_uuid) continue;\n\n            if (CFEqual(view_uuid, uuid)) {\n                struct view *view = view_list[j];\n\n                uuid_list[j] = NULL;\n                view_list[j] = NULL;\n\n                table_remove(&sm->view, &view->sid);\n                CFRelease(view->uuid);\n\n                struct space_label *label = space_manager_get_label_for_space(sm, view->sid);\n                if (label) label->sid = sid;\n\n                view->sid = sid;\n                view->uuid = CFRetain(uuid);\n\n                table_add(&sm->view, &sid, view);\n                break;\n            }\n        }\n\n        CFRelease(uuid);\n    }\n\n    sm->current_space_id = space_manager_active_space();\n    sm->last_space_id = sm->current_space_id;\n}\n\nvoid space_manager_begin(struct space_manager *sm)\n{\n    sm->layout = VIEW_FLOAT;\n    sm->split_ratio = 0.5f;\n    sm->auto_balance = SPLIT_NONE;\n    sm->split_type = SPLIT_AUTO;\n    sm->window_placement = CHILD_SECOND;\n    sm->window_insertion_point = INSERT_FOCUSED;\n    sm->window_zoom_persist = true;\n    sm->labels = NULL;\n    table_init(&sm->view, 23, hash_view, compare_view);\n\n    int display_count;\n    uint32_t *display_list = display_manager_active_display_list(&display_count);\n    if (!display_list) return;\n\n    for (int i = 0; i < display_count; ++i) {\n        int space_count;\n        uint64_t *space_list = display_space_list(display_list[i], &space_count);\n        if (!space_list) continue;\n\n        for (int j = 0; j < space_count; ++j) {\n            struct view *view = view_create(space_list[j]);\n            table_add(&sm->view, &space_list[j], view);\n        }\n    }\n\n    sm->current_space_id = space_manager_active_space();\n    sm->last_space_id = sm->current_space_id;\n    sm->did_begin = true;\n}\n"
  },
  {
    "path": "src/space_manager.h",
    "content": "#ifndef SPACE_MANAGER\n#define SPACE_MANAGER\n\nstruct space_label\n{\n    uint64_t sid;\n    char *label;\n};\n\nstruct space_manager\n{\n    struct table view;\n    uint64_t current_space_id;\n    uint64_t last_space_id;\n    bool did_begin;\n    enum view_type layout;\n    int top_padding;\n    int bottom_padding;\n    int left_padding;\n    int right_padding;\n    int window_gap;\n    float split_ratio;\n    enum window_node_split split_type;\n    enum window_node_child window_placement;\n    enum window_insertion_point window_insertion_point;\n    bool window_zoom_persist;\n    uint32_t auto_balance;\n    struct space_label *labels;\n};\n\nenum space_op_error\n{\n    SPACE_OP_ERROR_SUCCESS              = 0,\n    SPACE_OP_ERROR_MISSING_SRC          = 1,\n    SPACE_OP_ERROR_MISSING_DST          = 2,\n    SPACE_OP_ERROR_INVALID_SRC          = 3,\n    SPACE_OP_ERROR_INVALID_DST          = 4,\n    SPACE_OP_ERROR_INVALID_TYPE         = 5,\n    SPACE_OP_ERROR_SAME_SPACE           = 6,\n    SPACE_OP_ERROR_SAME_DISPLAY         = 7,\n    SPACE_OP_ERROR_DISPLAY_IS_ANIMATING = 8,\n    SPACE_OP_ERROR_IN_MISSION_CONTROL   = 9,\n    SPACE_OP_ERROR_SCRIPTING_ADDITION   = 10,\n};\n\nbool space_manager_query_space(FILE *rsp, uint64_t sid, uint64_t flags);\nbool space_manager_query_spaces_for_window(FILE *rsp, struct window *window, uint64_t flags);\nbool space_manager_query_spaces_for_display(FILE *rsp, uint32_t did, uint64_t flags);\nbool space_manager_query_spaces_for_displays(FILE *rsp, uint64_t flags);\nstruct view *space_manager_query_view(struct space_manager *sm, uint64_t sid);\nstruct view *space_manager_find_view(struct space_manager *sm, uint64_t sid);\nvoid space_manager_refresh_view(struct space_manager *sm, uint64_t sid);\nvoid space_manager_mark_view_invalid(struct space_manager *sm,  uint64_t sid);\nvoid space_manager_mark_view_dirty(struct space_manager *sm,  uint64_t sid);\nvoid space_manager_untile_window(struct view *view, struct window *window);\nstruct view *space_manager_tile_window_on_space_with_insertion_point(struct space_manager *sm, struct window *window, uint64_t sid, uint32_t insertion_point);\nstruct view *space_manager_tile_window_on_space(struct space_manager *sm, struct window *window, uint64_t sid);\nbool space_manager_equalize_space(struct space_manager *sm, uint64_t sid, uint32_t axis_flag);\nbool space_manager_balance_space(struct space_manager *sm, uint64_t sid, uint32_t axis_flag);\nvoid space_manager_toggle_window_split(struct space_manager *sm, struct window *window);\nint space_manager_mission_control_index(uint64_t sid);\nuint64_t space_manager_mission_control_space(int desktop_id);\nuint64_t space_manager_cursor_space(void);\nuint64_t space_manager_prev_space(uint64_t sid);\nuint64_t space_manager_next_space(uint64_t sid);\nuint64_t space_manager_first_space(void);\nuint64_t space_manager_last_space(void);\nuint64_t space_manager_active_space(void);\nstruct space_label *space_manager_get_label_for_space(struct space_manager *sm, uint64_t sid);\nstruct space_label *space_manager_get_space_for_label(struct space_manager *sm, char *label);\nbool space_manager_remove_label_for_space(struct space_manager *sm, uint64_t sid);\nvoid space_manager_set_label_for_space(struct space_manager *sm, uint64_t sid, char *label);\nvoid space_manager_set_layout_for_space(struct space_manager *sm, uint64_t sid, enum view_type type);\nbool space_manager_set_gap_for_space(struct space_manager *sm, uint64_t sid, int type, int gap);\nbool space_manager_toggle_gap_for_space(struct space_manager *sm, uint64_t sid);\nvoid space_manager_toggle_mission_control(uint64_t sid);\nvoid space_manager_toggle_show_desktop(uint64_t sid);\nvoid space_manager_set_layout_for_all_spaces(struct space_manager *sm, enum view_type layout);\nvoid space_manager_set_window_gap_for_all_spaces(struct space_manager *sm, int window_gap);\nvoid space_manager_set_top_padding_for_all_spaces(struct space_manager *sm, int top_padding);\nvoid space_manager_set_bottom_padding_for_all_spaces(struct space_manager *sm, int bottom_padding);\nvoid space_manager_set_left_padding_for_all_spaces(struct space_manager *sm, int left_padding);\nvoid space_manager_set_right_padding_for_all_spaces(struct space_manager *sm, int right_padding);\nvoid space_manager_set_split_type_for_all_spaces(struct space_manager *sm, enum window_node_split split_type);\nvoid space_manager_set_auto_balance_for_all_spaces(struct space_manager *sm, uint32_t auto_balance);\nbool space_manager_set_padding_for_space(struct space_manager *sm, uint64_t sid, int type, int top, int bottom, int left, int right);\nbool space_manager_toggle_padding_for_space(struct space_manager *sm, uint64_t sid);\nbool space_manager_rotate_space(struct space_manager *sm, uint64_t sid, int degrees);\nbool space_manager_mirror_space(struct space_manager *sm, uint64_t sid, enum window_node_split axis);\nvoid space_manager_move_window_list_to_space(uint64_t sid, uint32_t *window_list, int window_count);\nvoid space_manager_move_window_to_space(uint64_t sid, struct window *window);\nenum space_op_error space_manager_focus_space(uint64_t sid);\nenum space_op_error space_manager_switch_space(uint64_t sid);\nenum space_op_error space_manager_swap_space_with_space(uint64_t acting_sid, uint64_t selector_sid);\nenum space_op_error space_manager_move_space_to_space(uint64_t acting_sid, uint64_t selector_sid);\nenum space_op_error space_manager_move_space_to_display(struct space_manager *sm, uint64_t sid, uint32_t did);\nenum space_op_error space_manager_destroy_space(uint64_t sid);\nenum space_op_error space_manager_add_space(uint64_t sid);\nvoid space_manager_assign_process_to_space(pid_t pid, uint64_t sid);\nvoid space_manager_assign_process_to_all_spaces(pid_t pid);\nbool space_manager_is_window_on_active_space(struct window *window);\nbool space_manager_is_window_on_space(uint64_t sid, struct window *window);\nvoid space_manager_mark_spaces_invalid_for_display(struct space_manager *sm, uint32_t did);\nvoid space_manager_mark_spaces_invalid(struct space_manager *sm);\nbool space_manager_refresh_application_windows(struct space_manager *sm);\nvoid space_manager_handle_display_add(struct space_manager *sm, uint32_t did);\nvoid space_manager_begin(struct space_manager *sm);\n\n#endif\n"
  },
  {
    "path": "src/view.c",
    "content": "extern int g_connection;\nextern struct display_manager g_display_manager;\nextern struct space_manager g_space_manager;\nextern struct window_manager g_window_manager;\n\n#define INSERT_FEEDBACK_WIDTH 2\n#define INSERT_FEEDBACK_RADIUS 9\nvoid insert_feedback_show(struct window_node *node)\n{\n    CFTypeRef frame_region;\n    CGRect frame = {{node->area.x, node->area.y},{node->area.w, node->area.h}};\n    CGSNewRegionWithRect(&frame, &frame_region);\n    frame.origin.x = 0; frame.origin.y = 0;\n\n    if (!node->feedback_window.id) {\n        uint64_t tags = (1ULL << 1) | (1ULL << 9);\n        CFTypeRef empty_region = CGRegionCreateEmptyRegion();\n        SLSNewWindowWithOpaqueShapeAndContext(g_connection, 2, frame_region, empty_region, 13, &tags, 0, 0, 64, &node->feedback_window.id, NULL);\n        CFRelease(empty_region);\n\n        sls_window_disable_shadow(node->feedback_window.id);\n        SLSSetWindowResolution(g_connection, node->feedback_window.id, 1.0f);\n        SLSSetWindowOpacity(g_connection, node->feedback_window.id, 0);\n        SLSSetWindowLevel(g_connection, node->feedback_window.id, window_level(node->window_order[0]));\n        SLSSetWindowSubLevel(g_connection, node->feedback_window.id, window_sub_level(node->window_order[0]));\n        node->feedback_window.context = SLWindowContextCreate(g_connection, node->feedback_window.id, 0);\n        CGContextSetLineWidth(node->feedback_window.context, INSERT_FEEDBACK_WIDTH);\n        CGContextSetRGBFillColor(node->feedback_window.context,\n                                   g_window_manager.insert_feedback_color.r,\n                                   g_window_manager.insert_feedback_color.g,\n                                   g_window_manager.insert_feedback_color.b,\n                                   g_window_manager.insert_feedback_color.a*0.25f);\n        CGContextSetRGBStrokeColor(node->feedback_window.context,\n                                   g_window_manager.insert_feedback_color.r,\n                                   g_window_manager.insert_feedback_color.g,\n                                   g_window_manager.insert_feedback_color.b,\n                                   g_window_manager.insert_feedback_color.a);\n        SLSDisableUpdate(g_connection);\n        CGContextClearRect(node->feedback_window.context, frame);\n        CGContextFlush(node->feedback_window.context);\n        SLSReenableUpdate(g_connection);\n        SLSOrderWindow(g_connection, node->feedback_window.id, 1, node->window_order[0]);\n        table_add(&g_window_manager.insert_feedback, &node->window_order[0], node);\n        if (!workspace_is_macos_sequoia() && !workspace_is_macos_tahoe()) {\n            update_window_notifications();\n        }\n    }\n\n    CGFloat clip_x, clip_y, clip_w, clip_h;\n    CGFloat midx = CGRectGetMidX(frame);\n    CGFloat midy = CGRectGetMidY(frame);\n\n    switch (node->insert_dir) {\n    case DIR_NORTH: {\n        clip_x = -0.5f * INSERT_FEEDBACK_WIDTH;\n        clip_y = midy - 0.5f * INSERT_FEEDBACK_WIDTH;\n        clip_w = INSERT_FEEDBACK_WIDTH;\n        clip_h = INSERT_FEEDBACK_WIDTH;\n    } break;\n    case DIR_EAST: {\n        clip_x = midx - 0.5f * INSERT_FEEDBACK_WIDTH;\n        clip_y = -0.5f * INSERT_FEEDBACK_WIDTH;\n        clip_w = INSERT_FEEDBACK_WIDTH;\n        clip_h = INSERT_FEEDBACK_WIDTH;\n    } break;\n    case DIR_SOUTH: {\n        clip_x = -0.5f * INSERT_FEEDBACK_WIDTH;\n        clip_y = -0.5f * INSERT_FEEDBACK_WIDTH;\n        clip_w = INSERT_FEEDBACK_WIDTH;\n        clip_h = -midy + INSERT_FEEDBACK_WIDTH;\n    } break;\n    case DIR_WEST: {\n        clip_x = -0.5f * INSERT_FEEDBACK_WIDTH;\n        clip_y = -0.5f * INSERT_FEEDBACK_WIDTH;\n        clip_w = -midx + INSERT_FEEDBACK_WIDTH;\n        clip_h = INSERT_FEEDBACK_WIDTH;\n    } break;\n    case STACK: {\n        clip_x = -0.5f * INSERT_FEEDBACK_WIDTH;\n        clip_y = -0.5f * INSERT_FEEDBACK_WIDTH;\n        clip_w = INSERT_FEEDBACK_WIDTH;\n        clip_h = INSERT_FEEDBACK_WIDTH;\n    } break;\n    }\n\n    CGRect rect = (CGRect) {{ 0.5f*INSERT_FEEDBACK_WIDTH, 0.5f*INSERT_FEEDBACK_WIDTH }, { frame.size.width - INSERT_FEEDBACK_WIDTH, frame.size.height - INSERT_FEEDBACK_WIDTH }};\n    CGRect fill = CGRectInset(rect, 0.5f*INSERT_FEEDBACK_WIDTH, 0.5f*INSERT_FEEDBACK_WIDTH);\n    CGRect clip = { { rect.origin.x + clip_x, rect.origin.y + clip_y }, { rect.size.width + clip_w, rect.size.height + clip_h } };\n    CGPathRef path = CGPathCreateWithRoundedRect(rect, cgrect_clamp_x_radius(rect, INSERT_FEEDBACK_RADIUS), cgrect_clamp_y_radius(rect, INSERT_FEEDBACK_RADIUS), NULL);\n\n    SLSDisableUpdate(g_connection);\n    SLSSetWindowShape(g_connection, node->feedback_window.id, 0.0f, 0.0f, frame_region);\n    CGContextClearRect(node->feedback_window.context, frame);\n    CGContextClipToRect(node->feedback_window.context, clip);\n    CGContextFillRect(node->feedback_window.context, fill);\n    CGContextAddPath(node->feedback_window.context, path);\n    CGContextStrokePath(node->feedback_window.context);\n    CGContextResetClip(node->feedback_window.context);\n    CGContextFlush(node->feedback_window.context);\n    SLSReenableUpdate(g_connection);\n    CGPathRelease(path);\n    CFRelease(frame_region);\n}\n\nvoid insert_feedback_destroy(struct window_node *node)\n{\n    if (node->feedback_window.id) {\n        table_remove(&g_window_manager.insert_feedback, &node->window_order[0]);\n\n        if (!workspace_is_macos_sequoia() && !workspace_is_macos_tahoe()) {\n            update_window_notifications();\n        }\n\n        SLSOrderWindow(g_connection, node->feedback_window.id, 0, 0);\n        CGContextRelease(node->feedback_window.context);\n        SLSReleaseWindow(g_connection, node->feedback_window.id);\n        memset(&node->feedback_window, 0, sizeof(struct feedback_window));\n    }\n}\n\nstatic inline struct area area_from_cgrect(CGRect rect)\n{\n    return (struct area) { rect.origin.x, rect.origin.y, rect.size.width, rect.size.height };\n}\n\nstatic inline CGPoint area_max_point(struct area area)\n{\n    return (CGPoint) { area.x + area.w - 1, area.y + area.h - 1 };\n}\n\nstatic inline enum window_node_child window_node_get_child(struct window_node *node)\n{\n    return node->child != CHILD_NONE ? node->child : g_space_manager.window_placement;\n}\n\nstatic inline enum window_node_split window_node_get_split(struct view *view, struct window_node *node)\n{\n    if (node->split != SPLIT_NONE) return node->split;\n\n    if (view->split_type != SPLIT_NONE) {\n        if (view->split_type != SPLIT_AUTO) {\n            return view->split_type;\n        }\n    } else if (g_space_manager.split_type != SPLIT_AUTO) {\n        return g_space_manager.split_type;\n    }\n\n    return node->area.w >= node->area.h ? SPLIT_Y : SPLIT_X;\n}\n\nstatic inline float window_node_get_ratio(struct window_node *node)\n{\n    return in_range_ii(node->ratio, 0.1f, 0.9f) ? node->ratio : g_space_manager.split_ratio;\n}\n\nstatic inline int window_node_get_gap(struct view *view)\n{\n    return view_check_flag(view, VIEW_ENABLE_GAP) ? view->window_gap : 0;\n}\n\nstatic void area_make_pair(enum window_node_split split, int gap, float ratio, struct area *parent_area, struct area *left_area, struct area *right_area)\n{\n    if (split == SPLIT_Y) {\n        *left_area  = *parent_area;\n        *right_area = *parent_area;\n\n        float left_width  = (parent_area->w - gap) * ratio;\n        float right_width = (parent_area->w - gap) * (1 - ratio);\n\n        left_area->w   = (int)left_width;\n        right_area->w  = (int)right_width;\n        right_area->x += (int)(left_width + 0.5f) + gap;\n    } else {\n        *left_area  = *parent_area;\n        *right_area = *parent_area;\n\n        float left_width  = (parent_area->h - gap) * ratio;\n        float right_width = (parent_area->h - gap) * (1 - ratio);\n\n        left_area->h   = (int)left_width;\n        right_area->h  = (int)right_width;\n        right_area->y += (int)(left_width + 0.5f) + gap;\n    }\n}\n\nstatic void area_make_pair_for_node(struct view *view, struct window_node *node)\n{\n    enum window_node_split split = window_node_get_split(view, node);\n    float ratio = window_node_get_ratio(node);\n    int gap     = window_node_get_gap(view);\n\n    area_make_pair(split, gap, ratio, &node->area, &node->left->area, &node->right->area);\n\n    node->split = split;\n    node->ratio = ratio;\n}\n\nstatic inline bool window_node_is_occupied(struct window_node *node)\n{\n    return node->window_count != 0;\n}\n\nstatic inline bool window_node_is_intermediate(struct window_node *node)\n{\n    return node->parent != NULL;\n}\n\nstatic inline bool window_node_is_leaf(struct window_node *node)\n{\n    return node->left == NULL && node->right == NULL;\n}\n\nstatic inline bool window_node_is_left_child(struct window_node *node)\n{\n    return node->parent && node->parent->left == node;\n}\n\nstatic inline bool window_node_is_right_child(struct window_node *node)\n{\n    return node->parent && node->parent->right == node;\n}\n\nstatic void window_node_equalize(struct window_node *node, uint32_t axis_flag)\n{\n    if (node->left)  window_node_equalize(node->left, axis_flag);\n    if (node->right) window_node_equalize(node->right, axis_flag);\n\n    if ((axis_flag & SPLIT_Y) && node->split == SPLIT_Y) {\n        node->ratio = g_space_manager.split_ratio;\n    }\n\n    if ((axis_flag & SPLIT_X) && node->split == SPLIT_X) {\n        node->ratio = g_space_manager.split_ratio;\n    }\n}\n\nstatic inline struct balance_node balance_node_add(struct balance_node a, struct balance_node b)\n{\n    return (struct balance_node) { a.y_count + b.y_count, a.x_count + b.x_count, };\n}\n\nstatic struct balance_node window_node_balance(struct window_node *node, uint32_t axis_flag)\n{\n    if (window_node_is_leaf(node)) {\n        return (struct balance_node) {\n            node->parent ? node->parent->split == SPLIT_Y : 0,\n            node->parent ? node->parent->split == SPLIT_X : 0\n        };\n    }\n\n    struct balance_node left_leafs  = window_node_balance(node->left, axis_flag);\n    struct balance_node right_leafs = window_node_balance(node->right, axis_flag);\n    struct balance_node total_leafs = balance_node_add(left_leafs, right_leafs);\n\n    if (axis_flag & SPLIT_Y) {\n        if (node->split == SPLIT_Y) {\n            node->ratio = (float) left_leafs.y_count / total_leafs.y_count;\n            --total_leafs.y_count;\n        }\n    }\n\n    if (axis_flag & SPLIT_X) {\n        if (node->split == SPLIT_X) {\n            node->ratio = (float) left_leafs.x_count / total_leafs.x_count;\n            --total_leafs.x_count;\n        }\n    }\n\n    if (node->parent) {\n        total_leafs.y_count += node->parent->split == SPLIT_Y;\n        total_leafs.x_count += node->parent->split == SPLIT_X;\n    }\n\n    return total_leafs;\n}\n\nstatic void window_node_split(struct view *view, struct window_node *node, struct window *window)\n{\n    struct window_node *left = malloc(sizeof(struct window_node));\n    memset(left, 0, sizeof(struct window_node));\n\n    struct window_node *right = malloc(sizeof(struct window_node));\n    memset(right, 0, sizeof(struct window_node));\n\n    struct window_node *zoom = !g_space_manager.window_zoom_persist\n                             ? NULL\n                             : !node->zoom\n                             ? NULL\n                             : node->zoom == node->parent\n                             ? node\n                             : view->root;\n\n    if (window_node_get_child(node) == CHILD_SECOND) {\n        memcpy(left->window_list, node->window_list, sizeof(uint32_t) * node->window_count);\n        memcpy(left->window_order, node->window_order, sizeof(uint32_t) * node->window_count);\n        left->window_count = node->window_count;\n        left->zoom = zoom;\n\n        right->window_list[0] = window->id;\n        right->window_order[0] = window->id;\n        right->window_count = 1;\n    } else {\n        memcpy(right->window_list, node->window_list, sizeof(uint32_t) * node->window_count);\n        memcpy(right->window_order, node->window_order, sizeof(uint32_t) * node->window_count);\n        right->window_count = node->window_count;\n        right->zoom = zoom;\n\n        left->window_list[0] = window->id;\n        left->window_order[0] = window->id;\n        left->window_count = 1;\n    }\n\n    left->parent  = node;\n    right->parent = node;\n\n    node->window_count = 0;\n    node->left  = left;\n    node->right = right;\n    node->zoom  = NULL;\n\n    area_make_pair_for_node(view, node);\n}\n\nvoid window_node_update(struct view *view, struct window_node *node)\n{\n    if (window_node_is_leaf(node)) {\n        if (node->insert_dir) insert_feedback_show(node);\n    } else {\n        area_make_pair_for_node(view, node);\n        window_node_update(view, node->left);\n        window_node_update(view, node->right);\n    }\n}\n\nstatic void window_node_destroy(struct window_node *node)\n{\n    if (node->left)  window_node_destroy(node->left);\n    if (node->right) window_node_destroy(node->right);\n\n    for (int i = 0; i < node->window_count; ++i) {\n        window_manager_remove_managed_window(&g_window_manager, node->window_list[i]);\n    }\n\n    insert_feedback_destroy(node);\n    free(node);\n}\n\nstatic void window_node_clear_zoom(struct window_node *node)\n{\n    node->zoom = NULL;\n\n    if (!window_node_is_leaf(node)) {\n        window_node_clear_zoom(node->left);\n        window_node_clear_zoom(node->right);\n    }\n}\n\nvoid window_node_capture_windows(struct window_node *node, struct window_capture **window_list)\n{\n    if (window_node_is_leaf(node)) {\n        for (int i = 0; i < node->window_count; ++i) {\n            struct window *window = window_manager_find_window(&g_window_manager, node->window_list[i]);\n            if (window) {\n                struct area area = node->zoom ? node->zoom->area : node->area;\n                ts_buf_push(*window_list, ((struct window_capture) { .window = window, .x = area.x, .y = area.y, .w = area.w, .h = area.h }));\n            }\n        }\n    } else {\n        window_node_capture_windows(node->left, window_list);\n        window_node_capture_windows(node->right, window_list);\n    }\n}\n\nvoid window_node_flush(struct window_node *node)\n{\n    struct window_capture *window_list = NULL;\n    window_node_capture_windows(node, &window_list);\n    if (window_list) window_manager_animate_window_list(window_list, ts_buf_len(window_list));\n}\n\nbool window_node_contains_window(struct window_node *node, uint32_t window_id)\n{\n    for (int i = 0; i < node->window_count; ++i) {\n        if (node->window_list[i] == window_id) return true;\n    }\n\n    return false;\n}\n\nint window_node_index_of_window(struct window_node *node, uint32_t window_id)\n{\n    for (int i = 0; i < node->window_count; ++i) {\n        if (node->window_list[i] == window_id) return i;\n    }\n\n    return 0;\n}\n\nvoid window_node_swap_window_list(struct window_node *a_node, struct window_node *b_node)\n{\n    uint32_t tmp_window_list[NODE_MAX_WINDOW_COUNT];\n    uint32_t tmp_window_order[NODE_MAX_WINDOW_COUNT];\n    uint32_t tmp_window_count;\n\n    memcpy(tmp_window_list, a_node->window_list, sizeof(uint32_t) * a_node->window_count);\n    memcpy(tmp_window_order, a_node->window_order, sizeof(uint32_t) * a_node->window_count);\n    tmp_window_count = a_node->window_count;\n\n    memcpy(a_node->window_list, b_node->window_list, sizeof(uint32_t) * b_node->window_count);\n    memcpy(a_node->window_order, b_node->window_order, sizeof(uint32_t) * b_node->window_count);\n    a_node->window_count = b_node->window_count;\n\n    memcpy(b_node->window_list, tmp_window_list, sizeof(uint32_t) * tmp_window_count);\n    memcpy(b_node->window_order, tmp_window_order, sizeof(uint32_t) * tmp_window_count);\n    b_node->window_count = tmp_window_count;\n\n    a_node->zoom = NULL;\n    b_node->zoom = NULL;\n}\n\nstruct window_node *window_node_find_first_leaf(struct window_node *root)\n{\n    struct window_node *node = root;\n    while (!window_node_is_leaf(node)) {\n        node = node->left;\n    }\n    return node;\n}\n\nstruct window_node *window_node_find_last_leaf(struct window_node *root)\n{\n    struct window_node *node = root;\n    while (!window_node_is_leaf(node)) {\n        node = node->right;\n    }\n    return node;\n}\n\nstruct window_node *window_node_find_prev_leaf(struct window_node *node)\n{\n    if (!node->parent) return NULL;\n\n    if (window_node_is_left_child(node)) {\n        return window_node_find_prev_leaf(node->parent);\n    }\n\n    if (window_node_is_leaf(node->parent->left)) {\n        return node->parent->left;\n    }\n\n    return window_node_find_last_leaf(node->parent->left->right);\n}\n\nstruct window_node *window_node_find_next_leaf(struct window_node *node)\n{\n    if (!node->parent) return NULL;\n\n    if (window_node_is_right_child(node)) {\n        return window_node_find_next_leaf(node->parent);\n    }\n\n    if (window_node_is_leaf(node->parent->right)) {\n        return node->parent->right;\n    }\n\n    return window_node_find_first_leaf(node->parent->right->left);\n}\n\nvoid window_node_rotate(struct window_node *node, int degrees)\n{\n    if ((degrees ==  90 && node->split == SPLIT_Y) ||\n        (degrees == 270 && node->split == SPLIT_X) ||\n        (degrees == 180)) {\n        struct window_node *temp = node->left;\n        node->left  = node->right;\n        node->right = temp;\n        node->ratio = 1 - node->ratio;\n    }\n\n    if (degrees != 180) {\n        if (node->split == SPLIT_X) {\n            node->split = SPLIT_Y;\n        } else if (node->split == SPLIT_Y) {\n            node->split = SPLIT_X;\n        }\n    }\n\n    if (!window_node_is_leaf(node)) {\n        window_node_rotate(node->left, degrees);\n        window_node_rotate(node->right, degrees);\n    }\n}\n\nstruct window_node *window_node_mirror(struct window_node *node, enum window_node_split axis)\n{\n    if (!window_node_is_leaf(node)) {\n        struct window_node *left = window_node_mirror(node->left, axis);\n        struct window_node *right = window_node_mirror(node->right, axis);\n\n        if (node->split == axis) {\n            node->left = right;\n            node->right = left;\n        }\n    }\n\n    return node;\n}\n\nstruct window_node *window_node_fence(struct window_node *node, int dir)\n{\n    if (!node) return NULL;\n\n    for (struct window_node *parent = node->parent; parent; parent = parent->parent) {\n        if ((dir == DIR_NORTH && parent->split == SPLIT_X && parent->area.y < node->area.y) ||\n            (dir == DIR_WEST  && parent->split == SPLIT_Y && parent->area.x < node->area.x) ||\n            (dir == DIR_SOUTH && parent->split == SPLIT_X && (parent->area.y + parent->area.h) > (node->area.y + node->area.h)) ||\n            (dir == DIR_EAST  && parent->split == SPLIT_Y && (parent->area.x + parent->area.w) > (node->area.x + node->area.w))) {\n                return parent;\n        }\n    }\n\n    return NULL;\n}\n\nstruct window_node *view_find_min_depth_leaf_node(struct window_node *node)\n{\n    struct window_node *list[256] = { node };\n\n    for (int i = 0, j = 0; i < 256; ++i) {\n        if (window_node_is_leaf(list[i])) {\n            return list[i];\n        }\n\n        list[++j] = list[i]->left;\n        list[++j] = list[i]->right;\n    }\n\n    return NULL;\n}\n\nstatic inline bool area_is_in_direction(struct area *r1, CGPoint r1_max, struct area *r2, CGPoint r2_max, int direction)\n{\n    if (direction == DIR_NORTH && r1_max.y <= r2->y) return false;\n    if (direction == DIR_EAST  && r2_max.x <= r1->x) return false;\n    if (direction == DIR_SOUTH && r2_max.y <= r1->y) return false;\n    if (direction == DIR_WEST  && r1_max.x <= r2->x) return false;\n\n    if (direction == DIR_NORTH || direction == DIR_SOUTH) {\n        return ((r2_max.x >  r1->x && r2_max.x <= r1_max.x) ||\n                (r2->x    <  r1->x && r2_max.x >  r1_max.x) ||\n                (r2->x    >= r1->x && r2->x    <  r1_max.x));\n    }\n\n    if (direction == DIR_EAST || direction == DIR_WEST) {\n        return ((r2_max.y >  r1->y && r2_max.y <= r1_max.y) ||\n                (r2->y    <  r1->y && r2_max.y >  r1_max.y) ||\n                (r2->y    >= r1->y && r2->y    <  r1_max.y));\n    }\n\n    return false;\n}\n\nstatic inline int area_distance_in_direction(struct area *r1, CGPoint r1_max, struct area *r2, CGPoint r2_max, int direction)\n{\n    switch (direction) {\n    case DIR_NORTH: {\n        return r2_max.y > r1->y ? r2_max.y - r1->y : r1->y - r2_max.y;\n    } break;\n    case DIR_EAST: {\n        return r2->x < r1_max.x ? r1_max.x - r2->x : r2->x - r1_max.x;\n    } break;\n    case DIR_SOUTH: {\n        return r2->y < r1_max.y ? r1_max.y - r2->y : r2->y - r1_max.y;\n    } break;\n    case DIR_WEST: {\n        return r2_max.x > r1->x ? r2_max.x - r1->x : r1->x - r2_max.x;\n    } break;\n    }\n\n    return INT_MAX;\n}\n\nstruct window_node *view_find_window_node_in_direction(struct view *view, struct window_node *source, int direction)\n{\n    int window_count;\n    uint32_t *window_list = space_window_list(view->sid, &window_count, false);\n    if (!window_list) return NULL;\n\n    int best_distance = INT_MAX;\n    int best_rank = INT_MAX;\n    struct window_node *best_node = NULL;\n    CGPoint source_area_max = area_max_point(source->area);\n\n    for (struct window_node *target = window_node_find_first_leaf(view->root); target; target = window_node_find_next_leaf(target)) {\n        if (source == target) continue;\n\n        CGPoint target_area_max = area_max_point(target->area);\n        if (area_is_in_direction(&source->area, source_area_max, &target->area, target_area_max, direction)) {\n            int distance = area_distance_in_direction(&source->area, source_area_max, &target->area, target_area_max, direction);\n            int rank = window_manager_find_rank_of_window_in_list(target->window_order[0], window_list, window_count);\n            if ((distance < best_distance) || (distance == best_distance && rank < best_rank)) {\n                best_node = target;\n                best_distance = distance;\n                best_rank = rank;\n            }\n        }\n    }\n\n    return best_node;\n}\n\nstruct window_node *view_find_window_node(struct view *view, uint32_t window_id)\n{\n    for (struct window_node *node = window_node_find_first_leaf(view->root); node; node = window_node_find_next_leaf(node)) {\n        if (window_node_contains_window(node, window_id)) return node;\n    }\n\n    return NULL;\n}\n\nstruct window_node *view_remove_window_node(struct view *view, struct window *window)\n{\n    struct window_node *node = view_find_window_node(view, window->id);\n    if (!node) return NULL;\n\n    if (node->window_count > 1) {\n        bool removed_entry = false;\n        bool removed_order = false;\n\n        for (int i = 0; i < node->window_count; ++i) {\n            if (!removed_entry && node->window_list[i] == window->id) {\n                memmove(node->window_list + i, node->window_list + i + 1, sizeof(uint32_t) * (node->window_count - i - 1));\n                removed_entry = true;\n            }\n\n            if (!removed_order && node->window_order[i] == window->id) {\n                memmove(node->window_order + i, node->window_order + i + 1, sizeof(uint32_t) * (node->window_count - i - 1));\n                removed_order = true;\n            }\n        }\n\n        assert(removed_entry);\n        assert(removed_order);\n        --node->window_count;\n\n        if (view->insertion_point == window->id) {\n            view->insertion_point = node->window_order[0];\n        }\n\n        return NULL;\n    }\n\n    if (node == view->root) {\n        view->insertion_point = 0;\n        insert_feedback_destroy(node);\n        memset(node, 0, sizeof(struct window_node));\n        view_update(view);\n        return NULL;\n    }\n\n    struct window_node *parent = node->parent;\n    struct window_node *child  = window_node_is_right_child(node)\n                               ? parent->left\n                               : parent->right;\n\n\n    memcpy(parent->window_list, child->window_list, sizeof(uint32_t) * child->window_count);\n    memcpy(parent->window_order, child->window_order, sizeof(uint32_t) * child->window_count);\n    parent->window_count = child->window_count;\n\n    parent->left      = NULL;\n    parent->right     = NULL;\n    parent->zoom      = !g_space_manager.window_zoom_persist\n                      ? NULL\n                      : !child->zoom\n                      ? NULL\n                      : child->zoom == parent\n                      ? parent->parent\n                      : view->root;\n\n    if (child->insert_dir) {\n        parent->feedback_window = child->feedback_window;\n        parent->insert_dir      = child->insert_dir;\n        parent->split           = child->split;\n        parent->child           = child->child;\n        insert_feedback_show(parent);\n    }\n\n    if (window_node_is_intermediate(child) && !window_node_is_leaf(child)) {\n        parent->left          = child->left;\n        parent->left->parent  = parent;\n        parent->left->zoom    = !g_space_manager.window_zoom_persist\n                              ? NULL\n                              : !child->left->zoom\n                              ? NULL\n                              : child->left->zoom == child\n                              ? parent\n                              : view->root;\n\n        parent->right         = child->right;\n        parent->right->parent = parent;\n        parent->right->zoom   = !g_space_manager.window_zoom_persist\n                              ? NULL\n                              : !child->right->zoom\n                              ? NULL\n                              : child->right->zoom == child\n                              ? parent\n                              : view->root;\n\n        if (!g_space_manager.window_zoom_persist) {\n            window_node_clear_zoom(parent);\n        }\n\n        window_node_update(view, parent);\n    }\n\n    insert_feedback_destroy(node);\n    free(child);\n    free(node);\n\n    if (view->auto_balance != SPLIT_NONE) {\n        window_node_balance(view->root, view->auto_balance);\n        view_update(view);\n        return view->root;\n    }\n\n    return parent;\n}\n\nvoid view_stack_window_node(struct window_node *node, struct window *window)\n{\n    int insert_index = node->window_count;\n\n    for (int i = 0; i < node->window_count; ++i) {\n        if (node->window_list[i] == node->window_order[0]) {\n            insert_index = i+1;\n            break;\n        }\n    }\n\n    if (insert_index < node->window_count) {\n        memmove(node->window_list + insert_index + 1, node->window_list + insert_index, sizeof(uint32_t) * (node->window_count - insert_index));\n    }\n\n    node->window_list[insert_index] = window->id;\n    memmove(node->window_order + 1, node->window_order, sizeof(uint32_t) * node->window_count);\n    node->window_order[0] = window->id;\n    ++node->window_count;\n}\n\nstruct window_node *view_add_window_node_with_insertion_point(struct view *view, struct window *window, uint32_t insertion_point)\n{\n    if (!window_node_is_occupied(view->root) &&\n        window_node_is_leaf(view->root)) {\n        view->root->window_list[0] = window->id;\n        view->root->window_order[0] = window->id;\n        view->root->window_count = 1;\n        return view->root;\n    } else if (view->layout == VIEW_BSP) {\n        uint32_t prev_insertion_point = 0;\n        struct window_node *leaf = NULL;\n\n        if (insertion_point) {\n            prev_insertion_point = view->insertion_point;\n            view->insertion_point = insertion_point;\n        }\n\n        if (view->insertion_point) {\n            leaf = view_find_window_node(view, view->insertion_point);\n            view->insertion_point = prev_insertion_point;\n\n            if (leaf) {\n                bool do_stack = leaf->insert_dir == STACK;\n\n                leaf->insert_dir = 0;\n                insert_feedback_destroy(leaf);\n\n                if (do_stack) {\n                    view_stack_window_node(leaf, window);\n                    return leaf;\n                }\n            }\n        }\n\n        if (!leaf) {\n            if (g_space_manager.window_insertion_point == INSERT_FOCUSED) {\n                leaf = view_find_window_node(view, g_window_manager.focused_window_id);\n            } else if (g_space_manager.window_insertion_point == INSERT_FIRST) {\n                leaf = window_node_find_first_leaf(view->root);\n            } else if (g_space_manager.window_insertion_point == INSERT_LAST) {\n                leaf = window_node_find_last_leaf(view->root);\n            }\n\n            if (!leaf) leaf = view_find_min_depth_leaf_node(view->root);\n        }\n\n        window_node_split(view, leaf, window);\n\n        if (view->auto_balance != SPLIT_NONE) {\n            window_node_balance(view->root, view->auto_balance);\n            view_update(view);\n            return view->root;\n        }\n\n        return leaf;\n    } else if (view->layout == VIEW_STACK) {\n        view_stack_window_node(view->root, window);\n        return view->root;\n    }\n\n    return NULL;\n}\n\nstruct window_node *view_add_window_node(struct view *view, struct window *window)\n{\n    return view_add_window_node_with_insertion_point(view, window, 0);\n}\n\nuint32_t *view_find_window_list(struct view *view, int *window_count)\n{\n    *window_count = 0;\n\n    int capacity = 13;\n    uint32_t *window_list = ts_alloc_list(uint32_t, capacity);\n\n    for (struct window_node *node = window_node_find_first_leaf(view->root); node; node = window_node_find_next_leaf(node)) {\n        if (*window_count + node->window_count >= capacity) {\n            ts_expand(window_list, sizeof(uint32_t) * capacity, sizeof(uint32_t) * capacity);\n            capacity *= 2;\n        }\n\n        for (int i = 0; i < node->window_count; ++i) {\n            window_list[(*window_count)++] = node->window_list[i];\n        }\n    }\n\n    return window_list;\n}\n\nbool view_is_invalid(struct view *view)\n{\n    return !view_check_flag(view, VIEW_IS_VALID);\n}\n\nbool view_is_dirty(struct view *view)\n{\n    return view_check_flag(view, VIEW_IS_DIRTY);\n}\n\nvoid view_flush(struct view *view)\n{\n    if (space_is_visible(view->sid)) {\n        window_node_flush(view->root);\n        view_clear_flag(view, VIEW_IS_DIRTY);\n    } else {\n        view_set_flag(view, VIEW_IS_DIRTY);\n    }\n}\n\nvoid view_serialize(FILE *rsp, struct view *view, uint64_t flags)\n{\n    TIME_FUNCTION;\n\n    if (flags == 0x0) flags |= ~flags;\n\n    bool did_output = false;\n    fprintf(rsp, \"{\\n\");\n\n    if (flags & SPACE_PROPERTY_ID) {\n        fprintf(rsp, \"\\t\\\"id\\\":%lld\", view->sid);\n        did_output = true;\n    }\n\n    if (flags & SPACE_PROPERTY_UUID) {\n        if (did_output) fprintf(rsp, \",\\n\");\n\n        char *uuid = ts_cfstring_copy(view->uuid);\n        fprintf(rsp, \"\\t\\\"uuid\\\":\\\"%s\\\"\", uuid ? uuid : \"<unknown>\");\n        did_output = true;\n    }\n\n    if (flags & SPACE_PROPERTY_INDEX) {\n        if (did_output) fprintf(rsp, \",\\n\");\n\n        fprintf(rsp, \"\\t\\\"index\\\":%d\", space_manager_mission_control_index(view->sid));\n        did_output = true;\n    }\n\n    if (flags & SPACE_PROPERTY_LABEL) {\n        if (did_output) fprintf(rsp, \",\\n\");\n\n        struct space_label *space_label = space_manager_get_label_for_space(&g_space_manager, view->sid);\n        fprintf(rsp, \"\\t\\\"label\\\":\\\"%s\\\"\", space_label ? space_label->label : \"\");\n        did_output = true;\n    }\n\n    if (flags & SPACE_PROPERTY_TYPE) {\n        if (did_output) fprintf(rsp, \",\\n\");\n\n        fprintf(rsp, \"\\t\\\"type\\\":\\\"%s\\\"\", view_type_str[view->layout]);\n        did_output = true;\n    }\n\n    if (flags & SPACE_PROPERTY_DISPLAY) {\n        if (did_output) fprintf(rsp, \",\\n\");\n\n        fprintf(rsp, \"\\t\\\"display\\\":%d\", display_manager_display_id_arrangement(space_display_id(view->sid)));\n        did_output = true;\n    }\n\n    if (flags & SPACE_PROPERTY_WINDOWS) {\n        if (did_output) fprintf(rsp, \",\\n\");\n\n        int window_count = 0;\n        uint32_t *window_list = space_window_list(view->sid, &window_count, true);\n\n        fprintf(rsp, \"\\t\\\"windows\\\":[\");\n        for (int i = 0; i < window_count; ++i) {\n            if (i < window_count - 1) {\n                fprintf(rsp, \"%d, \", window_list[i]);\n            } else {\n                fprintf(rsp, \"%d\", window_list[i]);\n            }\n        }\n        fprintf(rsp, \"]\");\n        did_output = true;\n    }\n\n    if (flags & SPACE_PROPERTY_FIRST_WINDOW) {\n        if (did_output) fprintf(rsp, \",\\n\");\n\n        struct window_node *first_leaf = window_node_find_first_leaf(view->root);\n        fprintf(rsp, \"\\t\\\"first-window\\\":%d\", first_leaf ? first_leaf->window_order[0] : 0);\n        did_output = true;\n    }\n\n    if (flags & SPACE_PROPERTY_LAST_WINDOW) {\n        if (did_output) fprintf(rsp, \",\\n\");\n\n        struct window_node *last_leaf = window_node_find_last_leaf(view->root);\n        fprintf(rsp, \"\\t\\\"last-window\\\":%d\", last_leaf ? last_leaf->window_order[0] : 0);\n        did_output = true;\n    }\n\n    if (flags & SPACE_PROPERTY_HAS_FOCUS) {\n        if (did_output) fprintf(rsp, \",\\n\");\n\n        fprintf(rsp, \"\\t\\\"has-focus\\\":%s\", json_bool(view->sid == g_space_manager.current_space_id));\n        did_output = true;\n    }\n\n    if (flags & SPACE_PROPERTY_IS_VISIBLE) {\n        if (did_output) fprintf(rsp, \",\\n\");\n\n        fprintf(rsp, \"\\t\\\"is-visible\\\":%s\", json_bool(space_is_visible(view->sid)));\n        did_output = true;\n    }\n\n    if (flags & SPACE_PROPERTY_IS_FULLSCREEN) {\n        if (did_output) fprintf(rsp, \",\\n\");\n\n        fprintf(rsp, \"\\t\\\"is-native-fullscreen\\\":%s\", json_bool(space_is_fullscreen(view->sid)));\n    }\n\n    fprintf(rsp, \"\\n}\");\n}\n\nvoid view_update(struct view *view)\n{\n    uint32_t did = space_display_id(view->sid);\n    CGRect frame = display_bounds_constrained(did, false);\n    view->root->area = area_from_cgrect(frame);\n\n    if (view_check_flag(view, VIEW_ENABLE_PADDING)) {\n        view->root->area.x += view->left_padding;\n        view->root->area.w -= (view->left_padding + view->right_padding);\n        view->root->area.y += view->top_padding;\n        view->root->area.h -= (view->top_padding + view->bottom_padding);\n    }\n\n    window_node_update(view, view->root);\n    view_set_flag(view, VIEW_IS_VALID);\n    view_set_flag(view, VIEW_IS_DIRTY);\n}\n\nstruct view *view_create(uint64_t sid)\n{\n    struct view *view = malloc(sizeof(struct view));\n    memset(view, 0, sizeof(struct view));\n\n    view->root = malloc(sizeof(struct window_node));\n    memset(view->root, 0, sizeof(struct window_node));\n\n    view->sid = sid;\n    view->uuid = SLSSpaceCopyName(g_connection, sid);\n\n    view_set_flag(view, VIEW_ENABLE_PADDING);\n    view_set_flag(view, VIEW_ENABLE_GAP);\n\n    if (space_is_user(view->sid)) {\n        if (!view_check_flag(view, VIEW_LAYOUT))         view->layout         = g_space_manager.layout;\n        if (!view_check_flag(view, VIEW_TOP_PADDING))    view->top_padding    = g_space_manager.top_padding;\n        if (!view_check_flag(view, VIEW_BOTTOM_PADDING)) view->bottom_padding = g_space_manager.bottom_padding;\n        if (!view_check_flag(view, VIEW_LEFT_PADDING))   view->left_padding   = g_space_manager.left_padding;\n        if (!view_check_flag(view, VIEW_RIGHT_PADDING))  view->right_padding  = g_space_manager.right_padding;\n        if (!view_check_flag(view, VIEW_WINDOW_GAP))     view->window_gap     = g_space_manager.window_gap;\n        if (!view_check_flag(view, VIEW_AUTO_BALANCE))   view->auto_balance   = g_space_manager.auto_balance;\n        if (!view_check_flag(view, VIEW_SPLIT_TYPE))     view->split_type     = g_space_manager.split_type;\n        view_update(view);\n    } else {\n        view->layout = VIEW_FLOAT;\n    }\n\n    return view;\n}\n\nvoid view_destroy(struct view *view)\n{\n    if (view->root) {\n        if (view->root->left)  window_node_destroy(view->root->left);\n        if (view->root->right) window_node_destroy(view->root->right);\n\n        for (int i = 0; i < view->root->window_count; ++i) {\n            window_manager_remove_managed_window(&g_window_manager, view->root->window_list[i]);\n        }\n\n        insert_feedback_destroy(view->root);\n        memset(view->root, 0, sizeof(struct window_node));\n    }\n}\n\nvoid view_clear(struct view *view)\n{\n    if (view->root) {\n        if (view->root->left)  window_node_destroy(view->root->left);\n        if (view->root->right) window_node_destroy(view->root->right);\n\n        for (int i = 0; i < view->root->window_count; ++i) {\n            window_manager_remove_managed_window(&g_window_manager, view->root->window_list[i]);\n        }\n\n        insert_feedback_destroy(view->root);\n        memset(view->root, 0, sizeof(struct window_node));\n        view_update(view);\n    }\n}\n"
  },
  {
    "path": "src/view.h",
    "content": "#ifndef VIEW_H\n#define VIEW_H\n\n#define AX_ABS(a, b) (((a) - (b) < 0) ? (((a) - (b)) * -1) : ((a) - (b)))\n#define AX_DIFF(a, b) (AX_ABS(a, b) >= 1.5f)\n\n#define SPACE_PROPERTY_LIST \\\n    SPACE_PROPERTY_ENTRY(\"id\",                   SPACE_PROPERTY_ID,            0x001) \\\n    SPACE_PROPERTY_ENTRY(\"uuid\",                 SPACE_PROPERTY_UUID,          0x002) \\\n    SPACE_PROPERTY_ENTRY(\"index\",                SPACE_PROPERTY_INDEX,         0x004) \\\n    SPACE_PROPERTY_ENTRY(\"label\",                SPACE_PROPERTY_LABEL,         0x008) \\\n    SPACE_PROPERTY_ENTRY(\"type\",                 SPACE_PROPERTY_TYPE,          0x010) \\\n    SPACE_PROPERTY_ENTRY(\"display\",              SPACE_PROPERTY_DISPLAY,       0x020) \\\n    SPACE_PROPERTY_ENTRY(\"windows\",              SPACE_PROPERTY_WINDOWS,       0x040) \\\n    SPACE_PROPERTY_ENTRY(\"first-window\",         SPACE_PROPERTY_FIRST_WINDOW,  0x080) \\\n    SPACE_PROPERTY_ENTRY(\"last-window\",          SPACE_PROPERTY_LAST_WINDOW,   0x100) \\\n    SPACE_PROPERTY_ENTRY(\"has-focus\",            SPACE_PROPERTY_HAS_FOCUS,     0x200) \\\n    SPACE_PROPERTY_ENTRY(\"is-visible\",           SPACE_PROPERTY_IS_VISIBLE,    0x400) \\\n    SPACE_PROPERTY_ENTRY(\"is-native-fullscreen\", SPACE_PROPERTY_IS_FULLSCREEN, 0x800)\n\nenum space_property\n{\n#define SPACE_PROPERTY_ENTRY(n, p, v) p = v,\n    SPACE_PROPERTY_LIST\n#undef SPACE_PROPERTY_ENTRY\n};\n\nstatic uint64_t space_property_val[] =\n{\n#define SPACE_PROPERTY_ENTRY(n, p, v) p,\n    SPACE_PROPERTY_LIST\n#undef SPACE_PROPERTY_ENTRY\n};\n\nstatic char *space_property_str[] =\n{\n#define SPACE_PROPERTY_ENTRY(n, p, v) n,\n    SPACE_PROPERTY_LIST\n#undef SPACE_PROPERTY_ENTRY\n};\n\nstruct area\n{\n    float x;\n    float y;\n    float w;\n    float h;\n};\n\nstruct window;\nstruct window_capture\n{\n    struct window *window;\n    float x, y, w, h;\n};\n\nstruct window_proxy\n{\n    uint32_t id;\n    CGContextRef context;\n    float tx, ty, tw, th;\n    CGRect frame;\n    int level;\n    int sub_level;\n    CGImageRef image;\n};\n\nstruct window_animation\n{\n    struct window *window;\n    uint32_t wid;\n    float x, y, w, h;\n    int cid;\n    struct window_proxy proxy;\n    volatile bool skip;\n};\n\nstruct window_animation_context\n{\n    int animation_connection;\n    int animation_easing;\n    float animation_duration;\n    uint64_t animation_clock;\n    struct window_animation *animation_list;\n    int animation_count;\n};\n\nstruct balance_node\n{\n    int y_count;\n    int x_count;\n};\n\nenum window_insertion_point\n{\n    INSERT_FOCUSED,\n    INSERT_FIRST,\n    INSERT_LAST\n};\n\nstatic const char *window_insertion_point_str[] =\n{\n    \"focused\",\n    \"first\",\n    \"last\"\n};\n\nenum window_node_child\n{\n    CHILD_NONE,\n    CHILD_SECOND,\n    CHILD_FIRST,\n};\n\nstatic const char *window_node_child_str[] =\n{\n    \"none\",\n    \"second_child\",\n    \"first_child\"\n};\n\nenum window_node_split\n{\n    SPLIT_NONE,\n    SPLIT_Y,\n    SPLIT_X,\n    SPLIT_AUTO\n};\n\nstatic const char *window_node_split_str[] =\n{\n    \"none\",\n    \"vertical\",\n    \"horizontal\",\n    \"auto\"\n};\n\nstatic const char *auto_balance_str[] = {\n    \"off\",\n    \"vertical\",\n    \"horizontal\",\n    \"on\"\n};\n\nstruct feedback_window\n{\n    uint32_t id;\n    CGContextRef context;\n};\n\n#define NODE_MAX_WINDOW_COUNT 32\nstruct window_node\n{\n    struct area area;\n    struct window_node *parent;\n    struct window_node *left;\n    struct window_node *right;\n    struct window_node *zoom;\n    uint32_t window_list[NODE_MAX_WINDOW_COUNT];\n    uint32_t window_order[NODE_MAX_WINDOW_COUNT];\n    int window_count;\n    float ratio;\n    enum window_node_split split;\n    enum window_node_child child;\n    int insert_dir;\n    struct feedback_window feedback_window;\n};\n\nenum view_type\n{\n    VIEW_DEFAULT,\n    VIEW_BSP,\n    VIEW_STACK,\n    VIEW_FLOAT\n};\n\nstatic const char *view_type_str[] =\n{\n    \"default\",\n    \"bsp\",\n    \"stack\",\n    \"float\"\n};\n\nenum view_flag\n{\n    VIEW_LAYOUT         = 0x001,\n    VIEW_TOP_PADDING    = 0x002,\n    VIEW_BOTTOM_PADDING = 0x004,\n    VIEW_LEFT_PADDING   = 0x008,\n    VIEW_RIGHT_PADDING  = 0x010,\n    VIEW_WINDOW_GAP     = 0x020,\n    VIEW_AUTO_BALANCE   = 0x040,\n    VIEW_ENABLE_PADDING = 0x080,\n    VIEW_ENABLE_GAP     = 0x100,\n    VIEW_IS_VALID       = 0x200,\n    VIEW_IS_DIRTY       = 0x400,\n    VIEW_SPLIT_TYPE     = 0x800,\n};\n\nstruct view\n{\n    CFStringRef uuid;\n    uint64_t sid;\n    struct window_node *root;\n    uint32_t insertion_point;\n    enum view_type layout;\n    enum window_node_split split_type;\n    int top_padding;\n    int bottom_padding;\n    int left_padding;\n    int right_padding;\n    int window_gap;\n    uint32_t auto_balance;\n    uint64_t flags;\n};\n\n#define view_check_flag(v, x) ((v)->flags  &  (x))\n#define view_clear_flag(v, x) ((v)->flags &= ~(x))\n#define view_set_flag(v, x)   ((v)->flags |=  (x))\n\nvoid insert_feedback_show(struct window_node *node);\nvoid insert_feedback_destroy(struct window_node *node);\n\nvoid window_node_flush(struct window_node *node);\nvoid window_node_update(struct view *view, struct window_node *node);\nbool window_node_contains_window(struct window_node *node, uint32_t window_id);\nint window_node_index_of_window(struct window_node *node, uint32_t window_id);\nvoid window_node_swap_window_list(struct window_node *a_node, struct window_node *b_node);\nstruct window_node *window_node_find_first_leaf(struct window_node *root);\nstruct window_node *window_node_find_last_leaf(struct window_node *root);\nstruct window_node *window_node_find_prev_leaf(struct window_node *node);\nstruct window_node *window_node_find_next_leaf(struct window_node *node);\nvoid window_node_capture_windows(struct window_node *node, struct window_capture **window_list);\n\nstruct window_node *view_find_window_node_in_direction(struct view *view, struct window_node *source, int direction);\nstruct window_node *view_find_window_node(struct view *view, uint32_t window_id);\nvoid view_stack_window_node(struct window_node *node, struct window *window);\nstruct window_node *view_add_window_node_with_insertion_point(struct view *view, struct window *window, uint32_t insertion_point);\nstruct window_node *view_add_window_node(struct view *view, struct window *window);\nstruct window_node *view_remove_window_node(struct view *view, struct window *window);\nuint32_t *view_find_window_list(struct view *view, int *window_count);\n\nvoid view_serialize(FILE *rsp, struct view *view, uint64_t flags);\nbool view_is_invalid(struct view *view);\nbool view_is_dirty(struct view *view);\nvoid view_flush(struct view *view);\nvoid view_update(struct view *view);\nstruct view *view_create(uint64_t sid);\nvoid view_destroy(struct view *view);\nvoid view_clear(struct view *view);\n\n#endif\n"
  },
  {
    "path": "src/window.c",
    "content": "extern struct window_manager g_window_manager;\nextern int g_layer_normal_window_level;\nextern int g_layer_below_window_level;\nextern int g_layer_above_window_level;\nextern int g_connection;\n\nbool window_observe(struct window *window)\n{\n    for (int i = 0; i < array_count(ax_window_notification); ++i) {\n        AXError result = AXObserverAddNotification(window->application->observer_ref, window->ref, ax_window_notification[i], window);\n        if (result == kAXErrorSuccess || result == kAXErrorNotificationAlreadyRegistered) {\n            window->notification |= 1 << i;\n        } else {\n            debug(\"%s: %s failed with error %s\\n\", __FUNCTION__, ax_window_notification_str[i], ax_error_str[-result]);\n        }\n    }\n\n    return (window->notification & AX_WINDOW_ALL) == AX_WINDOW_ALL;\n}\n\nvoid window_unobserve(struct window *window)\n{\n    for (int i = 0; i < array_count(ax_window_notification); ++i) {\n        if (!(window->notification & (1 << i))) continue;\n\n        AXObserverRemoveNotification(window->application->observer_ref, window->ref, ax_window_notification[i]);\n        window->notification &= ~(1 << i);\n    }\n}\n\nCFStringRef window_display_uuid(uint32_t wid)\n{\n    CFStringRef uuid = SLSCopyManagedDisplayForWindow(g_connection, wid);\n    if (!uuid) {\n        CGRect frame;\n        SLSGetWindowBounds(g_connection, wid, &frame);\n        uuid = SLSCopyBestManagedDisplayForRect(g_connection, frame);\n    }\n    return uuid;\n}\n\nuint32_t window_display_id(uint32_t wid)\n{\n    CFStringRef uuid_string = window_display_uuid(wid);\n    if (!uuid_string) return 0;\n\n    CFUUIDRef uuid = CFUUIDCreateFromString(NULL, uuid_string);\n    int id = CGDisplayGetDisplayIDFromUUID(uuid);\n\n    CFRelease(uuid);\n    CFRelease(uuid_string);\n\n    return id;\n}\n\nstatic uint64_t window_display_space(uint32_t wid)\n{\n    CFStringRef uuid = window_display_uuid(wid);\n    if (!uuid) return 0;\n\n    uint64_t sid = SLSManagedDisplayGetCurrentSpace(g_connection, uuid);\n    CFRelease(uuid);\n\n    return sid;\n}\n\nuint64_t window_space(uint32_t wid)\n{\n    uint64_t sid = 0;\n\n    CFArrayRef window_list_ref = cfarray_of_cfnumbers(&wid, sizeof(uint32_t), 1, kCFNumberSInt32Type);\n    CFArrayRef space_list_ref = SLSCopySpacesForWindows(g_connection, 0x7, window_list_ref);\n    if (!space_list_ref) goto err;\n\n    int count = CFArrayGetCount(space_list_ref);\n    if (!count) goto free;\n\n    CFNumberRef id_ref = CFArrayGetValueAtIndex(space_list_ref, 0);\n    CFNumberGetValue(id_ref, CFNumberGetType(id_ref), &sid);\n\nfree:\n    CFRelease(space_list_ref);\nerr:\n    CFRelease(window_list_ref);\n\n    return sid ? sid : window_display_space(wid);\n}\n\nuint64_t *window_space_list(uint32_t wid, int *count)\n{\n    uint64_t *space_list = NULL;\n    CFArrayRef window_list_ref = cfarray_of_cfnumbers(&wid, sizeof(uint32_t), 1, kCFNumberSInt32Type);\n    CFArrayRef space_list_ref = SLSCopySpacesForWindows(g_connection, 0x7, window_list_ref);\n    if (!space_list_ref) goto err;\n\n    *count = CFArrayGetCount(space_list_ref);\n    if (!*count) goto out;\n\n    space_list = ts_alloc_list(uint64_t, *count);\n\n    for (int i = 0; i < *count; ++i) {\n        CFNumberRef id_ref = CFArrayGetValueAtIndex(space_list_ref, i);\n        CFNumberGetValue(id_ref, CFNumberGetType(id_ref), space_list + i);\n    }\n\nout:\n    CFRelease(space_list_ref);\nerr:\n    CFRelease(window_list_ref);\n    return space_list;\n}\n\nstatic inline const char *window_layer(int level)\n{\n    if (level == g_layer_below_window_level)  return layer_str[LAYER_BELOW];\n    if (level == g_layer_normal_window_level) return layer_str[LAYER_NORMAL];\n    if (level == g_layer_above_window_level)  return layer_str[LAYER_ABOVE];\n    return \"unknown\";\n}\n\nvoid window_nonax_serialize(FILE *rsp, uint32_t wid, uint64_t flags)\n{\n    TIME_FUNCTION;\n\n    if (flags == 0x0) flags |= ~flags;\n\n    int connection;\n    pid_t pid;\n    uint64_t sid;\n    int level;\n    int sub_level;\n\n    if ((flags & WINDOW_PROPERTY_PID) ||\n        (flags & WINDOW_PROPERTY_APP)) {\n        SLSGetWindowOwner(g_connection, wid, &connection);\n        SLSConnectionGetPID(connection, &pid);\n    }\n\n    if ((flags & WINDOW_PROPERTY_DISPLAY) ||\n        (flags & WINDOW_PROPERTY_SPACE) ||\n        (flags & WINDOW_PROPERTY_IS_FULLSCREEN)) {\n        sid = window_space(wid);\n    }\n\n    if ((flags & WINDOW_PROPERTY_LEVEL) ||\n        (flags & WINDOW_PROPERTY_LAYER)) {\n        level = window_level(wid);\n    }\n\n    if ((flags & WINDOW_PROPERTY_SUB_LEVEL) ||\n        (flags & WINDOW_PROPERTY_SUB_LAYER)) {\n        sub_level = window_sub_level(wid);\n    }\n\n    bool did_output = false;\n    fprintf(rsp, \"{\\n\");\n\n    if (flags & WINDOW_PROPERTY_ID) {\n        fprintf(rsp, \"\\t\\\"id\\\":%d\", wid);\n        did_output = true;\n    }\n\n    if (flags & WINDOW_PROPERTY_PID) {\n        if (did_output) fprintf(rsp, \",\\n\");\n\n        fprintf(rsp, \"\\t\\\"pid\\\":%d\", pid);\n        did_output = true;\n    }\n\n    if (flags & WINDOW_PROPERTY_APP) {\n        if (did_output) fprintf(rsp, \",\\n\");\n\n        static char process_name[PROC_PIDPATHINFO_MAXSIZE];\n        proc_name(pid, process_name, sizeof(process_name));\n\n        char *app = process_name;\n        char *escaped_app = ts_string_escape(app);\n\n        fprintf(rsp, \"\\t\\\"app\\\":\\\"%s\\\"\", escaped_app ? escaped_app : app);\n        did_output = true;\n    }\n\n    if (flags & WINDOW_PROPERTY_TITLE) {\n        if (did_output) fprintf(rsp, \",\\n\");\n\n        char *title = window_property_title_ts(wid);\n        char *escaped_title = ts_string_escape(title);\n\n        fprintf(rsp, \"\\t\\\"title\\\":\\\"%s\\\"\", escaped_title ? escaped_title : title);\n        did_output = true;\n    }\n\n    if (flags & WINDOW_PROPERTY_SCRATCHPAD) {\n        if (did_output) fprintf(rsp, \",\\n\");\n\n        fprintf(rsp, \"\\t\\\"scratchpad\\\":\\\"%s\\\"\", \"\");\n        did_output = true;\n    }\n\n    if (flags & WINDOW_PROPERTY_FRAME) {\n        if (did_output) fprintf(rsp, \",\\n\");\n\n        CGRect frame;\n        SLSGetWindowBounds(g_connection, wid, &frame);\n\n        fprintf(rsp, \"\\t\\\"frame\\\":{\\n\\t\\t\\\"x\\\":%.4f,\\n\\t\\t\\\"y\\\":%.4f,\\n\\t\\t\\\"w\\\":%.4f,\\n\\t\\t\\\"h\\\":%.4f\\n\\t}\", frame.origin.x, frame.origin.y, frame.size.width, frame.size.height);\n        did_output = true;\n    }\n\n    if (flags & WINDOW_PROPERTY_ROLE) {\n        if (did_output) fprintf(rsp, \",\\n\");\n\n        fprintf(rsp, \"\\t\\\"role\\\":\\\"%s\\\"\", \"\");\n        did_output = true;\n    }\n\n    if (flags & WINDOW_PROPERTY_SUBROLE) {\n        if (did_output) fprintf(rsp, \",\\n\");\n\n        fprintf(rsp, \"\\t\\\"subrole\\\":\\\"%s\\\"\", \"\");\n        did_output = true;\n    }\n\n    if (flags & WINDOW_PROPERTY_ROOT_WINDOW) {\n        if (did_output) fprintf(rsp, \",\\n\");\n\n        uint32_t parent_wid = window_parent(wid);\n        fprintf(rsp, \"\\t\\\"root-window\\\":%s\", json_bool(parent_wid == 0));\n        did_output = true;\n    }\n\n    if (flags & WINDOW_PROPERTY_DISPLAY) {\n        if (did_output) fprintf(rsp, \",\\n\");\n\n        int display = display_manager_display_id_arrangement(space_display_id(sid));\n        fprintf(rsp, \"\\t\\\"display\\\":%d\", display);\n        did_output = true;\n    }\n\n    if (flags & WINDOW_PROPERTY_SPACE) {\n        if (did_output) fprintf(rsp, \",\\n\");\n\n        int space = space_manager_mission_control_index(sid);\n        fprintf(rsp, \"\\t\\\"space\\\":%d\", space);\n        did_output = true;\n    }\n\n    if (flags & WINDOW_PROPERTY_LEVEL) {\n        if (did_output) fprintf(rsp, \",\\n\");\n\n        fprintf(rsp, \"\\t\\\"level\\\":%d\", level);\n        did_output = true;\n    }\n\n    if (flags & WINDOW_PROPERTY_SUB_LEVEL) {\n        if (did_output) fprintf(rsp, \",\\n\");\n\n        fprintf(rsp, \"\\t\\\"sub-level\\\":%d\", sub_level);\n        did_output = true;\n    }\n\n    if (flags & WINDOW_PROPERTY_LAYER) {\n        if (did_output) fprintf(rsp, \",\\n\");\n\n        const char *layer = window_layer(level);\n        fprintf(rsp, \"\\t\\\"layer\\\":\\\"%s\\\"\", layer);\n        did_output = true;\n    }\n\n    if (flags & WINDOW_PROPERTY_SUB_LAYER) {\n        if (did_output) fprintf(rsp, \",\\n\");\n\n        const char *sub_layer = window_layer(sub_level);\n        fprintf(rsp, \"\\t\\\"sub-layer\\\":\\\"%s\\\"\", sub_layer);\n        did_output = true;\n    }\n\n    if (flags & WINDOW_PROPERTY_OPACITY) {\n        if (did_output) fprintf(rsp, \",\\n\");\n\n        float opacity = window_opacity(wid);\n        fprintf(rsp, \"\\t\\\"opacity\\\":%.4f\", opacity);\n        did_output = true;\n    }\n\n    if (flags & WINDOW_PROPERTY_SPLIT_TYPE) {\n        if (did_output) fprintf(rsp, \",\\n\");\n\n        fprintf(rsp, \"\\t\\\"split-type\\\":\\\"%s\\\"\", window_node_split_str[0]);\n        did_output = true;\n    }\n\n    if (flags & WINDOW_PROPERTY_SPLIT_CHILD) {\n        if (did_output) fprintf(rsp, \",\\n\");\n\n        fprintf(rsp, \"\\t\\\"split-child\\\":\\\"%s\\\"\", window_node_child_str[CHILD_NONE]);\n        did_output = true;\n    }\n\n    if (flags & WINDOW_PROPERTY_STACK_INDEX) {\n        if (did_output) fprintf(rsp, \",\\n\");\n\n        fprintf(rsp, \"\\t\\\"stack-index\\\":%d\", 0);\n        did_output = true;\n    }\n\n    if (flags & WINDOW_PROPERTY_CAN_MOVE) {\n        if (did_output) fprintf(rsp, \",\\n\");\n\n        fprintf(rsp, \"\\t\\\"can-move\\\":%s\", json_bool(false));\n        did_output = true;\n    }\n\n    if (flags & WINDOW_PROPERTY_CAN_RESIZE) {\n        if (did_output) fprintf(rsp, \",\\n\");\n\n        fprintf(rsp, \"\\t\\\"can-resize\\\":%s\", json_bool(false));\n        did_output = true;\n    }\n\n    if (flags & WINDOW_PROPERTY_HAS_FOCUS) {\n        if (did_output) fprintf(rsp, \",\\n\");\n\n        fprintf(rsp, \"\\t\\\"has-focus\\\":%s\", json_bool(false));\n        did_output = true;\n    }\n\n    if (flags & WINDOW_PROPERTY_HAS_SHADOW) {\n        if (did_output) fprintf(rsp, \",\\n\");\n\n        fprintf(rsp, \"\\t\\\"has-shadow\\\":%s\", json_bool(window_shadow(wid)));\n        did_output = true;\n    }\n\n    if (flags & WINDOW_PROPERTY_HAS_PARENT_ZOOM) {\n        if (did_output) fprintf(rsp, \",\\n\");\n\n        fprintf(rsp, \"\\t\\\"has-parent-zoom\\\":%s\", json_bool(false));\n        did_output = true;\n    }\n\n    if (flags & WINDOW_PROPERTY_HAS_FULLSCREEN_ZOOM) {\n        if (did_output) fprintf(rsp, \",\\n\");\n\n        fprintf(rsp, \"\\t\\\"has-fullscreen-zoom\\\":%s\", json_bool(false));\n        did_output = true;\n    }\n\n    if (flags & WINDOW_PROPERTY_HAS_AX_REFERENCE) {\n        if (did_output) fprintf(rsp, \",\\n\");\n\n        fprintf(rsp, \"\\t\\\"has-ax-reference\\\":%s\", json_bool(false));\n        did_output = true;\n    }\n\n    if (flags & WINDOW_PROPERTY_IS_FULLSCREEN) {\n        if (did_output) fprintf(rsp, \",\\n\");\n\n        bool is_fullscreen = space_is_fullscreen(sid);\n        fprintf(rsp, \"\\t\\\"is-native-fullscreen\\\":%s\", json_bool(is_fullscreen));\n        did_output = true;\n    }\n\n    if (flags & WINDOW_PROPERTY_IS_VISIBLE) {\n        if (did_output) fprintf(rsp, \",\\n\");\n\n        fprintf(rsp, \"\\t\\\"is-visible\\\":%s\", json_bool(false));\n        did_output = true;\n    }\n\n    if (flags & WINDOW_PROPERTY_IS_MINIMIZED) {\n        if (did_output) fprintf(rsp, \",\\n\");\n\n        fprintf(rsp, \"\\t\\\"is-minimized\\\":%s\", json_bool(false));\n        did_output = true;\n    }\n\n    if (flags & WINDOW_PROPERTY_IS_HIDDEN) {\n        if (did_output) fprintf(rsp, \",\\n\");\n\n        fprintf(rsp, \"\\t\\\"is-hidden\\\":%s\", json_bool(false));\n        did_output = true;\n    }\n\n    if (flags & WINDOW_PROPERTY_IS_FLOATING) {\n        if (did_output) fprintf(rsp, \",\\n\");\n\n        fprintf(rsp, \"\\t\\\"is-floating\\\":%s\", json_bool(false));\n        did_output = true;\n    }\n\n    if (flags & WINDOW_PROPERTY_IS_STICKY) {\n        if (did_output) fprintf(rsp, \",\\n\");\n\n        bool is_sticky = window_is_sticky(wid);\n        fprintf(rsp, \"\\t\\\"is-sticky\\\":%s\", json_bool(is_sticky));\n        did_output = true;\n    }\n\n    if (flags & WINDOW_PROPERTY_IS_GRABBED) {\n        if (did_output) fprintf(rsp, \",\\n\");\n\n        fprintf(rsp, \"\\t\\\"is-grabbed\\\":%s\", json_bool(false));\n    }\n\n    fprintf(rsp, \"\\n}\");\n}\n\nvoid window_serialize(FILE *rsp, struct window *window, uint64_t flags)\n{\n    TIME_FUNCTION;\n\n    if (flags == 0x0) flags |= ~flags;\n\n    uint64_t sid;\n    int level;\n    int sub_level;\n    struct view *view;\n    struct window_node *node;\n    bool is_minimized;\n    bool is_sticky;\n\n    if ((flags & WINDOW_PROPERTY_DISPLAY) ||\n        (flags & WINDOW_PROPERTY_SPACE) ||\n        (flags & WINDOW_PROPERTY_IS_VISIBLE)) {\n        sid = window_space(window->id);\n    }\n\n    if ((flags & WINDOW_PROPERTY_LEVEL) ||\n        (flags & WINDOW_PROPERTY_LAYER)) {\n        level = window_level(window->id);\n    }\n\n    if ((flags & WINDOW_PROPERTY_SUB_LEVEL) ||\n        (flags & WINDOW_PROPERTY_SUB_LAYER)) {\n        sub_level = window_sub_level(window->id);\n    }\n\n    if ((flags & WINDOW_PROPERTY_SPLIT_TYPE) ||\n        (flags & WINDOW_PROPERTY_SPLIT_CHILD) ||\n        (flags & WINDOW_PROPERTY_STACK_INDEX) ||\n        (flags & WINDOW_PROPERTY_HAS_PARENT_ZOOM) ||\n        (flags & WINDOW_PROPERTY_HAS_FULLSCREEN_ZOOM)) {\n        view = window_manager_find_managed_window(&g_window_manager, window);\n        node = view ? view_find_window_node(view, window->id) : NULL;\n    }\n\n    if ((flags & WINDOW_PROPERTY_IS_VISIBLE) ||\n        (flags & WINDOW_PROPERTY_IS_MINIMIZED)) {\n        is_minimized = window_check_flag(window, WINDOW_MINIMIZE);\n    }\n\n    if ((flags & WINDOW_PROPERTY_IS_VISIBLE) ||\n        (flags & WINDOW_PROPERTY_IS_STICKY)) {\n        is_sticky = window_check_flag(window, WINDOW_STICKY) || window_is_sticky(window->id);\n    }\n\n    bool did_output = false;\n    fprintf(rsp, \"{\\n\");\n\n    if (flags & WINDOW_PROPERTY_ID) {\n        fprintf(rsp, \"\\t\\\"id\\\":%d\", window->id);\n        did_output = true;\n    }\n\n    if (flags & WINDOW_PROPERTY_PID) {\n        if (did_output) fprintf(rsp, \",\\n\");\n\n        fprintf(rsp, \"\\t\\\"pid\\\":%d\", window->application->pid);\n        did_output = true;\n    }\n\n    if (flags & WINDOW_PROPERTY_APP) {\n        if (did_output) fprintf(rsp, \",\\n\");\n\n        char *app = window->application->name;\n        char *escaped_app = ts_string_escape(app);\n\n        fprintf(rsp, \"\\t\\\"app\\\":\\\"%s\\\"\", escaped_app ? escaped_app : app);\n        did_output = true;\n    }\n\n    if (flags & WINDOW_PROPERTY_TITLE) {\n        if (did_output) fprintf(rsp, \",\\n\");\n\n        char *title = window_title_ts(window);\n        char *escaped_title = ts_string_escape(title);\n\n        fprintf(rsp, \"\\t\\\"title\\\":\\\"%s\\\"\", escaped_title ? escaped_title : title);\n        did_output = true;\n    }\n\n    if (flags & WINDOW_PROPERTY_SCRATCHPAD) {\n        if (did_output) fprintf(rsp, \",\\n\");\n\n        fprintf(rsp, \"\\t\\\"scratchpad\\\":\\\"%s\\\"\", window->scratchpad ? window->scratchpad : \"\");\n        did_output = true;\n    }\n\n    if (flags & WINDOW_PROPERTY_FRAME) {\n        if (did_output) fprintf(rsp, \",\\n\");\n\n        fprintf(rsp, \"\\t\\\"frame\\\":{\\n\\t\\t\\\"x\\\":%.4f,\\n\\t\\t\\\"y\\\":%.4f,\\n\\t\\t\\\"w\\\":%.4f,\\n\\t\\t\\\"h\\\":%.4f\\n\\t}\", window->frame.origin.x, window->frame.origin.y, window->frame.size.width, window->frame.size.height);\n        did_output = true;\n    }\n\n    if (flags & WINDOW_PROPERTY_ROLE) {\n        if (did_output) fprintf(rsp, \",\\n\");\n\n        char *role = window_role_ts(window);\n        fprintf(rsp, \"\\t\\\"role\\\":\\\"%s\\\"\", role);\n        did_output = true;\n    }\n\n    if (flags & WINDOW_PROPERTY_SUBROLE) {\n        if (did_output) fprintf(rsp, \",\\n\");\n\n        char *subrole = window_subrole_ts(window);\n        fprintf(rsp, \"\\t\\\"subrole\\\":\\\"%s\\\"\", subrole);\n        did_output = true;\n    }\n\n    if (flags & WINDOW_PROPERTY_ROOT_WINDOW) {\n        if (did_output) fprintf(rsp, \",\\n\");\n\n        fprintf(rsp, \"\\t\\\"root-window\\\":%s\", json_bool(window->is_root));\n        did_output = true;\n    }\n\n    if (flags & WINDOW_PROPERTY_DISPLAY) {\n        if (did_output) fprintf(rsp, \",\\n\");\n\n        int display = display_manager_display_id_arrangement(space_display_id(sid));\n        fprintf(rsp, \"\\t\\\"display\\\":%d\", display);\n        did_output = true;\n    }\n\n    if (flags & WINDOW_PROPERTY_SPACE) {\n        if (did_output) fprintf(rsp, \",\\n\");\n\n        int space = space_manager_mission_control_index(sid);\n        fprintf(rsp, \"\\t\\\"space\\\":%d\", space);\n        did_output = true;\n    }\n\n    if (flags & WINDOW_PROPERTY_LEVEL) {\n        if (did_output) fprintf(rsp, \",\\n\");\n\n        fprintf(rsp, \"\\t\\\"level\\\":%d\", level);\n        did_output = true;\n    }\n\n    if (flags & WINDOW_PROPERTY_SUB_LEVEL) {\n        if (did_output) fprintf(rsp, \",\\n\");\n\n        fprintf(rsp, \"\\t\\\"sub-level\\\":%d\", sub_level);\n        did_output = true;\n    }\n\n    if (flags & WINDOW_PROPERTY_LAYER) {\n        if (did_output) fprintf(rsp, \",\\n\");\n\n        const char *layer = window_layer(level);\n        fprintf(rsp, \"\\t\\\"layer\\\":\\\"%s\\\"\", layer);\n        did_output = true;\n    }\n\n    if (flags & WINDOW_PROPERTY_SUB_LAYER) {\n        if (did_output) fprintf(rsp, \",\\n\");\n\n        const char *sub_layer = window_layer(sub_level);\n        fprintf(rsp, \"\\t\\\"sub-layer\\\":\\\"%s\\\"\", sub_layer);\n        did_output = true;\n    }\n\n    if (flags & WINDOW_PROPERTY_OPACITY) {\n        if (did_output) fprintf(rsp, \",\\n\");\n\n        float opacity = window_opacity(window->id);\n        fprintf(rsp, \"\\t\\\"opacity\\\":%.4f\", opacity);\n        did_output = true;\n    }\n\n    if (flags & WINDOW_PROPERTY_SPLIT_TYPE) {\n        if (did_output) fprintf(rsp, \",\\n\");\n\n        fprintf(rsp, \"\\t\\\"split-type\\\":\\\"%s\\\"\", window_node_split_str[node && node->parent ? node->parent->split : 0]);\n        did_output = true;\n    }\n\n    if (flags & WINDOW_PROPERTY_SPLIT_CHILD) {\n        if (did_output) fprintf(rsp, \",\\n\");\n\n        fprintf(rsp, \"\\t\\\"split-child\\\":\\\"%s\\\"\", window_node_child_str[node ? window_node_is_left_child(node) ? CHILD_FIRST : CHILD_SECOND : CHILD_NONE]);\n        did_output = true;\n    }\n\n    if (flags & WINDOW_PROPERTY_STACK_INDEX) {\n        if (did_output) fprintf(rsp, \",\\n\");\n\n        int stack_index = node && node->window_count > 1 ? window_node_index_of_window(node, window->id)+1 : 0;\n        fprintf(rsp, \"\\t\\\"stack-index\\\":%d\", stack_index);\n        did_output = true;\n    }\n\n    if (flags & WINDOW_PROPERTY_CAN_MOVE) {\n        if (did_output) fprintf(rsp, \",\\n\");\n\n        fprintf(rsp, \"\\t\\\"can-move\\\":%s\", json_bool(window_can_move(window)));\n        did_output = true;\n    }\n\n    if (flags & WINDOW_PROPERTY_CAN_RESIZE) {\n        if (did_output) fprintf(rsp, \",\\n\");\n\n        fprintf(rsp, \"\\t\\\"can-resize\\\":%s\", json_bool(window_can_resize(window)));\n        did_output = true;\n    }\n\n    if (flags & WINDOW_PROPERTY_HAS_FOCUS) {\n        if (did_output) fprintf(rsp, \",\\n\");\n\n        fprintf(rsp, \"\\t\\\"has-focus\\\":%s\", json_bool(window->id == g_window_manager.focused_window_id));\n        did_output = true;\n    }\n\n    if (flags & WINDOW_PROPERTY_HAS_SHADOW) {\n        if (did_output) fprintf(rsp, \",\\n\");\n\n        fprintf(rsp, \"\\t\\\"has-shadow\\\":%s\", json_bool(window_shadow(window->id)));\n        did_output = true;\n    }\n\n    if (flags & WINDOW_PROPERTY_HAS_PARENT_ZOOM) {\n        if (did_output) fprintf(rsp, \",\\n\");\n\n        bool zoom_parent = node && node->zoom && node->zoom == node->parent;\n        fprintf(rsp, \"\\t\\\"has-parent-zoom\\\":%s\", json_bool(zoom_parent));\n        did_output = true;\n    }\n\n    if (flags & WINDOW_PROPERTY_HAS_FULLSCREEN_ZOOM) {\n        if (did_output) fprintf(rsp, \",\\n\");\n\n        bool zoom_fullscreen = node && node->zoom && node->zoom == view->root;\n        fprintf(rsp, \"\\t\\\"has-fullscreen-zoom\\\":%s\", json_bool(zoom_fullscreen));\n        did_output = true;\n    }\n\n    if (flags & WINDOW_PROPERTY_HAS_AX_REFERENCE) {\n        if (did_output) fprintf(rsp, \",\\n\");\n\n        fprintf(rsp, \"\\t\\\"has-ax-reference\\\":%s\", json_bool(true));\n        did_output = true;\n    }\n\n    if (flags & WINDOW_PROPERTY_IS_FULLSCREEN) {\n        if (did_output) fprintf(rsp, \",\\n\");\n\n        fprintf(rsp, \"\\t\\\"is-native-fullscreen\\\":%s\", json_bool(window_check_flag(window, WINDOW_FULLSCREEN)));\n        did_output = true;\n    }\n\n    if (flags & WINDOW_PROPERTY_IS_VISIBLE) {\n        if (did_output) fprintf(rsp, \",\\n\");\n\n        uint8_t ordered_in = 0;\n        SLSWindowIsOrderedIn(g_connection, window->id, &ordered_in);\n\n        bool visible = ordered_in && !is_minimized && !window->application->is_hidden && (is_sticky || space_is_visible(sid));\n        fprintf(rsp, \"\\t\\\"is-visible\\\":%s\", json_bool(visible));\n        did_output = true;\n    }\n\n    if (flags & WINDOW_PROPERTY_IS_MINIMIZED) {\n        if (did_output) fprintf(rsp, \",\\n\");\n\n        fprintf(rsp, \"\\t\\\"is-minimized\\\":%s\", json_bool(is_minimized));\n        did_output = true;\n    }\n\n    if (flags & WINDOW_PROPERTY_IS_HIDDEN) {\n        if (did_output) fprintf(rsp, \",\\n\");\n\n        fprintf(rsp, \"\\t\\\"is-hidden\\\":%s\", json_bool(window->application->is_hidden));\n        did_output = true;\n    }\n\n    if (flags & WINDOW_PROPERTY_IS_FLOATING) {\n        if (did_output) fprintf(rsp, \",\\n\");\n\n        fprintf(rsp, \"\\t\\\"is-floating\\\":%s\", json_bool(window_check_flag(window, WINDOW_FLOAT)));\n        did_output = true;\n    }\n\n    if (flags & WINDOW_PROPERTY_IS_STICKY) {\n        if (did_output) fprintf(rsp, \",\\n\");\n\n        fprintf(rsp, \"\\t\\\"is-sticky\\\":%s\", json_bool(is_sticky));\n        did_output = true;\n    }\n\n    if (flags & WINDOW_PROPERTY_IS_GRABBED) {\n        if (did_output) fprintf(rsp, \",\\n\");\n\n        bool grabbed = window == g_mouse_state.window;\n        fprintf(rsp, \"\\t\\\"is-grabbed\\\":%s\", json_bool(grabbed));\n    }\n\n    fprintf(rsp, \"\\n}\");\n}\n\nchar *window_property_title_ts(uint32_t wid)\n{\n    CFTypeRef value = NULL;\n    SLSCopyWindowProperty(g_connection, wid, CFSTR(\"kCGSWindowTitle\"), &value);\n    if (!value) return ts_string_copy(\"\");\n\n    char *result = ts_cfstring_copy(value);\n    CFRelease(value);\n    return result;\n}\n\nchar *window_title_ts(struct window *window)\n{\n    return window->title ? ts_cfstring_copy(window->title) : ts_string_copy(\"\");\n}\n\nCFStringRef window_title(struct window *window)\n{\n    CFTypeRef value = NULL;\n    AXUIElementCopyAttributeValue(window->ref, kAXTitleAttribute, &value);\n    return value;\n}\n\nCGPoint window_ax_origin(struct window *window)\n{\n    CGPoint origin = {0};\n    CFTypeRef position_ref = NULL;\n\n    AXUIElementCopyAttributeValue(window->ref, kAXPositionAttribute, &position_ref);\n\n    if (position_ref) {\n        AXValueGetValue(position_ref, kAXValueTypeCGPoint, &origin);\n        CFRelease(position_ref);\n    }\n\n    return origin;\n}\n\nCGRect window_ax_frame(struct window *window)\n{\n    CGRect frame = {0};\n    CFTypeRef position_ref = NULL;\n    CFTypeRef size_ref = NULL;\n\n    AXUIElementCopyAttributeValue(window->ref, kAXPositionAttribute, &position_ref);\n    AXUIElementCopyAttributeValue(window->ref, kAXSizeAttribute, &size_ref);\n\n    if (position_ref) {\n        AXValueGetValue(position_ref, kAXValueTypeCGPoint, &frame.origin);\n        CFRelease(position_ref);\n    }\n\n    if (size_ref) {\n        AXValueGetValue(size_ref, kAXValueTypeCGSize, &frame.size);\n        CFRelease(size_ref);\n    }\n\n    return frame;\n}\n\nbool window_ax_can_move(struct window *window)\n{\n    Boolean result;\n    if (AXUIElementIsAttributeSettable(window->ref, kAXPositionAttribute, &result) != kAXErrorSuccess) {\n        result = 0;\n    }\n    return result;\n}\n\nbool window_can_move(struct window *window)\n{\n    return window_check_flag(window, WINDOW_MOVABLE);\n}\n\nbool window_ax_can_resize(struct window *window)\n{\n    Boolean result;\n    if (AXUIElementIsAttributeSettable(window->ref, kAXSizeAttribute, &result) != kAXErrorSuccess) {\n        result = 0;\n    }\n    return result;\n}\n\nbool window_can_resize(struct window *window)\n{\n    return window_check_flag(window, WINDOW_RESIZABLE);\n}\n\nbool window_can_minimize(struct window *window)\n{\n    Boolean result;\n    if (AXUIElementIsAttributeSettable(window->ref, kAXMinimizedAttribute, &result) != kAXErrorSuccess) {\n        result = 0;\n    }\n    return result;\n}\n\nbool window_is_undersized(struct window *window)\n{\n    if (window->frame.size.width  <= 500.0f) return true;\n    if (window->frame.size.height <= 500.0f) return true;\n    return false;\n}\n\nstatic bool window_is_minimized(struct window *window)\n{\n    Boolean result = 0;\n    CFTypeRef value;\n\n    if (AXUIElementCopyAttributeValue(window->ref, kAXMinimizedAttribute, &value) == kAXErrorSuccess) {\n        result = CFBooleanGetValue(value);\n        CFRelease(value);\n    }\n\n    return result;\n}\n\nbool window_is_fullscreen(struct window *window)\n{\n    Boolean result = 0;\n    CFTypeRef value;\n\n    if (AXUIElementCopyAttributeValue(window->ref, kAXFullscreenAttribute, &value) == kAXErrorSuccess) {\n        result = CFBooleanGetValue(value);\n        CFRelease(value);\n    }\n\n    return result;\n}\n\nbool window_is_sticky(uint32_t wid)\n{\n    bool result = false;\n\n    CFArrayRef window_list_ref = cfarray_of_cfnumbers(&wid, sizeof(uint32_t), 1, kCFNumberSInt32Type);\n    CFArrayRef space_list_ref = SLSCopySpacesForWindows(g_connection, 0x7, window_list_ref);\n    if (!space_list_ref) goto err;\n\n    result = CFArrayGetCount(space_list_ref) > 1;\n    CFRelease(space_list_ref);\n\nerr:\n    CFRelease(window_list_ref);\n    return result;\n}\n\nbool window_shadow(uint32_t wid)\n{\n    uint64_t tags = window_tags(wid);\n    return !(tags & 0x8);\n}\n\nfloat window_opacity(uint32_t wid)\n{\n    float alpha = 0.0f;\n    SLSGetWindowAlpha(g_connection, wid, &alpha);\n    return alpha;\n}\n\nuint32_t window_parent(uint32_t wid)\n{\n    uint32_t parent_wid = 0;\n\n    CFArrayRef window_ref = cfarray_of_cfnumbers(&wid, sizeof(uint32_t), 1, kCFNumberSInt32Type);\n\n    CFTypeRef query = SLSWindowQueryWindows(g_connection, window_ref, 1);\n    if (!query) goto err2;\n\n    CFTypeRef iterator = SLSWindowQueryResultCopyWindows(query);\n    if (!iterator) goto err1;\n\n    if (SLSWindowIteratorGetCount(iterator) == 1) {\n        if (SLSWindowIteratorAdvance(iterator)) {\n            parent_wid = SLSWindowIteratorGetParentID(iterator);\n        }\n    }\n\n    CFRelease(iterator);\nerr1:\n    CFRelease(query);\nerr2:\n    CFRelease(window_ref);\n\n    return parent_wid;\n}\n\nint window_level(uint32_t wid)\n{\n    int level = 0;\n\n    if (workspace_is_macos_ventura() || workspace_is_macos_sonoma() || workspace_is_macos_sequoia() || workspace_is_macos_tahoe()) {\n        CFArrayRef window_ref = cfarray_of_cfnumbers(&wid, sizeof(uint32_t), 1, kCFNumberSInt32Type);\n\n        CFTypeRef query = SLSWindowQueryWindows(g_connection, window_ref, 1);\n        if (!query) goto err2;\n\n        CFTypeRef iterator = SLSWindowQueryResultCopyWindows(query);\n        if (!iterator) goto err1;\n\n        if (SLSWindowIteratorGetCount(iterator) == 1) {\n            if (SLSWindowIteratorAdvance(iterator)) {\n                level = SLSWindowIteratorGetLevel(iterator);\n            }\n        }\n\n        CFRelease(iterator);\n    err1:\n        CFRelease(query);\n    err2:\n        CFRelease(window_ref);\n    } else {\n        SLSGetWindowLevel(g_connection, wid, &level);\n    }\n\n    return level;\n}\n\nstatic int SLSGetWindowSubLevel__Internal(int cid, uint32_t wid)\n{\n    #pragma pack(push,4)\n    struct {\n        mach_msg_header_t header;\n        NDR_record_t NDR_record;\n        uint32_t window_id;\n        int32_t sub_level;\n        int32_t padding1;\n        int32_t padding2;\n    } msg = {0};\n    #pragma pack(pop)\n\n    msg.NDR_record = NDR_record;\n    msg.window_id = wid;\n    msg.header.msgh_bits = 0x1513;\n    msg.header.msgh_remote_port = CGSGetConnectionPortById(cid);\n    msg.header.msgh_local_port = mig_get_special_reply_port();\n    msg.header.msgh_id = workspace_is_macos_tahoe() ? 0x76E3 : 0x73C3;\n    mach_msg(&msg.header, MACH_SEND_MSG|MACH_RCV_MSG, 0x24, 0x30, msg.header.msgh_local_port, 0, 0);\n\n    return msg.sub_level;\n}\n\nint window_sub_level(uint32_t wid)\n{\n    if (CGSGetConnectionPortById) {\n        return SLSGetWindowSubLevel__Internal(g_connection, wid);\n    } else {\n        return SLSGetWindowSubLevel(g_connection, wid);\n    }\n}\n\nuint64_t window_tags(uint32_t wid)\n{\n    uint64_t tags = 0;\n    CFArrayRef window_ref = cfarray_of_cfnumbers(&wid, sizeof(uint32_t), 1, kCFNumberSInt32Type);\n\n    CFTypeRef query = SLSWindowQueryWindows(g_connection, window_ref, 1);\n    if (!query) goto err2;\n\n    CFTypeRef iterator = SLSWindowQueryResultCopyWindows(query);\n    if (!iterator) goto err1;\n\n    if (SLSWindowIteratorGetCount(iterator) == 1) {\n        if (SLSWindowIteratorAdvance(iterator)) {\n            tags = SLSWindowIteratorGetTags(iterator);\n        }\n    }\n\n    CFRelease(iterator);\nerr1:\n    CFRelease(query);\nerr2:\n    CFRelease(window_ref);\n\n    return tags;\n}\n\nCFStringRef window_ax_role(struct window *window)\n{\n    const void *role = NULL;\n    AXUIElementCopyAttributeValue(window->ref, kAXRoleAttribute, &role);\n    return role;\n}\n\nCFStringRef window_role(struct window *window)\n{\n    return window->role;\n}\n\nchar *window_role_ts(struct window *window)\n{\n    CFStringRef role = window_role(window);\n    if (!role) return ts_string_copy(\"\");\n\n    char *result = ts_cfstring_copy(role);\n    return result;\n}\n\nCFStringRef window_ax_subrole(struct window *window)\n{\n    const void *srole = NULL;\n    AXUIElementCopyAttributeValue(window->ref, kAXSubroleAttribute, &srole);\n    return srole;\n}\n\nCFStringRef window_subrole(struct window *window)\n{\n    return window->subrole;\n}\n\nchar *window_subrole_ts(struct window *window)\n{\n    CFStringRef subrole = window_subrole(window);\n    if (!subrole) return ts_string_copy(\"\");\n\n    char *result = ts_cfstring_copy(subrole);\n    return result;\n}\n\nstatic bool window_is_root(struct window *window)\n{\n    bool result = false;\n    CFTypeRef value = NULL;\n\n    if (AXUIElementCopyAttributeValue(window->ref, kAXParentAttribute, &value) == kAXErrorSuccess) {\n        result = !(value && !CFEqual(value, window->application->ref));\n    }\n\n    if (value) CFRelease(value);\n    return result;\n}\n\nbool window_is_real(struct window *window)\n{\n    bool win = false;\n    CFStringRef role  = NULL;\n    CFStringRef srole = NULL;\n\n    if (!(role  = window_role(window)))    goto out;\n    if (!(srole = window_subrole(window))) goto out;\n\n    win = CFEqual(role, kAXWindowRole) &&\n          (CFEqual(srole, kAXStandardWindowSubrole) ||\n           CFEqual(srole, kAXFloatingWindowSubrole) ||\n           CFEqual(srole, kAXDialogSubrole));\n\nout:\n    return win;\n}\n\nbool window_is_standard(struct window *window)\n{\n    bool standard_win = false;\n    CFStringRef role  = NULL;\n    CFStringRef srole = NULL;\n\n    if (!(role  = window_role(window)))    goto out;\n    if (!(srole = window_subrole(window))) goto out;\n\n    standard_win = CFEqual(role, kAXWindowRole) &&\n                   CFEqual(srole, kAXStandardWindowSubrole);\n\nout:\n    return standard_win;\n}\n\nbool window_level_is_standard(struct window *window)\n{\n    int level = window_level(window->id);\n    return level == g_layer_normal_window_level;\n}\n\nbool window_is_unknown(struct window *window)\n{\n    CFStringRef subrole = window_subrole(window);\n    if (!subrole) return false;\n\n    bool result = CFEqual(subrole, kAXUnknownSubrole);\n    return result;\n}\n\nstruct window *window_create(struct application *application, AXUIElementRef window_ref, uint32_t window_id)\n{\n    struct window *window = malloc(sizeof(struct window));\n    memset(window, 0, sizeof(struct window));\n\n    window->application = application;\n    window->ref = window_ref;\n    window->id = window_id;\n    window->id_ptr = &window->id;\n    window->frame = window_ax_frame(window);\n    window->role = window_ax_role(window);\n    window->subrole = window_ax_subrole(window);\n    window->title = window_title(window);\n    window->is_root = !window_parent(window->id) || window_is_root(window);\n\n    if (window_shadow(window->id)) {\n        window_set_flag(window, WINDOW_SHADOW);\n    }\n\n    if (window_is_minimized(window)) {\n        window_set_flag(window, WINDOW_MINIMIZE);\n    }\n\n    if (window_ax_can_move(window)) {\n        window_set_flag(window, WINDOW_MOVABLE);\n    }\n\n    if (window_ax_can_resize(window)) {\n        window_set_flag(window, WINDOW_RESIZABLE);\n    }\n\n    if ((window_is_fullscreen(window)) ||\n        (space_is_fullscreen(window_space(window->id)))) {\n        window_set_flag(window, WINDOW_FULLSCREEN);\n    }\n\n    if (window_is_sticky(window->id)) {\n        window_set_flag(window, WINDOW_STICKY);\n    }\n\n    return window;\n}\n\nvoid window_destroy(struct window *window)\n{\n    window->id = 0;\n    if (window->role) CFRelease(window->role);\n    if (window->subrole) CFRelease(window->subrole);\n    if (window->title) CFRelease(window->title);\n    CFRelease(window->ref);\n    free(window);\n}\n"
  },
  {
    "path": "src/window.h",
    "content": "#ifndef WINDOW_H\n#define WINDOW_H\n\nconst CFStringRef kAXFullscreenAttribute = CFSTR(\"AXFullScreen\");\n\n#define AX_WINDOW_MINIMIZED_INDEX      0\n#define AX_WINDOW_DEMINIMIZED_INDEX    1\n#define AX_WINDOW_DESTROYED_INDEX      2\n\n#define AX_WINDOW_DESTROYED      (1 << AX_WINDOW_DESTROYED_INDEX)\n#define AX_WINDOW_MINIMIZED      (1 << AX_WINDOW_MINIMIZED_INDEX)\n#define AX_WINDOW_DEMINIMIZED    (1 << AX_WINDOW_DEMINIMIZED_INDEX)\n#define AX_WINDOW_ALL            (AX_WINDOW_DESTROYED |\\\n                                  AX_WINDOW_MINIMIZED |\\\n                                  AX_WINDOW_DEMINIMIZED)\n\nstatic const char *ax_window_notification_str[] =\n{\n    [AX_WINDOW_DESTROYED_INDEX]      = \"kAXUIElementDestroyedNotification\",\n    [AX_WINDOW_MINIMIZED_INDEX]      = \"kAXWindowMiniaturizedNotification\",\n    [AX_WINDOW_DEMINIMIZED_INDEX]    = \"kAXWindowDeminiaturizedNotification\"\n};\n\nstatic CFStringRef ax_window_notification[] =\n{\n    [AX_WINDOW_DESTROYED_INDEX]      = kAXUIElementDestroyedNotification,\n    [AX_WINDOW_MINIMIZED_INDEX]      = kAXWindowMiniaturizedNotification,\n    [AX_WINDOW_DEMINIMIZED_INDEX]    = kAXWindowDeminiaturizedNotification\n};\n\n#define WINDOW_PROPERTY_LIST \\\n    WINDOW_PROPERTY_ENTRY(\"id\",                   WINDOW_PROPERTY_ID,                  0x000000001) \\\n    WINDOW_PROPERTY_ENTRY(\"pid\",                  WINDOW_PROPERTY_PID,                 0x000000002) \\\n    WINDOW_PROPERTY_ENTRY(\"app\",                  WINDOW_PROPERTY_APP,                 0x000000004) \\\n    WINDOW_PROPERTY_ENTRY(\"title\",                WINDOW_PROPERTY_TITLE,               0x000000008) \\\n    WINDOW_PROPERTY_ENTRY(\"scratchpad\",           WINDOW_PROPERTY_SCRATCHPAD,          0x000000010) \\\n    WINDOW_PROPERTY_ENTRY(\"frame\",                WINDOW_PROPERTY_FRAME,               0x000000020) \\\n    WINDOW_PROPERTY_ENTRY(\"role\",                 WINDOW_PROPERTY_ROLE,                0x000000040) \\\n    WINDOW_PROPERTY_ENTRY(\"subrole\",              WINDOW_PROPERTY_SUBROLE,             0x000000080) \\\n    WINDOW_PROPERTY_ENTRY(\"root-window\",          WINDOW_PROPERTY_ROOT_WINDOW,         0x000000100) \\\n    WINDOW_PROPERTY_ENTRY(\"display\",              WINDOW_PROPERTY_DISPLAY,             0x000000200) \\\n    WINDOW_PROPERTY_ENTRY(\"space\",                WINDOW_PROPERTY_SPACE,               0x000000400) \\\n    WINDOW_PROPERTY_ENTRY(\"level\",                WINDOW_PROPERTY_LEVEL,               0x000000800) \\\n    WINDOW_PROPERTY_ENTRY(\"sub-level\",            WINDOW_PROPERTY_SUB_LEVEL,           0x000001000) \\\n    WINDOW_PROPERTY_ENTRY(\"layer\",                WINDOW_PROPERTY_LAYER,               0x000002000) \\\n    WINDOW_PROPERTY_ENTRY(\"sub-layer\",            WINDOW_PROPERTY_SUB_LAYER,           0x000004000) \\\n    WINDOW_PROPERTY_ENTRY(\"opacity\",              WINDOW_PROPERTY_OPACITY,             0x000008000) \\\n    WINDOW_PROPERTY_ENTRY(\"split-type\",           WINDOW_PROPERTY_SPLIT_TYPE,          0x000010000) \\\n    WINDOW_PROPERTY_ENTRY(\"split-child\",          WINDOW_PROPERTY_SPLIT_CHILD,         0x000020000) \\\n    WINDOW_PROPERTY_ENTRY(\"stack-index\",          WINDOW_PROPERTY_STACK_INDEX,         0x000040000) \\\n    WINDOW_PROPERTY_ENTRY(\"can-move\",             WINDOW_PROPERTY_CAN_MOVE,            0x000080000) \\\n    WINDOW_PROPERTY_ENTRY(\"can-resize\",           WINDOW_PROPERTY_CAN_RESIZE,          0x000100000) \\\n    WINDOW_PROPERTY_ENTRY(\"has-focus\",            WINDOW_PROPERTY_HAS_FOCUS,           0x000200000) \\\n    WINDOW_PROPERTY_ENTRY(\"has-shadow\",           WINDOW_PROPERTY_HAS_SHADOW,          0x000400000) \\\n    WINDOW_PROPERTY_ENTRY(\"has-parent-zoom\",      WINDOW_PROPERTY_HAS_PARENT_ZOOM,     0x000800000) \\\n    WINDOW_PROPERTY_ENTRY(\"has-fullscreen-zoom\",  WINDOW_PROPERTY_HAS_FULLSCREEN_ZOOM, 0x001000000) \\\n    WINDOW_PROPERTY_ENTRY(\"has-ax-reference\",     WINDOW_PROPERTY_HAS_AX_REFERENCE,    0x002000000) \\\n    WINDOW_PROPERTY_ENTRY(\"is-native-fullscreen\", WINDOW_PROPERTY_IS_FULLSCREEN,       0x004000000) \\\n    WINDOW_PROPERTY_ENTRY(\"is-visible\",           WINDOW_PROPERTY_IS_VISIBLE,          0x008000000) \\\n    WINDOW_PROPERTY_ENTRY(\"is-minimized\",         WINDOW_PROPERTY_IS_MINIMIZED,        0x010000000) \\\n    WINDOW_PROPERTY_ENTRY(\"is-hidden\",            WINDOW_PROPERTY_IS_HIDDEN,           0x020000000) \\\n    WINDOW_PROPERTY_ENTRY(\"is-floating\",          WINDOW_PROPERTY_IS_FLOATING,         0x040000000) \\\n    WINDOW_PROPERTY_ENTRY(\"is-sticky\",            WINDOW_PROPERTY_IS_STICKY,           0x080000000) \\\n    WINDOW_PROPERTY_ENTRY(\"is-grabbed\",           WINDOW_PROPERTY_IS_GRABBED,          0x100000000)\n\nenum window_property\n{\n#define WINDOW_PROPERTY_ENTRY(n, p, v) p = v,\n    WINDOW_PROPERTY_LIST\n#undef WINDOW_PROPERTY_ENTRY\n};\n\nstatic uint64_t window_property_val[] =\n{\n#define WINDOW_PROPERTY_ENTRY(n, p, v) p,\n    WINDOW_PROPERTY_LIST\n#undef WINDOW_PROPERTY_ENTRY\n};\n\nstatic char *window_property_str[] =\n{\n#define WINDOW_PROPERTY_ENTRY(n, p, v) n,\n    WINDOW_PROPERTY_LIST\n#undef WINDOW_PROPERTY_ENTRY\n};\n\nstruct window\n{\n    struct application *application;\n    AXUIElementRef ref;\n    uint32_t id;\n    uint32_t *volatile id_ptr;\n    CFStringRef role;\n    CFStringRef subrole;\n    CFStringRef title;\n    CGRect frame;\n    CGRect windowed_frame;\n    bool is_root;\n    bool is_eligible;\n    uint8_t notification;\n    uint8_t rule_flags;\n    uint8_t flags;\n    float opacity;\n    int layer;\n    char *scratchpad;\n};\n\nenum window_flag\n{\n    WINDOW_SHADOW     = 0x01,\n    WINDOW_FULLSCREEN = 0x02,\n    WINDOW_MINIMIZE   = 0x04,\n    WINDOW_FLOAT      = 0x08,\n    WINDOW_STICKY     = 0x10,\n    WINDOW_WINDOWED   = 0x20,\n    WINDOW_MOVABLE    = 0x40,\n    WINDOW_RESIZABLE  = 0x80\n};\n\nenum window_rule_flag\n{\n    WINDOW_RULE_MANAGED    = 0x01,\n    WINDOW_RULE_FULLSCREEN = 0x02,\n    WINDOW_RULE_MFF        = 0x04,\n    WINDOW_RULE_MFF_VALUE  = 0x08\n};\n\nstatic inline bool window_check_flag(struct window *w, enum window_flag x) { return w->flags & x; }\nstatic inline void window_clear_flag(struct window *w, enum window_flag x) { w->flags &= ~x; }\nstatic inline void window_set_flag(struct window *w, enum window_flag x) { w->flags |= x; }\n\nstatic inline bool window_check_rule_flag(struct window *w, enum window_rule_flag x) { return w->rule_flags & x; }\nstatic inline void window_clear_rule_flag(struct window *w, enum window_rule_flag x) { w->rule_flags &= ~x; }\nstatic inline void window_set_rule_flag(struct window *w, enum window_rule_flag x) { w->rule_flags |= x; }\n\nCFStringRef window_display_uuid(uint32_t wid);\nuint32_t window_display_id(uint32_t wid);\nuint64_t window_space(uint32_t wid);\nuint64_t *window_space_list(uint32_t wid, int *count);\nvoid window_unknown_serialize(FILE *rsp, uint32_t wid, uint64_t flags);\nvoid window_serialize(FILE *rsp, struct window *window, uint64_t flags);\nchar *window_property_title_ts(uint32_t wid);\nchar *window_title_ts(struct window *window);\nCFStringRef window_title(struct window *window);\nbool window_shadow(uint32_t wid);\nfloat window_opacity(uint32_t wid);\nuint32_t window_parent(uint32_t wid);\nint window_level(uint32_t wid);\nint window_sub_level(uint32_t wid);\nuint64_t window_tags(uint32_t wid);\nbool window_is_sticky(uint32_t wid);\nCGPoint window_ax_origin(struct window *window);\nCGRect window_ax_frame(struct window *window);\nCFStringRef window_ax_role(struct window *window);\nCFStringRef window_role(struct window *window);\nchar *window_role_ts(struct window *window);\nCFStringRef window_ax_subrole(struct window *window);\nCFStringRef window_subrole(struct window *window);\nchar *window_subrole_ts(struct window *window);\nbool window_ax_can_move(struct window *window);\nbool window_can_move(struct window *window);\nbool window_ax_can_resize(struct window *window);\nbool window_can_resize(struct window *window);\nbool window_can_minimize(struct window *window);\nbool window_is_undersized(struct window *window);\nbool window_is_fullscreen(struct window *window);\nbool window_is_real(struct window *window);\nbool window_is_standard(struct window *window);\nbool window_level_is_standard(struct window *window);\nbool window_is_unknown(struct window *window);\nbool window_observe(struct window *window);\nvoid window_unobserve(struct window *window);\nstruct window *window_create(struct application *application, AXUIElementRef window_ref, uint32_t window_id);\nvoid window_destroy(struct window *window);\n\n#endif\n"
  },
  {
    "path": "src/window_manager.c",
    "content": "extern mach_port_t g_bs_port;\nextern uint8_t *g_event_bytes;\nextern struct event_loop g_event_loop;\nextern void *g_workspace_context;\nextern struct process_manager g_process_manager;\nextern struct mouse_state g_mouse_state;\nextern double g_cv_host_clock_frequency;\n\nstatic TABLE_HASH_FUNC(hash_wm)\n{\n    return *(uint32_t *) key;\n}\n\nstatic TABLE_COMPARE_FUNC(compare_wm)\n{\n    return *(uint32_t *) key_a == *(uint32_t *) key_b;\n}\n\nbool window_manager_is_window_eligible(struct window *window)\n{\n    bool result = window->is_root && (window_is_real(window) || window_check_rule_flag(window, WINDOW_RULE_MANAGED));\n    return result;\n}\n\nvoid window_manager_query_window_rules(FILE *rsp)\n{\n    TIME_FUNCTION;\n\n    fprintf(rsp, \"[\");\n    for (int i = 0; i < buf_len(g_window_manager.rules); ++i) {\n        struct rule *rule = &g_window_manager.rules[i];\n        rule_serialize(rsp, rule, i);\n        if (i < buf_len(g_window_manager.rules) - 1) fprintf(rsp, \",\");\n    }\n    fprintf(rsp, \"]\\n\");\n}\n\nvoid window_manager_query_windows_for_spaces(FILE *rsp, uint64_t *space_list, int space_count, uint64_t flags)\n{\n    TIME_FUNCTION;\n\n    int window_count = 0;\n    uint32_t *window_list = space_window_list_for_connection(space_list, space_count, 0, &window_count, true);\n\n    fprintf(rsp, \"[\");\n    for (int i = 0; i < window_count; ++i) {\n        struct window *window = window_manager_find_window(&g_window_manager, window_list[i]);\n        if (window) window_serialize(rsp, window, flags); else window_nonax_serialize(rsp, window_list[i], flags);\n        if (i < window_count - 1) fprintf(rsp, \",\");\n    }\n    fprintf(rsp, \"]\\n\");\n}\n\nvoid window_manager_query_windows_for_display(FILE *rsp, uint32_t did, uint64_t flags)\n{\n    TIME_FUNCTION;\n\n    int space_count = 0;\n    uint64_t *space_list = display_space_list(did, &space_count);\n    window_manager_query_windows_for_spaces(rsp, space_list, space_count, flags);\n}\n\nvoid window_manager_query_windows_for_displays(FILE *rsp, uint64_t flags)\n{\n    TIME_FUNCTION;\n\n    int display_count = 0;\n    uint32_t *display_list = display_manager_active_display_list(&display_count);\n\n    int space_count = 0;\n    uint64_t *space_list = NULL;\n\n    for (int i = 0; i < display_count; ++i) {\n        int count;\n        uint64_t *list = display_space_list(display_list[i], &count);\n        if (!list) continue;\n\n        //\n        // NOTE(asmvik): display_space_list(..) uses a linear allocator,\n        // and so we only need to track the beginning of the first list along\n        // with the total number of spaces that have been allocated.\n        //\n\n        if (!space_list) space_list = list;\n        space_count += count;\n    }\n\n    window_manager_query_windows_for_spaces(rsp, space_list, space_count, flags);\n}\n\nbool window_manager_rule_matches_window(struct rule *rule, struct window *window, char *window_title, char *window_role, char *window_subrole)\n{\n    int regex_match_app = rule_check_flag(rule, RULE_APP_EXCLUDE) ? REGEX_MATCH_YES : REGEX_MATCH_NO;\n    if (regex_match(rule_check_flag(rule, RULE_APP_VALID), &rule->app_regex, window->application->name) == regex_match_app) return false;\n\n    int regex_match_title = rule_check_flag(rule, RULE_TITLE_EXCLUDE) ? REGEX_MATCH_YES : REGEX_MATCH_NO;\n    if (regex_match(rule_check_flag(rule, RULE_TITLE_VALID), &rule->title_regex, window_title) == regex_match_title) return false;\n\n    int regex_match_role = rule_check_flag(rule, RULE_ROLE_EXCLUDE) ? REGEX_MATCH_YES : REGEX_MATCH_NO;\n    if (regex_match(rule_check_flag(rule, RULE_ROLE_VALID), &rule->role_regex, window_role) == regex_match_role) return false;\n\n    int regex_match_subrole = rule_check_flag(rule, RULE_SUBROLE_EXCLUDE) ? REGEX_MATCH_YES : REGEX_MATCH_NO;\n    if (regex_match(rule_check_flag(rule, RULE_SUBROLE_VALID), &rule->subrole_regex, window_subrole) == regex_match_subrole) return false;\n\n    return true;\n}\n\nvoid window_manager_apply_manage_rule_effects_to_window(struct space_manager *sm, struct window_manager *wm, struct window *window, struct rule_effects *effects)\n{\n    if (effects->manage == RULE_PROP_ON) {\n        window_set_rule_flag(window, WINDOW_RULE_MANAGED);\n        window_manager_make_window_floating(sm, wm, window, false, true);\n    } else if (effects->manage == RULE_PROP_OFF) {\n        window_clear_rule_flag(window, WINDOW_RULE_MANAGED);\n        window_manager_make_window_floating(sm, wm, window, true, true);\n    }\n}\n\nvoid window_manager_apply_rule_effects_to_window(struct space_manager *sm, struct window_manager *wm, struct window *window, struct rule_effects *effects)\n{\n    if (effects->sid || effects->did) {\n        if (!window_is_fullscreen(window) && !space_is_fullscreen(window_space(window->id))) {\n            uint64_t sid = effects->sid ? effects->sid : display_space_id(effects->did);\n            window_manager_send_window_to_space(sm, wm, window, sid, true);\n            if (rule_effects_check_flag(effects, RULE_FOLLOW_SPACE) || effects->fullscreen == RULE_PROP_ON) {\n                space_manager_focus_space(sid);\n            }\n        }\n    }\n\n    if (effects->sticky == RULE_PROP_ON) {\n        window_manager_make_window_sticky(sm, wm, window, true);\n    } else if (effects->sticky == RULE_PROP_OFF) {\n        window_manager_make_window_sticky(sm, wm, window, false);\n    }\n\n    if (effects->mff == RULE_PROP_ON) {\n        window_set_rule_flag(window, WINDOW_RULE_MFF);\n        window_set_rule_flag(window, WINDOW_RULE_MFF_VALUE);\n    } else if (effects->mff == RULE_PROP_OFF) {\n        window_set_rule_flag(window, WINDOW_RULE_MFF);\n        window_clear_rule_flag(window, WINDOW_RULE_MFF_VALUE);\n    }\n\n    if (rule_effects_check_flag(effects, RULE_LAYER)) {\n        window_manager_set_window_layer(window, effects->layer);\n    }\n\n    if (rule_effects_check_flag(effects, RULE_OPACITY) && in_range_ii(effects->opacity, 0.0f, 1.0f)) {\n        window->opacity = effects->opacity;\n        window_manager_set_opacity(wm, window, effects->opacity);\n    }\n\n    if (effects->fullscreen == RULE_PROP_ON) {\n        AXUIElementSetAttributeValue(window->ref, kAXFullscreenAttribute, kCFBooleanTrue);\n        window_set_rule_flag(window, WINDOW_RULE_FULLSCREEN);\n    }\n\n    if (effects->scratchpad) {\n        char *scratchpad = string_copy(effects->scratchpad);\n        if (!window_manager_set_scratchpad_for_window(wm, window, scratchpad)) {\n            free(scratchpad);\n        }\n    }\n\n    if (effects->grid[0] != 0 && effects->grid[1] != 0) {\n        window_manager_apply_grid(sm, wm, window, effects->grid[0], effects->grid[1], effects->grid[2], effects->grid[3], effects->grid[4], effects->grid[5]);\n    }\n}\n\nvoid window_manager_apply_manage_rules_to_window(struct space_manager *sm, struct window_manager *wm, struct window *window, char *window_title, char *window_role, char *window_subrole, bool one_shot_rules)\n{\n    bool match = false;\n    struct rule_effects effects = {0};\n\n    for (int i = 0; i < buf_len(wm->rules); ++i) {\n        if (one_shot_rules || !rule_check_flag(&wm->rules[i], RULE_ONE_SHOT)) {\n            if (window_manager_rule_matches_window(&wm->rules[i], window, window_title, window_role, window_subrole)) {\n                if (wm->rules[i].effects.manage == RULE_PROP_ON) {\n                    if (!rule_check_flag(&wm->rules[i], RULE_ROLE_VALID)    && !string_equals(window_role   , \"AXWindow\"))         continue;\n                    if (!rule_check_flag(&wm->rules[i], RULE_SUBROLE_VALID) && !string_equals(window_subrole, \"AXStandardWindow\")) continue;\n                }\n\n                match = true;\n                rule_combine_effects(&wm->rules[i].effects, &effects);\n\n                if (rule_check_flag(&wm->rules[i], RULE_ONE_SHOT)) rule_set_flag(&wm->rules[i], RULE_ONE_SHOT_REMOVE);\n            }\n        }\n    }\n\n    if (match) window_manager_apply_manage_rule_effects_to_window(sm, wm, window, &effects);\n}\n\nvoid window_manager_apply_rules_to_window(struct space_manager *sm, struct window_manager *wm, struct window *window, char *window_title, char *window_role, char *window_subrole, bool one_shot_rules)\n{\n    bool match = false;\n    struct rule_effects effects = {0};\n\n    for (int i = 0; i < buf_len(wm->rules); ++i) {\n        if (one_shot_rules || !rule_check_flag(&wm->rules[i], RULE_ONE_SHOT)) {\n            if (window_manager_rule_matches_window(&wm->rules[i], window, window_title, window_role, window_subrole)) {\n                if (!window_check_rule_flag(window, WINDOW_RULE_MANAGED)) {\n                    if (!rule_check_flag(&wm->rules[i], RULE_ROLE_VALID)    && !string_equals(window_role   , \"AXWindow\"))         continue;\n                    if (!rule_check_flag(&wm->rules[i], RULE_SUBROLE_VALID) && !string_equals(window_subrole, \"AXStandardWindow\")) continue;\n                }\n\n                match = true;\n                rule_combine_effects(&wm->rules[i].effects, &effects);\n\n                if (rule_check_flag(&wm->rules[i], RULE_ONE_SHOT)) rule_set_flag(&wm->rules[i], RULE_ONE_SHOT_REMOVE);\n            }\n        }\n    }\n\n    if (match) window_manager_apply_rule_effects_to_window(sm, wm, window, &effects);\n}\n\nvoid window_manager_set_focus_follows_mouse(struct window_manager *wm, enum ffm_mode mode)\n{\n    mouse_handler_end(&g_mouse_state);\n\n    if (mode == FFM_DISABLED) {\n        mouse_handler_begin(&g_mouse_state, MOUSE_EVENT_MASK);\n    } else {\n        mouse_handler_begin(&g_mouse_state, MOUSE_EVENT_MASK_FFM);\n    }\n\n    wm->ffm_mode = mode;\n}\n\nvoid window_manager_set_window_opacity_enabled(struct window_manager *wm, bool enabled)\n{\n    wm->enable_window_opacity = enabled;\n    table_for (struct window *window, wm->window, {\n        if (window_manager_is_window_eligible(window)) {\n            window_manager_set_opacity(wm, window, enabled ? window->opacity : 1.0f);\n        }\n    })\n}\n\nvoid window_manager_center_mouse(struct window_manager *wm, struct window *window)\n{\n    if (window_check_rule_flag(window, WINDOW_RULE_MFF)) {\n        if (!window_check_rule_flag(window, WINDOW_RULE_MFF_VALUE)) {\n            return;\n        }\n    } else {\n        if (!wm->enable_mff) {\n            return;\n        }\n    }\n\n    CGPoint cursor;\n    SLSGetCurrentCursorLocation(g_connection, &cursor);\n    if (CGRectContainsPoint(window->frame, cursor)) return;\n\n    uint32_t did = window_display_id(window->id);\n    if (!did) return;\n\n    CGPoint center = {\n        window->frame.origin.x + window->frame.size.width / 2,\n        window->frame.origin.y + window->frame.size.height / 2\n    };\n\n    CGRect bounds = CGDisplayBounds(did);\n    if (!CGRectContainsPoint(bounds, center)) return;\n\n    CGWarpMouseCursorPosition(center);\n}\n\nbool window_manager_should_manage_window(struct window *window)\n{\n    if (!window->is_root)                           return false;\n    if (window_check_flag(window, WINDOW_FLOAT))    return false;\n    if (window_is_sticky(window->id))               return false;\n    if (window_check_flag(window, WINDOW_MINIMIZE)) return false;\n    if (window->application->is_hidden)             return false;\n\n    return (window_is_standard(window) && window_level_is_standard(window) && window_can_move(window)) || window_check_rule_flag(window, WINDOW_RULE_MANAGED);\n}\n\nstruct view *window_manager_find_managed_window(struct window_manager *wm, struct window *window)\n{\n    return table_find(&wm->managed_window, &window->id);\n}\n\nvoid window_manager_remove_managed_window(struct window_manager *wm, uint32_t wid)\n{\n    table_remove(&wm->managed_window, &wid);\n}\n\nvoid window_manager_add_managed_window(struct window_manager *wm, struct window *window, struct view *view)\n{\n    if (view->layout == VIEW_FLOAT) return;\n    table_add(&wm->managed_window, &window->id, view);\n    window_manager_purify_window(wm, window);\n}\n\nenum window_op_error window_manager_adjust_window_ratio(struct window_manager *wm, struct window *window, int type, float ratio)\n{\n    TIME_FUNCTION;\n\n    struct view *view = window_manager_find_managed_window(wm, window);\n    if (!view) return WINDOW_OP_ERROR_INVALID_SRC_VIEW;\n\n    struct window_node *node = view_find_window_node(view, window->id);\n    if (!node || !node->parent) return WINDOW_OP_ERROR_INVALID_SRC_NODE;\n\n    switch (type) {\n    case TYPE_REL: {\n        node->parent->ratio = clampf_range(node->parent->ratio + ratio, 0.1f, 0.9f);\n    } break;\n    case TYPE_ABS: {\n        node->parent->ratio = clampf_range(ratio, 0.1f, 0.9f);\n    } break;\n    }\n\n    window_node_update(view, node->parent);\n\n    if (space_is_visible(view->sid)) {\n        window_node_flush(node->parent);\n    } else {\n        view_set_flag(view, VIEW_IS_DIRTY);\n    }\n\n    return WINDOW_OP_ERROR_SUCCESS;\n}\n\nenum window_op_error window_manager_move_window_relative(struct window_manager *wm, struct window *window, int type, float dx, float dy)\n{\n    TIME_FUNCTION;\n\n    struct view *view = window_manager_find_managed_window(wm, window);\n    if (view) return WINDOW_OP_ERROR_INVALID_SRC_VIEW;\n\n    if (type == TYPE_REL) {\n        dx += window->frame.origin.x;\n        dy += window->frame.origin.y;\n    }\n\n    window_manager_animate_window((struct window_capture) { .window = window, .x = dx, .y = dy, .w = window->frame.size.width, .h = window->frame.size.height });\n    return WINDOW_OP_ERROR_SUCCESS;\n}\n\nvoid window_manager_resize_window_relative_internal(struct window *window, CGRect frame, int direction, float dx, float dy, bool animate)\n{\n    TIME_FUNCTION;\n\n    int x_mod = (direction & HANDLE_LEFT) ? -1 : (direction & HANDLE_RIGHT)  ? 1 : 0;\n    int y_mod = (direction & HANDLE_TOP)  ? -1 : (direction & HANDLE_BOTTOM) ? 1 : 0;\n\n    float fw = max(1, frame.size.width  + dx * x_mod);\n    float fh = max(1, frame.size.height + dy * y_mod);\n    float fx = (direction & HANDLE_LEFT) ? frame.origin.x + frame.size.width  - fw : frame.origin.x;\n    float fy = (direction & HANDLE_TOP)  ? frame.origin.y + frame.size.height - fh : frame.origin.y;\n\n    if (animate) {\n        window_manager_animate_window((struct window_capture) { .window = window, .x = fx, .y = fy, .w = fw, .h = fh });\n    } else {\n        AX_ENHANCED_UI_WORKAROUND(window->application->ref, {\n            window_manager_move_window(window, fx, fy);\n            window_manager_resize_window(window, fw, fh);\n        });\n    }\n}\n\nenum window_op_error window_manager_resize_window_relative(struct window_manager *wm, struct window *window, int direction, float dx, float dy, bool animate)\n{\n    TIME_FUNCTION;\n\n    struct view *view = window_manager_find_managed_window(wm, window);\n    if (view) {\n        if (direction == HANDLE_ABS) return WINDOW_OP_ERROR_INVALID_OPERATION;\n\n        struct window_node *node = view_find_window_node(view, window->id);\n        if (!node) return WINDOW_OP_ERROR_INVALID_SRC_NODE;\n\n        struct window_node *x_fence = NULL;\n        struct window_node *y_fence = NULL;\n\n        if (direction & HANDLE_TOP)    x_fence = window_node_fence(node, DIR_NORTH);\n        if (direction & HANDLE_BOTTOM) x_fence = window_node_fence(node, DIR_SOUTH);\n        if (direction & HANDLE_LEFT)   y_fence = window_node_fence(node, DIR_WEST);\n        if (direction & HANDLE_RIGHT)  y_fence = window_node_fence(node, DIR_EAST);\n        if (!x_fence && !y_fence)      return WINDOW_OP_ERROR_INVALID_DST_NODE;\n\n        if (y_fence) {\n            float sr = y_fence->ratio + (float) dx / (float) y_fence->area.w;\n            y_fence->ratio = clampf_range(sr, 0.1f, 0.9f);\n        }\n\n        if (x_fence) {\n            float sr = x_fence->ratio + (float) dy / (float) x_fence->area.h;\n            x_fence->ratio = clampf_range(sr, 0.1f, 0.9f);\n        }\n\n        view_update(view);\n        view_flush(view);\n    } else {\n        if (direction == HANDLE_ABS) {\n            if (animate) {\n                window_manager_animate_window((struct window_capture) { .window = window, .x = window->frame.origin.x, .y = window->frame.origin.y, .w = dx, .h = dy });\n            } else {\n                AX_ENHANCED_UI_WORKAROUND(window->application->ref, { window_manager_resize_window(window, dx, dy); });\n            }\n        } else {\n            window_manager_resize_window_relative_internal(window, window_ax_frame(window), direction, dx, dy, animate);\n        }\n    }\n\n    return WINDOW_OP_ERROR_SUCCESS;\n}\n\nvoid window_manager_move_window(struct window *window, float x, float y)\n{\n    CGPoint position = CGPointMake(x, y);\n    CFTypeRef position_ref = AXValueCreate(kAXValueTypeCGPoint, (void *) &position);\n    if (!position_ref) return;\n\n    AXUIElementSetAttributeValue(window->ref, kAXPositionAttribute, position_ref);\n    CFRelease(position_ref);\n}\n\nvoid window_manager_resize_window(struct window *window, float width, float height)\n{\n    CGSize size = CGSizeMake(width, height);\n    CFTypeRef size_ref = AXValueCreate(kAXValueTypeCGSize, (void *) &size);\n    if (!size_ref) return;\n\n    AXUIElementSetAttributeValue(window->ref, kAXSizeAttribute, size_ref);\n    CFRelease(size_ref);\n}\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wmissing-field-initializers\"\nstatic inline void window_manager_notify_jankyborders(struct window_animation *animation_list, int animation_count, uint32_t event, bool skip, bool wait)\n{\n    mach_port_t port;\n    if (g_bs_port && bootstrap_look_up(g_bs_port, \"git.felix.jbevent\", &port) == KERN_SUCCESS) {\n        struct {\n            uint32_t event;\n            uint32_t count;\n            uint32_t proxy_wid[512];\n            uint32_t real_wid[512];\n        } data = { event, 0 };\n\n        for (int i = 0; i < animation_count; ++i) {\n            if (skip && __atomic_load_n(&animation_list[i].skip, __ATOMIC_RELAXED)) continue;\n\n            data.proxy_wid[data.count] = animation_list[i].proxy.id;\n            data.real_wid[data.count]  = animation_list[i].wid;\n\n            ++data.count;\n        }\n\n        mach_send(port, &data, sizeof(data));\n        if (wait) usleep(20000);\n    }\n}\n#pragma clang diagnostic pop\n\nstatic void window_manager_create_window_proxy(int animation_connection, float alpha, struct window_proxy *proxy)\n{\n    if (!proxy->image) return;\n\n    CFTypeRef frame_region;\n    CGSNewRegionWithRect(&proxy->frame, &frame_region);\n    CFTypeRef empty_region = CGRegionCreateEmptyRegion();\n\n    uint64_t tags = 1ULL << 46;\n    SLSNewWindowWithOpaqueShapeAndContext(animation_connection, 2, frame_region, empty_region, 13|(1 << 18), &tags, 0, 0, 64, &proxy->id, NULL);\n    sls_window_disable_shadow(proxy->id);\n    SLSSetWindowOpacity(animation_connection, proxy->id, 0);\n    SLSSetWindowResolution(animation_connection, proxy->id, 2.0f);\n    SLSSetWindowAlpha(animation_connection, proxy->id, alpha);\n    SLSSetWindowLevel(animation_connection, proxy->id, proxy->level);\n    SLSSetWindowSubLevel(animation_connection, proxy->id, proxy->sub_level);\n    proxy->context = SLWindowContextCreate(animation_connection, proxy->id, 0);\n\n    CGRect frame = { {0, 0}, proxy->frame.size };\n    CGContextClearRect(proxy->context, frame);\n    CGContextDrawImage(proxy->context, frame, proxy->image);\n    CGContextFlush(proxy->context);\n    CFRelease(frame_region);\n    CFRelease(empty_region);\n}\n\nstatic void window_manager_destroy_window_proxy(int animation_connection, struct window_proxy *proxy)\n{\n    if (proxy->image) {\n        CFRelease(proxy->image);\n        proxy->image = NULL;\n    }\n\n    if (proxy->context) {\n        CGContextRelease(proxy->context);\n        proxy->context = NULL;\n    }\n\n    if (proxy->id) {\n        SLSReleaseWindow(animation_connection, proxy->id);\n        proxy->id = 0;\n    }\n}\n\nstatic void *window_manager_build_window_proxy_thread_proc(void *data)\n{\n    struct window_animation *animation = data;\n\n    float alpha = 1.0f;\n    SLSGetWindowAlpha(animation->cid, animation->wid, &alpha);\n    animation->proxy.level = window_level(animation->wid);\n    animation->proxy.sub_level = window_sub_level(animation->wid);\n    SLSGetWindowBounds(animation->cid, animation->wid, &animation->proxy.frame);\n    animation->proxy.tx = animation->proxy.frame.origin.x;\n    animation->proxy.ty = animation->proxy.frame.origin.y;\n    animation->proxy.tw = animation->proxy.frame.size.width;\n    animation->proxy.th = animation->proxy.frame.size.height;\n\n    CFArrayRef image_array = SLSHWCaptureWindowList(animation->cid, &animation->wid, 1, (1 << 11) | (1 << 8));\n    if (image_array) {\n        animation->proxy.image = alpha == 1.0f\n                               ? (CGImageRef) CFRetain(CFArrayGetValueAtIndex(image_array, 0))\n                               : cgimage_restore_alpha((CGImageRef) CFArrayGetValueAtIndex(image_array, 0));\n        CFRelease(image_array);\n    } else {\n        animation->proxy.image = NULL;\n    }\n\n    window_manager_create_window_proxy(animation->cid, alpha, &animation->proxy);\n    return NULL;\n}\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wunused-parameter\"\nstatic CVReturn window_manager_animate_window_list_thread_proc(CVDisplayLinkRef link, const CVTimeStamp *now, const CVTimeStamp *output_time, CVOptionFlags flags, CVOptionFlags *flags_out, void *data)\n{\n    struct window_animation_context *context = data;\n    int animation_count = context->animation_count;\n\n    uint64_t current_clock = output_time->hostTime;\n    if (!context->animation_clock) context->animation_clock = now->hostTime;\n\n    double t = (double)(current_clock - context->animation_clock) / (double)(context->animation_duration * g_cv_host_clock_frequency);\n    if (t <= 0.0) t = 0.0f;\n    if (t >= 1.0) t = 1.0f;\n\n    float mt;\n    switch (context->animation_easing) {\n#define ANIMATION_EASING_TYPE_ENTRY(value) case value##_type: mt = value(t); break;\n        ANIMATION_EASING_TYPE_LIST\n#undef ANIMATION_EASING_TYPE_ENTRY\n    }\n\n    CFTypeRef transaction = SLSTransactionCreate(context->animation_connection);\n    for (int i = 0; i < animation_count; ++i) {\n        if (__atomic_load_n(&context->animation_list[i].skip, __ATOMIC_RELAXED)) continue;\n\n        context->animation_list[i].proxy.tx = lerp(context->animation_list[i].proxy.frame.origin.x,    mt, context->animation_list[i].x);\n        context->animation_list[i].proxy.ty = lerp(context->animation_list[i].proxy.frame.origin.y,    mt, context->animation_list[i].y);\n        context->animation_list[i].proxy.tw = lerp(context->animation_list[i].proxy.frame.size.width,  mt, context->animation_list[i].w);\n        context->animation_list[i].proxy.th = lerp(context->animation_list[i].proxy.frame.size.height, mt, context->animation_list[i].h);\n\n        CGAffineTransform transform = CGAffineTransformMakeTranslation(-context->animation_list[i].proxy.tx, -context->animation_list[i].proxy.ty);\n        CGAffineTransform scale = CGAffineTransformMakeScale(context->animation_list[i].proxy.frame.size.width / context->animation_list[i].proxy.tw, context->animation_list[i].proxy.frame.size.height / context->animation_list[i].proxy.th);\n        SLSTransactionSetWindowTransform(transaction, context->animation_list[i].proxy.id, 0, 0, CGAffineTransformConcat(transform, scale));\n\n        float alpha = 0.0f;\n        SLSGetWindowAlpha(context->animation_connection, context->animation_list[i].wid, &alpha);\n        if (alpha != 0.0f) SLSTransactionSetWindowAlpha(transaction, context->animation_list[i].proxy.id, alpha);\n    }\n    SLSTransactionCommit(transaction, 0);\n    CFRelease(transaction);\n    if (t != 1.0f) goto out;\n\n    pthread_mutex_lock(&g_window_manager.window_animations_lock);\n    SLSDisableUpdate(context->animation_connection);\n    window_manager_notify_jankyborders(context->animation_list, context->animation_count, 1326, true, true);\n    scripting_addition_swap_window_proxy_out(context->animation_list, context->animation_count);\n    for (int i = 0; i < animation_count; ++i) {\n        if (__atomic_load_n(&context->animation_list[i].skip, __ATOMIC_RELAXED)) continue;\n\n        table_remove(&g_window_manager.window_animations_table, &context->animation_list[i].wid);\n        window_manager_destroy_window_proxy(context->animation_connection, &context->animation_list[i].proxy);\n\n    }\n    SLSReenableUpdate(context->animation_connection);\n    pthread_mutex_unlock(&g_window_manager.window_animations_lock);\n\n    SLSReleaseConnection(context->animation_connection);\n    free(context->animation_list);\n    free(context);\n\n    CVDisplayLinkStop(link);\n    CVDisplayLinkRelease(link);\n\nout:\n    return kCVReturnSuccess;\n}\n#pragma clang diagnostic pop\n\nvoid window_manager_animate_window_list_async(struct window_capture *window_list, int window_count)\n{\n    struct window_animation_context *context = malloc(sizeof(struct window_animation_context));\n\n    SLSNewConnection(0, &context->animation_connection);\n    context->animation_count    = window_count;\n    context->animation_list     = malloc(window_count * sizeof(struct window_animation));\n    context->animation_duration = g_window_manager.window_animation_duration;\n    context->animation_easing   = g_window_manager.window_animation_easing;\n    context->animation_clock    = 0;\n\n    int thread_count = 0;\n    pthread_t *threads = ts_alloc_list(pthread_t, window_count);\n\n    TIME_BODY(window_manager_animate_window_list_async___prep_proxies, {\n    SLSDisableUpdate(context->animation_connection);\n    pthread_mutex_lock(&g_window_manager.window_animations_lock);\n    for (int i = 0; i < window_count; ++i) {\n        context->animation_list[i].window = window_list[i].window;\n        context->animation_list[i].wid    = window_list[i].window->id;\n        context->animation_list[i].x      = window_list[i].x;\n        context->animation_list[i].y      = window_list[i].y;\n        context->animation_list[i].w      = window_list[i].w;\n        context->animation_list[i].h      = window_list[i].h;\n        context->animation_list[i].cid    = context->animation_connection;\n        context->animation_list[i].skip   = false;\n        memset(&context->animation_list[i].proxy, 0, sizeof(struct window_proxy));\n\n        struct window_animation *existing_animation = table_find(&g_window_manager.window_animations_table, &context->animation_list[i].wid);\n        if (existing_animation) {\n            __atomic_store_n(&existing_animation->skip, true, __ATOMIC_RELEASE);\n\n            context->animation_list[i].proxy.frame.origin.x    = (int)(existing_animation->proxy.tx);\n            context->animation_list[i].proxy.frame.origin.y    = (int)(existing_animation->proxy.ty);\n            context->animation_list[i].proxy.frame.size.width  = (int)(existing_animation->proxy.tw);\n            context->animation_list[i].proxy.frame.size.height = (int)(existing_animation->proxy.th);\n            context->animation_list[i].proxy.tx                = (int)(existing_animation->proxy.tx);\n            context->animation_list[i].proxy.ty                = (int)(existing_animation->proxy.ty);\n            context->animation_list[i].proxy.tw                = (int)(existing_animation->proxy.tw);\n            context->animation_list[i].proxy.th                = (int)(existing_animation->proxy.th);\n            context->animation_list[i].proxy.level             = existing_animation->proxy.level;\n            context->animation_list[i].proxy.sub_level         = existing_animation->proxy.sub_level;\n            context->animation_list[i].proxy.image             = existing_animation->proxy.image\n                                                               ? (CGImageRef) CFRetain(existing_animation->proxy.image)\n                                                               : NULL;\n            __asm__ __volatile__ (\"\" ::: \"memory\");\n\n            float alpha = 1.0f;\n            SLSGetWindowAlpha(context->animation_connection, context->animation_list[i].wid, &alpha);\n            window_manager_create_window_proxy(context->animation_connection, alpha, &context->animation_list[i].proxy);\n            window_manager_notify_jankyborders(&context->animation_list[i], 1, 1325, true, false);\n            window_manager_notify_jankyborders(existing_animation, 1, 1326, false, false);\n\n            CFTypeRef transaction = SLSTransactionCreate(context->animation_connection);\n            SLSTransactionOrderWindowGroup(transaction, context->animation_list[i].proxy.id, 1, context->animation_list[i].wid);\n            SLSTransactionSetWindowSystemAlpha(transaction, existing_animation->proxy.id, 0);\n            SLSTransactionCommit(transaction, 0);\n            CFRelease(transaction);\n\n            table_remove(&g_window_manager.window_animations_table, &context->animation_list[i].wid);\n            window_manager_destroy_window_proxy(existing_animation->cid, &existing_animation->proxy);\n        } else {\n            pthread_t thread;\n            if (pthread_create(&thread, NULL, &window_manager_build_window_proxy_thread_proc, &context->animation_list[i]) == 0) {\n                threads[thread_count++] = thread;\n            } else {\n                window_manager_build_window_proxy_thread_proc(&context->animation_list[i]);\n            }\n        }\n\n        table_add(&g_window_manager.window_animations_table, &context->animation_list[i].wid, &context->animation_list[i]);\n    }\n    pthread_mutex_unlock(&g_window_manager.window_animations_lock);\n    });\n\n    TIME_BODY(window_manager_animate_window_list_async___wait_for_threads, {\n    for (int i = 0; i < thread_count; ++i) {\n        pthread_join(threads[i], NULL);\n    }\n    });\n\n    TIME_BODY(window_manager_animate_window_list_async___swap_proxy_in, {\n    scripting_addition_swap_window_proxy_in(context->animation_list, context->animation_count);\n    });\n\n    TIME_BODY(window_manager_animate_window_list_async___notify_jb, {\n    window_manager_notify_jankyborders(context->animation_list, context->animation_count, 1325, true, false);\n    });\n\n    TIME_BODY(window_manager_animate_window_list_async___set_frame, {\n    for (int i = 0; i < window_count; ++i) {\n        window_manager_set_window_frame(context->animation_list[i].window, context->animation_list[i].x, context->animation_list[i].y, context->animation_list[i].w, context->animation_list[i].h);\n    }\n    });\n\n    CVDisplayLinkRef link;\n    SLSReenableUpdate(context->animation_connection);\n    CVDisplayLinkCreateWithActiveCGDisplays(&link);\n    CVDisplayLinkSetOutputCallback(link, window_manager_animate_window_list_thread_proc, context);\n    CVDisplayLinkStart(link);\n}\n\nvoid window_manager_animate_window_list(struct window_capture *window_list, int window_count)\n{\n    TIME_FUNCTION;\n\n    if (g_window_manager.window_animation_duration) {\n        window_manager_animate_window_list_async(window_list, window_count);\n    } else {\n        for (int i = 0; i < window_count; ++i) {\n            window_manager_set_window_frame(window_list[i].window, window_list[i].x, window_list[i].y, window_list[i].w, window_list[i].h);\n        }\n    }\n}\n\nvoid window_manager_animate_window(struct window_capture capture)\n{\n    TIME_FUNCTION;\n\n    if (g_window_manager.window_animation_duration) {\n        window_manager_animate_window_list_async(&capture, 1);\n    } else {\n        window_manager_set_window_frame(capture.window, capture.x, capture.y, capture.w, capture.h);\n    }\n}\n\nvoid window_manager_set_window_frame(struct window *window, float x, float y, float width, float height)\n{\n    //\n    // NOTE(asmvik): Attempting to check the window frame cache to prevent unnecessary movement and resize calls to the AX API\n    // is not reliable because it is possible to perform operations that should be applied, at a higher rate than the AX API events\n    // are received, causing our cache to become out of date and incorrectly guard against some changes that **should** be applied.\n    // This causes the window layout to **not** be modified the way we expect.\n    //\n    // A possible solution is to use the faster CG window notifications, as they are **a lot** more responsive, and can be used to\n    // track changes to the window frame in real-time without delay.\n    //\n\n    AX_ENHANCED_UI_WORKAROUND(window->application->ref, {\n        // NOTE(asmvik): Due to macOS constraints (visible screen-area), we might need to resize the window *before* moving it.\n        window_manager_resize_window(window, width, height);\n\n        window_manager_move_window(window, x, y);\n\n        // NOTE(asmvik): Due to macOS constraints (visible screen-area), we might need to resize the window *after* moving it.\n        window_manager_resize_window(window, width, height);\n    });\n}\n\nvoid window_manager_set_purify_mode(struct window_manager *wm, enum purify_mode mode)\n{\n    wm->purify_mode = mode;\n    table_for (struct window *window, wm->window, {\n        if (window_manager_is_window_eligible(window)) {\n            window_manager_purify_window(wm, window);\n        }\n    })\n}\n\nbool window_manager_set_opacity(struct window_manager *wm, struct window *window, float opacity)\n{\n    if (opacity == 0.0f) {\n        if (wm->enable_window_opacity) {\n            opacity = window->id == wm->focused_window_id ? wm->active_window_opacity : wm->normal_window_opacity;\n        } else {\n            opacity = 1.0f;\n        }\n    }\n\n    return scripting_addition_set_opacity(window->id, opacity, wm->window_opacity_duration);\n}\n\nvoid window_manager_set_window_opacity(struct window_manager *wm, struct window *window, float opacity)\n{\n    if (!wm->enable_window_opacity)                 return;\n    if (!window_manager_is_window_eligible(window)) return;\n    if (window->opacity != 0.0f)                    return;\n\n    window_manager_set_opacity(wm, window, opacity);\n}\n\nvoid window_manager_set_menubar_opacity(struct window_manager *wm, float opacity)\n{\n    wm->menubar_opacity = opacity;\n    SLSSetMenuBarInsetAndAlpha(g_connection, 0, 1, opacity);\n}\n\nvoid window_manager_set_active_window_opacity(struct window_manager *wm, float opacity)\n{\n    wm->active_window_opacity = opacity;\n    struct window *window = window_manager_focused_window(wm);\n    if (window) window_manager_set_window_opacity(wm, window, wm->active_window_opacity);\n}\n\nvoid window_manager_set_normal_window_opacity(struct window_manager *wm, float opacity)\n{\n    wm->normal_window_opacity = opacity;\n    table_for (struct window *window, wm->window, {\n        if (window->id == wm->focused_window_id) continue;\n        if (window_manager_is_window_eligible(window)) {\n            window_manager_set_window_opacity(wm, window, wm->normal_window_opacity);\n        }\n    })\n}\n\nvoid window_manager_adjust_layer(struct window *window, int layer)\n{\n    if (window->layer != LAYER_AUTO) return;\n\n    scripting_addition_set_layer(window->id, layer);\n}\n\nbool window_manager_set_window_layer(struct window *window, int layer)\n{\n    int parent_layer = layer;\n    int child_layer = layer;\n\n    if (layer == LAYER_AUTO) {\n        parent_layer = window_manager_find_managed_window(&g_window_manager, window) ? LAYER_BELOW : LAYER_NORMAL;\n        child_layer = LAYER_NORMAL;\n    }\n\n    window->layer = layer;\n    bool result = scripting_addition_set_layer(window->id, parent_layer);\n    if (!result) return false;\n\n    CFArrayRef window_list = SLSCopyAssociatedWindows(g_connection, window->id);\n    if (!window_list) return result;\n\n    int window_count = CFArrayGetCount(window_list);\n    CFTypeRef query = SLSWindowQueryWindows(g_connection, window_list, window_count);\n    CFTypeRef iterator = SLSWindowQueryResultCopyWindows(query);\n\n    int relation_count = 0;\n    uint32_t parent_list[window_count];\n    uint32_t child_list[window_count];\n\n    while (SLSWindowIteratorAdvance(iterator)) {\n        parent_list[relation_count] = SLSWindowIteratorGetParentID(iterator);\n        child_list[relation_count] = SLSWindowIteratorGetWindowID(iterator);\n        ++relation_count;\n    }\n\n    int check_count = 1;\n    uint32_t check_list[window_count];\n    check_list[0] = window->id;\n\n    for (int i = 0; i < check_count; ++i) {\n        for (int j = 0; j < window_count; ++j) {\n            if (parent_list[j] != check_list[i]) continue;\n            scripting_addition_set_layer(child_list[j], child_layer);\n            check_list[check_count++] = child_list[j];\n        }\n    }\n\n    CFRelease(query);\n    CFRelease(iterator);\n    CFRelease(window_list);\n\n    return result;\n}\n\nvoid window_manager_purify_window(struct window_manager *wm, struct window *window)\n{\n    int value;\n\n    if (wm->purify_mode == PURIFY_DISABLED) {\n        value = 1;\n    } else if (wm->purify_mode == PURIFY_MANAGED) {\n        value = window_manager_find_managed_window(wm, window) ? 0 : 1;\n    } else /*if (wm->purify_mode == PURIFY_ALWAYS) */ {\n        value = 0;\n    }\n\n    if (scripting_addition_set_shadow(window->id, value)) {\n        if (value) {\n            window_set_flag(window, WINDOW_SHADOW);\n        } else {\n            window_clear_flag(window, WINDOW_SHADOW);\n        }\n    }\n}\n\nint window_manager_find_rank_of_window_in_list(uint32_t wid, uint32_t *window_list, int window_count)\n{\n    for (int i = 0, rank = 0; i < window_count; ++i) {\n        if (window_list[i] == wid) {\n            return rank;\n        } else {\n            ++rank;\n        }\n    }\n\n    return INT_MAX;\n}\n\nstruct window *window_manager_find_window_on_space_by_rank_filtering_window(struct window_manager *wm, uint64_t sid, int rank, uint32_t filter_wid)\n{\n    int count;\n    uint32_t *window_list = space_window_list(sid, &count, false);\n    if (!window_list) return NULL;\n\n    struct window *result = NULL;\n    for (int i = 0, j = 0; i < count; ++i) {\n        if (window_list[i] == filter_wid) continue;\n\n        struct window *window = window_manager_find_window(wm, window_list[i]);\n        if (!window) continue;\n\n        if (++j == rank) {\n            result = window;\n            break;\n        }\n    }\n\n    return result;\n}\n\nstatic inline bool window_manager_window_connection_is_jankyborders(int window_cid)\n{\n    static char process_name[PROC_PIDPATHINFO_MAXSIZE];\n\n    pid_t window_pid = 0;\n    SLSConnectionGetPID(window_cid, &window_pid);\n    proc_name(window_pid, process_name, sizeof(process_name));\n\n    return strcmp(process_name, \"borders\") == 0;\n}\n\nstruct window *window_manager_find_window_at_point_filtering_window(struct window_manager *wm, CGPoint point, uint32_t filter_wid)\n{\n    CGPoint window_point;\n    uint32_t window_id;\n    int window_cid;\n\n    SLSFindWindowAndOwner(g_connection, filter_wid, -1, 0, &point, &window_point, &window_id, &window_cid);\n    if (g_connection == window_cid) SLSFindWindowAndOwner(g_connection, window_id, -1, 0, &point, &window_point, &window_id, &window_cid);\n\n    if (window_manager_window_connection_is_jankyborders(window_cid)) {\n        SLSFindWindowAndOwner(g_connection, window_id, -1, 0, &point, &window_point, &window_id, &window_cid);\n        if (g_connection == window_cid) SLSFindWindowAndOwner(g_connection, window_id, -1, 0, &point, &window_point, &window_id, &window_cid);\n    }\n\n    return window_manager_find_window(wm, window_id);\n}\n\nstruct window *window_manager_find_window_at_point(struct window_manager *wm, CGPoint point)\n{\n    CGPoint window_point;\n    uint32_t window_id;\n    int window_cid;\n\n    SLSFindWindowAndOwner(g_connection, 0, 1, 0, &point, &window_point, &window_id, &window_cid);\n    if (g_connection == window_cid) SLSFindWindowAndOwner(g_connection, window_id, -1, 0, &point, &window_point, &window_id, &window_cid);\n\n    if (window_manager_window_connection_is_jankyborders(window_cid)) {\n        SLSFindWindowAndOwner(g_connection, window_id, -1, 0, &point, &window_point, &window_id, &window_cid);\n        if (g_connection == window_cid) SLSFindWindowAndOwner(g_connection, window_id, -1, 0, &point, &window_point, &window_id, &window_cid);\n    }\n\n    return window_manager_find_window(wm, window_id);\n}\n\nstruct window *window_manager_find_window_below_cursor(struct window_manager *wm)\n{\n    CGPoint cursor;\n    SLSGetCurrentCursorLocation(g_connection, &cursor);\n    return window_manager_find_window_at_point(wm, cursor);\n}\n\nstruct window *window_manager_find_closest_managed_window_in_direction(struct window_manager *wm, struct window *window, int direction)\n{\n    struct view *view = window_manager_find_managed_window(wm, window);\n    if (!view) return NULL;\n\n    struct window_node *node = view_find_window_node(view, window->id);\n    if (!node) return NULL;\n\n    struct window_node *closest = view_find_window_node_in_direction(view, node, direction);\n    if (!closest) return NULL;\n\n    return window_manager_find_window(wm, closest->window_order[0]);\n}\n\nstruct window *window_manager_find_prev_managed_window(struct space_manager *sm, struct window_manager *wm, struct window *window)\n{\n    struct view *view = space_manager_find_view(sm, space_manager_active_space());\n    if (!view) return NULL;\n\n    struct window_node *node = view_find_window_node(view, window->id);\n    if (!node) return NULL;\n\n    struct window_node *prev = window_node_find_prev_leaf(node);\n    if (!prev) return NULL;\n\n    return window_manager_find_window(wm, prev->window_order[0]);\n}\n\nstruct window *window_manager_find_next_managed_window(struct space_manager *sm, struct window_manager *wm, struct window *window)\n{\n    struct view *view = space_manager_find_view(sm, space_manager_active_space());\n    if (!view) return NULL;\n\n    struct window_node *node = view_find_window_node(view, window->id);\n    if (!node) return NULL;\n\n    struct window_node *next = window_node_find_next_leaf(node);\n    if (!next) return NULL;\n\n    return window_manager_find_window(wm, next->window_order[0]);\n}\n\nstruct window *window_manager_find_first_managed_window(struct space_manager *sm, struct window_manager *wm)\n{\n    struct view *view = space_manager_find_view(sm, space_manager_active_space());\n    if (!view) return NULL;\n\n    struct window_node *first = window_node_find_first_leaf(view->root);\n    if (!first) return NULL;\n\n    return window_manager_find_window(wm, first->window_order[0]);\n}\n\nstruct window *window_manager_find_last_managed_window(struct space_manager *sm, struct window_manager *wm)\n{\n    struct view *view = space_manager_find_view(sm, space_manager_active_space());\n    if (!view) return NULL;\n\n    struct window_node *last = window_node_find_last_leaf(view->root);\n    if (!last) return NULL;\n\n    return window_manager_find_window(wm, last->window_order[0]);\n}\n\nstruct window *window_manager_find_recent_managed_window(struct window_manager *wm)\n{\n    struct window *window = window_manager_find_window(wm, wm->last_window_id);\n    if (!window) return NULL;\n\n    struct view *view = window_manager_find_managed_window(wm, window);\n    if (!view) return NULL;\n\n    return window;\n}\n\nstruct window *window_manager_find_prev_window_in_stack(struct space_manager *sm, struct window_manager *wm, struct window *window)\n{\n    struct view *view = space_manager_find_view(sm, space_manager_active_space());\n    if (!view) return NULL;\n\n    struct window_node *node = view_find_window_node(view, window->id);\n    if (!node) return NULL;\n\n    for (int i = 1; i < node->window_count; ++i) {\n        if (node->window_list[i] == window->id) {\n            return window_manager_find_window(wm, node->window_list[i-1]);\n        }\n    }\n\n    return NULL;\n}\n\nstruct window *window_manager_find_next_window_in_stack(struct space_manager *sm, struct window_manager *wm, struct window *window)\n{\n    struct view *view = space_manager_find_view(sm, space_manager_active_space());\n    if (!view) return NULL;\n\n    struct window_node *node = view_find_window_node(view, window->id);\n    if (!node) return NULL;\n\n    for (int i = 0; i < node->window_count - 1; ++i) {\n        if (node->window_list[i] == window->id) {\n            return window_manager_find_window(wm, node->window_list[i+1]);\n        }\n    }\n\n    return NULL;\n}\n\nstruct window *window_manager_find_first_window_in_stack(struct space_manager *sm, struct window_manager *wm, struct window *window)\n{\n    struct view *view = space_manager_find_view(sm, space_manager_active_space());\n    if (!view) return NULL;\n\n    struct window_node *node = view_find_window_node(view, window->id);\n    if (!node) return NULL;\n\n    return node->window_count > 1 ? window_manager_find_window(wm, node->window_list[0]) : NULL;\n}\n\nstruct window *window_manager_find_last_window_in_stack(struct space_manager *sm, struct window_manager *wm, struct window *window)\n{\n    struct view *view = space_manager_find_view(sm, space_manager_active_space());\n    if (!view) return NULL;\n\n    struct window_node *node = view_find_window_node(view, window->id);\n    if (!node) return NULL;\n\n    return node->window_count > 1 ? window_manager_find_window(wm, node->window_list[node->window_count-1]) : NULL;\n}\n\nstruct window *window_manager_find_recent_window_in_stack(struct space_manager *sm, struct window_manager *wm, struct window *window)\n{\n    struct view *view = space_manager_find_view(sm, space_manager_active_space());\n    if (!view) return NULL;\n\n    struct window_node *node = view_find_window_node(view, window->id);\n    if (!node) return NULL;\n\n    return node->window_count > 1 ? window_manager_find_window(wm, node->window_order[1]) : NULL;\n}\n\nstruct window *window_manager_find_window_in_stack(struct space_manager *sm, struct window_manager *wm, struct window *window, int index)\n{\n    struct view *view = space_manager_find_view(sm, space_manager_active_space());\n    if (!view) return NULL;\n\n    struct window_node *node = view_find_window_node(view, window->id);\n    if (!node) return NULL;\n\n    return node->window_count > 1 && in_range_ii(index, 1, node->window_count) ? window_manager_find_window(wm, node->window_list[index-1]) : NULL;\n}\n\nstruct window *window_manager_find_largest_managed_window(struct space_manager *sm, struct window_manager *wm)\n{\n    struct view *view = space_manager_find_view(sm, space_manager_active_space());\n    if (!view) return NULL;\n\n    uint32_t best_id   = 0;\n    uint32_t best_area = 0;\n\n    for (struct window_node *node = window_node_find_first_leaf(view->root); node != NULL; node = window_node_find_next_leaf(node)) {\n        uint32_t area = node->area.w * node->area.h;\n        if (area > best_area) {\n            best_id   = node->window_order[0];\n            best_area = area;\n        }\n    }\n\n    return best_id ? window_manager_find_window(wm, best_id) : NULL;\n}\n\nstruct window *window_manager_find_smallest_managed_window(struct space_manager *sm, struct window_manager *wm)\n{\n    struct view *view = space_manager_find_view(sm, space_manager_active_space());\n    if (!view) return NULL;\n\n    uint32_t best_id   = 0;\n    uint32_t best_area = UINT32_MAX;\n\n    for (struct window_node *node = window_node_find_first_leaf(view->root); node != NULL; node = window_node_find_next_leaf(node)) {\n        uint32_t area = node->area.w * node->area.h;\n        if (area <= best_area) {\n            best_id   = node->window_order[0];\n            best_area = area;\n        }\n    }\n\n    return best_id ? window_manager_find_window(wm, best_id) : NULL;\n}\n\nstruct window *window_manager_find_sibling_for_managed_window(struct window_manager *wm, struct window *window)\n{\n    struct view *view = window_manager_find_managed_window(wm, window);\n    if (!view) return NULL;\n\n    struct window_node *node = view_find_window_node(view, window->id);\n    if (!node || !node->parent) return NULL;\n\n    struct window_node *sibling_node = window_node_is_left_child(node) ? node->parent->right : node->parent->left;\n    if (!window_node_is_leaf(sibling_node)) return NULL;\n\n    return window_manager_find_window(wm, sibling_node->window_order[0]);\n}\n\nstruct window *window_manager_find_first_nephew_for_managed_window(struct window_manager *wm, struct window *window)\n{\n    struct view *view = window_manager_find_managed_window(wm, window);\n    if (!view) return NULL;\n\n    struct window_node *node = view_find_window_node(view, window->id);\n    if (!node || !node->parent) return NULL;\n\n    struct window_node *sibling_node = window_node_is_left_child(node) ? node->parent->right : node->parent->left;\n    if (window_node_is_leaf(sibling_node) || !window_node_is_leaf(sibling_node->left)) return NULL;\n\n    return window_manager_find_window(wm, sibling_node->left->window_order[0]);\n}\n\nstruct window *window_manager_find_second_nephew_for_managed_window(struct window_manager *wm, struct window *window)\n{\n    struct view *view = window_manager_find_managed_window(wm, window);\n    if (!view) return NULL;\n\n    struct window_node *node = view_find_window_node(view, window->id);\n    if (!node || !node->parent) return NULL;\n\n    struct window_node *sibling_node = window_node_is_left_child(node) ? node->parent->right : node->parent->left;\n    if (window_node_is_leaf(sibling_node) || !window_node_is_leaf(sibling_node->right)) return NULL;\n\n    return window_manager_find_window(wm, sibling_node->right->window_order[0]);\n}\n\nstruct window *window_manager_find_uncle_for_managed_window(struct window_manager *wm, struct window *window)\n{\n    struct view *view = window_manager_find_managed_window(wm, window);\n    if (!view) return NULL;\n\n    struct window_node *node = view_find_window_node(view, window->id);\n    if (!node || !node->parent) return NULL;\n\n    struct window_node *grandparent = node->parent->parent;\n    if (!grandparent) return NULL;\n\n    struct window_node *uncle_node = window_node_is_left_child(node->parent) ? grandparent->right : grandparent->left;\n    if (!window_node_is_leaf(uncle_node)) return NULL;\n\n    return window_manager_find_window(wm, uncle_node->window_order[0]);\n}\n\nstruct window *window_manager_find_first_cousin_for_managed_window(struct window_manager *wm, struct window *window)\n{\n    struct view *view = window_manager_find_managed_window(wm, window);\n    if (!view) return NULL;\n\n    struct window_node *node = view_find_window_node(view, window->id);\n    if (!node || !node->parent) return NULL;\n\n    struct window_node *grandparent = node->parent->parent;\n    if (!grandparent) return NULL;\n\n    struct window_node *uncle_node = window_node_is_left_child(node->parent) ? grandparent->right : grandparent->left;\n    if (window_node_is_leaf(uncle_node) || !window_node_is_leaf(uncle_node->left)) return NULL;\n\n    return window_manager_find_window(wm, uncle_node->left->window_order[0]);\n}\n\nstruct window *window_manager_find_second_cousin_for_managed_window(struct window_manager *wm, struct window *window)\n{\n    struct view *view = window_manager_find_managed_window(wm, window);\n    if (!view) return NULL;\n\n    struct window_node *node = view_find_window_node(view, window->id);\n    if (!node || !node->parent) return NULL;\n\n    struct window_node *grandparent = node->parent->parent;\n    if (!grandparent) return NULL;\n\n    struct window_node *uncle_node = window_node_is_left_child(node->parent) ? grandparent->right : grandparent->left;\n    if (window_node_is_leaf(uncle_node) || !window_node_is_leaf(uncle_node->right)) return NULL;\n\n    return window_manager_find_window(wm, uncle_node->right->window_order[0]);\n}\n\nstatic void window_manager_make_key_window(ProcessSerialNumber *window_psn, uint32_t window_id)\n{\n    //\n    // :SynthesizedEvent\n    //\n    // NOTE(asmvik): These events will be picked up by an event-tap\n    // registered at the \"Annotated Session\" location; specifying that an\n    // event-tap is placed at the point where session events have been\n    // annotated to flow to an application.\n    //\n\n    memset(g_event_bytes, 0, 0xf8);\n    g_event_bytes[0x04] = 0xf8;\n    g_event_bytes[0x3a] = 0x10;\n    memcpy(g_event_bytes + 0x3c, &window_id, sizeof(uint32_t));\n    memset(g_event_bytes + 0x20, 0xff, 0x10);\n\n    g_event_bytes[0x08] = 0x01;\n    SLPSPostEventRecordTo(window_psn, g_event_bytes);\n\n    g_event_bytes[0x08] = 0x02;\n    SLPSPostEventRecordTo(window_psn, g_event_bytes);\n}\n\nvoid window_manager_focus_window_without_raise(ProcessSerialNumber *window_psn, uint32_t window_id)\n{\n    TIME_FUNCTION;\n\n    if (psn_equals(window_psn, &g_window_manager.focused_window_psn)) {\n        memset(g_event_bytes, 0, 0xf8);\n        g_event_bytes[0x04] = 0xf8;\n        g_event_bytes[0x08] = 0x0d;\n\n        g_event_bytes[0x8a] = 0x02;\n        memcpy(g_event_bytes + 0x3c, &g_window_manager.focused_window_id, sizeof(uint32_t));\n        SLPSPostEventRecordTo(&g_window_manager.focused_window_psn, g_event_bytes);\n\n        //\n        // @hack\n        // Artificially delay the activation by 1ms. This is necessary\n        // because some applications appear to be confused if both of\n        // the events appear instantaneously.\n        //\n\n        usleep(10000);\n\n        g_event_bytes[0x8a] = 0x01;\n        memcpy(g_event_bytes + 0x3c, &window_id, sizeof(uint32_t));\n        SLPSPostEventRecordTo(window_psn, g_event_bytes);\n    }\n\n    _SLPSSetFrontProcessWithOptions(window_psn, window_id, kCPSUserGenerated);\n    window_manager_make_key_window(window_psn, window_id);\n}\n\nvoid window_manager_focus_window_with_raise(ProcessSerialNumber *window_psn, uint32_t window_id, AXUIElementRef window_ref)\n{\n    TIME_FUNCTION;\n\n#if 1\n    _SLPSSetFrontProcessWithOptions(window_psn, window_id, kCPSUserGenerated);\n    window_manager_make_key_window(window_psn, window_id);\n    AXUIElementPerformAction(window_ref, kAXRaiseAction);\n#else\n    scripting_addition_focus_window(window_id);\n#endif\n}\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wdeprecated-declarations\"\nstruct application *window_manager_focused_application(struct window_manager *wm)\n{\n    TIME_FUNCTION;\n\n    ProcessSerialNumber psn = {0};\n    _SLPSGetFrontProcess(&psn);\n\n    pid_t pid;\n    GetProcessPID(&psn, &pid);\n\n    return window_manager_find_application(wm, pid);\n}\n\nstruct window *window_manager_focused_window(struct window_manager *wm)\n{\n    TIME_FUNCTION;\n\n    struct application *application = window_manager_focused_application(wm);\n    if (!application) return NULL;\n\n    uint32_t window_id = application_focused_window(application);\n    return window_manager_find_window(wm, window_id);\n}\n#pragma clang diagnostic pop\n\nbool window_manager_find_lost_front_switched_event(struct window_manager *wm, pid_t pid)\n{\n    return table_find(&wm->application_lost_front_switched_event, &pid) != NULL;\n}\n\nvoid window_manager_remove_lost_front_switched_event(struct window_manager *wm, pid_t pid)\n{\n    table_remove(&wm->application_lost_front_switched_event, &pid);\n}\n\nvoid window_manager_add_lost_front_switched_event(struct window_manager *wm, pid_t pid)\n{\n    table_add(&wm->application_lost_front_switched_event, &pid, (void *)(intptr_t) 1);\n}\n\nbool window_manager_find_lost_focused_event(struct window_manager *wm, uint32_t window_id)\n{\n    return table_find(&wm->window_lost_focused_event, &window_id) != NULL;\n}\n\nvoid window_manager_remove_lost_focused_event(struct window_manager *wm, uint32_t window_id)\n{\n    table_remove(&wm->window_lost_focused_event, &window_id);\n}\n\nvoid window_manager_add_lost_focused_event(struct window_manager *wm, uint32_t window_id)\n{\n    table_add(&wm->window_lost_focused_event, &window_id, (void *)(intptr_t) 1);\n}\n\nstruct window *window_manager_find_window(struct window_manager *wm, uint32_t window_id)\n{\n    return table_find(&wm->window, &window_id);\n}\n\nvoid window_manager_remove_window(struct window_manager *wm, uint32_t window_id)\n{\n    table_remove(&wm->window, &window_id);\n}\n\nvoid window_manager_add_window(struct window_manager *wm, struct window *window)\n{\n    table_add(&wm->window, &window->id, window);\n}\n\nstruct application *window_manager_find_application(struct window_manager *wm, pid_t pid)\n{\n    return table_find(&wm->application, &pid);\n}\n\nvoid window_manager_remove_application(struct window_manager *wm, pid_t pid)\n{\n    table_remove(&wm->application, &pid);\n}\n\nvoid window_manager_add_application(struct window_manager *wm, struct application *application)\n{\n    table_add(&wm->application, &application->pid, application);\n}\n\nstruct window **window_manager_find_application_windows(struct window_manager *wm, struct application *application, int *window_count)\n{\n    *window_count = 0;\n    struct window **window_list = ts_alloc_list(struct window *, wm->window.count);\n\n    table_for (struct window *window, wm->window, {\n        if (window->application == application) {\n            window_list[(*window_count)++] = window;\n        }\n    })\n\n    return window_list;\n}\n\nstruct window *window_manager_create_and_add_window(struct space_manager *sm, struct window_manager *wm, struct application *application, AXUIElementRef window_ref, uint32_t window_id, bool one_shot_rules)\n{\n    struct window *window = window_create(application, window_ref, window_id);\n\n    char *window_title = window_title_ts(window);\n    char *window_role = window_role_ts(window);\n    char *window_subrole = window_subrole_ts(window);\n    debug(\"%s:%d %s - %s (%s:%s:%d)\\n\", __FUNCTION__, window->id, window->application->name, window_title, window_role, window_subrole, window->is_root);\n\n    if (window_is_unknown(window)) {\n        debug(\"%s: ignoring AXUnknown window %s %d\\n\", __FUNCTION__, window->application->name, window->id);\n        window_manager_remove_lost_focused_event(wm, window->id);\n        window_destroy(window);\n        return NULL;\n    }\n\n    //\n    // NOTE(asmvik): Attempt to track **all** windows.\n    //\n\n    if (!window_observe(window)) {\n        debug(\"%s: could not observe %s %d\\n\", __FUNCTION__, window->application->name, window->id);\n        window_manager_remove_lost_focused_event(wm, window->id);\n        window_unobserve(window);\n        window_destroy(window);\n        return NULL;\n    }\n\n    if (window_manager_find_lost_focused_event(wm, window->id)) {\n        event_loop_post(&g_event_loop, WINDOW_FOCUSED, (void *)(intptr_t) window->id, 0);\n        window_manager_remove_lost_focused_event(wm, window->id);\n    }\n\n    window_manager_add_window(wm, window);\n\n    //\n    // NOTE(asmvik): However, only **root windows** are eligible for management.\n    //\n\n    if (window->is_root) {\n\n        //\n        // NOTE(asmvik): A lot of windows misreport their accessibility role, so we allow the user\n        // to specify rules to make sure that we do in fact manage these windows properly.\n        //\n        // This part of the rule must be applied at this stage (prior to other rule properties), and if\n        // no such rule matches this window, it will be ignored if it does not have a role of kAXWindowRole.\n        //\n\n        window_manager_apply_manage_rules_to_window(sm, wm, window, window_title, window_role, window_subrole, one_shot_rules);\n\n        if (window_manager_is_window_eligible(window)) {\n            window->is_eligible = true;\n            window_manager_apply_rules_to_window(sm, wm, window, window_title, window_role, window_subrole, one_shot_rules);\n            window_manager_purify_window(wm, window);\n            window_manager_set_window_opacity(wm, window, wm->normal_window_opacity);\n\n            if (application->is_hidden)                              goto out;\n            if (window_check_flag(window, WINDOW_MINIMIZE))          goto out;\n            if (window_check_flag(window, WINDOW_FULLSCREEN))        goto out;\n            if (window_check_rule_flag(window, WINDOW_RULE_MANAGED)) goto out;\n\n            if (window_check_rule_flag(window, WINDOW_RULE_FULLSCREEN)) {\n                window_clear_rule_flag(window, WINDOW_RULE_FULLSCREEN);\n                goto out;\n            }\n\n            if (window_is_sticky(window->id) ||\n                !window_can_move(window) ||\n                !window_is_standard(window) ||\n                !window_level_is_standard(window) ||\n                (!window_can_resize(window) && window_is_undersized(window))) {\n                window_set_flag(window, WINDOW_FLOAT);\n            }\n        } else {\n            debug(\"%s ignoring incorrectly marked window %s %d\\n\", __FUNCTION__, window->application->name, window->id);\n            window_set_flag(window, WINDOW_FLOAT);\n\n            //\n            // NOTE(asmvik): Print window information when debug_output is enabled.\n            // Useful for identifying and creating rules if this window should in fact be managed.\n            //\n\n            if (g_verbose) {\n                fprintf(stdout, \"window info: \\n\");\n                window_serialize(stdout, window, 0);\n                fprintf(stdout, \"\\n\");\n            }\n        }\n    } else {\n        debug(\"%s ignoring child window %s %d\\n\", __FUNCTION__, window->application->name, window->id);\n        window_set_flag(window, WINDOW_FLOAT);\n\n        //\n        // NOTE(asmvik): Print window information when debug_output is enabled.\n        //\n\n        if (g_verbose) {\n            fprintf(stdout, \"window info: \\n\");\n            window_serialize(stdout, window, 0);\n            fprintf(stdout, \"\\n\");\n        }\n    }\n\nout:\n    return window;\n}\n\nstruct window **window_manager_add_application_windows(struct space_manager *sm, struct window_manager *wm, struct application *application, int *count)\n{\n    *count = 0;\n    CFArrayRef window_list = application_window_list(application);\n    if (!window_list) return NULL;\n\n    int window_count = CFArrayGetCount(window_list);\n    struct window **list = ts_alloc_list(struct window *, window_count);\n\n    for (int i = 0; i < window_count; ++i) {\n        AXUIElementRef window_ref = CFArrayGetValueAtIndex(window_list, i);\n\n        uint32_t window_id = ax_window_id(window_ref);\n        if (!window_id || window_manager_find_window(wm, window_id)) continue;\n\n        struct window *window = window_manager_create_and_add_window(sm, wm, application, CFRetain(window_ref), window_id, true);\n        if (window) list[(*count)++] = window;\n    }\n\n    int rule_len = buf_len(wm->rules);\n    for (int i = 0; i < rule_len; ++i) {\n        if (rule_check_flag(&wm->rules[i], RULE_ONE_SHOT_REMOVE)) {\n            rule_destroy(&wm->rules[i]);\n            if (buf_del(wm->rules, i)) {\n                --i;\n                --rule_len;\n            }\n        }\n    }\n\n    CFRelease(window_list);\n    return list;\n}\n\nstatic uint32_t *window_manager_existing_application_window_list(struct application *application, int *window_count)\n{\n    int display_count;\n    uint32_t *display_list = display_manager_active_display_list(&display_count);\n    if (!display_list) return NULL;\n\n    int space_count = 0;\n    uint64_t *space_list = NULL;\n\n    for (int i = 0; i < display_count; ++i) {\n        int count;\n        uint64_t *list = display_space_list(display_list[i], &count);\n        if (!list) continue;\n\n        //\n        // NOTE(asmvik): display_space_list(..) uses a linear allocator,\n        // and so we only need to track the beginning of the first list along\n        // with the total number of windows that have been allocated.\n        //\n\n        if (!space_list) space_list = list;\n        space_count += count;\n    }\n\n    return space_list ? space_window_list_for_connection(space_list, space_count, application ? application->connection : 0, window_count, true) : NULL;\n}\n\nbool window_manager_add_existing_application_windows(struct space_manager *sm, struct window_manager *wm, struct application *application, int refresh_index)\n{\n    bool result = false;\n\n    int global_window_count;\n    uint32_t *global_window_list = window_manager_existing_application_window_list(application, &global_window_count);\n    if (!global_window_list) return result;\n\n    CFArrayRef window_list_ref = application_window_list(application);\n    int window_count = window_list_ref ? CFArrayGetCount(window_list_ref) : 0;\n\n    int empty_count = 0;\n    for (int i = 0; i < window_count; ++i) {\n        AXUIElementRef window_ref = CFArrayGetValueAtIndex(window_list_ref, i);\n        uint32_t window_id = ax_window_id(window_ref);\n\n        //\n        // @cleanup\n        //\n        // :Workaround\n        //\n        // NOTE(asmvik): The AX API appears to always include a single element for Finder that returns an empty window id.\n        // This is likely the desktop window. Other similar cases should be handled the same way; simply ignore the window when\n        // we attempt to do an equality check to see if we have correctly discovered the number of windows to track.\n        //\n\n        if (!window_id) {\n            ++empty_count;\n            continue;\n        }\n\n        if (!window_manager_find_window(wm, window_id)) {\n            window_manager_create_and_add_window(sm, wm, application, CFRetain(window_ref), window_id, false);\n        }\n    }\n\n    if (global_window_count != window_count-empty_count) {\n        if (refresh_index == -1) {\n            bool missing_window = false;\n            uint32_t *app_window_list = NULL;\n\n            for (int i = 0; i < global_window_count; ++i) {\n                struct window *window = window_manager_find_window(wm, global_window_list[i]);\n                if (!window) {\n                    missing_window = true;\n                    ts_buf_push(app_window_list, global_window_list[i]);\n                }\n            }\n\n            if (missing_window) {\n                debug(\"%s: %s has %d windows that are not yet resolved, attempting workaround\\n\", __FUNCTION__, application->name, ts_buf_len(app_window_list));\n\n                //\n                // NOTE(asmvik): MacOS API does not return AXUIElementRef of windows on inactive spaces.\n                // However, we can just brute-force the element_id and create the AXUIElementRef ourselves.\n                //\n                // :Attribution\n                // https://github.com/decodism\n                // https://github.com/lwouis/alt-tab-macos/issues/1324#issuecomment-2631035482\n                //\n\n                CFMutableDataRef data_ref = CFDataCreateMutable(NULL, 0x14);\n                CFDataIncreaseLength(data_ref, 0x14);\n\n                uint8_t *data = CFDataGetMutableBytePtr(data_ref);\n                *(uint32_t *) (data + 0x0) = application->pid;\n                *(uint32_t *) (data + 0x8) = 0x636f636f;\n\n                for (uint64_t element_id = 0; element_id < 0x7fff; ++element_id) {\n                    int app_window_list_len = ts_buf_len(app_window_list);\n                    if (app_window_list_len == 0) break;\n\n                    memcpy(data+0xc, &element_id, sizeof(uint64_t));\n                    AXUIElementRef element_ref = _AXUIElementCreateWithRemoteToken(data_ref);\n\n                    const void *role = NULL;\n                    AXUIElementCopyAttributeValue(element_ref, kAXRoleAttribute, &role);\n\n                    if (role) {\n                        if (CFEqual(role, kAXWindowRole)) {\n                            uint32_t element_wid = ax_window_id(element_ref);\n                            bool matched = false;\n\n                            if (element_wid != 0) {\n                                for (int i = 0; i < app_window_list_len; ++i) {\n                                    if (app_window_list[i] == element_wid) {\n                                        matched = true;\n                                        ts_buf_del(app_window_list, i);\n                                        break;\n                                    }\n                                }\n                            }\n\n                            if (matched) {\n                                window_manager_create_and_add_window(sm, wm, application, element_ref, element_wid, false);\n                            } else {\n                                CFRelease(element_ref);\n                            }\n                        }\n\n                        CFRelease(role);\n                    }\n                }\n\n                CFRelease(data_ref);\n            }\n\n            if (ts_buf_len(app_window_list) > 0) {\n                debug(\"%s: workaround failed to resolve all windows for %s\\n\", __FUNCTION__, application->name);\n                buf_push(wm->applications_to_refresh, application);\n            } else {\n                debug(\"%s: workaround resolved all windows for %s\\n\", __FUNCTION__, application->name);\n            }\n        } else {\n            bool missing_window = false;\n\n            for (int i = 0; i < global_window_count; ++i) {\n                struct window *window = window_manager_find_window(wm, global_window_list[i]);\n                if (!window) {\n                    missing_window = true;\n                    break;\n                }\n            }\n\n            if (!missing_window) {\n                debug(\"%s: all windows for %s are now resolved\\n\", __FUNCTION__, application->name);\n                buf_del(wm->applications_to_refresh, refresh_index);\n                result = true;\n            }\n        }\n    } else if (refresh_index != -1) {\n        debug(\"%s: all windows for %s are now resolved\\n\", __FUNCTION__, application->name);\n        buf_del(wm->applications_to_refresh, refresh_index);\n        result = true;\n    }\n\n    if (window_list_ref) CFRelease(window_list_ref);\n\n    return result;\n}\n\nenum window_op_error window_manager_set_window_insertion(struct space_manager *sm, struct window *window, int direction)\n{\n    TIME_FUNCTION;\n\n    uint64_t sid = window_space(window->id);\n    struct view *view = space_manager_find_view(sm, sid);\n    if (view->layout != VIEW_BSP) return WINDOW_OP_ERROR_INVALID_SRC_VIEW;\n\n    struct window_node *node = view_find_window_node(view, window->id);\n    if (!node) return WINDOW_OP_ERROR_INVALID_SRC_NODE;\n\n    if (view->insertion_point && view->insertion_point != window->id) {\n        struct window_node *insert_node = view_find_window_node(view, view->insertion_point);\n        if (insert_node) {\n            insert_feedback_destroy(insert_node);\n            insert_node->split = SPLIT_NONE;\n            insert_node->child = CHILD_NONE;\n            insert_node->insert_dir = 0;\n        }\n    }\n\n    if (direction == node->insert_dir) {\n        insert_feedback_destroy(node);\n        node->split = SPLIT_NONE;\n        node->child = CHILD_NONE;\n        node->insert_dir = 0;\n        view->insertion_point = 0;\n        return WINDOW_OP_ERROR_SUCCESS;\n    }\n\n    if (direction == DIR_NORTH) {\n        node->split = SPLIT_X;\n        node->child = CHILD_FIRST;\n    } else if (direction == DIR_EAST) {\n        node->split = SPLIT_Y;\n        node->child = CHILD_SECOND;\n    } else if (direction == DIR_SOUTH) {\n        node->split = SPLIT_X;\n        node->child = CHILD_SECOND;\n    } else if (direction == DIR_WEST) {\n        node->split = SPLIT_Y;\n        node->child = CHILD_FIRST;\n    }\n\n    node->insert_dir = direction;\n    view->insertion_point = node->window_order[0];\n    insert_feedback_show(node);\n\n    return WINDOW_OP_ERROR_SUCCESS;\n}\n\nenum window_op_error window_manager_stack_window(struct space_manager *sm, struct window_manager *wm, struct window *a, struct window *b)\n{\n    TIME_FUNCTION;\n\n    if (a->id == b->id) return WINDOW_OP_ERROR_SAME_WINDOW;\n\n    struct view *a_view = window_manager_find_managed_window(wm, a);\n    if (!a_view) return WINDOW_OP_ERROR_INVALID_SRC_NODE;\n\n    struct view *b_view = window_manager_find_managed_window(wm, b);\n    if (b_view) {\n        space_manager_untile_window(b_view, b);\n        window_manager_remove_managed_window(wm, b->id);\n        window_manager_purify_window(wm, b);\n    } else if (window_check_flag(b, WINDOW_FLOAT)) {\n        if (!window_manager_is_window_eligible(b)) return WINDOW_OP_ERROR_INVALID_SRC_NODE;\n        window_clear_flag(b, WINDOW_FLOAT);\n        if (window_check_flag(b, WINDOW_STICKY)) window_manager_make_window_sticky(sm, wm, b, false);\n    }\n\n    struct window_node *a_node = view_find_window_node(a_view, a->id);\n    if (a_node->window_count+1 >= NODE_MAX_WINDOW_COUNT) return WINDOW_OP_ERROR_MAX_STACK;\n\n    view_stack_window_node(a_node, b);\n    window_manager_add_managed_window(wm, b, a_view);\n    window_manager_adjust_layer(b, LAYER_BELOW);\n    scripting_addition_order_window(b->id, 1, a_node->window_order[1]);\n\n    struct area area = a_node->zoom ? a_node->zoom->area : a_node->area;\n    window_manager_animate_window((struct window_capture) { b, area.x, area.y, area.w, area.h });\n    return WINDOW_OP_ERROR_SUCCESS;\n}\n\nenum window_op_error window_manager_warp_window(struct space_manager *sm, struct window_manager *wm, struct window *a, struct window *b)\n{\n    TIME_FUNCTION;\n\n    if (a->id == b->id) return WINDOW_OP_ERROR_SAME_WINDOW;\n\n    uint64_t a_sid = window_space(a->id);\n    struct view *a_view = space_manager_find_view(sm, a_sid);\n    if (a_view->layout != VIEW_BSP) return WINDOW_OP_ERROR_INVALID_SRC_VIEW;\n\n    uint64_t b_sid = window_space(b->id);\n    struct view *b_view = space_manager_find_view(sm, b_sid);\n    if (b_view->layout != VIEW_BSP) return WINDOW_OP_ERROR_INVALID_DST_VIEW;\n\n    struct window_node *a_node = view_find_window_node(a_view, a->id);\n    if (!a_node) return WINDOW_OP_ERROR_INVALID_SRC_NODE;\n\n    struct window_node *b_node = view_find_window_node(b_view, b->id);\n    if (!b_node) return WINDOW_OP_ERROR_INVALID_DST_NODE;\n\n    if (a_node == b_node) return WINDOW_OP_ERROR_SAME_STACK;\n\n    if (a_node->parent && b_node->parent &&\n        a_node->parent == b_node->parent &&\n        a_node->window_count == 1) {\n        if (window_node_contains_window(b_node, b_view->insertion_point)) {\n            b_node->parent->split = b_node->split;\n            b_node->parent->child = b_node->child;\n\n            view_remove_window_node(a_view, a);\n            window_manager_remove_managed_window(wm, a->id);\n            window_manager_add_managed_window(wm, a, b_view);\n            struct window_node *a_node_add = view_add_window_node_with_insertion_point(b_view, a, b->id);\n\n            struct window_capture *window_list = NULL;\n            window_node_capture_windows(a_node_add, &window_list);\n            window_manager_animate_window_list(window_list, ts_buf_len(window_list));\n        } else {\n            if (window_node_contains_window(a_node, a_view->insertion_point)) {\n                a_view->insertion_point = b->id;\n            }\n\n            window_node_swap_window_list(a_node, b_node);\n\n            struct window_capture *window_list = NULL;\n            window_node_capture_windows(a_node, &window_list);\n            window_node_capture_windows(b_node, &window_list);\n            window_manager_animate_window_list(window_list, ts_buf_len(window_list));\n        }\n    } else {\n        if (a_view->sid == b_view->sid) {\n\n            //\n            // :NaturalWarp\n            //\n            // NOTE(asmvik): Precalculate both target areas and select the one that has the closest distance to the source area.\n            // This allows the warp to feel more natural in terms of where the window is placed on screen, however, this is only utilized\n            // for warp operations where both operands belong to the same space. There may be a better system to handle this if/when multiple\n            // monitors should be supported.\n            //\n\n            struct area cf, cs;\n            area_make_pair(window_node_get_split(b_view, b_node), window_node_get_gap(b_view), window_node_get_ratio(b_node), &b_node->area, &cf, &cs);\n\n            CGPoint ca = { (int)(0.5f + a_node->area.x + a_node->area.w / 2.0f), (int)(0.5f + a_node->area.y + a_node->area.h / 2.0f) };\n            float dcf = powf((ca.x - (int)(0.5f + cf.x + cf.w / 2.0f)), 2.0f) + powf((ca.y - (int)(0.5f + cf.y + cf.h / 2.0f)), 2.0f);\n            float dcs = powf((ca.x - (int)(0.5f + cs.x + cs.w / 2.0f)), 2.0f) + powf((ca.y - (int)(0.5f + cs.y + cs.h / 2.0f)), 2.0f);\n\n            if (dcf < dcs) {\n                b_node->child = CHILD_FIRST;\n            } else if (dcf > dcs) {\n                b_node->child = CHILD_SECOND;\n            } else {\n                b_node->child = window_node_is_left_child(a_node) ? CHILD_FIRST : CHILD_SECOND;\n            }\n\n            struct window_node *a_node_rm = view_remove_window_node(a_view, a);\n            struct window_node *a_node_add = view_add_window_node_with_insertion_point(b_view, a, b->id);\n\n            struct window_capture *window_list = NULL;\n            if (a_node_rm) {\n                window_node_capture_windows(a_node_rm, &window_list);\n            }\n\n            if (a_node_rm != a_node_add && a_node_rm != a_node_add->parent) {\n                window_node_capture_windows(a_node_add, &window_list);\n            }\n\n            window_manager_animate_window_list(window_list, ts_buf_len(window_list));\n        } else {\n            if (wm->focused_window_id == a->id) {\n                struct window *next = window_manager_find_window_on_space_by_rank_filtering_window(wm, a_view->sid, 1, a->id);\n                if (next) {\n                    window_manager_focus_window_with_raise(&next->application->psn, next->id, next->ref);\n                } else {\n                    _SLPSSetFrontProcessWithOptions(&g_process_manager.finder_psn, 0, kCPSNoWindows);\n                }\n            }\n\n            //\n            // :NaturalWarp\n            //\n            // TODO(asmvik): Warp operations with operands that belong to different monitors does not yet implement a heuristic to select\n            // the target area that feels the most natural in terms of where the window is placed on screen. Is it possible to do better when\n            // warping between spaces that belong to the same monitor as well??\n            //\n\n            space_manager_untile_window(a_view, a);\n            window_manager_remove_managed_window(wm, a->id);\n            window_manager_add_managed_window(wm, a, b_view);\n            space_manager_move_window_to_space(b_view->sid, a);\n            space_manager_tile_window_on_space_with_insertion_point(sm, a, b_view->sid, b->id);\n        }\n    }\n\n    return WINDOW_OP_ERROR_SUCCESS;\n}\n\nenum window_op_error window_manager_swap_window(struct space_manager *sm, struct window_manager *wm, struct window *a, struct window *b)\n{\n    TIME_FUNCTION;\n\n    if (a->id == b->id) return WINDOW_OP_ERROR_SAME_WINDOW;\n\n    uint64_t a_sid = window_space(a->id);\n    struct view *a_view = space_manager_find_view(sm, a_sid);\n\n    uint64_t b_sid = window_space(b->id);\n    struct view *b_view = space_manager_find_view(sm, b_sid);\n\n    struct window_node *a_node = view_find_window_node(a_view, a->id);\n    if (!a_node) return WINDOW_OP_ERROR_INVALID_SRC_NODE;\n\n    struct window_node *b_node = view_find_window_node(b_view, b->id);\n    if (!b_node) return WINDOW_OP_ERROR_INVALID_DST_NODE;\n\n    if (a_node == b_node) {\n        int a_list_index = 0;\n        int a_order_index = 0;\n\n        int b_list_index = 0;\n        int b_order_index = 0;\n\n        for (int i = 0; i < a_node->window_count; ++i) {\n            if (a_node->window_list[i] == a->id) {\n                a_list_index = i;\n            } else if (a_node->window_list[i] == b->id) {\n                b_list_index = i;\n            }\n\n            if (a_node->window_order[i] == a->id) {\n                a_order_index = i;\n            } else if (a_node->window_order[i] == b->id) {\n                b_order_index = i;\n            }\n        }\n\n        a_node->window_list[a_list_index] = b->id;\n        a_node->window_order[a_order_index] = b->id;\n\n        a_node->window_list[b_list_index] = a->id;\n        a_node->window_order[b_order_index] = a->id;\n\n        if (a->id == wm->focused_window_id) {\n            window_manager_focus_window_with_raise(&b->application->psn, b->id, b->ref);\n        } else if (b->id == wm->focused_window_id) {\n            window_manager_focus_window_with_raise(&a->application->psn, a->id, a->ref);\n        }\n\n        return WINDOW_OP_ERROR_SUCCESS;\n    }\n\n    if (a_view->layout != VIEW_BSP) return WINDOW_OP_ERROR_INVALID_SRC_VIEW;\n    if (b_view->layout != VIEW_BSP) return WINDOW_OP_ERROR_INVALID_DST_VIEW;\n\n    if (window_node_contains_window(a_node, a_view->insertion_point)) {\n        a_view->insertion_point = b->id;\n    } else if (window_node_contains_window(b_node, b_view->insertion_point)) {\n        b_view->insertion_point = a->id;\n    }\n\n    bool a_visible = space_is_visible(a_view->sid);\n    bool b_visible = space_is_visible(b_view->sid);\n\n    if (a_view->sid != b_view->sid) {\n        for (int i = 0; i < a_node->window_count; ++i) {\n            struct window *window = window_manager_find_window(wm, a_node->window_list[i]);\n            window_manager_remove_managed_window(wm, a_node->window_list[i]);\n            space_manager_move_window_to_space(b_view->sid, window);\n            window_manager_add_managed_window(wm, window, b_view);\n        }\n\n        for (int i = 0; i < b_node->window_count; ++i) {\n            struct window *window = window_manager_find_window(wm, b_node->window_list[i]);\n            window_manager_remove_managed_window(wm, b_node->window_list[i]);\n            space_manager_move_window_to_space(a_view->sid, window);\n            window_manager_add_managed_window(wm, window, a_view);\n        }\n\n        if (a_visible && !b_visible && a->id == wm->focused_window_id) {\n            window_manager_focus_window_with_raise(&b->application->psn, b->id, b->ref);\n        } else if (b_visible && !a_visible && b->id == wm->focused_window_id) {\n            window_manager_focus_window_with_raise(&a->application->psn, a->id, a->ref);\n        }\n    }\n\n    window_node_swap_window_list(a_node, b_node);\n    struct window_capture *window_list = NULL;\n\n    if (a_visible) {\n        window_node_capture_windows(a_node, &window_list);\n    } else {\n        view_set_flag(a_view, VIEW_IS_DIRTY);\n    }\n\n    if (b_visible) {\n        window_node_capture_windows(b_node, &window_list);\n    } else {\n        view_set_flag(b_view, VIEW_IS_DIRTY);\n    }\n\n    window_manager_animate_window_list(window_list, ts_buf_len(window_list));\n    return WINDOW_OP_ERROR_SUCCESS;\n}\n\nenum window_op_error window_manager_minimize_window(struct window *window)\n{\n    TIME_FUNCTION;\n\n    if (!window_can_minimize(window)) return WINDOW_OP_ERROR_CANT_MINIMIZE;\n    if (window_check_flag(window, WINDOW_MINIMIZE)) return WINDOW_OP_ERROR_ALREADY_MINIMIZED;\n\n    AXError result = AXUIElementSetAttributeValue(window->ref, kAXMinimizedAttribute, kCFBooleanTrue);\n    return result == kAXErrorSuccess ? WINDOW_OP_ERROR_SUCCESS : WINDOW_OP_ERROR_MINIMIZE_FAILED;\n}\n\nenum window_op_error window_manager_deminimize_window(struct window *window)\n{\n    TIME_FUNCTION;\n\n    if (!window_check_flag(window, WINDOW_MINIMIZE)) return WINDOW_OP_ERROR_NOT_MINIMIZED;\n\n    AXError result = AXUIElementSetAttributeValue(window->ref, kAXMinimizedAttribute, kCFBooleanFalse);\n    return result == kAXErrorSuccess ? WINDOW_OP_ERROR_SUCCESS : WINDOW_OP_ERROR_DEMINIMIZE_FAILED;\n}\n\nbool window_manager_close_window(struct window *window)\n{\n    TIME_FUNCTION;\n\n    CFTypeRef button = NULL;\n    AXUIElementCopyAttributeValue(window->ref, kAXCloseButtonAttribute, &button);\n    if (!button) return false;\n\n    AXUIElementPerformAction(button, kAXPressAction);\n    CFRelease(button);\n\n    return true;\n}\n\nvoid window_manager_send_window_to_space(struct space_manager *sm, struct window_manager *wm, struct window *window, uint64_t dst_sid, bool moved_by_rule)\n{\n    TIME_FUNCTION;\n\n    uint64_t src_sid = window_space(window->id);\n    if (src_sid == dst_sid) return;\n\n    if ((space_is_visible(src_sid) && (moved_by_rule || wm->focused_window_id == window->id))) {\n        struct window *next = window_manager_find_window_on_space_by_rank_filtering_window(wm, src_sid, 1, window->id);\n        if (next) {\n            window_manager_focus_window_with_raise(&next->application->psn, next->id, next->ref);\n        } else {\n            _SLPSSetFrontProcessWithOptions(&g_process_manager.finder_psn, 0, kCPSNoWindows);\n        }\n    }\n\n    struct view *view = window_manager_find_managed_window(wm, window);\n    if (view) {\n        space_manager_untile_window(view, window);\n        window_manager_remove_managed_window(wm, window->id);\n        window_manager_purify_window(wm, window);\n    }\n\n    space_manager_move_window_to_space(dst_sid, window);\n\n    if (window_manager_should_manage_window(window)) {\n        struct view *view = space_manager_tile_window_on_space(sm, window, dst_sid);\n        window_manager_add_managed_window(wm, window, view);\n    }\n}\n\nenum window_op_error window_manager_apply_grid(struct space_manager *sm, struct window_manager *wm, struct window *window, unsigned r, unsigned c, unsigned x, unsigned y, unsigned w, unsigned h)\n{\n    TIME_FUNCTION;\n\n    struct view *view = window_manager_find_managed_window(wm, window);\n    if (view) return WINDOW_OP_ERROR_INVALID_SRC_VIEW;\n\n    uint32_t did = window_display_id(window->id);\n    if (!did) return WINDOW_OP_ERROR_INVALID_SRC_VIEW;\n\n    if (x >=   c) x = c - 1;\n    if (y >=   r) y = r - 1;\n    if (w <=   0) w = 1;\n    if (h <=   0) h = 1;\n    if (w >  c-x) w = c - x;\n    if (h >  r-y) h = r - y;\n\n    CGRect bounds = display_bounds_constrained(did, false);\n    struct view *dview = space_manager_find_view(sm, display_space_id(did));\n\n    if (dview) {\n        if (view_check_flag(dview, VIEW_ENABLE_PADDING)) {\n            bounds.origin.x    += dview->left_padding;\n            bounds.size.width  -= (dview->left_padding + dview->right_padding);\n            bounds.origin.y    += dview->top_padding;\n            bounds.size.height -= (dview->top_padding + dview->bottom_padding);\n        }\n\n        if (view_check_flag(dview, VIEW_ENABLE_GAP)) {\n            int gap = window_node_get_gap(dview);\n\n            if (x > 0) {\n                bounds.origin.x   += gap;\n                bounds.size.width -= gap;\n            }\n\n            if (y > 0) {\n                bounds.origin.y    += gap;\n                bounds.size.height -= gap;\n            }\n\n            if (c > x+w) bounds.size.width  -= gap;\n            if (r > y+h) bounds.size.height -= gap;\n        }\n    }\n\n    float cw = bounds.size.width / c;\n    float ch = bounds.size.height / r;\n    float fx = bounds.origin.x + bounds.size.width  - cw * (c - x);\n    float fy = bounds.origin.y + bounds.size.height - ch * (r - y);\n    float fw = cw * w;\n    float fh = ch * h;\n\n    window_manager_animate_window((struct window_capture) { .window = window, .x = fx, .y = fy, .w = fw, .h = fh });\n    return WINDOW_OP_ERROR_SUCCESS;\n}\n\nvoid window_manager_make_window_floating(struct space_manager *sm, struct window_manager *wm, struct window *window, bool should_float, bool force)\n{\n    TIME_FUNCTION;\n\n    if (!window_manager_is_window_eligible(window)) return;\n\n    if (!force) {\n        if (!window_is_standard(window) || !window_level_is_standard(window) || !window_can_move(window)) {\n            if (!window_check_rule_flag(window, WINDOW_RULE_MANAGED)) {\n                return;\n            }\n        }\n    }\n\n    if (should_float) {\n        struct view *view = window_manager_find_managed_window(wm, window);\n        if (view) {\n            space_manager_untile_window(view, window);\n            window_manager_remove_managed_window(wm, window->id);\n            window_manager_purify_window(wm, window);\n        }\n        window_set_flag(window, WINDOW_FLOAT);\n    } else {\n        window_clear_flag(window, WINDOW_FLOAT);\n\n        if (!window_check_flag(window, WINDOW_STICKY)) {\n            if ((window_manager_should_manage_window(window)) && (!window_manager_find_managed_window(wm, window))) {\n                struct view *view = space_manager_tile_window_on_space(sm, window, space_manager_active_space());\n                window_manager_add_managed_window(wm, window, view);\n            }\n        }\n    }\n}\n\nvoid window_manager_make_window_sticky(struct space_manager *sm, struct window_manager *wm, struct window *window, bool should_sticky)\n{\n    TIME_FUNCTION;\n\n    if (!window_manager_is_window_eligible(window)) return;\n\n    if (should_sticky) {\n        if (scripting_addition_set_sticky(window->id, true)) {\n            struct view *view = window_manager_find_managed_window(wm, window);\n            if (view) {\n                space_manager_untile_window(view, window);\n                window_manager_remove_managed_window(wm, window->id);\n                window_manager_purify_window(wm, window);\n            }\n            window_set_flag(window, WINDOW_STICKY);\n        }\n    } else {\n        if (scripting_addition_set_sticky(window->id, false)) {\n            window_clear_flag(window, WINDOW_STICKY);\n\n            if (!window_check_flag(window, WINDOW_FLOAT)) {\n                if ((window_manager_should_manage_window(window)) && (!window_manager_find_managed_window(wm, window))) {\n                    struct view *view = space_manager_tile_window_on_space(sm, window, space_manager_active_space());\n                    window_manager_add_managed_window(wm, window, view);\n                }\n            }\n        }\n    }\n}\n\nvoid window_manager_toggle_window_shadow(struct window *window)\n{\n    TIME_FUNCTION;\n\n    bool shadow = !window_check_flag(window, WINDOW_SHADOW);\n    if (scripting_addition_set_shadow(window->id, shadow)) {\n        if (shadow) {\n            window_set_flag(window, WINDOW_SHADOW);\n        } else {\n            window_clear_flag(window, WINDOW_SHADOW);\n        }\n    }\n}\n\nvoid window_manager_wait_for_native_fullscreen_transition(struct window *window)\n{\n    TIME_FUNCTION;\n\n    if (workspace_is_macos_monterey() ||\n        workspace_is_macos_ventura() ||\n        workspace_is_macos_sonoma() ||\n        workspace_is_macos_sequoia() ||\n        workspace_is_macos_tahoe()) {\n        while (!space_is_user(space_manager_active_space())) {\n\n            //\n            // NOTE(asmvik): Window has exited native-fullscreen mode.\n            // We need to spin lock until the display is finished animating\n            // because we are not actually able to interact with the window.\n            //\n            // The display_manager API does not work on macOS Monterey.\n            //\n\n            usleep(100000);\n        }\n    } else {\n        uint32_t did = window_display_id(window->id);\n\n        do {\n\n            //\n            // NOTE(asmvik): Window has exited native-fullscreen mode.\n            // We need to spin lock until the display is finished animating\n            // because we are not actually able to interact with the window.\n            //\n\n            usleep(100000);\n        } while (display_manager_display_is_animating(did));\n    }\n}\n\nvoid window_manager_toggle_window_native_fullscreen(struct window *window)\n{\n    TIME_FUNCTION;\n\n    uint32_t sid = window_space(window->id);\n\n    //\n    // NOTE(asmvik): The window must become the focused window\n    // before we can change its fullscreen attribute. We focus the\n    // window and spin lock until a potential space animation has finished.\n    //\n\n    window_manager_focus_window_with_raise(&window->application->psn, window->id, window->ref);\n    while (sid != space_manager_active_space()) { usleep(100000); }\n\n\n    if (!window_is_fullscreen(window)) {\n        AXUIElementSetAttributeValue(window->ref, kAXFullscreenAttribute, kCFBooleanTrue);\n    } else {\n        AXUIElementSetAttributeValue(window->ref, kAXFullscreenAttribute, kCFBooleanFalse);\n    }\n\n    //\n    // NOTE(asmvik): We toggled the fullscreen attribute and must\n    // now spin lock until the post-exit space animation has finished.\n    //\n\n    window_manager_wait_for_native_fullscreen_transition(window);\n}\n\nvoid window_manager_toggle_window_zoom_parent(struct window_manager *wm, struct window *window)\n{\n    TIME_FUNCTION;\n\n    struct view *view = window_manager_find_managed_window(wm, window);\n    if (!view || view->layout != VIEW_BSP) return;\n\n    struct window_node *node = view_find_window_node(view, window->id);\n    assert(node);\n\n    if (!node->parent) return;\n\n    if (node->zoom == node->parent) {\n        node->zoom = NULL;\n        if (space_is_visible(view->sid)) {\n            window_node_flush(node);\n        } else {\n            view_set_flag(view, VIEW_IS_DIRTY);\n        }\n    } else {\n        node->zoom = node->parent;\n        if (space_is_visible(view->sid)) {\n            window_node_flush(node);\n        } else {\n            view_set_flag(view, VIEW_IS_DIRTY);\n        }\n    }\n}\n\nvoid window_manager_toggle_window_zoom_fullscreen(struct window_manager *wm, struct window *window)\n{\n    TIME_FUNCTION;\n\n    struct view *view = window_manager_find_managed_window(wm, window);\n    if (!view || view->layout != VIEW_BSP) return;\n\n    struct window_node *node = view_find_window_node(view, window->id);\n    assert(node);\n\n    if (node == view->root) return;\n\n    if (node->zoom == view->root) {\n        node->zoom = NULL;\n        if (space_is_visible(view->sid)) {\n            window_node_flush(node);\n        } else {\n            view_set_flag(view, VIEW_IS_DIRTY);\n        }\n    } else {\n        node->zoom = view->root;\n        if (space_is_visible(view->sid)) {\n            window_node_flush(node);\n        } else {\n            view_set_flag(view, VIEW_IS_DIRTY);\n        }\n    }\n}\n\nvoid window_manager_toggle_window_windowed_fullscreen(struct window *window)\n{\n    TIME_FUNCTION;\n\n    uint32_t did = window_display_id(window->id);\n    if (!did) return;\n\n    if (window_check_flag(window, WINDOW_WINDOWED)) {\n        window_clear_flag(window, WINDOW_WINDOWED);\n        window_manager_animate_window((struct window_capture) { .window = window, .x = window->windowed_frame.origin.x , .y = window->windowed_frame.origin.y, .w = window->windowed_frame.size.width, .h = window->windowed_frame.size.height });\n    } else {\n        window_set_flag(window, WINDOW_WINDOWED);\n        window->windowed_frame = window->frame;\n        CGRect bounds = display_bounds_constrained(did, true);\n        window_manager_animate_window((struct window_capture) { .window = window, .x = bounds.origin.x, .y = bounds.origin.y, .w = bounds.size.width, .h = bounds.size.height });\n    }\n}\n\nvoid window_manager_toggle_window_expose(struct window *window)\n{\n    TIME_FUNCTION;\n\n    window_manager_focus_window_with_raise(&window->application->psn, window->id, window->ref);\n    CoreDockSendNotification(CFSTR(\"com.apple.expose.front.awake\"), 0);\n}\n\nvoid window_manager_toggle_window_pip(struct space_manager *sm, struct window *window)\n{\n    TIME_FUNCTION;\n\n    uint32_t did = window_display_id(window->id);\n    if (!did) return;\n\n    uint64_t sid = display_space_id(did);\n    struct view *dview = space_manager_find_view(sm, sid);\n\n    CGRect bounds = display_bounds_constrained(did, false);\n    if (dview && view_check_flag(dview, VIEW_ENABLE_PADDING)) {\n        bounds.origin.x    += dview->left_padding;\n        bounds.size.width  -= (dview->left_padding + dview->right_padding);\n        bounds.origin.y    += dview->top_padding;\n        bounds.size.height -= (dview->top_padding + dview->bottom_padding);\n    }\n\n    scripting_addition_scale_window(window->id, bounds.origin.x, bounds.origin.y, bounds.size.width, bounds.size.height);\n}\n\nstatic inline struct window *window_manager_find_scratchpad_window(struct window_manager *wm, char *label)\n{\n    for (int i = 0; i < buf_len(wm->scratchpad_window); ++i) {\n        if (string_equals(wm->scratchpad_window[i].label, label)) {\n            return wm->scratchpad_window[i].window;\n        }\n    }\n\n    return NULL;\n}\n\nbool window_manager_toggle_scratchpad_window_by_label(struct window_manager *wm, char *label)\n{\n    struct window *window = window_manager_find_scratchpad_window(wm, label);\n    return window ? window_manager_toggle_scratchpad_window(wm, window, 0) : false;\n}\n\nbool window_manager_toggle_scratchpad_window(struct window_manager *wm, struct window *window, int forced_mode)\n{\n    TIME_FUNCTION;\n\n    uint64_t sid = space_manager_active_space();\n    if (!sid) return false;\n\n    // TODO(asmvik): Both functions use the same underlying API and could be combined in a single function to reduce redundant work.\n    bool visible_space = window_space(window->id) == sid || window_is_sticky(window->id);\n\n    uint8_t ordered_in = 0;\n    SLSWindowIsOrderedIn(g_connection, window->id, &ordered_in);\n\n    switch (forced_mode) {\n    case 0: goto mode_0;\n    case 1: goto mode_1;\n    case 2: goto mode_2;\n    case 3: goto mode_3;\n    }\n\nmode_0:;\n    if (visible_space && ordered_in) {\nmode_1:;\n        struct window *next = window_manager_find_window_on_space_by_rank_filtering_window(wm, sid, 1, window->id);\n        if (next) {\n            window_manager_focus_window_with_raise(&next->application->psn, next->id, next->ref);\n        } else {\n            _SLPSSetFrontProcessWithOptions(&g_process_manager.finder_psn, 0, kCPSNoWindows);\n        }\n        scripting_addition_order_window(window->id, 0, 0);\n    } else if (visible_space && !ordered_in) {\nmode_2:;\n        scripting_addition_order_window(window->id, 1, 0);\n        window_manager_focus_window_with_raise(&window->application->psn, window->id, window->ref);\n    } else {\nmode_3:;\n        space_manager_move_window_to_space(sid, window);\n        scripting_addition_order_window(window->id, 1, 0);\n        window_manager_focus_window_with_raise(&window->application->psn, window->id, window->ref);\n    }\n\n    return true;\n}\n\nbool window_manager_set_scratchpad_for_window(struct window_manager *wm, struct window *window, char *label)\n{\n    struct window *existing_window = window_manager_find_scratchpad_window(wm, label);\n    if (existing_window) return false;\n\n    window_manager_remove_scratchpad_for_window(wm, window, false);\n    buf_push(wm->scratchpad_window, ((struct scratchpad) {\n        .label = label,\n        .window = window\n    }));\n    window->scratchpad = label;\n    window_manager_make_window_floating(&g_space_manager, wm, window, true, false);\n\n    return true;\n}\n\nbool window_manager_remove_scratchpad_for_window(struct window_manager *wm, struct window *window, bool unfloat)\n{\n    for (int i = 0; i < buf_len(wm->scratchpad_window); ++i) {\n        if (wm->scratchpad_window[i].window == window) {\n            window->scratchpad = NULL;\n\n            free(wm->scratchpad_window[i].label);\n            buf_del(wm->scratchpad_window, i);\n\n            if (unfloat) {\n                window_manager_toggle_scratchpad_window(wm, window, 3);\n                window_manager_make_window_floating(&g_space_manager, wm, window, false, false);\n            }\n\n            return true;\n        }\n    }\n\n    return false;\n}\n\nvoid window_manager_scratchpad_recover_windows(void)\n{\n    int window_count;\n    uint32_t *window_list = window_manager_existing_application_window_list(NULL, &window_count);\n    if (!window_list) return;\n\n    if (scripting_addition_order_window_in(window_list, window_count)) {\n        space_manager_refresh_application_windows(&g_space_manager);\n    }\n}\n\nstatic void window_manager_validate_windows_on_space(struct window_manager *wm, struct view *view, uint32_t *window_list, int window_count)\n{\n    int view_window_count;\n    uint32_t *view_window_list = view_find_window_list(view, &view_window_count);\n\n    for (int i = 0; i < view_window_count; ++i) {\n        bool found = false;\n\n        for (int j = 0; j < window_count; ++j) {\n            if (view_window_list[i] == window_list[j]) {\n                found = true;\n                break;\n            }\n        }\n\n        if (!found) {\n            struct window *window = window_manager_find_window(wm, view_window_list[i]);\n            if (!window) continue;\n\n            //\n            // @cleanup\n            //\n            // :AXBatching\n            //\n            // NOTE(asmvik): Batch all operations and mark the view as dirty so that we can perform a single flush,\n            // making sure that each window is only moved and resized a single time, when the final layout has been computed.\n            // This is necessary to make sure that we do not call the AX API for each modification to the tree.\n            //\n\n            view_remove_window_node(view, window);\n            window_manager_adjust_layer(window, LAYER_NORMAL);\n            window_manager_remove_managed_window(wm, window->id);\n            window_manager_purify_window(wm, window);\n\n            view_set_flag(view, VIEW_IS_DIRTY);\n        }\n    }\n}\n\nstatic void window_manager_check_for_windows_on_space(struct window_manager *wm, struct view *view, uint32_t *window_list, int window_count)\n{\n    for (int i = 0; i < window_count; ++i) {\n        struct window *window = window_manager_find_window(wm, window_list[i]);\n        if (!window || !window_manager_should_manage_window(window)) continue;\n\n        struct view *existing_view = window_manager_find_managed_window(wm, window);\n        if (existing_view && existing_view->layout != VIEW_FLOAT && existing_view != view) {\n\n            //\n            // @cleanup\n            //\n            // :AXBatching\n            //\n            // NOTE(asmvik): Batch all operations and mark the view as dirty so that we can perform a single flush,\n            // making sure that each window is only moved and resized a single time, when the final layout has been computed.\n            // This is necessary to make sure that we do not call the AX API for each modification to the tree.\n            //\n\n            view_remove_window_node(existing_view, window);\n            window_manager_adjust_layer(window, LAYER_NORMAL);\n            window_manager_remove_managed_window(wm, window->id);\n            window_manager_purify_window(wm, window);\n            view_set_flag(existing_view, VIEW_IS_DIRTY);\n        }\n\n        if (!existing_view || (existing_view->layout != VIEW_FLOAT && existing_view != view)) {\n\n            //\n            // @cleanup\n            //\n            // :AXBatching\n            //\n            // NOTE(asmvik): Batch all operations and mark the view as dirty so that we can perform a single flush,\n            // making sure that each window is only moved and resized a single time, when the final layout has been computed.\n            // This is necessary to make sure that we do not call the AX API for each modification to the tree.\n            //\n\n            view_add_window_node(view, window);\n            window_manager_adjust_layer(window, LAYER_BELOW);\n            window_manager_add_managed_window(wm, window, view);\n            view_set_flag(view, VIEW_IS_DIRTY);\n        }\n    }\n}\n\nvoid window_manager_validate_and_check_for_windows_on_space(struct space_manager *sm, struct window_manager *wm, uint64_t sid)\n{\n    struct view *view = space_manager_find_view(sm, sid);\n    if (view->layout == VIEW_FLOAT) return;\n\n    int window_count = 0;\n    uint32_t *window_list = space_window_list(sid, &window_count, false);\n    window_manager_validate_windows_on_space(wm, view, window_list, window_count);\n    window_manager_check_for_windows_on_space(wm, view, window_list, window_count);\n\n    //\n    // @cleanup\n    //\n    // :AXBatching\n    //\n    // NOTE(asmvik): Flush previously batched operations if the view is marked as dirty.\n    // This is necessary to make sure that we do not call the AX API for each modification to the tree.\n    //\n\n    if (space_is_visible(view->sid) && view_is_dirty(view)) {\n        window_node_flush(view->root);\n        view_clear_flag(view, VIEW_IS_DIRTY);\n    }\n}\n\nvoid window_manager_correct_for_mission_control_changes(struct space_manager *sm, struct window_manager *wm)\n{\n    int display_count;\n    uint32_t *display_list = display_manager_active_display_list(&display_count);\n    if (!display_list) return;\n\n    float animation_duration = wm->window_animation_duration;\n    wm->window_animation_duration = 0.0f;\n\n    for (int i = 0; i < display_count; ++i) {\n        uint32_t did = display_list[i];\n\n        int space_count;\n        uint64_t *space_list = display_space_list(did, &space_count);\n        if (!space_list) continue;\n\n        uint64_t sid = display_space_id(did);\n        for (int j = 0; j < space_count; ++j) {\n            if (space_list[j] == sid) {\n                window_manager_validate_and_check_for_windows_on_space(sm, wm, sid);\n            } else {\n                space_manager_mark_view_invalid(sm, space_list[j]);\n            }\n        }\n    }\n\n    wm->window_animation_duration = animation_duration;\n}\n\nvoid window_manager_handle_display_add_and_remove(struct space_manager *sm, struct window_manager *wm, uint32_t did)\n{\n    int space_count;\n    uint64_t *space_list = display_space_list(did, &space_count);\n    if (!space_list) return;\n\n    for (int i = 0; i < space_count; ++i) {\n        if (space_is_user(space_list[i])) {\n            int window_count;\n            uint32_t *window_list = space_window_list(space_list[i], &window_count, false);\n            if (window_list) {\n                struct view *view = space_manager_find_view(sm, space_list[i]);\n                if (view->layout != VIEW_FLOAT) {\n                    window_manager_check_for_windows_on_space(wm, view, window_list, window_count);\n                }\n            }\n            break;\n        }\n    }\n\n    uint64_t sid = display_space_id(did);\n    for (int i = 0; i < space_count; ++i) {\n        if (space_list[i] == sid) {\n            space_manager_refresh_view(sm, sid);\n        } else {\n            space_manager_mark_view_invalid(sm, space_list[i]);\n        }\n    }\n}\n\nvoid window_manager_init(struct window_manager *wm)\n{\n    wm->system_element = AXUIElementCreateSystemWide();\n    AXUIElementSetMessagingTimeout(wm->system_element, 1.0);\n\n    wm->ffm_mode = FFM_DISABLED;\n    wm->purify_mode = PURIFY_DISABLED;\n    wm->window_origin_mode = WINDOW_ORIGIN_DEFAULT;\n    wm->enable_mff = false;\n    wm->enable_window_opacity = false;\n    wm->menubar_opacity = 1.0f;\n    wm->active_window_opacity = 1.0f;\n    wm->normal_window_opacity = 1.0f;\n    wm->window_opacity_duration = 0.0f;\n    wm->window_animation_duration = 0.0f;\n    wm->window_animation_easing = ease_out_circ_type;\n    wm->insert_feedback_color = rgba_color_from_hex(0xffd75f5f);\n\n    table_init(&wm->application, 150, hash_wm, compare_wm);\n    table_init(&wm->window, 150, hash_wm, compare_wm);\n    table_init(&wm->managed_window, 150, hash_wm, compare_wm);\n    table_init(&wm->window_lost_focused_event, 150, hash_wm, compare_wm);\n    table_init(&wm->application_lost_front_switched_event, 150, hash_wm, compare_wm);\n    table_init(&wm->window_animations_table, 150, hash_wm, compare_wm);\n    table_init(&wm->insert_feedback, 150, hash_wm, compare_wm);\n    pthread_mutex_init(&wm->window_animations_lock, NULL);\n}\n\nvoid window_manager_begin(struct space_manager *sm, struct window_manager *wm)\n{\n    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];\n    table_for (struct process *process, g_process_manager.process, {\n        if (workspace_application_is_observable(process)) {\n            struct application *application = application_create(process);\n\n            if (application_observe(application)) {\n                window_manager_add_application(wm, application);\n                window_manager_add_existing_application_windows(sm, wm, application, -1);\n            } else {\n                application_unobserve(application);\n                application_destroy(application);\n            }\n        } else {\n            debug(\"%s: %s (%d) is not observable, subscribing to activationPolicy changes\\n\", __FUNCTION__, process->name, process->pid);\n            workspace_application_observe_activation_policy(g_workspace_context, process);\n        }\n    })\n    [pool drain];\n\n    struct window *window = window_manager_focused_window(wm);\n    if (window) {\n        wm->last_window_id = window->id;\n        wm->focused_window_id = window->id;\n        wm->focused_window_psn = window->application->psn;\n        window_manager_set_window_opacity(wm, window, wm->active_window_opacity);\n    }\n}\n"
  },
  {
    "path": "src/window_manager.h",
    "content": "#ifndef WINDOW_MANAGER_H\n#define WINDOW_MANAGER_H\n\n#define kCPSAllWindows    0x100\n#define kCPSUserGenerated 0x200\n#define kCPSNoWindows     0x400\n\nenum window_op_error\n{\n    WINDOW_OP_ERROR_SUCCESS,\n    WINDOW_OP_ERROR_INVALID_SRC_VIEW,\n    WINDOW_OP_ERROR_INVALID_SRC_NODE,\n    WINDOW_OP_ERROR_INVALID_DST_VIEW,\n    WINDOW_OP_ERROR_INVALID_DST_NODE,\n    WINDOW_OP_ERROR_INVALID_OPERATION,\n    WINDOW_OP_ERROR_SAME_WINDOW,\n    WINDOW_OP_ERROR_CANT_MINIMIZE,\n    WINDOW_OP_ERROR_ALREADY_MINIMIZED,\n    WINDOW_OP_ERROR_MINIMIZE_FAILED,\n    WINDOW_OP_ERROR_NOT_MINIMIZED,\n    WINDOW_OP_ERROR_DEMINIMIZE_FAILED,\n    WINDOW_OP_ERROR_MAX_STACK,\n    WINDOW_OP_ERROR_SAME_STACK,\n};\n\nenum purify_mode\n{\n    PURIFY_DISABLED,\n    PURIFY_MANAGED,\n    PURIFY_ALWAYS\n};\n\nstatic const char *purify_mode_str[] =\n{\n    \"on\",\n    \"float\",\n    \"off\"\n};\n\nenum ffm_mode\n{\n    FFM_DISABLED,\n    FFM_AUTOFOCUS,\n    FFM_AUTORAISE\n};\n\nstatic const char *ffm_mode_str[] =\n{\n    \"disabled\",\n    \"autofocus\",\n    \"autoraise\"\n};\n\nenum window_origin_mode\n{\n    WINDOW_ORIGIN_DEFAULT,\n    WINDOW_ORIGIN_FOCUSED,\n    WINDOW_ORIGIN_CURSOR\n};\n\nstatic const char *window_origin_mode_str[] =\n{\n    \"default\",\n    \"focused\",\n    \"cursor\"\n};\n\nstruct scratchpad\n{\n    char *label;\n    struct window *window;\n};\n\nstruct window_manager\n{\n    AXUIElementRef system_element;\n    struct table application;\n    struct table window;\n    struct table managed_window;\n    struct table window_lost_focused_event;\n    struct table application_lost_front_switched_event;\n    struct table window_animations_table;\n    struct table insert_feedback;\n    pthread_mutex_t window_animations_lock;\n    struct rule *rules;\n    struct application **applications_to_refresh;\n    uint32_t focused_window_id;\n    ProcessSerialNumber focused_window_psn;\n    uint32_t last_window_id;\n    bool enable_mff;\n    enum ffm_mode ffm_mode;\n    enum purify_mode purify_mode;\n    enum window_origin_mode window_origin_mode;\n    bool enable_window_opacity;\n    float menubar_opacity;\n    float active_window_opacity;\n    float normal_window_opacity;\n    float window_opacity_duration;\n    float window_animation_duration;\n    int window_animation_easing;\n    struct rgba_color insert_feedback_color;\n    struct scratchpad *scratchpad_window;\n};\n\nvoid window_manager_query_window_rules(FILE *rsp);\nvoid window_manager_query_windows_for_spaces(FILE *rsp, uint64_t *space_list, int space_count, uint64_t flags);\nvoid window_manager_query_windows_for_display(FILE *rsp, uint32_t did, uint64_t flags);\nvoid window_manager_query_windows_for_displays(FILE *rsp, uint64_t flags);\nbool window_manager_rule_matches_window(struct rule *rule, struct window *window, char *window_title, char *window_role, char *window_subrole);\nvoid window_manager_apply_manage_rule_effects_to_window(struct space_manager *sm, struct window_manager *wm, struct window *window, struct rule_effects *effects);\nvoid window_manager_apply_rule_effects_to_window(struct space_manager *sm, struct window_manager *wm, struct window *window, struct rule_effects *effects);\nvoid window_manager_apply_manage_rules_to_window(struct space_manager *sm, struct window_manager *wm, struct window *window, char *window_title, char *window_role, char *window_subrole, bool one_shot_rules);\nvoid window_manager_apply_rules_to_window(struct space_manager *sm, struct window_manager *wm, struct window *window, char *window_title, char *window_role, char *window_subrole, bool one_shot_rules);\nvoid window_manager_center_mouse(struct window_manager *wm, struct window *window);\nbool window_manager_is_window_eligible(struct window *window);\nbool window_manager_should_manage_window(struct window *window);\nvoid window_manager_tile_window(struct window_manager *wm, struct window *window);\nvoid window_manager_move_window(struct window *window, float x, float y);\nvoid window_manager_resize_window(struct window *window, float width, float height);\nenum window_op_error window_manager_adjust_window_ratio(struct window_manager *wm, struct window *window, int action, float ratio);\nvoid window_manager_animate_window(struct window_capture capture);\nvoid window_manager_animate_window_list(struct window_capture *window_list, int window_count);\nvoid window_manager_set_window_frame(struct window *window, float x, float y, float width, float height);\nint window_manager_find_rank_of_window_in_list(uint32_t wid, uint32_t *window_list, int window_count);\nstruct window *window_manager_find_window_on_space_by_rank_filtering_window(struct window_manager *wm, uint64_t sid, int rank, uint32_t filter_wid);\nstruct window *window_manager_find_window_at_point_filtering_window(struct window_manager *wm, CGPoint point, uint32_t filter_wid);\nstruct window *window_manager_find_window_at_point(struct window_manager *wm, CGPoint point);\nstruct window *window_manager_find_window_below_cursor(struct window_manager *wm);\nstruct window *window_manager_find_closest_managed_window_in_direction(struct window_manager *wm, struct window *window, int direction);\nstruct window *window_manager_find_prev_managed_window(struct space_manager *sm, struct window_manager *wm, struct window *window);\nstruct window *window_manager_find_next_managed_window(struct space_manager *sm, struct window_manager *wm, struct window *window);\nstruct window *window_manager_find_first_managed_window(struct space_manager *sm, struct window_manager *wm);\nstruct window *window_manager_find_last_managed_window(struct space_manager *sm, struct window_manager *wm);\nstruct window *window_manager_find_recent_managed_window(struct window_manager *wm);\nstruct window *window_manager_find_prev_window_in_stack(struct space_manager *sm, struct window_manager *wm, struct window *window);\nstruct window *window_manager_find_next_window_in_stack(struct space_manager *sm, struct window_manager *wm, struct window *window);\nstruct window *window_manager_find_first_window_in_stack(struct space_manager *sm, struct window_manager *wm, struct window *window);\nstruct window *window_manager_find_last_window_in_stack(struct space_manager *sm, struct window_manager *wm, struct window *window);\nstruct window *window_manager_find_recent_window_in_stack(struct space_manager *sm, struct window_manager *wm, struct window *window);\nstruct window *window_manager_find_window_in_stack(struct space_manager *sm, struct window_manager *wm, struct window *window, int index);\nstruct window *window_manager_find_largest_managed_window(struct space_manager *sm, struct window_manager *wm);\nstruct window *window_manager_find_smallest_managed_window(struct space_manager *sm, struct window_manager *wm);\nstruct window *window_manager_find_sibling_for_managed_window(struct window_manager *wm, struct window *window);\nstruct window *window_manager_find_first_nephew_for_managed_window(struct window_manager *wm, struct window *window);\nstruct window *window_manager_find_second_nephew_for_managed_window(struct window_manager *wm, struct window *window);\nstruct window *window_manager_find_uncle_for_managed_window(struct window_manager *wm, struct window *window);\nstruct window *window_manager_find_first_cousin_for_managed_window(struct window_manager *wm, struct window *window);\nstruct window *window_manager_find_second_cousin_for_managed_window(struct window_manager *wm, struct window *window);\nvoid window_manager_focus_window_without_raise(ProcessSerialNumber *window_psn, uint32_t window_id);\nvoid window_manager_focus_window_with_raise(ProcessSerialNumber *window_psn, uint32_t window_id, AXUIElementRef window_ref);\nstruct window *window_manager_focused_window(struct window_manager *wm);\nstruct application *window_manager_focused_application(struct window_manager *wm);\nstruct view *window_manager_find_managed_window(struct window_manager *wm, struct window *window);\nvoid window_manager_remove_managed_window(struct window_manager *wm, uint32_t wid);\nvoid window_manager_add_managed_window(struct window_manager *wm, struct window *window, struct view *view);\nbool window_manager_find_lost_front_switched_event(struct window_manager *wm, pid_t pid);\nvoid window_manager_remove_lost_front_switched_event(struct window_manager *wm, pid_t pid);\nvoid window_manager_add_lost_front_switched_event(struct window_manager *wm, pid_t pid);\nbool window_manager_find_lost_focused_event(struct window_manager *wm, uint32_t window_id);\nvoid window_manager_remove_lost_focused_event(struct window_manager *wm, uint32_t window_id);\nvoid window_manager_add_lost_focused_event(struct window_manager *wm, uint32_t window_id);\nstruct window *window_manager_find_window(struct window_manager *wm, uint32_t window_id);\nvoid window_manager_remove_window(struct window_manager *wm, uint32_t window_id);\nvoid window_manager_add_window(struct window_manager *wm, struct window *window);\nstruct application *window_manager_find_application(struct window_manager *wm, pid_t pid);\nvoid window_manager_remove_application(struct window_manager *wm, pid_t pid);\nvoid window_manager_add_application(struct window_manager *wm, struct application *application);\nstruct window **window_manager_find_application_windows(struct window_manager *wm, struct application *application, int *window_count);\nenum window_op_error window_manager_move_window_relative(struct window_manager *wm, struct window *window, int type, float dx, float dy);\nvoid window_manager_resize_window_relative_internal(struct window *window, CGRect frame, int direction, float dx, float dy, bool animate);\nenum window_op_error window_manager_resize_window_relative(struct window_manager *wm, struct window *window, int direction, float dx, float dy, bool animate);\nvoid window_manager_set_purify_mode(struct window_manager *wm, enum purify_mode mode);\nvoid window_manager_set_menubar_opacity(struct window_manager *wm, float opacity);\nvoid window_manager_set_active_window_opacity(struct window_manager *wm, float opacity);\nvoid window_manager_set_normal_window_opacity(struct window_manager *wm, float opacity);\nvoid window_manager_set_window_opacity_enabled(struct window_manager *wm, bool enabled);\nbool window_manager_set_opacity(struct window_manager *wm, struct window *window, float opacity);\nvoid window_manager_set_window_opacity(struct window_manager *wm, struct window *window, float opacity);\nvoid window_manager_set_focus_follows_mouse(struct window_manager *wm, enum ffm_mode mode);\nenum window_op_error window_manager_set_window_insertion(struct space_manager *sm, struct window *window, int direction);\nenum window_op_error window_manager_stack_window(struct space_manager *sm, struct window_manager *wm, struct window *a, struct window *b);\nenum window_op_error window_manager_warp_window(struct space_manager *sm, struct window_manager *wm, struct window *a, struct window *b);\nenum window_op_error window_manager_swap_window(struct space_manager *sm, struct window_manager *wm, struct window *a, struct window *b);\nenum window_op_error window_manager_minimize_window(struct window *window);\nenum window_op_error window_manager_deminimize_window(struct window *window);\nbool window_manager_close_window(struct window *window);\nvoid window_manager_send_window_to_space(struct space_manager *sm, struct window_manager *wm, struct window *window, uint64_t sid, bool moved_by_rule);\nstruct window *window_manager_create_and_add_window(struct space_manager *sm, struct window_manager *wm, struct application *application, AXUIElementRef window_ref, uint32_t window_id, bool one_shot_rules);\nstruct window **window_manager_add_application_windows(struct space_manager *sm, struct window_manager *wm, struct application *application, int *count);\nbool window_manager_add_existing_application_windows(struct space_manager *sm, struct window_manager *wm, struct application *application, int refresh_index);\nenum window_op_error window_manager_apply_grid(struct space_manager *sm, struct window_manager *wm, struct window *window, unsigned r, unsigned c, unsigned x, unsigned y, unsigned w, unsigned h);\nvoid window_manager_purify_window(struct window_manager *wm, struct window *window);\nvoid window_manager_make_window_floating(struct space_manager *sm, struct window_manager *wm, struct window *window, bool should_float, bool force);\nvoid window_manager_make_window_sticky(struct space_manager *sm, struct window_manager *wm, struct window *window, bool should_sticky);\nvoid window_manager_adjust_layer(struct window *window, int layer);\nbool window_manager_set_window_layer(struct window *window, int layer);\nvoid window_manager_toggle_window_shadow(struct window *window);\nvoid window_manager_toggle_window_zoom_parent(struct window_manager *wm, struct window *window);\nvoid window_manager_toggle_window_zoom_fullscreen(struct window_manager *wm, struct window *window);\nvoid window_manager_toggle_window_windowed_fullscreen(struct window *window);\nvoid window_manager_toggle_window_native_fullscreen(struct window *window);\nvoid window_manager_toggle_window_expose(struct window *window);\nvoid window_manager_toggle_window_pip(struct space_manager *sm, struct window *window);\nbool window_manager_toggle_scratchpad_window_by_label(struct window_manager *wm, char *label);\nbool window_manager_toggle_scratchpad_window(struct window_manager *wm, struct window *window, int forced_mode);\nbool window_manager_set_scratchpad_for_window(struct window_manager *wm, struct window *window, char *label);\nbool window_manager_remove_scratchpad_for_window(struct window_manager *wm, struct window *window, bool unfloat);\nvoid window_manager_scratchpad_recover_windows(void);\nvoid window_manager_wait_for_native_fullscreen_transition(struct window *window);\nvoid window_manager_validate_and_check_for_windows_on_space(struct space_manager *sm, struct window_manager *wm, uint64_t sid);\nvoid window_manager_correct_for_mission_control_changes(struct space_manager *sm, struct window_manager *wm);\nvoid window_manager_handle_display_add_and_remove(struct space_manager *sm, struct window_manager *wm, uint32_t did);\nvoid window_manager_begin(struct space_manager *sm, struct window_manager *wm);\nvoid window_manager_init(struct window_manager *wm);\n\n#endif\n"
  },
  {
    "path": "src/workspace.h",
    "content": "#ifndef WORKSPACE_H\n#define WORKSPACE_H\n\n#define SUPPORTED_MACOS_VERSION_LIST    \\\n    SUPPORT_MACOS_VERSION(tahoe,    26) \\\n    SUPPORT_MACOS_VERSION(sequoia,  15) \\\n    SUPPORT_MACOS_VERSION(sonoma,   14) \\\n    SUPPORT_MACOS_VERSION(ventura,  13) \\\n    SUPPORT_MACOS_VERSION(monterey, 12) \\\n    SUPPORT_MACOS_VERSION(bigsur,   11)\n\n#define SUPPORT_MACOS_VERSION(name, major_version) \\\nstatic bool _workspace_is_macos_version_##name; \\\nstatic inline bool workspace_is_macos_##name(void) \\\n{ \\\n    return _workspace_is_macos_version_##name; \\\n}\n    SUPPORTED_MACOS_VERSION_LIST\n#undef SUPPORT_MACOS_VERSION\n\n@interface workspace_context : NSObject {\n}\n- (id)init;\n@end\n\nstruct process;\nvoid *workspace_application_create_running_ns_application(struct process *process);\nvoid workspace_application_destroy_running_ns_application(void *context, struct process *process);\nvoid workspace_application_unobserve(void *context, struct process *process);\nbool workspace_application_is_observable(struct process *process);\nbool workspace_application_is_finished_launching(struct process *process);\nvoid workspace_application_observe_finished_launching(void *context, struct process *process);\nvoid workspace_application_observe_activation_policy(void *context, struct process *process);\nint workspace_display_notch_height(uint32_t did);\npid_t workspace_get_dock_pid(void);\nbool workspace_event_handler_begin(void **context);\nbool workspace_use_macos_space_workaround(void);\n\n#endif\n"
  },
  {
    "path": "src/workspace.m",
    "content": "bool workspace_event_handler_begin(void **context)\n{\n    NSOperatingSystemVersion version = [[NSProcessInfo processInfo] operatingSystemVersion];\n#define SUPPORT_MACOS_VERSION(name, major_version) _workspace_is_macos_version_##name = version.majorVersion == major_version;\n    SUPPORTED_MACOS_VERSION_LIST\n#undef SUPPORT_MACOS_VERSION\n\n    workspace_context *ws_context = [workspace_context alloc];\n    if (!ws_context) return false;\n\n    [ws_context init];\n    *context = ws_context;\n\n    return true;\n}\n\nbool workspace_use_macos_space_workaround(void)\n{\n    NSOperatingSystemVersion os_version = [[NSProcessInfo processInfo] operatingSystemVersion];\n\n    if (os_version.majorVersion == 12 && os_version.minorVersion >= 7) return true;\n    if (os_version.majorVersion == 13 && os_version.minorVersion >= 6) return true;\n    if (os_version.majorVersion == 14 && os_version.minorVersion >= 5) return true;\n\n    return os_version.majorVersion >= 15;\n}\n\nvoid *workspace_application_create_running_ns_application(struct process *process)\n{\n    return [[NSRunningApplication runningApplicationWithProcessIdentifier:process->pid] retain];\n}\n\nvoid workspace_application_destroy_running_ns_application(void *ws_context, struct process *process)\n{\n    NSRunningApplication *application = __atomic_load_n(&process->ns_application, __ATOMIC_RELAXED);\n\n    if (application) {\n        if ([application observationInfo]) {\n\n            //\n            // :WorstApiEverMade\n            //\n            // NOTE(asmvik): Because the developers of this API did such an amazing job\n            // there is no way for us to actually just friggin loop through the currently\n            // registered observations and then call removeObservation on them..\n            //\n            // Instead we just try to force remove the observations that **could** be present\n            // at this point in time, because it will complain if we try to actually release\n            // the object when it has observers present.\n            //\n            // We can't actually correctly track whether it did actually get unobserved previously,\n            // because even when our notification callback is triggered it will claim that we try\n            // to remove a non-existing observation when it just called us back.\n            //\n\n            @try {\n                [application removeObserver:ws_context forKeyPath:@\"activationPolicy\" context:process];\n            } @catch (NSException * __unused exception) {}\n\n            @try {\n                [application removeObserver:ws_context forKeyPath:@\"finishedLaunching\" context:process];\n            } @catch (NSException * __unused exception) {}\n        }\n\n        [application release];\n    }\n}\n\nvoid workspace_application_observe_finished_launching(void *context, struct process *process)\n{\n    NSRunningApplication *application = __atomic_load_n(&process->ns_application, __ATOMIC_RELAXED);\n    if (application) {\n        [application addObserver:context forKeyPath:@\"finishedLaunching\" options:NSKeyValueObservingOptionInitial|NSKeyValueObservingOptionNew context:process];\n    } else {\n        debug(\"%s: could not subscribe to finished launching changes for %s (%d)\\n\", __FUNCTION__, process->name, process->pid);\n    }\n}\n\nvoid workspace_application_observe_activation_policy(void *context, struct process *process)\n{\n    NSRunningApplication *application = __atomic_load_n(&process->ns_application, __ATOMIC_RELAXED);\n    if (application) {\n        [application addObserver:context forKeyPath:@\"activationPolicy\" options:NSKeyValueObservingOptionInitial|NSKeyValueObservingOptionNew context:process];\n    } else {\n        debug(\"%s: could not subscribe to activation policy changes for %s (%d)\\n\", __FUNCTION__, process->name, process->pid);\n    }\n}\n\nvoid workspace_application_unobserve(void *ws_context, struct process *process)\n{\n    NSRunningApplication *application = __atomic_load_n(&process->ns_application, __ATOMIC_RELAXED);\n    if (application) {\n        @try {\n            [application removeObserver:ws_context forKeyPath:@\"activationPolicy\" context:process];\n        } @catch (NSException * __unused exception) {}\n\n        @try {\n            [application removeObserver:ws_context forKeyPath:@\"finishedLaunching\" context:process];\n        } @catch (NSException * __unused exception) {}\n    }\n}\n\nbool workspace_application_is_observable(struct process *process)\n{\n    NSRunningApplication *application = __atomic_load_n(&process->ns_application, __ATOMIC_RELAXED);\n    if (application) {\n        process->policy = [application activationPolicy];\n        return process->policy == NSApplicationActivationPolicyRegular;\n    } else {\n        process->policy = NSApplicationActivationPolicyProhibited;\n        return false;\n    }\n}\n\nbool workspace_application_is_finished_launching(struct process *process)\n{\n    NSRunningApplication *application = __atomic_load_n(&process->ns_application, __ATOMIC_RELAXED);\n    if (application) {\n        return [application isFinishedLaunching] == YES;\n    } else {\n        return false;\n    }\n}\n\nint workspace_display_notch_height(uint32_t did)\n{\n    if (!CGDisplayIsBuiltin(did)) return 0;\n\n    if (__builtin_available(macos 12.0, *)) {\n        for (NSScreen *screen in [NSScreen screens]) {\n            if ([[[screen deviceDescription] objectForKey:@\"NSScreenNumber\"] unsignedIntValue] == did) {\n                return screen.safeAreaInsets.top;\n            }\n        }\n    }\n\n    return 0;\n}\n\npid_t workspace_get_dock_pid(void)\n{\n    NSArray *list = [NSRunningApplication runningApplicationsWithBundleIdentifier:@\"com.apple.dock\"];\n\n    if (list.count == 1) {\n        NSRunningApplication *dock = list[0];\n        return [dock processIdentifier];\n    }\n\n    return 0;\n}\n\nextern struct event_loop g_event_loop;\n@implementation workspace_context\n- (id)init\n{\n    if ((self = [super init])) {\n       [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self\n                selector:@selector(activeDisplayDidChange:)\n                name:@\"NSWorkspaceActiveDisplayDidChangeNotification\"\n                object:nil];\n\n       [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self\n                selector:@selector(activeSpaceDidChange:)\n                name:NSWorkspaceActiveSpaceDidChangeNotification\n                object:nil];\n\n       [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self\n                selector:@selector(didHideApplication:)\n                name:NSWorkspaceDidHideApplicationNotification\n                object:nil];\n\n       [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self\n                selector:@selector(didUnhideApplication:)\n                name:NSWorkspaceDidUnhideApplicationNotification\n                object:nil];\n\n       [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self\n                selector:@selector(didWake:)\n                name:NSWorkspaceDidWakeNotification\n                object:nil];\n\n       [[NSDistributedNotificationCenter defaultCenter] addObserver:self\n                selector:@selector(didChangeMenuBarHiding:)\n                name:@\"AppleInterfaceMenuBarHidingChangedNotification\"\n                object:nil];\n\n       [[NSNotificationCenter defaultCenter] addObserver:self\n                selector:@selector(didRestartDock:)\n                name:@\"NSApplicationDockDidRestartNotification\"\n                object:nil];\n\n       [[NSDistributedNotificationCenter defaultCenter] addObserver:self\n                selector:@selector(didChangeDockPref:)\n                name:@\"com.apple.dock.prefchanged\"\n                object:nil];\n    }\n\n    return self;\n}\n\n- (void)dealloc\n{\n    [[[NSWorkspace sharedWorkspace] notificationCenter] removeObserver:self];\n    [[NSNotificationCenter defaultCenter] removeObserver:self];\n    [[NSDistributedNotificationCenter defaultCenter] removeObserver:self];\n    [super dealloc];\n}\n\n- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context\n{\n    if ([keyPath isEqualToString:@\"activationPolicy\"]) {\n        struct process *process = context;\n        if (process->terminated) return;\n\n        id result = [change objectForKey:NSKeyValueChangeNewKey];\n        if ([result intValue] != process->policy) {\n            //\n            // :WorstApiEverMade\n            //\n            // NOTE(asmvik): For some stupid reason it is possible to get notified by the system\n            // about a change, and NOT being able to remove ourselves from observation because\n            // it claims that we are not observing the key-path, but we clearly are, as we would\n            // otherwise not be here in the first place..\n            //\n\n            @try {\n                [object removeObserver:self forKeyPath:@\"activationPolicy\" context:process];\n            } @catch (NSException * __unused exception) {}\n\n            process->policy = [result intValue];\n            debug(\"%s: activation policy changed for %s (%d)\\n\", __FUNCTION__, process->name, process->pid);\n            event_loop_post(&g_event_loop, APPLICATION_LAUNCHED, process, 0);\n        }\n    }\n\n    if ([keyPath isEqualToString:@\"finishedLaunching\"]) {\n        struct process *process = context;\n        if (process->terminated) return;\n\n        id result = [change objectForKey:NSKeyValueChangeNewKey];\n        if ([result intValue] == 1) {\n            //\n            // :WorstApiEverMade\n            //\n            // NOTE(asmvik): For some stupid reason it is possible to get notified by the system\n            // about a change, and NOT being able to remove ourselves from observation because\n            // it claims that we are not observing the key-path, but we clearly are, as we would\n            // otherwise not be here in the first place..\n            //\n\n            @try {\n                [object removeObserver:self forKeyPath:@\"finishedLaunching\" context:process];\n            } @catch (NSException * __unused exception) {}\n\n            debug(\"%s: %s (%d) finished launching\\n\", __FUNCTION__, process->name, process->pid);\n            event_loop_post(&g_event_loop, APPLICATION_LAUNCHED, process, 0);\n        }\n    }\n}\n\n- (void)didWake:(NSNotification *)notification\n{\n    event_loop_post(&g_event_loop, SYSTEM_WOKE, NULL, 0);\n}\n\n- (void)didChangeMenuBarHiding:(NSNotification *)notification\n{\n    event_loop_post(&g_event_loop, MENU_BAR_HIDDEN_CHANGED, NULL, 0);\n}\n\n- (void)didRestartDock:(NSNotification *)notification\n{\n    event_loop_post(&g_event_loop, DOCK_DID_RESTART, NULL, 0);\n}\n\n- (void)didChangeDockPref:(NSNotification *)notification\n{\n    event_loop_post(&g_event_loop, DOCK_DID_CHANGE_PREF, NULL, 0);\n}\n\n- (void)activeDisplayDidChange:(NSNotification *)notification\n{\n    event_loop_post(&g_event_loop, DISPLAY_CHANGED, NULL, 0);\n}\n\n- (void)activeSpaceDidChange:(NSNotification *)notification\n{\n    event_loop_post(&g_event_loop, SPACE_CHANGED, NULL, 0);\n}\n\n- (void)didHideApplication:(NSNotification *)notification\n{\n    pid_t pid = [[notification.userInfo objectForKey:NSWorkspaceApplicationKey] processIdentifier];\n    event_loop_post(&g_event_loop, APPLICATION_HIDDEN, (void *)(intptr_t) pid, 0);\n}\n\n- (void)didUnhideApplication:(NSNotification *)notification\n{\n    pid_t pid = [[notification.userInfo objectForKey:NSWorkspaceApplicationKey] processIdentifier];\n    event_loop_post(&g_event_loop, APPLICATION_VISIBLE, (void *)(intptr_t) pid, 0);\n}\n\n@end\n"
  },
  {
    "path": "src/yabai.c",
    "content": "#define SA_SOCKET_PATH_FMT      \"/tmp/yabai-sa_%s.socket\"\n#define SOCKET_PATH_FMT         \"/tmp/yabai_%s.socket\"\n#define LCFILE_PATH_FMT         \"/tmp/yabai_%s.lock\"\n\n#define SCRPT_ADD_LOAD_OPT      \"--load-sa\"\n#define SCRPT_ADD_UNINSTALL_OPT \"--uninstall-sa\"\n#define SERVICE_INSTALL_OPT     \"--install-service\"\n#define SERVICE_UNINSTALL_OPT   \"--uninstall-service\"\n#define SERVICE_START_OPT       \"--start-service\"\n#define SERVICE_RESTART_OPT     \"--restart-service\"\n#define SERVICE_STOP_OPT        \"--stop-service\"\n#define CLIENT_OPT_LONG         \"--message\"\n#define CLIENT_OPT_SHRT         \"-m\"\n#define CONFIG_OPT_LONG         \"--config\"\n#define CONFIG_OPT_SHRT         \"-c\"\n#define DEBUG_VERBOSE_OPT_LONG  \"--verbose\"\n#define DEBUG_VERBOSE_OPT_SHRT  \"-V\"\n#define VERSION_OPT_LONG        \"--version\"\n#define VERSION_OPT_SHRT        \"-v\"\n#define HELP_OPT_LONG           \"--help\"\n#define HELP_OPT_SHRT           \"-h\"\n\n#define MAJOR  7\n#define MINOR  1\n#define PATCH 17\n\nstruct signal *g_signal_event[SIGNAL_TYPE_COUNT];\nstruct process_manager g_process_manager;\nstruct display_manager g_display_manager;\nstruct window_manager g_window_manager;\nstruct space_manager g_space_manager;\nstruct memory_pool g_signal_storage;\nstruct mouse_state g_mouse_state;\nstruct event_loop g_event_loop;\nvoid *g_workspace_context;\n\nenum mission_control_mode g_mission_control_mode;\ndouble g_cv_host_clock_frequency;\nint g_layer_normal_window_level;\nint g_layer_below_window_level;\nint g_layer_above_window_level;\nuint8_t *g_event_bytes;\n\nchar g_sa_socket_file[MAXLEN];\nchar g_socket_file[MAXLEN];\nchar g_config_file[4096];\nchar g_lock_file[MAXLEN];\n\nmach_port_t g_bs_port;\nint g_connection;\nbool g_verbose;\npid_t g_pid;\n\nstatic int client_send_message(int argc, char **argv)\n{\n    if (argc <= 1) {\n        error(\"yabai-msg: no arguments given! abort..\\n\");\n    }\n\n    char *user = getenv(\"USER\");\n    if (!user) {\n        error(\"yabai-msg: 'env USER' not set! abort..\\n\");\n    }\n\n    int message_length = argc;\n    int argl[argc];\n\n    for (int i = 1; i < argc; ++i) {\n        argl[i] = strlen(argv[i]);\n        message_length += argl[i];\n    }\n\n    char *message = malloc(sizeof(int)+message_length);\n    char *temp = sizeof(int)+message;\n\n    memcpy(message, &message_length, sizeof(int));\n    for (int i = 1; i < argc; ++i) {\n        memcpy(temp, argv[i], argl[i]);\n        temp += argl[i];\n        *temp++ = '\\0';\n    }\n    *temp++ = '\\0';\n\n    int sockfd;\n    char socket_file[MAXLEN];\n    snprintf(socket_file, sizeof(socket_file), SOCKET_PATH_FMT, user);\n\n    if (!socket_open(&sockfd)) {\n        error(\"yabai-msg: failed to open socket..\\n\");\n    }\n\n    if (!socket_connect(sockfd, socket_file)) {\n        error(\"yabai-msg: failed to connect to socket..\\n\");\n    }\n\n    if (send(sockfd, message, sizeof(int)+message_length, 0) == -1) {\n        error(\"yabai-msg: failed to send data..\\n\");\n    }\n\n    shutdown(sockfd, SHUT_WR);\n    free(message);\n\n    int result = EXIT_SUCCESS;\n    FILE *output = stdout;\n    int bytes_read = 0;\n    char rsp[BUFSIZ];\n\n    while ((bytes_read = read(sockfd, rsp, sizeof(rsp)-1)) > 0) {\n        rsp[bytes_read] = '\\0';\n\n        if (rsp[0] == FAILURE_MESSAGE[0]) {\n            result = EXIT_FAILURE;\n            output = stderr;\n            fprintf(output, \"%s\", rsp + 1);\n            fflush(output);\n        } else {\n            fprintf(output, \"%s\", rsp);\n            fflush(output);\n        }\n    }\n\n    socket_close(sockfd);\n    return result;\n}\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wdeprecated-declarations\"\nstatic inline bool configure_settings_and_acquire_lock(void)\n{\n    char *user = getenv(\"USER\");\n    if (!user) {\n        error(\"yabai: 'env USER' not set! abort..\\n\");\n    }\n\n    snprintf(g_sa_socket_file, sizeof(g_sa_socket_file), SA_SOCKET_PATH_FMT, user);\n    snprintf(g_socket_file, sizeof(g_socket_file), SOCKET_PATH_FMT, user);\n    snprintf(g_lock_file, sizeof(g_lock_file), LCFILE_PATH_FMT, user);\n\n    NSApplicationLoad();\n    g_pid = getpid();\n    g_event_bytes = malloc(0x100);\n    memset(g_event_bytes, 0, 0x100);\n    g_connection = SLSMainConnectionID();\n    g_cv_host_clock_frequency   = CVGetHostClockFrequency();\n    g_layer_normal_window_level = CGWindowLevelForKey(LAYER_NORMAL);\n    g_layer_below_window_level  = CGWindowLevelForKey(LAYER_BELOW);\n    g_layer_above_window_level  = CGWindowLevelForKey(LAYER_ABOVE);\n    CGSGetConnectionPortById    = macho_find_symbol(\"/System/Library/PrivateFrameworks/SkyLight.framework/Versions/A/SkyLight\", \"_CGSGetConnectionPortById\");\n\n    signal(SIGCHLD, SIG_IGN);\n    signal(SIGPIPE, SIG_IGN);\n    CGSetLocalEventsSuppressionInterval(0.0f);\n    CGEnableEventStateCombining(false);\n    mouse_state_init(&g_mouse_state);\n    task_get_special_port(mach_task_self(), TASK_BOOTSTRAP_PORT, &g_bs_port);\n\n#if 0\n    hook_nsobject_autorelease();\n    hook_autoreleasepool_drain();\n    hook_autoreleasepool_release();\n#endif\n\n    int handle = open(g_lock_file, O_CREAT | O_WRONLY, 0600);\n    if (handle == -1) {\n        error(\"yabai: could not create lock-file! abort..\\n\");\n    }\n\n    struct flock lockfd = {\n        .l_start  = 0,\n        .l_len    = 0,\n        .l_pid    = g_pid,\n        .l_type   = F_WRLCK,\n        .l_whence = SEEK_SET\n    };\n\n    return fcntl(handle, F_SETLK, &lockfd) != -1;\n}\n#pragma clang diagnostic pop\n\nstatic void parse_arguments(int argc, char **argv)\n{\n    if ((string_equals(argv[1], HELP_OPT_LONG)) ||\n        (string_equals(argv[1], HELP_OPT_SHRT))) {\n        fprintf(stdout, \"Usage: yabai [option]\\n\"\n                        \"Options:\\n\"\n                        \"    --load-sa              Install and load the scripting-addition.\\n\"\n                        \"    --uninstall-sa         Uninstall the scripting-addition.\\n\"\n                        \"    --install-service      Write launchd service file to disk.\\n\"\n                        \"    --uninstall-service    Remove launchd service file from disk.\\n\"\n                        \"    --start-service        Enable, load, and start the launchd service.\\n\"\n                        \"    --restart-service      Attempts to restart the service instance.\\n\"\n                        \"    --stop-service         Stops a running instance of the service.\\n\"\n                        \"    --message, -m <msg>    Send message to a running instance of yabai.\\n\"\n                        \"    --config, -c <config>  Use the specified configuration file.\\n\"\n                        \"    --verbose, -V          Output debug information to stdout.\\n\"\n                        \"    --version, -v          Print version to stdout and exit.\\n\"\n                        \"    --help, -h             Print options to stdout and exit.\\n\"\n                        \"Type `man yabai` for more information, or visit: \"\n                        \"https://github.com/asmvik/yabai/blob/v%d.%d.%d/doc/yabai.asciidoc\\n\", MAJOR, MINOR, PATCH);\n        exit(EXIT_SUCCESS);\n    }\n\n    if ((string_equals(argv[1], VERSION_OPT_LONG)) ||\n        (string_equals(argv[1], VERSION_OPT_SHRT))) {\n        fprintf(stdout, \"yabai-v%d.%d.%d\\n\", MAJOR, MINOR, PATCH);\n        exit(EXIT_SUCCESS);\n    }\n\n    if ((string_equals(argv[1], CLIENT_OPT_LONG)) ||\n        (string_equals(argv[1], CLIENT_OPT_SHRT))) {\n        exit(client_send_message(argc-1, argv+1));\n    }\n\n    if (string_equals(argv[1], SCRPT_ADD_UNINSTALL_OPT)) {\n        exit(scripting_addition_uninstall());\n    }\n\n    if (string_equals(argv[1], SCRPT_ADD_LOAD_OPT)) {\n        exit(scripting_addition_load());\n    }\n\n    if (string_equals(argv[1], SERVICE_INSTALL_OPT)) {\n        exit(service_install());\n    }\n\n    if (string_equals(argv[1], SERVICE_UNINSTALL_OPT)) {\n        exit(service_uninstall());\n    }\n\n    if (string_equals(argv[1], SERVICE_START_OPT)) {\n        exit(service_start());\n    }\n\n    if (string_equals(argv[1], SERVICE_RESTART_OPT)) {\n        exit(service_restart());\n    }\n\n    if (string_equals(argv[1], SERVICE_STOP_OPT)) {\n        exit(service_stop());\n    }\n\n    for (int i = 1; i < argc; ++i) {\n        char *opt = argv[i];\n\n        if ((string_equals(opt, DEBUG_VERBOSE_OPT_LONG)) ||\n            (string_equals(opt, DEBUG_VERBOSE_OPT_SHRT))) {\n            g_verbose = true;\n        } else if ((string_equals(opt, CONFIG_OPT_LONG)) ||\n                   (string_equals(opt, CONFIG_OPT_SHRT))) {\n            char *val = i < argc - 1 ? argv[++i] : NULL;\n            if (!val) error(\"yabai: option '%s|%s' requires an argument!\\n\", CONFIG_OPT_LONG, CONFIG_OPT_SHRT);\n            snprintf(g_config_file, sizeof(g_config_file), \"%s\", val);\n        } else {\n            error(\"yabai: '%s' is not a valid option!\\n\", opt);\n        }\n    }\n}\n\n#ifndef TESTS\nint main(int argc, char **argv)\n{\n    if (argc > 1) {\n        parse_arguments(argc, argv);\n    }\n\n    if (is_root()) {\n        require(\"yabai: running as root is not allowed! abort..\\n\");\n    }\n\n    if (!ax_privilege()) {\n        require(\"yabai: could not access accessibility features! abort..\\n\");\n    }\n\n    if (!(SLSGetSpaceManagementMode(SLSMainConnectionID()) == 1)) {\n        require(\"yabai: 'display has separate spaces' is disabled! abort..\\n\");\n    }\n\n    if (!ts_init(MEGABYTES(8))) {\n        error(\"yabai: could not allocate temporary storage! abort..\\n\");\n    }\n\n    if (!memory_pool_init(&g_signal_storage, KILOBYTES(256))) {\n        error(\"yabai: could not allocate event signal storage! abort..\\n\");\n    }\n\n    if (!configure_settings_and_acquire_lock()) {\n        error(\"yabai: could not acquire lock-file! abort..\\n\");\n    }\n\n    if (!event_loop_begin(&g_event_loop)) {\n        error(\"yabai: could not start event loop! abort..\\n\");\n    }\n\n    if (!workspace_event_handler_begin(&g_workspace_context)) {\n        error(\"yabai: could not start workspace context! abort..\\n\");\n    }\n\n    if (!process_manager_begin(&g_process_manager)) {\n        error(\"yabai: could not start process manager! abort..\\n\");\n    }\n\n    if (!display_manager_begin(&g_display_manager)) {\n        error(\"yabai: could not start display manager! abort..\\n\");\n    }\n\n    if (!mouse_handler_begin(&g_mouse_state, MOUSE_EVENT_MASK)) {\n        error(\"yabai: could not start mouse handler! abort..\\n\");\n    }\n\n    if (workspace_is_macos_monterey() ||\n        workspace_is_macos_ventura() ||\n        workspace_is_macos_sonoma() ||\n        workspace_is_macos_sequoia() ||\n        workspace_is_macos_tahoe()) {\n        mission_control_observe();\n\n        if (workspace_is_macos_ventura() ||\n            workspace_is_macos_sonoma() ||\n            workspace_is_macos_sequoia() ||\n            workspace_is_macos_tahoe()) {\n            SLSRegisterConnectionNotifyProc(g_connection, connection_handler, 1327, NULL);\n            SLSRegisterConnectionNotifyProc(g_connection, connection_handler, 1328, NULL);\n        }\n    } else {\n        SLSRegisterConnectionNotifyProc(g_connection, connection_handler, 1204, NULL);\n    }\n\n    SLSRegisterConnectionNotifyProc(g_connection, connection_handler, 808, NULL);\n\n    if (workspace_is_macos_sequoia() || workspace_is_macos_tahoe()) {\n        SLSRegisterConnectionNotifyProc(g_connection, connection_handler, 804, NULL);\n    }\n\n    window_manager_init(&g_window_manager);\n    space_manager_begin(&g_space_manager);\n    window_manager_begin(&g_space_manager, &g_window_manager);\n\n    if (workspace_is_macos_sequoia() || workspace_is_macos_tahoe()) {\n        update_window_notifications();\n    }\n\n    if (!message_loop_begin(g_socket_file)) {\n        error(\"yabai: could not start message loop! abort..\\n\");\n    }\n\n    exec_config_file(g_config_file, sizeof(g_config_file));\n\n    [NSApp run];\n\n    return 0;\n}\n#endif\n\nPROFILER_END_TRANSLATION_UNIT\n"
  },
  {
    "path": "tests/makefile",
    "content": ".PHONY: clean build run all\n\nall: clean build run\n\nclean:\n\trm -rf ./bin\n\nbuild:\n\tmkdir -p ./bin\n\tclang ./src/tests.m -o ./bin/tests -DTESTS -DPROFILE=1 -F/System/Library/PrivateFrameworks -framework Carbon -framework Cocoa -framework CoreServices -framework CoreVideo -framework SkyLight\n\nrun:\n\t./bin/tests\n"
  },
  {
    "path": "tests/src/area.c",
    "content": "struct test_area\n{\n    struct area area;\n    CGPoint area_max;\n};\n\nstatic inline void init_test_display_list(struct test_area display_list[3])\n{\n    display_list[0].area.x   = 0;\n    display_list[0].area.y   = 0;\n    display_list[0].area.w   = 2560;\n    display_list[0].area.h   = 1440;\n    display_list[0].area_max = area_max_point(display_list[0].area);\n\n    display_list[1].area.x   = -1728;\n    display_list[1].area.y   = 0;\n    display_list[1].area.w   = 1728;\n    display_list[1].area.h   = 1117;\n    display_list[1].area_max = area_max_point(display_list[1].area);\n\n    display_list[2].area.x   = 2560;\n    display_list[2].area.y   = 0;\n    display_list[2].area.w   = 1920;\n    display_list[2].area.h   = 1080;\n    display_list[2].area_max = area_max_point(display_list[2].area);\n}\n\nTEST_FUNC(display_area_is_in_direction,\n{\n    struct test_area display_list[3];\n    init_test_display_list(display_list);\n\n    bool t1 = area_is_in_direction(&display_list[0].area, display_list[0].area_max, &display_list[1].area, display_list[1].area_max, DIR_WEST);\n    TEST_CHECK(t1, true);\n\n    bool t2 = area_is_in_direction(&display_list[0].area, display_list[0].area_max, &display_list[1].area, display_list[1].area_max, DIR_EAST);\n    TEST_CHECK(t2, false);\n\n    bool t3 = area_is_in_direction(&display_list[0].area, display_list[0].area_max, &display_list[2].area, display_list[2].area_max, DIR_WEST);\n    TEST_CHECK(t3, false);\n\n    bool t4 = area_is_in_direction(&display_list[0].area, display_list[0].area_max, &display_list[2].area, display_list[2].area_max, DIR_EAST);\n    TEST_CHECK(t4, true);\n});\n\nstatic inline int closest_display_in_direction(struct test_area *display_list, int display_count, int source, int direction)\n{\n    int best_index    = -1;\n    int best_distance = INT_MAX;\n\n    for (int i = 0; i < display_count; ++i) {\n        if (i == source) continue;\n\n        if (area_is_in_direction(&display_list[source].area, display_list[source].area_max, &display_list[i].area, display_list[i].area_max, direction)) {\n            int distance = area_distance_in_direction(&display_list[source].area, display_list[source].area_max, &display_list[i].area, display_list[i].area_max, direction);\n            if (distance < best_distance) {\n                best_index = i;\n                best_distance = distance;\n            }\n        }\n    }\n\n    return best_index;\n}\n\nTEST_FUNC(closest_display_in_direction,\n{\n    int best_index;\n    struct test_area display_list[3];\n    init_test_display_list(display_list);\n\n    best_index = closest_display_in_direction(display_list, array_count(display_list), 0, DIR_WEST);\n    TEST_CHECK(best_index, 1);\n\n    best_index = closest_display_in_direction(display_list, array_count(display_list), 1, DIR_WEST);\n    TEST_CHECK(best_index, -1);\n\n    best_index = closest_display_in_direction(display_list, array_count(display_list), 2, DIR_WEST);\n    TEST_CHECK(best_index, 0);\n\n    best_index = closest_display_in_direction(display_list, array_count(display_list), 0, DIR_EAST);\n    TEST_CHECK(best_index, 2);\n\n    best_index = closest_display_in_direction(display_list, array_count(display_list), 1, DIR_EAST);\n    TEST_CHECK(best_index, 0);\n\n    best_index = closest_display_in_direction(display_list, array_count(display_list), 2, DIR_EAST);\n    TEST_CHECK(best_index, -1);\n});\n"
  },
  {
    "path": "tests/src/tests.m",
    "content": "unsigned char __src_osax_payload[1];\nunsigned int __src_osax_payload_len;\nunsigned char __src_osax_loader[1];\nunsigned int __src_osax_loader_len;\n\n#include \"../../src/manifest.m\"\n\n#define TEST_SIG(name) bool test_##name(void)\ntypedef TEST_SIG(function);\n\n#define TEST_FUNC(name, code) static TEST_SIG(name) { char *test_name = #name; bool result = true; {code} return result; }\n#define TEST_CHECK(r, e) if ((r) != (e)) { printf(\"                   \\e[1;33m%s\\e[m\\e[1;31m#%d %s == %s\\e[m \\e[1;31m(%d == %d)\\e[m\\n\", test_name, __LINE__, #r, #e, r, e); result = false; }\n\n#include \"area.c\"\n\n#define TEST_ENTRY(name) { #name, test_##name },\n#define TEST_LIST                                              \\\n    TEST_ENTRY(display_area_is_in_direction)                   \\\n    TEST_ENTRY(closest_display_in_direction)\n\nstatic struct {\n    char *name;\n    test_function *func;\n} tests[] = {\n    TEST_LIST\n};\n\nint main(int argc, char **argv)\n{\n    int succeeded = 0;\n    int failed = 0;\n    int total = array_count(tests);\n    printf(\"\\e[1;34m -- Running %d tests\\e[m\\n\\n\", total);\n\n    uint64_t cpu_freq  = read_cpu_freq();\n    uint64_t begin_tsc = read_cpu_timer();\n\n    for (int i = 0; i < total; ++i) {\n        uint64_t tsc = read_cpu_timer();\n        bool result = tests[i].func();\n        double ms_elapsed = 1000.0 * (double)(read_cpu_timer() - tsc) / (double)cpu_freq;\n\n        printf(\"(%0.4fms) %s \\e[1;33m%s\\e[m\\n\", ms_elapsed, result ? \"\\e[1;32msuccess\\e[m\" : \" \\e[1;31mfailed\\e[m\", tests[i].name);\n        if (result) ++succeeded; else ++failed;\n    }\n\n    double ms_elapsed = 1000.0 * (double)(read_cpu_timer() - begin_tsc) / (double)cpu_freq;\n    printf(\"\\n\\e[1;34m -- Completed (%0.4fms)\\e[m\\n\", ms_elapsed);\n    printf(\"\\t%d \\e[1;32msucceeded\\e[m\\n\", succeeded);\n    printf(\"\\t%d \\e[1;31mfailed\\e[m\\n\", failed);\n    printf(\"\\t%d \\e[1;33mtotal\\e[m\\n\", total);\n\n    return total == succeeded ? EXIT_SUCCESS : EXIT_FAILURE;\n}\n"
  }
]