ViennaRSS / vienna-rss

Vienna is a free and open-source RSS/Atom newsreader for macOS.
https://www.vienna-rss.com
Apache License 2.0
1.82k stars 228 forks source link

Drawing issues in macOS 14 with Xcode 15 #1707

Closed Eitot closed 7 months ago

Eitot commented 9 months ago

When running a debug build on macOS 14 with Xcode 15 there are some UI issues:

Feed entries that have attachments:

Screenshot 2023-09-27 at 05 19 21

The navigation bar of the browser:

Screenshot 2023-09-27 at 05 13 14

The current beta build seems to be unaffected, so Xcode 14 seems to be fine.

From the AppKit release notes for macOS 14:

In macOS 14, AppKit is exposing the clipsToBounds property of NSView. For applications linked against the macOS 14 SDK, the default value of this property is false. Apps linked against older SDKs default to true. Some classes, like NSClipView, continue to default to true. The change in defaults recognizes that it is vastly easier to reason about clipping a view’s descendants than it is to unclip a view’s ancestors. Users can turn clipping back on by using the NSView.clipsToBounds setter or using the attributes inspector of a view in the Xcode interface builder. This property is available back to macOS 10.9. This availability is intended to allow code targeting older OSes to set this property to true without guarding the setter in an availability check. Setting this property to false on previous OSes may not work reliably. Some patterns that have historically worked will require adjustment:

  • Showing or hiding UI by setting an ancestor’s frame to zero. When attempting to hide a view hierarchy by shrinking the size of an ancestor, or positioning a descendent view outside an ancestors view’s bounds, it is now necessary to set the ancestor’s view’s .clipsToBounds property to true. An alternative may be to set NSView.isHidden, instead.
  • Filling the dirty rect of a view inside of -drawRect. A fairly common pattern is to simply rect fill the dirty rect passed into an override of NSView.draw(). The dirty rect can now extend outside of your view’s bounds. This pattern can be adjusted by filling the bounds instead of the dirty rect, or by setting clipsToBounds = true.
  • Confusing a view’s bounds and its dirty rect. The dirty rect passed to .drawRect() should be used to determine what to draw, not where to draw it. Use NSView.bounds when determining the layout of what your view draws. (10905750)

A quick look at the code in EnclosureView.m makes this the likely cause for the bug: https://github.com/ViennaRSS/vienna-rss/blob/f02c9209743b15a3f5a2c5e4a6abd5ea4eb78469/Vienna/Sources/Main%20window/EnclosureView.m#L151-L154

LoadingIndicator.swift also uses draw(_:). The UI issue there might be related.

We should go over the code base for any calls to -drawRect:/draw(_:) in Vienna. I suspect MMTabBarView might also be affected.