*System specification are as follow...
macOS Mojave -> Mac OS X 10.14.2
wxWidgets 3.1.2 -> --with-osx_cocoa --with-macosx-version-min=10.14 --with-macosx=MacOSX10.14.sdk
SFML 2.5.1 -> macOS OS X 10.7+, compatible with C++11 and libc++
The following code snippet, shown below, comes from a GitHub project that you can find at this link
https://gist.github.com/eriknelson/e4ccf32534eb3d25a1ea. Please give Eriknelson credit for his SFML 2.3+ into wxWidgets 3.0 integration demo. This demo is not prefect but it only has one flaw. The application crashes after closing the wxWidgets window.
#include <iostream>
#include <wx/wx.h>
#include <memory>
#include <SFML/Graphics.hpp>
#ifdef __WXGTK__
#include <gdk/gdkx.h>
#include <gtk/gtk.h>
#endif
using namespace std;
static const int kDefaultWindowWidth = 1280;
static const int kDefaultWindowHeight = 720;
static const int kCanvasMargin = 0;
struct wxSfmlCanvas : public wxControl, public sf::RenderWindow
{
wxSfmlCanvas(
wxWindow *parent = nullptr,
wxWindowID windowId = -1,
const wxPoint &position = wxDefaultPosition,
const wxSize &size = wxDefaultSize,
long style = 0) :
wxControl(parent, windowId, position, size, style)
{
createRenderWindow();
}
virtual void onUpdate(){};
void onIdle(wxIdleEvent& event)
{
// Send a paint message when control is idle, to ensure max framerate
Refresh();
}
void onPaint(wxPaintEvent& event)
{
wxPaintDC dc(this); // Prepare control to be repainted
onUpdate(); // Tick update
display(); // Draw
}
// Explicitly overriding prevents wxWidgets from drawing, which could result in flicker
void onEraseBackground(wxEraseEvent& event){}
void createRenderWindow()
{
#ifdef __WXGTK__
// gtk_widget_realize(m_wxwindow);
// gtk_widget_set_double_buffered(m_wxwindow, false);
// GdkWindow *gdkWindow = gtk_widget_get_window((GtkWidget*)GetHandle());
// XFlush(GDK_WINDOW_XDISPLAY(gdkWindow));
// sf::RenderWindow::create(GDK_WINDOW_XWINDOW(gdkWindow));
#else
sf::RenderWindow::create(GetHandle());
#endif
}
void setwxWindowSize(const wxSize& size)
{
this->SetSize(size);
}
void setRenderWindowSize(const sf::Vector2u& size)
{
this->setSize(size);
}
virtual ~wxSfmlCanvas(){};
wxDECLARE_EVENT_TABLE();
};
struct Canvas : public wxSfmlCanvas
{
Canvas(
wxWindow* parent,
wxWindowID id,
wxPoint position,
wxSize size,
long style = 0) :
wxSfmlCanvas(parent, id, position, size, style)
{
}
virtual void onUpdate()
{
clear(sf::Color::Yellow);
sf::CircleShape shape(50);
shape.setFillColor(sf::Color(150, 50, 250));
shape.setOutlineThickness(10);
shape.setOutlineColor(sf::Color(250, 150, 100));
sf::RectangleShape line(sf::Vector2f(150, 5));
line.rotate(45);
this->draw(shape);
this->draw(line);
}
void onResize(wxSizeEvent& event)
{
auto size = event.GetSize();
auto newCanvasWidth = size.x - (2 * kCanvasMargin);
auto newCanvasHeight = size.y - (2 * kCanvasMargin);
sf::Vector2u v(newCanvasWidth,newCanvasHeight);
wxSize s(newCanvasWidth,newCanvasHeight);
this->SetSize(s); //wx setSize
this->setSize(v); //SFML setSize
}
};
struct AppFrame : public wxFrame
{
AppFrame(const wxString& title, const wxPoint& pos, const wxSize& size) :
wxFrame(NULL, wxID_ANY, title, pos, size),
_panel(new wxPanel(this)),
_canvas(new Canvas(
_panel.get(),
wxID_ANY,
wxPoint(kCanvasMargin, kCanvasMargin),
wxSize(kDefaultWindowWidth - (2 * kCanvasMargin), kDefaultWindowHeight - (2 * kCanvasMargin))
))
{
_panel->SetBackgroundColour(*wxCYAN);
////////////////////////////////////////////////////////////////////////////////
// Probably due to some RTTI, IDE is getting confused by this dynamic call
// and doesn't understand the correct Bind overload. Causes non sequitur errors
// to display in the inspector. Suppress.
//
// Dynamic binding is cleanest here, since we don't want to hook up our resize
// handler until our dependencies (Canvas namely) have finished their initialization
////////////////////////////////////////////////////////////////////////////////
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wint-conversion"
Bind(wxEVT_SIZE, &AppFrame::onResize, this);
#pragma clang diagnostic pop
////////////////////////////////////////////////////////////////////////////////
}
void onResize(wxSizeEvent& event)
{
_canvas->onResize(event);
event.Skip();
}
unique_ptr<wxPanel> _panel;
unique_ptr<Canvas> _canvas;
};
struct App : public wxApp
{
virtual bool OnInit()
{
auto frame = new AppFrame("SFML Canvas Demo", wxPoint(100, 100),
wxSize(kDefaultWindowWidth, kDefaultWindowHeight));
frame->Show(true);
return true;
}
};
wxBEGIN_EVENT_TABLE(wxSfmlCanvas, wxControl)
EVT_IDLE(wxSfmlCanvas::onIdle)
EVT_PAINT(wxSfmlCanvas::onPaint)
EVT_ERASE_BACKGROUND(wxSfmlCanvas::onEraseBackground)
wxEND_EVENT_TABLE()
wxIMPLEMENT_APP(App);
His example runs as expected but upon closing the wxWidgets windows it crashes with the following error shown below.
rashed Thread: 0 Dispatch queue: com.apple.main-thread
Exception Type: EXC_CRASH (SIGABRT)
Exception Codes: 0x0000000000000000, 0x0000000000000000
Exception Note: EXC_CORPSE_NOTIFY
Termination Reason: Namespace OBJC, Code 0x1
Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
0 libsystem_kernel.dylib 0x00007fff64e7c01e __abort_with_payload + 10
1 libsystem_kernel.dylib 0x00007fff64e77541 abort_with_payload_wrapper_internal + 82
2 libsystem_kernel.dylib 0x00007fff64e774ef abort_with_reason + 22
3 libobjc.A.dylib 0x00007fff63c58674 _objc_fatalv(unsigned long long, unsigned long long, char const*, __va_list_tag*) + 108
4 libobjc.A.dylib 0x00007fff63c58526 _objc_fatal(char const*, ...) + 135
5 libobjc.A.dylib 0x00007fff63c62525 (anonymous namespace)::AutoreleasePoolPage::fastcheck(bool) + 125
6 libobjc.A.dylib 0x00007fff63c4a9f7 (anonymous namespace)::AutoreleasePoolPage::pop(void*) + 65
7 com.apple.CoreFoundation 0x00007fff37ab9ee6 _CFAutoreleasePoolPop + 22
8 com.apple.Foundation 0x00007fff39e66a5e -[NSAutoreleasePool drain] + 144
9 org.sfml-dev.sfml-window 0x000000010ffc86a5 drainThreadPool() + 37
10 org.sfml-dev.sfml-window 0x000000010ffc76e4 sf::priv::WindowImplCocoa::~WindowImplCocoa() + 148
11 org.sfml-dev.sfml-window 0x000000010ffc772f sf::priv::WindowImplCocoa::~WindowImplCocoa() + 15
12 org.sfml-dev.sfml-window 0x000000010ffb85ca sf::Window::~Window() + 58
13 org.wxwindows. 0x000000010fe8dc75 wxSfmlCanvas::~wxSfmlCanvas() + 37 (main.cpp:73)
14 org.wxwindows. 0x000000010fe8dc45 Canvas::~Canvas() + 21 (main.cpp:78)
15 org.wxwindows. 0x000000010fe8d505 Canvas::~Canvas() + 21 (main.cpp:78)
16 org.wxwindows. 0x000000010fe8d529 Canvas::~Canvas() + 25 (main.cpp:78)
17 org.wxwindows. 0x000000010fe8e740 AppFrame::~AppFrame() + 304 (memory:2285)
18 org.wxwindows. 0x000000010fe8b335 AppFrame::~AppFrame() + 21 (main.cpp:125)
19 org.wxwindows. 0x000000010fe8b359 AppFrame::~AppFrame() + 25 (main.cpp:125)
20 libwx_osx_cocoau-3.1.2.0.0.dylib 0x000000010fffdd3d wxAppConsoleBase::ProcessIdle() + 157
21 libwx_osx_cocoau-3.1.2.0.0.dylib 0x0000000110238476 wxAppBase::ProcessIdle() + 22
22 libwx_osx_cocoau-3.1.2.0.0.dylib 0x000000011018550a wxApp::ProcessIdle() + 26
23 libwx_osx_cocoau-3.1.2.0.0.dylib 0x00000001100e41fc wxCFEventLoop::OSXCommonModeObserverCallBack(__CFRunLoopObserver*, int, void*) + 92
24 com.apple.CoreFoundation 0x00007fff37b459cd __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 23
25 com.apple.CoreFoundation 0x00007fff37b45902 __CFRunLoopDoObservers + 452
26 com.apple.CoreFoundation 0x00007fff37ae7558 __CFRunLoopRun + 1469
27 com.apple.CoreFoundation 0x00007fff37ae6d48 CFRunLoopRunSpecific + 463
28 com.apple.HIToolbox 0x00007fff36d7dab5 RunCurrentEventLoopInMode + 293
29 com.apple.HIToolbox 0x00007fff36d7d7eb ReceiveNextEventCommon + 618
30 com.apple.HIToolbox 0x00007fff36d7d568 _BlockUntilNextEventMatchingListInModeWithFilter + 64
31 com.apple.AppKit 0x00007fff35038363 _DPSNextEvent + 997
32 com.apple.AppKit 0x00007fff35037102 -[NSApplication(NSEvent) _nextEventMatchingEventMask:untilDate:inMode:dequeue:] + 1362
33 com.apple.AppKit 0x00007fff35031165 -[NSApplication run] + 699
34 libwx_osx_cocoau-3.1.2.0.0.dylib 0x00000001101f0dff wxGUIEventLoop::OSXDoRun() + 207
35 libwx_osx_cocoau-3.1.2.0.0.dylib 0x00000001100e4ab1 wxCFEventLoop::DoRun() + 49
36 libwx_osx_cocoau-3.1.2.0.0.dylib 0x000000011002fcae wxEventLoopBase::Run() + 158
37 libwx_osx_cocoau-3.1.2.0.0.dylib 0x000000010fffda13 wxAppConsoleBase::MainLoop() + 99
38 libwx_osx_cocoau-3.1.2.0.0.dylib 0x000000011018555a wxApp::OnRun() + 26
39 libwx_osx_cocoau-3.1.2.0.0.dylib 0x0000000110067763 wxEntry(int&, wchar_t**) + 131
40 org.wxwindows. 0x000000010fe883b6 main + 38 (main.cpp:182)
41 libdyld.dylib 0x00007fff64d24ed9 start + 1
Thread 1:
0 libsystem_pthread.dylib 0x00007fff64f173f8 start_wqthread + 0
1 ??? 0x0000000054485244 0 + 1414025796
Thread 2:: Dispatch queue: NSCGSDisableUpdates
0 libsystem_kernel.dylib 0x00007fff64e5e17a mach_msg_trap + 10
1 libsystem_kernel.dylib 0x00007fff64e5e6d0 mach_msg + 60
2 com.apple.SkyLight 0x00007fff5dc44bc5 CGSUpdateManager::enable_updates_common() + 577
3 com.apple.SkyLight 0x00007fff5dbe7e3b CGSUpdateManager::enable_update(unsigned long long) + 317
4 libdispatch.dylib 0x00007fff64cd5d53 _dispatch_call_block_and_release + 12
5 libdispatch.dylib 0x00007fff64cd6dcf _dispatch_client_callout + 8
6 libdispatch.dylib 0x00007fff64cdd124 _dispatch_lane_serial_drain + 618
7 libdispatch.dylib 0x00007fff64cddbdc _dispatch_lane_invoke + 388
8 libdispatch.dylib 0x00007fff64ce6090 _dispatch_workloop_worker_thread + 603
9 libsystem_pthread.dylib 0x00007fff64f1760b _pthread_wqthread + 409
10 libsystem_pthread.dylib 0x00007fff64f17405 start_wqthread + 13
Thread 3:
0 libsystem_pthread.dylib 0x00007fff64f173f8 start_wqthread + 0
1 ??? 0x0000000054485244 0 + 1414025796
Thread 4:: com.apple.NSEventThread
0 libsystem_kernel.dylib 0x00007fff64e5e17a mach_msg_trap + 10
1 libsystem_kernel.dylib 0x00007fff64e5e6d0 mach_msg + 60
2 com.apple.CoreFoundation 0x00007fff37ae80c2 __CFRunLoopServiceMachPort + 337
3 com.apple.CoreFoundation 0x00007fff37ae7611 __CFRunLoopRun + 1654
4 com.apple.CoreFoundation 0x00007fff37ae6d48 CFRunLoopRunSpecific + 463
5 com.apple.AppKit 0x00007fff35040f89 _NSEventThread + 160
6 libsystem_pthread.dylib 0x00007fff64f18305 _pthread_body + 126
7 libsystem_pthread.dylib 0x00007fff64f1b26f _pthread_start + 70
8 libsystem_pthread.dylib 0x00007fff64f17415 thread_start + 13
Thread 5:
0 libsystem_pthread.dylib 0x00007fff64f173f8 start_wqthread + 0
Thread 0 crashed with X86 Thread State (64-bit):
rax: 0x0000000002000209 rbx: 0x0000000000000080 rcx: 0x00007ffedfd767c8 rdx: 0x0000000000000000
rdi: 0x0000000000000008 rsi: 0x0000000000000001 rbp: 0x00007ffedfd76810 rsp: 0x00007ffedfd767c8
r8: 0x00007febce519d50 r9: 0x0000000000000080 r10: 0x0000000000000000 r11: 0x0000000000000246
r12: 0x0000000000000000 r13: 0x0000000000000000 r14: 0x0000000000000001 r15: 0x0000000000000008
rip: 0x00007fff64e7c01e rfl: 0x0000000000000246 cr2: 0x0000000116681000
Logical CPU: 0
Error Code: 0x02000209
Trap Number: 133
I suspect wxControl and sf::RenderWindows are trying the close the NSView, which comes from the GetHandle() call, at the same time. Before I start dissecting through wxWidgets and SFML source with a debugger, I would like to ask if anyone here have a solution for gracefully handling this scenario.
Meanwhile, I will be actively debugging this issue while this forum post is active. If I find a solution first, I will most definitely update this post with the solution as reference for all who have or will encounter this issue in the future.
-James Harris