A Seamless X11 Experience on OS X

By Calum MacRae

May 4, 2015

Introduction

When Youri and I first set out hacking on OS X, before the real inception of Save OS X, we spent quite some time chasing an X11 set up that felt as if we were on any other *nix platform that we had become accustomed to. We never did quite get it exactly the same. I even tried, at one point, taking apart and hacking about with some of the sources from the PureDarwin project. At the time, I felt I was very close to getting X11 to run natively… though, in hindsight, I think that feeling was more down to my naivety.

That said, we did reach a set up that we both became quite happy with and used extensively - that's what I'll be talking about in this post.

Why would I want to run X11 on OS X?

It's funny, it seems quite a sought after "achievement" to run X11 on OS X in a manner close to the BSDs/Linux/other *nixes. I quote achievement here, because, well, I don't think it really warrants the use of that word - but it seems that's what the community deems it as when people reach it.

Nowadays, I don't touch X11 on OS X, but I can understand the appeal. If you become proficient in a window manager of choice, or other tools that are only available in an X11 environment, it's perfectly rational to want to continue doing so on OS X. When I was using X11 on OS X heavily, I did everything in it (with the exception of web browsing). It fit quite nicely, I'd have one workspace that housed an X11 environment, and another which simply had my browser.

Other than wanting to reside within a familiar environment, I think it's safe to say there's a particular motive from some individuals to run X11 on OS X because it just seems cool… I'll leave it at "cool" - it's fairly ambiguous, but it's good enough. Wanting to do something because it's "cool", often when relating to hacking something (in a curious sense, not malicious), is a pretty fair reason and can often help spur the individual on to learn more and discover more useful/practical projects.

Why I'm writing about this

With some changes I made earlier today to the SaveOS X bootstrapper, removing the clunky collection of scripts & plists, I deprecated support for our X11 hacks. Save OS X has drifted from our initial goals and now focuses primarily on an easy to set up implementation of classic binary package management on OS X using pkgsrc.

It actually started off as a little script that would go through and strip out a bunch of "crap" that Apple had included in OS X, with the intention of saving disk space and other resources.

But, I digress; I figured I'd preserve the "achievement" in this write-up, for anyone else out there who wants to implement the same.

Some eye candy

https://i.imgur.com/JJJv957.png

Here's how my MacBook Air looked in January 2014. You can see bspwm running on OS X here. This was the culmination of a few little tricks - this isn't even running in 'Full-screen' mode.

The software/hacks

XQuartz

Up until Mountain Lion, Apple used to include a native X11.app in OS X, which - as you may have guessed - allowed users to run their X11 applications. With its removal, users turned to XQuartz to fill the gap.

I don't feel I need to touch on this much. You can simply go to the official XQuartz site, download, and install as you would most other software on OS X.

Installation of X11 software (wms, utils, libs, etc)

Let's say you're on a BSD or Linux distro: you want to install a new window manager or desktop environment. You'd usually just do that through the package manager, right? Well, same approach with OS X really, unless you're more comfortable building from source.

So, of course, I'm going to recommend Save OS X, but you could use any other package/ports managers available to get your actual X11 applications.

When using Save OS X this would be as simple as something like sudo pkgin -y in twm, then setting up your ~/.xinitrc as you would on any other system: echo "exec twm" > ~/.xinitrc, for example.

Property List trickery

This next one depends how you'd like to interact with X11 and the extent of functionality that you desire.

When using XQuartz, you can opt to use a setting called 'Full-screen mode', found in XQuartz's preferences, under the 'Output' tab. This will, as one might be able to surmise, make XQuartz full screen. That is to say, the X11 server will occupy your entire display. Use of this option is as close to a 'standard' X11 set up as you can get. It allows you to use root-menus, Aqua's keybindings don't interfere, and you don't see any Aqua interface.

Whilst the above is nice, you may want to occupy your desktop with a mix of X11 & Aqua windows simultaneously. In doing so, you may be such a perfectionist that you don't want to see the dock or menubar - that was the case for me at least. You can do some trickery with Aqua applications' Info.plist to make certain UI elements behave a particular way.

