Skip to content

Instantly share code, notes, and snippets.

@Airr
Created June 1, 2018 21:56
Show Gist options
  • Save Airr/07bc19f240736032080e0c8376a1385b to your computer and use it in GitHub Desktop.
Save Airr/07bc19f240736032080e0c8376a1385b to your computer and use it in GitHub Desktop.
"Menulet Demo": A Single Source CONSOLE OSX Objective C StatusBar App (NO IB/NIB/XIB/XCODE)
// "Menulet Demo": A Single Source CONSOLE OSX Objective C StatusBar App (NO IB/NIB/XIB)
// Copyright (c) 2018 Armando Rivera
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
// REQUIRED IMPORTS
#import <Cocoa/Cocoa.h>
#import <mach-o/getsect.h>
#import <mach-o/ldsyms.h>
// TYPEDEF FOR FUNCTION CALLBACKS
typedef void(*ACTION)(id);
// SUBCLASSED NSMENUITEM ENABLING C-STYLE CALLBACKS
@interface CocoaMenuItem: NSMenuItem{
ACTION menuAction;
}
@property ACTION menuAction;
- (void) click:(id)sender;
@end
@implementation CocoaMenuItem
@synthesize menuAction;
- (void) click:(id)sender {
menuAction(sender);
}
@end
// FUNCTION DECLARATIONS
NSData *getResource(NSString *sectionName, NSString *itemName);
void Cocoa_Init();
void Cocoa_Run(id mainWin);
void menuCallback(CocoaMenuItem *widget);
CocoaMenuItem *createMenuItem(id parent, NSString *title, ACTION func);
NSMenu *createMenu();
// FUNCTION TO RETRIEVE EMBEDDED PNG FILE
NSData *getResource(NSString *sectionName, NSString *itemName) {
unsigned long size;
void *ptr = getsectiondata(&_mh_execute_header, sectionName.UTF8String, itemName.UTF8String, &size);
NSData *resourceData = [NSData dataWithBytesNoCopy:ptr length:size freeWhenDone:NO];
return resourceData;
}
// FUNCTION TO INITIALIZE COCOA SUBSYSTEM
void Cocoa_Init() {
[NSApplication sharedApplication];
[NSApp setActivationPolicy:NSApplicationActivationPolicyAccessory];
}
// FUNCTION THAT PASSES CONTROL TO COCOA SUBSYSTEM
void Cocoa_Run(id mainWin) {
[NSApp setDelegate:mainWin];
[NSApp run];
}
// FUNCTION TO CREATE STATUSBAR ITEM, WITH EMBEDDED ICON EXTRACTED FROM THE BINARY
id createStatusBarItem() {
NSStatusItem *self;
NSStatusBar *statusBar = [NSStatusBar systemStatusBar];
self = [statusBar statusItemWithLength:NSSquareStatusItemLength];
NSImage *icon = [[NSImage alloc] initWithData: getResource(@"__PNG",@"__icon")];
icon.template = YES;
self.button.image = icon;
return self;
}
// FUNCTION TO CREATE MENU ITEMS/ENTRIES
CocoaMenuItem *createMenuItem(id parent, NSString *title, ACTION func) {
CocoaMenuItem *self = [CocoaMenuItem new];
self.title = title;
self.target = self;
if (func)
{
self.menuAction = func;
self.action = @selector(click:);
}
[parent addItem: self];
return self;
}
// FUNCTION THAT RETURNS A MENU OBJECT
NSMenu *createMenu() {
return NSMenu.new;
}
// FUNCTION TO ADD A SEPARATOR TO A MENU
void addSeparator(id parent) {
[parent addItem: [NSMenuItem separatorItem]];
}
// CALLBACK USED BY MENU CLICKS
void menuCallback(CocoaMenuItem *widget) {
switch (widget.tag) {
case 1001:
[NSApp terminate:nil];
break;
default:
printf("%s\n",widget.title.UTF8String);
break;
}
}
// MAIN PROGRAM BEGINS HERE
int main(int argc, char const *argv[]) {
@autoreleasepool {
NSStatusItem *statusItem;
NSMenu *menu;
CocoaMenuItem *item1,*item2,*item3,*quitItem;
// Initialize GUI
Cocoa_Init();
// Create Menu
menu = createMenu();
// Create StatusBar Widget
statusItem = createStatusBarItem();
// Create Several Menu Items
item1 = createMenuItem(menu, @"Item 1",menuCallback);
item2 = createMenuItem(menu, @"Item 2",menuCallback);
item3 = createMenuItem(menu, @"Item 3",menuCallback);
addSeparator(menu);
quitItem = createMenuItem(menu, @"Quit",menuCallback);
// We can set numeric Identifiers on Menu Items
quitItem.tag = 1001;
// Add the Menu to the StatusItem
statusItem.menu = menu;
// Run the GUI!!!
Cocoa_Run(menu);
}
return 0;
}
/* Makefile MAKE SURE YOU CHANGE THE PATH IN THE 'RESOURCE' VARIABLE TO A VALID PNG FILE!!!
CC := gcc
LDFLAGS := -fobjc-arc -framework Cocoa
EMBED := -sectcreate __PNG __icon
RESOURCE := img/icon.png
SOURCE := demo.m
MODULES :=
PROGRAM := demo
all:
@echo Building demo....
@${CC} ${LDFLAGS} ${EMBED} ${RESOURCE} ${SOURCE} ${MODULES} -o ${PROGRAM}
@echo Build Complete.
clean:
@echo Removing Demo...
@rm -f ${PROGRAM}
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment