The next sample has a little wrinkle. Here is the first port:

statusbar-item.rb (status item disappears)

#!/usr/bin/env macruby
framework 'cocoa'

class App
  def applicationDidFinishLaunching(aNotification)
    statusbar = NSStatusBar.systemStatusBar
    status_item = statusbar.statusItemWithLength(NSVariableStatusItemLength)

    image = NSImage.alloc.initWithContentsOfFile("stretch.tiff")
    raise "Icon file 'stretch.tiff' is missing." unless image

    status_item.setImage(image)
  end
end

NSApplication.sharedApplication
NSApp.delegate = App.new
NSApp.run

However, this does not quite work as expected. After briefly appearing, the status_item disappears. Now, in objective c one would have to explicitly retain the result of statusItemWithLength, so I assumed this was the local variable status_item getting garbage collected.

Sure enough, if we change it to @status_item (which will then live for the life of the App object, not just the duration of applicationDidFinishLaunching), it works fine.

However I also noticed that adding a “sleep 1″ to the end of applicationDidFinishLaunching makes it work as well, with status_item as a local variable. I was not really sure why this would be, so I posted it to the Macruby dev list, and this is what Laurent replied:

I believe the reason is because your sleep 1 prevented a non-deterministic garbage collection cycle. In the presence of a Cocoa run loop the GC might be triggered by a few different ways. I believe you’re just lucky that it works :)

In my opinion the Macruby behaviour (without the sleep) is better: the status item really should disappear when it goes out of scope. The reason it doesn’t in the rubycocoa example is because rubycocoa does a retain behind the scenes, so although the ruby variable pointing at the status item goes out of scope, the status item itself does not.

statusbar-item.rb (works)

#!/usr/bin/env macruby
framework 'cocoa'

class App
  def applicationDidFinishLaunching(aNotification)
    statusbar = NSStatusBar.systemStatusBar
    @status_item = statusbar.statusItemWithLength(NSVariableStatusItemLength)

    image = NSImage.new.initWithContentsOfFile("stretch.tiff")
    raise "Icon file 'stretch.tiff' is missing." unless image

    @status_item.setImage(image)
  end
end

NSApplication.sharedApplication
NSApp.delegate = App.new
NSApp.run

Pages: 1 2 3