Skip to content

Commit

Permalink
Initial version
Browse files Browse the repository at this point in the history
- shows status of services in status bar
- allows start/stop toggle
  • Loading branch information
andrewn committed Apr 30, 2016
1 parent 450f24e commit bc505d5
Show file tree
Hide file tree
Showing 8 changed files with 142 additions and 16 deletions.
100 changes: 98 additions & 2 deletions BrewServicesMenubar/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,116 @@

import Cocoa

struct Service {
var name = ""
var state = "unknown" // "started", "stopped", "unknown"
}

func matchesForRegexInText(regex: String!, text: String!) -> [String] {
do {
let regex = try NSRegularExpression(pattern: regex, options: [])
let nsString = text as NSString
let results = regex.matchesInString(text,
options: [], range: NSMakeRange(0, nsString.length))
return results.map { nsString.substringWithRange($0.range)}
} catch let error as NSError {
print("invalid regex: \(error.localizedDescription)")
return []
}
}


@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {

@IBOutlet weak var window: NSWindow!

@IBOutlet weak var statusMenu: NSMenu!

// Returns a status item from the system menu bar of variable length
let statusItem = NSStatusBar.systemStatusBar().statusItemWithLength(-1)
var services = [Service]()

func applicationDidFinishLaunching(aNotification: NSNotification) {
// Insert code here to initialize your application
let icon = NSImage(named: "statusIcon")

statusItem.image = icon
statusItem.menu = statusMenu

services = serviceStates()
updateMenu()
}

func applicationWillTerminate(aNotification: NSNotification) {
// Insert code here to tear down your application
}

func updateMenu() {
for service in services {
let item = NSMenuItem.init(title: service.name, action:#selector(AppDelegate.handleClick(_:)), keyEquivalent: "")
if service.state == "started" {
item.state = NSOnState
}
statusMenu.addItem(item)
}
}

func serviceStates() -> [Service] {
let task = NSTask()
let outpipe = NSPipe()
task.standardOutput = outpipe

task.launchPath = "/usr/local/bin/brew"
task.arguments = ["services", "list"]
task.launch()

let outdata = outpipe.fileHandleForReading.readDataToEndOfFile()
if var string = String.fromCString(UnsafePointer(outdata.bytes)) {
string = string.stringByTrimmingCharactersInSet(NSCharacterSet.newlineCharacterSet())
return parseServiceList(string)
}

return []
}

func controlService(name:String, state:String) {
let task = NSTask()
let outpipe = NSPipe()
task.standardOutput = outpipe

task.launchPath = "/usr/local/bin/brew"
task.arguments = ["services", state, name]
task.launch()
}

func parseServiceList(raw: String) -> [Service] {
let r = "([^ ]+)([^ ]+)"
var services = [Service]()
let rawServices = raw.componentsSeparatedByString("\n")
for s in rawServices {
let parts = matchesForRegexInText(r, text: s)
let service = Service(name: parts[0], state: parts[1])
services.append(service)
}
return services
}

func handleClick(sender: NSMenuItem) {
if (sender.state == NSOnState) {
sender.state = NSOffState
controlService(sender.title, state: "stop")
} else {
sender.state = NSOnState
controlService(sender.title, state: "start")
}
}


@IBAction func itemClicked(sender: NSMenuItem) {
if (sender.state == NSOnState) {
sender.state = NSOffState
} else {
sender.state = NSOnState
}
}
}

6 changes: 6 additions & 0 deletions BrewServicesMenubar/Assets.xcassets/Contents.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"info" : {
"version" : 1,
"author" : "xcode"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "icon.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "[email protected]",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "[email protected]",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
27 changes: 13 additions & 14 deletions BrewServicesMenubar/Base.lproj/MainMenu.xib
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="6233" systemVersion="14A329f" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="10116" systemVersion="15E65" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="6233"/>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="10116"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="NSApplication">
Expand All @@ -11,9 +12,9 @@
</customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
<customObject id="Voe-Tx-rLC" customClass="AppDelegate" customModuleProvider="target">
<customObject id="Voe-Tx-rLC" customClass="AppDelegate" customModule="BrewServicesMenubar" customModuleProvider="target">
<connections>
<outlet property="window" destination="QvC-M9-y7g" id="gIp-Ho-8D9"/>
<outlet property="statusMenu" destination="nT1-qv-Jg9" id="wdj-Rl-AUX"/>
</connections>
</customObject>
<customObject id="YLy-65-1bz" customClass="NSFontManager"/>
Expand Down Expand Up @@ -666,15 +667,13 @@
</menuItem>
</items>
</menu>
<window title="BrewServicesMenubar" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" animationBehavior="default" id="QvC-M9-y7g">
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
<rect key="contentRect" x="335" y="390" width="480" height="360"/>
<rect key="screenRect" x="0.0" y="0.0" width="1920" height="1177"/>
<view key="contentView" wantsLayer="YES" id="EiT-Mj-1SZ">
<rect key="frame" x="0.0" y="0.0" width="480" height="360"/>
<autoresizingMask key="autoresizingMask"/>
</view>
</window>
<menu id="nT1-qv-Jg9">
<items>
<menuItem title="No services found" id="0Yg-7w-ef3">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
</items>
<point key="canvasLocation" x="141.5" y="296.5"/>
</menu>
</objects>
</document>
2 changes: 2 additions & 0 deletions BrewServicesMenubar/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,7 @@
<string>MainMenu</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
<key>LSUIElement</key>
<true/>
</dict>
</plist>

0 comments on commit bc505d5

Please sign in to comment.