⬆️ ⬇️

Minimize apps to dock for lazy using AppleScript

How often do you use the options of some programs (iTerm 2, Total Finder, Adium), which allow you to show the application window by pressing the global hotkey and hide this application when you lose focus? Personally, I - constantly. And what if a certain program does not have such functionality and constantly looms before your eyes? The same Skype, for example. Under the cut option to bring your workspace in order.





Open and hide the application by hotkey



Let's start with the simplest. Task: by clicking on the global hotkey from any program, transfer the focus to Skype and hide it with the same action. There is a whole fleet of programs that allow you to do this very simply. However, we are not looking for simple ways and are not ready to install additional programs for these purposes. In this case, Automator comes to the rescue with the ability to create a service and hang up a hotkey to call it from any application.



Launch Automator, select the document type Service . In the list the service gets we select no input data in the adjacent list is left in any program . Add the action Launch AppleScript to our service and insert the following code:

')

set appName to "Skype" set startIt to false tell application "System Events" if not (exists process appName) then set startIt to true else if frontmost of process appName then set visible of process appName to false else set frontmost of process appName to true end if end tell if startIt then tell application appName to activate end if 


What it looks like




This code is honestly borrowed from here .

Everything is simple here: the script checks whether the application is running, if not, then launches it, otherwise it minimizes it (if the application window is in focus), or gives it focus (if another application is currently active).



We save our service, go to System Preferences> Keyboard> Shortcut in the list on the left, select Services , in the list on the right we find the service we just created and assign a hotkey to it. The goal is achieved, but without one, but there will not be.



The problem is that the service call does not bind to the global hotkey. Services are called from each application "locally". For example, being in Safari at the moment, in the program menu we find the Services submenu (i.e. Safari> Services ), where our service will be available for us to run. Accordingly, we can manually launch it from any application, and the hotkey we assign has a lower priority than the settings of a particular application. From here we have two choices: either assign a keyboard shortcut to call our service, which is not used anywhere else in the system, in any program, or resort to using those third-party programs that will give the opportunity to hang a global hotkey to call the service. Personally, I went through the third way and used the possibilities of Alfred, which allows not to resort to the above described actions and gives the opportunity to show and hide the application by clicking on a given global hotkey.



What is there with autochipping?



So, we learned how to show and hide the application by clicking on the global hotkey, but pressing the button before switching to another application is stressful. Solve this problem.



Open AppleScript Editor and paste the following code:



 property appName : "Skype" on idle tell application "System Events" set focusedApp to (name of the first process whose frontmost is true) if (focusedApp is not appName) and (exists process appName) and (visible of process appName) then set visible of process appName to false end if end tell return 0.5 end idle 


Click File> Save , select the file format - Program , put a check mark next to Leave open after starting the handler , save the program. After that, the Package Contents button is available in the editor, clicking on it will crawl to the right of the window in which we are looking for a button with a gear, in the menu that appears, select Show in Finder :



What it looks like








In the opened folder there will be an Info.plist file, open it in a text editor, after the fourth line insert:



 <key>LSBackgroundOnly</key> <string>1</string> 




This is what should happen.
 <?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>LSBackgroundOnly</key> <string>1</string> <key>CFBundleAllowMixedLocalizations</key> <true/> <key>CFBundleDevelopmentRegion</key> <string>English</string> <key>CFBundleExecutable</key> <string>applet</string> <key>CFBundleIconFile</key> <string>applet</string> <key>CFBundleIdentifier</key> <string>com.apple.ScriptEditor.id.HideSkype</string> <key>CFBundleInfoDictionaryVersion</key> <string>6.0</string> <key>CFBundleName</key> <string>HideSkype</string> <key>CFBundlePackageType</key> <string>APPL</string> <key>CFBundleShortVersionString</key> <string>1.0</string> <key>CFBundleSignature</key> <string>aplt</string> <key>LSMinimumSystemVersionByArchitecture</key> <dict> <key>x86_64</key> <string>10.6</string> </dict> <key>LSRequiresCarbon</key> <true/> <key>WindowState</key> <dict> <key>dividerCollapsed</key> <false/> <key>eventLogLevel</key> <integer>2</integer> <key>name</key> <string>ScriptWindowState</string> <key>positionOfDivider</key> <real>333</real> <key>savedFrame</key> <string>55 281 602 597 0 0 1440 878 </string> <key>selectedTabView</key> <string>event log</string> </dict> </dict> </plist> 




