fix wx 2.8 compat, debug logging works everywhere

Fix backcompat with wx 2.8. This involved writing
wxPositiveDoubleValidator and rewiring the DrawingPanel inheritance tree
and event handling mechanisms (because 2.8 does not have ->Bind, only
->Connect which is less flexible.) As a result all the event handling
has been gathered into GameArea and the affected code is somewhat
cleaner. 2.8 support is untested on Mac because it requires 32 bit libs
and Carbon.

Add support for cross-compiling for windows using the Fedora MinGW
packages in ./installdeps.

Check for OpenGL support in the wx library being linked, this was
necessary because the Fedora MinGW wx library does not have OpenGL
support.

Remove vbamDebug() in favor of wxLogDebug(), and add an override for it
so that it works in non-debug builds of wx as well as on Windows. Turn
off buffering on stdout and stderr on startup so that debug logging
works in msys2/cygwin mintty as well.

On Windows, build a console binary for debug builds.

Update README.md to reflect Fedora MinGW support and debug logging
support.

Add -Wextra to cflags for debug builds.
This commit is contained in:
Rafael Kitover 2017-01-25 10:53:05 -08:00
parent 82d694df3a
commit fdc389c280
15 changed files with 402 additions and 164 deletions

View File

@ -124,13 +124,21 @@ ENDIF()
FIND_PACKAGE(ZLIB REQUIRED)
FIND_PACKAGE(OpenGL REQUIRED)
# TODO: make static on mac
# TODO: make static on mac and fedora cross-compiles
FIND_PACKAGE(PNG REQUIRED)
IF(APPLE AND NOT MACPORTS)
SET(SDL2_STATIC ON)
ENDIF()
IF(EXISTS /etc/redhat-release)
SET(FEDORA_HOST ON)
ENDIF()
IF(WINDOWS AND FEDORA_HOST)
SET(SDL2_STATIC ON)
ENDIF()
FIND_PACKAGE(SDL2 REQUIRED)
ADD_DEFINITIONS(${SDL2_DEFINITIONS})
@ -299,8 +307,8 @@ IF(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
ENDIF(MINGW)
IF(CMAKE_BUILD_TYPE STREQUAL Debug)
SET(MY_C_FLAGS ${MY_C_FLAGS} ${MY_C_AND_CXX_DBG_FLAGS} -Wall)
SET(MY_CXX_FLAGS ${MY_CXX_FLAGS} ${MY_C_AND_CXX_DBG_FLAGS} -Wall)
SET(MY_C_FLAGS ${MY_C_FLAGS} ${MY_C_AND_CXX_DBG_FLAGS} -Wall -Wextra)
SET(MY_CXX_FLAGS ${MY_CXX_FLAGS} ${MY_C_AND_CXX_DBG_FLAGS} -Wall -Wextra)
ELSE()
SET(MY_C_FLAGS ${MY_C_FLAGS} ${MY_C_AND_CXX_OPT_FLAGS} -Wno-error)
SET(MY_CXX_FLAGS ${MY_CXX_FLAGS} ${MY_C_AND_CXX_OPT_FLAGS} -Wno-error)

View File

@ -142,10 +142,15 @@ IF(NOT APPLE)
FIND_PACKAGE(Threads)
ENDIF(NOT APPLE)
# MinGW needs an additional link flag, -mwindows
# MinGW needs an additional link flag, -mwindows (to make a GUI app)
# but we only add it when not making a Debug build.
# It's total link flags should look like -lmingw32 -lSDL2main -lSDL2 -mwindows
IF(MINGW)
SET(MINGW32_LIBRARY -lmingw32 -mwindows CACHE STRING "mwindows for MinGW")
SET(MINGW32_LIBRARY -lmingw32 CACHE STRING "MinGW library")
IF(NOT CMAKE_BUILD_TYPE STREQUAL Debug)
SET(MINGW32_LIBRARY ${MINGW32_LIBRARY} -mwindows)
ENDIF()
ENDIF(MINGW)
IF(SDL2_LIBRARY_TEMP)

View File

@ -60,6 +60,9 @@ value of `$MSYSTEM`.) It will not run in the MSys shell.
On Debian/Ubuntu this uses the MXE apt repository and works really well.
On Fedora it can build using the Fedora MinGW packages, albeit with wx 2.8, no
OpenGL support, and no Link support for lack of SFML.
On Arch it currently doesn't work at all because the AUR stuff is completely
broken, I will at some point redo the arch stuff to use MXE as well.
@ -110,8 +113,8 @@ To run the resulting binary, you can simply type:
in the shell where you built it.
**NOTE:** you will not see debug console messages because it is a GUI app, we
will try to fix this for debug builds.
If you built with `-DCMAKE_BUILD_TYPE=Debug`, you will get a console app and
will see debug messages, even in mintty.
If you want to start the binary from e.g. a shortcut or Explorer, you will need
to put `c:\msys64\mingw32\bin` for 32 bit builds and `c:\msys64\mingw64\bin`
@ -123,6 +126,26 @@ depends on, they can install to the same directory as the binary.
For our own builds, we use MXE to make static builds.
## Debug Messages
We have an override for `wxLogDebug()` to make it work even in non-debug builds
of wx and on windows, even in mintty. Using this function for console debug
messages is recommended.
It works like `printf()`, but using `wxString`, so use `wxT()` e.g.:
```cpp
int foo = 42;
wxLogDebug(wxT("the value of foo = %d"), foo);
```
`%s` does not work for `wxString`, so use concatenation instead, e.g.:
```cpp
wxString world = "world";
wxLogDebug(wxT("Hello, ") + world + wxT("!"));
```
## CONTRIBUTING
Please keep in mind that this app needs to run on Windows, Linux and Mac OS X at

