Cocoa exceptions: pre-and post-Mojave

Sam noted this earlier:

[quote]Cocoa exceptions are no longer logged to the console.
Workaround: none yet.
Note: Trying to prepare applications for Mojave are hard when things have changed, which causes a Cocoa Exception. This results in a function silently failing, with no pointers or indication why. You must manually step through code until you find the line it fails on, then do research to figure out why that line fails.[/quote]

This just bit me in a big way.

I was trying to work out the declares to detect Dark Mode, and used the following code:

#if TargetMacOS
function IsDarkMode() as boolean
  // see https://developer.apple.com/documentation/appkit/nsappearance
  
  Declare Function NSClassFromString Lib "Foundation" (classname As CFStringRef) As Ptr
  Declare Function NSAppearanceCurrentApperance Lib "Foundation" Selector "currentAppearance:" (classname As Ptr) As Ptr
  Declare Function NSAppearanceName Lib "Foundation" Selector "name:" (obj As Ptr) As CFStringRef
  
  dim nsa as Ptr = NSClassFromString("NSAppearance")
  dim currentAppearance as Ptr = NSAppearanceCurrentApperance(nsa)
  if currentAppearance <> nil then
    dim name as string = NSAppearanceName(currentAppearance)
    if name = "NSAppearanceNameDarkAqua" then
      return true
    end if
  end if
  return false
#else
  return false
#endif
end function

Looks good, right?

Except there are two flaws which are subtle but fatal.

Without fixing the flaws, this function dies silently mid-stream. And by “dies” I do not mean “crashes” or “throws an exception” - no. Instead, the thread just disappears. This is extremely hard to debug and very user unfriendly. Very non “Xojo” like.

Puzzle:
• can anyone identify the flaws?

Questions:
• can Xojo do something to prevent these types of errors from being so incredibly hard to find and fix?

  1. You need to get the appearance from an Appearance compatible object (one that adheres to the Appearance protocol), mainly a window, or under Mojave, the application also.

  2. I can’t answer that one.

Close but not quite. The fixed code works under 10.12 and 10.14.

The bug is subtle.

Hint: this is more like https://priceonomics.com/the-typo-that-destroyed-a-space-shuttle/

only it wasn’t a Hypen

Huh? My understanding of the appearance framework was that it only worked on the objects that it adhered to? At least that’s how I’ve been using it. Then again, I am more familiar with using it in 10.10 + to force my applications to have a dark theme.

p.s. If you use the right declares at the right time (i.e. right event) you don’t need to know which theme is being used, you’ll get the correct colors for the controls that the OS doesn’t auto update for you.

Without having checked the code completely: Two selectors are wrong. They must be

"currentAppearance" and "name"

(without the colons).

EDIT: I’ve been searching console up and down and finally found a clue under the “devices” tab (Mojave 18A353d):

EDIT II: Below that message, I see two private errors listed marked “” (showing only the pid and thread ID), and further below

[quote]standard 10:45:28.905691 +0200 My Application.debug 27366555: RECEIVED OUT-OF-SEQUENCE NOTIFICATION: 191 vs 296, 512,
standard 10:45:30.639889 +0200 My Application.debug LSExceptions shared instance invalidated for timeout.[/quote]

Could that be a hint to the reason macOS does not show a crash window in this case?

I’d also like to point out that NSAppearance is in the AppKit framework, not Foundation.

[quote=399929:@Ulrich Bogun]Without having checked the code completely: Two selectors are wrong. They must be
“currentAppearance” and “name”
(without the colons).[/quote]

This is correct!

Weirdly, that doesn’t seem to matter - the corrected code works for me (in 10.12.6 and 10.14 beta 6 at least):

Public Function IsDarkMode() as boolean
  #if TargetMacOS
    // see https://developer.apple.com/documentation/appkit/nsappearance
    Declare Function NSClassFromString Lib "Foundation" (classname As CFStringRef) As Ptr
    Declare Function NSAppearanceCurrentApperance Lib "Foundation" Selector "currentAppearance" (classname As Ptr) As Ptr
    Declare Function NSAppearanceName Lib "Foundation" Selector "name" (obj As Ptr) As CFStringRef
    dim nsa as Ptr = NSClassFromString("NSAppearance")
    dim currentAppearance as Ptr = NSAppearanceCurrentApperance(nsa)
    if currentAppearance <> nil then
      dim name as string = NSAppearanceName(currentAppearance)
      if name = "NSAppearanceNameDarkAqua" then
        return true
      end if
    end if
    return false
  #else
    return false
  #endif
End Function

Does Xojo or macOS have some sort of search function to find the function even if we provide the wrong framework?

It’s a bug that it works.

Isn’t that a “feature”?

I am pretty sure Xojo Inc will make the new changes for Mojave work in the next Xojo release (auto switching Light/Dark mode, …) :wink: :wink: