Is there anyway by which one can have grayscale system wide except some selected (by user) apps, on macOS?
2 Answers
Yes, this is possible, though my solution is a bit hacky. Note that this method uses some undocumented Objective C APIs, and doesn't go through ordinary accessibility settings, so be careful.
First you need to have developer tools installed so that you can compile Objective C code. Then compile two commands enable-grayscale
and disable-grayscale
from source (based on this StackOverflow answer which provides some additional ways of doing this).
$ cat enable-grayscale.c
// https://stackoverflow.com/questions/14163788/how-does-on-screen-color-inversion-work-in-os-x
#include <stdio.h>
#include <ApplicationServices/ApplicationServices.h>
CG_EXTERN bool CGDisplayUsesForceToGray(void);
CG_EXTERN void CGDisplayForceToGray(bool forceToGray);
int
main(int argc, char** argv)
{
bool isGrayscale = CGDisplayUsesForceToGray();
if (!isGrayscale) {
CGDisplayForceToGray(TRUE);
}
return 0;
}
$ cat disable-grayscale.c
// https://stackoverflow.com/questions/14163788/how-does-on-screen-color-inversion-work-in-os-x
#include <stdio.h>
#include <ApplicationServices/ApplicationServices.h>
CG_EXTERN bool CGDisplayUsesForceToGray(void);
CG_EXTERN void CGDisplayForceToGray(bool forceToGray);
int
main(int argc, char** argv)
{
bool isGrayscale = CGDisplayUsesForceToGray();
if (isGrayscale) {
CGDisplayForceToGray(0);
}
return 0;
}
Then compile them into commands:
clang -g -O2 -std=c11 -Wall -framework ApplicationServices enable-grayscale.c -o enable-grayscale
clang -g -O2 -std=c11 -Wall -framework ApplicationServices disable-grayscale.c -o disable-grayscale
Put the resulting files somewhere you want to run them, e.g. your home directory.
Now install Hammerspoon. You'll need to give it accessibility access in System Preferences. Within Hammerspoon, select "Open Config", and modify the Lua code to do what you want. My configuration is below, based on this example from their docs:
function applicationWatcher(appName, eventType, appObject)
if (eventType == hs.application.watcher.activated) then
if (appName == "Firefox") then
os.execute('/path/to/scripts/enable-grayscale')
end
end
if (eventType == hs.application.watcher.deactivated) then
if (appName == "Firefox") then
os.execute('/path/to/scripts/disable-grayscale')
end
end
end
appWatcher = hs.application.watcher.new(applicationWatcher)
appWatcher:start()
That's the configuration I chose (turn on grayscale for Firefox, but leave it off for all other applications). Whenever Firefox is focused, the whole screen becomes grayscale. When other applications are focused, it's color. It sounds like you'd want the opposite: grayscale turned on in System Preferences, with it being disabled when you focus an app from the list you're interested in. Once you've configured it as you want, click "Reload Config" to activate the changes.
-
nice, does this work if the application which triggers this change is maximized while switching to another application? will the switching app trigger the screen to grayscale in that case?. I am trying to get this to work on iTerm, I want terminal app to have color and everything else to be gray, so far I got to the point where c code works, but Hammerspoon does not respond to appName "iTerm". Commented Jul 15, 2019 at 14:12
-
You might be able to add a logging statement logging the
appName
, then you can check what theappName
it's seeing in the hammerspoon debug console (like maybe it's "iTerm 2" or something). To be honest, I stopped using this a while ago, so I can't help further. Commented Jul 16, 2019 at 18:18