Creating a HUD on top of another application with Cocoa - objective-c

Is it possible to create a HUD with Cocoa on top of a window from another application? For example, if I were to create a Poker HUD, which would display information about opponents on top of a Poker Client window, how would I implement it in OS X (with Cocoa?).
For example how would I recreate the following Windows program (PokerTracker HUD: displays a HUD on top of PokerStars)?

I'm not sure if this is what you're asking, but I think the HUD elements would be controls or views within an NSWindow set up as an overlay. Here are some key steps to configure it:
[myWindow setOpaque: NO];
[myWindow setBackgroundColor: [NSColor clearColor]];
[myWindow setLevel: NSStatusWindowLevel];
And then you'd need to track which app is frontmost, so that your overlay would only be visible when the target app is in front. I think you could do this by finding the NSRunningApplication for the target app and then key-value-observing its active property.

Related

Find the top-most NSView object located under NSPoint position

I know this question was already asked here in few forms but unfortunately non of the suggested solutions worked for me.I am implementing a multi-touch capability for my osx app.My problem:I need to resolve a location on the screen, described by NSPoint in screen coordinates, to the very top NSView object from my application that resides under this location (if any).This is a bit like HWND WindowFromPoint( Point) under Windows OS.
Few points to consider:
My application manage several NSWindows, where each window contains an hierarchy of several NSViews,
The NSView that I am interested in is not necessarily the application Key Window or Main Window, as it can be any of my other currently non-active NSView objects that happen to be under this screen location,
It is possible that under a particular NSPoint I will have more then one NSWindows and/or NSViews. In this case I wll be interested only in the very top-most NSView,
It is possible that NSView A is on top of NSView B, partialy hiding it, but the NSPoint location is present only on B, which is not the very top-most window of the application (but only the very top-most for this location). Here again I will be interested in B.
Things that I managed todo:
Enumerate NSApp for all its windows (NSApp.windows),
Enumerate NSWindow for its views (NSWindow.contentView.subviews),
Enumerate NSView for its sub-views (NSView.subviews)
Doing this I managed to enumerate all NSViews of my application, but I still need to filter out non-relevant NSViews, which are not visible.
Things that did not work for me:
NSView.hitTest returned nil for valid locations,
NSView.layer.zPosition alwyas is zero (0),
The order of the NSView.subviews list also does not reflacts the current GUI layout,
Testing if NSView is Visible also did not help as it returns true also if this window is hidden by other window.
My environment:Mac, OSX El-Capitan, XCode-7, Cocoa, Objective-C
Thanks for any help!PazO
Found it:
// 1. Get the Window-Number of the NSWindow object owning this point:
NSInteger wndNumber = [NSWindow windowNumberAtPoint:(point) belowWindowWithWindowNumber:(0)];
// 2. Get the NSWindow object associated with this particular Window-Number:
NSWindow* window = [NSApp windowWithWindowNumber:(wndNumber)];
// 3. Convert NSPoint values from System-coordinates to NSWindow-coordinates (Thanks #Willeke for his comment)
NSRect rctScreen;
rctScreen.origin = point;
rctScreen.size.height = rctScreen.size.width = 0;
NSRect rctWindow = [window convertRectFromScreen:rctScreen];
// 4. Now do the hitTest:
NSView* viewFound = [[window contentView] hitTest:rctWindow.origin];
Obviously each line should be tested for nil, but I leave this out for code brevity.

NSTextfield not accepting keyevents on NSWindow which has NSTitledWindowMask

I have started coding cocoa app. I have created a NSwindow with initWithContentRect.
I have created a NSTextField. I can not get any of the keyboard events. It is selectable. I also explicitly set editable to true.
I have realized there are similar questions but they are mostly about the responder, key window and Borderlesswindow style.
I have a NSWindows which has a titled window mask , is the key window and it is selected when I set it to be the first responder.
But why cant I type anything into the box.
int style = NSClosableWindowMask |NSTexturedBackgroundWindowMask | NSTitledWindowMask | NSMiniaturizableWindowMask;
window = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 130, 150)
styleMask:style backing:NSBackingStoreBuffered defer:NO];
CGFloat height=20;
NSTextField * username=[[NSTextField alloc] initWithFrame:NSMakeRect(10, NSHeight(window.frame)-80, 100, height)];
[username setEditable:true];
[window.contentView addSubview:username ];
Is it because I need to create a subclass of NSwindow. I see this is suggested when the style is NSBorderlessWindowMask and by overriding
canBecomeKeyWindow it is suggested to solve the issue.
But I am not using NSBorderlessWindowMask.
What am I missing? Any help is appreciated.
From your comment, you say you don't have a Info.plist file. I'm guessing your app isn't even bundled. This is a crucial fact that you left out of your question, which only makes it hard for people to help you.
First, you should create apps the normal way. Make a bundled app with a main NIB. Follow the standard template, except delete the window from the main NIB and use separate window NIBs.
If you aren't equipped to understand what's going wrong with a "manually" constructed app and fix it, then you really shouldn't be going that route.
That said, an unbundled app will start life as a background-only process. What little interactivity you're seeing is, more or less, a bug. You can transform your app into a foreground app by setting the activationPolicy of the application object (instance of NSApplication or a subclass) to NSApplicationActivationPolicyRegular. Then, make it the active app by calling [NSApp activateWithOptions:NSApplicationActivateIgnoringOtherApps].

