Mac OS X Cocoa:applicationDidBecomeActive未触发问题求助
纯代码开发Mac OS X Cocoa应用时检测应用激活状态的问题
我正在纯代码开发一款Mac OS X Cocoa应用(因此并非依赖Nib文件配置的场景),需要检测应用何时成为主应用。
我通过以下代码创建应用:
@interface MilskoCocoa : NSObject { NSApplication *application; MilskoCocoaWindow *window; NSRect rect; MilskoCocoaView *view; MwLL parent; } + (MilskoCocoa *)newWithParent:(MwLL)parent x:(int)x y:(int)y width:(int)width height:(int)height; @end // ... @implementation MilskoCocoa + (MilskoCocoa *)newWithParent:(MwLL)parent x:(int)x y:(int)y width:(int)width height:(int)height handle:(MwLL)r { MilskoCocoa *c = [MilskoCocoa alloc]; [c retain]; c->application = [NSApplication sharedApplication]; c->rect = rectFlip(NSMakeRect(x, y, width, height)); if (parent == NULL) { c->window = [[MilskoCocoaWindow alloc] initWithContentRect:c->rect styleMask:(NSTitledWindowMask | NSTexturedBackgroundWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask) backing:NSBackingStoreBuffered defer:NO]; } else { double offset = 0; MilskoCocoaWindow *parentWindow = parent->cocoa.real->window; offset = [parentWindow frameRectForContentRect:[parentWindow frame]] .size.height - [parentWindow contentRectForFrameRect:[parentWindow frame]].size.height; c->rect.origin.x += [parentWindow frame].origin.x; c->rect.origin.y -= [parentWindow frame].origin.y - offset; c->rect.origin.y -= offset; c->window = [[MilskoCocoaWindow alloc] initWithContentRect:c->rect styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO]; } [c->window setDelegate:[[MilskoCocoaWindowDelegate alloc] initWithWin:c->window]]; [c->window makeKeyAndOrderFront:c->application]; [c->window retain]; if (parent != NULL) { MilskoCocoa *p = parent->cocoa.real; double offset = 0; offset = [p->window frameRectForContentRect:[p->window frame]].size.height - [p->window contentRectForFrameRect:[p->window frame]].size.height; [p->window addChildWindow:c->window ordered:NSWindowAbove]; [c->window setHasShadow:MwFALSE]; [c->window setParentWindow:p->window]; c->rect.origin.x += [p->window frame].origin.x; c->rect.origin.y -= [p->window frame].origin.y - offset; c->rect.origin.y -= offset; } else { [c->application setActivationPolicy:NSApplicationActivationPolicyRegular]; [c->application activateIgnoringOtherApps:true]; [c->window makeFirstResponder:c->view]; [c->window makeKeyAndOrderFront:nil]; } [c->application setDelegate:[[MilskoCocoaApplicationDelegate alloc] initWithAppl:c->application]]; [c->application retain]; c->view = [[MilskoCocoaView alloc] initWithFrame:c->rect]; [c->view retain]; [c->window setContentView:c->view]; c->parent = parent; [c->application finishLaunching]; return c; }
如代码所示,我还设置了如下应用代理:
@implementation MilskoCocoaApplicationDelegate - (MilskoCocoaApplicationDelegate *)initWithAppl:(NSApplication *)_appl { self->appl = _appl; return self; } - (void)applicationDidBecomeActive:(NSNotification *)notification { printf("test\n"); } @end
我理解当应用成为主窗口(点击窗口内非标题栏区域时),applicationDidBecomeActive方法应被调用,但实际并未触发,日志从未输出。是否有其他替代方法?
需要说明的是,由于正在移植的库的设计限制,我未使用系统默认的事件循环,而是通过手动调用nextEventMatchingMask、根据NSEvent类型执行代码并调用[NSWindow sendEvent:{event}]实现自定义主循环,这曾导致其他等效回调无法触发。
编辑:调用[c->application run]时应用可激活,以下是自定义事件循环代码:
/* Check whether there are pending events. Yes, this is hacky and unreliable, but the rest of the library REALLY doesn't like us just always returning 1 from this function so we have to do Something. */ - (int)pending { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; MwBool isPending = MwFALSE; if (_forceRender) { _forceRender = MwFALSE; [pool release]; return 1; } self->lastEvent = [self->window nextEventMatchingMask:NSAnyEventMask untilDate:[NSDate distantPast] inMode:NSDefaultRunLoopMode dequeue:YES]; isPending = self->lastEvent != NULL; [pool release]; return isPending; }; /* Actually process the event assuming there are any pending */ - (void)getNextEvent { [self eventProcess:self->lastEvent]; while (true) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; NSEvent *ev = [self->window nextEventMatchingMask:NSAnyEventMask untilDate:[NSDate distantPast] inMode:NSDefaultRunLoopMode dequeue:YES]; if (!ev) { [pool release]; break; } [self eventProcess:ev]; [pool release]; } [self sendClipboardEvent]; [self->application updateWindows]; [self->application runModalForWindow:self->window]; }; - (void)eventProcess:(NSEvent *)ev { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; NSWindow *win = [ev window]; MwLL h; MwBool doSendEvent = MwTRUE; if (!win) { [pool release]; return; } switch ([ev type]) { /* snip */ } if (doSendEvent) { [win sendEvent:ev]; } [pool release]; }
内容的提问来源于stack exchange,提问作者ioi-xd
相关产品推荐
相关产品推荐

