Я пытаюсь создать приложение для 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. Если бы я мог это сделать, я бы сделал это дочерним окном главного окна или просто плавающим окном.
Любые идеи о том, как это можно сделать?
Edit- Добавление предложений от @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);
}
Чтобы окно приложения было видно во всех пространствах, вы можете сделать что-то вроде этого:
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 окна приложения вы хотите остаться на вершине.
Других решений пока нет …