MAAttachedWindow for NSStatusItem without a custom view

I have a simple app that has a NSStatusItem, which only displays an icon.
I would now like to add functionality that would make a MAAttachedWindow appear under the NSStatusItem.
I saw the demo code Matt Gemmel provided; the code he uses to make the MAAttachedWindow appear under the NSStatusItem is:
NSRect frame = [[self window] frame];
NSPoint pt = NSMakePoint(NSMidX(frame), NSMinY(frame));
[controller toggleAttachedWindowAtPoint:pt];
The above is done in the custom view of the NSStatusItem. However, my NSStatusItem has no custom view. How can I add the MAAttachedWindow in my case?
You can't afaik. You have to have a way to get coordinates to attach the window to, and the only way i've been able to get that to work is to use a custom view so you can get the coordinates on mouse down and the only way i've seen is to use your own view. Anything else would probably be a little hacky unless there is some way to get the view for a status item without a custom view and it wouldn't be good to display the MSAttachedWindow and a menu.
I just settled on doing a NSStatusitem with a custom view and faking selection by drawing a background gradient when its selected.
Have you considered using NSPopover ?

Working with the frontmost window's controls in a document-based app?

I've scanned the documentation and googled fairly extensively and found nothing on this subject.
What I'm needing to do is interact with a specific instance of one of my NSWindows - that is, one created through the NSDocument system put in place by creating a document-based application in Xcode.
So is there a way to do this? Something like [[NSSharedDocumentController frontmostWindow] subView: doAction], perhaps?
To obtain the frontmost window (aka the main window), use -[NSApplication mainWindow]:
NSWindow *mainWindow = [NSApp mainWindow];
To obtain the window corresponding to a given document:
NSDocument *someDocument; // reference to the document you’re interested in
NSWindow *window = [[[someDocument windowControllers] objectAtIndex:0] window];
NSDocument creates a single window controller to manage the corresponding document window, so -[NSDocument windowControllers] returns an array with a single element corresponding to the window controller. -[NSWindowController window] returns the window managed by that window controller.

Cocoa window position anomaly

I have a weird problem with positioning a window on screen. I want to center the window on the screen, but i don't know how to do that. Here's what i've got. The window is created from nib by the main controller:
IdentFormController *ftf = [[IdentFormController alloc] initWithWindowNibName:#"IdentForm"];
[[ftf window] makeKeyAndOrderFront:self];
Now the IdentFormController has awakeFromNib() method in which it tries to position the window. For the sake of simplicity i've just tried to do setFrameOrigin(NSMakePoint(0, 0)). What happens is as follows:
The first time i create this window, everything works as expected. But if i create it again after releasing the previous, it starts appearing at random positions. Why does it do that?
So as I understand it you want to center the window on the screen?
Well assuming NSWindow *window is your window object then there are two methods...
[window center];
This is the best way to do it but it will ofset to take into account visual weight and the Dock's presence.
If you want dead center then this would work...
// Calculate the actual center
CGFloat x = (window.screen.frame.size.width - window.frame.size.width) / 2;
CGFloat y = (window.screen.frame.size.height - window.frame.size.height) / 2;
// Create a rect to send to the window
NSRect newFrame = NSMakeRect(x, y, window.frame.size.width, window.frame.size.height);
// Send message to the window to resize/relocate
[window setFrame:newFrame display:YES animate:NO];
This code is untested but it gives you a fair idea of what you need to do to get this thing working the way you want, personally I would advise you stick with Apple's code because it has been tested and is what the user would expect to see, also from a design perspective as a designer my self I don't always rely on the actual center to be where the optical center is.
You're probably running afoul of automatic window positioning. Have you tried calling
[myWindowController setShouldCascadeWindows: NO];
?
First of all, it sounds like you need to check "dealloc on close" or "release on close" in the NSWindow's property inspector. Then the window will clean up after itself and you can remove the (risky) call to [self release] in your own code.
awakeFromNib is called after all objects from the nib have been unarchived and outlets have been connected, but that may be too early to be setting the window coordinates. I believe Cocoa does some work to automatically position subsequent windows below and to the right of existing windows, so that new windows don't completely obscure old ones. It is likely doing this AFTER you set the position in awakeFromNib, stomping on your changes.
The best place to set your window position is probably in one of the NSWindow delegate methods (windowWillBecomeVisible: perhaps), or possibly right before you call makeKeyAndOrderFront:.
Check out if you can set the centre of your window with the centre of your screen. And set the window position on it. It might work out.