【问题标题】:Making External App Float On Top Of OS X Application使外部应用程序浮动在 OS X 应用程序之上
【发布时间】:2016-11-23 21:41:30
【问题描述】:

我正在尝试创建一个 OS X 应用程序,它允许外部应用程序(即 textEdit)浮动在正在运行的应用程序之上而不保持焦点,但永远不会消失。基本上我想要做的是模仿 ForceQuit 应用程序(按 option-command-esc 来查看它),它总是在顶部,但并不总是有焦点。

我现在正在做的事情是这样的:

创建一个 NSTimer 以将其置于顶部:

_timer = [NSTimer scheduleTimerWithTimeInterval:0.1 target:self selector:@selector(keepTextEditOnTop) userInfo:nil repeats:YES];

...

将 textEdit 置于最前面:

- (void)keepTextEditOnTop {
    AXUIElementRef appRef = AXUIElementCreateApplication(_textEditProcessID);
    AXUIElementSetAttributeValue(appRef, kAXFrontmostAttribute, kCFBooleanTrue);
}

如果您单击它,textEdit 窗口将停留在顶部(使其失去焦点)。但是有两个问题。 1.) 它会短暂闪烁,让它回到顶部 2.) 它基本上始终保持焦点,因此您无法与底层应用程序交互。

从appRef中,可以得到窗口:

CFArrayRef windowList;
AXUIElementCopyAttributeValue(appRef, kAXWindowsAttribute, (CFTypeRef *)&windowList);

AXUIElementRef windowRef = (AXUIElementRef) CFArrayGetValueAtIndex(windowList, 0);

但我认为不可能将其转换为 NSWindow。如果我能做到这一点,我想我可以让它成为主窗口的子窗口,或者只是一个浮动窗口。

关于如何做到这一点的任何想法?

编辑 - 添加来自 @TheDarkKnight 的建议

我正在尝试这个:

- (void)testing{

    CFArrayRef windowList = CGWindowListCopyWindowInfo(kCGWindowListOptionOnScreenOnly, kCGNullWindowID);
    for (NSMutableDictionary* entry in (__bridge NSArray*)windowList)
    {
        NSString* ownerName = [entry objectForKey:(__bridge id)kCGWindowOwnerName];
        NSString *windowNum = [entry objectForKey:(__bridge id)kCGWindowNumber];
    if([ownerName isEqualToString:@"Sublime Text"]){
       [self holdToTheFront:[windowNum integerValue]];
    }
}
CFRelease(windowList);

}

收到 EXC_BAD_ACCESS 错误,如下评论中所述:

- (void)holdToTheFront:(NSInteger)winNum {
     objc_object*  nsviewObject = reinterpret_cast<objc_object *>(winNum);

    //Getting a "Thread 1:EXC_BAD_ACCESS (code=1, address=0x18)" at the line below:
    NSWindow* nsWindowObject = ((id (*)(id, SEL))objc_msgSend)((__bridge NSView *)nsviewObject, sel_registerName("window"));

    int NSWindowCollectionBehaviorCanJoinAllSpaces = 1 << 0;
    ((id (*)(id, SEL, NSUInteger))objc_msgSend)(nsWindowObject, sel_registerName("setCollectionBehavior:"), NSWindowCollectionBehaviorCanJoinAllSpaces);
}

【问题讨论】:

  • 你有这方面的最新消息吗?

标签: c++ objective-c cocoa nswindow macos-carbon


【解决方案1】:

为了让应用程序窗口在所有空间都可见,您可以执行以下操作:-

objc_object* nsviewObject = reinterpret_cast<objc_object *>(windowObject);
objc_object* nsWindowObject = objc_msgSend(nsviewObject, sel_registerName("window"));
int NSWindowCollectionBehaviorCanJoinAllSpaces = 1 << 0;
objc_msgSend(nsWindowObject, sel_registerName("setCollectionBehavior:"), NSWindowCollectionBehaviorCanJoinAllSpaces);

其中windowObject 是您希望保留在顶部的应用程序窗口的windowNumber

【讨论】:

  • 谢谢!我会在早上试一试。
  • 我认为不可能为应用程序不拥有的窗口获取窗口编号。然后就会假设外部应用程序是 Cocoa。
  • this 有帮助吗?
  • 是的。我根据您对我的问题的输入添加了我正在处理的代码。如评论所述,我收到 EXC_BAD_ACCESS 错误。
  • 查看nsviewObject的地址。我怀疑问题可能是返回的数字在您从中检索的进程的 VM 空间中,而不是您自己的进程中。如果是这种情况,那么您将无法这样做。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-01
相关资源
最近更新 更多