macOS version in obj-c runtime
This commit is contained in:
156
tray.h
156
tray.h
@@ -90,92 +90,118 @@ static void tray_exit() { loop_result = -1; }
|
|||||||
|
|
||||||
#elif defined(TRAY_APPKIT)
|
#elif defined(TRAY_APPKIT)
|
||||||
|
|
||||||
#import <Cocoa/Cocoa.h>
|
#include <objc/objc-runtime.h>
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
static NSAutoreleasePool *pool;
|
static id app;
|
||||||
static NSStatusBar *statusBar;
|
static id pool;
|
||||||
|
static id statusBar;
|
||||||
static id statusItem;
|
static id statusItem;
|
||||||
static id statusBarButton;
|
static id statusBarButton;
|
||||||
|
|
||||||
@interface Tray : NSObject <NSApplicationDelegate>
|
static id _tray_menu(struct tray_menu *m) {
|
||||||
- (void)menuCallback:(id)sender;
|
id menu = objc_msgSend((id)objc_getClass("NSMenu"), sel_registerName("new"));
|
||||||
@end
|
objc_msgSend(menu, sel_registerName("autorelease"));
|
||||||
@implementation Tray
|
objc_msgSend(menu, sel_registerName("setAutoenablesItems:"), false);
|
||||||
- (void)menuCallback:(id)sender {
|
|
||||||
struct tray_menu *m =
|
|
||||||
(struct tray_menu *)[[sender representedObject] pointerValue];
|
|
||||||
if (m != NULL && m->cb != NULL) {
|
|
||||||
m->cb(m);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@end
|
|
||||||
|
|
||||||
static NSMenu *_tray_menu(struct tray_menu *m) {
|
for (; m != NULL && m->text != NULL; m++) {
|
||||||
NSMenu *menu = [NSMenu new];
|
if (strcmp(m->text, "-") == 0) {
|
||||||
[menu autorelease];
|
objc_msgSend(menu, sel_registerName("addItem:"),
|
||||||
[menu setAutoenablesItems:NO];
|
objc_msgSend((id)objc_getClass("NSMenuItem"), sel_registerName("separatorItem")));
|
||||||
for (; m != NULL && m->text != NULL; m++) {
|
} else {
|
||||||
if (strcmp(m->text, "-") == 0) {
|
id menuItem = objc_msgSend((id)objc_getClass("NSMenuItem"), sel_registerName("alloc"));
|
||||||
[menu addItem:[NSMenuItem separatorItem]];
|
objc_msgSend(menuItem, sel_registerName("autorelease"));
|
||||||
} else {
|
objc_msgSend(menuItem, sel_registerName("initWithTitle:action:keyEquivalent:"),
|
||||||
NSMenuItem *menuItem = [NSMenuItem alloc];
|
objc_msgSend((id)objc_getClass("NSString"), sel_registerName("stringWithUTF8String:"), m->text),
|
||||||
[menuItem autorelease];
|
sel_registerName("menuCallback:"),
|
||||||
[menuItem initWithTitle:[NSString stringWithUTF8String:m->text]
|
objc_msgSend((id)objc_getClass("NSString"), sel_registerName("stringWithUTF8String:"), ""));
|
||||||
action:@selector(menuCallback:)
|
|
||||||
keyEquivalent:@""];
|
objc_msgSend(menuItem, sel_registerName("setEnabled:"), (m->disabled ? false : true));
|
||||||
[menuItem setEnabled:(m->disabled ? NO : YES)];
|
objc_msgSend(menuItem, sel_registerName("setState:"), (m->checked ? 1 : 0));
|
||||||
[menuItem setState:(m->checked ? NSOnState : NSOffState)];
|
objc_msgSend(menuItem, sel_registerName("setRepresentedObject:"),
|
||||||
[menuItem setRepresentedObject:[NSValue valueWithPointer:m]];
|
objc_msgSend((id)objc_getClass("NSValue"), sel_registerName("valueWithPointer:"), m));
|
||||||
|
|
||||||
[menu addItem:menuItem];
|
objc_msgSend(menu, sel_registerName("addItem:"), menuItem);
|
||||||
|
|
||||||
if (m->submenu != NULL) {
|
if (m->submenu != NULL) {
|
||||||
[menu setSubmenu:_tray_menu(m->submenu) forItem:menuItem];
|
objc_msgSend(menu, sel_registerName("setSubmenu:forItem:"), _tray_menu(m->submenu), menuItem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return menu;
|
return menu;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void menu_callback(id self, SEL cmd, id sender) {
|
||||||
|
struct tray_menu *m =
|
||||||
|
(struct tray_menu *)objc_msgSend(objc_msgSend(sender, sel_registerName("representedObject")),
|
||||||
|
sel_registerName("pointerValue"));
|
||||||
|
|
||||||
|
if (m != NULL && m->cb != NULL) {
|
||||||
|
m->cb(m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int tray_init(struct tray *tray) {
|
static int tray_init(struct tray *tray) {
|
||||||
pool = [NSAutoreleasePool new];
|
pool = objc_msgSend((id)objc_getClass("NSAutoreleasePool"),
|
||||||
[NSApplication sharedApplication];
|
sel_registerName("new"));
|
||||||
|
|
||||||
Tray *trayDelegate = [Tray new];
|
objc_msgSend((id)objc_getClass("NSApplication"),
|
||||||
[NSApp setDelegate:trayDelegate];
|
sel_registerName("sharedApplication"));
|
||||||
|
|
||||||
statusBar = [NSStatusBar systemStatusBar];
|
Class trayDelegateClass = objc_allocateClassPair(objc_getClass("NSObject"), "Tray", 0);
|
||||||
statusItem = [statusBar statusItemWithLength:NSVariableStatusItemLength];
|
class_addProtocol(trayDelegateClass, objc_getProtocol("NSApplicationDelegate"));
|
||||||
[statusItem retain];
|
class_addMethod(trayDelegateClass, sel_registerName("menuCallback:"), (IMP)menu_callback, "v@:@");
|
||||||
[statusItem setHighlightMode:YES];
|
objc_registerClassPair(trayDelegateClass);
|
||||||
statusBarButton = [statusItem button];
|
|
||||||
|
id trayDelegate = objc_msgSend((id)trayDelegateClass,
|
||||||
tray_update(tray);
|
sel_registerName("new"));
|
||||||
[NSApp activateIgnoringOtherApps:YES];
|
|
||||||
return 0;
|
app = objc_msgSend((id)objc_getClass("NSApplication"),
|
||||||
|
sel_registerName("sharedApplication"));
|
||||||
|
|
||||||
|
objc_msgSend(app, sel_registerName("setDelegate:"), trayDelegate);
|
||||||
|
|
||||||
|
statusBar = objc_msgSend((id)objc_getClass("NSStatusBar"),
|
||||||
|
sel_registerName("systemStatusBar"));
|
||||||
|
|
||||||
|
statusItem = objc_msgSend(statusBar, sel_registerName("statusItemWithLength:"), -1.0);
|
||||||
|
|
||||||
|
objc_msgSend(statusItem, sel_registerName("retain"));
|
||||||
|
objc_msgSend(statusItem, sel_registerName("setHighlightMode:"), true);
|
||||||
|
statusBarButton = objc_msgSend(statusItem, sel_registerName("button"));
|
||||||
|
tray_update(tray);
|
||||||
|
objc_msgSend(app, sel_registerName("activateIgnoringOtherApps:"), true);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int tray_loop(int blocking) {
|
static int tray_loop(int blocking) {
|
||||||
NSEvent *event;
|
id until = (blocking ?
|
||||||
NSDate *until = (blocking ? [NSDate distantFuture] : [NSDate distantPast]);
|
objc_msgSend((id)objc_getClass("NSDate"), sel_registerName("distantFuture")) :
|
||||||
event = [NSApp nextEventMatchingMask:NSAnyEventMask
|
objc_msgSend((id)objc_getClass("NSDate"), sel_registerName("distantPast")));
|
||||||
untilDate:until
|
|
||||||
inMode:NSDefaultRunLoopMode
|
id event = objc_msgSend(app, sel_registerName("nextEventMatchingMask:untilDate:inMode:dequeue:"),
|
||||||
dequeue:YES];
|
ULONG_MAX,
|
||||||
if (event) {
|
until,
|
||||||
[NSApp sendEvent:event];
|
objc_msgSend((id)objc_getClass("NSString"),
|
||||||
}
|
sel_registerName("stringWithUTF8String:"),
|
||||||
return 0;
|
"kCFRunLoopDefaultMode"),
|
||||||
|
true);
|
||||||
|
if (event) {
|
||||||
|
objc_msgSend(app, sel_registerName("sendEvent:"), event);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tray_update(struct tray *tray) {
|
static void tray_update(struct tray *tray) {
|
||||||
[statusBarButton
|
objc_msgSend(statusBarButton, sel_registerName("setImage:"),
|
||||||
setImage:[NSImage imageNamed:[NSString stringWithUTF8String:tray->icon]]];
|
objc_msgSend((id)objc_getClass("NSImage"), sel_registerName("imageNamed:"),
|
||||||
|
objc_msgSend((id)objc_getClass("NSString"), sel_registerName("stringWithUTF8String:"), tray->icon)));
|
||||||
|
|
||||||
[statusItem setMenu:_tray_menu(tray->menu)];
|
objc_msgSend(statusItem, sel_registerName("setMenu:"), _tray_menu(tray->menu));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tray_exit() { [NSApp terminate:NSApp]; }
|
static void tray_exit() { objc_msgSend(app, sel_registerName("terminate:"), app); }
|
||||||
|
|
||||||
#elif defined(TRAY_WINAPI)
|
#elif defined(TRAY_WINAPI)
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
|||||||
Reference in New Issue
Block a user