Skip to content

Commit

Permalink
Merge pull request #200 from mcorino/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
mcorino authored Oct 20, 2023
2 parents 249836c + 25720ba commit 7d2d188
Show file tree
Hide file tree
Showing 13 changed files with 170 additions and 54 deletions.
2 changes: 0 additions & 2 deletions TODO

This file was deleted.

2 changes: 1 addition & 1 deletion ext/wxruby3/swig/wx.i
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ WXRUBY_EXPORT VALUE wxRuby_WrapWxObjectInRuby(wxObject *wx_obj)
// Otherwise, retrieve the swig type info for this class and wrap it
// in Ruby. wxRuby_GetSwigTypeForClass is defined in wx.i
swig_type_info* swig_type = wxRuby_GetSwigTypeForClass(r_class);
VALUE r_obj = SWIG_NewPointerObj(wx_obj, swig_type, 1);
VALUE r_obj = SWIG_NewPointerObj(wx_obj, swig_type, 0);
return r_obj;
}

Expand Down
6 changes: 0 additions & 6 deletions lib/wx/doc/event.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,4 @@ def clone; end

end

# Find a window with the focus, that is also a descendant of the given window.
# This is used to determine the window to initially send commands to.
# @param [Wx::Window] ancestor
# @return [Wx::Window,nil] descendant window of ancestor with focus
def self.find_focus_descendant(ancestor) end

end
5 changes: 5 additions & 0 deletions lib/wx/doc/window.rb
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,9 @@ def find_window_by_label(label) end
# @return [Wx::Window]
def find_window_by_name(name) end

# Switches the current sizer with the given sizer and detaches and returns the 'old' sizer.
# @param [Wx::Sizer] new_sizer new sizer for window
# @return [Wx::Sizer] previous window sizer
def switch_sizer(new_sizer) end

end
5 changes: 5 additions & 0 deletions rakelib/lib/director/dialog.rb
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,11 @@ def setup
end
spec.do_not_generate :functions
when 'wxPropertySheetDialog'
# need to adjust sizer arg name to apply disown specs
spec.ignore 'wxPropertySheetDialog::SetInnerSizer(wxSizer *)', ignore_doc: false
spec.extend_interface 'wxPropertySheetDialog',
'void SetInnerSizer(wxSizer *sizer_disown)'
spec.disown 'wxSizer *sizer_disown'
spec.ignore 'wxPropertySheetDialog::GetContentWindow'
# In Ruby a derived class with customized '#initialize' is far easier
spec.ignore 'wxPropertySheetDialog::CreateBookCtrl'
Expand Down
2 changes: 0 additions & 2 deletions rakelib/lib/director/event.rb
Original file line number Diff line number Diff line change
Expand Up @@ -201,8 +201,6 @@ class WXRUBY_EXPORT wxRubyCommandEvent : public wxCommandEvent
spec.add_swig_code %Q{%constant wxEventType wxEVT_MENU_HIGHLIGHT_ALL = wxEVT_MENU_HIGHLIGHT;}
# add event type constant missing from interface defs
spec.add_swig_code %Q{%constant wxEventType wxEVT_NC_PAINT = wxEVT_NC_PAINT;}
# add undocumented global function
spec.add_swig_code 'wxWindow* wxFindFocusDescendant(wxWindow* ancestor);'
end
super
end
Expand Down
65 changes: 64 additions & 1 deletion rakelib/lib/director/sizer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ class Sizer < Director