Save the file.



That's all, run our application, add to autoload and enjoy the result. From now on, Skype eyes do not callous.

If you are interested in the implementation features, then read on.



Debriefing



AppleScript turned out to be a discovery for me, so just a couple of days ago I didn’t know about the existence of this “miracle” (it looks like a language for housewives). But it provides enough opportunities to automate processes in your work environment. For the above described actions, installation of developer tools was not needed, and given the result, we can talk about the presence of a powerful tool that is always at hand.



I will try to decompose the solution to the problem of the application auto-hide.



First, let's learn how to determine whether a particular application is in focus or not:



 set appName to "Skype" --,    tell application "System Events" --    application,      System Events set focusedApp to (name of the first process whose frontmost is true) --  focusedApp  ,       if focusedApp is appName then --  ,     appName    end if end tell 


It is very unusual to read such a code, but it’s nice to have a self-documented code.



If the application’s focus is lost, then hide it:



 set appName to "Skype" tell application "System Events" set focusedApp to (name of the first process whose frontmost is true) if (focusedApp is not appName) and (exists process appName) and (visible of process appName) then set visible of process appName to false end if end tell 


That's the solution to the problem. It remains to wrap it in an infinite loop.



 set appName to "Skype" repeat while true tell application "System Events" set focusedApp to (name of the first process whose frontmost is true) if (focusedApp is not appName) and (exists process appName) and (visible of process appName) then set visible of process appName to false end if end tell delay 0.5 --        end repeat 




And this is a working decision. However, if we leave it in this form, the script simply hangs, although it will work correctly. The solution is to put the cycle into a separate thread. But alas, there are no threads in AppleScript. Go to the documentation and discover the idle handler. Handlers in AppleScript are called, in fact, familiar to us procedures. The idle handler’s peculiarity is that it is called by the system every 30 seconds, if it does not return any value, if it returns, say, 5, it will be called every 5 seconds.



 on idle set appName to "Skype" tell application "System Events" set focusedApp to (name of the first process whose frontmost is true) if (focusedApp is not appName) and (exists process appName) and (visible of process appName) then set visible of process appName to false end if end tell return 0.5 end idle 




You can also stop using idle and work with run and quit handlers:



 property appName: "Skype" property running: true on run repeat while running tell application "System Events" set focusedApp to (name of the first process whose frontmost is true) if (focusedApp is not appName) and (exists process appName) and (visible of process appName) then set visible of process appName to false end if end tell delay 1 end repeat end run on quit set running to false end quit 




I want one handler for several programs



No problem:



 property appsToHide: {"Skype", "Adium", "Sublime Text 2"} on idle tell application "System Events" set focusedApp to name of the first process whose frontmost is true repeat with appToHide in appsToHide if (focusedApp is not in appToHide) and (exists process appToHide) and (visible of process appToHide) then set visible of process appToHide to false end if end repeat end tell return 0.5 end idle 




The following point is worth noting: focusedApp is not in appToHide . It checks whether the value of focusedApp in appToHide , although it would be correct to simply compare strings (operators =, is equal, equals, [is] equal to, is not

isn't, isn't equal [to], is not equal [to], doesn't equal, does not equal
=, is equal, equals, [is] equal to, is not

isn't, isn't equal [to], is not equal [to], doesn't equal, does not equal
=, is equal, equals, [is] equal to, is not

isn't, isn't equal [to], is not equal [to], doesn't equal, does not equal
. But in this example, the strings (data type text ) did not want to be compared correctly.



On this I finish my story. Many details about AppleScript can be found in the official documentation . If anyone doubts the relevance of this tool, then look at the release notes - the language expands with each release of OS X. Also, search engines are full of ready-made howto to solve problems using AppleScript.



Thanks for attention.

Source: https://habr.com/ru/post/202864/



All Articles