8

I am aware of the Script Editor menu. That is not what I'm looking for.

Is there a way to run an Applescript from the menu bar? I can save it as a file and run it from the Script Editor menu, and I can save it as an application and stick it in my dock. Is there a file format that allows it to run from the menu bar, as many applications do? Or a way to edit the code that does the same thing?

8

Cocoa-AppleScript as a script or AppleScript application created in Script Editor supports Menu Bar app. This script runs on macOS 10.12 (maybe runs on 10.10.x, 10.11.x). This script can be saved as application.

--AppleScript: menu bar script -- Created 2017-03-03 by Takaaki Naganoya
--2017 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "AppKit"
--http://piyocast.com/as/archives/4502

property aStatusItem : missing value

on run
    init() of me
end run

on init()
    set aList to {"Piyomaru", "Software", "", "Takaaki", "Naganoya", "", "Quit"}
    set aStatusItem to current application's NSStatusBar's systemStatusBar()'s statusItemWithLength:(current application's NSVariableStatusItemLength)

    aStatusItem's setTitle:"🚗"
    aStatusItem's setHighlightMode:true
    aStatusItem's setMenu:(createMenu(aList) of me)
end init

on createMenu(aList)
    set aMenu to current application's NSMenu's alloc()'s init()
    set aCount to 1
    repeat with i in aList
        set j to contents of i
        if j is not equal to "" then
            set aMenuItem to (current application's NSMenuItem's alloc()'s initWithTitle:j action:"actionHandler:" keyEquivalent:"")
        else
            set aMenuItem to (current application's NSMenuItem's separatorItem())
        end if
        (aMenuItem's setTarget:me)
        (aMenuItem's setTag:aCount)
        (aMenu's addItem:aMenuItem)
        if j is not equal to "" then
            set aCount to aCount + 1
        end if
    end repeat

    return aMenu
end createMenu

on actionHandler:sender
    set aTag to tag of sender as integer
    set aTitle to title of sender as string

    if aTitle is not equal to "Quit" then
        display dialog aTag as string
    else
        current application's NSStatusBar's systemStatusBar()'s removeStatusItem:aStatusItem
    end if
end actionHandler:

I previously edited the original code, posted by Piyomaru, just to the point it would compile and wanted to add some additional information to make the example code more useful for anyone relatively new to AppleScript.

Presently in the example code, if saved as an application it has no code to quit the application, it only removes the menu bar object. So, in the actionHandler handler of the script, add the following to the else branch of the if statement, after the existing code:

        if (name of current application) is not "Script Editor" then
            tell current application to quit
        end if

It's coded so if/when run from within Script Editor it will not attempt to close Script Editor. You can use it without the if statement block and use just tell current application to quit if you're not going to run it from within Script Editor.

Because this script is using Cocoa-AppleScript, once run from within Script Editor, it must be compiled again just before saving it in order to flush the C and Objective-C pointers created by the Cocoa-Applescript code, since pointers cannot be saved in the script. Just click the hammer icon on the Toolbar, or: Script Editor > Script > Compile ⌘K

Additionally, when saved as an application you must check the Stay open after run handler check-box when saving it, and by default the app's Dock Tile will show in the Dock when running. As this might be unwanted behavior for a menu bar app, use the following command in Terminal to add the necessary key to the app's Info.plist file so it will not show in the Dock.

defaults write /Applications/name_of_app.app/Contents/Info.plist LSUIElement -bool yes
  • Replace name_of_app with the actual name you saved it as, and if necessary change the path if not in /Applications.
  • Note that if you drag the app to the Dock, its Dock Tile will still show on the Dock, just won't have a open indicator under it when open. This added key to the Info.plist file is to keep the Dock Tile from showing on the Dock when running, when the app has not been dragged to the Dock in the first place.

In the actionHandler handler of the original example code, it just displays a dialog box with the menu item number that was clicked, which certainly fine for example code, however, I'd like to show a different example how to have separate code execute based on which menu item was clicked. The following example code could replace the entire actionHandler handler in the original script:

on actionHandler:sender
    set aTitle to title of sender as string
    if aTitle is equal to "Quit" then
        current application's NSStatusBar's systemStatusBar()'s removeStatusItem:aStatusItem
        if (name of current application) is not "Script Editor" then
            tell current application to quit
        end if
    else if aTitle is equal to "Piyomaru" then

        --  # Your code to run for this menu choice goes here:

    else if aTitle is equal to "Software" then

        --  # Your code to run for this menu choice goes here:

    else if aTitle is equal to "Takaaki" then

        --  # Your code to run for this menu choice goes here:

    else if aTitle is equal to "Naganoya" then

        --  # Your code to run for this menu choice goes here:

    end if
end actionHandler:

Now this could be written differently, i.e. "Quit" as an else or else if at the bottom, but I did it this way because I want all other menu commands to be an else if choice, even though logically any other given menu command is more likely to be clicked then "Quit". For me, I think it's easier to add/edit/remove the menu command's code when written this way. It's just a personal preference, so do it as you feel what's right for you.

A discussion note from the AppleScript Language Guide:

An if statement can contain any number of else if clauses; AppleScript looks for the first Boolean expression contained in an if or else if clause that is true, executes the statements contained in its block (the statements between one else if and the following else if or else clause), and then exits the if statement.

An if statement can also include a final else clause. The statements in its block are executed if no other test in the if statement passes.

For the most part of the original example code, you should only have to modify two line of code in the init handler:

set aList to {"Piyomaru", "Software", "", "Takaaki", "Naganoya", "", "Quit"}
  • This sets the name of the menu commands in their order, and "" is for a separator.

For a different icon:

aStatusItem's setTitle:"🚗"
  • Change the "🚗" to something else you prefer, from: Script Editor > Edit > Emoji & Symbols

Hopefully it's obvious that the if statement block in the actionHandler handler will correspond to the aList in the init handler, so match the names in the aTitle is equal to in the actionHandler handler to the names in the aList in the init handler.

The rest of the code should not need to be modified, although it certainly can if need be or wanted.

  • I edited your answer because as written is would not compile, it should now. Also, this script uses Cocoa-AppleScript, not normal or standard AppleScript alone. +1 though. – user3439894 Jul 29 '17 at 14:38
  • I can't save it - either as script or application. I have done the compile step, but keep getting: The document "xxx" could not be autosaved. C and Objective-C pointers cannot be saved in scripts. What am I doing wrong? – Gilby Aug 4 '17 at 3:30
  • AppleScript document file can not save C and Objective-C pointers in it. So, you have to edit AppleScript (ex.add blank lines or delete blank lines), then you can save it. It is a normal operation for Apple genuine Script Editor. – Piyomaru Aug 5 '17 at 6:15
7

Normal AppleScript as a script or AppleScript application created in Script Editor is not supported as a Menu Bar app. You'd have to use Cocoa-AppleScript or build an app in Xcode (or use a third-party launcher) if you don't want to use the Script menu in the Menu bar.

Here's an example app done in Xcode using Swift: WeatherBar.

One long time trusted app that does this is FastScripts, and although it's looks like the Scripts menu it does offer additional functionality. It can be run as a free app, up to 10 keyboard shortcuts, or upgraded for $9.95 to unlock unlimited keyboard shortcuts.

I have no affiliation with Red Sweater Software, LLC, other then as a user of FastScripts as a free app.

  • FastScripts is nice in that it lets you assign keyboard shortcuts for your menu items. Apple's "Script Editor menu" stopped letting you assign shortcuts to its menu items years and years ago, – Wayfaring Stranger Jul 28 '17 at 23:34
3

Depending on what exactly you want to do with your apple script, maybe bitbar could be suitable for your purpose.

In general this application lets you display the output of a variety of scripts in the menu bar - many scripts are already finish but you can also write your own.

But it can also be used to execute applescripts. I use it to execute an applescripted saved as service by calling it through a little bash script:

#!/bin/bash
echo "blub"
echo "---"
echo "1 | bash=/Users/username/Library/Services/Space_1 terminal=false"
-2

There is a little-used "Services" menu (in the menu under the application's name) and you can save scripts as services and make them available in the services menu for either a specific application .

There is also the concept of applications that are "attachable," these applications allow you to add scripts to the application's own menu commands. But applications that are attachable seem rare.

Does any of that fit what you are looking for?

  • Nope. I'm looking for an application that runs from the menu bar itself, not a service. Do you have the Speedtest app? Something like that, where the app itself is in the menu bar, not just launched from it. – DonielF Jul 28 '17 at 21:18

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .