Why doesn't this applescript seem to work as expected? - osx-lion

I'm writing a service using automator. It receives no input in any application.
All it does is run this simple script:
on run {input, parameters}
--FIRST BLOCK
tell application "System Events"
set app_name to name of the first process whose frontmost is true
end tell
--SECOND BLOCK
if (do shell script "defaults read com.apple.finder AppleShowAllFiles") is equal to "0" then
do shell script "defaults write com.apple.finder AppleShowAllFiles 1"
else
do shell script "defaults write com.apple.finder AppleShowAllFiles 0"
end if
--THIRD BLOCK
do shell script "killall Finder"
delay 0.5
--FOURTH BLOCK
if (app_name is equal to "Finder") then
tell application "Finder"
activate
end tell
end if
end run
I'll walk you trough it step by step:
first block: get the name of the current frontmost app and store it in a variable app_name.
second block: toggle the hidden files variable on or of, depending on its value.
third block: run killall Finder to relaunch Finder, taking the toggle from the second block into effect. Pause 0.5 sec, somehow this is necessary (don't know why, but without this the next instruction will be ignored).
fourth block: Check what the variable app_name was. If it equals Finder this means finder was active when the script was initiated, thus activate Finder once more (killall Finder leaves it in the background).
Problem: Everything works as expected but for one thing: when using this service in the Finder, Finder doesn't get activated again.
One might argue that there must be something wrong with the code in the fourth block, yet I've experimented a bit to show everything works as expected:
When I replace equal by not equal and run the script from any app that is not the Finder, Finder DOES get activated as should be.
So it seems that there only is a problem when the script is fired when Finder is in front.
(This is what the service should do: from within any app, toggle the visibility of the hidden files in Finder. When Finder was in front, it should be in front after execution of the cript, when another app was in front, this app should still be in front.)
I'm on Lion.

I have come across this before too. Basically you're saying that when this gets run when the Finder is frontmost that the Finder is not really frontmost. And that is true because you said this is an automator service. I believe automator stuff is run by an application named "Automator Runner". So actually as soon as the service is run Automator Runner becomes frontmost. Note that it is a faceless application so you can't see that it's frontmost but it is. So when you check if the Finder is frontmost it never is. Does that make sense? I see the same thing when running applescripts because they're run using Applescript Runner.
So how do you fix this? Here's a thought. Make this your FIRST BLOCK and see if it helps...
tell application "System Events"
set app_name to name of the first process whose frontmost is true
if app_name is "Automator Runner" then
set visible of process "Automator Runner" to false
set app_name to name of first process whose frontmost is true
end if
end tell
NOTE: I'm not certain that Automator Runner will be the frontmost process. It may be something else like the name of your automator action. But you can be certain something else is frontmost because of the automator action being run... so if my code doesn't work then you just have to figure out the name of the process that's running when your automator action is running and put that into the code. You can always put a "display dialog" in your code to show you the name of the frontmost process.
One other tip. In general I do not like to use the KILLALL command if I can use a QUIT command instead. Quit is designed for the Mac and makes sure things are stopped gracefully. As luck would have it the Finder has a quit command. Try this for your 3rd and 4th blocks. You'll see that if the Finder was frontmost then we activate it which makes it frontmost again but if it wasn't then we launch it so it is at least running again but doesn't come to the front.
-- quit the Finder
tell application "Finder" to quit
-- delay until the Finder quits
repeat
try
tell application "System Events" to get first process whose name is "Finder"
delay 0.1
on error
exit repeat
end try
end repeat
-- restart the Finder
if (app_name is equal to "Finder") then
tell application "Finder" to activate
else
tell application "Finder" to launch
end if
EDIT: It seems your step #2 is incorrect. You need to use "ON" or "OFF" instead of 0 or 1. Try this...
if (do shell script "defaults read com.apple.finder AppleShowAllFiles") is equal to "ON" then
do shell script "defaults write com.apple.finder AppleShowAllFiles OFF"
else
do shell script "defaults write com.apple.finder AppleShowAllFiles ON"
end if

A slight modification of #regulus6633’s script works on my machine:
-- restart the Finder
tell application "Finder" to launch # always launch
if (app_name is equal to "Finder") then
tell application "Finder" to activate # activate separately
end if
I must admit I am not entirely sure of the why and how – the AppleScript documentation for the launch and activate commands does not seem to be adequate in Finder’s case…

Related

Hide all apps using applescript

I am trying to work on an applescript to hide all apps that are open.
tell application "System Events"
set visible of every process whose visible is true and name is not "Finder" to false
end tell
Unfortunately it is not working as expected.
The first time when I run it, it hides script editor but not other apps
The second or third time when I run it, it closes script editor and other apps(but not finder windows)
My goal is as soon as applescript runs, hide all apps that are running
according to Willeke, this works for me :
tell application "System Events"
set visibleApps to every process whose visible is true and name is not "Finder"
repeat with theApp in visibleApps
set visible of theApp to false
end repeat
end tell

SecurityAgent pop-up does not get to window 1 (or any for that matter)

I am writing some simple apps using AppleScript for my own need. I should say I am a total noob still trying to make sense of the various elements of code.
When trying to enable a service, let's say to turn the server on using scripted UI actions, any other time, a Security Agent popup occurs. In order to automate the action, I have written the following piece of code:
the 1st bit is to check whether the Server is already ON and if not click the button to turn it on (it works):
tell application "ServerActivator" to activate
try
tell application "System Events"
tell process "ServerActivator"
if text field 1 of group "IP Config" of tab group 1 of window "Server Activator" is enabled then click button "ON" of window "Server Activator"
end tell
end tell
on error errMsg
end try
the second bit is to put fill the SecurityAgent pop up with the password
try
tell application "System Events"
tell process "SecurityAgent"
activate
set value of text field "Password :" of window 1 to "myPassword"
click button 2 of window 1
end tell
end tell
on error errMsg
end try
The second bit does not work properly as the code usually returns that windows 1 does not exist. However should I manually click on the window when the SecurityAgent popup appears, then and only then the code works. Obviously I want this to work independently of any user action. Any idea?
Thank you very much for your help!
Just wait until the process exists, the try block as well as the activate line is not needed.
tell application "System Events"
repeat until exists window 1 of process "SecurityAgent"
delay 0.5
end repeat
tell window 1 of process "SecurityAgent"
set value of text field 1 to "myPassword"
keystroke return
end tell
end tell

Applescript drag and drop doesn't work

I am new to Applescript, and wrote a script to securely wipe files, which brings up a file-selection dialog and confirmation, then wipes the file. However, when I tried to add drag and drop functionality, it doesn't work like everyone says it should. The icon never highlights (indicating drag and drop is working), and Finder just copies the file to the app's folder instead of dragging onto the app!
Here is the original script, which works fine (saved as "Wipe File.app"):
on run
set the_file to choose file with prompt "Select the file to wipe:"
wipe_file(the_file)
end run
to wipe_file(file_to_wipe)
set file_to_wipe to POSIX path of file_to_wipe
set ok_to_wipe to display dialog "Are you sure you want to wipe \"" & file_to_wipe & "\"?" buttons {"Cancel", "OK"} default button "Cancel"
set ok_to_wipe to button returned of ok_to_wipe
if (ok_to_wipe = "OK") then
tell application "Terminal"
activate
do script "set prompt='';cls;srm -v \"" & file_to_wipe & "\""
delay 3
close front window
set still_active to count windows
if still_active = 0 then
quit
end if
end tell
end if
end wipe_file
Then I added the following to the top. Running the script still works with the file-selection dialog, but the system never allows drag and drop!
on open the_files
repeat with the_file in the_files
wipe_file(the_file)
end repeat
end open
Everywhere I looked (Google, stack overflow) all say this approach should work, but it doesn't. I even tried removing the on run... block, leaving just on open..., but then the script does nothing at all.
EDIT
If I create a new script with the content above, and save it as an app, then copy it to the Applications folder, and paste a custom icon onto it, drag and drop works. However, the old script, which originally didn't have "on open" support, still doesn't work even after "on open" support was added to the script. So now I'm thinking that Apple must set some special attribute to indicate a script supports drag and drop, and for some reason (because it didn't have it when I first saved?) Apple didn't set that attribute for my file. Looking at Get Info and Show Package Contents for both apps, there are some strange differences:
The newly-created (working) app is only 693 KB, but the old (supposedly identical, but broken) one is 9.4 MB!
Inside the Contents/MacOS folder, the new (working) app has a file called "droplet", whereas the old one (broken) one has a file called "applet".
The first one is bizarre, and made me think of some sort of file corruption, but the second one is clearly the magic setting Apple uses for drag and drop. I verified that if I remove the "on open" block from the working script, and save it, Apple does not update the script icon to remove the "drop" arrow, and you can still drag and drop files onto it, but nothing happens.
So it seems that Apple decides whether a script supports drag and drop or not the first time it saves the script, and after that you get the wrong results unless save a brand new script!
You do not need to call Terminal and open window. The ‘do shell script’ opens already a shell session, in background, not visible in Terminal. You must just use it inside a 'try/end try' block to avoid script stops in case of error (like no authorization for the files !)
Also you are using ‘srm’ with option v (verbose). This option is used to display what is being done, but you do not see it because you are closing the window.
The possible issue of your script could also be when your file path contains special characters which must be escaped in shell. To avoid this, use ‘quoted form of ‘.
Script bellow is tested OK :
on run
set the_file to choose file with prompt "Select the file to wipe:"
wipe_file(the_file)
end run
on open the_files
repeat with the_file in the_files
wipe_file(the_file)
end repeat
end open
to wipe_file(file_to_wipe)
set file_to_wipe to POSIX path of file_to_wipe
set ok_to_wipe to display dialog "Are you sure you want to wipe \"" & file_to_wipe & "\"?" buttons {"Cancel", "OK"} default button "Cancel"
if (button returned of ok_to_wipe = "OK") then
try
do shell script "srm " & quoted form of (file_to_wipe)
end try
end if
end wipe_file

