Skip to content

Commit

Permalink
cocoa: fix KVO detection on macOS 15 [p=2809649]
Browse files Browse the repository at this point in the history
macOS 15 broke the current isKVOSubclass check (and the undocumented _isKVOA too).

ISA-swizzling when KVO is active throws when removing observers (see 2585715).

[NSObject removeObserver:...] actively does this:

  Class klass = object_getClass(observer);
  ... = NSKeyValuePropertyForIsaAndKeyPath(klass, ...);

The exception:

    Cannot remove an observer <NSTitlebarView 0x7f9c63a241a0> for the key path "_titlebarBackdropGroupName" from <SWELLWindowOverride_REAPERSwell_modelesswindow 0x7f9c63a21640> because it is not registered as an observer.

    0   CoreFoundation                      0x00007ff806aed6d6 __exceptionPreprocess + 242
    1   libobjc.A.dylib                     0x00007ff8065d4c00 objc_exception_throw + 62
    2   Foundation                          0x00007ff807a96066 -[NSObject(NSKeyValueObserverRegistration) _removeObserver:forProperty:] + 659
    3   Foundation                          0x00007ff807a95d83 -[NSObject(NSKeyValueObserverRegistration) removeObserver:forKeyPath:] + 129
    4   Foundation                          0x00007ff807a95a49 -[NSObject(NSKeyValueObserverRegistration) removeObserver:forKeyPath:context:] + 225
    5   AppKit                              0x00007ff80af94be8 -[NSWindow removeObserver:forKeyPath:context:] + 108
    6   AppKit                              0x00007ff80b16ce32 -[NSTitlebarView viewWillMoveToWindow:] + 73
    7   AppKit                              0x00007ff80a3c61cd -[NSView _setWindow:] + 349
    8   AppKit                              0x00007ff80af75ba5 __21-[NSView _setWindow:]_block_invoke.393 + 324
    9   AppKit                              0x00007ff80a3c67f7 -[NSView _setWindow:] + 1927
    10  AppKit                              0x00007ff80af75ba5 __21-[NSView _setWindow:]_block_invoke.393 + 324
    11  AppKit                              0x00007ff80a3c67f7 -[NSView _setWindow:] + 1927
    12  AppKit                              0x00007ff80a3f92a1 __25-[NSWindow setStyleMask:]_block_invoke + 495
    13  AppKit                              0x00007ff80a3f9058 NSPerformVisuallyAtomicChange + 134
    14  AppKit                              0x00007ff80a3f8f71 -[NSWindow setStyleMask:] + 150
    15  reaper_imgui-x86_64.dylib           0x000000010830c5e6 _ZN11CocoaWindow6updateEv + 678
    16  reaper_imgui-x86_64.dylib           0x00000001082f9b86 _ZN17ViewportForwarderIXadL_ZN13ImGuiViewport16PlatformUserDataEEEE4wrapIXadL_ZN8Viewport6updateEvEEJEEEDaPS0_DpT0_ + 102
    17  reaper_imgui-x86_64.dylib           0x0000000108351024 _ZN5ImGui21UpdatePlatformWindowsEv + 1492
    18  reaper_imgui-x86_64.dylib           0x00000001082a2cde _ZN7Context8endFrameEb + 270
    19  reaper_imgui-x86_64.dylib           0x00000001082a37e9 _ZN7Context9heartbeatEv + 73
    20  reaper_imgui-x86_64.dylib           0x00000001082e1987 _ZN8Resource5Timer4tickEv + 135
    21  REAPER                              0x0000000100056b5b _Z13runMiscTimersv + 3243
    22  REAPER                              0x000000010075bfb1 _Z8MainProcP6HWND__jml + 5249
    23  REAPER                              0x00000001005a55bc _ZL28SwellDialogDefaultWindowProcP6HWND__jml + 444
    24  reaper_imgui-x86_64.dylib           0x00000001082e18b9 _ZN8Resource5Timer16mainProcOverrideEP6HWND__jml + 89
    25  Foundation                          0x00007ff807ae1340 __NSFireTimer + 67
    26  CoreFoundation                      0x00007ff806a95874 __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ + 20
    27  CoreFoundation                      0x00007ff806a95422 __CFRunLoopDoTimer + 801
    28  CoreFoundation                      0x00007ff806a9504e __CFRunLoopDoTimers + 285
    29  CoreFoundation                      0x00007ff806a7ba31 __CFRunLoopRun + 2261
    30  CoreFoundation                      0x00007ff806a7ab6c CFRunLoopRunSpecific + 536
    31  HIToolbox                           0x00007ff81215afe3 RunCurrentEventLoopInMode + 292
    32  HIToolbox                           0x00007ff8121609c4 ReceiveNextEventCommon + 646
    33  HIToolbox                           0x00007ff812160b62 _BlockUntilNextEventMatchingListInModeWithFilter + 66
    34  AppKit                              0x00007ff80a3aed8b _DPSNextEvent + 902
    35  AppKit                              0x00007ff80adcb4c8 -[NSApplication(NSEventRouting) _nextEventMatchingEventMask:untilDate:inMode:dequeue:] + 1290
    36  AppKit                              0x00007ff80a39feb7 -[NSApplication run] + 610
    37  AppKit                              0x00007ff80a373234 NSApplicationMain + 823
    38  dyld                                0x00007ff8066092cd start + 1805
  • Loading branch information
cfillion committed Sep 19, 2024
1 parent 2cb03cf commit fa70cd4
Show file tree
Hide file tree
Showing 2 changed files with 4 additions and 3 deletions.
5 changes: 3 additions & 2 deletions src/cocoa_inject.mm
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

#include "cocoa_inject.hpp"

#include <Foundation/Foundation.h>
#include <objc/runtime.h>
#include <string>

Expand All @@ -33,7 +34,7 @@

static bool isKVOSubclass(NSObject *object)
{
return [object class] == class_getSuperclass(object_getClass(object));
return [object observationInfo] != nil;
}

static void injectMethods(Class source, Class target)
Expand Down Expand Up @@ -67,7 +68,7 @@ static Class makeSubclass(Class parent, Class child)
void CocoaInject::inject(Class source, NSObject *target)
{
// [target class] gives the original class
// object_getClass may give the subclass generated by KVO
// object_getClass may give the subclass generated by KVO in macOS 12-14
Class targetClass { [target class] };

if(isKVOSubclass(target))
Expand Down
2 changes: 1 addition & 1 deletion src/cocoa_window.mm
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ - (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen
DetachWindowTopmostButton(m_hwnd, false);
NSString *title { [window title] };
[window setStyleMask:NSWindowStyleMaskBorderless]; // also clears the title
[window setTitle: title];
[window setTitle:title];
}
else {
[window setStyleMask:m_defaultStyleMask];
Expand Down

0 comments on commit fa70cd4

Please sign in to comment.