2016-11-23 2 views
0

J'essaie de créer une application OS X qui permet à une application externe (c'est-à-dire textEdit) de flotter au-dessus de l'application en cours d'exécution sans la focaliser, mais sans jamais disparaître. Fondamentalement, ce que j'essaie de faire est d'imiter l'application ForceQuit (appuyez sur option-command-esc pour le voir), où elle est toujours en haut, mais n'a pas toujours le focus.Application d'un flottement d'application externe sur l'application OS X

Ce que je fais maintenant avec un succès limité est ceci:

Création d'un NSTimer pour continuer à mettre sur le dessus:

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

...

Apportez textEdit à l'avant:

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

La fenêtre textEdit restera en haut si vous cliquez dessus (faites-la perdre concentrer). Mais il y a deux problèmes. 1.) Il clignotera brièvement en le remettant sur le dessus 2.) Il maintiendra toujours toujours la mise au point afin que vous ne puissiez pas interagir avec l'application sous-jacente.

De l'appRef, vous pouvez obtenir la fenêtre:

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

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

Mais je ne pense pas qu'il sera possible de le convertir en un NSWindow. Si je pouvais le faire, j'imagine que je pourrais en faire une fenêtre enfant de la fenêtre principale ou peut-être juste une fenêtre flottante.

Des idées sur la façon dont cela pourrait être fait?

Édition- Ajout des suggestions de @TheDarkKnight

J'essaie ceci:

- (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); 

}

Obtenir une erreur de EXC_BAD_ACCESS comme indiqué dans le commentaire ci-dessous:

- (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); 
} 

Répondre

0

Pour une application wi Ndow être visible sur tous les espaces, vous pouvez faire quelque chose comme ceci: -

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 est le windowNumber de la fenêtre de l'application que vous voulez rester sur le dessus.

+0

Merci! Je vais tenter le coup le matin. – user3564870

+0

Je ne pense pas qu'il soit possible d'obtenir un numéro de fenêtre pour les fenêtres que l'application ne possède pas. Ensuite, il y aurait l'hypothèse que l'application externe est Cocoa. – user3564870

+0

Est-ce que [this] (http://stackoverflow.com/questions/2107657/mac-cocoa-getting-a-list-of-windows-using-accessibility-api) aide? – TheDarkKnight