Applescript quit after 1 minute - xcode

i have a very simple applescript app in xcode that just opens a window and has a button that redirects to a website. Is there a way to automatically exit the window if the user hasnt clicked the button in 60 seconds.
Here is my code
script AppDelegate
-- property parent : class "NSObject"
-- IBOutlets
property theWindow : missing value
on applicationWillFinishLaunching_(aNotification)
-- Insert code here to initialize your application before any files are opened
end applicationWillFinishLaunching_
on buttonClicked_(sender)
open location "https://example.com"
quit
end buttonClicked_
on applicationShouldTerminate_(sender)
-- Insert code here to do any housekeeping before your application quits
return current application's NSTerminateNow
end applicationShouldTerminate_
end script

Since the window is being shown when the application starts up, you can just call a method/handler after a delay from the applicationWillFinishLaunching method. Since you are also quitting from the button handler, that can perform double duty, for example, replace these handlers:
on applicationWillFinishLaunching_(aNotification)
my performSelector:"buttonCLicked:" withObject:me afterDelay:60
end applicationWillFinishLaunching_
on buttonClicked_(sender)
if sender is not me then open location "https://example.com"
current application's NSApp's terminate:me -- quit
end buttonClicked_

Related

How to convert window object to string in AppleScript?

I've an AppleScript that retrieves window id of an app.
Example following script retrieves the window id of Brave Browser.
set urls to {"https://google.com"}
tell application "Brave Browser"
set myNewWindow to make new window
repeat with theURL in urls
tell myNewWindow to open location theURL
end repeat
delay 0.3
log myNewWindow
return class of myNewWindow //comment - returns "window" as a class
end tell
My goal is it possible to convert the window id to a string and vice-versa.
Why conversion?
I want to save window id in UserDefaults on macOS.
Note: This AppleScript is used in macOS app.
To be honest, it's hard for me to understand why the ID should be kept in defaults. Because theID variable will already store this value throughout the script. And at any time you can close the window using a variable in a later part of the script. I can only assume one thing: you want to open a window locally and then close it from other script executed on a remote machine.
And getting the window ID in Brave Browser as text is easy:
set urls to {"https://google.com"}
tell application "Brave Browser"
set myNewWindow to make new window
repeat with theURL in urls
open location theURL
end repeat
delay 0.3
set theID to (id of myNewWindow) as text --> the ID of window in text form
end tell
-- write theID value to defaults here
Closing the window from other script:
-- first, read theID from defaults here
tell application "Brave Browser"
close window id (theID as integer)
end tell

How can I bypass an index error or have the script run again?

I am encountering an index error that appears when the app in use has an overlay or notification appear. To provide a better description, the app will occasionally show an alert if something needs to be acknowledged or dismissed. When that happens, the script is unable to return the value from the designated location in the GUI, and returns the following error message: "Can’t get group 4 of toolbar 1 of window 1 of process "App I'm Using". Invalid index.System Events got an error: Can’t get group 4 of toolbar 1 of window 1 of process "App I'm Using". Invalid index. (-1719)"
The behavior is expected, but I would like to adjust the script to where it will either delay trying again for 30 seconds or so, or just not display said error at all.
I've been toying around with using an 'on error' statement, but I can't get it to take with the 'tell' statement that it's referring to, for example:
on error error_message number error_number
if error_number = -1719 then
wait 30
end if
I'm unsure of how I can use the 'on error' function with the section of the script below, but if I can make it try again in 30 - 45 seconds without displaying an error, it would be perfect.
on idle
-- Update the status item's text here.
tell application "System Events"
if not (exists process appName) then
display alert "Application " & appName & " is not running" as warning giving up after 6
quit me
end if
tell process appName
tell first window's first toolbar's fourth group's first group's first menu button
set activityState to first item of (value as list) as text
end tell
end tell
end tell
end idle
I believe the error is encountered when the script reaches "tell window's first toolbar's fourth group's..." before it is supposed to "set activityState to first item...".
I have used the 'on error' function with 'try' statements successfully, but I'm having issues moving forward with this one.
Or you can try this approach which will remain in the repeat loop until first window's first toolbar's fourth group's first group's first menu button becomes available.
on idle
-- Update the status item's text here.
tell application "System Events"
if not (exists process appName) then
display alert "Application " & appName & " is not running" as warning giving up after 6
quit me
end if
tell process appName
repeat until exists of first window's first toolbar's fourth group's first group's first menu button
delay 0.2
end repeat
tell first window's first toolbar's fourth group's first group's first menu button
set activityState to first item of (value as list) as text
end tell
end tell
end tell
end idle
You can’t split statements (such as if or tell). The try statement needs to wrap around the complete statement(s) you want it to work with, for example, the statement telling the app process:
on idle
tell application "System Events"
if not (exists process appName) then
---
end if
try
tell process appName
---
end tell
on error errmess number errnum
return 30 -- try the idle handler again in 30 seconds
end try
end tell
end idle
You can use the exists keyword to check if an element is present before trying to access it. exists won't through an error if the element isn't there, and will let you skip over the problematic lines:
on idle
-- Update the status item's text here.
tell application "System Events"
if not (exists process appName) then
display alert "Application " & appName & " is not running" as warning giving up after 6
quit me
end if
tell process appName
-- assuming the window and toolbar are always going to be there
try
tell first window's first toolbar
-- check to see if the UI element exists
if exists fourth group's first group's first menu button then
-- only get the activity state if it does
tell fourth group's first group's first menu button
set activityState to first item of (value as list) as text
end tell
end if
end tell
on error errstr
(*
this code is in an 'idle' handler, so on any error we
just return 30 to idle for another 30 seconds and try again.
*)
return 30
end try
end tell
end tell
end idle