View File

@ -92,11 +92,13 @@ error() {
}
warning() {
[ -z "$1" ] && return 0
printf '\nWARNING: %s.\n\n' "$1" >&2
}
info_msg() {
[ -z "$1" ] && return 0
printf '\nINFO: %s.\n\n' "$1" >&2
}
@ -167,8 +169,8 @@ check_cross() {
fi
fi
if [ -z "$arch_linux" -a -z "$msys2" -a -z "$debian" ]; then
error 'cross compiling targets are only supported on Debian/Ubuntu, Arch Linux and MSYS2 at the moment'
if [ -z "$arch_linux" -a -z "$msys2" -a -z "$debian" -a -z "$fedora" ]; then
error 'cross compiling targets are only supported on Debian/Ubuntu, Fedora, Arch Linux and MSYS2 at the moment'
fi
target=$(echo "$target" | tr 'A-Z' 'a-z')
@ -240,23 +242,55 @@ fedora_installdeps() {
check_cross
installing
warning=
# make sure rpmfusion is installed for ffmpeg
check sudo su -c 'dnf -y install https://download1.rpmfusion.org/free/fedora/rpmfusion-free-release-$(rpm -E %fedora).noarch.rpm https://download1.rpmfusion.org/nonfree/fedora/rpmfusion-nonfree-release-$(rpm -E %fedora).noarch.rpm'
# non-multiarch packages first
check sudo dnf -y install gcc gcc-c++ make cmake git nasm
check sudo dnf -y install gcc gcc-c++ make cmake git nasm redhat-rpm-config
# install both 64bit and 32bit versions on 64 bit hosts
set --
for pkg in pkgconfig zlib-devel mesa-libGL-devel ffmpeg-devel gettext-devel libjpeg-turbo-devel libpng-devel libtiff-devel SDL2-devel SFML-devel openal-soft-devel wxGTK3-devel; do
if [ -n "$amd64" ]; then
set -- "$@" "${pkg}.x86_64" "${pkg}.i686"
else
set -- "$@" "$pkg"
fi
done
if [ -z "$target" ]; then
# install both 64bit and 32bit versions on 64 bit hosts
for pkg in pkgconfig zlib-devel mesa-libGL-devel ffmpeg-devel gettext-devel libjpeg-turbo-devel libpng-devel libtiff-devel SDL2-devel SFML-devel openal-soft-devel wxGTK3-devel; do
if [ -n "$amd64" ]; then
set -- "$@" "${pkg}.x86_64" "${pkg}.i686"
else
set -- "$@" "$pkg"
fi
done
else # mingw build
set -- "$@" pkgconfig
case "$target" in
mingw-w64-i686)
target=mingw32
cmake_flags='-DCMAKE_TOOLCHAIN_FILE=../CMakeScripts/Toolchain-cross-MinGW-w64-i686.cmake -DENABLE_LINK=NO'
;;
mingw-w64-x86_64)
target=mingw64
cmake_flags='-DCMAKE_TOOLCHAIN_FILE=../CMakeScripts/Toolchain-cross-MinGW-w64-x86_64.cmake -DENABLE_LINK=NO'
;;
*)
error 'unknown cross target (this should not happen)'
;;
esac
# install static deps
for pkg in zlib gettext libjpeg-turbo libpng libtiff SDL2 wxWidgets; do
set -- "$@" "${target}-${pkg}-static"
done
# install deps that are not available as static
for pkg in openal-soft; do
set -- "$@" "${target}-${pkg}"
done
warning='SFML is required for LINK support, Fedora does not currently have a MinGW SFML package, if you want LINK support you will need to install it manually'
fi
check sudo dnf -y install "$@"
warning "$warning"
build_instructions
}

View File

