Fix clipping of scrolled windows under macOS Sonoma

We need to use a native clip view for things to behave correctly under
this OS version, otherwise scrollbars can be overdrawn by the window
contents.

Closes #24067.

Closes #24073.
This commit is contained in:
Stefan Csomor 2023-11-20 10:07:25 +01:00 committed by Vadim Zeitlin
parent 8ca312b17c
commit bcbc31e97f
5 changed files with 98 additions and 4 deletions

View file

@ -220,8 +220,13 @@ public :
// from the same pimpl class.
virtual void controlTextDidChange();
virtual void AdjustClippingView(wxScrollBar* horizontal, wxScrollBar* vertical) override;
virtual void UseClippingView(bool clip) override;
virtual WXWidget GetContainer() const override { return m_osxClipView ? m_osxClipView : m_osxView; }
protected:
WXWidget m_osxView;
WXWidget m_osxClipView;
// begins processing of native key down event, storing the native event for later wx event generation
void BeginNativeKeyDownEvent( NSEvent* event );

View file

@ -365,6 +365,14 @@ public :
virtual bool EnableTouchEvents(int eventsMask) = 0;
// scrolling views need a clip subview that acts as parent for native children
// (except for the scollbars) which are children of the view itself
virtual void AdjustClippingView(wxScrollBar* horizontal, wxScrollBar* vertical);
virtual void UseClippingView(bool clip);
// returns native view which acts as a parent for native children
virtual WXWidget GetContainer() const;
// Mechanism used to keep track of whether a change should send an event
// Do SendEvents(false) when starting actions that would trigger programmatic events
// and SendEvents(true) at the end of the block.

View file

@ -224,7 +224,7 @@ public:
// returns true if children have to clipped to the content area
// (e.g., scrolled windows)
bool MacClipChildren() const { return m_clipChildren ; }
void MacSetClipChildren( bool clip ) { m_clipChildren = clip ; }
void MacSetClipChildren( bool clip );
// returns true if the grandchildren need to be clipped to the children's content area
// (e.g., splitter windows)

View file

@ -16,6 +16,7 @@
#include "wx/textctrl.h"
#include "wx/combobox.h"
#include "wx/radiobut.h"
#include "wx/scrolbar.h"
#endif
#ifdef __WXMAC__
@ -2562,6 +2563,7 @@ wxWidgetImpl( peer, flags )
{
Init();
m_osxView = w;
m_osxClipView = nil;
// check if the user wants to create the control initially hidden
if ( !peer->IsShown() )
@ -3215,6 +3217,21 @@ bool wxWidgetCocoaImpl::CanFocus() const
return canFocus;
}
@interface wxNSClipView : NSClipView
@end
@implementation wxNSClipView
#if wxOSX_USE_NATIVE_FLIPPED
- (BOOL)isFlipped
{
return YES;
}
#endif
@end
bool wxWidgetCocoaImpl::HasFocus() const
{
NSView* targetView = m_osxView;
@ -3305,7 +3322,13 @@ void wxWidgetCocoaImpl::RemoveFromParent()
void wxWidgetCocoaImpl::Embed( wxWidgetImpl *parent )
{
NSView* container = parent->GetWXWidget() ;
NSView* container = nil;
if ( m_wxPeer->MacIsWindowScrollbar( parent->GetWXPeer()))
container = parent->GetWXWidget();
else
container = parent->GetContainer();
wxASSERT_MSG( container != nullptr , wxT("No valid mac container control") ) ;
[container addSubview:m_osxView];
@ -4034,6 +4057,41 @@ void wxWidgetCocoaImpl::SetDrawingEnabled(bool enabled)
[[m_osxView window] disableFlushWindow];
}
}
void wxWidgetCocoaImpl::AdjustClippingView(wxScrollBar* horizontal, wxScrollBar* vertical)
{
if( m_osxClipView )
{
NSRect bounds = m_osxView.bounds;
if( horizontal && horizontal->IsShown() )
{
int sz = horizontal->GetSize().y;
bounds.size.height -= sz;
}
if( vertical && vertical->IsShown() )
{
int sz = vertical->GetSize().x;
bounds.size.width -= sz;
}
m_osxClipView.frame = bounds;
}
}
void wxWidgetCocoaImpl::UseClippingView(bool clip)
{
wxWindow* peer = m_wxPeer;
if ( peer && m_osxClipView == nil)
{
m_osxClipView = [[wxNSClipView alloc] initWithFrame: m_osxView.bounds];
[(NSClipView*)m_osxClipView setDrawsBackground: NO];
[m_osxView addSubview:m_osxClipView];
// TODO check for additional subwindows which might have to be moved to the clip view ?
}
}
//
// Factory methods
//

View file

@ -261,6 +261,13 @@ wxWindowMac::~wxWindowMac()
delete GetPeer() ;
}
void wxWindowMac::MacSetClipChildren( bool clip )
{
m_clipChildren = clip ;
if ( m_peer )
m_peer->UseClippingView(clip);
}
WXWidget wxWindowMac::GetHandle() const
{
if ( GetPeer() )
@ -386,6 +393,8 @@ bool wxWindowMac::Create(wxWindowMac *parent,
{
SetPeer(wxWidgetImpl::CreateUserPane( this, parent, id, pos, size , style, GetExtraStyle() ));
MacPostControlCreate(pos, size) ;
if ( m_clipChildren )
m_peer->UseClippingView(m_clipChildren);
}
wxWindowCreateEvent event((wxWindow*)this);
@ -2139,6 +2148,7 @@ void wxWindowMac::MacRepositionScrollBars()
m_growBox->Hide();
}
}
m_peer->AdjustClippingView(m_hScrollBar, m_vScrollBar);
#endif
}
@ -2700,3 +2710,16 @@ bool wxWidgetImpl::NeedsFrame() const
void wxWidgetImpl::SetDrawingEnabled(bool WXUNUSED(enabled))
{
}
void wxWidgetImpl::AdjustClippingView(wxScrollBar* WXUNUSED(horizontal), wxScrollBar* WXUNUSED(vertical))
{
}
void wxWidgetImpl::UseClippingView(bool WXUNUSED(clip))
{
}
WXWidget wxWidgetImpl::GetContainer() const
{
return GetWXWidget();
}