From 5ebd76c5db02f850998d6fa3adc1820b735eec3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Va=CC=81clav=20Slavi=CC=81k?= Date: Thu, 31 Dec 2020 14:00:43 +0100 Subject: [PATCH 1/4] Fix window background tinting on macOS 11 macOS 11 has an option (on by default) to tint window backgrounds with wallpaper colors. This means that standard window background color is not a constant anymore and can change as the window is moved across the screen. The key to supporting this is to _not set background color_ internally to what we think is the correct default color, or to repaint backgrounds. Let the OS handle the default behavior instead. --- src/generic/splitter.cpp | 26 +++++++++++++++++++++----- src/osx/carbon/frame.cpp | 1 - src/osx/nonownedwnd_osx.cpp | 2 -- 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/src/generic/splitter.cpp b/src/generic/splitter.cpp index 0a8512278c..dc4732baf2 100644 --- a/src/generic/splitter.cpp +++ b/src/generic/splitter.cpp @@ -31,6 +31,10 @@ #include "wx/settings.h" #endif +#ifdef __WXOSX__ + #include "wx/osx/private/available.h" +#endif + #include "wx/renderer.h" #include @@ -175,11 +179,23 @@ void wxSplitterWindow::OnPaint(wxPaintEvent& WXUNUSED(event)) { wxPaintDC dc(this); #ifdef __WXOSX__ - // as subpanels might have a transparent background we must erase the background - // at least on OSX, otherwise traces of the sash will remain - // test with: splitter sample->replace right window - dc.Clear(); -#endif + #if __MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_16 + if ( WX_IS_MACOS_AVAILABLE(10, 16) ) + { + // Nothing to do: since macOS 10.14, views are layer-backed or using a shared + // layer and explicitly clearing the background isn't needed. This only + // started mattering here with macOS 11 (aka 10.16 when built with older SDK), + // where we must avoid explicitly painting window backgrounds + } + else + #endif + { + // as subpanels might have a transparent background we must erase the background + // at least on OSX, otherwise traces of the sash will remain + // test with: splitter sample->replace right window + dc.Clear(); + } +#endif // __WXOSX__ DrawSash(dc); } diff --git a/src/osx/carbon/frame.cpp b/src/osx/carbon/frame.cpp index 67d8616303..25ee3616a2 100644 --- a/src/osx/carbon/frame.cpp +++ b/src/osx/carbon/frame.cpp @@ -129,7 +129,6 @@ void wxFrame::PositionStatusBar() // Responds to colour changes, and passes event on to children. void wxFrame::OnSysColourChanged(wxSysColourChangedEvent& event) { - SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_APPWORKSPACE)); Refresh(); #if wxUSE_STATUSBAR diff --git a/src/osx/nonownedwnd_osx.cpp b/src/osx/nonownedwnd_osx.cpp index 470b8ea7ca..81938b9a92 100644 --- a/src/osx/nonownedwnd_osx.cpp +++ b/src/osx/nonownedwnd_osx.cpp @@ -152,8 +152,6 @@ bool wxNonOwnedWindow::Create(wxWindow *parent, wxWindowCreateEvent event(this); HandleWindowEvent(event); - SetBackgroundColour(wxSystemSettings::GetColour( wxSYS_COLOUR_APPWORKSPACE )); - if ( parent ) parent->AddChild(this); From e687d0c4f6e3c4ea4e81976b9ea03172f7afa117 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Va=CC=81clav=20Slavi=CC=81k?= Date: Thu, 31 Dec 2020 18:51:46 +0100 Subject: [PATCH 2/4] Render statusbar natively on macOS Instead of trying to mimic native statusbar background rendering in our own code, use NSWindow setContentBorderThickness:forEdge: to extend the border that is drawn by the system. This is the canonical way of doing statusbars ("bottom bar") in AppKit. The text is still drawn generically, but that's a much smaller issue than trying to match the border gradient. --- include/wx/osx/cocoa/private.h | 2 ++ include/wx/osx/core/private.h | 2 ++ include/wx/osx/frame.h | 2 ++ include/wx/osx/statusbr.h | 4 +-- src/osx/carbon/frame.cpp | 6 ++++ src/osx/carbon/statbrma.cpp | 53 +++++----------------------------- src/osx/cocoa/nonownedwnd.mm | 6 ++++ 7 files changed, 27 insertions(+), 48 deletions(-) diff --git a/include/wx/osx/cocoa/private.h b/include/wx/osx/cocoa/private.h index 3e6dc20a6e..7c13d5897c 100644 --- a/include/wx/osx/cocoa/private.h +++ b/include/wx/osx/cocoa/private.h @@ -329,6 +329,8 @@ public : virtual void SetRepresentedFilename(const wxString& filename) wxOVERRIDE; + virtual void SetBottomBorderThickness(int thickness) wxOVERRIDE; + wxNonOwnedWindow* GetWXPeer() { return m_wxPeer; } CGWindowLevel GetWindowLevel() const wxOVERRIDE { return m_macWindowLevel; } diff --git a/include/wx/osx/core/private.h b/include/wx/osx/core/private.h index a25b3e104e..bc4c852bce 100644 --- a/include/wx/osx/core/private.h +++ b/include/wx/osx/core/private.h @@ -984,6 +984,8 @@ public : virtual void SetRepresentedFilename(const wxString& WXUNUSED(filename)) { } + virtual void SetBottomBorderThickness(int WXUNUSED(thickness)) { } + #if wxOSX_USE_IPHONE virtual CGFloat GetWindowLevel() const { return 0.0; } #else diff --git a/include/wx/osx/frame.h b/include/wx/osx/frame.h index 155e7ccf3a..9fef19f146 100644 --- a/include/wx/osx/frame.h +++ b/include/wx/osx/frame.h @@ -71,6 +71,8 @@ public: long style = wxSTB_DEFAULT_STYLE, wxWindowID id = 0, const wxString& name = wxASCII_STR(wxStatusLineNameStr)) wxOVERRIDE; + + virtual void SetStatusBar(wxStatusBar *statbar) wxOVERRIDE; #endif // wxUSE_STATUSBAR void PositionBars(); diff --git a/include/wx/osx/statusbr.h b/include/wx/osx/statusbr.h index 9b6e84e56a..ea931f998f 100644 --- a/include/wx/osx/statusbr.h +++ b/include/wx/osx/statusbr.h @@ -38,9 +38,7 @@ protected: virtual void InitColours() wxOVERRIDE; private: - wxColour m_textActive, m_textInactive, - m_bgActiveFrom, m_bgActiveTo, - m_borderActive, m_borderInactive; + wxColour m_textActive, m_textInactive; wxDECLARE_DYNAMIC_CLASS(wxStatusBarMac); wxDECLARE_EVENT_TABLE(); diff --git a/src/osx/carbon/frame.cpp b/src/osx/carbon/frame.cpp index 25ee3616a2..0ca60a20b3 100644 --- a/src/osx/carbon/frame.cpp +++ b/src/osx/carbon/frame.cpp @@ -112,6 +112,12 @@ wxStatusBar *wxFrame::OnCreateStatusBar(int number, long style, wxWindowID id, return statusBar; } +void wxFrame::SetStatusBar(wxStatusBar *statbar) +{ + wxFrameBase::SetStatusBar(statbar); + m_nowpeer->SetBottomBorderThickness(statbar ? WX_MAC_STATUSBAR_HEIGHT : 0); +} + void wxFrame::PositionStatusBar() { if (m_frameStatusBar && m_frameStatusBar->IsShown() ) diff --git a/src/osx/carbon/statbrma.cpp b/src/osx/carbon/statbrma.cpp index 4201551b50..29e7b9fe76 100644 --- a/src/osx/carbon/statbrma.cpp +++ b/src/osx/carbon/statbrma.cpp @@ -78,42 +78,22 @@ void wxStatusBarMac::InitColours() { if ( WX_IS_MACOS_AVAILABLE(10, 14) ) { - // FIXME: None of this is correct and is only very loose - // approximation. 10.14's dark mode uses dynamic colors that - // use desktop tinting. The only correct way to render the - // statusbar is to use windowBackgroundColor in a NSBox. - wxColour bg = wxSystemSettings::GetColour(wxSYS_COLOUR_APPWORKSPACE); - m_textActive = wxSystemSettings::GetColour(wxSYS_COLOUR_BTNTEXT); - m_textInactive = wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT); - if ( wxSystemSettings::GetAppearance().IsDark() ) { - // dark mode appearance - m_textActive = wxColour(0xB0, 0xB0, 0xB0); - m_bgActiveFrom = wxColour(0x32, 0x32, 0x34); - m_bgActiveTo = wxColour(0x29, 0x29, 0x2A); - m_borderActive = wxColour(0x00, 0x00, 0x00); - m_borderInactive = wxColour(0x00, 0x00, 0x00); + m_textActive = wxColour(0xA9, 0xA9, 0xA9); + m_textInactive = wxColour(0x67, 0x67, 0x67); } else { - m_bgActiveFrom = wxColour(0xE9, 0xE7, 0xEA); - m_bgActiveTo = wxColour(0xCD, 0xCB, 0xCE); - m_borderActive = wxColour(0xBA, 0xB8, 0xBB); - m_borderInactive = wxColour(0xC3, 0xC3, 0xC3); + m_textActive = wxColour(0x4B, 0x4B, 0x4B); + m_textInactive = wxColour(0xB1, 0xB1, 0xB1); } - SetBackgroundColour(bg); // inactive bg } - else + else // 10.10 Yosemite to 10.13: { - // 10.10 Yosemite to 10.13 : + m_textActive = wxColour(0x40, 0x40, 0x40); m_textInactive = wxColour(0x4B, 0x4B, 0x4B); - m_bgActiveFrom = wxColour(0xE9, 0xE7, 0xEA); - m_bgActiveTo = wxColour(0xCD, 0xCB, 0xCE); - m_borderActive = wxColour(0xBA, 0xB8, 0xBB); - m_borderInactive = wxColour(0xC3, 0xC3, 0xC3); - SetBackgroundColour(wxColour(0xF4, 0xF4, 0xF4)); // inactive bg } } @@ -165,10 +145,6 @@ void wxStatusBarMac::DoUpdateStatusText(int number) void wxStatusBarMac::OnPaint(wxPaintEvent& WXUNUSED(event)) { wxPaintDC dc(this); - dc.Clear(); - - int w, h; - GetSize( &w, &h ); // Notice that wxOSXGetKeyWindow (aka [NSApp keyWindow] used below is // subtly different from IsActive() (aka [NSWindow iskeyWindow]): the @@ -188,22 +164,9 @@ void wxStatusBarMac::OnPaint(wxPaintEvent& WXUNUSED(event)) break; } - if ( tlw == keyWindow ) - { - dc.GradientFillLinear(dc.GetSize(), m_bgActiveFrom, m_bgActiveTo, wxBOTTOM); + // Don't paint any background, that's handled by the OS. Only draw text: - // Finder statusbar border color - dc.SetPen(wxPen(m_borderActive, 2, wxPENSTYLE_SOLID)); - dc.SetTextForeground(m_textActive); - } - else - { - // Finder statusbar border color - dc.SetPen(wxPen(m_borderInactive, 2, wxPENSTYLE_SOLID)); - dc.SetTextForeground(m_textInactive); - } - - dc.DrawLine(0, 0, w, 0); + dc.SetTextForeground(tlw == keyWindow ? m_textActive : m_textInactive); if ( GetFont().IsOk() ) dc.SetFont(GetFont()); diff --git a/src/osx/cocoa/nonownedwnd.mm b/src/osx/cocoa/nonownedwnd.mm index 2068807142..d9702e6682 100644 --- a/src/osx/cocoa/nonownedwnd.mm +++ b/src/osx/cocoa/nonownedwnd.mm @@ -1288,6 +1288,12 @@ void wxNonOwnedWindowCocoaImpl::SetRepresentedFilename(const wxString& filename) [m_macWindow setRepresentedFilename:wxCFStringRef(filename).AsNSString()]; } +void wxNonOwnedWindowCocoaImpl::SetBottomBorderThickness(int thickness) +{ + [m_macWindow setAutorecalculatesContentBorderThickness:(thickness ? NO : YES) forEdge:NSMinYEdge]; + [m_macWindow setContentBorderThickness:thickness forEdge:NSMinYEdge]; +} + void wxNonOwnedWindowCocoaImpl::RestoreWindowLevel() { if ( [m_macWindow level] != m_macWindowLevel ) From d28771cfb527e3ca1ec092c8bf9144f0cb5dcd2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Va=CC=81clav=20Slavi=CC=81k?= Date: Fri, 1 Jan 2021 12:14:45 +0100 Subject: [PATCH 3/4] Tweak wxStatusBar size for macOS 11 Finder's status bar size increased by 4pt in Big Sur. --- src/osx/carbon/frame.cpp | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/src/osx/carbon/frame.cpp b/src/osx/carbon/frame.cpp index 0ca60a20b3..fdce201ced 100644 --- a/src/osx/carbon/frame.cpp +++ b/src/osx/carbon/frame.cpp @@ -24,14 +24,28 @@ #endif // WX_PRECOMP #include "wx/osx/private.h" +#include "wx/osx/private/available.h" + +namespace +{ + +int GetMacStatusbarHeight() +{ +#if __MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_16 + if ( WX_IS_MACOS_AVAILABLE(10, 16) ) + return 28; + else +#endif + return 24; +} + +} // anonymous namespace wxBEGIN_EVENT_TABLE(wxFrame, wxFrameBase) EVT_ACTIVATE(wxFrame::OnActivate) EVT_SYS_COLOUR_CHANGED(wxFrame::OnSysColourChanged) wxEND_EVENT_TABLE() -#define WX_MAC_STATUSBAR_HEIGHT 24 - // ---------------------------------------------------------------------------- // creation/destruction // ---------------------------------------------------------------------------- @@ -106,7 +120,7 @@ wxStatusBar *wxFrame::OnCreateStatusBar(int number, long style, wxWindowID id, wxStatusBar *statusBar; statusBar = new wxStatusBar(this, id, style, name); - statusBar->SetSize(100, WX_MAC_STATUSBAR_HEIGHT); + statusBar->SetSize(100, GetMacStatusbarHeight()); statusBar->SetFieldsCount(number); return statusBar; @@ -115,7 +129,7 @@ wxStatusBar *wxFrame::OnCreateStatusBar(int number, long style, wxWindowID id, void wxFrame::SetStatusBar(wxStatusBar *statbar) { wxFrameBase::SetStatusBar(statbar); - m_nowpeer->SetBottomBorderThickness(statbar ? WX_MAC_STATUSBAR_HEIGHT : 0); + m_nowpeer->SetBottomBorderThickness(statbar ? GetMacStatusbarHeight() : 0); } void wxFrame::PositionStatusBar() @@ -127,7 +141,7 @@ void wxFrame::PositionStatusBar() // Since we wish the status bar to be directly under the client area, // we use the adjusted sizes without using wxSIZE_NO_ADJUSTMENTS. - m_frameStatusBar->SetSize(0, h, w, WX_MAC_STATUSBAR_HEIGHT); + m_frameStatusBar->SetSize(0, h, w, GetMacStatusbarHeight()); } } #endif // wxUSE_STATUSBAR @@ -223,7 +237,7 @@ void wxFrame::DoGetClientSize(int *x, int *y) const #if wxUSE_STATUSBAR if ( GetStatusBar() && GetStatusBar()->IsShown() && y ) - *y -= WX_MAC_STATUSBAR_HEIGHT; + *y -= GetMacStatusbarHeight(); #endif #if wxUSE_TOOLBAR From 634f60ff2385ffc6465560b182672274420875a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Va=CC=81clav=20Slavi=CC=81k?= Date: Sat, 16 Jan 2021 18:30:45 +0100 Subject: [PATCH 4/4] Remove redundant code from wxStatusBarMac MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove a lot of Mac-specific code from wxStatusBarMac in favour of using shared wxStatusBarGeneric: - Now that wxFRAME_EX_METAL aka NSWindowStyleMaskTexturedBackground doesn’t affect text placement, there’s no reason for customized DrawFieldText(). As a side effect of this removal, ellipsizing fields is now supported. - Remove customized DoUpdateStatusText() code that is no longer needed. See https://github.com/wxWidgets/wxWidgets/pull/2160#pullrequestreview-563916013 --- include/wx/generic/statusbr.h | 2 +- include/wx/osx/statusbr.h | 4 +--- src/generic/statusbr.cpp | 6 +++-- src/osx/carbon/statbrma.cpp | 45 ----------------------------------- 4 files changed, 6 insertions(+), 51 deletions(-) diff --git a/include/wx/generic/statusbr.h b/include/wx/generic/statusbr.h index 8a3d73d4f7..a13ca9e133 100644 --- a/include/wx/generic/statusbr.h +++ b/include/wx/generic/statusbr.h @@ -70,7 +70,7 @@ protected: void OnSysColourChanged(wxSysColourChangedEvent& event); protected: - + virtual int GetEffectiveFieldStyle(int i) const { return m_panes[i].GetStyle(); } virtual void DrawFieldText(wxDC& dc, const wxRect& rc, int i, int textHeight); virtual void DrawField(wxDC& dc, int i, int textHeight); diff --git a/include/wx/osx/statusbr.h b/include/wx/osx/statusbr.h index ea931f998f..d80d5a9d78 100644 --- a/include/wx/osx/statusbr.h +++ b/include/wx/osx/statusbr.h @@ -31,9 +31,7 @@ public: void OnPaint(wxPaintEvent& event); protected: - virtual void DrawFieldText(wxDC& dc, const wxRect& rc, int i, int textHeight) wxOVERRIDE; - virtual void DrawField(wxDC& dc, int i, int textHeight) wxOVERRIDE; - virtual void DoUpdateStatusText(int number = 0) wxOVERRIDE; + virtual int GetEffectiveFieldStyle(int WXUNUSED(i)) const wxOVERRIDE { return wxSB_NORMAL; } virtual void InitColours() wxOVERRIDE; diff --git a/src/generic/statusbr.cpp b/src/generic/statusbr.cpp index b8494d4a9d..4993a3f23f 100644 --- a/src/generic/statusbr.cpp +++ b/src/generic/statusbr.cpp @@ -265,9 +265,11 @@ void wxStatusBarGeneric::DrawFieldText(wxDC& dc, const wxRect& rect, int i, int SetEllipsizedFlag(i, text != GetStatusText(i)); } -#if defined( __WXGTK__ ) || defined(__WXMAC__) +#if defined( __WXGTK__ ) xpos++; ypos++; +#elif defined(__WXMAC__) + xpos++; #endif // draw the text @@ -285,7 +287,7 @@ void wxStatusBarGeneric::DrawField(wxDC& dc, int i, int textHeight) if (rect.GetWidth() <= 0) return; // happens when the status bar is shrunk in a very small area! - int style = m_panes[i].GetStyle(); + int style = GetEffectiveFieldStyle(i); if (style == wxSB_RAISED || style == wxSB_SUNKEN) { // Draw border diff --git a/src/osx/carbon/statbrma.cpp b/src/osx/carbon/statbrma.cpp index 29e7b9fe76..91e78d80bc 100644 --- a/src/osx/carbon/statbrma.cpp +++ b/src/osx/carbon/statbrma.cpp @@ -97,51 +97,6 @@ void wxStatusBarMac::InitColours() } } -void wxStatusBarMac::DrawFieldText(wxDC& dc, const wxRect& rect, int i, int textHeight) -{ - int w, h; - GetSize( &w , &h ); - - wxString text(GetStatusText( i )); - - int xpos = rect.x + wxFIELD_TEXT_MARGIN + 1; - int ypos = 2 + (rect.height - textHeight) / 2; - - if ( MacGetTopLevelWindow()->GetExtraStyle() & wxFRAME_EX_METAL ) - ypos++; - - dc.SetClippingRegion(rect.x, 0, rect.width, h); - dc.DrawText(text, xpos, ypos); - dc.DestroyClippingRegion(); -} - -void wxStatusBarMac::DrawField(wxDC& dc, int i, int textHeight) -{ - wxRect rect; - GetFieldRect(i, rect); - - DrawFieldText(dc, rect, i, textHeight); -} - -void wxStatusBarMac::DoUpdateStatusText(int number) -{ - wxRect rect; - GetFieldRect(number, rect); - - int w, h; - GetSize( &w, &h ); - - rect.y = 0; - rect.height = h ; - - Refresh( true, &rect ); - // we should have to force the update here - // TODO Remove if no regressions occur -#if 0 - Update(); -#endif -} - void wxStatusBarMac::OnPaint(wxPaintEvent& WXUNUSED(event)) { wxPaintDC dc(this);