/ Scripting

Resizing Mac application windows with Python

One of my recent obsessions has been using Python for local scripting. I've spent a lot of time over the last few years writing shell scripts, bash and zsh scripts to be specific. Bash scripts do the trick and, for simple tasks, can be the least fussy approach. But they become problematic for more involved workloads.

Here are a few reasons why:

  1. Bash scripts aren't very portable: there are platform and shell dependencies to consider
  2. The package management ecosystem seems less robust than what you may have grown to expect from npm, pip, gems, and so on
  3. The syntax is a beast, and if you are only writing shell scripts every so often you will forget how to even read some of the code you wrote six months ago

None of these reasons alone would be a deal-breaker, but in practice I've found that they exacerbate one another in more involved scripts.

So, I decided to try Python to automate some local tasks a while back and it blew my mind how quickly you can get things done.

There's not really meant to be a high-level take-away from this post, but if there is one, it's that bash scripting is a great tool for local automation, but it isn't the only tool. I'll probably use bash scripts for quick 5-liners, but I'd now rather use Python for more complex workflows that I intend to maintain over time.

The context for scripting a window resize

One bash script I've been using and maintaining for a couple of years now, called blog.sh, puts my computer in "blog mode": ask for new filename, make a new file, launch my text editor, launch my Markdown previewer, launch the website I will be publishing to, etc.

In blog.sh, after the text editor and Markdown previewer are launched, I call a Keyboard Maestro script that I set up to split the screen 50/50 between my writing tools: text editor on the left, and Markdown previewer on the right.

I use a Keyboard Maestro script because, at least at the time, it just seemed easier than figuring out a way to drive app windows from a bash script. But needing a whole third party app to be installed is obviously a huge dependency.

Perhaps there are good ways to write a bash script that can resize app windows on a Mac (or maybe you're screaming "Applescript" at the screen at this point), but now that I'm in full Python obsession mode, I wanted to give it a shot in Python.

A simple example

Again, the goal in this case is to take two application windows and resize them so they split the screen 50/50.

To make that happen, you would need:

  1. Information about the screen being used.
  2. A way to programmatically resize a particular window for a particular application.

There are surely multiple Python modules out there to achieve these goals. I went with the AppKit and ScriptingBridge Python modules (both available as part of PyObjC).

Below is a simple example of a function called resize_windows(), which:

  1. Gets the screen dimensions
  2. Gets the Atom application (my text editor) and the first Atom window available
  3. Sets the bounds of the Atom window based on the screen dimensions from step #1
  4. Repeats steps #2 and #3 for the Marked 2 application (my Markdown previewer)
from AppKit import NSScreen
from ScriptingBridge import SBApplication

def resize_windows():
    # (1)
    screen_height = NSScreen.mainScreen().frame().size.height
    screen_width = NSScreen.mainScreen().frame().size.width

    # (2)
    atom_app = SBApplication.applicationWithBundleIdentifier_("com.github.atom")
    atom_window = atom_app.windows()[0]

    # (3)
    atom_window.setBounds_([[0, 0], [screen_width/2, screen_height]])

    # (4)
    marked_app = SBApplication.applicationWithBundleIdentifier_("com.brettterpstra.marked2")
    marked_window = marked_app.windows()[0]
    marked_window.setBounds_([[screen_width/2, 0], [screen_width/2, screen_height]])

    return True

This function could surely be written more eloquently. In particular, those hard coded bundle IDs are a nagging concern, and there's an opportunity for a for ... in loop here. Also, the function is assuming that Atom and Marked 2 will already be open.

But the point here is to show how simple it can be to resize Mac application windows using Python. Hopefully this is helpful if you're looking to accomplish something similar.