Search code examples
objective-cmacoscocoaxcode7osx-elcapitan

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


Solution

  • 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.