FluffyDisplay icon indicating copy to clipboard operation
FluffyDisplay copied to clipboard

[Feature Request] A way to make FluffyDisplay start on boot/startup and automatically make a virtual display without user interaction

Open gui710 opened this issue 4 years ago • 1 comments

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.

gui710 avatar Jan 11 '22 03:01 gui710

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.

Rhys-T avatar Mar 22 '23 04:03 Rhys-T