play a stream in iTunes without adding it to the library / playlist

I am controlling iTunes via AppleScript and I am playing streams from an HTTP server. The code I'm using looks like this:
tell application "iTunes"
open location "your_url_here"
play
end tell
It works fine, but I would like to avoid those URLs to show up in the iTunes library or any playlist afterwards. Is there a trick to achieve that?
Have you considered using QuickTimePlayer to play the stream instead?
tell application "QuickTime Player"
open URL "http://www.a-1radio.com/listen.pls"
end tell
It should open all the iTunes formats, it comes as a default on OsX, it is more "minimal", won't save tracks.
(I know you specified you want to use iTunes so this might not be a solution, but being preinstalled software it was worth a try)
EDIT To have it hidden, this seems to work:
tell application "QuickTime Player"
-- don't use launch or activate
-- on my mac with launch I see a flicker of the window
set numberOfWindows to (count windows)
repeat with i from 1 to numberOfWindows
close front window
end repeat
end tell
-- may add some delay here if it still flickers the window
-- delay 1
tell application "QuickTime Player"
open URL "http://www.a-1radio.com/listen.pls"
set visible of every window to false
end tell
tell application "System Events"
set visible of process "QuickTime Player" to false
end tell
-- must be called after the open URL command or won't work (no idea why)
To close the stream either quit or close windows (just close if you plan to reopen):
tell application "QuickTime Player"
-- here you can either:
-- close all (will leave app open and hidden)
set numberOfWindows to (count windows)
repeat with i from 1 to numberOfWindows
close front window
end repeat
-- or:
quit -- or just quit (will close app so will need to hide again next time)
end tell
If you hide it before opening the url, it doesn't work (no idea why). Of course the window, even if invisible, is still open so if someone clicks on the dock icon it will show all the open windows.
If you don't want to stop previous streams remove the first repeat -- end repeat part at the top, but leave the set numberOfWindows to (count windows) that is useless but activates the app without needing a activate/launch command

emacs+geben how do I open a file to put breakpoints in it

When I'm debugging code in a framework, it usually goes through a bunch of different calls in different files before actually getting to the file I want to investigate. Is there a way to open the file I want when I start geben, put the breakpoint in that file then tell geben to run (press g)?
Otherwise I have to keep stepping over/into until geben finally get's to the file I want, at which point I can then go to the line I want and set the breakpoint.
C-cf runs geben-find-file
IIRC, geben must already be in an active debugging session for that function to work; but once set the breakpoints are persistent, so it's not too onerous.
geben-breakpoint-menu menu is very convenient for setting conditionals, if you hadn't noticed that.