All Projects → tmandry → Swindler

tmandry / Swindler

Licence: mit
macOS window management library for Swift

Programming Languages

swift
15916 projects

Labels

Projects that are alternatives of or similar to Swindler

Macos headers
📚 A consistently maintained dump of most macOS Headers
Stars: ✭ 374 (-21.1%)
Mutual labels:  osx
Dellxps15 9550 Osx
Tutorial for a full working Mac OS (10.11 up to 11.0) enviroment on the Dell XPS 15 (9550)
Stars: ✭ 428 (-9.7%)
Mutual labels:  osx
Luascriptcore
一款简单易用的多平台Lua桥接器,目前支持在iOS、Mac OS X、Android以及Unity3D中使用,让原生环境与Lua无障碍沟通。
Stars: ✭ 463 (-2.32%)
Mutual labels:  osx
Headsetcontrol
Sidetone and Battery status for Logitech G930, G533, G633, G933 SteelSeries Arctis 7/PRO 2019 and Corsair VOID (Pro) in Linux and MacOSX
Stars: ✭ 392 (-17.3%)
Mutual labels:  osx
Vulkandemos
Some simple vulkan examples.
Stars: ✭ 413 (-12.87%)
Mutual labels:  osx
Spaces Renamer
💻 Ability to rename desktop spaces on macOS 10.10+
Stars: ✭ 435 (-8.23%)
Mutual labels:  osx
Infosec reference
An Information Security Reference That Doesn't Suck; https://rmusser.net/git/admin-2/Infosec_Reference for non-MS Git hosted version.
Stars: ✭ 4,162 (+778.06%)
Mutual labels:  osx
Picolove
PICO-8 Reimplementation in Love2D
Stars: ✭ 467 (-1.48%)
Mutual labels:  osx
Phaser Ce Npm Webpack Typescript Starter Project
Project to get you started with your Phaser-CE (using the npm module) game using Typescript and Webpack for building! No hassle asset management, Google Web Font loader, live server, development vs distribution build pipeline, Electron packaging for desktop builds, and more...
Stars: ✭ 414 (-12.66%)
Mutual labels:  osx
Github Matrix Screensaver
The GitHub Matrix Screensaver for Mac OSX
Stars: ✭ 453 (-4.43%)
Mutual labels:  osx
Lein template descjop
A Leiningen template(Clojure/ClojureScript Project) for Web based desktop application with Electron (atom-shell).
Stars: ✭ 394 (-16.88%)
Mutual labels:  osx
Solar
A Swift micro library for generating Sunrise and Sunset times.
Stars: ✭ 409 (-13.71%)
Mutual labels:  osx
Node Bluetooth Serial Port
Serial I/O over bluetooth for NodeJS
Stars: ✭ 444 (-6.33%)
Mutual labels:  osx
Osx Abi Macho File Format Reference
Mirror of OS X ABI Mach-O File Format Reference
Stars: ✭ 379 (-20.04%)
Mutual labels:  osx
Blueutil
CLI for bluetooth on OSX: power, discoverable state, list, inquire devices, connect, info, …
Stars: ✭ 464 (-2.11%)
Mutual labels:  osx
Cartool
Mac上解压Assets.car文件的小工具(支持右键解压)
Stars: ✭ 375 (-20.89%)
Mutual labels:  osx
Qt Nice Frameless Window
Qt Frameless Window for both Windows and OS X, support Aero Snap, drop shadow on Windows, and support Native Style such as round corner, drop shadow on OS X. Based on QMainWindow.
Stars: ✭ 430 (-9.28%)
Mutual labels:  osx
Sogou Input Skin
搜狗拼音输入法的几款极简风格皮肤
Stars: ✭ 462 (-2.53%)
Mutual labels:  osx
Sloth
Mac app that shows all open files, directories, sockets, pipes and devices in use by all running processes. Nice GUI for lsof.
Stars: ✭ 4,549 (+859.7%)
Mutual labels:  osx
Ergo
The management of multiple apps running over different ports made easy
Stars: ✭ 452 (-4.64%)
Mutual labels:  osx

Swindler

A Swift window management library for macOS

Build Status Join the chat at https://gitter.im/tmandry/Swindler

In the past few years, many developers formerly on Linux and Windows have migrated to Mac for their excellent hardware and UNIX-based OS that "just works".

But along the way we gave up something dear to us: control over our desktop environment.

The goal of Swindler is to help us take back that control, and give us the best of both worlds.

What Swindler Does

Writing window managers for macOS is hard. There are a lot of systemic challenges, including limited and poorly-documented APIs. All window managers on macOS must use the C-based accessibility APIs, which are difficult to use and are surprisingly buggy themselves.

As a result, the selection of window managers is pretty limited, and many of the ones out there have annoying bugs, like freezes, race conditions, "phantom windows", and not "seeing" windows that are actually there. The more sophisticated the window manager is, the more it relies on these APIs and the more these bugs start to show up.

Swindler's job is to make it easy to write powerful window managers using a well-documented Swift API and abstraction layer. It addresses the problems of the accessibility API with these features:

