You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.11 10:38:10