def setup
# Any nested sizers passed to Add() in are owned by C++, not GC'd by Ruby
spec.disown 'wxSizer* sizer'
case spec.module_name
when 'wxSizer'
spec.items << 'wxSizerFlags'
Expand All @@ -26,6 +25,64 @@ def setup
'wxSizer::Insert(size_t, wxSizerItem *)',
'wxSizer::Prepend(wxSizerItem *)'
spec.ignore 'wxSizer::Remove(wxWindow *)' # long time deprecated
# need to adjust sizer arg name to apply disown specs
spec.ignore 'wxSizer::Add(wxSizer *, const wxSizerFlags &)',
'wxSizer::Add(wxSizer *, int, int, int, wxObject *)',
'wxSizer::Insert(size_t, wxSizer *, const wxSizerFlags &)',
'wxSizer::Insert(size_t, wxSizer *, int, int, int, wxObject *)',
'wxSizer::Prepend(wxSizer *, const wxSizerFlags &)',
'wxSizer::Prepend(wxSizer *, int, int, int, wxObject *)',
ignore_doc: false
spec.extend_interface 'wxSizer',
'wxSizerItem* Add(wxSizer *sizer_disown, const wxSizerFlags &flags)',
'wxSizerItem* Add(wxSizer *sizer_disown, int proportion=0, int flag=0, int border=0, wxObject *userData=NULL)',
'wxSizerItem* Insert(size_t index, wxSizer *sizer_disown, const wxSizerFlags &flags)',
'wxSizerItem* Insert(size_t index, wxSizer *sizer_disown, int proportion=0, int flag=0, int border=0, wxObject *userData=NULL)',
'wxSizerItem* Prepend(wxSizer *sizer_disown, const wxSizerFlags &flags)',
'wxSizerItem* Prepend(wxSizer *sizer_disown, int proportion=0, int flag=0, int border=0, wxObject *userData=NULL)'
spec.disown 'wxSizer* sizer_disown'
# needs custom impl to transfer ownership of detached items
spec.ignore 'wxSizer::Detach(wxSizer*)',
'wxSizer::Detach(int)', ignore_doc: false
spec.add_extend_code 'wxSizer', <<~__HEREDOC
bool detach(wxSizer* szr)
{
if ($self->Detach(szr))
{
VALUE rb_szr = SWIG_RubyInstanceFor(szr);
if (rb_szr && !NIL_P(rb_szr))
{
// transfer ownership to Ruby
RDATA(rb_szr)->dfree = GcSizerFreeFunc;
}
return true;
}
return false;
}
bool detach(int itm_nr)
{
wxSizerItem* itm = $self->GetItem(itm_nr);
if (itm)
{
VALUE rb_szr = Qnil;
if (itm->IsSizer())
{
rb_szr = SWIG_RubyInstanceFor(itm->GetSizer());
}
if ($self->Detach(itm_nr))
{
if (rb_szr && !NIL_P(rb_szr))
{
// transfer ownership to Ruby
RDATA(rb_szr)->dfree = GcSizerFreeFunc;
}
return true;
}
}
return false;
}
__HEREDOC
# Typemap for GetChildren - convert to array of Sizer items
spec.map 'wxSizerItemList&' => 'Array<Wx::SizerItem>' do
map_out code: <<~__CODE
Expand All @@ -50,6 +107,12 @@ def setup
spec.gc_as_untracked 'wxGBSpan', 'wxGBPosition'
# cannot use this with wxRuby
spec.ignore 'wxGridBagSizer::Add(wxGBSizerItem *)'
# need to adjust sizer arg name to apply disown specs
spec.ignore 'wxGridBagSizer::Add(wxSizer *, const wxGBPosition &, const wxGBSpan &, int, int, wxObject *)',
ignore_doc: false
spec.extend_interface 'wxGridBagSizer',
'wxSizerItem *Add(wxSizer *sizer_disown, const wxGBPosition &pos, const wxGBSpan &span=wxDefaultSpan, int flag=0, int border=0, wxObject *userData=NULL)'
spec.disown 'wxSizer* sizer_disown'
end
# no real use for allowing these to be overloaded but a whole lot of grieve
# if we do allow it
Expand Down
22 changes: 22 additions & 0 deletions rakelib/lib/director/sizer_item.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,28 @@ def setup
# ignore constructors
spec.ignore 'wxSizerItem::wxSizerItem'
spec.ignore(%w[wxSizerItem::SetSizer wxSizerItem::SetSpacer wxSizerItem::SetWindow])
# need to adjust sizer arg name to apply disown specs
spec.ignore 'wxSizerItem::AssignSizer(wxSizer *)', ignore_doc: false
spec.extend_interface 'wxSizerItem',
'void AssignSizer(wxSizer *sizer_disown)'
spec.disown 'wxSizer *sizer_disown'
# needs custom impl to properly transfer ownership to Ruby
spec.ignore 'wxSizerItem::DetachSizer', ignore_doc: false
spec.add_extend_code 'wxSizerItem', <<~__HEREDOC
void detach_sizer()
{
if ($self->IsSizer())
{
VALUE rb_szr = SWIG_RubyInstanceFor($self->GetSizer());
if (rb_szr && !NIL_P(rb_szr))
{
// transfer ownership to Ruby
RDATA(rb_szr)->dfree = GcSizerFreeFunc;
}
$self->DetachSizer();
}
}
__HEREDOC
when 'wxGBSizerItem'
spec.make_abstract 'wxGBSizerItem'
# ignore constructors
Expand Down
4 changes: 0 additions & 4 deletions rakelib/lib/generate/doc/events.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -114,10 +114,6 @@
vb_pt = get_view_start # Top left corner of client

Wx::RegionIterator.for_region(get_update_region) do |region_it|

int vX,vY,vW,vH
wxRegionIterator upd(GetUpdateRegion()) # get the update rect list