Type safety

Swindler's API is fully documented and type-safe thanks to Swift. It's much easier and safer to use than the C-based accessibility APIs. (See the example below.)

In-memory model

Window managers on macOS rely on IPC: you ask an application for a window's position, wait for it to respond, request that it be moved or focused, then wait for the application to comply (or not). Most of the time this works okay, but it works at the mercy of the remote application's event loop, which can lead to long, multi-second delays.

Swindler maintains a model of all applications and window states, so your code knows everything about the windows on the screen. Reads are instantaneous, because all state is cached within your application's process and stays up to date. Swindler is extensively tested to ensure it stays consistent with the system in any situation.

Asynchronous writes and refreshes

If you need to resize a lot of windows simultaneously, for example, you can do so without fear of one unresponsive application holding everything else up. Write requests are dispatched asynchronously and concurrently, and Swindler's promise-based API makes it easy to keep up with the state of operations.

Friendly events

More sophisticated window managers have to observe events on windows, but the observer API is not well documented and often leaves out events you might expect, or delivers them in the wrong order. For example, the following situation is common when a new window pops up:

1. MainWindowChanged on com.google.chrome to <window1>
2. WindowCreated on com.google.chrome: <window1>

See the problem? With Swindler, all events are emitted in the expected order, and missing ones are filled in. Swindler's in-memory state will always be consistent with itself and with the events you receive, avoiding many bugs that are difficult to diagnose.

As a bonus, events caused by your code are marked as such, so you don't respond to them as user actions. This feature alone makes a whole new level of sophistication possible.

Example

The following code assigns all windows on the screen to a grid. Note the simplicity and power of the promise-based API. Requests are dispatched concurrently and in the background, not serially.

Swindler.initialize().then { state -> Void in
    let screen = state.screens.first!

    let allPlacedOnGrid = screen.knownWindows.enumerate().map { index, window in
        let rect = gridRect(screen, index)
        return window.frame.set(rect)
    }

    when(allPlacedOnGrid) { _ in
        print("all done!")
    }
}.catch { error in
    // ...
}

func gridRect(screen: Swindler.Screen, index: Int) -> CGRect {
    let gridSteps = 3
    let position  = CGSize(width: screen.width / gridSteps,
                           height: screen.height / gridSteps)
    let size      = CGPoint(x: gridSize.width * (index % gridSteps),
                            y: gridSize.height * (index / gridSteps))
    return CGRect(origin: position, size: size)
}

Watching for events is simple. Here's how you would implement snap-to-grid:

swindlerState.on { (event: WindowMovedEvent) in
    guard event.external == true else {
        // Ignore events that were caused by us.
        return
    }
    let snapped = closestGridPosition(event.window.frame.value)
    event.window.frame.value = snapped
}

Requesting permission

Your application must request access to the trusted AX API. To do this, simply use this code in your AppDelegate:

func applicationDidFinishLaunching(_ aNotification: Notification) {
    guard AXSwift.checkIsProcessTrusted(prompt: true) else {
        print("Not trusted as an AX process; please authorize and re-launch")
        NSApp.terminate(self)
        return
    }

    // your code here
}

A note on error messages

Many helper or otherwise "special" app components don't respond to the AX requests or respond with an error. As a result, it's expected to see a number of messages like this:

<Debug>: Window <AXUnknown "<AXUIElement 0x610000054eb0> {pid=464}" (pid=464)> has subrole AXUnknown, unwatching
<Debug>: Application invalidated: com.apple.dock
<Debug>: Couldn't initialize window for element <AXUnknown "<AXUIElement 0x610000054eb0> {pid=464}" (pid=464)> () of com.google.Chrome: windowIgnored(<AXUnknown "<AXUIElement 0x610000054eb0> {pid=464}" (pid=464)>)
<Notice>: Could not watch application com.apple.dock (pid=308): invalidObject(AXError.NotificationUnsupported)
<Debug>: Couldn't initialize window for element <AXScrollArea "<AXUIElement 0x61800004ed90> {pid=312}" (pid=312)> (desktop) of com.apple.finder: AXError.NotificationUnsupported

Currently these are logged because it's hard to determine if an app "should" fail (especially on timeouts). As long as things appear to be working, you can ignore them.

Project Status

Swindler is in development and is in alpha. Here is the state of its major features:

  • Asynchronous property system: 100% complete
  • Event system: 100% complete
  • Window API: 90% complete
  • Application API: 90% complete
  • Screen API: 90% complete
  • Spaces API: 0% complete

You can see the entire planned API here.

API Documentation (latest release)

API Documentation (master)

Development

Swindler uses Swift Package Manager.

Building the project

Clone the project, then in your shell run:

$ cd Swindler
$ git submodule init
$ git submodule update

At this point you should be able to build Swindler in Xcode and start on your way!

Using the command line

You can run the example project from the command line.

swift run

Contact

You can chat with us on Gitter.

Follow me on Twitter: @tmandry

Related Projects

Swindler is built on AXSwift.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].