mirror of https://github.com/BOINC/boinc.git
252 lines
6.9 KiB
Objective-C
252 lines
6.9 KiB
Objective-C
/* SystemMenu.m */
|
|
|
|
// Berkeley Open Infrastructure for Network Computing
|
|
// http://boinc.berkeley.edu
|
|
// Copyright (C) 2005 University of California
|
|
//
|
|
// This is free software; you can redistribute it and/or
|
|
// modify it under the terms of the GNU Lesser General Public
|
|
// License as published by the Free Software Foundation;
|
|
// either version 2.1 of the License, or (at your option) any later version.
|
|
//
|
|
// This software is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
// See the GNU Lesser General Public License for more details.
|
|
//
|
|
// To view the GNU Lesser General Public License visit
|
|
// http://www.gnu.org/copyleft/lesser.html
|
|
// or write to the Free Software Foundation, Inc.,
|
|
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
/* Cocoa routines for BOINC Manager OS X System Icon Menu.
|
|
Written by Charlie Fenton for UC Berkeley Space Sciences Laboratory 2005
|
|
|
|
Adapted from Apple Developer Tech Support sample code, including:
|
|
SpellingChecker-CarbonCocoa
|
|
MenuMadness
|
|
*/
|
|
|
|
#include <Carbon/Carbon.h>
|
|
#include <Cocoa/Cocoa.h>
|
|
|
|
#define _DEBUG 0
|
|
|
|
@interface SystemMenu : NSObject {
|
|
}
|
|
- (void)BuildSysMenu:(MenuRef)menuToCopy;
|
|
@end
|
|
|
|
|
|
|
|
|
|
SystemMenu *gSystemMenu = NULL;
|
|
NSStatusItem *gStatusItem = NULL;
|
|
|
|
void SetSystemMenuIcon(PicHandle theIcon);
|
|
static OSStatus LoadFrameworkBundle(CFStringRef framework, CFBundleRef *bundlePtr);
|
|
|
|
/*
|
|
Needed to make sure the Cocoa framework has a chance to initialize things in a Carbon app.
|
|
|
|
NSApplicationLoad() is an API introduced in 10.2 which is a startup function to call when
|
|
running Cocoa code from a Carbon application.
|
|
|
|
Because NSApplicationLoad() is not available pre 10.2, we load the function pointer through
|
|
CFBundle. If we encounter an error during this process, (i.e. it's not there), we fall back
|
|
to calling NSApplication *NSApp=[NSApplication sharedApplication];
|
|
The fallback method does have bugs with regard to window activation seen when hiding and showing
|
|
the main application.
|
|
*/
|
|
typedef BOOL (*NSApplicationLoadFuncPtr)( void );
|
|
|
|
void InitializeCocoa() {
|
|
CFBundleRef appKitBundleRef;
|
|
NSApplicationLoadFuncPtr myNSApplicationLoad;
|
|
OSStatus err;
|
|
|
|
// Load the "AppKit.framework" bundl to locate NSApplicationLoad
|
|
err = LoadFrameworkBundle( CFSTR("AppKit.framework"), &appKitBundleRef );
|
|
if (err != noErr) goto FallbackMethod;
|
|
|
|
// Manually load the Mach-O function pointers for the routines we will be using.
|
|
myNSApplicationLoad = (NSApplicationLoadFuncPtr) CFBundleGetFunctionPointerForName( appKitBundleRef, CFSTR("NSApplicationLoad") );
|
|
if ( myNSApplicationLoad == NULL ) goto FallbackMethod;
|
|
|
|
(void) myNSApplicationLoad();
|
|
return;
|
|
|
|
FallbackMethod:
|
|
{ /* NSApplication *NSApp = */ [NSApplication sharedApplication]; }
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
*/
|
|
void SetUpSystemMenu(MenuRef menuToCopy, PicHandle theIcon) {
|
|
NSAutoreleasePool* pool;
|
|
|
|
if (gSystemMenu == NULL)
|
|
InitializeCocoa();
|
|
|
|
pool = [[NSAutoreleasePool alloc] init];
|
|
|
|
if (gSystemMenu)
|
|
[gSystemMenu release];
|
|
|
|
gSystemMenu = [[SystemMenu alloc] init];
|
|
[gSystemMenu retain];
|
|
|
|
[gSystemMenu BuildSysMenu:menuToCopy];
|
|
// [gStatusItem setImage: [NSImage imageNamed:@"Icon0"]];
|
|
SetSystemMenuIcon(theIcon);
|
|
|
|
[pool release];
|
|
}
|
|
|
|
|
|
@implementation SystemMenu
|
|
|
|
- (void)BuildSysMenu:(MenuRef)menuToCopy {
|
|
NSStatusBar *bar;
|
|
NSMenuItem *newItem;
|
|
NSMenu *sysMenu;
|
|
int i, n;
|
|
Str255 s;
|
|
CFStringRef CFText;
|
|
|
|
// Add the submenu
|
|
newItem = [[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:@"BOINC!" action:NULL keyEquivalent:@""];
|
|
sysMenu = [[NSMenu allocWithZone:[NSMenu menuZone]] initWithTitle:@"BOINC!"];
|
|
[newItem setSubmenu:sysMenu];
|
|
|
|
if (gStatusItem == NULL) {
|
|
bar = [NSStatusBar systemStatusBar];
|
|
|
|
gStatusItem = [bar statusItemWithLength:NSSquareStatusItemLength];
|
|
[gStatusItem retain];
|
|
}
|
|
|
|
[gStatusItem setTitle: NSLocalizedString(@"",@"")];
|
|
[gStatusItem setHighlightMode:YES];
|
|
[gStatusItem setMenu:sysMenu];
|
|
|
|
[sysMenu release];
|
|
[newItem release];
|
|
|
|
n = CountMenuItems(menuToCopy);
|
|
// Add the items
|
|
for (i=1; i<=n; i++)
|
|
{
|
|
GetMenuItemText(menuToCopy, i, s);
|
|
if (PLstrcmp(s, "\p-") == 0)
|
|
{
|
|
[sysMenu addItem:[NSMenuItem separatorItem]];
|
|
continue;
|
|
}
|
|
|
|
CFText = CFStringCreateWithPascalString(kCFAllocatorDefault, s, kCFStringEncodingMacRoman);
|
|
if (CFText != NULL)
|
|
{
|
|
newItem = [[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:(NSString*)CFText action:NULL keyEquivalent:@""];
|
|
[newItem setTarget:self];
|
|
[sysMenu addItem:newItem];
|
|
if( IsMenuItemEnabled(menuToCopy, i) )
|
|
[newItem setEnabled:YES];
|
|
else
|
|
[newItem setEnabled:NO];
|
|
|
|
[newItem release];
|
|
CFRelease(CFText);
|
|
}
|
|
}
|
|
|
|
[sysMenu setAutoenablesItems:NO];
|
|
return;
|
|
}
|
|
|
|
|
|
void SetSystemMenuIcon(PicHandle theIcon)
|
|
{
|
|
if (theIcon == NULL)
|
|
{
|
|
// A NULL icon handle is a request to remove the status item from the menu bar
|
|
[[gStatusItem statusBar] removeStatusItem:gStatusItem];
|
|
[gStatusItem release];
|
|
[gSystemMenu release];
|
|
gStatusItem = NULL;
|
|
gSystemMenu = NULL;
|
|
|
|
return;
|
|
}
|
|
|
|
unsigned theLength = GetHandleSize((Handle)theIcon);
|
|
NSData* theData = [[NSData alloc] initWithBytes:*theIcon length:theLength];
|
|
NSImage* theImage = [[NSImage alloc] initWithData:theData];
|
|
|
|
[gStatusItem setImage:theImage];
|
|
|
|
[theImage release];
|
|
[theData release];
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
static OSStatus LoadFrameworkBundle(CFStringRef framework, CFBundleRef *bundlePtr)
|
|
{
|
|
OSStatus err;
|
|
FSRef frameworksFolderRef;
|
|
CFURLRef baseURL;
|
|
CFURLRef bundleURL;
|
|
|
|
if ( bundlePtr == nil ) return( -1 );
|
|
|
|
*bundlePtr = nil;
|
|
|
|
baseURL = nil;
|
|
bundleURL = nil;
|
|
|
|
err = FSFindFolder(kOnAppropriateDisk, kFrameworksFolderType, true, &frameworksFolderRef);
|
|
if (err == noErr) {
|
|
baseURL = CFURLCreateFromFSRef(kCFAllocatorSystemDefault, &frameworksFolderRef);
|
|
if (baseURL == nil) {
|
|
err = coreFoundationUnknownErr;
|
|
}
|
|
}
|
|
if (err == noErr) {
|
|
bundleURL = CFURLCreateCopyAppendingPathComponent(kCFAllocatorSystemDefault, baseURL, framework, false);
|
|
if (bundleURL == nil) {
|
|
err = coreFoundationUnknownErr;
|
|
}
|
|
}
|
|
if (err == noErr) {
|
|
*bundlePtr = CFBundleCreate(kCFAllocatorSystemDefault, bundleURL);
|
|
if (*bundlePtr == nil) {
|
|
err = coreFoundationUnknownErr;
|
|
}
|
|
}
|
|
if (err == noErr) {
|
|
if ( ! CFBundleLoadExecutable( *bundlePtr ) ) {
|
|
err = coreFoundationUnknownErr;
|
|
}
|
|
}
|
|
|
|
// Clean up.
|
|
if (err != noErr && *bundlePtr != nil) {
|
|
CFRelease(*bundlePtr);
|
|
*bundlePtr = nil;
|
|
}
|
|
if (bundleURL != nil) {
|
|
CFRelease(bundleURL);
|
|
}
|
|
if (baseURL != nil) {
|
|
CFRelease(baseURL);
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
@end
|