From 3380a2438d724f6525e0bb947e780735bf8824af Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sat, 2 Dec 2017 22:33:53 +0100 Subject: [PATCH 1/5] Fix scale factor confusion in wxMac wxBitmap implementation Merge ctors from (width, height) and (width, height, scale) into a single one because the former really should be just a special case of the latter for scale == 1 but, surprisingly and confusingly it wasn't, because the latter also multiplied the size by scale, meaning that width and height parameters had different meanings. This resulted in at least 3 bugs when using scale factors different from 1: first, copying bitmaps wasn't done correctly because as wxBitmapRefData copy ctor incorrectly scaled its size by scale again. And second, creating bitmap from wxImage whose size wasn't divisible by scale not just didn't work correctly but crashed when accessing memory outside of the image because (unnecessarily) dividing and multiplying the image size by scale wasn't idempotent. Finally, even for the images of even size (assuming scale factor of 2), bitmaps created from them used incorrect width and height, corresponding to the half of the image dimensions, instead of the same ones, as they're supposed to be (the scaled dimensions are supposed to be returned by GetScale{Width,Height} methods). Closes #17505. --- src/osx/core/bitmap.cpp | 27 +++++++-------------------- 1 file changed, 7 insertions(+), 20 deletions(-) diff --git a/src/osx/core/bitmap.cpp b/src/osx/core/bitmap.cpp index 16bec10892..52d161b17b 100644 --- a/src/osx/core/bitmap.cpp +++ b/src/osx/core/bitmap.cpp @@ -49,8 +49,7 @@ class WXDLLEXPORT wxBitmapRefData: public wxGDIRefData friend class WXDLLIMPEXP_FWD_CORE wxIcon; friend class WXDLLIMPEXP_FWD_CORE wxCursor; public: - wxBitmapRefData(int width , int height , int depth, double logicalscale); - wxBitmapRefData(int width , int height , int depth); + wxBitmapRefData(int width , int height , int depth, double logicalscale = 1.0); wxBitmapRefData(CGContextRef context); wxBitmapRefData(CGImageRef image, double scale); wxBitmapRefData(); @@ -106,8 +105,7 @@ public: int GetBytesPerRow() const { return m_bytesPerRow; } private : - bool Create(int width , int height , int depth); - bool Create(int width , int height , int depth, double logicalScale); + bool Create(int width , int height , int depth, double logicalscale); bool Create( CGImageRef image, double scale ); bool Create( CGContextRef bitmapcontext); void Init(); @@ -269,13 +267,7 @@ wxBitmapRefData::wxBitmapRefData() Init() ; } -wxBitmapRefData::wxBitmapRefData( int w , int h , int d ) -{ - Init() ; - Create( w , h , d ) ; -} - -wxBitmapRefData::wxBitmapRefData(int w , int h , int d, double logicalscale) +wxBitmapRefData::wxBitmapRefData( int w , int h , int d , double logicalscale) { Init() ; Create( w , h , d, logicalscale ) ; @@ -370,11 +362,12 @@ bool wxBitmapRefData::Create(CGContextRef context) return m_ok ; } -bool wxBitmapRefData::Create( int w , int h , int d ) +bool wxBitmapRefData::Create( int w , int h , int d, double logicalscale ) { m_width = wxMax(1, w); m_height = wxMax(1, h); m_depth = d ; + m_scaleFactor = logicalscale; m_hBitmap = NULL ; m_bytesPerRow = GetBestBytesPerRow( m_width * 4 ) ; @@ -395,12 +388,6 @@ bool wxBitmapRefData::Create( int w , int h , int d ) return m_ok ; } -bool wxBitmapRefData::Create( int w , int h , int d, double logicalScale ) -{ - m_scaleFactor = logicalScale; - return Create(w*logicalScale,h*logicalScale,d); -} - void wxBitmapRefData::UseAlpha( bool use ) { if ( m_hasAlpha == use ) @@ -1125,7 +1112,7 @@ bool wxBitmap::CreateScaled(int w, int h, int d, double logicalScale) if ( d < 0 ) d = wxDisplayDepth() ; - m_refData = new wxBitmapRefData( w , h , d, logicalScale ); + m_refData = new wxBitmapRefData( w*logicalScale , h*logicalScale , d, logicalScale ); return M_BITMAPDATA->IsOk() ; } @@ -1220,7 +1207,7 @@ wxBitmap::wxBitmap(const wxImage& image, int depth, double scale) wxBitmapRefData* bitmapRefData; - m_refData = bitmapRefData = new wxBitmapRefData( width/scale, height/scale, depth, scale) ; + m_refData = bitmapRefData = new wxBitmapRefData( width, height, depth, scale) ; if ( bitmapRefData->IsOk()) { From ad8d73cb15e39c4787a0ea71cb1759dc9921909f Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sat, 2 Dec 2017 23:11:10 +0100 Subject: [PATCH 2/5] Work around missing expanders in wxTreeListCtrl under Mac Re-indent the column containing the expanders explicitly if the control has just switched from "list" to "tree" mode. Closes #17409. --- src/generic/treelist.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/generic/treelist.cpp b/src/generic/treelist.cpp index 1880bee6a3..6dd3f275cb 100644 --- a/src/generic/treelist.cpp +++ b/src/generic/treelist.cpp @@ -482,6 +482,13 @@ wxTreeListModel::InsertItem(Node* parent, { // Not flat any more, this is a second level child. m_isFlat = false; + + // This is a hack needed to work around wxOSX wxDataViewCtrl + // implementation which removes the indent if it thinks that the model + // is flat. We need to re-add the indent back if it turns out that it + // isn't flat, in fact. + wxDataViewCtrl* const dvc = m_treelist->GetDataView(); + dvc->SetIndent(dvc->GetIndent()); } wxScopedPtr From 0eb456f08e7f6322232bfeb33c392a0c91913ea1 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sat, 2 Dec 2017 23:07:46 +0100 Subject: [PATCH 3/5] Revert "Fix wxTreeListCtrl under wxOSX" This reverts commit 28f96bdff022da758beb802b34b5bcda77d8031d as it isn't necessary any more after the fix in the previous commit. See #17409. --- include/wx/osx/cocoa/dataview.h | 2 -- src/osx/cocoa/dataview.mm | 30 ++++++++---------------------- 2 files changed, 8 insertions(+), 24 deletions(-) diff --git a/include/wx/osx/cocoa/dataview.h b/include/wx/osx/cocoa/dataview.h index 6587f97bd9..ffe1ac2e5d 100644 --- a/include/wx/osx/cocoa/dataview.h +++ b/include/wx/osx/cocoa/dataview.h @@ -551,8 +551,6 @@ private: wxCocoaOutlineDataSource* m_DataSource; wxCocoaOutlineView* m_OutlineView; - - bool m_removeIndentIfNecessary; }; #endif // _WX_DATAVIEWCTRL_COCOOA_H_ diff --git a/src/osx/cocoa/dataview.mm b/src/osx/cocoa/dataview.mm index 9b0207eb92..c48c9c976e 100644 --- a/src/osx/cocoa/dataview.mm +++ b/src/osx/cocoa/dataview.mm @@ -2033,8 +2033,7 @@ wxCocoaDataViewControl::wxCocoaDataViewControl(wxWindow* peer, [[NSScrollView alloc] initWithFrame:wxOSXGetFrameForControl(peer,pos,size)] ), m_DataSource(NULL), - m_OutlineView([[wxCocoaOutlineView alloc] init]), - m_removeIndentIfNecessary(false) + m_OutlineView([[wxCocoaOutlineView alloc] init]) { // initialize scrollview (the outline view is part of a scrollview): NSScrollView* scrollview = (NSScrollView*) GetWXWidget(); @@ -2408,11 +2407,13 @@ bool wxCocoaDataViewControl::AssociateModel(wxDataViewModel* model) m_DataSource = NULL; [m_OutlineView setDataSource:m_DataSource]; // if there is a data source the data is immediately going to be requested - // Set this to true to check if we need to remove the indent in the next - // OnSize() call: we can't do it directly here because the model might not - // be fully initialized yet and so might not know whether it has any items - // with children or not. - m_removeIndentIfNecessary = true; + // By default, the first column is indented to leave enough place for the + // expanders, but this looks bad if there are no expanders, so don't use + // indent in this case. + if ( model && model->IsListModel() ) + { + DoSetIndent(0); + } return true; } @@ -2577,21 +2578,6 @@ void wxCocoaDataViewControl::SetRowHeight(const wxDataViewItem& WXUNUSED(item), void wxCocoaDataViewControl::OnSize() { - if ( m_removeIndentIfNecessary ) - { - m_removeIndentIfNecessary = false; - - const wxDataViewModel* const model = GetDataViewCtrl()->GetModel(); - - // By default, the first column is indented to leave enough place for the - // expanders, but this looks bad if there are no expanders, so don't use - // indent in this case. - if ( model && model->IsListModel() ) - { - DoSetIndent(0); - } - } - if ([m_OutlineView numberOfColumns] == 1) [m_OutlineView sizeLastColumnToFit]; } From d3f20c3837533c6a54c82694a4ed6e5cbb020c4f Mon Sep 17 00:00:00 2001 From: sbrowne Date: Sun, 3 Dec 2017 00:15:03 +0100 Subject: [PATCH 4/5] Fix hang when reparenting a frozen window in wxOSX The wrong order of changing parent and freezing/thawing could result in hanging the application when reparenting frozen windows, e.g. when switching order of pages in a notebook. Closes #16722. --- src/osx/cocoa/window.mm | 56 ++++++++++++++++++++++++++++++++++++++--- src/osx/window_osx.cpp | 12 +++++++-- 2 files changed, 63 insertions(+), 5 deletions(-) diff --git a/src/osx/cocoa/window.mm b/src/osx/cocoa/window.mm index b218573f9e..1106b2b888 100644 --- a/src/osx/cocoa/window.mm +++ b/src/osx/cocoa/window.mm @@ -769,6 +769,30 @@ void wxWidgetCocoaImpl::SetupMouseEvent( wxMouseEvent &wxevent , NSEvent * nsEve } } +static void SetDrawingEnabledIfFrozenRecursive(wxWidgetCocoaImpl *impl, bool enable) +{ + if (!impl->GetWXPeer()) + return; + + if (impl->GetWXPeer()->IsFrozen()) + impl->SetDrawingEnabled(enable); + + for ( wxWindowList::iterator i = impl->GetWXPeer()->GetChildren().begin(); + i != impl->GetWXPeer()->GetChildren().end(); + ++i ) + { + wxWindow *child = *i; + if ( child->IsTopLevel() || !child->IsFrozen() ) + continue; + + // Skip any user panes as they'll handle this themselves + if ( !child->GetPeer() || child->GetPeer()->IsUserPane() ) + continue; + + SetDrawingEnabledIfFrozenRecursive((wxWidgetCocoaImpl *)child->GetPeer(), enable); + } +} + @implementation wxNSView + (void)initialize @@ -887,6 +911,24 @@ void wxWidgetCocoaImpl::SetupMouseEvent( wxMouseEvent &wxevent , NSEvent * nsEve return [super hitTest:aPoint]; } +- (void) viewWillMoveToWindow:(NSWindow *)newWindow +{ + wxWidgetCocoaImpl* viewimpl = (wxWidgetCocoaImpl*) wxWidgetImpl::FindFromWXWidget( self ); + if (viewimpl) + SetDrawingEnabledIfFrozenRecursive(viewimpl, true); + + [super viewWillMoveToWindow:newWindow]; +} + +- (void) viewDidMoveToWindow +{ + wxWidgetCocoaImpl* viewimpl = (wxWidgetCocoaImpl*) wxWidgetImpl::FindFromWXWidget( self ); + if (viewimpl) + SetDrawingEnabledIfFrozenRecursive(viewimpl, false); + + [super viewDidMoveToWindow]; +} + @end // wxNSView // We need to adopt NSTextInputClient protocol in order to interpretKeyEvents: to work. @@ -2486,7 +2528,7 @@ void wxWidgetCocoaImpl::Init() wxWidgetCocoaImpl::~wxWidgetCocoaImpl() { if ( GetWXPeer() && GetWXPeer()->IsFrozen() ) - [[m_osxView window] enableFlushWindow]; + SetDrawingEnabled(true); RemoveAssociations( this ); @@ -3034,6 +3076,10 @@ void wxWidgetCocoaImpl::SetDropTarget(wxDropTarget* target) void wxWidgetCocoaImpl::RemoveFromParent() { + // User panes will be thawed in the removeFromSuperview call below + if (!IsUserPane() && m_wxPeer->IsFrozen()) + SetDrawingEnabled(true); + [m_osxView removeFromSuperview]; } @@ -3043,8 +3089,9 @@ void wxWidgetCocoaImpl::Embed( wxWidgetImpl *parent ) wxASSERT_MSG( container != NULL , wxT("No valid mac container control") ) ; [container addSubview:m_osxView]; - if( m_wxPeer->IsFrozen() ) - [[m_osxView window] disableFlushWindow]; + // User panes will be frozen elsewhere + if( m_wxPeer->IsFrozen() && !IsUserPane() ) + SetDrawingEnabled(false); } void wxWidgetCocoaImpl::SetBackgroundColour( const wxColour &col ) @@ -3693,6 +3740,9 @@ void wxWidgetCocoaImpl::SetFlipped(bool flipped) void wxWidgetCocoaImpl::SetDrawingEnabled(bool enabled) { + if ( [m_osxView window] == nil ) + return; + if ( enabled ) { [[m_osxView window] enableFlushWindow]; diff --git a/src/osx/window_osx.cpp b/src/osx/window_osx.cpp index c725ef8d57..5928260429 100644 --- a/src/osx/window_osx.cpp +++ b/src/osx/window_osx.cpp @@ -1638,6 +1638,15 @@ void wxWindowMac::RemoveChild( wxWindowBase *child ) if ( child == m_growBox ) m_growBox = NULL ; #endif + if (!child->IsBeingDeleted() && !child->IsTopLevel()) + { + // Must be removed prior to RemoveChild and next AddChild call + // Otherwise the next AddChild may freeze the wrong window + wxWindowMac *mac = (wxWindowMac *)child; + if (mac->GetPeer() && mac->GetPeer()->IsOk()) + mac->GetPeer()->RemoveFromParent(); + } + wxWindowBase::RemoveChild( child ) ; } @@ -2458,10 +2467,9 @@ bool wxWindowMac::Reparent(wxWindowBase *newParentBase) if ( !wxWindowBase::Reparent(newParent) ) return false; - GetPeer()->RemoveFromParent(); GetPeer()->Embed( GetParent()->GetPeer() ); - MacChildAdded(); + GetParent()->MacChildAdded(); return true; } From c677e4e6526378ff3cd4a55abe628b8e9a190031 Mon Sep 17 00:00:00 2001 From: Paul Kulchenko Date: Thu, 9 Nov 2017 16:25:17 -0800 Subject: [PATCH 5/5] Fix crash on calltip click on macOS Commit b0d0494f fixed it for autocomplete popup, but a similar issue is still present for calltips. This commit fixes it. Closes https://github.com/wxWidgets/wxWidgets/pull/595 --- src/stc/ScintillaWX.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/stc/ScintillaWX.cpp b/src/stc/ScintillaWX.cpp index a18796220a..deaacadbfe 100644 --- a/src/stc/ScintillaWX.cpp +++ b/src/stc/ScintillaWX.cpp @@ -490,9 +490,10 @@ void ScintillaWX::NotifyParent(SCNotification scn) { // a side effect that the AutoComp will also not be destroyed when switching // to another window, but I think that is okay. void ScintillaWX::CancelModes() { - if (! focusEvent) + if (! focusEvent) { AutoCompleteCancel(); - ct.CallTipCancel(); + ct.CallTipCancel(); + } Editor::CancelModes(); }