Archive for category Cocoa

Release of Shift It

Hi everyone,

I have been working on this app for a while now. Shift it is an application that will allow you to manage your windows easily. The application can shift your focused window to a particular corner of the screen or fill the whole screen. All this is done using hotkeys. The application is open source,so you can download the source and have a go a it. The whole application was made using the previous posts. If you ever get stuck, please refer to the previous posts or leave comment here.

Please check out Shift It and Shift it – Hot Keys for more details.


100% Clean
As always, any suggestions are welcome.

Cheers,
Aravind

Tags: , , ,

Opening System Preferences Pane


Hi All,
In this post, we are going to look at how to programatically open a Preference Pane in the Mac OS X. It is really simple and there are no special requirements to it. In the previous post, we saw how to retrieve the focused window using the Accessibility APIs. In this post, we are going to add on to it by opening the Universal Access Preference pane if the user does not have assistive devices enabled.

Since all the preferences are stored in file with a .prefPane extension, all we basically have to do it is

    //opening the Universal Access Preference Pane.
    [[NSWorkspace sharedWorkspace] openFile:@"/System/Library/PreferencePanes/UniversalAccessPref.prefPane"];

The list of Preference Pane are the .prefPane files in the folder /System/Library/PreferencePanes/. Adding on to the previous post, we would open the Preferences if the Accessibility API is not enabled.

    if(!AXAPIEnabled()){
        [[NSWorkspace sharedWorkspace] openFile:@"/System/Library/PreferencePanes/UniversalAccessPref.prefPane"];
        [NSApp terminate:self];
    }
    AXUIElementRef _systemWideElement;
    AXUIElementRef _focusedApp;
    CFTypeRef _focusedWindow;
    _systemWideElement = AXUIElementCreateSystemWide();
    AXUIElementCopyAttributeValue(_systemWideElement,
                         (CFStringRef)kAXFocusedApplicationAttribute,(CFTypeRef*)&_focusedApp);
    AXUIElementCopyAttributeValue((AXUIElementRef)_focusedApp,
                         (CFStringRef)NSAccessibilityFocusedWindowAttribute,(CFTypeRef*)&_focusedWindow)

Tags: , ,

Retrieving the window that has focus


In this post, we are going to look at how to retrieve the window that has focus, that does not necessarily belong to your app. For this to be possible, you MUST have enabled access for assistive devices in the “Universal Access” Preference Pane.

Ensure the "Enable access for assistive devices" is checked

Firstly, we need to check if the preference has been set. To do this we have to use one of the Accessibility APIs.

    Boolean AXAPIEnabled (void);

This method returns true if the access for assistive devices have been enabled. False, otherwise. If access has not been enabled, we will inform the user to enable it and quit the app(for now. Next post we will look at how to open the preference pane).

Secondly, we need to create a system wide element that can listen to focused accessibility object regardless of which application is currently active.

    AXUIElementRef AXUIElementCreateSystemWide (void);

We have to use this element to retrieve information about the focused application and then focused window. We cannot get the focused window directly. Therefore, we have to first get the application that is in focus and the get the window that is in focus. Note: We can only get copies of the above mentioned information. To do this, we have to use the following method.

    AXError AXUIElementCopyAttributeValue (
        AXUIElementRef element,
        CFStringRef attribute,
        CFTypeRef *value);

The allowed attributes can be found here. ‘Value’ refers to the value associated with the specified attribute. Thats it folks. Now we can look at the actual implementation.

Implementation

    AXUIElementRef _systemWideElement;
    if(!AXAPIEnabled()){
        //exit
    }
    AXUIElementRef _focusedApp;
    CFTypeRef _focusedWindow;
    _systemWideElement = AXUIElementCreateSystemWide();
    AXUIElementCopyAttributeValue(_systemWideElement,
                         (CFStringRef)kAXFocusedApplicationAttribute,(CFTypeRef*)&_focusedApp);
    AXUIElementCopyAttributeValue((AXUIElementRef)_focusedApp,
                         (CFStringRef)NSAccessibilityFocusedWindowAttribute,(CFTypeRef*)&_focusedWindow)

That is all for now! Good luck. Comments are welcome.

Tags: , , , , , , ,

Creating a Status Bar Application


This tutorial assumes you have a basic knowledge of Objective-C.  In this tutorial, we will walk-through on how to create a status bar only application for the Mac OS X. The final project can be downloaded from here.