To hide the dock and menubar when using an Aqua application, you can add the following properties to its Info.plist (usually located at /Applications/AppName.app/Contents/Info.plist):

<key>LSUIPresentationMode</key> 
<integer>4</integer>

This won't always work and its placement can vary. Simply replacing XQuart'z Info.plist with this one should achieve the desired behavior.

Custom launchd service

If you're heavily reliant on X11, and plan to use it a lot, you can have it auto-start using a launchd service.

Place something like the following in ~/Library/LaunchAgents/org.saveosx.startx.plist

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>EnvironmentVariables</key>
  <dict>
    <key>LANG</key>
    <string>en_US.UTF-8</string>
    <key>LC_ALL</key>
    <string>en_US.UTF-8</string>
    <key>PATH</key>
    <string>/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/opt/X11/bin:/usr/pkg/bin:/usr/pkg/sbin</string>
  </dict>
  <key>Label</key>
  <string>org.saveosx.startx</string>
  <key>Program</key>
  <string>/opt/X11/bin/startx</string>
  <key>RunAtLoad</key>
  <true/>
  <key>StandardErrorPath</key>
  <string>/var/log/saveosx.log</string>
  <key>StandardOutPath</key>
  <string>/var/log/saveosx.log</string>
</dict>
</plist>

It should be quite clear from the above what's happening here. It's just like any other service management manifest, but uses XML to define keys and their values - just like SMF.

Once the above is in place, you can import the service and have it set to launch upon login by issuing the following command launchctl load -w ~/Library/LaunchAgents/org.saveosx.startx.plist

Some small caveats/tips

Well, of course it's not perfect…

XQuartz focus

One problem with going the non-Full-screen path is that getting XQuartz to focus upon first launch can be quite a pain. I tackled this by simply having an instance of urxvt launch along with my window manager. If you use a panel/bar, this isn't as much of an issue, since your WM/DE has already launched an X11 tool which you can simply click on to gain X11 focus. However, if you're using a lightweight window manager, without any panel/bar - as there is the absence of a root-window (selecting the desktop will just focus Finder) - it can be quite awkward. Simply having a terminal, or something else in X11, launch automatically circumvents this issue.

Of course, if you opt to use 'Full-screen', you needn't worry about this.

Opening Aqua applications from XQuartz

Say you want to launch an Aqua application from dmenu, or you need to send a URL to Safari from urxvt. This is where the open(1) utility comes in handy. If you wanted to be able to open Safari using dmenu you could simply add a little shell script somewhere in your PATH containing the following:

#! /bin/bash
open -a Safari

Or if you're using the urxvt-perls perl extensions for urxvt and you need to tell it what to launch URLs with:

Urxvt-url-select.launcher:  open -a safari

Which reminds me, the following can be used with urxvt-perls for clipboard management:

URxvt*perl-lib:             /usr/pkg/lib/urxvt/perl/
URxvt*perl-ext-common:      default,clipboard
URxvt*keysym.M-c:           perl📋copy
URxvt*keysym.M-v:           perl📋paste
URxvt*clipboard.copycmd:    pbcopy
URxvt*clipboard.pastecmd:   pbpaste

This is all dead simple, but makes it a much more enjoyable experience. I didn't delve too far into integrating the two "sides", but I'm sure you could do some pretty nifty stuff with Automater/AppleScript.

Too lazy? Use the legacy script!

If you've got Git installed, you could simply clone the bootstrap repo and checkout a point in history that still implemented all the above functionality for you:

$ git clone git@github.com:cmacrae/saveosx
$ cd saveosx
$ git checkout 1c79fa66d99ae5a841b763ab5a29841b7458dba5
$ cd scripts
$ ./bootstrap

Posted on:
May 4, 2015
Length:
7 minute read, 1413 words
Tags:
macOS X11 package-management hacking
See Also:
A Quick Demo of Save OS X on a Fresh Yosemite Install
A Streamlined Bootstrapper for Save OS X
Dropping status bars for tmux