Tigger is a scrolling ticker for the menu bar. Alternatively the ticker can be placed in a floating window. For more information visit the furrysoft website: http://www.furrysoft.de/?page=tigger
This document will help you in developing plug-ins for Tigger or accessing it from your own application.
(Tigger's AppleScript interface is documented here.)
The first chapter will explain the nature of plug-ins and their relationship to the Tigger application. You will also learn about the techniques used to communicate between Tigger and other applications.
Explains how Tigger handles it's ticker data.
Users can change defaults and click the ticker. This chapter explains how clients can get at user input.
Here wou will find a list of all relevant protocols, categories and classes with descriptions of their methods and how to use them.
A list of revisions and changes.
The Tigger application displays a view with a scrolling ticker. The actual contents for the ticker is provided by plug-ins or other applications. Tigger acts as a server and plug-ins and other applications are both called Tigger clients.
Tigger plug-ins are Cocoa bundles. They are automatically loaded at application start or when the user adds them to a plug-in folder. (Objective-C classes can not be unloaded. So it is not possible to replace an already loaded plug-in by a newer version at runtime.)
Other applications use Distributed Objects to talk to the Tigger server.
The structure of the data clients send to the server is defined through classes declared in the AMTickerService framework. This framework is necessary for Tigger to run. While clients need to include the framework into the project to build it, they will run fine without it, as long as they don't try to use it. This is due to Objective-C's dynamic nature and Mac OS X's weak linking capabilities.
All Tigger clients need to implement at least the AMTiggerClientProtocol protocol.
Plug-Ins additionally must implement the AMTiggerClientPrefPane protocol. If they want to display a preference pane implementation of the AMTiggerPluginProtocol protocol is needed.
Some informal protocols offer additional functionality and may be implemented as needed. See the reference section for details.
The server implements the AMTiggerServerProtocol protocol. Clients use this interface to talk to the server.
The individual chunks of text or images that Tigger displays are called 'signs'. (I'm not a native english speaker, so please excuse if this not too great a name ☺.)
Tigger manages two queues. A wait queue and a display queue.
Clients add signs to the wait queue (typically at the end of the queue).
The display queue holds all signs that are displayed in the ticker at the moment.
When there is room in the ticker for a new sign, the first one is removed from the wait queue and added to the display queue. When a sign is scrolled out of the ticker, it is removed from the display queue and it's loop count is decremented. If the loop count reaches zero, the sign is desposed of. Otherwise it is appended to the end of the wait queue again.
Clients do not have any access to the display queue. They may only add to and remove signs from the wait queue.
The main menu, the preferences window and the ticker itself are Tiggers main elements for user interaction.
While the menu is only accessible to the Tigger application itself, plug-ins may provide their own preference pane. See the AMPrefPaneProtocol protocol.
All clients can attach a string to each sign. The action type argument defines the action triggered when the respective sign is clicked by the user.
There is one plug-in and one client application project located inside the development kit's Examples folder. Use theses examples as a starting point for your own projects.
Protocols
AMTiggerClientProtocol(Protocol)
AMTiggerClientPrefPane (Informal Protocol)
AMTiggerClientAction(Informal Protocol)
AMTiggerPluginProtocol(Protocol)
AMPrefPaneProtocol(Protocol)
AMPrefPaneBundleProtocol(Protocol)
AMPrefPaneInformalProtocol(Informal Protocol)
AMTiggerServerProtocol(Protocol)
Helper Class
AMTiggerServerDefaults(NSMutableDictionary Category)
Data Structures
AMTickerSign(Abstract Class)
AMImageTickerSign(Class)
AMTextTickerSign (Class)
Both, plug-ins and distant clients need to implement this protocol.
- (void)setupWithServer:(id)theServer;
The client may retrieve/set it's defaults but should not begin displaying signs yet. (Client might be disabled by the user.)
- (void)activate;
Will be called when the client is supposed to start sending signs to the server.
(activateWithServer: is still supported for backwards compatibility.)
- (void)deactivate;
Will be called when the client should stop operation.
- (BOOL)hasPrefsPane;
Tell the server if you bring your own pref pane. Plug-Ins only at the moment.
You need to make sure that the client can be started and stopped repeatedly.
Informal protocol for clients to provide additional information to the server.
- (NSString *)clientIdentifier; - (NSImage *)prefPaneIcon; - (NSString *)prefPaneIconLabel;
These will allow a client that is not a plug-in, to display it's own preference pane in Tigger's preference window. (Not yet implemented.)
- (NSString *)userInfo;
This string will be displayed in Tigger's Plug-Ins preference pane.
Informal protocol for clients that want to support clickable signs.
- (void)performAction:(in NSString *)action;
Tigger will send the client this message when one of it's signs is clicked by the user. The action argument is the string supplied by the client with AMTickerSign's setActionString:
- (void)performAction:(in NSString *)action buttonNumber:(in int)button modifierFlags:(in unsigned int)flags;
Available in Tigger 1.3.1 and later.
If implemented, Tigger will send this message to the client instead of performAction:.
- (out NSMenu *)menuForAction:(in NSString *)action;
Available in Tigger 1.3.1 and later.
This message will be sent when the user does a control-click or right-click on one of the client's signs. The action argument is the string supplied by the client with AMTickerSign's setActionString:.
The returned menu will be displayed at the mouse position.
Plug-Ins only. Mandatory.
- (id)initWithBundle:(NSBundle *)theBundle;
The plug-in has been loaded from theBundle. Do all basic initialization here.
Mandatory only if you want to use your own pref pane, i.e. if you answer YES to hasPrefsPane.
Most of these values are extracted from a plug-in's info.plist automatically.
- (NSView *)mainView;
The main view of the pref pane.
- (NSString *)identifier;
A unique identifier for the plug-in.
- (NSImage *)icon;
The image used as a preferences icon.
- (NSString *)label;
The label (localized) for the preferences icon.
- (NSString *)category;
The preferences category. Not used in Tigger. Return an empty string;
Plug-Ins don't need to answer most of these requests, since the values are read from their info.plist when the bundle is loaded. The corresponding keys are:
CFBundleIdentifier | is also used as plug-in identifier |
NSPrefPaneIconFile | image name for pref pane icon |
NSPrefPaneIconLabel | label for pref pane (localized) |
AMPrefPaneCategory | category for pref pane (*not* localized) |
More info.plist keys:
CFBundleVersion | version number for system |
AMPrefPaneVersion | version number for display |
AMPrefPaneHelpURL | URL for online help |
The CFBundleVersion is used when comparing two plug-ins with the same name to find out which one is more recent.
The AMPrefPaneVersion is the string displayed to the user in Tigger's Plug-Ins preference pane.
It's up to the plug-in developer if those two should be the same.
You need to provide ascending AMPrefPaneVersion values for drag & drop installs of your plug-ins to work.
You might also want to implement this one. Though, since it overlaps with the previous protocols for the most part, it's not required.
- (id)initWithBundle:(NSBundle *)theBundle;
Same as declared in AMTiggerPluginProtocol.
- (NSBundle *)bundle;
Just for completeness sake.
- (NSView *)loadMainView;
This may be interesting for lazy loading of the plug-in's nib.
- (NSView *)mainView;
Already required by the AMPrefPaneProtocol.
This informal protocol declares some optional methods.
- (void)willSelect;
Will be called before the pref pane is displayed.
- (void)didSelect;
Will be called after the pref pane is displayed.
- (int)shouldUnselect;
Does not do anything at the moment.
- (void)willUnselect;
Will be called before the pref pane is closed/switched away.
- (void)didUnselect;
Will be called after the pref pane was closed/switched away.
- (NSString *)categoryDisplayName;
Here you may provide a localized name for your category. Not used by Tigger.
- (NSString *)version;
Return a version number for your plug-in. You may return an empty string and put the actual version number in your info.plist instead.
- (NSString *)helpURL;
Available in Tigger 1.3 and later.
Return a URL for online help. You may either provide a remote http link (example: http://www.domain.com/myplugin/help.html) or a file link, that points to a help page inside your plug-in bundle. Insert %BUNDLE% in place of your bundle folder's path. Tigger will automatically replace that string with the correct path at runtime. Example: file://%BUNDLE%/help/help.html
You may return an empty string and put the actual URL in your info.plist instead.
- (BOOL)shouldResize;
Available in Tigger 1.3 and later.
Return YES from this method to make your preference pane resizable. If you do, you should also provide the following two methods:
- (NSSize)minSize; - (NSSize)maxSize;
Available in Tigger 1.3 and later.
Denotes the minimum and maximum size for a resizable preference pane, respectively.
- (NSSize)standardSize;
Available in Tigger 1.3 and later.
Will be called when the user clicks the window's zoom button. Return the 'best' size for your preference pane. If this method is not implemented, the zoom button will be disabled.
This is the protocol the server is known to conform to.
- (oneway void)registerClient:(byref id)client withName:(bycopy in NSString *)name;
Will be automatically performed for plug-ins. Distant clients will have to register here.
- (oneway void)deregisterClientWithName:(bycopy in NSString *)name;
Make sure to deregister when you terminate. Plug-Ins are automatically deregistered.
- (oneway void)addSign:(bycopy in AMTickerSign *)aSign client:(byref id)client; - (oneway void)addSign:(bycopy in AMTickerSign *)aSign;
This is the usual way to add something to the wait queue.
(You need to use the first version and provide your client object if you want to receive performAction: messages. The second version ist just a shortcut and calls the first one with nil as client argument.)
- (oneway void)insertSignAtCursor:(bycopy in AMTickerSign *)aTickerSign client:(byref id)client; - (oneway void)insertSignAtCursor:(bycopy in AMTickerSign *)aTickerSign;
If you have to display something urgent, this method will put it right in front of the display queue.
(You need to use the first version and provide your client object if you want to receive performAction: messages. The second version ist just a shortcut and calls the first one with nil as client argument.)
- (oneway void)removeSign:(bycopy in AMTickerSign *)aSign;
Since it is possible to choose an endless loop count, there has to be a way to remove a sign manually. This is it. Don't forget or the sign in question will never go away!
- (out NSSize)viewSize;
Here you may request the size of the scroll area. You might want to scale your signs accordingly. Signs smaller than the viewSize (in width or height, depending on the scroll direction) will be centered.
- (oneway void)setFrame:(bycopy in NSRect)newFrame forTickerWithID:(bycopy NSString *)tickerID;
Available in Tigger 1.3 and later.
This message may be sent to resize the ticker's frame. The ticker ID is meant for future extensions; it is ignored at the moment. Plug-Ins should usually not mess with the ticker view.
- (oneway void)openHelpForIdentifier:(bycopy in NSString *)theIdentifier;
Available in Tigger 1.3 and later.
This will open the help page specified with helpURL.
- (oneway void)runAppleScript:(bycopy in NSString *)scriptFile delegate:(id)delegate scriptFinishedSelector:(SEL)selector;
Available in Tigger 1.3 and later.
This will execute an AppleScript in a separate process (using the osascript command line tool).
AppleScript can be rather slow, since it often has to wait for answer from another application. If you execute an AppleScript in the application's main thread it may stop the ticker from scrolling smoothly. Since AppleScript is not threadsafe you can't start the script in a second thread either. Instead use this method to execute your script in it's own process space.selector is the message that is sent to the delegate when the script finishes. The method signature for selector looks like this:
- (void)scriptFinishedWithResult:(NSString *)result error:(NSString *)error;
runAppleScript:delegate:scriptFinishedSelector: will start osascript with the -sh argument. To learn more, type man osascript in Terminal.
- (inout NSMutableDictionary *)preferencesForIdentifier:(bycopy in NSString *)theIdentifier;
This handy method gives you a mutable dictionary where you may store you plug-in's user defaults.
Note that what you get is not really an NSDictionary – but it has nearly the same interface. Actually it's interface is probably more similar to NSUserDefaults, but that class wouldn't really fit either.
There's a category on NSDictionary that may be used on the object you get from this method.
This category is declared in AMTiggerServerDefaults.
It is used to handle plug-in defaults. See preferencesForIdentifier:.
@interface NSMutableDictionary (AMTiggerServerDefaults) - (NSArray *)arrayForKey:(NSString *)defaultName; - (BOOL)boolForKey:(NSString *)defaultName; - (NSData *)dataForKey:(NSString *)defaultName; - (NSDictionary *)dictionaryForKey:(NSString *)defaultName; - (float)floatForKey:(NSString *)defaultName; - (int)integerForKey:(NSString *)defaultName; - (id)objectForKey:(NSString *)defaultName; - (NSArray *)stringArrayForKey:(NSString *)defaultName; - (NSString *)stringForKey:(NSString *)defaultName; - (NSColor *)colorForKey:(NSString *)defaultName; - (void)removeObjectForKey:(NSString *)defaultName; - (void)setBool:(BOOL)value forKey:(NSString *)defaultName; - (void)setFloat:(float)value forKey:(NSString *)defaultName; - (void)setInteger:(int)value forKey:(NSString *)defaultName; - (void)setObject:(id)value forKey:(NSString *)defaultName; - (void)setColor:(NSColor *)value forKey:(NSString *)defaultName; - (BOOL)synchronize; @end
Do not try to use the additional methods on normal NSMutableDictionary objects; there's no implementation behind it.
At this time there are three classes that constitute the data structures which hold the ticker signs: AMTickerSign, AMImageTickerSign and AMTextTickerSign.
These are declared in the AMTickerService.framework.
This is an abstract base class. You will not instantiate instances of AMTickerSign but rather of AMImageTickerSign or AMTextTickerSign.
extern int AMEndlessLoopCount; typedef enum { AMScrollNone = 0, AMScrollHorizontal = 1, AMScrollVertical = 2 } AMScrollDirection; typedef enum { AMFadeInOutNone = 0, AMFadeInOutDefault = 1 } AMFadeInOutType;
typedef enum { AMTiggerActionTypeNone = 0, AMTiggerActionTypeURL = 1, AMTiggerActionTypeCustom = 99 } AMTiggerActionType;
Types used in the following methods.
@interface AMTickerSign : NSObject <NSCopying, NSCoding> { [... private instance variables ommited ...] } - (NSSize)size; - (void)setSize:(NSSize)newSize; - (void)drawAtPoint:(NSPoint)point;
Only for subclasses.
- (AMScrollDirection)scrollDirection; - (void)setScrollDirection:(AMScrollDirection)newScrollDirection;
It is recommended that you not set the scroll direction (i.e. leave it at AMScrollNone). That way the user's default will be used. If you think about specifying something else, remember that a change in scrolling direction will result in a wait time while the ticker is to be cleared.
- (AMFadeInOutType)fadeInOutType; - (void)setFadeInOutType:(AMFadeInOutType)newFadeInOutType;
Do not use.
- (BOOL)continuousScrolling; - (void)setContinuousScrolling:(BOOL)newContinuousScrolling;
Set to YES unless you really want your sign displayed on it's own. If set to NO, the server will wait for the scrolling area to be cleared before this sign is displayed.
- (int)loopCount; - (void)setLoopCount:(int)newLoopCount;
Tells the server how often this sign should be displayed before it is removed. Whenever a sign is scrolled out of the scrolling area, it's loop count get's decremented. If the loop count reaches zero, the sign will be disposed of. Otherwise it will be inserted at the end of the wait queue again.
- (AMTiggerActionType)actionType; - (void)setActionType:(AMTiggerActionType)newActionType; - (NSString *)actionString; - (void)setActionString:(NSString *)newActionString;
Starting with Tigger 1.2 clients may attach a string to each sign. The action type argument defines the action triggered when the respective sign is clicked by the user.
An action type of AMTiggerActionTypeURL will result in the action string being opened as a URL with whatever application is registered for that URL type.
A value of AMTiggerActionTypeCustom as action type will cause Tigger to send a performAction: message to the client. The argument will be the string set with setActionString:.
A loop count of AMEndlessLoopCount will cause the sign to stick in the queue until it is removed manually. See removeSign:
Concrete subclass of AMTickerSign that accepts NSImage objects as contents.
@interface AMImageTickerSign : AMTickerSign <NSCopying, NSCoding> { [... private instance variables ommited ...] } - (id)initWithImage:(NSImage *)image; - (NSImage *)image; - (void)setImage:(NSImage *)newImage; @end
Concrete subclass of AMTickerSign that accepts strings as contents. You may use either an NSString or an NSAttributedString to initialize an AMTextTickerSign.
Note that AMTextTickerSign is actually a subclass of AMImageTickerSign and will convert any string to an image first.
@interface AMTextTickerSign : AMImageTickerSign <NSCopying> { [... private instance variables ommited ...] } - (id)initWithAttributedString:(NSAttributedString *)aString; - (id)initWithString:(NSString *)aString; - (NSAttributedString *)text; - (void)setText:(NSAttributedString *)newText; @end
© 2004, Andreas Mayer