What is a Menu Bar Extra?

They are extra menus that are visible at the right side of the menu bar. Some of the in-built menu extras are the battery indicator, time indicator. Menu bar extras are typically used to display application/system status information. Two things to note about the Menu bar extras are that

  • If there are too many menu bar extras, the OS will remove some of them to avoid crowding and to provide space for application menus.
  • The menu can also be disabled by the user.

Some websites call this kind of application a menulet application or a status bar application.

Implementation

To start off, we create a new Project in Xcode.

Open Xcode. File->New Project. Choose the “Cocoa Application” and click “Choose”. Next, Xcode should ask you to give a name for the project. Pick a name and directory for the project. In this example, the project name will be “StatusMenuApp”. Once you have chosen a project name and location, click “Save”.

Xcode should have created a new project with some default files. The two folders “Classes” and “Resources” are the most important folders for this walk-through. You can ignore the remaining folders for this example.

First, we will add an NSMenu outlet in the In the StatusMenuAppAppDelegate.h to which the menus can be referenced to. Also we will add a NSStatusItem that will eventually become the status bar menu item.

@interface StatusMenuAppAppDelegate : NSObject  {
    NSWindow *window;
    IBOutlet NSMenu *statusMenu;
    NSStatusItem * statusItem;
}
@property (assign) IBOutlet NSWindow *window;

@end

List of 'Outlets' available in the class

Final view of nib file

We will now create the MenuItems that will be available in the application. To do this, we open the MainMenu.xib in the Interface Builder. For this example, we will not touch the existing Menu in nib. Drag and drop another “Menu” object from the Library into the Document window. Give each of the MenuItem a unique title. Now we have to link the Menu object to the statusMenu outlet. To do this, CTRL+click on the StatusMenuAppDelegate object and drag and release the pointer on the Menu object. This should open up a panel titled “Outlets”. This panel will show all the Outlets available in the StatusMenuAppDelegate class. In our example, there is only one outlet. Click on the ’statusMenu’ to link the Menu object to statusMenu. Finally, delete the Window object. Save the nib file and close Interface Builder.

Now we move on to actually creating the Status Bar Menu. In the “StatusMenuAppDelegate.m”, we override the function awakeFromNib. awakeFromNibmessage is sent to every object that is loaded from a Nib(.nib or .xib) file. Firstly, we will create the NSStatusItem. To do so, we have to call

- (NSStatusItem *)statusItemWithLength:(CGFloat)length

The parameter length can take the following two values:

  1. NSVariableStatusItemLength -Makes the status item length dynamic, adjusting to the width of its contents.
  2. NSSquareStatusItemLength – Sets the status item length to the status bar thickness.

For this example, we will use the NSVariableStatusItemLength.

statusItem = [[[NSStatusBar systemStatusBar] statusItemWithLength:NSVariableStatusItemLength] retain]; 

Secondly, we have to add the statusMenu to the statusItem. To do so, we all the following code:

[statusItem setMenu:statusMenu];

Thirdly, we give a title for the statusItem. This will be seen in the Menu Extras.

[statusItem setTitle:@"Status"];

If you would like to see an image instead of text, you can use the following methods:

- (void)setImage:(NSImage *)image
-(void)setAlternateImage:(NSImage *)image

Lastly, we want to highlight the menu when the user clicks on it. So we use the following code.

[statusItem setHighlightMode:YES];

By default, the highlight mode will be set to NO.

The StatusMenuAppDelegate.m file should look like this now.

#import "StatusMenuAppDelegate.h"

@implementation StatusMenuAppDelegate

@synthesize window;

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
 // Insert code here to initialize your application
}

-(void)awakeFromNib{
 statusItem = [[[NSStatusBar systemStatusBar] statusItemWithLength:NSVariableStatusItemLength] retain];
 [statusItem setMenu:statusMenu];
 [statusItem setTitle:@"Status"];
 [statusItem setHighlightMode:YES];
}
@end

Since we want the app to only appear on the status menu, the last step is the most important one.We need to modify the StatusMenu-Info.plist file. Double click to open this file. Add a new property with key “Application is agent (UIElement)” and value as TRUE(i.e. check the box). Your .plist should look like this.

Final view of pList

Final output of the program should look like this:

Tags: , , , ,