@ -48,23 +48,74 @@ endif(ENABLE_OPENAL)
IF(CMAKE_BUILD_TYPE STREQUAL "Debug")
SET(wxWidgets_USE_DEBUG ON) # noop if wx is compiled with --disable-debug, like in Mac Homebrew atm
# and if this is the case, we can't set debug level without link failing
IF(NOT wxWidgets_DEFINITIONS MATCHES "-DwxDEBUG_LEVEL=0")
ADD_DEFINITIONS(-DwxDEBUG_LEVEL=1)
ENDIF()
ENDIF()
IF(APPLE)
IF(APPLE OR (WINDOWS AND FEDORA_HOST))
SET(wxWidgets_USE_STATIC ON)
ENDIF(APPLE)
ENDIF()
SET(wxWidgets_USE_UNICODE ON)
# adv is for wxAboutBox
# xml, html is for xrc
SET( wxWidgets_USE_LIBS xrc xml html adv gl net core base )
SET(wxWidgets_USE_LIBS xrc xml html adv gl net core base gl)
#list(APPEND wxWidgets_CONFIG_OPTIONS --version=2.8)
FIND_PACKAGE ( wxWidgets REQUIRED )
FIND_PACKAGE(wxWidgets REQUIRED)
INCLUDE_DIRECTORIES(${wxWidgets_INCLUDE_DIRS})
IF(CMAKE_BUILD_TYPE STREQUAL "Debug")
# tell wx to enable debug mode if possible, if the cmake module did not do it for us
EXECUTE_PROCESS(COMMAND "${wxWidgets_CONFIG_EXECUTABLE} --debug=yes" RESULT_VARIABLE WX_CONFIG_DEBUG OUTPUT_QUIET ERROR_QUIET)
IF(WX_CONFIG_DEBUG EQUAL 0)
ADD_DEFINITIONS(-DwxDEBUG_LEVEL=1)
ENDIF()
# this one should be safe in non-debug builds too
ADD_DEFINITIONS(-DWXDEBUG)
ENDIF()
# check if this build of wx actually has OpenGL support
SET(CURRENT_CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES})
SET(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} ${wxWidgets_LIBRARIES})
SET(CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS} ${wxWidgets_CXX_FLAGS} -fPIC)
SET(CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES} ${wxWidgets_INCLUDE_DIRS})
FOREACH(DEF ${wxWidgets_DEFINITIONS})
SET(CMAKE_REQUIRED_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS} "-D${DEF}")
ADD_DEFINITIONS("-D${DEF}")
ENDFOREACH()
# CheckCXXSourceCompiles ignores compiler flags, so we have to stuff them into the definitions
SET(CURRENT_CMAKE_REQUIRED_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS})
SET(CMAKE_REQUIRED_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS} ${CMAKE_REQUIRED_FLAGS})
INCLUDE(CheckCXXSourceCompiles)
CHECK_CXX_SOURCE_COMPILES("
#include <wx/config.h>
#include <wx/glcanvas.h>
int main(int argc, char** argv) {
wxGLCanvas canvas(NULL, wxID_ANY, NULL, wxPoint(0, 0), wxSize(300, 300), 0);
return 0;
}" WX_HAS_OPENGL)
IF(NOT WX_HAS_OPENGL)
ADD_DEFINITIONS(-DNO_OGL)
LIST(REMOVE_ITEM wxWidgets_USE_LIBS gl)
FIND_PACKAGE(wxWidgets REQUIRED)
ENDIF()
SET(CMAKE_REQUIRED_LIBRARIES ${CURRENT_CMAKE_REQUIRED_LIBRARIES})
SET(CMAKE_REQUIRED_DEFINITIONS ${CURRENT_CMAKE_REQUIRED_DEFINITIONS})
# end of wx OpenGL check
FOREACH(CXX_COMPILE_FLAG ${wxWidgets_CXX_FLAGS})
ADD_COMPILE_OPTIONS($<$<COMPILE_LANGUAGE:CXX>:${CXX_COMPILE_FLAG}>)
ENDFOREACH()
#EXECUTE_PROCESS(COMMAND sh "${wxWidgets_CONFIG_EXECUTABLE}" --cxxflags)
INCLUDE( ${wxWidgets_USE_FILE} )
FIND_PACKAGE ( Gettext REQUIRED )
@ -248,6 +299,12 @@ TARGET_LINK_LIBRARIES (
${DIRECTX_LIBRARIES}
${CAIRO_LIBRARIES}
)
# Build a console app in debug mode on Windows
IF(WIN32 AND CMAKE_BUILD_TYPE STREQUAL Debug)
SET(CMAKE_CXX_LINK_EXECUTABLE "${CMAKE_CXX_LINK_EXECUTABLE} -Wl,--subsystem,console")
ENDIF()
IF(WIN32)
INSTALL(PROGRAMS ${PROJECT_BINARY_DIR}/visualboyadvance-m${CMAKE_EXECUTABLE_SUFFIX} DESTINATION ${CMAKE_BINARY_DIR})
ENDIF(WIN32)

View File

@ -2270,7 +2270,7 @@ EVT_HANDLER_MASK(DisplayConfigure, "Display options...", CMDEN_NREC_ANY)
}
if (panel->panel) {
panel->panel->Delete();
panel->panel->Destroy();
panel->panel = NULL;
}
@ -2288,7 +2288,7 @@ EVT_HANDLER_MASK(ChangeFilter, "Change Pixel Filter", CMDEN_NREC_ANY)
update_opts();
if (panel->panel) {
panel->panel->Delete();
panel->panel->Destroy();
panel->panel = NULL;
}
}
@ -2299,7 +2299,7 @@ EVT_HANDLER_MASK(ChangeIFB, "Change Interframe Blending", CMDEN_NREC_ANY)
update_opts();
if (panel->panel) {
panel->panel->Delete();
panel->panel->Destroy();
panel->panel = NULL;
}
}

View File