region_it.each do |rct|
# rct == Dimensions of client area to repaint in pixels

Expand Down
9 changes: 1 addition & 8 deletions rakelib/lib/typemap/common.rb
Original file line number Diff line number Diff line change
Expand Up @@ -456,12 +456,10 @@ module Common
end


# Validators must be cast to correct subclass, but internal validator
# is a clone, and should not be freed, so disown after wrapping.
# Validators must be cast to correct subclass, but not owned
map 'wxValidator*' => 'Wx::Validator' do
map_out code: <<~__CODE
$result = wxRuby_WrapWxObjectInRuby($1);
if (!NIL_P($result)) RDATA($result)->dfree = SWIG_RubyRemoveTracking;
__CODE
end

Expand Down Expand Up @@ -633,11 +631,6 @@ module Common
end
end

# special case bc SWIG causes trouble in Window.cpp
map 'const wxRegion&', 'const wxRegion*', as: 'Wx::Region' do
map_out code: '$result = wxRuby_WrapWxObjectInRuby(new wxRegion(*static_cast<const wxRegion*> ($1)));'
end

# add type mapping for wxVariant input args
intypes = 'nil,String,Integer,Float,Time,Wx::Font,Wx::Colour,Wx::Variant,Array<WxVariant>,Array<String>,Object'
if Config.instance.features_set?('wxUSE_PROPGRID')
Expand Down
30 changes: 0 additions & 30 deletions samples/text/richtext.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1432,36 +1432,6 @@ def win_id=(id)

end

# Forward command events to the current rich text control, if any
def try_before(event)
if event.is_command_event && !event.is_a?(Wx::ChildFocusEvent)
# Problem: we can get infinite recursion because the events
# climb back up to this frame, and repeat.
# Assume that command events don't cause another command event
# to be called, so we can rely on inCommand not being overwritten

if MyFrame.win_id != event.id && MyFrame.event_type != event.event_type
MyFrame.event_type = event.event_type
MyFrame.win_id = event.id
focusWin = Wx.find_focus_descendant(self)
focusWin = @richTextCtrl unless focusWin

if focusWin && focusWin.get_event_handler.process_event(event)
MyFrame.event_type = 0
MyFrame.win_id = 0
return true
end

MyFrame.event_type = 0
MyFrame.win_id = 0
else
return false
end
end

false
end

# Write text
def write_initial_text
r = @richTextCtrl
Expand Down
29 changes: 29 additions & 0 deletions tests/test_book_controls.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Copyright (c) 2023 M.J.N. Corino, The Netherlands
#
# This software is released under the MIT license.

require_relative './lib/wxframe_runner'

class BookCtrlTests < WxRuby::Test::GUITests

def setup
super
@book = Wx::Choicebook.new(frame_win, name: 'ChoiceBook')
end

def cleanup
@book.destroy
super
GC.start
end

attr_reader :book

def test_control_sizer
btn = Wx::Button.new(book, Wx::ID_ANY, 'First')
# issue #199 : returning the control sizer should not cause it to be owned by Ruby
# because that would cause double deletes
book.get_control_sizer.add(btn, Wx::SizerFlags.new.expand.border(Wx::ALL))
end

end
43 changes: 43 additions & 0 deletions tests/test_sizer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Copyright (c) 2023 M.J.N. Corino, The Netherlands
#
# This software is released under the MIT license.

require_relative './lib/wxframe_runner'

class SizerTests < WxRuby::Test::GUITests

def setup
super
frame_win.set_sizer(Wx::VBoxSizer.new)
end

def cleanup
super
GC.start
end

def test_detach
frame_win.get_sizer.add(Wx::HBoxSizer.new)
frame_win.get_sizer.add_spacer(5)
# detaches HBoxSizer transferring ownership to Ruby; should not cause segfaults at GC
frame_win.get_sizer.detach(0)
end

def test_sizer_item_detach_and_re_attach
frame_win.get_sizer.add(Wx::HBoxSizer.new)
frame_win.get_sizer.add_spacer(5)
# get and detach
szr_itm = frame_win.get_sizer.get_item(0)
assert_not_nil(szr_itm)
assert_true(szr_itm.is_sizer)
szr = szr_itm.get_sizer
assert_not_nil(szr)
szr_itm.detach_sizer
assert_nil(szr_itm.get_sizer)
# remove sizer item
assert_true(frame_win.get_sizer.remove(0))
# re-attach detached sizer (should not cause segfaults at close due to incorrect ownership transfers)
assert_not_nil(frame_win.get_sizer.prepend(szr))
end

end

0 comments on commit 7d2d188

Please sign in to comment.