Display Variable from Repeat loop in a Floating Window

I have an applescript that captures a counter in another application. This works fine but I'd like to output the results to another floating window and have it update with each loop. Does anyone know of a way to do this? Complete newb.
Thanks
EDIT:
My code is:
tell application "System Events"
tell process "MIDI Editor"
with timeout of 0 seconds
repeat
set barCount to value of text field "Main Counter" of group "Counter Display Cluster" of window "Edit: kjhsdf" of application process "MIDI Editor" of application "System Events"
delay 0.01
end repeat
end timeout
end tell
end tell
(Not sure why that last end tell keeps breaking out of the code block!)
So its barCount that I want to mirror in real time in another window
From the Script Editor you can use some AppleScriptObjC to programmatically create a non-modal window with a text field that can be updated. In the example below I am using a repeating timer instead of an AppleScript repeat statement, as tight loops like that will block the user interface. Save the script as an application, with the option set to stay open.
use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Cocoa"
use scripting additions
property WindowFrame : {{200, 600}, {150, 50}} -- window location and size
property TextFrame : {{10, 10}, {130, 30}} -- window size minus 20
property mainWindow : missing value
property textField : missing value
property timer : missing value
on run -- example
setup()
update()
set my timer to current application's NSTimer's timerWithTimeInterval:0.25 target:me selector:"update" userInfo:(missing value) repeats:true
current application's NSRunLoop's mainRunLoop's addTimer:timer forMode:(current application's NSDefaultRunLoopMode)
end run
to update() -- update text field
set barCount to ""
with timeout of 0.5 seconds
tell application "System Events" to tell process "MIDI Editor"
set barCount to value of text field "Main Counter" of group "Counter Display Cluster" of window "Edit: kjhsdf"
end tell
end timeout
textField's setStringValue:(barCount as text)
end update
to setup() -- create UI objects
tell (current application's NSTextField's alloc's initWithFrame:TextFrame)
set my textField to it
its setFont:(current application's NSFont's fontWithName:"Menlo" |size|:18)
its setBordered:false
its setDrawsBackground:false
its setSelectable:false
end tell
tell (current application's NSWindow's alloc's initWithContentRect:WindowFrame styleMask:1 backing:(current application's NSBackingStoreBuffered) defer:true)
set my mainWindow to it
its setAllowsConcurrentViewDrawing:true
its setHasShadow:true
its setTitle:"Progress"
its setLevel:(current application's NSFloatingWindowLevel)
its (contentView's addSubview:textField)
its setFrameAutosaveName:"Update Window" -- keep window position
its setFrameUsingName:"Update Window"
its makeKeyAndOrderFront:me
end tell
end setup

Can't get Window 1 of process intermittently thrown

I have an applescript saved as an always on application, which generally works. However, there are odd instances where it will throw the error:
"Systems Events got an error: Can't get window 1 of process "FaceTime". Invalid index. (-1719)"
Mostly occurs if FaceTime app is closed, but not always. Odd.
Can anyone advise how I can dismiss this or write better code to avoid?
Here is my code:
on idle
if application "FaceTime" is running then
tell application "System Events"
tell process "FaceTime"
if get value of attribute "axFullScreen" of window 1 = false then
set FullscreenButton to a reference to (button "Full Screen" of window 1)
if FullscreenButton exists then
click FullscreenButton
end if
end if
end tell
end tell
end if
return 3
end idle
on quit
continue quit
end quit
Put all Code inside the idle block in a try and Error Block. If an error is thrown itll be catched
try
-- your code
on error err
log err
end try

How to link code to the GUI with Cocoa-Applescript on Xcode

I am trying to link my code to my GUI. But it won't let me.
Currently, I have a label, Button, and a Text Field on my GUI. This is my code for the GUI:
-- IBOutlets
property window : missing value
on buttonClicked_(sender)
display alert "Hello there " & (stringValue() of textField)
end buttonClicked_
on applicationWillFinishLaunching_(aNotification)
-- Insert code here to initialize your application before any files are opened
end applicationWillFinishLaunching_
on applicationShouldTerminate_(sender)
-- Insert code here to do any housekeeping before your application quits
return current application's NSTerminateNow
end applicationShouldTerminate_
When I try using the App Delegate tool, It doesn't work. I drag it to the parts on the GUI and it makes a blue line. But, The only thing the shows up under "Outlets" is "Window"
If I run the program, The GUI comes up, but it doesn't do anything cause the code isn't connected!
How do I connect my code to my GUI?
Extra Info: Xcode 5.1
You have to declare the outlet and then connect the outlets in the xib. ctrl-drag (or click right mouse button and drag) from AppDelegate to the textfield.
Then ctrl-drag from the button to the AppDelegate and choose the method, you want to send.
-- IBOutlets
property window : missing value
property myTextField : missing value
on applicationWillFinishLaunching_(aNotification)
-- Insert code here to initialize your application before any files are opened
end applicationWillFinishLaunching_
on buttonClicked_(sender)
display alert "Hello there " & myTextField's stringValue
end buttonClicked_
on applicationShouldTerminate_(sender)
-- Insert code here to do any housekeeping before your application quits
return current application's NSTerminateNow
end applicationShouldTerminate_

Resources