Normally I use a separate account to present talks and demos but I’ve recently taken up a more regular instruction gig and in doing so, it’s too inconvenient to move from my main account. My main account is where all my development tools and code are a few clicks and keystrokes away. The demo one is very safe for public presentation but also very distant from my workflow.
To address this, I’ve built a demo-setup utility in Swift. I thought I’d share some of the features and approaches. A lot of these were non-trivial to track down in terms of time and I thought having them in one place could be useful to some of you reading my blog.
If you have others to share, please let me know.
Desktop Wallpaper
I use Backdrop from Apps from Outer Space to cover my normal desktop with a plain and boring background. Set up preferences in the app and then use open /Applications/Backdrop.app
/ killall Backdrop
to toggle. It covers your wall paper without having to set it back to your favorite picture each time you enter and leave demo mode.
Do Not Disturb
Automate DND with AppleScript. I grabbed code off the web, letting me enable and disable do not disturb mode. (Make sure to enable Script Editor in Accessibility so they’ll run: Settings > Security & Privacy > Accessibility > Allow the apps below to control your computer.)
I didn’t make these pretty or write the osascript stuff into my code. They’re just two scripts in ~/bin
right now. At some point, time allowing, I’ll unify these into a single script or app but as they work for now, shrug:
Desktop Icons
I keep a lot of work on my desktop that I’d prefer not to share. It’s easy to hide and show my desktop icons with a simple defaults command:
defaults write com.apple.finder CreateDesktop false; killall Finder"
Substitute true
for false
to re-enable.
Keyboard Maestro Macros
I not only quit email (killall Mail
) but I also disable my Keyboard Maestro shortcut so I don’t accidentally re-launch it from muscle memory.
osascript -e 'tell application "Keyboard Maestro" to setMacroEnable "8E84EF4C-13F8-41AB-85EC-44AF70A52909" without enable'
Grab the unique identifiers for troublesome shortcuts from the files stored in ~/Library/Application\ Support/Keyboard\ Maestro
. Use with
and without enable
to automate the macros off and then back on.
Safari History
No one wants their personal browsing history to pop up during demos in Safari as part of auto-completion suggestions. (Imagine, if you will, typing “s”, and having all your sloth sites listed as possible completions. Or, heaven forfend, things worth than sloth sites.)
If you use iCloud bookmarks, you can disable iCloud, remove your history and bookmarks files from ~/Library/Safari
, and relaunch Safari (open /Applications/Safari.app
). To re-enable, restart iCloud and wait for the data to sync back to your Mac.
I automated file deletion (actually, moving the files to another location) once iCloud is off and after quitting Safari (killall Safari
). However, I didn’t automate enabling/disabling iCloud Safari bookmark sync from the command line. Instead, I used open 'x-apple.systempreferences:com.apple.preference.icloud'
to get me to the right place for a single check mark toggle.
I hide my favorites bar:
defaults write com.apple.Safari ShowFavoritesBar-v2 false
Use true
instead of false
to restore.
You may want to limit Autofill and Search options (Safari > Preferences > Autofill and Search). I didn’t as they don’t really impact my presentations. I’m okay with Safari providing Search Engine-supplied suggestions, especially when searching for tech topics, as for me these are features not bugs.
System Calls
Here’s my ancient code to perform system calls to execute all the setup and teardown without using system()
. Although lightly updated, I haven’t spent a lot of time improving something that works. If you have better solutions, please let me know:
extension NSString { /// Trim output var trimmed: String { return self.trimmingCharacters(in: .whitespacesAndNewlines) } } /// Execute a command as a shell script @discardableResult func perform( _ command: String) -> [String] { let task = Process() (task.launchPath, task.arguments) = ("/bin/sh", ["-c", command]) let pipe = Pipe() task.standardOutput = pipe task.launch() let data = pipe.fileHandleForReading.readDataToEndOfFile() task.waitUntilExit() if let output = NSString(data: data, encoding: String.Encoding.utf8.rawValue)?.trimmed { return output.components(separatedBy: "\n") } // Something went wrong print(task.terminationStatus); return [] }
Comments are closed.