@ -3,21 +3,33 @@
#include "wxvbam.h"
class BasicDrawingPanel : public DrawingPanel, public wxPanel {
class BasicDrawingPanel : public DrawingPanel {
public:
BasicDrawingPanel(wxWindow* parent, int _width, int _height);
protected:
void DrawArea(wxWindowDC& dc);
virtual void DrawImage(wxWindowDC& dc, wxImage* im);
DECLARE_CLASS()
};
// wx <= 2.8 may not be compiled with opengl support
#if !wxCHECK_VERSION(2, 9, 0) && !wxUSE_GLCANVAS
#define NO_OGL
#endif
#ifndef NO_OGL
#include <wx/glcanvas.h>
class GLDrawingPanel : public DrawingPanel, public wxGLCanvas {
// shuffled parms for 2.9 indicates non-auto glcontext
// before 2.9, wxMAC does not have this (but wxGTK & wxMSW do)
#if !wxCHECK_VERSION(2, 9, 0) && defined(__WXMAC__)
#define wxglc(a, b, c, d, e, f) wxGLCanvas(a, b, d, e, f, wxEmptyString, c)
#define wxGL_IMPLICIT_CONTEXT
#else
#define wxglc wxGLCanvas
#endif
class GLDrawingPanel : public DrawingPanelBase, public wxGLCanvas {
public:
GLDrawingPanel(wxWindow* parent, int _width, int _height);
virtual ~GLDrawingPanel();
@ -26,33 +38,29 @@ protected:
void DrawArea(wxWindowDC& dc);
void OnSize(wxSizeEvent& ev);
void AdjustViewport();
#if wxCHECK_VERSION(2, 9, 0)
#ifndef wxGL_IMPLICIT_CONTEXT
wxGLContext* ctx;
#endif
void DrawingPanelInit();
GLuint texid, vlist;
int texsize;
DECLARE_CLASS()
};
#endif
#if defined(__WXMSW__) && !defined(NO_D3D)
class DXDrawingPanel : public DrawingPanel, public wxPanel {
class DXDrawingPanel : public DrawingPanel {
public:
DXDrawingPanel(wxWindow* parent, int _width, int _height);
protected:
void DrawArea(wxWindowDC&);
DECLARE_CLASS()
};
#endif
#ifndef NO_CAIRO
#include <cairo.h>
class CairoDrawingPanel : public DrawingPanel, public wxPanel {
class CairoDrawingPanel : public DrawingPanel {
public:
CairoDrawingPanel(wxWindow* parent, int _width, int _height);
~CairoDrawingPanel();
@ -60,8 +68,6 @@ public:
protected:
void DrawArea(wxWindowDC&);
cairo_surface_t* conv_surf;
DECLARE_CLASS()
};
#endif
@ -70,9 +76,6 @@ class Quartz2DDrawingPanel : public BasicDrawingPanel {
public:
Quartz2DDrawingPanel(wxWindow* parent, int _width, int _height);
virtual void DrawImage(wxWindowDC& dc, wxImage* im);
protected:
DECLARE_CLASS()
};
#endif

View File

@ -2899,10 +2899,10 @@ bool MainFrame::BindControls()
tc = SafeXRCCTRL<wxTextCtrl>(d, n); \
tc->SetValidator(wxTextValidator(wxFILTER_NONE, &o)); \
} while (0)
#define getgtc(n, o) \
#define getdtc(n, o) \
do { \
tc = SafeXRCCTRL<wxTextCtrl>(d, n); \
tc->SetValidator(wxGenericValidator(&o)); \
tc->SetValidator(wxPositiveDoubleValidator(&o)); \
} while (0)
#ifndef NO_LINK
{
@ -3297,9 +3297,9 @@ bool MainFrame::BindControls()
/// On-Screen Display
ch = GetValidatedChild<wxChoice, wxGenericValidator>(d, "SpeedIndicator", wxGenericValidator(&showSpeed));
/// Zoom
getdtc("DefaultScale", gopts.video_scale);
// this was a choice, but I'd rather not have to make an off-by-one
// validator just for this, and spinctrl is good enough.
getgtc("DefaultScale", gopts.video_scale);
getsc("MaxScale", maxScale);
/// Basic
getrbi("OutputSimple", gopts.render_method, RND_SIMPLE);

View File

@ -41,8 +41,6 @@ void HiDPIAware::GetRealPixelClientSize(int* x, int* y)
*y = backing_size.height;
}
IMPLEMENT_CLASS(Quartz2DDrawingPanel, BasicDrawingPanel)
Quartz2DDrawingPanel::Quartz2DDrawingPanel(wxWindow* parent, int _width, int _height)
: BasicDrawingPanel(parent, _width, _height)
{

View File

@ -532,7 +532,7 @@ void GameArea::UnloadGame(bool destruct)
// in destructor, panel should be auto-deleted by wx since all panels
// are derived from a window attached as child to GameArea
if (panel)
panel->Delete();
panel->Destroy();
panel = NULL;
@ -680,7 +680,7 @@ void GameArea::AddBorder()
GetSizer()->Detach(panel->GetWindow());
if (panel)
panel->Delete();
panel->Destroy();
panel = NULL;
}
@ -699,7 +699,7 @@ void GameArea::DelBorder()
GetSizer()->Detach(panel->GetWindow());
if (panel)
panel->Delete();
panel->Destroy();
panel = NULL;
}
@ -782,7 +782,7 @@ void GameArea::ShowFullScreen(bool full)
// just in case screen mode is going to change, go ahead and preemptively
// delete panel to be recreated immediately after resize
if (panel) {
panel->Delete();
panel->Destroy();
panel = NULL;
}
@ -1035,9 +1035,14 @@ void GameArea::OnIdle(wxIdleEvent& event)
// set focus to panel
w->SetFocus();
// capture keyboard events
w->Connect(wxEVT_CHAR_HOOK, wxKeyEventHandler(GameArea::OnKeyDown), NULL, this);
w->Connect(wxEVT_KEY_UP, wxKeyEventHandler(GameArea::OnKeyUp), NULL, this);
// set up event handlers
// use both CHAR_HOOK and KEY_DOWN in case CHAR_HOOK does not work for whatever reason
w->Connect(wxEVT_CHAR_HOOK, wxKeyEventHandler(GameArea::OnKeyDown), NULL, this);
w->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(GameArea::OnKeyDown), NULL, this);
w->Connect(wxEVT_KEY_UP, wxKeyEventHandler(GameArea::OnKeyUp), NULL, this);
w->Connect(wxEVT_PAINT, wxPaintEventHandler(GameArea::PaintEv), NULL, this);
w->Connect(wxEVT_ERASE_BACKGROUND, wxEraseEventHandler(GameArea::EraseBackground), NULL, this);
w->Connect(wxEVT_SIZE, wxSizeEventHandler(GameArea::OnSize), NULL, this);
}
if (!paused && (!pauseWhenInactive || wxGetApp().frame->HasFocus())) {
@ -1223,6 +1228,28 @@ void GameArea::OnKeyUp(wxKeyEvent& ev)
ev.Skip(!process_key_press(false, ev.GetKeyCode(), ev.GetModifiers()));
}
// these three are forwarded to the DrawingPanel instance
void GameArea::PaintEv(wxPaintEvent& ev)
{
DrawingPanelBase* panel = dynamic_cast<DrawingPanelBase*>(ev.GetEventObject());
panel->PaintEv(ev);
}
void GameArea::EraseBackground(wxEraseEvent& ev)
{
DrawingPanelBase* panel = dynamic_cast<DrawingPanelBase*>(ev.GetEventObject());
panel->EraseBackground(ev);
}
void GameArea::OnSize(wxSizeEvent& ev)
{
DrawingPanelBase* panel = dynamic_cast<DrawingPanelBase*>(ev.GetEventObject());
panel->OnSize(ev);
}
void GameArea::OnSDLJoy(wxSDLJoyEvent& ev)
{
int key = ev.GetControlIndex();
@ -1256,11 +1283,8 @@ EVT_KEY_UP(GameArea::OnKeyUp)
EVT_MOUSE_EVENTS(GameArea::MouseEvent)
END_EVENT_TABLE()
IMPLEMENT_ABSTRACT_CLASS(DrawingPanel, wxEvtHandler)
DrawingPanel::DrawingPanel(int _width, int _height)
: wxObject()
, width(_width)
DrawingPanelBase::DrawingPanelBase(int _width, int _height)
: width(_width)
, height(_height)
, scale(1)
, todraw(0)
@ -1349,18 +1373,19 @@ DrawingPanel::DrawingPanel(int _width, int _height)
utilUpdateSystemColorMaps(false);
}
void DrawingPanel::DrawingPanelInit()
DrawingPanel::DrawingPanel(wxWindow* parent, int _width, int _height)
: DrawingPanelBase(_width, _height)
, wxPanel(parent, wxID_ANY, wxPoint(0, 0), parent->GetSize(),
wxFULL_REPAINT_ON_RESIZE | wxWANTS_CHARS)
{
wxWindow* w = dynamic_cast<wxWindow*>(this);
// this is not 2.8 compatible, sorry
w->Bind(wxEVT_PAINT, &DrawingPanel::PaintEv, this);
w->Bind(wxEVT_ERASE_BACKGROUND, &DrawingPanel::EraseBackground, this);
}
void DrawingPanelBase::DrawingPanelInit()
{
did_init = true;
}
void DrawingPanel::PaintEv(wxPaintEvent& ev)
void DrawingPanelBase::PaintEv(wxPaintEvent& ev)
{
wxPaintDC dc(GetWindow());
@ -1379,7 +1404,7 @@ void DrawingPanel::PaintEv(wxPaintEvent& ev)
DrawOSD(dc);
}
void DrawingPanel::EraseBackground(wxEraseEvent& ev)
void DrawingPanelBase::EraseBackground(wxEraseEvent& ev)
{
// do nothing, do not allow propagation
}
@ -1611,7 +1636,7 @@ public:
}
};
void DrawingPanel::DrawArea(uint8_t** data)
void DrawingPanelBase::DrawArea(uint8_t** data)
{
// double-buffer buffer:
// if filtering, this is filter output, retained for redraws
@ -1766,7 +1791,7 @@ void DrawingPanel::DrawArea(uint8_t** data)
DrawOSD(dc);
}
void DrawingPanel::DrawOSD(wxWindowDC& dc)
void DrawingPanelBase::DrawOSD(wxWindowDC& dc)
{
// draw OSD message, if available
// doing this here rather than using drawText() directly into the screen
@ -1854,7 +1879,12 @@ void DrawingPanel::DrawOSD(wxWindowDC& dc)
}
}
DrawingPanel::~DrawingPanel()
void DrawingPanelBase::OnSize(wxSizeEvent& ev)
{
ev.Skip(true);
}
DrawingPanelBase::~DrawingPanelBase()
{
// pixbuf1 freed by emulator
if (pixbuf2)
@ -1876,12 +1906,8 @@ DrawingPanel::~DrawingPanel()
}
}
IMPLEMENT_CLASS2(BasicDrawingPanel, DrawingPanel, wxPanel)
BasicDrawingPanel::BasicDrawingPanel(wxWindow* parent, int _width, int _height)
: wxPanel(parent, wxID_ANY, wxPoint(0, 0), parent->GetSize(),
wxFULL_REPAINT_ON_RESIZE | wxWANTS_CHARS)
, DrawingPanel(_width, _height)
: DrawingPanel(parent, _width, _height)
{
// wxImage is 24-bit RGB, so 24-bit is preferred. Filters require
// 16 or 32, though
@ -1957,32 +1983,23 @@ void BasicDrawingPanel::DrawImage(wxWindowDC& dc, wxImage* im)
#include <GL/glx.h>
#endif
#ifdef __WXMSW__
#include <GL/gl.h>
#include <GL/glext.h>
#endif
IMPLEMENT_CLASS2(GLDrawingPanel, DrawingPanel, wxGLCanvas)
// This is supposed to be the default, but DOUBLEBUFFER doesn't seem to be
// turned on by default for wxGTK.
static int glopts[] = {
WX_GL_RGBA, WX_GL_DOUBLEBUFFER, 0
};
#if wxCHECK_VERSION(2, 9, 0)
#define glc wxGLCanvas
#else
// shuffled parms for 2.9 indicates non-auto glcontext
// before 2.9, wxMAC does not have this (but wxGTK & wxMSW do)
#define glc(a, b, c, d, e, f) wxGLCanvas(a, b, d, e, f, wxEmptyString, c)
#endif
GLDrawingPanel::GLDrawingPanel(wxWindow* parent, int _width, int _height)
: glc(parent, wxID_ANY, glopts, wxPoint(0, 0), parent->GetSize(),
: DrawingPanelBase(_width, _height)
, wxglc(parent, wxID_ANY, glopts, wxPoint(0, 0), parent->GetSize(),
wxFULL_REPAINT_ON_RESIZE | wxWANTS_CHARS)
, DrawingPanel(_width, _height)
{
RequestHighResolutionOpenGLSurface();
#if wxCHECK_VERSION(2, 9, 0)
#ifndef wxGL_IMPLICIT_CONTEXT
ctx = new wxGLContext(this);
SetCurrent(*ctx);
#endif
@ -1991,39 +2008,36 @@ GLDrawingPanel::GLDrawingPanel(wxWindow* parent, int _width, int _height)
GLDrawingPanel::~GLDrawingPanel()
{
#if wxCHECK_VERSION(2, 9, 0)
delete ctx;
#endif
#if 0
// this should be automatically deleted w/ context
// it's also unsafe if panel no longer displayed
if (did_init)
{
#if wxCHECK_VERSION(2, 9, 0)
SetContext(*ctx);
// this should be automatically deleted w/ context
// it's also unsafe if panel no longer displayed
if (did_init)
{
#ifndef wxGL_IMPLICIT_CONTEXT
SetCurrent(*ctx);
#else
SetContext();
SetCurrent();
#endif
glDeleteLists(vlist, 1);
glDeleteTextures(1, &texid);
}
glDeleteLists(vlist, 1);
glDeleteTextures(1, &texid);
}
#ifndef wxGL_IMPLICIT_CONTEXT
delete ctx;
#endif
}
void GLDrawingPanel::DrawingPanelInit()
{
#if wxCHECK_VERSION(2, 9, 0)
#ifndef wxGL_IMPLICIT_CONTEXT
SetCurrent(*ctx);
#else
SetCurrent();
#endif
DrawingPanel::DrawingPanelInit();
DrawingPanelBase::DrawingPanelInit();
AdjustViewport();
Connect(wxEVT_SIZE, wxSizeEventHandler(GLDrawingPanel::OnSize), NULL, this);
// taken from GTK front end almost verbatim
glDisable(GL_CULL_FACE);
glEnable(GL_TEXTURE_2D);
@ -2105,7 +2119,18 @@ void GLDrawingPanel::DrawingPanelInit()
void GLDrawingPanel::OnSize(wxSizeEvent& ev)
{
#ifndef wxGL_IMPLICIT_CONTEXT
SetCurrent(*ctx);
#else
SetCurrent();
#endif
SetSize(ev.GetSize());
AdjustViewport();
Center();
ev.Skip(true);
}
void GLDrawingPanel::AdjustViewport()
@ -2118,13 +2143,13 @@ void GLDrawingPanel::AdjustViewport()
// you can use this to check that the gl surface is indeed high res
GLint m_viewport[4];
glGetIntegerv(GL_VIEWPORT, m_viewport);
vbamDebug("GL VIEWPORT: %d, %d, %d, %d", m_viewport[0], m_viewport[1], m_viewport[2], m_viewport[3]);
wxLogDebug(wxT("GL VIEWPORT: %d, %d, %d, %d"), m_viewport[0], m_viewport[1], m_viewport[2], m_viewport[3]);
#endif
}
void GLDrawingPanel::DrawArea(wxWindowDC& dc)
{
#if wxCHECK_VERSION(2, 9, 0)
#ifndef wxGL_IMPLICIT_CONTEXT
SetCurrent(*ctx);
#else
SetCurrent();
@ -2151,16 +2176,13 @@ void GLDrawingPanel::DrawArea(wxWindowDC& dc)
SwapBuffers();
}
#endif
#endif // GL support
#ifndef NO_CAIRO
IMPLEMENT_CLASS(CairoDrawingPanel, DrawingPanel)
CairoDrawingPanel::CairoDrawingPanel(wxWindow* parent, int _width, int _height)
: wxPanel(parent, wxID_ANY, wxPoint(0, 0), parent->GetSize(),
wxFULL_REPAINT_ON_RESIZE | wxWANTS_CHARS)
, DrawingPanel(_width, _height)
: DrawingPanel(parent, _width, _height)
{
conv_surf = NULL;
@ -2280,12 +2302,8 @@ void CairoDrawingPanel::DrawArea(wxWindowDC& dc)
#include <d3d9.h>
//#include <Dxerr.h>
IMPLEMENT_CLASS(DXDrawingPanel, DrawingPanel)
DXDrawingPanel::DXDrawingPanel(wxWindow* parent, int _width, int _height)
: wxPanel(parent, wxID_ANY, wxPoint(0, 0), parent->GetSize(),
wxFULL_REPAINT_ON_RESIZE | wxWANTS_CHARS)
, DrawingPanel(_width, _height)
: DrawingPanel(parent, _width, _height)
{
// FIXME: implement
if (!did_init) DrawingPanelInit();

View File

@ -110,8 +110,8 @@ protected:
const struct {
wxKeyCode code;
const char *name;
const char *display_name;
wxString name;
wxString display_name;
} keys_with_display_names[] = {
{ WXK_BACK, wxTRANSLATE("Back"), wxTRANSLATE("Backspace") },
{ WXK_PAGEUP, wxTRANSLATE("PageUp"), wxTRANSLATE("Page Up") },
@ -146,4 +146,10 @@ const struct {
{ WXK_NUMPAD_DIVIDE, wxTRANSLATE("KP_Divide"), wxTRANSLATE("Num /") },
};
// 2.x does not have the WXK_RAW_XXX values for Mac
#if wxMAJOR_VERSION < 3
#define WXK_RAW_CONTROL WXK_COMMAND
#define wxMOD_RAW_CONTROL wxMOD_CMD
#endif
#endif /* WX_KEYTEXT_H */

View File

@ -3,6 +3,7 @@
// utility widgets
#include <wx/checkbox.h>
#include <wx/valgen.h>
// simple radio button not under the same parent window
// note that it must be checkbox, as wx radio buttons have rigid behavior
@ -59,6 +60,18 @@ protected:
int val, mask, *vptr;
};
class wxPositiveDoubleValidator : public wxGenericValidator {
public:
wxPositiveDoubleValidator(double* _val);
bool TransferToWindow();
bool TransferFromWindow();
bool Validate(wxWindow* parent);
wxObject* Clone() const;
protected:
double* double_val;
wxString str_val;
};
// boolean copy-only validator with reversed value
// may be attached to radio button or checkbox
class wxBoolRevValidator : public wxValidator {

View File

@ -375,3 +375,56 @@ static const wxChar* /* const */ val_unsdigits_s[] = {
const wxArrayString val_unsdigits(sizeof(val_unsdigits_s) / sizeof(val_unsdigits_s[0]),
val_unsdigits_s);
wxPositiveDoubleValidator::wxPositiveDoubleValidator(double* _val)
: wxGenericValidator(&str_val)
, double_val(_val)
{
if (double_val) {
str_val = wxString::Format(wxT("%.1f"), *double_val);
TransferToWindow();
}
}
bool wxPositiveDoubleValidator::TransferToWindow()
{
if (double_val) {
str_val = wxString::Format(wxT("%.1f"), *double_val);
return wxGenericValidator::TransferToWindow();
}
}
bool wxPositiveDoubleValidator::TransferFromWindow()
{
if (wxGenericValidator::TransferFromWindow()) {
if (double_val) {
return str_val.ToDouble(double_val);
}
}
return false;
}
bool wxPositiveDoubleValidator::Validate(wxWindow* parent)
{
if (wxGenericValidator::Validate(parent)) {
wxTextCtrl* ctrl = wxDynamicCast(GetWindow(), wxTextCtrl);
if (ctrl) {
wxString cur_txt = ctrl->GetValue();
double val;
if (cur_txt.ToDouble(&val)) {
return val >= 0;
}
return false;
}
return true;
}
return false;
}
wxObject* wxPositiveDoubleValidator::Clone() const
{
return new wxPositiveDoubleValidator(double_val);
}

View File

@ -5,6 +5,8 @@
// create & display main frame
#include "wxvbam.h"
#include <unistd.h>
#include <stdio.h>
#include <wx/cmdline.h>
#include <wx/file.h>
#include <wx/filesys.h>
@ -30,24 +32,6 @@
IMPLEMENT_APP(wxvbamApp)
IMPLEMENT_DYNAMIC_CLASS(MainFrame, wxFrame)
// For spewing stuff to terminal when debugging
void vbamDebug(const char* format, ...) {
#ifdef DEBUG
wxLog *active_log = wxLog::GetActiveTarget();
wxLogStderr log_to_stderr;
wxLog::SetActiveTarget(&log_to_stderr);
va_list argptr;
va_start(argptr, format);
wxVLogDebug(format, argptr);
va_end(argptr);
wxLog::SetActiveTarget(active_log);
#endif
}
// generate config file path
static void get_config_path(wxPathList& path, bool exists = true)
{
@ -74,13 +58,13 @@ static void get_config_path(wxPathList& path, bool exists = true)
static bool debug_dumped = false;
if (!debug_dumped) {
vbamDebug("GetUserLocalDataDir(): %s", static_cast<const char*>(stdp.GetUserLocalDataDir().utf8_str()));
vbamDebug("GetUserDataDir(): %s", static_cast<const char*>(stdp.GetUserDataDir().utf8_str()));
vbamDebug("GetLocalizedResourcesDir(wxGetApp().locale.GetCanonicalName()): %s", static_cast<const char*>(stdp.GetLocalizedResourcesDir(wxGetApp().locale.GetCanonicalName()).utf8_str()));
vbamDebug("GetResourcesDir(): %s", static_cast<const char*>(stdp.GetResourcesDir().utf8_str()));
vbamDebug("GetDataDir(): %s", static_cast<const char*>(stdp.GetDataDir().utf8_str()));
vbamDebug("GetLocalDataDir(): %s", static_cast<const char*>(stdp.GetLocalDataDir().utf8_str()));
vbamDebug("GetPluginsDir(): %s", static_cast<const char*>(stdp.GetPluginsDir().utf8_str()));
wxLogDebug(wxT("GetUserLocalDataDir(): %s"), stdp.GetUserLocalDataDir().c_str());
wxLogDebug(wxT("GetUserDataDir(): %s"), stdp.GetUserDataDir().c_str());
wxLogDebug(wxT("GetLocalizedResourcesDir(wxGetApp().locale.GetCanonicalName()): %s"), stdp.GetLocalizedResourcesDir(wxGetApp().locale.GetCanonicalName()).c_str());
wxLogDebug(wxT("GetResourcesDir(): %s"), stdp.GetResourcesDir().c_str());
wxLogDebug(wxT("GetDataDir(): %s"), stdp.GetDataDir().c_str());
wxLogDebug(wxT("GetLocalDataDir(): %s"), stdp.GetLocalDataDir().c_str());
wxLogDebug(wxT("GetPluginsDir(): %s"), stdp.GetPluginsDir().c_str());
debug_dumped = true;
}
@ -165,6 +149,17 @@ wxString wxvbamApp::GetAbsolutePath(wxString path)
bool wxvbamApp::OnInit()
{
// set up logging
#ifndef NDEBUG
wxLog::SetLogLevel(wxLOG_Trace);
#endif
// turn off output buffering on Windows to support mintty
#ifdef __WXMSW__
setvbuf(stdout, NULL, _IONBF, 0);
setvbuf(stderr, NULL, _IONBF, 0);
dup2(1, 2); // redirect stderr to stdout
#endif
// use consistent names for config
SetAppName(_("vbam"));
#if (wxMAJOR_VERSION >= 3)

View File

@ -4,7 +4,12 @@
#include <list>
#include <stdexcept>
#include <typeinfo>
#include <iostream>
#include <stdio.h>
#include <time.h>
#include <wx/log.h>
#include <wx/propdlg.h>
#include <wx/datetime.h>
#include "wx/joyedit.h"
#include "wx/keyedit.h"
@ -27,6 +32,23 @@
#include "../gba/Globals.h"
#include "../gba/Sound.h"
// make wxLogDebug work on non-debug builds of Wx, and make it use the console
// on Windows
// (this works on 2.8 too!)
#if !defined(NDEBUG) && (!wxDEBUG_LEVEL || defined(__WXMSW__))
#ifdef __WXMSW__
#define VBAM_DEBUG_STREAM stdout
#else
#define VBAM_DEBUG_STREAM stderr
#endif
#undef wxLogDebug
#define wxLogDebug(...) \
do { \
fputs(wxString::Format(wxDateTime::UNow().Format(wxT("%X")) + wxT(": Debug: ") + __VA_ARGS__).utf8_str(), VBAM_DEBUG_STREAM); \
fputc('\n', VBAM_DEBUG_STREAM); \
} while(0)
#endif
template <typename T>
void CheckPointer(T pointer)
{
@ -38,9 +60,6 @@ void CheckPointer(T pointer)
}
}
// For spewing stuff to terminal
void vbamDebug(const char* format, ...);
/// Helper functions to convert WX's crazy string types to std::string
inline std::string ToString(wxCharBuffer aString)
@ -441,7 +460,7 @@ enum audioapi { AUD_SDL,
// display time, in ms
#define OSD_TIME 3000
class DrawingPanel;
class DrawingPanelBase;
class GameArea : public wxPanel, public HiDPIAware {
public:
@ -501,7 +520,7 @@ public:
void AddBorder();
void DelBorder();
// Delete() & set to NULL to force reinit
DrawingPanel* panel;
DrawingPanelBase* panel;
struct EmulatedSystem* emusys;
// pause game or signal a long operation, similar to pausing
@ -585,6 +604,9 @@ protected:
void OnKeyDown(wxKeyEvent& ev);
void OnKeyUp(wxKeyEvent& ev);
void OnSDLJoy(wxSDLJoyEvent& ev);
void PaintEv(wxPaintEvent& ev);
void EraseBackground(wxEraseEvent& ev);
void OnSize(wxSizeEvent& ev);
#ifndef NO_FFMPEG
MediaRecorder snd_rec, vid_rec;
@ -628,18 +650,17 @@ extern bool cmditem_lt(const struct cmditem& cmd1, const struct cmditem& cmd2);
class FilterThread;
class DrawingPanel : public wxObject, public HiDPIAware {
class DrawingPanelBase : public HiDPIAware {
public:
DrawingPanel(int _width, int _height);
~DrawingPanel();
DrawingPanelBase(int _width, int _height);
~DrawingPanelBase();
void DrawArea(uint8_t** pixels);
// using dynamic_cast<> to not force trivial reimplementation in concrete classes
virtual wxWindow* GetWindow() { return dynamic_cast<wxWindow*>(this); }
virtual void Delete() { (dynamic_cast<wxWindow*>(this))->Destroy(); }
virtual void PaintEv(wxPaintEvent& ev);
virtual void EraseBackground(wxEraseEvent& ev);
virtual void OnSize(wxSizeEvent& ev);
wxWindow* GetWindow() { return dynamic_cast<wxWindow*>(this); }
virtual bool Destroy() { return GetWindow()->Destroy(); }
protected:
virtual void DrawArea(wxWindowDC&) = 0;
virtual void DrawOSD(wxWindowDC&);
@ -656,8 +677,12 @@ protected:
const RENDER_PLUGIN_INFO* rpi; // also flag indicating plugin loaded
// largest buffer required is 32-bit * (max width + 1) * (max height + 2)
uint8_t delta[257 * 4 * 226];
};
DECLARE_ABSTRACT_CLASS()
// base class with a wxPanel when a subclass (such as wxGLCanvas) is not being used
class DrawingPanel : public DrawingPanelBase, public wxPanel {
public:
DrawingPanel(wxWindow* parent, int _width, int _height);
};
class LogDialog : public wxDialog {