[Feature Request] A way to make FluffyDisplay start on boot/startup and automatically make a virtual display without user interaction
I've recently starting to mess around with an OSX VM with GPU passthrough but happens that the GPU doesn't have any sort of display outputs, so I'm currently using the VM's display whose performance is horrible. I was wondering if it would somehow be possible to automatically run FluffyDisplay and pick a Virtual Display without the user's input on boot/startup.
It's not ideal, but if you need to, you can control FluffyDisplay by selecting its menu items through the Accessibility API. I tried to write an example of doing this with AppleScript's GUI scripting features, but I couldn't figure out any way to keep the script from hanging for several seconds after opening the menu. However, if you're open to installing Hammerspoon, something like this should work:
Example Hammerspoon code to turn on FluffyDisplay
-- don't create a display if there's already one (e.g. when reloading Hammerspoon config)
if not hs.screen 'FluffyDisplay' then
local fdResolution = {w=1920, h=1200} -- <-- fill this with the resolution of the virtual display to create
local fdBundleID = 'fi.iki.tml.FluffyDisplay'
local fdApp = hs.application.get(fdBundleID) or hs.application.open(fdBundleID)
local fdAxApp = hs.axuielement.applicationElement(fdApp)
-- wait for menu to appear in menubar
local fdExtrasMenuBar
for i = 1, 100 do
fdExtrasMenuBar = fdAxApp.AXExtrasMenuBar
if fdExtrasMenuBar and fdExtrasMenuBar[1] then break end
hs.timer.usleep(10000)
end
if not fdExtrasMenuBar then error "Couldn't get FluffyDisplay's AXExtrasMenuBar" end
local fdMenuBarItem = fdExtrasMenuBar[1]
-- Normally, fdMenuBarItem:doAXPress() below seems to hang until the menu closes again, or the call times out.
-- Make that timeout happen immediately, so we can start messing with the menu inside.
-- This is the part I couldn't figure out how to do from AppleScript.
fdMenuBarItem:setTimeout(0.1)
-- Click the menu icon, because the menu doesn't exist until it's opened.
fdMenuBarItem:doAXPress()
-- Click on 'New' to open the submenu. The submenu already exists by this point, but if I don't
-- open it, selecting the item inside does nothing for some reason.
local fdMenu = fdMenuBarItem[1]
local fdNewMenuItem = fdMenu[1]
fdNewMenuItem:doAXPress()
-- Find the menu item for the desired resolution, and click it.
local fdNewMenu = fdNewMenuItem[1]
local fdNewCommandMenuItemPattern = ('^%d×%d %%('):format(fdResolution.w, fdResolution.h)
-- ^- e.g. '^1920×1200 %(' ^- note: Unicode MULTIPLICATION SIGN, not letter 'x'
local fdNewCommandMenuItem = hs.fnutils.find(fdNewMenu.AXChildren, function(item)
return item.AXTitle:match(fdNewCommandMenuItemPattern)
end)
fdNewCommandMenuItem:doAXPress()
end
Set Hammerspoon to run at login, grant it Accessibility access, and add the code above to ~/.hammerspoon/init.lua. (Or put it in e.g. ~/.hammerspoon/startFluffyDisplay.lua, and add require 'startFluffyDisplay' to ~/.hammerspoon/init.lua.) It should automatically create a display as soon as you're logged in.