KPCTabsControl icon indicating copy to clipboard operation
KPCTabsControl copied to clipboard

Receive NSEvent error when inserted into title bar

Open SevenBits opened this issue 8 years ago • 9 comments

Hi there,

Using the native NSWindow APIs* I’m inserting a TabsControl instance into the title bar of an NSWindow. Whenever I try to resize the window, I receive either an exception or failed assertion, both involving NSEvent:

2017-05-22 17:58:32.728021-0400 SECLookup[1518:41383] *** Assertion failure in -[NSEvent trackingArea], /Library/Caches/com.apple.xbs/Sources/AppKit/AppKit-1504.83.101/AppKit.subproj/NSEvent.m:3000

You can find a full output log here. The bug occurs within AppKit, but it does not occur unless I insert the tabs control into the window title bar, so I surmise that this class is interfering with AppKit somehow.

You can find a sample project here, stripped to the bare-bones necessary to let you see the problem. Launch the app, re-size the window, and the crash will occur.

I would appreciate any assistance you can provide.

* - I’m using the WAYWindow subclass to make this simple, but I can confirm that this also causes a crash when I do the insertion manually.

SevenBits avatar May 26 '17 01:05 SevenBits

Hi. Thanks for your report. Interesting problem. I've look at your bare project, and one can easily see where the crash occurs indeed.

I've always used this small snippet in the function updateTrackingAreas to ensure the state of elements depending on the mouse being inside or not is correct. But here it causes a crash, and inspection of the event in my case reveals only a "System Event".

I am a bit reluctant to remove that snippet without understanding the root cause, even if it suppress the problem...

onekiloparsec avatar May 26 '17 08:05 onekiloparsec

@onekiloparsec Where is the troublesome code in your framework? I will try commenting it out and seeing if it affects the behavior of my application at all.

I can't identify the root cause, either. I've filed a bug with Apple but haven't heard back from them.

SevenBits avatar May 26 '17 15:05 SevenBits

Simple, the issue points in the updateTrackingAreas function of the TabButton class. But the answer is already known: commenting out the code will solve your issue. And you can certainly close the radar at Apple, this isn't a bug on their side.

The problem is : this code is making useful things. I could remove it for sure, but I would rather prefer making it smarter.

The thing I would investigate (no time for now, but you can check): is to forward the event to the mouseExited and mouseEntered functions only for certain type of events and not others.

onekiloparsec avatar May 26 '17 16:05 onekiloparsec

I’ve got it working @onekiloparsec. It would be nice to have a work around but in the meantime I just commented out the code. And I will investigate your suggestion.

SevenBits avatar May 26 '17 23:05 SevenBits

For reference, we're talking about a crash here, right?

https://github.com/onekiloparsec/KPCTabsControl/blob/master/KPCTabsControl/TabButton.swift#L133

@SevenBits can you try what's the absolute minimum you have to comment-out to make this work?

For what it's worth, I have experimented with a hover-aware sidebar component and use similar code: https://github.com/CleanCocoa/FatSidebar/blob/master/FatSidebar/FatSidebarItem.swift#L419

There, I call super.updateTrackingAreas() first. Maybe the order of instructions is a factor?

DivineDominion avatar May 27 '17 19:05 DivineDominion

@DivineDominion @onekiloparsec If I comment out the self.addTrackingArea(self.trackingArea!) statement in the updateTrackingAreas method, then everything works except for the fullscreen/maximize button. If I need the fullscreen/maximize to work, I need to comment out two additional lines. The fully working code is this:

open override func updateTrackingAreas() {
    if let ta = self.trackingArea {
        self.removeTrackingArea(ta)
    }
    
    let item: AnyObject? = self.cell?.representedObject as AnyObject?
    
    let userInfo: [String: AnyObject]? = (item != nil) ? ["item": item!] : nil
    self.trackingArea = NSTrackingArea(rect: self.bounds,
                                       options: [.mouseEnteredAndExited, .activeInActiveApp, .inVisibleRect],
                                       owner: self, userInfo: userInfo)
    
    //self.addTrackingArea(self.trackingArea!)
    
    if let w = self.window, let e = NSApp.currentEvent {
        let mouseLocation = w.mouseLocationOutsideOfEventStream
        let convertedMouseLocation = self.convert(mouseLocation, from: nil)
    
        if NSPointInRect(convertedMouseLocation, self.bounds) {
            //self.mouseEntered(with: e)
        }
        else {
            //self.mouseExited(with: e)
        }
    }
    
    super.updateTrackingAreas()
}

I do not know what impact this workaround has on the remainder of the library.

SevenBits avatar May 29 '17 19:05 SevenBits

Commenting out the line self.addTrackingArea effectively removes the tracking area from doing anything useful. It will just sit in memory.

I keep thinking the investigation must focus on what type of event we receive, and forwarding them only the ones that make sense.

onekiloparsec avatar May 30 '17 07:05 onekiloparsec

Hi @onekiloparsec, I agree, it is not the ideal solution. However I was looking at the minimum amount of code I needed to comment out to get it work. I will examine different types of events next. Do you have any ideas on which events might be the best places to start looking?

SevenBits avatar May 30 '17 13:05 SevenBits

Sorry but you just make "get it work" for you. I have tried a few things this morning, and maybe this type of events is not the issue.

I've tried to get rid of the WAYWindow class to make sure this isn't creating an addition layer of complications. But for adding tabs to a titlebar one must use a NSTitlebarAccessoryViewController.

But when trying to do so, I get an error message warning: could not execute support code to read Objective-C class data in the process. This may reduce the quality of type information available. WTF.

Anyway, I would prefer to understand what's going on before changing something that is otherwise working. I would suggest to get rid of the WAYWindow first in your tests, as I tried myself without success so far.

onekiloparsec avatar May 31 '17 05:05 onekiloparsec