Back port macOS 26 controls fixes from 3.3

Fixes for controls appearance under macOS 26 Tahoe and also some fixes
to their sizes under the previous macOS versions.

(cherry picked from commit b6f1b6d889)

See #25767.

Closes #26121.

Co-Authored-By: Richard <61946508+nobugshere@users.noreply.github.com>
This commit is contained in:
Vadim Zeitlin
2026-01-28 01:19:06 +01:00
co-authored by Richard
parent 7ab64626d3
commit 2ebaa0aee6
16 changed files with 177 additions and 27 deletions
+1 -1
View File
@@ -267,8 +267,8 @@ wxMSW:
wxOSX:
- Fix wxChoice default size under macOS 26 Tahoe (#26058).
- Improve wxRichTextCtrl handling of cursor keys (Lee Ockert, #26064).
- Many appearance fixes for macOS 26 Tahoe (#26058, #25767, #26121).
- Show applications launched from keyboard under macOS 26 (#26095).
+2
View File
@@ -232,6 +232,8 @@ public :
// from the same pimpl class.
virtual void controlTextDidChange();
virtual void ClipsToBounds(bool clip) wxOVERRIDE;
virtual void AdjustClippingView(wxScrollBar* horizontal, wxScrollBar* vertical) wxOVERRIDE;
virtual void UseClippingView(bool clip) wxOVERRIDE;
virtual WXWidget GetContainer() const wxOVERRIDE { return m_osxClipView ? m_osxClipView : m_osxView; }
+2
View File
@@ -366,6 +366,8 @@ public :
virtual bool EnableTouchEvents(int eventsMask) = 0;
virtual void ClipsToBounds(bool clip);
// 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);
+3
View File
@@ -226,6 +226,9 @@ public:
// returns the visible region of this control in window ie non-client coordinates
const wxRegion& MacGetVisibleRegion( bool includeOuterStructures = false ) ;
// sets NSView.clipsToBounds property
void MacClipsToBounds( bool clip );
// returns true if children have to clipped to the content area
// (e.g., scrolled windows)
bool MacClipChildren() const { return m_clipChildren ; }
+3
View File
@@ -491,6 +491,9 @@
# ifndef MAC_OS_VERSION_14_0
# define MAC_OS_VERSION_14_0 140000
# endif
# ifndef MAC_OS_VERSION_26_0
# define MAC_OS_VERSION_26_0 260000
# endif
# if __MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_13
# ifndef NSAppKitVersionNumber10_10
# define NSAppKitVersionNumber10_10 1343
+12 -4
View File
@@ -50,11 +50,15 @@ wxIMPLEMENT_DYNAMIC_CLASS(wxSpinDoubleEvent, wxNotifyEvent);
// ----------------------------------------------------------------------------
// The margin between the text control and the spin: the value here is the same
// as the margin between the spin button and its "buddy" text control in wxMSW
// so the generic control looks similarly to the native one there, we might
// need to use different value for the other platforms (and maybe even
// determine it dynamically?).
// as the margin between the spin button and its "buddy" text control in wxMSW,
// and the commonly used spacing on macOS, so the generic control looks
// similarly to the native one there, we might need to use different value for
// other platforms (and maybe even determine it dynamically?).
#ifdef __WXOSX__
static const wxCoord MARGIN = 4;
#else
static const wxCoord MARGIN = 1;
#endif
#define SPINCTRLBUT_MAX 32000 // large to avoid wrap around trouble
@@ -244,6 +248,10 @@ bool wxSpinCtrlGenericBase::Create(wxWindow *parent,
m_value = AdjustAndSnap(d);
}
#ifdef __WXOSX__
MacClipsToBounds(false);
#endif
m_textCtrl = new wxSpinCtrlTextGeneric(this, DoValueToText(m_value), style);
m_spinButton = new wxSpinCtrlButtonGeneric(this, styleWithoutBorder);
+11 -1
View File
@@ -129,7 +129,17 @@ wxStatusBar *wxFrame::OnCreateStatusBar(int number, long style, wxWindowID id,
void wxFrame::SetStatusBar(wxStatusBar *statbar)
{
wxFrameBase::SetStatusBar(statbar);
m_nowpeer->SetBottomBorderThickness(statbar ? GetMacStatusbarHeight() : 0);
#if __MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_VERSION_11_0
if ( WX_IS_MACOS_AVAILABLE(11, 0) )
{
// textured borders are unwanted, statusbar renders w/o them
}
else
#endif
{
m_nowpeer->SetBottomBorderThickness(statbar ? GetMacStatusbarHeight() : 0);
}
}
void wxFrame::PositionStatusBar()
+1 -1
View File
@@ -586,7 +586,7 @@ wxSize wxRendererMac::GetCollapseButtonSize(wxWindow *WXUNUSED(win), wxDC& WXUNU
}
// strict metrics size cutoff the button, increase the size
size.IncBy(1);
size.IncBy(3);
return size;
}
+78 -3
View File
@@ -34,6 +34,7 @@ wxBEGIN_EVENT_TABLE(wxStatusBarMac, wxStatusBarGeneric)
EVT_PAINT(wxStatusBarMac::OnPaint)
wxEND_EVENT_TABLE()
static wxColor s_bgActive, s_bgInactive, s_separator;
wxStatusBarMac::wxStatusBarMac(wxWindow *parent,
wxWindowID id,
@@ -76,6 +77,51 @@ bool wxStatusBarMac::Create(wxWindow *parent, wxWindowID id,
void wxStatusBarMac::InitColours()
{
#if __MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_VERSION_26_0
if ( WX_IS_MACOS_AVAILABLE(26, 0) )
{
if ( wxSystemSettings::GetAppearance().IsDark() )
{
m_textActive = wxColour(0x9B, 0x9F, 0x9F);
m_textInactive = wxColour(0x59, 0x5F, 0x60);
// native separator uses hairline black plus some shading,
// this approximates it well visually:
s_separator = wxColour(0x18, 0x18, 0x18);
}
else
{
m_textActive = wxColour(0x80, 0x80, 0x80);
m_textInactive = wxColour(0xB8, 0xB8, 0xB8);
s_separator = wxColour(0xD9, 0xD9, 0xD9);
}
}
else
#endif // MAC_OS_VERSION_26_0
#if __MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_VERSION_11_0
if ( WX_IS_MACOS_AVAILABLE(11, 0) )
{
if ( wxSystemSettings::GetAppearance().IsDark() )
{
m_textActive = wxColour(0xB1, 0xB2, 0xB2);
m_textInactive = wxColour(0x68, 0x69, 0x6A);
s_bgActive = wxColour(0x35, 0x36, 0x36);
s_bgInactive = wxColour(0x27, 0x28, 0x29);
// native separator uses hairline black plus some shading,
// this approximates it well visually:
s_separator = wxColour(0x18, 0x18, 0x18);
}
else
{
m_textActive = wxColour(0x73, 0x74, 0x74);
m_textInactive = wxColour(0xA5, 0xA6, 0xA6);
s_bgActive = wxColour(0xF3, 0xF3, 0xF3);
s_bgInactive = wxColour(0xE6, 0xE6, 0xE6);
s_separator = wxColour(0xCC, 0xCC, 0xCC);
}
}
else
#endif // MAC_OS_VERSION_11_0
#if __MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_14
if ( WX_IS_MACOS_AVAILABLE(10, 14) )
{
if ( wxSystemSettings::GetAppearance().IsDark() )
@@ -89,7 +135,9 @@ void wxStatusBarMac::InitColours()
m_textInactive = wxColour(0xB1, 0xB1, 0xB1);
}
}
else // 10.10 Yosemite to 10.13:
else
#endif // MAC_OS_X_VERSION_10_14
// 10.10 Yosemite to 10.13:
{
m_textActive = wxColour(0x40, 0x40, 0x40);
@@ -119,7 +167,34 @@ void wxStatusBarMac::OnPaint(wxPaintEvent& WXUNUSED(event))
break;
}
// Don't paint any background, that's handled by the OS. Only draw text:
#if __MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_VERSION_26_0
if ( WX_IS_MACOS_AVAILABLE(26, 0) )
{
// don't paint the background, handled by the OS
}
else
#endif
#if __MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_VERSION_11_0
if ( WX_IS_MACOS_AVAILABLE(11, 0) )
{
// we _do_ need to paint the background on Big Sur up to Tahoe
// to match Finder's appearance:
dc.SetBackground(tlw == keyWindow ? s_bgActive : s_bgInactive);
dc.Clear();
}
// else: background is rendered by OS, it is part of NSWindow border
#endif
#if __MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_VERSION_11_0
// Draw horizontal separator above the status bar:
if ( WX_IS_MACOS_AVAILABLE(11, 0) )
{
dc.SetPen(s_separator);
dc.DrawLine(0, 0, GetSize().x, 0);
}
#endif
// Draw the text:
dc.SetTextForeground(tlw == keyWindow ? m_textActive : m_textInactive);
@@ -131,7 +206,7 @@ void wxStatusBarMac::OnPaint(wxPaintEvent& WXUNUSED(event))
int textHeight = dc.GetCharHeight();
for ( size_t i = 0; i < m_panes.GetCount(); i ++ )
DrawField(dc, i, textHeight);
DrawField(dc, (int)i, textHeight);
}
void wxStatusBarMac::MacHiliteChanged()
+1 -1
View File
@@ -44,5 +44,5 @@ wxSize wxAnyButton::DoGetBestSize() const
wxSize wxAnyButton::GetDefaultSize()
{
return wxSize(84, 20);
return wxSize(74, 20);
}
+15 -1
View File
@@ -24,6 +24,7 @@
#include "wx/string.h"
#include "wx/private/bmpbndl.h"
#include "wx/osx/private.h"
#include "wx/osx/private/available.h"
//
// controller
@@ -87,7 +88,20 @@
if (!initialized)
{
initialized = YES;
wxOSXCocoaClassAddWXMethods( self );
// On macOS 26 Tahoe, the mere presence of drawRect: in derived class,
// even if it just calls super's implementation, triggers legacy
// rendering of NSTabView.
#if __MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_VERSION_26_0
if (WX_IS_MACOS_AVAILABLE(26, 0))
{
wxOSXCocoaClassAddWXMethods(self, wxOSXSKIP_DRAW);
}
else
#endif
{
wxOSXCocoaClassAddWXMethods(self);
}
}
}
+8
View File
@@ -1746,6 +1746,14 @@ wxSize wxNSTextFieldControl::GetBestSize() const
sz.x = (int)ceil(best.size.width);
sz.y = (int)ceil(best.size.height);
// never be smaller than single-line NSMiniControlSize field:
sz.y = wxMax(sz.y, 16);
// !!! Any changes to these adjustments must be mirrored in wxTextCtrl::DoGetSizeFromTextSize() !!!
sz.x -= 4;
sz.y -= 2;
if ( [m_textField isBezeled] || [m_textField isBordered] )
{
// since this will be added again in DoGetSizeFromTextSize
+8 -1
View File
@@ -2606,7 +2606,9 @@ wxWidgetImpl( peer, flags )
if ( m_osxView )
CFRetain(m_osxView);
[m_osxView release];
m_osxView.clipsToBounds = YES;
if ( IsUserPane() )
ClipsToBounds(true);
}
@@ -4166,6 +4168,11 @@ void wxWidgetCocoaImpl::UseClippingView(bool clip)
#endif
}
void wxWidgetCocoaImpl::ClipsToBounds(bool clip)
{
m_osxView.clipsToBounds = clip;
}
//
// Factory methods
+11 -1
View File
@@ -14,6 +14,7 @@
#include "wx/spinbutt.h"
#include "wx/osx/private.h"
#include "wx/osx/private/available.h"
wxSpinButton::wxSpinButton()
@@ -81,7 +82,16 @@ bool wxSpinButton::OSXHandleClicked( double WXUNUSED(timestampsec) )
wxSize wxSpinButton::DoGetBestSize() const
{
return wxSize( 16, 24 );
#if __MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_VERSION_26_0
if ( WX_IS_MACOS_AVAILABLE(26, 0) )
{
return wxSize(21, 28);
}
else
#endif
{
return wxSize(13, 22);
}
}
void wxSpinButton::TriggerScrollEvent(wxEventType scrollEvent)
+11 -6
View File
@@ -42,6 +42,7 @@
#include "wx/thread.h"
#include "wx/osx/private.h"
#include "wx/osx/private/available.h"
wxBEGIN_EVENT_TABLE(wxTextCtrl, wxTextCtrlBase)
EVT_DROP_FILES(wxTextCtrl::OnDropFiles)
@@ -209,23 +210,25 @@ wxSize wxTextCtrl::DoGetSizeFromTextSize(int xlen, int ylen) const
// these are the numbers from the HIG:
switch ( m_windowVariant )
{
case wxWINDOW_VARIANT_NORMAL :
hText = 22;
break ;
case wxWINDOW_VARIANT_SMALL :
hText = 19;
break ;
case wxWINDOW_VARIANT_MINI :
hText = 15;
hText = 16;
break ;
case wxWINDOW_VARIANT_NORMAL :
default :
hText = 22;
hText = 21;
break ;
}
#if __MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_VERSION_26_0
if ( WX_IS_MACOS_AVAILABLE(26, 0) )
hText += 3;
#endif
// the numbers above include the border size, so subtract it before
// possibly adding it back below
hText -= TEXTCTRL_BORDER_SIZE;
@@ -242,6 +245,8 @@ wxSize wxTextCtrl::DoGetSizeFromTextSize(int xlen, int ylen) const
// has small positive xlen, therefore don't compare just with > 0 anymore
wxSize size(xlen > TEXTCTRL_MAX_EMPTY_WIDTH ? xlen : 100, hText);
// !!! Any changes to these adjustments must be mirrored in wxNSTextFieldControl::GetBestSize() !!!
// Use extra margin size which works under macOS 10.15: note that we don't
// need the vertical margin when using the automatically determined hText.
if ( xlen > TEXTCTRL_MAX_EMPTY_WIDTH )
+10 -7
View File
@@ -263,6 +263,12 @@ wxWindowMac::~wxWindowMac()
delete GetPeer() ;
}
void wxWindowMac::MacClipsToBounds( bool clip )
{
if ( m_peer )
m_peer->ClipsToBounds(clip);
}
void wxWindowMac::MacSetClipChildren( bool clip )
{
m_clipChildren = clip ;
@@ -1071,13 +1077,6 @@ wxSize wxWindowMac::DoGetBestSize() const
r.height = 16 ;
}
else
#endif
#if wxUSE_SPINBTN
if ( IsKindOf( CLASSINFO( wxSpinButton ) ) )
{
r.height = 24 ;
}
else
#endif
{
// return wxWindowBase::DoGetBestSize() ;
@@ -2762,6 +2761,10 @@ void wxWidgetImpl::SetDrawingEnabled(bool WXUNUSED(enabled))
{
}
void wxWidgetImpl::ClipsToBounds(bool WXUNUSED(clip))
{
}
void wxWidgetImpl::AdjustClippingView(wxScrollBar* WXUNUSED(horizontal), wxScrollBar* WXUNUSED(vertical))
{
}