diff --git a/.clang-format b/.clang-format index 2dd4bfc242287..7b41bf7f9ee3b 100644 --- a/.clang-format +++ b/.clang-format @@ -61,7 +61,7 @@ KeepEmptyLinesAtTheStartOfBlocks: true MacroBlockBegin: '' MacroBlockEnd: '' MaxEmptyLinesToKeep: 3 -NamespaceIndentation: All +NamespaceIndentation: None ObjCBlockIndentWidth: 2 ObjCSpaceAfterProperty: false ObjCSpaceBeforeProtocolList: true diff --git a/.github/workflows/scripts/build-linux.sh b/.github/workflows/scripts/build-linux.sh index 4f38dea494176..a1e7aeeee8fa1 100644 --- a/.github/workflows/scripts/build-linux.sh +++ b/.github/workflows/scripts/build-linux.sh @@ -97,8 +97,6 @@ generate_cmake() { # Generate CMake into ./build cmake \ - -D CMAKE_C_COMPILER_LAUNCHER=ccache \ - -D CMAKE_CXX_COMPILER_LAUNCHER=ccache \ -D CMAKE_BUILD_TYPE=Release \ -D BUILD_REPLAY_LOADERS=TRUE \ -D CMAKE_BUILD_PO=FALSE \ diff --git a/.gitignore b/.gitignore index 333c2dab9f8c4..57e0fb917c387 100644 --- a/.gitignore +++ b/.gitignore @@ -116,3 +116,14 @@ oprofile_data/ /pcsx2/windows/VCprojects/GSdx_opengl_debug_hw.txt /pcsx2/windows/VCprojects/GSdx_opengl_debug_sw.txt /out/build/x64-Debug (default) + +bin/* +build*/ +*.cflags +*.config +*.creator +*.creator.user.* +*.cxxflags +*.files +*.includes +*.autosave diff --git a/3rdparty/baseclasses/CMakeLists.txt b/3rdparty/baseclasses/CMakeLists.txt new file mode 100644 index 0000000000000..40cfac3658d9c --- /dev/null +++ b/3rdparty/baseclasses/CMakeLists.txt @@ -0,0 +1,57 @@ +add_library(baseclasses + amextra.cpp + amfilter.cpp + amvideo.cpp + combase.cpp + ctlutil.cpp + ddmm.cpp + mtype.cpp + outputq.cpp + pstream.cpp + pullpin.cpp + refclock.cpp + renbase.cpp + schedule.cpp + seekpt.cpp + source.cpp + strmctl.cpp + sysclock.cpp + transfrm.cpp + transip.cpp + vtrans.cpp + wxdebug.cpp + wxlist.cpp + wxutil.cpp + + amextra.h + amfilter.h + cache.h + combase.h + ctlutil.h + ddmm.h + fourcc.h + measure.h + msgthrd.h + mtype.h + outputq.h + pstream.h + pullpin.h + refclock.h + reftime.h + renbase.h + schedule.h + seekpt.h + source.h + streams.h + strmctl.h + sysclock.h + transfrm.h + transip.h + vtrans.h + wxdebug.h + wxlist.h + wxutil.h +) + +target_include_directories(baseclasses PRIVATE .) +target_compile_definitions(baseclasses PRIVATE -DHAVE_PTW32_CONFIG_H -DPTW32_BUILD_INLINED) diff --git a/3rdparty/libpng/CMakeLists.txt b/3rdparty/libpng/CMakeLists.txt new file mode 100644 index 0000000000000..4728eca4ca514 --- /dev/null +++ b/3rdparty/libpng/CMakeLists.txt @@ -0,0 +1,111 @@ +if(UNIX) +set(wxUnixSources + src/unix/appunix.cpp + src/unix/dir.cpp + src/unix/dlunix.cpp + src/unix/evtloopunix.cpp + src/unix/epolldispatcher.cpp + src/unix/fdiounix.cpp + src/unix/stackwalk.cpp + src/unix/stdpaths.cpp + src/unix/threadpsx.cpp + src/unix/timerunx.cpp + src/unix/utilsunx.cpp + src/unix/wakeuppipe.cpp + src/common/selectdispatcher.cpp + src/common/fdiodispatcher.cpp + ) +endif() +if(WIN32) +set(wxWindowsSources + src/msw/basemsw.cpp + src/msw/crashrpt.cpp + src/msw/dde.cpp + src/msw/debughlp.cpp + src/msw/dir.cpp + src/msw/dlmsw.cpp + src/msw/evtloopconsole.cpp + src/msw/fswatcher.cpp + src/msw/main.cpp + src/msw/mimetype.cpp + src/msw/mslu.cpp + src/msw/power.cpp + src/msw/regconf.cpp + src/msw/registry.cpp + src/msw/snglinst.cpp + src/msw/stackwalk.cpp + src/msw/stdpaths.cpp + src/msw/thread.cpp + src/msw/timer.cpp + src/msw/utils.cpp + src/msw/utilsexc.cpp + src/msw/volume.cpp + ) +endif() +add_library(wxwidgets + src/common/appbase.cpp + src/common/arrstr.cpp + src/common/cmdline.cpp + src/common/config.cpp + src/common/convauto.cpp + src/common/datetime.cpp + src/common/datetimefmt.cpp + src/common/dircmn.cpp + src/common/dynarray.cpp + src/common/dynlib.cpp + src/common/event.cpp + src/common/evtloopcmn.cpp + src/common/ffile.cpp + src/common/file.cpp + src/common/fileconf.cpp + src/common/filefn.cpp + src/common/filename.cpp + src/common/fmapbase.cpp + src/common/hashmap.cpp + src/common/init.cpp + src/common/intl.cpp + src/common/languageinfo.cpp + src/common/list.cpp + src/common/log.cpp + src/common/longlong.cpp + src/common/module.cpp + src/common/msgout.cpp + src/common/mstream.cpp + src/common/object.cpp + src/common/platinfo.cpp + src/common/stdpbase.cpp + src/common/strconv.cpp + src/common/stream.cpp + src/common/string.cpp + src/common/stringimpl.cpp + src/common/strvararg.cpp + src/common/sysopt.cpp + src/common/tarstrm.cpp + src/common/textbuf.cpp + src/common/textfile.cpp + src/common/threadinfo.cpp + src/common/time.cpp + src/common/timercmn.cpp + src/common/timerimpl.cpp + src/common/tokenzr.cpp + src/common/translation.cpp + src/common/txtstrm.cpp + src/common/unichar.cpp + src/common/utilscmn.cpp + src/common/wfstream.cpp + src/common/wxcrt.cpp + src/common/xlocale.cpp + src/common/zipstrm.cpp + src/common/zstream.cpp + src/common/any.cpp + src/common/archive.cpp + src/common/base64.cpp + src/common/datstrm.cpp + src/common/encconv.cpp + src/common/extended.c + src/common/hash.cpp + src/common/process.cpp + src/common/variant.cpp + ${wxUnixSources} + ${wxWindowsSources} +) diff --git a/3rdparty/pthreads4w/CMakeLists.txt b/3rdparty/pthreads4w/CMakeLists.txt new file mode 100644 index 0000000000000..42c78c68957f3 --- /dev/null +++ b/3rdparty/pthreads4w/CMakeLists.txt @@ -0,0 +1,14 @@ +add_library(pthread + pthread.c + config.h + context.h + implement.h + need_errno.h + include/pthread.h + include/sched.h + include/semaphore.h +) + +target_include_directories(pthread PRIVATE . include) +#target_compile_definitions(pthread PRIVATE -DHAVE_PTW32_CONFIG_H -DPTW32_BUILD_INLINED) + diff --git a/3rdparty/wxwidgets3.0/CMakeLists.txt b/3rdparty/wxwidgets3.0/CMakeLists.txt new file mode 100644 index 0000000000000..d8e20314d3f2c --- /dev/null +++ b/3rdparty/wxwidgets3.0/CMakeLists.txt @@ -0,0 +1,112 @@ +if(UNIX) +set(wxUnixSources + src/unix/appunix.cpp + src/unix/dir.cpp + src/unix/dlunix.cpp + src/unix/evtloopunix.cpp + src/unix/epolldispatcher.cpp + src/unix/fdiounix.cpp + src/unix/stackwalk.cpp + src/unix/stdpaths.cpp + src/unix/threadpsx.cpp + src/unix/timerunx.cpp + src/unix/utilsunx.cpp + src/unix/wakeuppipe.cpp + src/common/selectdispatcher.cpp + src/common/fdiodispatcher.cpp + ) +endif() +if(WIN32) +set(wxWindowsSources + src/msw/basemsw.cpp + src/msw/crashrpt.cpp + src/msw/dde.cpp + src/msw/debughlp.cpp + src/msw/dir.cpp + src/msw/dlmsw.cpp + src/msw/evtloopconsole.cpp + src/msw/fswatcher.cpp + src/msw/main.cpp + src/msw/mimetype.cpp + src/msw/mslu.cpp + src/msw/power.cpp + src/msw/regconf.cpp + src/msw/registry.cpp + src/msw/snglinst.cpp + src/msw/stackwalk.cpp + src/msw/stdpaths.cpp + src/msw/thread.cpp + src/msw/timer.cpp + src/msw/utils.cpp + src/msw/utilsexc.cpp + src/msw/volume.cpp + src/common/ipcbase.cpp + ) +endif() +add_library(wxwidgets + src/common/appbase.cpp + src/common/arrstr.cpp + src/common/cmdline.cpp + src/common/config.cpp + src/common/convauto.cpp + src/common/datetime.cpp + src/common/datetimefmt.cpp + src/common/dircmn.cpp + src/common/dynarray.cpp + src/common/dynlib.cpp + src/common/event.cpp + src/common/evtloopcmn.cpp + src/common/ffile.cpp + src/common/file.cpp + src/common/fileconf.cpp + src/common/filefn.cpp + src/common/filename.cpp + src/common/fmapbase.cpp + src/common/hashmap.cpp + src/common/init.cpp + src/common/intl.cpp + src/common/languageinfo.cpp + src/common/list.cpp + src/common/log.cpp + src/common/longlong.cpp + src/common/module.cpp + src/common/msgout.cpp + src/common/mstream.cpp + src/common/object.cpp + src/common/platinfo.cpp + src/common/stdpbase.cpp + src/common/strconv.cpp + src/common/stream.cpp + src/common/string.cpp + src/common/stringimpl.cpp + src/common/strvararg.cpp + src/common/sysopt.cpp + src/common/tarstrm.cpp + src/common/textbuf.cpp + src/common/textfile.cpp + src/common/threadinfo.cpp + src/common/time.cpp + src/common/timercmn.cpp + src/common/timerimpl.cpp + src/common/tokenzr.cpp + src/common/translation.cpp + src/common/txtstrm.cpp + src/common/unichar.cpp + src/common/utilscmn.cpp + src/common/wfstream.cpp + src/common/wxcrt.cpp + src/common/xlocale.cpp + src/common/zipstrm.cpp + src/common/zstream.cpp + src/common/any.cpp + src/common/archive.cpp + src/common/base64.cpp + src/common/datstrm.cpp + src/common/encconv.cpp + src/common/extended.c + src/common/hash.cpp + src/common/process.cpp + src/common/variant.cpp + ${wxUnixSources} + ${wxWindowsSources} +) diff --git a/3rdparty/wxwidgets3.0/UsewxWidgets.cmake b/3rdparty/wxwidgets3.0/UsewxWidgets.cmake new file mode 100644 index 0000000000000..2a985ed65bf02 --- /dev/null +++ b/3rdparty/wxwidgets3.0/UsewxWidgets.cmake @@ -0,0 +1,24 @@ +set(wxWidgets_FOUND 1) +set(wxWidgets_DIR ${CMAKE_SOURCE_DIR}/3rdparty/wxwidgets3.0) +set(wxWidgets_INCLUDE_DIRS ${wxWidgets_DIR}/include ${wxWidgets_DIR}/include/nogui) +set(wxWidgets_LIBRARIES wxwidgets) +set(wxWidgets_CXX_FLAGS) + +include_directories(SYSTEM ${wxWidgets_INCLUDE_DIRS}) +add_definitions(-DwxUSE_GUI=0 -D_FILE_OFFSET_BITS=64) +if(UNIX) + add_definitions(-DwxUSE_UNIX -D__UNIX__) + if(APPLE) + add_definitions(-D__DARWIN__) + else() + add_definitions(-D__LINUX__) + endif() +elseif(WIN32) + add_definitions(-D__WINDOWS__) + if(MINGW) + add_definitions(-D__GNUWIN32__) + endif() +endif() + + + diff --git a/3rdparty/wxwidgets3.0/include/nogui/wx/setup.h b/3rdparty/wxwidgets3.0/include/nogui/wx/setup.h new file mode 100644 index 0000000000000..6777c3ac08fa0 --- /dev/null +++ b/3rdparty/wxwidgets3.0/include/nogui/wx/setup.h @@ -0,0 +1,1139 @@ +/* lib/wx/include/gtk3-unicode-3.0/wx/setup.h. Generated from setup.h.in by configure. */ +/* This define (__WX_SETUP_H__) is used both to ensure setup.h is included + * only once and to indicate that we are building using configure. */ +#ifndef __WX_SETUP_H__ +#define __WX_SETUP_H__ +#if __UNIX__ +/* Define if ssize_t type is available. */ +#define HAVE_SSIZE_T 1 + +/* Define if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define this to get extra features from GNU libc. */ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE 1 +#endif +#endif +/* --- start common options --- */ + +#ifndef wxUSE_GUI + #define wxUSE_GUI 0 +#endif + + +#define WXWIN_COMPATIBILITY_2_6 0 + +#define WXWIN_COMPATIBILITY_2_8 0 + +#define wxDIALOG_UNIT_COMPATIBILITY 0 + + +#define wxUSE_ON_FATAL_EXCEPTION 1 + +#define wxUSE_STACKWALKER 1 + +#define wxUSE_DEBUGREPORT 1 + + +#define wxUSE_DEBUG_CONTEXT 0 + +#define wxUSE_MEMORY_TRACING 0 + +#define wxUSE_GLOBAL_MEMORY_OPERATORS 0 + +#define wxUSE_DEBUG_NEW_ALWAYS 0 + + + +#ifndef wxUSE_UNICODE + #define wxUSE_UNICODE 1 +#endif + +#define wxUSE_WCHAR_T 1 + + +#define wxUSE_EXCEPTIONS 1 + +#define wxUSE_EXTENDED_RTTI 0 + +#define wxUSE_LOG 1 + +#define wxUSE_LOGWINDOW 1 + +#define wxUSE_LOGGUI 1 + +#define wxUSE_LOG_DIALOG 1 + +#define wxUSE_CMDLINE_PARSER 1 + +#define wxUSE_THREADS 1 + +#define wxUSE_STREAMS 1 + +#define wxUSE_PRINTF_POS_PARAMS 1 + +#define wxUSE_COMPILER_TLS 1 + + +#define wxUSE_STL 0 + +#if defined(__DMC__) || defined(__WATCOMC__) \ + || (defined(_MSC_VER) && _MSC_VER < 1200) + #define wxUSE_STD_DEFAULT 0 +#else + #define wxUSE_STD_DEFAULT 1 +#endif + +#define wxUSE_STD_CONTAINERS 0 + +#define wxUSE_STD_IOSTREAM wxUSE_STD_DEFAULT + +#define wxUSE_STD_STRING wxUSE_STD_DEFAULT + +#define wxUSE_STD_STRING_CONV_IN_WXSTRING wxUSE_STL + +#define wxUSE_IOSTREAMH 0 + + + +#define wxUSE_LONGLONG 1 + +#define wxUSE_BASE64 1 + +#define wxUSE_CONSOLE_EVENTLOOP 1 + +#define wxUSE_FILE 1 +#define wxUSE_FFILE 1 + +#define wxUSE_FSVOLUME 1 + +#define wxUSE_STDPATHS 1 + +#define wxUSE_TEXTBUFFER 1 + +#define wxUSE_TEXTFILE 1 + +#define wxUSE_INTL 1 + +#define wxUSE_XLOCALE 1 + +#define wxUSE_DATETIME 1 + +#define wxUSE_TIMER 1 + +#define wxUSE_STOPWATCH 1 + +#define wxUSE_FSWATCHER 0 + +#define wxUSE_CONFIG 1 + +#define wxUSE_CONFIG_NATIVE 1 + +#define wxUSE_DIALUP_MANAGER 1 + +#define wxUSE_DYNLIB_CLASS 1 + +#define wxUSE_DYNAMIC_LOADER 1 + +#define wxUSE_SOCKETS 1 + +#define wxUSE_IPV6 0 + +#define wxUSE_FILESYSTEM 1 + +#define wxUSE_FS_ZIP 1 + +#define wxUSE_FS_ARCHIVE 1 + +#define wxUSE_FS_INET 1 + +#define wxUSE_ARCHIVE_STREAMS 1 + +#define wxUSE_ZIPSTREAM 1 + +#define wxUSE_TARSTREAM 1 + +#define wxUSE_ZLIB 1 + +#define wxUSE_APPLE_IEEE 1 + +#define wxUSE_JOYSTICK 1 + +#define wxUSE_FONTENUM 1 + +#define wxUSE_FONTMAP 0 /* 1 */ + +#define wxUSE_MIMETYPE 1 + +#define wxUSE_PROTOCOL 1 + +#define wxUSE_PROTOCOL_FILE 1 +#define wxUSE_PROTOCOL_FTP 1 +#define wxUSE_PROTOCOL_HTTP 1 + +#define wxUSE_URL 1 + +#define wxUSE_URL_NATIVE 0 + +#define wxUSE_VARIANT 1 + +#define wxUSE_ANY 1 + +#define wxUSE_REGEX 1 + +#define wxUSE_SYSTEM_OPTIONS 1 + +#define wxUSE_SOUND 1 + +#define wxUSE_MEDIACTRL 0 + +#define wxUSE_XRC 1 + +#define wxUSE_XML 1 + +#define wxUSE_AUI 1 + +#define wxUSE_RIBBON 1 + +#define wxUSE_PROPGRID 1 + +#define wxUSE_STC 1 + +#define wxUSE_WEBVIEW 1 + +#ifdef __WXMSW__ +#define wxUSE_WEBVIEW_IE 0 +#else +#define wxUSE_WEBVIEW_IE 0 +#endif + +#if (defined(__WXGTK__) && !defined(__WXGTK3__)) || defined(__WXOSX__) +#define wxUSE_WEBVIEW_WEBKIT 0 +#else +#define wxUSE_WEBVIEW_WEBKIT 0 +#endif + +#if defined(__WXGTK3__) +#define wxUSE_WEBVIEW_WEBKIT2 1 +#else +#define wxUSE_WEBVIEW_WEBKIT2 1 +#endif + + +#ifdef _MSC_VER +# if _MSC_VER >= 1310 + + +#define wxUSE_GRAPHICS_CONTEXT 1 +# else + + +# define wxUSE_GRAPHICS_CONTEXT 0 +# endif +#else + + + + + +# define wxUSE_GRAPHICS_CONTEXT 1 +#endif + +#define wxUSE_CAIRO 0 + + + +#define wxUSE_CONTROLS 1 + +#define wxUSE_MARKUP 1 + +#define wxUSE_POPUPWIN 1 + +#define wxUSE_TIPWINDOW 1 + +#define wxUSE_ANIMATIONCTRL 1 +#define wxUSE_BANNERWINDOW 1 +#define wxUSE_BUTTON 1 +#define wxUSE_BMPBUTTON 1 +#define wxUSE_CALENDARCTRL 1 +#define wxUSE_CHECKBOX 1 +#define wxUSE_CHECKLISTBOX 1 +#define wxUSE_CHOICE 1 +#define wxUSE_COLLPANE 1 +#define wxUSE_COLOURPICKERCTRL 1 +#define wxUSE_COMBOBOX 1 +#define wxUSE_COMMANDLINKBUTTON 1 +#define wxUSE_DATAVIEWCTRL 1 +#define wxUSE_DATEPICKCTRL 1 +#define wxUSE_DIRPICKERCTRL 1 +#define wxUSE_EDITABLELISTBOX 1 +#define wxUSE_FILECTRL 1 +#define wxUSE_FILEPICKERCTRL 1 +#define wxUSE_FONTPICKERCTRL 1 +#define wxUSE_GAUGE 1 +#define wxUSE_HEADERCTRL 1 +#define wxUSE_HYPERLINKCTRL 1 +#define wxUSE_LISTBOX 1 +#define wxUSE_LISTCTRL 1 +#define wxUSE_RADIOBOX 1 +#define wxUSE_RADIOBTN 1 +#define wxUSE_RICHMSGDLG 1 +#define wxUSE_SCROLLBAR 1 +#define wxUSE_SEARCHCTRL 1 +#define wxUSE_SLIDER 1 +#define wxUSE_SPINBTN 1 +#define wxUSE_SPINCTRL 1 +#define wxUSE_STATBOX 1 +#define wxUSE_STATLINE 1 +#define wxUSE_STATTEXT 1 +#define wxUSE_STATBMP 1 +#define wxUSE_TEXTCTRL 1 +#define wxUSE_TIMEPICKCTRL 1 +#define wxUSE_TOGGLEBTN 1 +#define wxUSE_TREECTRL 1 +#define wxUSE_TREELISTCTRL 1 + +#define wxUSE_STATUSBAR 1 + +#define wxUSE_NATIVE_STATUSBAR 1 + +#define wxUSE_TOOLBAR 1 +#define wxUSE_TOOLBAR_NATIVE 1 + +#define wxUSE_NOTEBOOK 0 + +#define wxUSE_LISTBOOK 1 + +#define wxUSE_CHOICEBOOK 1 + +#define wxUSE_TREEBOOK 1 + +#define wxUSE_TOOLBOOK 1 + +#define wxUSE_TASKBARICON 1 + +#define wxUSE_GRID 1 + +#define wxUSE_MINIFRAME 1 + +#define wxUSE_COMBOCTRL 1 + +#define wxUSE_ODCOMBOBOX 1 + +#define wxUSE_BITMAPCOMBOBOX 1 + +#define wxUSE_REARRANGECTRL 1 + + +#define wxUSE_ACCEL 1 + +#define wxUSE_ARTPROVIDER_STD 1 + +#define wxUSE_ARTPROVIDER_TANGO 0 /* 1 */ + +#define wxUSE_HOTKEY 0 /* 1 */ + +#define wxUSE_CARET 1 + +#define wxUSE_DISPLAY 1 + +#define wxUSE_GEOMETRY 1 + +#define wxUSE_IMAGLIST 1 + +#define wxUSE_INFOBAR 1 + +#define wxUSE_MENUS 1 + +#define wxUSE_NOTIFICATION_MESSAGE 1 + +#define wxUSE_PREFERENCES_EDITOR 1 + +#define wxUSE_RICHTOOLTIP 1 + +#define wxUSE_SASH 1 + +#define wxUSE_SPLITTER 1 + +#define wxUSE_TOOLTIPS 1 + +#define wxUSE_VALIDATORS 1 + +#ifdef __WXMSW__ +#define wxUSE_AUTOID_MANAGEMENT 0 +#else +#define wxUSE_AUTOID_MANAGEMENT 0 +#endif + + +#define wxUSE_COMMON_DIALOGS 0 /* 1 */ + +#define wxUSE_BUSYINFO 1 + +#define wxUSE_CHOICEDLG 1 + +#define wxUSE_COLOURDLG 1 + +#define wxUSE_DIRDLG 1 + + +#define wxUSE_FILEDLG 1 + +#define wxUSE_FINDREPLDLG 1 + +#define wxUSE_FONTDLG 1 + +#define wxUSE_MSGDLG 1 + +#define wxUSE_PROGRESSDLG 1 + +#define wxUSE_STARTUP_TIPS 1 + +#define wxUSE_TEXTDLG 1 + +#define wxUSE_NUMBERDLG 1 + +#define wxUSE_SPLASH 1 + +#define wxUSE_WIZARDDLG 1 + +#define wxUSE_ABOUTDLG 1 + +#define wxUSE_FILE_HISTORY 1 + + +#define wxUSE_METAFILE 0 /* 1 */ +#define wxUSE_ENH_METAFILE 0 /* 1 */ +#define wxUSE_WIN_METAFILES_ALWAYS 0 + + +#define wxUSE_MDI 1 + +#define wxUSE_DOC_VIEW_ARCHITECTURE 1 + +#define wxUSE_MDI_ARCHITECTURE 1 + +#define wxUSE_PRINTING_ARCHITECTURE 1 + +#define wxUSE_HTML 1 + +#define wxUSE_GLCANVAS 1 + +#define wxUSE_RICHTEXT 1 + + +#define wxUSE_CLIPBOARD 1 + +#define wxUSE_DATAOBJ 0 /* 1 */ + +#define wxUSE_DRAG_AND_DROP 1 + +#define wxUSE_ACCESSIBILITY 0 + + +#define wxUSE_SNGLINST_CHECKER 1 + +#define wxUSE_DRAGIMAGE 1 + +#define wxUSE_IPC 1 + +#define wxUSE_HELP 1 + + +#define wxUSE_MS_HTML_HELP 0 + + +#define wxUSE_WXHTML_HELP 1 + +#define wxUSE_CONSTRAINTS 1 + + +#define wxUSE_SPLINES 1 + + +#define wxUSE_MOUSEWHEEL 1 + + +#define wxUSE_UIACTIONSIMULATOR 1 + + +#define wxUSE_POSTSCRIPT 1/* 0 */ + +#define wxUSE_AFM_FOR_POSTSCRIPT 1 + +#define wxUSE_SVG 1 + +#define wxUSE_DC_TRANSFORM_MATRIX 1 + + + +#define wxUSE_IMAGE 1 + +#define wxUSE_LIBPNG 1 + +#define wxUSE_LIBJPEG 1 + +#define wxUSE_LIBTIFF 1/* 0 */ + +#define wxUSE_TGA 1 + +#define wxUSE_GIF 1 + +#define wxUSE_PNM 1 + +#define wxUSE_PCX 1 + +#define wxUSE_IFF 1 + +#define wxUSE_XPM 1/* 0 */ + +#define wxUSE_ICO_CUR 1 + +#define wxUSE_PALETTE 1 + + +#define wxUSE_ALL_THEMES 0 /* 1 */ + +#define wxUSE_THEME_GTK 0 +#define wxUSE_THEME_METAL 0 +#define wxUSE_THEME_MONO 0 +#define wxUSE_THEME_WIN32 0 + + +/* --- end common options --- */ +#if __unix__ +/* + * Unix-specific options + */ +#define wxUSE_SELECT_DISPATCHER 1 +#define wxUSE_EPOLL_DISPATCHER 1 + +#define wxUSE_UNICODE_UTF8 0 +#define wxUSE_UTF8_LOCALE_ONLY 0 + +/* + Use GStreamer for Unix. + + Default is 0 as this requires a lot of dependencies which might not be + available. + + Recommended setting: 1 (wxMediaCtrl won't work by default without it). + */ +#define wxUSE_GSTREAMER 1 +#else +/* --- start MSW options --- */ + +#ifndef wxUSE_UNICODE_MSLU + #define wxUSE_UNICODE_MSLU 0 +#endif + +#define wxUSE_MFC 0 + +#define wxUSE_OLE 0 /* 1 */ + +#define wxUSE_OLE_AUTOMATION 0 /* 1 */ + +#define wxUSE_ACTIVEX 0 /* 1 */ + +#define wxUSE_DC_CACHEING 0 /* 1 */ + +#define wxUSE_WXDIB 0 /* 1 */ + +#define wxUSE_POSTSCRIPT_ARCHITECTURE_IN_MSW 0 /* 1 */ + +#define wxUSE_REGKEY 1 /* 1 */ + +#define wxUSE_RICHEDIT 1 + +#define wxUSE_RICHEDIT2 1 + +#define wxUSE_OWNER_DRAWN 0 /* 1 */ + +#define wxUSE_TASKBARICON_BALLOONS 1 + +#define wxUSE_UXTHEME 0 /* 1 */ + +#define wxUSE_INKEDIT 0 + +#define wxUSE_INICONF 0 + + +#define wxUSE_DATEPICKCTRL_GENERIC 0 + +#define wxUSE_TIMEPICKCTRL_GENERIC 0 + + +#define wxUSE_CRASHREPORT 0 /* 1 */ +/* --- end MSW options --- */ +#endif +#ifndef _WIN32 +/* + * Define if your compiler supports the explicit keyword + */ +#define HAVE_EXPLICIT 1 + +/* + * Define if your compiler has C99 va_copy + */ +#define HAVE_VA_COPY 1 + +/* + * Define if va_list type is an array + */ +/* #undef VA_LIST_IS_ARRAY */ + +/* + * Define if the compiler supports variadic macros + */ +#define HAVE_VARIADIC_MACROS 1 + +/* + * Define if you don't want variadic macros to be used even if they are + * supported by the compiler. + */ +/* #undef wxNO_VARIADIC_MACROS */ + +/* + * Define if your compiler has std::wstring + */ +#define HAVE_STD_WSTRING 1 +/* + * Define if your compiler has compliant std::string::compare + */ +/* #undef HAVE_STD_STRING_COMPARE */ +/* + * Define if your compiler has + */ +/* #undef HAVE_HASH_MAP */ +/* + * Define if your compiler has + */ +/* #undef HAVE_EXT_HASH_MAP */ +/* + * Define if your compiler has std::hash_map/hash_set + */ +/* #undef HAVE_STD_HASH_MAP */ +/* + * Define if your compiler has __gnu_cxx::hash_map/hash_set + */ +/* #undef HAVE_GNU_CXX_HASH_MAP */ + +/* + * Define if your compiler has std::unordered_map + */ +/* #undef HAVE_STD_UNORDERED_MAP */ + +/* + * Define if your compiler has std::unordered_set + */ +/* #undef HAVE_STD_UNORDERED_SET */ + +/* + * Define if your compiler has std::tr1::unordered_map + */ +/* #undef HAVE_TR1_UNORDERED_MAP */ + +/* + * Define if your compiler has std::tr1::unordered_set + */ +/* #undef HAVE_TR1_UNORDERED_SET */ + +/* + * Define if your compiler has + */ +/* #undef HAVE_TR1_TYPE_TRAITS */ + +/* + * Define if your compiler has + */ +#define HAVE_TYPE_TRAITS 1 + +/* + * Define if the compiler supports simple visibility declarations. + */ +#define HAVE_VISIBILITY 1 + +/* + * Define if the compiler supports GCC's atomic memory access builtins + */ +#define HAVE_GCC_ATOMIC_BUILTINS 1 + +/* + * Define if compiler's visibility support in libstdc++ is broken + */ +/* #undef HAVE_BROKEN_LIBSTDCXX_VISIBILITY */ + +/* + * The built-in regex supports advanced REs in additional to POSIX's basic + * and extended. Your system regex probably won't support this, and in this + * case WX_NO_REGEX_ADVANCED should be defined. + */ +#define WX_NO_REGEX_ADVANCED 1 +/* + * On GNU systems use re_search instead of regexec, since the latter does a + * strlen on the search text affecting the performance of some operations. + */ +/* #undef HAVE_RE_SEARCH */ +/* + * Use SDL for audio (Unix) + */ +#define wxUSE_LIBSDL 0 + +/* + * Compile sound backends as plugins + */ +#define wxUSE_PLUGINS 0 + +/* + * Use GTK print for printing under GTK+ 2.10+ + */ +#define wxUSE_GTKPRINT 0 +/* + * Use GNOME VFS for MIME types + */ +#define wxUSE_LIBGNOMEVFS 0 +/* + * Use the Hildon framework + */ +#define wxUSE_LIBHILDON 0 +/* + * Use the Hildon 2.0 framework + */ +#define wxUSE_LIBHILDON2 0 +/* + * Use libnotify library. + */ +#define wxUSE_LIBNOTIFY 0 +/* + * Use libnotify 0.7+ API. + */ +#define wxUSE_LIBNOTIFY_0_7 0 +/* + * Use libXpm + */ +#define wxHAVE_LIB_XPM 0 +/* + * Define if you have pthread_cleanup_push/pop() + */ +#define wxHAVE_PTHREAD_CLEANUP 1 +/* + * Define if compiler has __thread keyword. + */ +/* #undef HAVE___THREAD_KEYWORD */ +/* + * Define if large (64 bit file offsets) files are supported. + */ +#define HAVE_LARGEFILE_SUPPORT 1 + +/* + * Use OpenGL + */ +#define wxUSE_OPENGL 0 + +/* + * Use MS HTML Help via libmspack (Unix) + */ +#define wxUSE_LIBMSPACK 0 + +/* + * Matthews garbage collection (used for MrEd?) + */ +#define WXGARBAGE_COLLECTION_ON 0 + +/* + * wxWebKitCtrl + */ +#define wxUSE_WEBKIT 0 + +/* + * wxMediaCtrl on OS X + */ +/* #undef wxOSX_USE_QTKIT */ + +/* + * Objective-C class name uniquifying + */ +#define wxUSE_OBJC_UNIQUIFYING 0 + +/* + * The const keyword is being introduced more in wxWindows. + * You can use this setting to maintain backward compatibility. + * If 0: will use const wherever possible. + * If 1: will use const only where necessary + * for precompiled headers to work. + * If 2: will be totally backward compatible, but precompiled + * headers may not work and program size will be larger. + */ +#define CONST_COMPATIBILITY 0 + +/* + * use the session manager to detect KDE/GNOME + */ +#define wxUSE_DETECT_SM 1 + + +/* define with the name of timezone variable */ +#define WX_TIMEZONE timezone + +/* The type of 3rd argument to getsockname() - usually size_t or int */ +#define WX_SOCKLEN_T socklen_t + +/* The type of 5th argument to getsockopt() - usually size_t or int */ +#define SOCKOPTLEN_T socklen_t + +/* The type of statvfs(2) argument */ +#define WX_STATFS_T struct statfs + +/* The signal handler prototype */ +#define wxTYPE_SA_HANDLER int + +/* gettimeofday() usually takes 2 arguments, but some really old systems might + * have only one, in which case define WX_GETTIMEOFDAY_NO_TZ */ +/* #undef WX_GETTIMEOFDAY_NO_TZ */ + +/* struct tm doesn't always have the tm_gmtoff field, define this if it does */ +#define WX_GMTOFF_IN_TM 1 + +/* Define if you have poll(2) function */ +/* #undef HAVE_POLL */ + +/* Define if you have pw_gecos field in struct passwd */ +#define HAVE_PW_GECOS 1 + +/* Define if you have __cxa_demangle() in */ +#define HAVE_CXA_DEMANGLE 1 + +/* Define if you have dlopen() */ +#define HAVE_DLOPEN 1 + +/* Define if you have gettimeofday() */ +#define HAVE_GETTIMEOFDAY 1 + +/* Define if fsync() is available */ +#define HAVE_FSYNC 1 + +/* Define if round() is available */ +#define HAVE_ROUND 1 + +/* Define if you have ftime() */ +/* #undef HAVE_FTIME */ + +/* Define if you have nanosleep() */ +#define HAVE_NANOSLEEP 1 + +/* Define if you have sched_yield */ +#define HAVE_SCHED_YIELD 1 + +/* Define if you have pthread_mutexattr_t and functions to work with it */ +#define HAVE_PTHREAD_MUTEXATTR_T 1 + +/* Define if you have pthread_mutexattr_settype() declaration */ +#define HAVE_PTHREAD_MUTEXATTR_SETTYPE_DECL 1 + +/* Define if you have PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP */ +/* #undef HAVE_PTHREAD_RECURSIVE_MUTEX_INITIALIZER */ + +/* Define if you have pthread_cancel */ +#define HAVE_PTHREAD_CANCEL 1 + +/* Define if you have pthread_mutex_timedlock */ +#define HAVE_PTHREAD_MUTEX_TIMEDLOCK 1 + +/* Define if you have pthread_attr_setstacksize */ +#define HAVE_PTHREAD_ATTR_SETSTACKSIZE 1 + +/* Define if you have shl_load() */ +/* #undef HAVE_SHL_LOAD */ + +/* Define if you have snprintf() */ +#define HAVE_SNPRINTF 1 + +/* Define if you have snprintf() declaration in the header */ +#define HAVE_SNPRINTF_DECL 1 + +/* Define if you have a snprintf() which supports positional arguments + (defined in the unix98 standard) */ +#define HAVE_UNIX98_PRINTF 1 + +/* define if you have statfs function */ +#define HAVE_STATFS 1 + +/* define if you have statfs prototype */ +#define HAVE_STATFS_DECL 1 + +/* define if you have statvfs function */ +/* #undef HAVE_STATVFS */ + +/* Define if you have strtoull() and strtoll() */ +#define HAVE_STRTOULL 1 + +/* Define if you have all functions to set thread priority */ +#define HAVE_THREAD_PRIORITY_FUNCTIONS 1 + +/* Define if you have vsnprintf() */ +#define HAVE_VSNPRINTF 1 + +/* Define if you have vsnprintf() declaration in the header */ +#define HAVE_VSNPRINTF_DECL 1 + +/* Define if you have a _broken_ vsnprintf() declaration in the header, + * with 'char*' for the 3rd parameter instead of 'const char*' */ +/* #undef HAVE_BROKEN_VSNPRINTF_DECL */ + +/* Define if you have a _broken_ vsscanf() declaration in the header, + * with 'char*' for the 1st parameter instead of 'const char*' */ +/* #undef HAVE_BROKEN_VSSCANF_DECL */ + +/* Define if you have vsscanf() */ +#define HAVE_VSSCANF 1 + +/* Define if you have vsscanf() declaration in the header */ +#define HAVE_VSSCANF_DECL 1 + +/* Define if you have usleep() */ +/* #undef HAVE_USLEEP */ + +/* Define if you have wcscasecmp() function */ +#define HAVE_WCSCASECMP 1 + +/* Define if you have wcsncasecmp() function */ +#define HAVE_WCSNCASECMP 1 + +/* Define if you have wcslen function */ +#define HAVE_WCSLEN 1 + +/* Define if you have wcsdup function */ +#define HAVE_WCSDUP 1 + +/* Define if you have wcsftime() function */ +#define HAVE_WCSFTIME 1 + +/* Define if you have strnlen() function */ +#define HAVE_STRNLEN 1 + +/* Define if you have wcsnlen() function */ +#define HAVE_WCSNLEN 1 + +/* Define if you have wcstoull() and wcstoll() */ +/* #undef HAVE_WCSTOULL */ + +/* The number of bytes in a wchar_t. */ +#define SIZEOF_WCHAR_T 4 + +/* The number of bytes in a int. */ +#define SIZEOF_INT 4 + +/* The number of bytes in a pointer. */ +#define SIZEOF_VOID_P 8 + +/* The number of bytes in a long. */ +#define SIZEOF_LONG 8 + +/* The number of bytes in a long long. */ +#define SIZEOF_LONG_LONG 8 + +/* The number of bytes in a short. */ +#define SIZEOF_SHORT 2 + +/* The number of bytes in a size_t. */ +#define SIZEOF_SIZE_T 8 + +/* Define if size_t on your machine is the same type as unsigned int. */ +/* #undef wxSIZE_T_IS_UINT */ + +/* Define if size_t on your machine is the same type as unsigned long. */ +#define wxSIZE_T_IS_ULONG 1 + +/* Define if wchar_t is distinct type in your compiler. */ +#define wxWCHAR_T_IS_REAL_TYPE 1 + +/* Define if you have the dlerror function. */ +#define HAVE_DLERROR 1 + +/* Define if you have Posix fnctl() function. */ +#define HAVE_FCNTL 1 + +/* Define if you have BSD flock() function. */ +/* #undef HAVE_FLOCK */ + +/* Define if you have getaddrinfo function. */ +/* #undef HAVE_GETADDRINFO */ + +/* Define if you have a gethostbyname_r function taking 6 arguments. */ +#define HAVE_FUNC_GETHOSTBYNAME_R_6 1 + +/* Define if you have a gethostbyname_r function taking 5 arguments. */ +/* #undef HAVE_FUNC_GETHOSTBYNAME_R_5 */ + +/* Define if you have a gethostbyname_r function taking 3 arguments. */ +/* #undef HAVE_FUNC_GETHOSTBYNAME_R_3 */ + +/* Define if you only have a gethostbyname function */ +/* #undef HAVE_GETHOSTBYNAME */ + +/* Define if you have the gethostname function. */ +/* #undef HAVE_GETHOSTNAME */ + +/* Define if you have a getservbyname_r function taking 6 arguments. */ +#define HAVE_FUNC_GETSERVBYNAME_R_6 1 + +/* Define if you have a getservbyname_r function taking 5 arguments. */ +/* #undef HAVE_FUNC_GETSERVBYNAME_R_5 */ + +/* Define if you have a getservbyname_r function taking 4 arguments. */ +/* #undef HAVE_FUNC_GETSERVBYNAME_R_4 */ + +/* Define if you only have a getservbyname function */ +/* #undef HAVE_GETSERVBYNAME */ + +/* Define if you have the gmtime_r function. */ +#define HAVE_GMTIME_R 1 + +/* Define if you have the inet_addr function. */ +#define HAVE_INET_ADDR 1 + +/* Define if you have the inet_aton function. */ +#define HAVE_INET_ATON 1 + +/* Define if you have the localtime_r function. */ +#define HAVE_LOCALTIME_R 1 + +/* Define if you have the mktemp function. */ +/* #undef HAVE_MKTEMP */ + +/* Define if you have the mkstemp function. */ +#define HAVE_MKSTEMP 1 + +/* Define if you have the putenv function. */ +/* #undef HAVE_PUTENV */ + +/* Define if you have the setenv function. */ +#define HAVE_SETENV 1 + +/* Define if you have strtok_r function. */ +/* #define HAVE_STRTOK_R */ + +/* Define if you have thr_setconcurrency function */ +/* #undef HAVE_THR_SETCONCURRENCY */ + +/* Define if you have pthread_setconcurrency function */ +#define HAVE_PTHREAD_SET_CONCURRENCY 1 + +/* Define if you have the uname function. */ +#define HAVE_UNAME 1 + +/* Define if you have the unsetenv function. */ +#define HAVE_UNSETENV 1 + +/* Define if you have the header file. */ +#define HAVE_X11_XKBLIB_H 1 + +/* Define if you have the header file. */ +#define HAVE_X11_EXTENSIONS_XF86VMODE_H 1 + +/* Define if you have the header file. */ +#define HAVE_SCHED_H 1 + +/* Define if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define if you have the header file. */ +/* #undef HAVE_FCNTL_H */ + +/* Define if you have the header file. */ +#define HAVE_WCHAR_H 1 + +/* Define if you have the header file. */ +/* #undef HAVE_WCSTR_H */ + +/* Define if you have (Solaris only) */ +/* #undef HAVE_WIDEC_H */ + +/* Define if you have the header file and iconv() symbol. */ +#define HAVE_ICONV 1 + +/* Define as "const" if the declaration of iconv() needs const. */ +#define ICONV_CONST + +/* Define if you have the header file. */ +#define HAVE_LANGINFO_H 1 + +/* Define if you have the header file (mingw,cygwin). */ +/* #undef HAVE_W32API_H */ + +/* Define if you have the header file. */ +#define HAVE_SYS_SOUNDCARD_H 1 + +/* Define if you have wcsrtombs() function */ +#define HAVE_WCSRTOMBS 1 + +/* Define this if you have putws() */ +/* #undef HAVE_PUTWS */ + +/* Define this if you have fputws() */ +#define HAVE_FPUTWS 1 + +/* Define this if you have wprintf() and related functions */ +#define HAVE_WPRINTF 1 + +/* Define this if you have vswprintf() and related functions */ +#define HAVE_VSWPRINTF 1 + +/* Define this if you have _vsnwprintf */ +/* #undef HAVE__VSNWPRINTF */ + +/* vswscanf() */ +#define HAVE_VSWSCANF 1 + +/* Define if fseeko and ftello are available. */ +#define HAVE_FSEEKO 1 + +/* Define this if you are using gtk and gdk contains support for X11R6 XIM */ +/* #undef HAVE_XIM */ + +/* Define this if you have X11/extensions/shape.h */ +/* #undef HAVE_XSHAPE */ + +/* Define this if you have type SPBCDATA */ +/* #undef HAVE_SPBCDATA */ + +/* Define if you have pango_font_family_is_monospace() (Pango >= 1.3.3) */ +/* #undef HAVE_PANGO_FONT_FAMILY_IS_MONOSPACE */ + +/* Define if you have Pango xft support */ +/* #undef HAVE_PANGO_XFT */ + +/* Define if you have the header file. */ +#define HAVE_SYS_SELECT_H 1 + +/* Define if you have abi::__forced_unwind in your . */ +#define HAVE_ABI_FORCEDUNWIND 1 + +/* Define if fdopen is available. */ +#define HAVE_FDOPEN 1 + +/* Define if sysconf is available. */ +#define HAVE_SYSCONF 1 + +/* Define if getpwuid_r is available. */ +#define HAVE_GETPWUID_R 1 + +/* Define if getgrgid_r is available. */ +#define HAVE_GETGRGID_R 1 + +/* Define if setpriority() is available. */ +#define HAVE_SETPRIORITY 1 + +/* Define if locale_t is available */ +/* #undef HAVE_LOCALE_T */ + +/* Define if you have inotify_xxx() functions. */ +#define wxHAS_INOTIFY 1 + +/* Define if you have kqueu_xxx() functions. */ +/* #undef wxHAS_KQUEUE */ +#endif + +#endif /* __WX_SETUP_H__ */ + diff --git a/3rdparty/wxwidgets3.0/include/wx/chartype.h b/3rdparty/wxwidgets3.0/include/wx/chartype.h index 5217258d1b54b..d1f26e529d5a5 100644 --- a/3rdparty/wxwidgets3.0/include/wx/chartype.h +++ b/3rdparty/wxwidgets3.0/include/wx/chartype.h @@ -287,17 +287,16 @@ /* a helper macro allowing to make another macro Unicode-friendly, see below */ #define wxAPPLY_T(x) wxT(x) -/* Unicode-friendly __FILE__, __DATE__ and __TIME__ analogs */ #ifndef __TFILE__ #define __TFILE__ wxAPPLY_T(__FILE__) #endif #ifndef __TDATE__ - #define __TDATE__ wxAPPLY_T(__DATE__) + #define __TDATE__ "" #endif #ifndef __TTIME__ - #define __TTIME__ wxAPPLY_T(__TIME__) + #define __TTIME__ "" #endif #endif /* _WX_WXCHARTYPE_H_ */ diff --git a/3rdparty/wxwidgets3.0/include/wx/unix/app.h b/3rdparty/wxwidgets3.0/include/wx/unix/app.h new file mode 100755 index 0000000000000..f14df9ec3fa79 --- /dev/null +++ b/3rdparty/wxwidgets3.0/include/wx/unix/app.h @@ -0,0 +1,73 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: wx/unix/app.h +// Purpose: wxAppConsole implementation for Unix +// Author: Lukasz Michalski +// Created: 28/01/2005 +// Copyright: (c) Lukasz Michalski +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +//Ensure that sigset_t is being defined +#include + +class wxFDIODispatcher; +class wxFDIOHandler; +class wxWakeUpPipe; + +// wxApp subclass implementing event processing for console applications +class WXDLLIMPEXP_BASE wxAppConsole : public wxAppConsoleBase +{ +public: + wxAppConsole(); + virtual ~wxAppConsole(); + + // override base class initialization + virtual bool Initialize(int& argc, wxChar** argv); + + + // Unix-specific: Unix signal handling + // ----------------------------------- + + // type of the function which can be registered as signal handler: notice + // that it isn't really a signal handler, i.e. it's not subject to the + // usual signal handlers constraints, because it is called later from + // CheckSignal() and not when the signal really occurs + typedef void (*SignalHandler)(int); + + // Set signal handler for the given signal, SIG_DFL or SIG_IGN can be used + // instead of a function pointer + // + // Return true if handler was installed, false on error + bool SetSignalHandler(int signal, SignalHandler handler); + + // Check if any Unix signals arrived since the last call and execute + // handlers for them + void CheckSignal(); + + // Register the signal wake up pipe with the given dispatcher. + // + // This is used by wxExecute(wxEXEC_NOEVENTS) implementation only. + // + // The pointer to the handler used for processing events on this descriptor + // is returned so that it can be deleted when we no longer needed it. + wxFDIOHandler* RegisterSignalWakeUpPipe(wxFDIODispatcher& dispatcher); + +private: + // signal handler set up by SetSignalHandler() for all signals we handle, + // it just adds the signal to m_signalsCaught -- the real processing is + // done later, when CheckSignal() is called + static void HandleSignal(int signal); + + + // signals for which HandleSignal() had been called (reset from + // CheckSignal()) + sigset_t m_signalsCaught; + + // the signal handlers + WX_DECLARE_HASH_MAP(int, SignalHandler, wxIntegerHash, wxIntegerEqual, SignalHandlerHash); + SignalHandlerHash m_signalHandlerHash; + + // pipe used for wake up signal handling: if a signal arrives while we're + // blocking for input, writing to this pipe triggers a call to our CheckSignal() + wxWakeUpPipe *m_signalWakeUpPipe; +}; diff --git a/3rdparty/wxwidgets3.0/include/wx/unix/apptbase.h b/3rdparty/wxwidgets3.0/include/wx/unix/apptbase.h new file mode 100755 index 0000000000000..6ce6f152c3320 --- /dev/null +++ b/3rdparty/wxwidgets3.0/include/wx/unix/apptbase.h @@ -0,0 +1,67 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: wx/unix/apptbase.h +// Purpose: declaration of wxAppTraits for Unix systems +// Author: Vadim Zeitlin +// Modified by: +// Created: 23.06.2003 +// Copyright: (c) 2003 Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _WX_UNIX_APPTBASE_H_ +#define _WX_UNIX_APPTBASE_H_ + +#include "wx/evtloop.h" +#include "wx/evtloopsrc.h" + +class wxExecuteData; +class wxFDIOManager; +class wxEventLoopSourcesManagerBase; + +// ---------------------------------------------------------------------------- +// wxAppTraits: the Unix version adds extra hooks needed by Unix code +// ---------------------------------------------------------------------------- + +class WXDLLIMPEXP_BASE wxAppTraits : public wxAppTraitsBase +{ +public: + // wxExecute() support methods + // --------------------------- + + // Wait for the process termination and return its exit code or -1 on error. + // + // Notice that this is only used when execData.flags contains wxEXEC_SYNC + // and does not contain wxEXEC_NOEVENTS, i.e. when we need to really wait + // until the child process exit and dispatch the events while doing it. + virtual int WaitForChild(wxExecuteData& execData); + +#if wxUSE_SOCKETS + // return a pointer to the object which should be used to integrate + // monitoring of the file descriptors to the event loop (currently this is + // used for the sockets only but should be used for arbitrary event loop + // sources in the future) + // + // this object may be different for the console and GUI applications + // + // the pointer is not deleted by the caller as normally it points to a + // static variable + virtual wxFDIOManager *GetFDIOManager(); +#endif // wxUSE_SOCKETS + +#if wxUSE_CONSOLE_EVENTLOOP + // Return a non-NULL pointer to the object responsible for managing the + // event loop sources in this kind of application. + virtual wxEventLoopSourcesManagerBase* GetEventLoopSourcesManager(); +#endif // wxUSE_CONSOLE_EVENTLOOP + +protected: + // Wait for the process termination by running the given event loop until + // this happens. + // + // This is used by the public WaitForChild() after creating the event loop + // of the appropriate kind. + int RunLoopUntilChildExit(wxExecuteData& execData, wxEventLoopBase& loop); +}; + +#endif // _WX_UNIX_APPTBASE_H_ + diff --git a/3rdparty/wxwidgets3.0/include/wx/unix/apptrait.h b/3rdparty/wxwidgets3.0/include/wx/unix/apptrait.h new file mode 100755 index 0000000000000..3fbe4d82daa59 --- /dev/null +++ b/3rdparty/wxwidgets3.0/include/wx/unix/apptrait.h @@ -0,0 +1,94 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: wx/unix/apptrait.h +// Purpose: standard implementations of wxAppTraits for Unix +// Author: Vadim Zeitlin +// Modified by: +// Created: 23.06.2003 +// Copyright: (c) 2003 Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _WX_UNIX_APPTRAIT_H_ +#define _WX_UNIX_APPTRAIT_H_ + +// ---------------------------------------------------------------------------- +// wxGUI/ConsoleAppTraits: must derive from wxAppTraits, not wxAppTraitsBase +// ---------------------------------------------------------------------------- + +class WXDLLIMPEXP_BASE wxConsoleAppTraits : public wxConsoleAppTraitsBase +{ +public: +#if wxUSE_CONSOLE_EVENTLOOP + virtual wxEventLoopBase *CreateEventLoop(); +#endif // wxUSE_CONSOLE_EVENTLOOP +#if wxUSE_TIMER + virtual wxTimerImpl *CreateTimerImpl(wxTimer *timer); +#endif +}; + +#if wxUSE_GUI + +// GTK+ and Motif integrate sockets and child processes monitoring directly in +// their main loop, the other Unix ports do it at wxEventLoop level and so use +// the non-GUI traits and don't need anything here +// +// TODO: Should we use XtAddInput() for wxX11 too? Or, vice versa, if there is +// no advantage in doing this compared to the generic way currently used +// by wxX11, should we continue to use GTK/Motif-specific stuff? +#if defined(__WXGTK__) || defined(__WXMOTIF__) + #define wxHAS_GUI_FDIOMANAGER + #define wxHAS_GUI_PROCESS_CALLBACKS +#endif // ports using wxFDIOManager + +#if defined(__WXMAC__) + #define wxHAS_GUI_PROCESS_CALLBACKS + #define wxHAS_GUI_SOCKET_MANAGER +#endif + +class WXDLLIMPEXP_CORE wxGUIAppTraits : public wxGUIAppTraitsBase +{ +public: + virtual wxEventLoopBase *CreateEventLoop(); + virtual int WaitForChild(wxExecuteData& execData); +#if wxUSE_TIMER + virtual wxTimerImpl *CreateTimerImpl(wxTimer *timer); +#endif +#if wxUSE_THREADS && defined(__WXGTK20__) + virtual void MutexGuiEnter(); + virtual void MutexGuiLeave(); +#endif + +#if (defined(__WXMAC__) || defined(__WXCOCOA__)) && wxUSE_STDPATHS + virtual wxStandardPaths& GetStandardPaths(); +#endif + virtual wxPortId GetToolkitVersion(int *majVer = NULL, int *minVer = NULL) const; + +#ifdef __WXGTK20__ + virtual wxString GetDesktopEnvironment() const; + virtual wxString GetStandardCmdLineOptions(wxArrayString& names, + wxArrayString& desc) const; +#endif // __WXGTK20____ + +#if defined(__WXGTK20__) + virtual bool ShowAssertDialog(const wxString& msg); +#endif + +#if wxUSE_SOCKETS + +#ifdef wxHAS_GUI_SOCKET_MANAGER + virtual wxSocketManager *GetSocketManager(); +#endif + +#ifdef wxHAS_GUI_FDIOMANAGER + virtual wxFDIOManager *GetFDIOManager(); +#endif + +#endif // wxUSE_SOCKETS + + virtual wxEventLoopSourcesManagerBase* GetEventLoopSourcesManager(); +}; + +#endif // wxUSE_GUI + +#endif // _WX_UNIX_APPTRAIT_H_ + diff --git a/3rdparty/wxwidgets3.0/include/wx/unix/chkconf.h b/3rdparty/wxwidgets3.0/include/wx/unix/chkconf.h new file mode 100755 index 0000000000000..b8a1904133460 --- /dev/null +++ b/3rdparty/wxwidgets3.0/include/wx/unix/chkconf.h @@ -0,0 +1,43 @@ +/* + * Name: wx/unix/chkconf.h + * Purpose: Unix-specific config settings consistency checks + * Author: Vadim Zeitlin + * Created: 2007-07-14 + * Copyright: (c) 2007 Vadim Zeitlin + * Licence: wxWindows licence + */ + +/* THIS IS A C FILE, DON'T USE C++ FEATURES (IN PARTICULAR COMMENTS) IN IT */ + +#if wxUSE_CONSOLE_EVENTLOOP +# if !wxUSE_SELECT_DISPATCHER && !wxUSE_EPOLL_DISPATCHER +# ifdef wxABORT_ON_CONFIG_ERROR +# error "wxSelect/EpollDispatcher needed for console event loop" +# else +# undef wxUSE_SELECT_DISPATCHER +# define wxUSE_SELECT_DISPATCHER 1 +# endif +# endif +#endif /* wxUSE_CONSOLE_EVENTLOOP */ + +#if wxUSE_FSWATCHER +# if !defined(wxHAS_INOTIFY) && !defined(wxHAS_KQUEUE) +# ifdef wxABORT_ON_CONFIG_ERROR +# error "wxFileSystemWatcher requires either inotify() or kqueue()" +# else +# undef wxUSE_FSWATCHER +# define wxUSE_FSWATCHER 0 +# endif +# endif +#endif /* wxUSE_FSWATCHER */ + +#if wxUSE_GSTREAMER +# if !wxUSE_THREADS +# ifdef wxABORT_ON_CONFIG_ERROR +# error "GStreamer requires threads" +# else +# undef wxUSE_GSTREAMER +# define wxUSE_GSTREAMER 0 +# endif +# endif +#endif /* wxUSE_GSTREAMER */ diff --git a/3rdparty/wxwidgets3.0/include/wx/unix/evtloop.h b/3rdparty/wxwidgets3.0/include/wx/unix/evtloop.h new file mode 100755 index 0000000000000..2b91c72375bfd --- /dev/null +++ b/3rdparty/wxwidgets3.0/include/wx/unix/evtloop.h @@ -0,0 +1,62 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: wx/unix/evtloop.h +// Purpose: declares wxEventLoop class +// Author: Lukasz Michalski (lm@zork.pl) +// Created: 2007-05-07 +// Copyright: (c) 2007 Lukasz Michalski +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _WX_UNIX_EVTLOOP_H_ +#define _WX_UNIX_EVTLOOP_H_ + +#if wxUSE_CONSOLE_EVENTLOOP + +// ---------------------------------------------------------------------------- +// wxConsoleEventLoop +// ---------------------------------------------------------------------------- + +class wxEventLoopSource; +class wxFDIODispatcher; +class wxWakeUpPipeMT; + +class WXDLLIMPEXP_BASE wxConsoleEventLoop +#ifdef __WXOSX__ +: public wxCFEventLoop +#else +: public wxEventLoopManual +#endif +{ +public: + // initialize the event loop, use IsOk() to check if we were successful + wxConsoleEventLoop(); + virtual ~wxConsoleEventLoop(); + + // implement base class pure virtuals + virtual bool Pending() const; + virtual bool Dispatch(); + virtual int DispatchTimeout(unsigned long timeout); + virtual void WakeUp(); + virtual bool IsOk() const { return m_dispatcher != NULL; } + virtual bool YieldFor(long WXUNUSED(eventsToProcess)) { return true; } + +protected: + virtual void OnNextIteration(); + +private: + // pipe used for wake up messages: when a child thread wants to wake up + // the event loop in the main thread it writes to this pipe + wxWakeUpPipeMT *m_wakeupPipe; + + // the event loop source used to monitor this pipe + wxEventLoopSource* m_wakeupSource; + + // either wxSelectDispatcher or wxEpollDispatcher + wxFDIODispatcher *m_dispatcher; + + wxDECLARE_NO_COPY_CLASS(wxConsoleEventLoop); +}; + +#endif // wxUSE_CONSOLE_EVENTLOOP + +#endif // _WX_UNIX_EVTLOOP_H_ diff --git a/3rdparty/wxwidgets3.0/include/wx/unix/evtloopsrc.h b/3rdparty/wxwidgets3.0/include/wx/unix/evtloopsrc.h new file mode 100755 index 0000000000000..4c2cfec16770f --- /dev/null +++ b/3rdparty/wxwidgets3.0/include/wx/unix/evtloopsrc.h @@ -0,0 +1,48 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: wx/unix/evtloopsrc.h +// Purpose: wxUnixEventLoopSource class +// Author: Vadim Zeitlin +// Created: 2009-10-21 +// Copyright: (c) 2009 Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _WX_UNIX_EVTLOOPSRC_H_ +#define _WX_UNIX_EVTLOOPSRC_H_ + +class wxFDIODispatcher; +class wxFDIOHandler; + +// ---------------------------------------------------------------------------- +// wxUnixEventLoopSource: wxEventLoopSource for Unix-like toolkits using fds +// ---------------------------------------------------------------------------- + +class wxUnixEventLoopSource : public wxEventLoopSource +{ +public: + // dispatcher and fdioHandler are only used here to allow us to unregister + // from the event loop when we're destroyed + wxUnixEventLoopSource(wxFDIODispatcher *dispatcher, + wxFDIOHandler *fdioHandler, + int fd, + wxEventLoopSourceHandler *handler, + int flags) + : wxEventLoopSource(handler, flags), + m_dispatcher(dispatcher), + m_fdioHandler(fdioHandler), + m_fd(fd) + { + } + + virtual ~wxUnixEventLoopSource(); + +private: + wxFDIODispatcher * const m_dispatcher; + wxFDIOHandler * const m_fdioHandler; + const int m_fd; + + wxDECLARE_NO_COPY_CLASS(wxUnixEventLoopSource); +}; + +#endif // _WX_UNIX_EVTLOOPSRC_H_ + diff --git a/3rdparty/wxwidgets3.0/include/wx/unix/execute.h b/3rdparty/wxwidgets3.0/include/wx/unix/execute.h new file mode 100755 index 0000000000000..9756c00a7dc48 --- /dev/null +++ b/3rdparty/wxwidgets3.0/include/wx/unix/execute.h @@ -0,0 +1,102 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: wx/unix/execute.h +// Purpose: private details of wxExecute() implementation +// Author: Vadim Zeitlin +// Copyright: (c) 1998 Robert Roebling, Julian Smart, Vadim Zeitlin +// (c) 2013 Vadim Zeitlin +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifndef _WX_UNIX_EXECUTE_H +#define _WX_UNIX_EXECUTE_H + +#include "wx/app.h" +#include "wx/hashmap.h" +#include "wx/process.h" + +#if wxUSE_STREAMS + #include "wx/unix/pipe.h" + #include "wx/private/streamtempinput.h" +#endif + +class wxEventLoopBase; + +// Information associated with a running child process. +class wxExecuteData +{ +public: + wxExecuteData() + { + flags = + pid = 0; + exitcode = -1; + + process = NULL; + + syncEventLoop = NULL; + +#if wxUSE_STREAMS + fdOut = + fdErr = wxPipe::INVALID_FD; +#endif // wxUSE_STREAMS + } + + // This must be called in the parent process as soon as fork() returns to + // update us with the effective child PID. It also ensures that we handle + // SIGCHLD to be able to detect when this PID exits, so wxTheApp must be + // available. + void OnStart(int pid); + + // Called when the child process exits. + void OnExit(int exitcode); + + // Return true if we should (or already did) redirect the child IO. + bool IsRedirected() const { return process && process->IsRedirected(); } + + + // wxExecute() flags + int flags; + + // the pid of the child process + int pid; + + // The exit code of the process, set once the child terminates. + int exitcode; + + // the associated process object or NULL + wxProcess *process; + + // Local event loop used to wait for the child process termination in + // synchronous execution case. We can't create it ourselves as its exact + // type depends on the application kind (console/GUI), so we rely on + // wxAppTraits setting up this pointer to point to the appropriate object. + wxEventLoopBase *syncEventLoop; + +#if wxUSE_STREAMS + // the input buffer bufOut is connected to stdout, this is why it is + // called bufOut and not bufIn + wxStreamTempInputBuffer bufOut, + bufErr; + + // the corresponding FDs, -1 if not redirected + int fdOut, + fdErr; +#endif // wxUSE_STREAMS + + +private: + // SIGCHLD signal handler that checks whether any of the currently running + // children have exited. + static void OnSomeChildExited(int sig); + + // All currently running child processes indexed by their PID. + // + // Notice that the container doesn't own its elements. + WX_DECLARE_HASH_MAP(int, wxExecuteData*, wxIntegerHash, wxIntegerEqual, + ChildProcessesData); + static ChildProcessesData ms_childProcesses; + + wxDECLARE_NO_COPY_CLASS(wxExecuteData); +}; + +#endif // _WX_UNIX_EXECUTE_H diff --git a/3rdparty/wxwidgets3.0/include/wx/unix/fontutil.h b/3rdparty/wxwidgets3.0/include/wx/unix/fontutil.h new file mode 100755 index 0000000000000..64cb3a3ccd43a --- /dev/null +++ b/3rdparty/wxwidgets3.0/include/wx/unix/fontutil.h @@ -0,0 +1,36 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: wx/unix/fontutil.h +// Purpose: font-related helper functions for Unix/X11 +// Author: Vadim Zeitlin +// Modified by: +// Created: 05.11.99 +// Copyright: (c) wxWidgets team +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifndef _WX_UNIX_FONTUTIL_H_ +#define _WX_UNIX_FONTUTIL_H_ + +#ifdef __X__ + typedef WXFontStructPtr wxNativeFont; +#elif defined(__WXGTK__) + typedef GdkFont *wxNativeFont; +#else + #error "Unsupported toolkit" +#endif + +// returns the handle of the nearest available font or 0 +extern wxNativeFont +wxLoadQueryNearestFont(int pointSize, + int family, + int style, + int weight, + bool underlined, + const wxString &facename, + wxFontEncoding encoding, + wxString* xFontName = NULL); + +// returns the font specified by the given XLFD +extern wxNativeFont wxLoadFont(const wxString& fontSpec); + +#endif // _WX_UNIX_FONTUTIL_H_ diff --git a/3rdparty/wxwidgets3.0/include/wx/unix/fswatcher_inotify.h b/3rdparty/wxwidgets3.0/include/wx/unix/fswatcher_inotify.h new file mode 100755 index 0000000000000..1881966053252 --- /dev/null +++ b/3rdparty/wxwidgets3.0/include/wx/unix/fswatcher_inotify.h @@ -0,0 +1,36 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: wx/unix/fswatcher_inotify.h +// Purpose: wxInotifyFileSystemWatcher +// Author: Bartosz Bekier +// Created: 2009-05-26 +// Copyright: (c) 2009 Bartosz Bekier +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifndef _WX_FSWATCHER_UNIX_H_ +#define _WX_FSWATCHER_UNIX_H_ + +#include "wx/defs.h" + +#if wxUSE_FSWATCHER + +class WXDLLIMPEXP_BASE wxInotifyFileSystemWatcher : + public wxFileSystemWatcherBase +{ +public: + wxInotifyFileSystemWatcher(); + + wxInotifyFileSystemWatcher(const wxFileName& path, + int events = wxFSW_EVENT_ALL); + + virtual ~wxInotifyFileSystemWatcher(); + + void OnDirDeleted(const wxString& path); + +protected: + bool Init(); +}; + +#endif + +#endif /* _WX_FSWATCHER_UNIX_H_ */ diff --git a/3rdparty/wxwidgets3.0/include/wx/unix/fswatcher_kqueue.h b/3rdparty/wxwidgets3.0/include/wx/unix/fswatcher_kqueue.h new file mode 100755 index 0000000000000..a324eb7efd1c4 --- /dev/null +++ b/3rdparty/wxwidgets3.0/include/wx/unix/fswatcher_kqueue.h @@ -0,0 +1,34 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: wx/unix/fswatcher_kqueue.h +// Purpose: wxKqueueFileSystemWatcher +// Author: Bartosz Bekier +// Created: 2009-05-26 +// Copyright: (c) 2009 Bartosz Bekier +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifndef _WX_FSWATCHER_KQUEUE_H_ +#define _WX_FSWATCHER_KQUEUE_H_ + +#include "wx/defs.h" + +#if wxUSE_FSWATCHER + +class WXDLLIMPEXP_BASE wxKqueueFileSystemWatcher : + public wxFileSystemWatcherBase +{ +public: + wxKqueueFileSystemWatcher(); + + wxKqueueFileSystemWatcher(const wxFileName& path, + int events = wxFSW_EVENT_ALL); + + virtual ~wxKqueueFileSystemWatcher(); + +protected: + bool Init(); +}; + +#endif + +#endif /* _WX_FSWATCHER_OSX_H_ */ diff --git a/3rdparty/wxwidgets3.0/include/wx/unix/glx11.h b/3rdparty/wxwidgets3.0/include/wx/unix/glx11.h new file mode 100755 index 0000000000000..34ed4dd46de2f --- /dev/null +++ b/3rdparty/wxwidgets3.0/include/wx/unix/glx11.h @@ -0,0 +1,164 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: wx/unix/glx11.h +// Purpose: class common for all X11-based wxGLCanvas implementations +// Author: Vadim Zeitlin +// Created: 2007-04-15 +// Copyright: (c) 2007 Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _WX_UNIX_GLX11_H_ +#define _WX_UNIX_GLX11_H_ + +#include + +// ---------------------------------------------------------------------------- +// wxGLContext +// ---------------------------------------------------------------------------- + +class WXDLLIMPEXP_GL wxGLContext : public wxGLContextBase +{ +public: + wxGLContext(wxGLCanvas *win, const wxGLContext *other = NULL); + virtual ~wxGLContext(); + + virtual bool SetCurrent(const wxGLCanvas& win) const; + +private: + // attach context to the drawable or unset it (if NULL) + static bool MakeCurrent(GLXDrawable drawable, GLXContext context); + + GLXContext m_glContext; + + DECLARE_CLASS(wxGLContext) +}; + +// ---------------------------------------------------------------------------- +// wxGLCanvasX11 +// ---------------------------------------------------------------------------- + +class WXDLLIMPEXP_GL wxGLCanvasX11 : public wxGLCanvasBase +{ +public: + // initialization and dtor + // ----------------------- + + // default ctor doesn't do anything, InitVisual() must be called + wxGLCanvasX11(); + + // initializes the XVisualInfo corresponding to the given attributes + bool InitVisual(const int *attribList); + + // frees XVisualInfo info + virtual ~wxGLCanvasX11(); + + + // implement wxGLCanvasBase methods + // -------------------------------- + + virtual bool SwapBuffers(); + + + // X11-specific methods + // -------------------- + + // return GLX version: 13 means 1.3 &c + static int GetGLXVersion(); + + // return true if multisample extension is available + static bool IsGLXMultiSampleAvailable(); + + // get the X11 handle of this window + virtual Window GetXWindow() const = 0; + + + // override some wxWindow methods + // ------------------------------ + + // return true only if the window is realized: OpenGL context can't be + // created until we are + virtual bool IsShownOnScreen() const; + + + // implementation only from now on + // ------------------------------- + + // get the GLXFBConfig/XVisualInfo we use + GLXFBConfig *GetGLXFBConfig() const { return m_fbc; } + XVisualInfo *GetXVisualInfo() const { return m_vi; } + + // initialize the global default GL visual, return false if matching visual + // not found + static bool InitDefaultVisualInfo(const int *attribList); + + // get the default GL X11 visual (may be NULL, shouldn't be freed by caller) + static XVisualInfo *GetDefaultXVisualInfo() { return ms_glVisualInfo; } + + // free the global GL visual, called by wxGLApp + static void FreeDefaultVisualInfo(); + + // initializes XVisualInfo (in any case) and, if supported, GLXFBConfig + // + // returns false if XVisualInfo couldn't be initialized, otherwise caller + // is responsible for freeing the pointers + static bool InitXVisualInfo(const int *attribList, + GLXFBConfig **pFBC, XVisualInfo **pXVisual); + +private: + // fills in glattrs with attributes defined by wxattrs which must be + // 0-terminated if it is non-NULL + // + // n is the max size of glattrs, false is returned if we overflow it, it + // should be at least 16 to accommodate the default attributes + static bool ConvertWXAttrsToGL(const int *wxattrs, int *glattrs, size_t n); + + + // this is only used if it's supported i.e. if GL >= 1.3 + GLXFBConfig *m_fbc; + + // used for all GL versions, obtained from GLXFBConfig for GL >= 1.3 + XVisualInfo *m_vi; + + // the global/default versions of the above + static GLXFBConfig *ms_glFBCInfo; + static XVisualInfo *ms_glVisualInfo; +}; + +// ---------------------------------------------------------------------------- +// wxGLApp +// ---------------------------------------------------------------------------- + +// this is used in wx/glcanvas.h, prevent it from defining a generic wxGLApp +#define wxGL_APP_DEFINED + +class WXDLLIMPEXP_GL wxGLApp : public wxGLAppBase +{ +public: + wxGLApp() : wxGLAppBase() { } + + // implement wxGLAppBase method + virtual bool InitGLVisual(const int *attribList) + { + return wxGLCanvasX11::InitDefaultVisualInfo(attribList); + } + + // and implement this wxGTK::wxApp method too + virtual void *GetXVisualInfo() + { + return wxGLCanvasX11::GetDefaultXVisualInfo(); + } + + // and override this wxApp method to clean up + virtual int OnExit() + { + wxGLCanvasX11::FreeDefaultVisualInfo(); + + return wxGLAppBase::OnExit(); + } + +private: + DECLARE_DYNAMIC_CLASS(wxGLApp) +}; + +#endif // _WX_UNIX_GLX11_H_ + diff --git a/3rdparty/wxwidgets3.0/include/wx/unix/joystick.h b/3rdparty/wxwidgets3.0/include/wx/unix/joystick.h new file mode 100755 index 0000000000000..ef7a5db223d65 --- /dev/null +++ b/3rdparty/wxwidgets3.0/include/wx/unix/joystick.h @@ -0,0 +1,94 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: wx/unix/joystick.h +// Purpose: wxJoystick class +// Author: Guilhem Lavaux +// Modified by: +// Created: 01/02/97 +// Copyright: (c) Guilhem Lavaux +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifndef _WX_UNIX_JOYSTICK_H_ +#define _WX_UNIX_JOYSTICK_H_ + +#include "wx/event.h" + +class WXDLLIMPEXP_FWD_CORE wxJoystickThread; + +class WXDLLIMPEXP_ADV wxJoystick: public wxObject +{ + DECLARE_DYNAMIC_CLASS(wxJoystick) + public: + /* + * Public interface + */ + + wxJoystick(int joystick = wxJOYSTICK1); + virtual ~wxJoystick(); + + // Attributes + //////////////////////////////////////////////////////////////////////////// + + wxPoint GetPosition() const; + int GetPosition(unsigned axis) const; + bool GetButtonState(unsigned button) const; + int GetZPosition() const; + int GetButtonState() const; + int GetPOVPosition() const; + int GetPOVCTSPosition() const; + int GetRudderPosition() const; + int GetUPosition() const; + int GetVPosition() const; + int GetMovementThreshold() const; + void SetMovementThreshold(int threshold) ; + + // Capabilities + //////////////////////////////////////////////////////////////////////////// + + bool IsOk() const; // Checks that the joystick is functioning + static int GetNumberJoysticks() ; + int GetManufacturerId() const ; + int GetProductId() const ; + wxString GetProductName() const ; + int GetXMin() const; + int GetYMin() const; + int GetZMin() const; + int GetXMax() const; + int GetYMax() const; + int GetZMax() const; + int GetNumberButtons() const; + int GetNumberAxes() const; + int GetMaxButtons() const; + int GetMaxAxes() const; + int GetPollingMin() const; + int GetPollingMax() const; + int GetRudderMin() const; + int GetRudderMax() const; + int GetUMin() const; + int GetUMax() const; + int GetVMin() const; + int GetVMax() const; + + bool HasRudder() const; + bool HasZ() const; + bool HasU() const; + bool HasV() const; + bool HasPOV() const; + bool HasPOV4Dir() const; + bool HasPOVCTS() const; + + // Operations + //////////////////////////////////////////////////////////////////////////// + + // pollingFreq = 0 means that movement events are sent when above the threshold. + // If pollingFreq > 0, events are received every this many milliseconds. + bool SetCapture(wxWindow* win, int pollingFreq = 0); + bool ReleaseCapture(); + +protected: + int m_device; + int m_joystick; + wxJoystickThread* m_thread; +}; + +#endif // _WX_UNIX_JOYSTICK_H_ diff --git a/3rdparty/wxwidgets3.0/include/wx/unix/mimetype.h b/3rdparty/wxwidgets3.0/include/wx/unix/mimetype.h new file mode 100755 index 0000000000000..df76534aa5bf5 --- /dev/null +++ b/3rdparty/wxwidgets3.0/include/wx/unix/mimetype.h @@ -0,0 +1,173 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: wx/unix/mimetype.h +// Purpose: classes and functions to manage MIME types +// Author: Vadim Zeitlin +// Modified by: +// Created: 23.09.98 +// Copyright: (c) 1998 Vadim Zeitlin +// Licence: wxWindows licence (part of wxExtra library) +///////////////////////////////////////////////////////////////////////////// + +#ifndef _MIMETYPE_IMPL_H +#define _MIMETYPE_IMPL_H + +#include "wx/mimetype.h" + +#if wxUSE_MIMETYPE + +class wxMimeTypeCommands; + +WX_DEFINE_ARRAY_PTR(wxMimeTypeCommands *, wxMimeCommandsArray); + +// this is the real wxMimeTypesManager for Unix +class WXDLLIMPEXP_BASE wxMimeTypesManagerImpl +{ +public: + // ctor and dtor + wxMimeTypesManagerImpl(); + virtual ~wxMimeTypesManagerImpl(); + + // load all data into memory - done when it is needed for the first time + void Initialize(int mailcapStyles = wxMAILCAP_ALL, + const wxString& extraDir = wxEmptyString); + + // and delete the data here + void ClearData(); + + // implement containing class functions + wxFileType *GetFileTypeFromExtension(const wxString& ext); + wxFileType *GetFileTypeFromMimeType(const wxString& mimeType); + + size_t EnumAllFileTypes(wxArrayString& mimetypes); + + void AddFallback(const wxFileTypeInfo& filetype); + + // add information about the given mimetype + void AddMimeTypeInfo(const wxString& mimetype, + const wxString& extensions, + const wxString& description); + void AddMailcapInfo(const wxString& strType, + const wxString& strOpenCmd, + const wxString& strPrintCmd, + const wxString& strTest, + const wxString& strDesc); + + // add a new record to the user .mailcap/.mime.types files + wxFileType *Associate(const wxFileTypeInfo& ftInfo); + // remove association + bool Unassociate(wxFileType *ft); + + // accessors + // get the string containing space separated extensions for the given + // file type + wxString GetExtension(size_t index) { return m_aExtensions[index]; } + +protected: + void InitIfNeeded(); + + wxArrayString m_aTypes, // MIME types + m_aDescriptions, // descriptions (just some text) + m_aExtensions, // space separated list of extensions + m_aIcons; // Icon filenames + + // verb=command pairs for this file type + wxMimeCommandsArray m_aEntries; + + // are we initialized? + bool m_initialized; + + wxString GetCommand(const wxString &verb, size_t nIndex) const; + + // Read XDG *.desktop file + void LoadXDGApp(const wxString& filename); + // Scan XDG directory + void LoadXDGAppsFilesFromDir(const wxString& dirname); + + // Load XDG globs files + void LoadXDGGlobs(const wxString& filename); + + // functions used to do associations + virtual int AddToMimeData(const wxString& strType, + const wxString& strIcon, + wxMimeTypeCommands *entry, + const wxArrayString& strExtensions, + const wxString& strDesc, + bool replaceExisting = true); + virtual bool DoAssociation(const wxString& strType, + const wxString& strIcon, + wxMimeTypeCommands *entry, + const wxArrayString& strExtensions, + const wxString& strDesc); + + // give it access to m_aXXX variables + friend class WXDLLIMPEXP_FWD_BASE wxFileTypeImpl; +}; + +class WXDLLIMPEXP_BASE wxFileTypeImpl +{ +public: + // initialization functions + // this is used to construct a list of mimetypes which match; + // if built with GetFileTypeFromMimetype index 0 has the exact match and + // index 1 the type / * match + // if built with GetFileTypeFromExtension, index 0 has the mimetype for + // the first extension found, index 1 for the second and so on + + void Init(wxMimeTypesManagerImpl *manager, size_t index) + { m_manager = manager; m_index.Add(index); } + + // accessors + bool GetExtensions(wxArrayString& extensions); + bool GetMimeType(wxString *mimeType) const + { *mimeType = m_manager->m_aTypes[m_index[0]]; return true; } + bool GetMimeTypes(wxArrayString& mimeTypes) const; + bool GetIcon(wxIconLocation *iconLoc) const; + + bool GetDescription(wxString *desc) const + { *desc = m_manager->m_aDescriptions[m_index[0]]; return true; } + + bool GetOpenCommand(wxString *openCmd, + const wxFileType::MessageParameters& params) const + { + *openCmd = GetExpandedCommand(wxT("open"), params); + return (! openCmd -> IsEmpty() ); + } + + bool GetPrintCommand(wxString *printCmd, + const wxFileType::MessageParameters& params) const + { + *printCmd = GetExpandedCommand(wxT("print"), params); + return (! printCmd -> IsEmpty() ); + } + + // return the number of commands defined for this file type, 0 if none + size_t GetAllCommands(wxArrayString *verbs, wxArrayString *commands, + const wxFileType::MessageParameters& params) const; + + + // remove the record for this file type + // probably a mistake to come here, use wxMimeTypesManager.Unassociate (ft) instead + bool Unassociate(wxFileType *ft) + { + return m_manager->Unassociate(ft); + } + + // set an arbitrary command, ask confirmation if it already exists and + // overwriteprompt is TRUE + bool SetCommand(const wxString& cmd, const wxString& verb, bool overwriteprompt = true); + bool SetDefaultIcon(const wxString& strIcon = wxEmptyString, int index = 0); + +private: + wxString + GetExpandedCommand(const wxString & verb, + const wxFileType::MessageParameters& params) const; + + wxMimeTypesManagerImpl *m_manager; + wxArrayInt m_index; // in the wxMimeTypesManagerImpl arrays +}; + +#endif // wxUSE_MIMETYPE + +#endif // _MIMETYPE_IMPL_H + + diff --git a/3rdparty/wxwidgets3.0/include/wx/unix/pipe.h b/3rdparty/wxwidgets3.0/include/wx/unix/pipe.h new file mode 100755 index 0000000000000..1bde4228a7284 --- /dev/null +++ b/3rdparty/wxwidgets3.0/include/wx/unix/pipe.h @@ -0,0 +1,102 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: wx/unix/pipe.h +// Purpose: wxPipe class +// Author: Vadim Zeitlin +// Modified by: +// Created: 24.06.2003 (extracted from src/unix/utilsunx.cpp) +// Copyright: (c) 2003 Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _WX_UNIX_PIPE_H_ +#define _WX_UNIX_PIPE_H_ + +#include +#include + +#include "wx/log.h" +#include "wx/intl.h" + +// ---------------------------------------------------------------------------- +// wxPipe: this class encapsulates pipe() system call +// ---------------------------------------------------------------------------- + +class wxPipe +{ +public: + // the symbolic names for the pipe ends + enum Direction + { + Read, + Write + }; + + enum + { + INVALID_FD = -1 + }; + + // default ctor doesn't do anything + wxPipe() { m_fds[Read] = m_fds[Write] = INVALID_FD; } + + // create the pipe, return TRUE if ok, FALSE on error + bool Create() + { + if ( pipe(m_fds) == -1 ) + { + wxLogSysError(wxGetTranslation("Pipe creation failed")); + + return false; + } + + return true; + } + + // switch the given end of the pipe to non-blocking IO + bool MakeNonBlocking(Direction which) + { + const int flags = fcntl(m_fds[which], F_GETFL, 0); + if ( flags == -1 ) + return false; + + return fcntl(m_fds[which], F_SETFL, flags | O_NONBLOCK) == 0; + } + + // return TRUE if we were created successfully + bool IsOk() const { return m_fds[Read] != INVALID_FD; } + + // return the descriptor for one of the pipe ends + int operator[](Direction which) const { return m_fds[which]; } + + // detach a descriptor, meaning that the pipe dtor won't close it, and + // return it + int Detach(Direction which) + { + int fd = m_fds[which]; + m_fds[which] = INVALID_FD; + + return fd; + } + + // close the pipe descriptors + void Close() + { + for ( size_t n = 0; n < WXSIZEOF(m_fds); n++ ) + { + if ( m_fds[n] != INVALID_FD ) + { + close(m_fds[n]); + m_fds[n] = INVALID_FD; + } + } + } + + // dtor closes the pipe descriptors + ~wxPipe() { Close(); } + +private: + int m_fds[2]; +}; + +#endif // _WX_UNIX_PIPE_H_ + diff --git a/3rdparty/wxwidgets3.0/include/wx/unix/private.h b/3rdparty/wxwidgets3.0/include/wx/unix/private.h new file mode 100755 index 0000000000000..fafc5435db3f0 --- /dev/null +++ b/3rdparty/wxwidgets3.0/include/wx/unix/private.h @@ -0,0 +1,19 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: wx/unix/private.h +// Purpose: miscellaneous private things for Unix wx ports +// Author: Vadim Zeitlin +// Created: 2005-09-25 +// Copyright: (c) 2005 Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _WX_UNIX_PRIVATE_H_ +#define _WX_UNIX_PRIVATE_H_ + +// this file is currently empty as its original contents was moved to +// include/wx/private/fd.h but let's keep it for now in case we need it for +// something again in the future +#include "wx/private/fd.h" + +#endif // _WX_UNIX_PRIVATE_H_ + diff --git a/3rdparty/wxwidgets3.0/include/wx/unix/private/epolldispatcher.h b/3rdparty/wxwidgets3.0/include/wx/unix/private/epolldispatcher.h new file mode 100755 index 0000000000000..c73411f221b0b --- /dev/null +++ b/3rdparty/wxwidgets3.0/include/wx/unix/private/epolldispatcher.h @@ -0,0 +1,53 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: wx/unix/private/epolldispatcher.h +// Purpose: wxEpollDispatcher class +// Authors: Lukasz Michalski +// Created: April 2007 +// Copyright: (c) Lukasz Michalski +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifndef _WX_PRIVATE_EPOLLDISPATCHER_H_ +#define _WX_PRIVATE_EPOLLDISPATCHER_H_ + +#include "wx/defs.h" + +#ifdef wxUSE_EPOLL_DISPATCHER + +#include "wx/private/fdiodispatcher.h" + +struct epoll_event; + +class WXDLLIMPEXP_BASE wxEpollDispatcher : public wxFDIODispatcher +{ +public: + // create a new instance of this class, can return NULL if + // epoll() is not supported on this system + // + // the caller should delete the returned pointer + static wxEpollDispatcher *Create(); + + virtual ~wxEpollDispatcher(); + + // implement base class pure virtual methods + virtual bool RegisterFD(int fd, wxFDIOHandler* handler, int flags = wxFDIO_ALL); + virtual bool ModifyFD(int fd, wxFDIOHandler* handler, int flags = wxFDIO_ALL); + virtual bool UnregisterFD(int fd); + virtual bool HasPending() const; + virtual int Dispatch(int timeout = TIMEOUT_INFINITE); + +private: + // ctor is private, use Create() + wxEpollDispatcher(int epollDescriptor); + + // common part of HasPending() and Dispatch(): calls epoll_wait() with the + // given timeout + int DoPoll(epoll_event *events, int numEvents, int timeout) const; + + + int m_epollDescriptor; +}; + +#endif // wxUSE_EPOLL_DISPATCHER + +#endif // _WX_PRIVATE_SOCKETEVTDISPATCH_H_ diff --git a/3rdparty/wxwidgets3.0/include/wx/unix/private/executeiohandler.h b/3rdparty/wxwidgets3.0/include/wx/unix/private/executeiohandler.h new file mode 100755 index 0000000000000..2a7c2d7aa3f39 --- /dev/null +++ b/3rdparty/wxwidgets3.0/include/wx/unix/private/executeiohandler.h @@ -0,0 +1,136 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: wx/unix/private/executeiohandler.h +// Purpose: IO handler class for the FD used by wxExecute() under Unix +// Author: Rob Bresalier, Vadim Zeitlin +// Created: 2013-01-06 +// Copyright: (c) 2013 Rob Bresalier, Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _WX_UNIX_PRIVATE_EXECUTEIOHANDLER_H_ +#define _WX_UNIX_PRIVATE_EXECUTEIOHANDLER_H_ + +#include "wx/private/streamtempinput.h" + +// This class handles IO events on the pipe FD connected to the child process +// stdout/stderr and is used by wxExecute(). +// +// Currently it can derive from either wxEventLoopSourceHandler or +// wxFDIOHandler depending on the kind of dispatcher/event loop it is used +// with. In the future, when we get rid of wxFDIOHandler entirely, it will +// derive from wxEventLoopSourceHandler only. +template +class wxExecuteIOHandlerBase : public T +{ +public: + wxExecuteIOHandlerBase(int fd, wxStreamTempInputBuffer& buf) + : m_fd(fd), + m_buf(buf) + { + m_callbackDisabled = false; + } + + // Called when the associated descriptor is available for reading. + virtual void OnReadWaiting() + { + // Sync process, process all data coming at us from the pipe so that + // the pipe does not get full and cause a deadlock situation. + m_buf.Update(); + + if ( m_buf.Eof() ) + DisableCallback(); + } + + // These methods are never called as we only monitor the associated FD for + // reading, but we still must implement them as they're pure virtual in the + // base class. + virtual void OnWriteWaiting() { } + virtual void OnExceptionWaiting() { } + + // Disable any future calls to our OnReadWaiting(), can be called when + // we're sure that no more input is forthcoming. + void DisableCallback() + { + if ( !m_callbackDisabled ) + { + m_callbackDisabled = true; + + DoDisable(); + } + } + +protected: + const int m_fd; + +private: + virtual void DoDisable() = 0; + + wxStreamTempInputBuffer& m_buf; + + // If true, DisableCallback() had been already called. + bool m_callbackDisabled; + + wxDECLARE_NO_COPY_CLASS(wxExecuteIOHandlerBase); +}; + +// This is the version used with wxFDIODispatcher, which must be passed to the +// ctor in order to register this handler with it. +class wxExecuteFDIOHandler : public wxExecuteIOHandlerBase +{ +public: + wxExecuteFDIOHandler(wxFDIODispatcher& dispatcher, + int fd, + wxStreamTempInputBuffer& buf) + : wxExecuteIOHandlerBase(fd, buf), + m_dispatcher(dispatcher) + { + dispatcher.RegisterFD(fd, this, wxFDIO_INPUT); + } + + virtual ~wxExecuteFDIOHandler() + { + DisableCallback(); + } + +private: + virtual void DoDisable() + { + m_dispatcher.UnregisterFD(m_fd); + } + + wxFDIODispatcher& m_dispatcher; + + wxDECLARE_NO_COPY_CLASS(wxExecuteFDIOHandler); +}; + +// And this is the version used with an event loop. As AddSourceForFD() is +// static, we don't require passing the event loop to the ctor but an event +// loop must be running to handle our events. +class wxExecuteEventLoopSourceHandler + : public wxExecuteIOHandlerBase +{ +public: + wxExecuteEventLoopSourceHandler(int fd, wxStreamTempInputBuffer& buf) + : wxExecuteIOHandlerBase(fd, buf) + { + m_source = wxEventLoop::AddSourceForFD(fd, this, wxEVENT_SOURCE_INPUT); + } + + virtual ~wxExecuteEventLoopSourceHandler() + { + DisableCallback(); + } + +private: + virtual void DoDisable() + { + delete m_source; + m_source = NULL; + } + + wxEventLoopSource* m_source; + + wxDECLARE_NO_COPY_CLASS(wxExecuteEventLoopSourceHandler); +}; + +#endif // _WX_UNIX_PRIVATE_EXECUTEIOHANDLER_H_ diff --git a/3rdparty/wxwidgets3.0/include/wx/unix/private/fdiounix.h b/3rdparty/wxwidgets3.0/include/wx/unix/private/fdiounix.h new file mode 100755 index 0000000000000..2807821e19763 --- /dev/null +++ b/3rdparty/wxwidgets3.0/include/wx/unix/private/fdiounix.h @@ -0,0 +1,27 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: wx/unix/private/fdiounix.h +// Purpose: wxFDIOManagerUnix class used by console Unix applications +// Author: Vadim Zeitlin +// Created: 2009-08-17 +// Copyright: (c) 2009 Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _UNIX_PRIVATE_FDIOUNIX_H_ +#define _UNIX_PRIVATE_FDIOUNIX_H_ + +#include "wx/private/fdiomanager.h" + +// ---------------------------------------------------------------------------- +// wxFDIOManagerUnix: implement wxFDIOManager interface using wxFDIODispatcher +// ---------------------------------------------------------------------------- + +class wxFDIOManagerUnix : public wxFDIOManager +{ +public: + virtual int AddInput(wxFDIOHandler *handler, int fd, Direction d); + virtual void RemoveInput(wxFDIOHandler *handler, int fd, Direction d); +}; + +#endif // _UNIX_PRIVATE_FDIOUNIX_H_ + diff --git a/3rdparty/wxwidgets3.0/include/wx/unix/private/fswatcher_inotify.h b/3rdparty/wxwidgets3.0/include/wx/unix/private/fswatcher_inotify.h new file mode 100755 index 0000000000000..249450eb509cb --- /dev/null +++ b/3rdparty/wxwidgets3.0/include/wx/unix/private/fswatcher_inotify.h @@ -0,0 +1,71 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: wx/unix/private/fswatcher_inotify.h +// Purpose: File system watcher impl classes +// Author: Bartosz Bekier +// Created: 2009-05-26 +// Copyright: (c) 2009 Bartosz Bekier +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifndef WX_UNIX_PRIVATE_FSWATCHER_INOTIFY_H_ +#define WX_UNIX_PRIVATE_FSWATCHER_INOTIFY_H_ + +#include "wx/filename.h" +#include "wx/evtloopsrc.h" + +// ============================================================================ +// wxFSWatcherEntry implementation & helper declarations +// ============================================================================ + +class wxFSWatcherImplUNIX; + +class wxFSWatchEntry : public wxFSWatchInfo +{ +public: + wxFSWatchEntry(const wxFSWatchInfo& winfo) : + wxFSWatchInfo(winfo) + { + } + + int GetWatchDescriptor() const + { + return m_wd; + } + + void SetWatchDescriptor(int wd) + { + m_wd = wd; + } + +private: + int m_wd; + + wxDECLARE_NO_COPY_CLASS(wxFSWatchEntry); +}; + + +// ============================================================================ +// wxFSWSourceHandler helper class +// ============================================================================ + +class wxFSWatcherImplUnix; + +/** + * Handler for handling i/o from inotify descriptor + */ +class wxFSWSourceHandler : public wxEventLoopSourceHandler +{ +public: + wxFSWSourceHandler(wxFSWatcherImplUnix* service) : + m_service(service) + { } + + virtual void OnReadWaiting(); + virtual void OnWriteWaiting(); + virtual void OnExceptionWaiting(); + +protected: + wxFSWatcherImplUnix* m_service; +}; + +#endif /* WX_UNIX_PRIVATE_FSWATCHER_INOTIFY_H_ */ diff --git a/3rdparty/wxwidgets3.0/include/wx/unix/private/fswatcher_kqueue.h b/3rdparty/wxwidgets3.0/include/wx/unix/private/fswatcher_kqueue.h new file mode 100755 index 0000000000000..de3d489a382a6 --- /dev/null +++ b/3rdparty/wxwidgets3.0/include/wx/unix/private/fswatcher_kqueue.h @@ -0,0 +1,108 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: wx/unix/private/fswatcher_kqueue.h +// Purpose: File system watcher impl classes +// Author: Bartosz Bekier +// Created: 2009-05-26 +// Copyright: (c) 2009 Bartosz Bekier +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifndef WX_UNIX_PRIVATE_FSWATCHER_KQUEUE_H_ +#define WX_UNIX_PRIVATE_FSWATCHER_KQUEUE_H_ + +#include +#include +#include "wx/dir.h" +#include "wx/debug.h" +#include "wx/arrstr.h" + +// ============================================================================ +// wxFSWatcherEntry implementation & helper declarations +// ============================================================================ + +class wxFSWatcherImplKqueue; + +class wxFSWatchEntryKq : public wxFSWatchInfo +{ +public: + struct wxDirState + { + wxDirState(const wxFSWatchInfo& winfo) + { + if (!wxDir::Exists(winfo.GetPath())) + return; + + wxDir dir(winfo.GetPath()); + wxCHECK_RET( dir.IsOpened(), + wxString::Format("Unable to open dir '%s'", winfo.GetPath())); + + wxString filename; + bool ret = dir.GetFirst(&filename); + while (ret) + { + files.push_back(filename); + ret = dir.GetNext(&filename); + } + } + + wxSortedArrayString files; + }; + + wxFSWatchEntryKq(const wxFSWatchInfo& winfo) : + wxFSWatchInfo(winfo), m_lastState(winfo) + { + m_fd = wxOpen(m_path, O_RDONLY, 0); + if (m_fd == -1) + { + wxLogSysError(_("Unable to open path '%s'"), m_path); + } + } + + virtual ~wxFSWatchEntryKq() + { + (void) Close(); + } + + bool Close() + { + if (!IsOk()) + return false; + + int ret = close(m_fd); + if (ret == -1) + { + wxLogSysError(_("Unable to close path '%s'"), m_path); + } + m_fd = -1; + + return ret != -1; + } + + bool IsOk() const + { + return m_fd != -1; + } + + int GetFileDescriptor() const + { + return m_fd; + } + + void RefreshState() + { + m_lastState = wxDirState(*this); + } + + const wxDirState& GetLastState() const + { + return m_lastState; + } + +private: + int m_fd; + wxDirState m_lastState; + + wxDECLARE_NO_COPY_CLASS(wxFSWatchEntryKq); +}; + +#endif /* WX_UNIX_PRIVATE_FSWATCHER_KQUEUE_H_ */ diff --git a/3rdparty/wxwidgets3.0/include/wx/unix/private/pipestream.h b/3rdparty/wxwidgets3.0/include/wx/unix/private/pipestream.h new file mode 100755 index 0000000000000..313a271741f87 --- /dev/null +++ b/3rdparty/wxwidgets3.0/include/wx/unix/private/pipestream.h @@ -0,0 +1,37 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: wx/unix/private/pipestream.h +// Purpose: Unix wxPipeInputStream and wxPipeOutputStream declarations +// Author: Vadim Zeitlin +// Created: 2013-06-08 (extracted from wx/unix/pipe.h) +// Copyright: (c) 2013 Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _WX_UNIX_PRIVATE_PIPESTREAM_H_ +#define _WX_UNIX_PRIVATE_PIPESTREAM_H_ + +#include "wx/wfstream.h" + +class wxPipeInputStream : public wxFileInputStream +{ +public: + wxEXPLICIT wxPipeInputStream(int fd) : wxFileInputStream(fd) { } + + // return true if the pipe is still opened + bool IsOpened() const { return !Eof(); } + + // return true if we have anything to read, don't block + virtual bool CanRead() const; +}; + +class wxPipeOutputStream : public wxFileOutputStream +{ +public: + wxPipeOutputStream(int fd) : wxFileOutputStream(fd) { } + + // Override the base class version to ignore "pipe full" errors: this is + // not an error for this class. + size_t OnSysWrite(const void *buffer, size_t size); +}; + +#endif // _WX_UNIX_PRIVATE_PIPESTREAM_H_ diff --git a/3rdparty/wxwidgets3.0/include/wx/unix/private/sockunix.h b/3rdparty/wxwidgets3.0/include/wx/unix/private/sockunix.h new file mode 100755 index 0000000000000..642ef43bfa333 --- /dev/null +++ b/3rdparty/wxwidgets3.0/include/wx/unix/private/sockunix.h @@ -0,0 +1,144 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: wx/unix/private/sockunix.h +// Purpose: wxSocketImpl implementation for Unix systems +// Authors: Guilhem Lavaux, Vadim Zeitlin +// Created: April 1997 +// Copyright: (c) 1997 Guilhem Lavaux +// (c) 2008 Vadim Zeitlin +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifndef _WX_UNIX_GSOCKUNX_H_ +#define _WX_UNIX_GSOCKUNX_H_ + +#include +#include + +// Under older (Open)Solaris versions FIONBIO is declared in this header only. +// In the newer versions it's included by sys/ioctl.h but it's simpler to just +// include it always instead of testing for whether it is or not. +#ifdef __SOLARIS__ + #include +#endif + +#include "wx/private/fdiomanager.h" + +class wxSocketImplUnix : public wxSocketImpl, + public wxFDIOHandler +{ +public: + wxSocketImplUnix(wxSocketBase& wxsocket) + : wxSocketImpl(wxsocket) + { + m_fds[0] = + m_fds[1] = -1; + } + + virtual wxSocketError GetLastError() const; + + virtual void ReenableEvents(wxSocketEventFlags flags) + { + // enable the notifications about input/output being available again in + // case they were disabled by OnRead/WriteWaiting() + // + // notice that we'd like to enable the events here only if there is + // nothing more left on the socket right now as otherwise we're going + // to get a "ready for whatever" notification immediately (well, during + // the next event loop iteration) and disable the event back again + // which is rather inefficient but unfortunately doing it like this + // doesn't work because the existing code (e.g. src/common/sckipc.cpp) + // expects to keep getting notifications about the data available from + // the socket even if it didn't read all the data the last time, so we + // absolutely have to continue generating them + EnableEvents(flags); + } + + // wxFDIOHandler methods + virtual void OnReadWaiting(); + virtual void OnWriteWaiting(); + virtual void OnExceptionWaiting(); + virtual bool IsOk() const { return m_fd != INVALID_SOCKET; } + +private: + virtual void DoClose() + { + DisableEvents(); + + close(m_fd); + } + + virtual void UnblockAndRegisterWithEventLoop() + { + int trueArg = 1; + ioctl(m_fd, FIONBIO, &trueArg); + + EnableEvents(); + } + + // enable or disable notifications for socket input/output events + void EnableEvents(int flags = wxSOCKET_INPUT_FLAG | wxSOCKET_OUTPUT_FLAG) + { DoEnableEvents(flags, true); } + void DisableEvents(int flags = wxSOCKET_INPUT_FLAG | wxSOCKET_OUTPUT_FLAG) + { DoEnableEvents(flags, false); } + + // really enable or disable socket input/output events + void DoEnableEvents(int flags, bool enable); + +protected: + // descriptors for input and output event notification channels associated + // with the socket + int m_fds[2]; + +private: + // notify the associated wxSocket about a change in socket state and shut + // down the socket if the event is wxSOCKET_LOST + void OnStateChange(wxSocketNotify event); + + // check if there is any input available, return 1 if yes, 0 if no or -1 on + // error + int CheckForInput(); + + + // give it access to our m_fds + friend class wxSocketFDBasedManager; +}; + +// A version of wxSocketManager which uses FDs for socket IO: it is used by +// Unix console applications and some X11-like ports (wxGTK and wxMotif but not +// wxX11 currently) which implement their own port-specific wxFDIOManagers +class wxSocketFDBasedManager : public wxSocketManager +{ +public: + wxSocketFDBasedManager() + { + m_fdioManager = NULL; + } + + virtual bool OnInit(); + virtual void OnExit() { } + + virtual wxSocketImpl *CreateSocket(wxSocketBase& wxsocket) + { + return new wxSocketImplUnix(wxsocket); + } + + virtual void Install_Callback(wxSocketImpl *socket_, wxSocketNotify event); + virtual void Uninstall_Callback(wxSocketImpl *socket_, wxSocketNotify event); + +protected: + // get the FD index corresponding to the given wxSocketNotify + wxFDIOManager::Direction + GetDirForEvent(wxSocketImpl *socket, wxSocketNotify event); + + // access the FDs we store + int& FD(wxSocketImplUnix *socket, wxFDIOManager::Direction d) + { + return socket->m_fds[d]; + } + + wxFDIOManager *m_fdioManager; + + wxDECLARE_NO_COPY_CLASS(wxSocketFDBasedManager); +}; + +#endif /* _WX_UNIX_GSOCKUNX_H_ */ diff --git a/3rdparty/wxwidgets3.0/include/wx/unix/private/timer.h b/3rdparty/wxwidgets3.0/include/wx/unix/private/timer.h new file mode 100755 index 0000000000000..6275b53d913e4 --- /dev/null +++ b/3rdparty/wxwidgets3.0/include/wx/unix/private/timer.h @@ -0,0 +1,138 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: wx/unix/private/timer.h +// Purpose: wxTimer for wxBase (unix) +// Author: Lukasz Michalski +// Created: 15/01/2005 +// Copyright: (c) Lukasz Michalski +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifndef _WX_UNIX_PRIVATE_TIMER_H_ +#define _WX_UNIX_PRIVATE_TIMER_H_ + +#if wxUSE_TIMER + +#include "wx/private/timer.h" + +// the type used for milliseconds is large enough for microseconds too but +// introduce a synonym for it to avoid confusion +typedef wxMilliClock_t wxUsecClock_t; + +// ---------------------------------------------------------------------------- +// wxTimer implementation class for Unix platforms +// ---------------------------------------------------------------------------- + +// NB: we have to export at least this symbol from the shared library, because +// it's used by wxDFB's wxCore +class WXDLLIMPEXP_BASE wxUnixTimerImpl : public wxTimerImpl +{ +public: + wxUnixTimerImpl(wxTimer *timer); + virtual ~wxUnixTimerImpl(); + + virtual bool IsRunning() const; + virtual bool Start(int milliseconds = -1, bool oneShot = false); + virtual void Stop(); + + // for wxTimerScheduler only: resets the internal flag indicating that the + // timer is running + void MarkStopped() + { + wxASSERT_MSG( m_isRunning, wxT("stopping non-running timer?") ); + + m_isRunning = false; + } + +private: + bool m_isRunning; +}; + +// ---------------------------------------------------------------------------- +// wxTimerSchedule: information about a single timer, used by wxTimerScheduler +// ---------------------------------------------------------------------------- + +struct wxTimerSchedule +{ + wxTimerSchedule(wxUnixTimerImpl *timer, wxUsecClock_t expiration) + : m_timer(timer), + m_expiration(expiration) + { + } + + // the timer itself (we don't own this pointer) + wxUnixTimerImpl *m_timer; + + // the time of its next expiration, in usec + wxUsecClock_t m_expiration; +}; + +// the linked list of all active timers, we keep it sorted by expiration time +WX_DECLARE_LIST(wxTimerSchedule, wxTimerList); + +// ---------------------------------------------------------------------------- +// wxTimerScheduler: class responsible for updating all timers +// ---------------------------------------------------------------------------- + +class wxTimerScheduler +{ +public: + // get the unique timer scheduler instance + static wxTimerScheduler& Get() + { + if ( !ms_instance ) + ms_instance = new wxTimerScheduler; + + return *ms_instance; + } + + // must be called on shutdown to delete the global timer scheduler + static void Shutdown() + { + if ( ms_instance ) + { + delete ms_instance; + ms_instance = NULL; + } + } + + // adds timer which should expire at the given absolute time to the list + void AddTimer(wxUnixTimerImpl *timer, wxUsecClock_t expiration); + + // remove timer from the list, called automatically from timer dtor + void RemoveTimer(wxUnixTimerImpl *timer); + + + // the functions below are used by the event loop implementation to monitor + // and notify timers: + + // if this function returns true, the time remaining until the next time + // expiration is returned in the provided parameter (always positive or 0) + // + // it returns false if there are no timers + bool GetNext(wxUsecClock_t *remaining) const; + + // trigger the timer event for all timers which have expired, return true + // if any did + bool NotifyExpired(); + +private: + // ctor and dtor are private, this is a singleton class only created by + // Get() and destroyed by Shutdown() + wxTimerScheduler() { } + ~wxTimerScheduler(); + + // add the given timer schedule to the list in the right place + // + // we take ownership of the pointer "s" which must be heap-allocated + void DoAddTimer(wxTimerSchedule *s); + + + // the list of all currently active timers sorted by expiration + wxTimerList m_timers; + + static wxTimerScheduler *ms_instance; +}; + +#endif // wxUSE_TIMER + +#endif // _WX_UNIX_PRIVATE_TIMER_H_ diff --git a/3rdparty/wxwidgets3.0/include/wx/unix/private/wakeuppipe.h b/3rdparty/wxwidgets3.0/include/wx/unix/private/wakeuppipe.h new file mode 100755 index 0000000000000..5bd6db870a85a --- /dev/null +++ b/3rdparty/wxwidgets3.0/include/wx/unix/private/wakeuppipe.h @@ -0,0 +1,97 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: wx/unix/private/wakeuppipe.h +// Purpose: Helper class allowing to wake up the main thread. +// Author: Vadim Zeitlin +// Created: 2013-06-09 (extracted from src/unix/evtloopunix.cpp) +// Copyright: (c) 2013 Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _WX_UNIX_PRIVATE_WAKEUPPIPE_H_ +#define _WX_UNIX_PRIVATE_WAKEUPPIPE_H_ + +#include "wx/unix/pipe.h" +#include "wx/evtloopsrc.h" + +// ---------------------------------------------------------------------------- +// wxWakeUpPipe: allows to wake up the event loop by writing to it +// ---------------------------------------------------------------------------- + +// This class is not MT-safe, see wxWakeUpPipeMT below for a wake up pipe +// usable from other threads. + +class wxWakeUpPipe : public wxEventLoopSourceHandler +{ +public: + // Create and initialize the pipe. + // + // It's the callers responsibility to add the read end of this pipe, + // returned by GetReadFd(), to the code blocking on input. + wxWakeUpPipe(); + + // Wake up the blocking operation involving this pipe. + // + // It simply writes to the write end of the pipe. + // + // As indicated by its name, this method does no locking and so can be + // called only from the main thread. + void WakeUpNoLock(); + + // Same as WakeUp() but without locking. + + // Return the read end of the pipe. + int GetReadFd() { return m_pipe[wxPipe::Read]; } + + + // Implement wxEventLoopSourceHandler pure virtual methods + virtual void OnReadWaiting(); + virtual void OnWriteWaiting() { } + virtual void OnExceptionWaiting() { } + +private: + wxPipe m_pipe; + + // This flag is set to true after writing to the pipe and reset to false + // after reading from it in the main thread. Having it allows us to avoid + // overflowing the pipe with too many writes if the main thread can't keep + // up with reading from it. + bool m_pipeIsEmpty; +}; + +// ---------------------------------------------------------------------------- +// wxWakeUpPipeMT: thread-safe version of wxWakeUpPipe +// ---------------------------------------------------------------------------- + +// This class can be used from multiple threads, i.e. its WakeUp() can be +// called concurrently. + +class wxWakeUpPipeMT : public wxWakeUpPipe +{ +#if wxUSE_THREADS +public: + wxWakeUpPipeMT() { } + + // Thread-safe wrapper around WakeUpNoLock(): can be called from another + // thread to wake up the main one. + void WakeUp() + { + wxCriticalSectionLocker lock(m_pipeLock); + + WakeUpNoLock(); + } + + virtual void OnReadWaiting() + { + wxCriticalSectionLocker lock(m_pipeLock); + + wxWakeUpPipe::OnReadWaiting(); + } + +private: + // Protects access to m_pipeIsEmpty. + wxCriticalSection m_pipeLock; + +#endif // wxUSE_THREADS +}; + +#endif // _WX_UNIX_PRIVATE_WAKEUPPIPE_H_ diff --git a/3rdparty/wxwidgets3.0/include/wx/unix/sound.h b/3rdparty/wxwidgets3.0/include/wx/unix/sound.h new file mode 100755 index 0000000000000..76efeae3dc80a --- /dev/null +++ b/3rdparty/wxwidgets3.0/include/wx/unix/sound.h @@ -0,0 +1,160 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: wx/unix/sound.h +// Purpose: wxSound class +// Author: Julian Smart, Vaclav Slavik +// Modified by: +// Created: 25/10/98 +// Copyright: (c) Julian Smart, Vaclav Slavik +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifndef _WX_SOUND_H_ +#define _WX_SOUND_H_ + +#include "wx/defs.h" + +#if wxUSE_SOUND + +#include "wx/object.h" + +// ---------------------------------------------------------------------------- +// wxSound: simple audio playback class +// ---------------------------------------------------------------------------- + +class WXDLLIMPEXP_FWD_ADV wxSoundBackend; +class WXDLLIMPEXP_FWD_ADV wxSound; +class WXDLLIMPEXP_FWD_BASE wxDynamicLibrary; + +/// Sound data, as loaded from .wav file: +class WXDLLIMPEXP_ADV wxSoundData +{ +public: + wxSoundData() : m_refCnt(1) {} + void IncRef(); + void DecRef(); + + // .wav header information: + unsigned m_channels; // num of channels (mono:1, stereo:2) + unsigned m_samplingRate; + unsigned m_bitsPerSample; // if 8, then m_data contains unsigned 8bit + // samples (wxUint8), if 16 then signed 16bit + // (wxInt16) + unsigned m_samples; // length in samples: + + // wave data: + size_t m_dataBytes; + wxUint8 *m_data; // m_dataBytes bytes of data + +private: + ~wxSoundData(); + unsigned m_refCnt; + wxUint8 *m_dataWithHeader; // ditto, but prefixed with .wav header + friend class wxSound; +}; + + +/// Simple sound class: +class WXDLLIMPEXP_ADV wxSound : public wxSoundBase +{ +public: + wxSound(); + wxSound(const wxString& fileName, bool isResource = false); + wxSound(size_t size, const void* data); + virtual ~wxSound(); + + // Create from resource or file + bool Create(const wxString& fileName, bool isResource = false); + // Create from data + bool Create(size_t size, const void* data); + + bool IsOk() const { return m_data != NULL; } + + // Stop playing any sound + static void Stop(); + + // Returns true if a sound is being played + static bool IsPlaying(); + + // for internal use + static void UnloadBackend(); + +protected: + bool DoPlay(unsigned flags) const; + + static void EnsureBackend(); + void Free(); + bool LoadWAV(const void* data, size_t length, bool copyData); + + static wxSoundBackend *ms_backend; +#if wxUSE_LIBSDL && wxUSE_PLUGINS + // FIXME - temporary, until we have plugins architecture + static wxDynamicLibrary *ms_backendSDL; +#endif + +private: + wxSoundData *m_data; +}; + + +// ---------------------------------------------------------------------------- +// wxSoundBackend: +// ---------------------------------------------------------------------------- + +// This is interface to sound playing implementation. There are multiple +// sound architectures in use on Unix platforms and wxWidgets can use several +// of them for playback, depending on their availability at runtime; hence +// the need for backends. This class is for use by wxWidgets and people writing +// additional backends only, it is _not_ for use by applications! + +// Structure that holds playback status information +struct wxSoundPlaybackStatus +{ + // playback is in progress + bool m_playing; + // main thread called wxSound::Stop() + bool m_stopRequested; +}; + +// Audio backend interface +class WXDLLIMPEXP_ADV wxSoundBackend +{ +public: + virtual ~wxSoundBackend() {} + + // Returns the name of the backend (e.g. "Open Sound System") + virtual wxString GetName() const = 0; + + // Returns priority (higher priority backends are tried first) + virtual int GetPriority() const = 0; + + // Checks if the backend's audio system is available and the backend can + // be used for playback + virtual bool IsAvailable() const = 0; + + // Returns true if the backend is capable of playing sound asynchronously. + // If false, then wxWidgets creates a playback thread and handles async + // playback, otherwise it is left up to the backend (will usually be more + // effective). + virtual bool HasNativeAsyncPlayback() const = 0; + + // Plays the sound. flags are same flags as those passed to wxSound::Play. + // The function should periodically check the value of + // status->m_stopRequested and terminate if it is set to true (it may + // be modified by another thread) + virtual bool Play(wxSoundData *data, unsigned flags, + volatile wxSoundPlaybackStatus *status) = 0; + + // Stops playback (if something is played). + virtual void Stop() = 0; + + // Returns true if the backend is playing anything at the moment. + // (This method is never called for backends that don't support async + // playback.) + virtual bool IsPlaying() const = 0; +}; + + +#endif // wxUSE_SOUND + +#endif // _WX_SOUND_H_ + diff --git a/3rdparty/wxwidgets3.0/include/wx/unix/stackwalk.h b/3rdparty/wxwidgets3.0/include/wx/unix/stackwalk.h new file mode 100755 index 0000000000000..e99741934a04c --- /dev/null +++ b/3rdparty/wxwidgets3.0/include/wx/unix/stackwalk.h @@ -0,0 +1,98 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: wx/unix/stackwalk.h +// Purpose: declaration of wxStackWalker for Unix +// Author: Vadim Zeitlin +// Modified by: +// Created: 2005-01-19 +// Copyright: (c) 2005 Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _WX_UNIX_STACKWALK_H_ +#define _WX_UNIX_STACKWALK_H_ + +// ---------------------------------------------------------------------------- +// wxStackFrame +// ---------------------------------------------------------------------------- + +class WXDLLIMPEXP_BASE wxStackFrame : public wxStackFrameBase +{ + friend class wxStackWalker; + +public: + // arguments are the stack depth of this frame, its address and the return + // value of backtrace_symbols() for it + // + // NB: we don't copy syminfo pointer so it should have lifetime at least as + // long as ours + wxStackFrame(size_t level = 0, void *address = NULL, const char *syminfo = NULL) + : wxStackFrameBase(level, address) + { + m_syminfo = syminfo; + } + +protected: + virtual void OnGetName(); + + // optimized for the 2 step initialization done by wxStackWalker + void Set(const wxString &name, const wxString &filename, const char* syminfo, + size_t level, size_t numLine, void *address) + { + m_level = level; + m_name = name; + m_filename = filename; + m_syminfo = syminfo; + + m_line = numLine; + m_address = address; + } + +private: + const char *m_syminfo; +}; + +// ---------------------------------------------------------------------------- +// wxStackWalker +// ---------------------------------------------------------------------------- + +class WXDLLIMPEXP_BASE wxStackWalker : public wxStackWalkerBase +{ +public: + // we need the full path to the program executable to be able to use + // addr2line, normally we can retrieve it from wxTheApp but if wxTheApp + // doesn't exist or doesn't have the correct value, the path may be given + // explicitly + wxStackWalker(const char *argv0 = NULL) + { + ms_exepath = wxString::FromAscii(argv0); + } + + ~wxStackWalker() + { + FreeStack(); + } + + virtual void Walk(size_t skip = 1, size_t maxDepth = wxSTACKWALKER_MAX_DEPTH); +#if wxUSE_ON_FATAL_EXCEPTION + virtual void WalkFromException(size_t maxDepth = wxSTACKWALKER_MAX_DEPTH) { Walk(2, maxDepth); } +#endif // wxUSE_ON_FATAL_EXCEPTION + + static const wxString& GetExePath() { return ms_exepath; } + + + // these two may be used to save the stack at some point (fast operation) + // and then process it later (slow operation) + void SaveStack(size_t maxDepth); + void ProcessFrames(size_t skip); + void FreeStack(); + +private: + int InitFrames(wxStackFrame *arr, size_t n, void **addresses, char **syminfo); + + static wxString ms_exepath; + static void *ms_addresses[]; + static char **ms_symbols; + static int m_depth; +}; + +#endif // _WX_UNIX_STACKWALK_H_ diff --git a/3rdparty/wxwidgets3.0/include/wx/unix/stdpaths.h b/3rdparty/wxwidgets3.0/include/wx/unix/stdpaths.h new file mode 100755 index 0000000000000..2f111992a3f42 --- /dev/null +++ b/3rdparty/wxwidgets3.0/include/wx/unix/stdpaths.h @@ -0,0 +1,63 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: wx/unix/stdpaths.h +// Purpose: wxStandardPaths for Unix systems +// Author: Vadim Zeitlin +// Modified by: +// Created: 2004-10-19 +// Copyright: (c) 2004 Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _WX_UNIX_STDPATHS_H_ +#define _WX_UNIX_STDPATHS_H_ + +// ---------------------------------------------------------------------------- +// wxStandardPaths +// ---------------------------------------------------------------------------- + +class WXDLLIMPEXP_BASE wxStandardPaths : public wxStandardPathsBase +{ +public: + // tries to determine the installation prefix automatically (Linux only right + // now) and returns /usr/local if it failed + void DetectPrefix(); + + // set the program installation directory which is /usr/local by default + // + // under some systems (currently only Linux) the program directory can be + // determined automatically but for portable programs you should always set + // it explicitly + void SetInstallPrefix(const wxString& prefix); + + // get the program installation prefix + // + // if the prefix had been previously by SetInstallPrefix, returns that + // value, otherwise calls DetectPrefix() + wxString GetInstallPrefix() const; + + + // implement base class pure virtuals + virtual wxString GetExecutablePath() const; + virtual wxString GetConfigDir() const; + virtual wxString GetUserConfigDir() const; + virtual wxString GetDataDir() const; + virtual wxString GetLocalDataDir() const; + virtual wxString GetUserDataDir() const; + virtual wxString GetPluginsDir() const; + virtual wxString GetLocalizedResourcesDir(const wxString& lang, + ResourceCat category) const; +#ifndef __VMS + virtual wxString GetDocumentsDir() const; +#endif + +protected: + // Ctor is protected, use wxStandardPaths::Get() instead of instantiating + // objects of this class directly. + wxStandardPaths() { } + +private: + wxString m_prefix; +}; + +#endif // _WX_UNIX_STDPATHS_H_ + diff --git a/3rdparty/wxwidgets3.0/include/wx/unix/taskbarx11.h b/3rdparty/wxwidgets3.0/include/wx/unix/taskbarx11.h new file mode 100755 index 0000000000000..02a920094116b --- /dev/null +++ b/3rdparty/wxwidgets3.0/include/wx/unix/taskbarx11.h @@ -0,0 +1,40 @@ +///////////////////////////////////////////////////////////////////////// +// File: wx/unix/taskbarx11.h +// Purpose: Defines wxTaskBarIcon class for most common X11 desktops +// Author: Vaclav Slavik +// Modified by: +// Created: 04/04/2003 +// Copyright: (c) Vaclav Slavik, 2003 +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////// + +#ifndef _WX_UNIX_TASKBAR_H_ +#define _WX_UNIX_TASKBAR_H_ + +class WXDLLIMPEXP_FWD_ADV wxTaskBarIconArea; + +class WXDLLIMPEXP_ADV wxTaskBarIcon: public wxTaskBarIconBase +{ +public: + wxTaskBarIcon(); + virtual ~wxTaskBarIcon(); + + // Accessors: + bool IsOk() const; + bool IsIconInstalled() const; + + // Operations: + bool SetIcon(const wxIcon& icon, const wxString& tooltip = wxEmptyString); + bool RemoveIcon(); + bool PopupMenu(wxMenu *menu); + +protected: + wxTaskBarIconArea *m_iconWnd; + +private: + void OnDestroy(wxWindowDestroyEvent&); + + DECLARE_DYNAMIC_CLASS(wxTaskBarIcon) +}; + +#endif // _WX_UNIX_TASKBAR_H_ diff --git a/3rdparty/wxwidgets3.0/include/wx/unix/tls.h b/3rdparty/wxwidgets3.0/include/wx/unix/tls.h new file mode 100755 index 0000000000000..ce61e6fff7782 --- /dev/null +++ b/3rdparty/wxwidgets3.0/include/wx/unix/tls.h @@ -0,0 +1,65 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: wx/unix/tls.h +// Purpose: Pthreads implementation of wxTlsValue<> +// Author: Vadim Zeitlin +// Created: 2008-08-08 +// Copyright: (c) 2008 Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _WX_UNIX_TLS_H_ +#define _WX_UNIX_TLS_H_ + +#include + +// ---------------------------------------------------------------------------- +// wxTlsKey is a helper class encapsulating the TLS value index +// ---------------------------------------------------------------------------- + +class wxTlsKey +{ +public: + // ctor allocates a new key and possibly registering a destructor function + // for it + wxTlsKey(wxTlsDestructorFunction destructor) + { + m_destructor = destructor; + if ( pthread_key_create(&m_key, destructor) != 0 ) + m_key = 0; + } + + // return true if the key was successfully allocated + bool IsOk() const { return m_key != 0; } + + // get the key value, there is no error return + void *Get() const + { + return pthread_getspecific(m_key); + } + + // change the key value, return true if ok + bool Set(void *value) + { + void *old = Get(); + if ( old ) + m_destructor(old); + + return pthread_setspecific(m_key, value) == 0; + } + + // free the key + ~wxTlsKey() + { + if ( IsOk() ) + pthread_key_delete(m_key); + } + +private: + wxTlsDestructorFunction m_destructor; + pthread_key_t m_key; + + wxDECLARE_NO_COPY_CLASS(wxTlsKey); +}; + +#endif // _WX_UNIX_TLS_H_ + diff --git a/3rdparty/wxwidgets3.0/include/wx/unix/utilsx11.h b/3rdparty/wxwidgets3.0/include/wx/unix/utilsx11.h new file mode 100755 index 0000000000000..29898372fa33a --- /dev/null +++ b/3rdparty/wxwidgets3.0/include/wx/unix/utilsx11.h @@ -0,0 +1,78 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: wx/unix/utilsx11.h +// Purpose: Miscellaneous X11 functions +// Author: Mattia Barbon, Vaclav Slavik, Vadim Zeitlin +// Modified by: +// Created: 25.03.02 +// Copyright: (c) wxWidgets team +// (c) 2010 Vadim Zeitlin +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifndef _WX_UNIX_UTILSX11_H_ +#define _WX_UNIX_UTILSX11_H_ + +#include "wx/defs.h" +#include "wx/gdicmn.h" + +#include + +// NB: Content of this header is for wxWidgets' private use! It is not +// part of public API and may be modified or even disappear in the future! + +#if defined(__WXMOTIF__) || defined(__WXGTK__) || defined(__WXX11__) + +#if defined(__WXGTK__) +typedef void WXDisplay; +typedef void* WXWindow; +#endif +typedef unsigned long WXKeySym; + +int wxCharCodeXToWX(WXKeySym keySym); +WXKeySym wxCharCodeWXToX(int id); + +class wxIconBundle; + +void wxSetIconsX11( WXDisplay* display, WXWindow window, + const wxIconBundle& ib ); + + +enum wxX11FullScreenMethod +{ + wxX11_FS_AUTODETECT = 0, + wxX11_FS_WMSPEC, + wxX11_FS_KDE, + wxX11_FS_GENERIC +}; + +wxX11FullScreenMethod wxGetFullScreenMethodX11(WXDisplay* display, + WXWindow rootWindow); + +void wxSetFullScreenStateX11(WXDisplay* display, WXWindow rootWindow, + WXWindow window, bool show, wxRect *origSize, + wxX11FullScreenMethod method); + + +// Class wrapping X11 Display: it opens it in ctor and closes it in dtor. +class wxX11Display +{ +public: + wxX11Display() { m_dpy = XOpenDisplay(NULL); } + ~wxX11Display() { if ( m_dpy ) XCloseDisplay(m_dpy); } + + operator Display *() const { return m_dpy; } + + // Using DefaultRootWindow() with an object of wxX11Display class doesn't + // compile because it is a macro which tries to cast wxX11Display so + // provide a convenient helper. + Window DefaultRoot() const { return DefaultRootWindow(m_dpy); } + +private: + Display *m_dpy; + + wxDECLARE_NO_COPY_CLASS(wxX11Display); +}; + +#endif // __WXMOTIF__, __WXGTK__, __WXX11__ + +#endif // _WX_UNIX_UTILSX11_H_ diff --git a/3rdparty/wxwidgets3.0/src/unix/appunix.cpp b/3rdparty/wxwidgets3.0/src/unix/appunix.cpp new file mode 100755 index 0000000000000..62f0c79ec92ab --- /dev/null +++ b/3rdparty/wxwidgets3.0/src/unix/appunix.cpp @@ -0,0 +1,193 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: src/unix/appunix.cpp +// Purpose: wxAppConsole with wxMainLoop implementation +// Author: Lukasz Michalski +// Created: 28/01/2005 +// Copyright: (c) Lukasz Michalski +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#ifndef WX_PRECOMP + #include "wx/app.h" + #include "wx/log.h" +#endif + +#include "wx/evtloop.h" +#include "wx/scopedptr.h" +#include "wx/unix/private/wakeuppipe.h" +#include "wx/private/fdiodispatcher.h" +#include "wx/private/fdioeventloopsourcehandler.h" + +#include +#include + +#ifndef SA_RESTART + // don't use for systems which don't define it (at least VMS and QNX) + #define SA_RESTART 0 +#endif + +// ---------------------------------------------------------------------------- +// Helper class calling CheckSignal() on wake up +// ---------------------------------------------------------------------------- + +namespace +{ + +class SignalsWakeUpPipe : public wxWakeUpPipe +{ +public: + // Ctor automatically registers this pipe with the event loop. + SignalsWakeUpPipe() + { + m_source = wxEventLoopBase::AddSourceForFD + ( + GetReadFd(), + this, + wxEVENT_SOURCE_INPUT + ); + } + + virtual void OnReadWaiting() + { + // The base class wxWakeUpPipe::OnReadWaiting() needs to be called in order + // to read the data out of the wake up pipe and clear it for next time. + wxWakeUpPipe::OnReadWaiting(); + + if ( wxTheApp ) + wxTheApp->CheckSignal(); + } + + virtual ~SignalsWakeUpPipe() + { + delete m_source; + } + +private: + wxEventLoopSource* m_source; +}; + +} // anonymous namespace + +wxAppConsole::wxAppConsole() +{ + m_signalWakeUpPipe = NULL; +} + +wxAppConsole::~wxAppConsole() +{ + delete m_signalWakeUpPipe; +} + +// use unusual names for arg[cv] to avoid clashes with wxApp members with the +// same names +bool wxAppConsole::Initialize(int& argc_, wxChar** argv_) +{ + if ( !wxAppConsoleBase::Initialize(argc_, argv_) ) + return false; + + sigemptyset(&m_signalsCaught); + + return true; +} + +// The actual signal handler. It does as little as possible (because very few +// things are safe to do from inside a signal handler) and just ensures that +// CheckSignal() will be called later from SignalsWakeUpPipe::OnReadWaiting(). +void wxAppConsole::HandleSignal(int signal) +{ + wxAppConsole * const app = wxTheApp; + if ( !app ) + return; + + // Register the signal that is caught. + sigaddset(&(app->m_signalsCaught), signal); + + // Wake up the application for handling the signal. + // + // Notice that we must have a valid wake up pipe here as we only install + // our signal handlers after allocating it. + app->m_signalWakeUpPipe->WakeUpNoLock(); +} + +void wxAppConsole::CheckSignal() +{ + for ( SignalHandlerHash::iterator it = m_signalHandlerHash.begin(); + it != m_signalHandlerHash.end(); + ++it ) + { + int sig = it->first; + if ( sigismember(&m_signalsCaught, sig) ) + { + sigdelset(&m_signalsCaught, sig); + (it->second)(sig); + } + } +} + +wxFDIOHandler* wxAppConsole::RegisterSignalWakeUpPipe(wxFDIODispatcher& dispatcher) +{ + wxCHECK_MSG( m_signalWakeUpPipe, NULL, "Should be allocated" ); + + // we need a bridge to wxFDIODispatcher + // + // TODO: refactor the code so that only wxEventLoopSourceHandler is used + wxScopedPtr + fdioHandler(new wxFDIOEventLoopSourceHandler(m_signalWakeUpPipe)); + + if ( !dispatcher.RegisterFD + ( + m_signalWakeUpPipe->GetReadFd(), + fdioHandler.get(), + wxFDIO_INPUT + ) ) + return NULL; + + return fdioHandler.release(); +} + +// the type of the signal handlers we use is "void(*)(int)" while the real +// signal handlers are extern "C" and so have incompatible type and at least +// Sun CC warns about it, so use explicit casts to suppress these warnings as +// they should be harmless +extern "C" +{ + typedef void (*SignalHandler_t)(int); +} + +bool wxAppConsole::SetSignalHandler(int signal, SignalHandler handler) +{ + const bool install = (SignalHandler_t)handler != SIG_DFL && + (SignalHandler_t)handler != SIG_IGN; + + if ( !m_signalWakeUpPipe ) + { + // Create the pipe that the signal handler will use to cause the event + // loop to call wxAppConsole::CheckSignal(). + m_signalWakeUpPipe = new SignalsWakeUpPipe(); + } + + struct sigaction sa; + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = (SignalHandler_t)&wxAppConsole::HandleSignal; + sa.sa_flags = SA_RESTART; + int res = sigaction(signal, &sa, 0); + if ( res != 0 ) + { + wxLogSysError(_("Failed to install signal handler")); + return false; + } + + if ( install ) + m_signalHandlerHash[signal] = handler; + else + m_signalHandlerHash.erase(signal); + + return true; +} + diff --git a/3rdparty/wxwidgets3.0/src/unix/dir.cpp b/3rdparty/wxwidgets3.0/src/unix/dir.cpp new file mode 100755 index 0000000000000..f88a5949355e6 --- /dev/null +++ b/3rdparty/wxwidgets3.0/src/unix/dir.cpp @@ -0,0 +1,338 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: src/unix/dir.cpp +// Purpose: wxDir implementation for Unix/POSIX systems +// Author: Vadim Zeitlin +// Modified by: +// Created: 08.12.99 +// Copyright: (c) 1999 Vadim Zeitlin +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#ifndef WX_PRECOMP + #include "wx/intl.h" + #include "wx/log.h" +#endif // PCH + +#include "wx/dir.h" +#include "wx/filefn.h" // for wxMatchWild +#include "wx/filename.h" + +#include +#include +#include + +#include + +// ---------------------------------------------------------------------------- +// macros +// ---------------------------------------------------------------------------- + +#define M_DIR ((wxDirData *)m_data) + +// ---------------------------------------------------------------------------- +// private classes +// ---------------------------------------------------------------------------- + +// this class stores everything we need to enumerate the files +class wxDirData +{ +public: + wxDirData(const wxString& dirname); + ~wxDirData(); + + bool IsOk() const { return m_dir != NULL; } + + void SetFileSpec(const wxString& filespec) { m_filespec = filespec; } + void SetFlags(int flags) { m_flags = flags; } + + void Rewind() { rewinddir(m_dir); } + bool Read(wxString *filename); + + const wxString& GetName() const { return m_dirname; } + +private: + DIR *m_dir; + + wxString m_dirname; + wxString m_filespec; + + int m_flags; +}; + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxDirData +// ---------------------------------------------------------------------------- + +#if !defined( __VMS__ ) || ( __VMS_VER >= 70000000 ) + +wxDirData::wxDirData(const wxString& dirname) + : m_dirname(dirname) +{ + m_dir = NULL; + + // throw away the trailing slashes + size_t n = m_dirname.length(); + wxCHECK_RET( n, wxT("empty dir name in wxDir") ); + + while ( n > 0 && m_dirname[--n] == '/' ) + ; + + m_dirname.Truncate(n + 1); + + // do open the dir + m_dir = opendir(m_dirname.fn_str()); +} + +wxDirData::~wxDirData() +{ + if ( m_dir ) + { + if ( closedir(m_dir) != 0 ) + { + wxLogLastError(wxT("closedir")); + } + } +} + +bool wxDirData::Read(wxString *filename) +{ + dirent *de = NULL; // just to silence compiler warnings + bool matches = false; + + // speed up string concatenation in the loop a bit + wxString path = m_dirname; + path += wxT('/'); + path.reserve(path.length() + 255); + + wxString de_d_name; + + while ( !matches ) + { + de = readdir(m_dir); + if ( !de ) + return false; + +#if wxUSE_UNICODE + de_d_name = wxString(de->d_name, *wxConvFileName); +#else + de_d_name = de->d_name; +#endif + + // don't return "." and ".." unless asked for + if ( de->d_name[0] == '.' && + ((de->d_name[1] == '.' && de->d_name[2] == '\0') || + (de->d_name[1] == '\0')) ) + { + if ( !(m_flags & wxDIR_DOTDOT) ) + continue; + + // we found a valid match + break; + } + + // check the type now: notice that we may want to check the type of + // the path itself and not whatever it points to in case of a symlink + wxFileName fn = wxFileName::DirName(path + de_d_name); + if ( m_flags & wxDIR_NO_FOLLOW ) + { + fn.DontFollowLink(); + } + + if ( !(m_flags & wxDIR_FILES) && !fn.DirExists() ) + { + // it's a file, but we don't want them + continue; + } + else if ( !(m_flags & wxDIR_DIRS) && fn.DirExists() ) + { + // it's a dir, and we don't want it + continue; + } + + // finally, check the name + if ( m_filespec.empty() ) + { + matches = m_flags & wxDIR_HIDDEN ? true : de->d_name[0] != '.'; + } + else + { + // test against the pattern + matches = wxMatchWild(m_filespec, de_d_name, + !(m_flags & wxDIR_HIDDEN)); + } + } + + *filename = de_d_name; + + return true; +} + +#else // old VMS (TODO) + +wxDirData::wxDirData(const wxString& WXUNUSED(dirname)) +{ + wxFAIL_MSG(wxT("not implemented")); +} + +wxDirData::~wxDirData() +{ +} + +bool wxDirData::Read(wxString * WXUNUSED(filename)) +{ + return false; +} + +#endif // not or new VMS/old VMS + +// ---------------------------------------------------------------------------- +// wxDir construction/destruction +// ---------------------------------------------------------------------------- + +wxDir::wxDir(const wxString& dirname) +{ + m_data = NULL; + + (void)Open(dirname); +} + +bool wxDir::Open(const wxString& dirname) +{ + delete M_DIR; + m_data = new wxDirData(dirname); + + if ( !M_DIR->IsOk() ) + { + delete M_DIR; + m_data = NULL; + + return false; + } + + return true; +} + +bool wxDir::IsOpened() const +{ + return m_data != NULL; +} + +wxString wxDir::GetName() const +{ + wxString name; + if ( m_data ) + { + name = M_DIR->GetName(); + + // Notice that we need to check for length > 1 as we shouldn't remove + // the last slash from the root directory! + if ( name.length() > 1 && (name.Last() == wxT('/')) ) + { + // chop off the last slash + name.RemoveLast(); + } + } + + return name; +} + +void wxDir::Close() +{ + if ( m_data ) + { + delete m_data; + m_data = NULL; + } +} + +// ---------------------------------------------------------------------------- +// wxDir enumerating +// ---------------------------------------------------------------------------- + +bool wxDir::GetFirst(wxString *filename, + const wxString& filespec, + int flags) const +{ + wxCHECK_MSG( IsOpened(), false, wxT("must wxDir::Open() first") ); + + M_DIR->Rewind(); + + M_DIR->SetFileSpec(filespec); + M_DIR->SetFlags(flags); + + return GetNext(filename); +} + +bool wxDir::GetNext(wxString *filename) const +{ + wxCHECK_MSG( IsOpened(), false, wxT("must wxDir::Open() first") ); + + wxCHECK_MSG( filename, false, wxT("bad pointer in wxDir::GetNext()") ); + + return M_DIR->Read(filename); +} + +bool wxDir::HasSubDirs(const wxString& spec) const +{ + wxCHECK_MSG( IsOpened(), false, wxT("must wxDir::Open() first") ); + + if ( spec.empty() ) + { + // faster check for presence of any subdirectory: normally each subdir + // has a hard link to the parent directory and so, knowing that there + // are at least "." and "..", we have a subdirectory if and only if + // links number is > 2 - this is just a guess but it works fairly well + // in practice + // + // note that we may guess wrongly in one direction only: i.e. we may + // return true when there are no subdirectories but this is ok as the + // caller will learn it soon enough when it calls GetFirst(wxDIR) + // anyhow + wxStructStat stBuf; + if ( wxStat(M_DIR->GetName(), &stBuf) == 0 ) + { + switch ( stBuf.st_nlink ) + { + case 2: + // just "." and ".." + return false; + + case 0: + case 1: + // weird filesystem, don't try to guess for it, use dumb + // method below + break; + + default: + // assume we have subdirs - may turn out to be wrong if we + // have other hard links to this directory but it's not + // that bad as explained above + return true; + } + } + } + + // just try to find first directory + wxString s; + return GetFirst(&s, spec, wxDIR_DIRS | wxDIR_HIDDEN); +} + diff --git a/3rdparty/wxwidgets3.0/src/unix/dlunix.cpp b/3rdparty/wxwidgets3.0/src/unix/dlunix.cpp new file mode 100755 index 0000000000000..74c2277321413 --- /dev/null +++ b/3rdparty/wxwidgets3.0/src/unix/dlunix.cpp @@ -0,0 +1,284 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: src/unix/dlunix.cpp +// Purpose: Unix-specific part of wxDynamicLibrary and related classes +// Author: Vadim Zeitlin +// Modified by: +// Created: 2005-01-16 (extracted from common/dynlib.cpp) +// Copyright: (c) 2000-2005 Vadim Zeitlin +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_DYNLIB_CLASS + +#include "wx/dynlib.h" +#include "wx/ffile.h" + +#ifndef WX_PRECOMP + #include "wx/intl.h" + #include "wx/log.h" +#endif + +#ifdef HAVE_DLOPEN + #include +#endif + +#ifdef __DARWIN__ + #include +#endif + +// if some flags are not supported, just ignore them +#ifndef RTLD_LAZY + #define RTLD_LAZY 0 +#endif + +#ifndef RTLD_NOW + #define RTLD_NOW 0 +#endif + +#ifndef RTLD_GLOBAL + #define RTLD_GLOBAL 0 +#endif + + +#if defined(HAVE_DLOPEN) || defined(__DARWIN__) + #define USE_POSIX_DL_FUNCS +#elif !defined(HAVE_SHL_LOAD) + #error "Don't know how to load dynamic libraries on this platform!" +#endif + +// ---------------------------------------------------------------------------- +// constants +// ---------------------------------------------------------------------------- + +// ---------------------------------------------------------------------------- +// loading/unloading DLLs +// ---------------------------------------------------------------------------- + +wxDllType wxDynamicLibrary::GetProgramHandle() +{ +#ifdef USE_POSIX_DL_FUNCS + return dlopen(0, RTLD_LAZY); +#else + return PROG_HANDLE; +#endif +} + +/* static */ +wxDllType wxDynamicLibrary::RawLoad(const wxString& libname, int flags) +{ + wxASSERT_MSG( !(flags & wxDL_NOW) || !(flags & wxDL_LAZY), + wxT("wxDL_LAZY and wxDL_NOW are mutually exclusive.") ); + +#ifdef USE_POSIX_DL_FUNCS + // we need to use either RTLD_NOW or RTLD_LAZY because if we call dlopen() + // with flags == 0 recent versions of glibc just fail the call, so use + // RTLD_NOW even if wxDL_NOW was not specified + int rtldFlags = flags & wxDL_LAZY ? RTLD_LAZY : RTLD_NOW; + + if ( flags & wxDL_GLOBAL ) + rtldFlags |= RTLD_GLOBAL; + + return dlopen(libname.fn_str(), rtldFlags); +#else // !USE_POSIX_DL_FUNCS + int shlFlags = 0; + + if ( flags & wxDL_LAZY ) + { + shlFlags |= BIND_DEFERRED; + } + else if ( flags & wxDL_NOW ) + { + shlFlags |= BIND_IMMEDIATE; + } + + return shl_load(libname.fn_str(), shlFlags, 0); +#endif // USE_POSIX_DL_FUNCS/!USE_POSIX_DL_FUNCS +} + +/* static */ +void wxDynamicLibrary::Unload(wxDllType handle) +{ +#ifdef wxHAVE_DYNLIB_ERROR + int rc = +#endif + +#ifdef USE_POSIX_DL_FUNCS + dlclose(handle); +#else // !USE_POSIX_DL_FUNCS + shl_unload(handle); +#endif // USE_POSIX_DL_FUNCS/!USE_POSIX_DL_FUNCS + +#if defined(USE_POSIX_DL_FUNCS) && defined(wxHAVE_DYNLIB_ERROR) + if ( rc != 0 ) + Error(); +#endif +} + +/* static */ +void *wxDynamicLibrary::RawGetSymbol(wxDllType handle, const wxString& name) +{ + void *symbol; + +#ifdef USE_POSIX_DL_FUNCS + symbol = dlsym(handle, name.fn_str()); +#else // !USE_POSIX_DL_FUNCS + // note that shl_findsym modifies the handle argument to indicate where the + // symbol was found, but it's ok to modify the local handle copy here + if ( shl_findsym(&handle, name.fn_str(), TYPE_UNDEFINED, &symbol) != 0 ) + symbol = 0; +#endif // USE_POSIX_DL_FUNCS/!USE_POSIX_DL_FUNCS + + return symbol; +} + +// ---------------------------------------------------------------------------- +// error handling +// ---------------------------------------------------------------------------- + +#ifdef wxHAVE_DYNLIB_ERROR + +/* static */ +void wxDynamicLibrary::Error() +{ + wxString err(dlerror()); + + if ( err.empty() ) + err = _("Unknown dynamic library error"); + + wxLogError(wxT("%s"), err); +} + +#endif // wxHAVE_DYNLIB_ERROR + +// ---------------------------------------------------------------------------- +// listing loaded modules +// ---------------------------------------------------------------------------- + +// wxDynamicLibraryDetails declares this class as its friend, so put the code +// initializing new details objects here +class wxDynamicLibraryDetailsCreator +{ +public: + // create a new wxDynamicLibraryDetails from the given data + static wxDynamicLibraryDetails * + New(void *start, void *end, const wxString& path) + { + wxDynamicLibraryDetails *details = new wxDynamicLibraryDetails; + details->m_path = path; + details->m_name = path.AfterLast(wxT('/')); + details->m_address = start; + details->m_length = (char *)end - (char *)start; + + // try to extract the library version from its name + const size_t posExt = path.rfind(wxT(".so")); + if ( posExt != wxString::npos ) + { + if ( path.c_str()[posExt + 3] == wxT('.') ) + { + // assume "libfoo.so.x.y.z" case + details->m_version.assign(path, posExt + 4, wxString::npos); + } + else + { + size_t posDash = path.find_last_of(wxT('-'), posExt); + if ( posDash != wxString::npos ) + { + // assume "libbar-x.y.z.so" case + posDash++; + details->m_version.assign(path, posDash, posExt - posDash); + } + } + } + + return details; + } +}; + +/* static */ +wxDynamicLibraryDetailsArray wxDynamicLibrary::ListLoaded() +{ + wxDynamicLibraryDetailsArray dlls; + +#ifdef __LINUX__ + // examine /proc/self/maps to find out what is loaded in our address space + wxFFile file(wxT("/proc/self/maps")); + if ( file.IsOpened() ) + { + // details of the module currently being parsed + wxString pathCur; + void *startCur = NULL, + *endCur = NULL; + + char path[1024]; + char buf[1024]; + while ( fgets(buf, WXSIZEOF(buf), file.fp()) ) + { + // format is: "start-end perm offset maj:min inode path", see proc(5) + void *start, + *end; + switch ( sscanf(buf, "%p-%p %*4s %*p %*02x:%*02x %*d %1024s\n", + &start, &end, path) ) + { + case 2: + // there may be no path column + path[0] = '\0'; + break; + + case 3: + // nothing to do, read everything we wanted + break; + + default: + // chop '\n' + buf[strlen(buf) - 1] = '\0'; + wxLogDebug(wxT("Failed to parse line \"%s\" in /proc/self/maps."), + buf); + continue; + } + + wxASSERT_MSG( start >= endCur, + wxT("overlapping regions in /proc/self/maps?") ); + + wxString pathNew = wxString::FromAscii(path); + if ( pathCur.empty() ) + { + // new module start + pathCur = pathNew; + startCur = start; + endCur = end; + } + else if ( pathCur == pathNew && endCur == end ) + { + // continuation of the same module in the address space + endCur = end; + } + else // end of the current module + { + dlls.Add(wxDynamicLibraryDetailsCreator::New(startCur, + endCur, + pathCur)); + pathCur.clear(); + } + } + } +#endif // __LINUX__ + + return dlls; +} + +#endif // wxUSE_DYNLIB_CLASS + diff --git a/3rdparty/wxwidgets3.0/src/unix/epolldispatcher.cpp b/3rdparty/wxwidgets3.0/src/unix/epolldispatcher.cpp new file mode 100755 index 0000000000000..1efc707d00ad6 --- /dev/null +++ b/3rdparty/wxwidgets3.0/src/unix/epolldispatcher.cpp @@ -0,0 +1,247 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: src/unix/epolldispatcher.cpp +// Purpose: implements dispatcher for epoll_wait() call +// Author: Lukasz Michalski +// Created: April 2007 +// Copyright: (c) 2007 Lukasz Michalski +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// for compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#if wxUSE_EPOLL_DISPATCHER + +#include "wx/unix/private/epolldispatcher.h" +#include "wx/unix/private.h" +#include "wx/stopwatch.h" + +#ifndef WX_PRECOMP + #include "wx/log.h" + #include "wx/intl.h" +#endif + +#include +#include +#include + +#define wxEpollDispatcher_Trace wxT("epolldispatcher") + +// ============================================================================ +// implementation +// ============================================================================ + +// helper: return EPOLLxxx mask corresponding to the given flags (and also log +// debugging messages about it) +static uint32_t GetEpollMask(int flags, int fd) +{ + wxUnusedVar(fd); // unused if wxLogTrace() disabled + + uint32_t ep = 0; + + if ( flags & wxFDIO_INPUT ) + { + ep |= EPOLLIN; + wxLogTrace(wxEpollDispatcher_Trace, + wxT("Registered fd %d for input events"), fd); + } + + if ( flags & wxFDIO_OUTPUT ) + { + ep |= EPOLLOUT; + wxLogTrace(wxEpollDispatcher_Trace, + wxT("Registered fd %d for output events"), fd); + } + + if ( flags & wxFDIO_EXCEPTION ) + { + ep |= EPOLLERR | EPOLLHUP; + wxLogTrace(wxEpollDispatcher_Trace, + wxT("Registered fd %d for exceptional events"), fd); + } + + return ep; +} + +// ---------------------------------------------------------------------------- +// wxEpollDispatcher +// ---------------------------------------------------------------------------- + +/* static */ +wxEpollDispatcher *wxEpollDispatcher::Create() +{ + int epollDescriptor = epoll_create(1024); + if ( epollDescriptor == -1 ) + { + wxLogSysError(_("Failed to create epoll descriptor")); + return NULL; + } + wxLogTrace(wxEpollDispatcher_Trace, + wxT("Epoll fd %d created"), epollDescriptor); + return new wxEpollDispatcher(epollDescriptor); +} + +wxEpollDispatcher::wxEpollDispatcher(int epollDescriptor) +{ + wxASSERT_MSG( epollDescriptor != -1, wxT("invalid descriptor") ); + + m_epollDescriptor = epollDescriptor; +} + +wxEpollDispatcher::~wxEpollDispatcher() +{ + if ( close(m_epollDescriptor) != 0 ) + { + wxLogSysError(_("Error closing epoll descriptor")); + } +} + +bool wxEpollDispatcher::RegisterFD(int fd, wxFDIOHandler* handler, int flags) +{ + epoll_event ev; + ev.events = GetEpollMask(flags, fd); + ev.data.ptr = handler; + + const int ret = epoll_ctl(m_epollDescriptor, EPOLL_CTL_ADD, fd, &ev); + if ( ret != 0 ) + { + wxLogSysError(_("Failed to add descriptor %d to epoll descriptor %d"), + fd, m_epollDescriptor); + + return false; + } + wxLogTrace(wxEpollDispatcher_Trace, + wxT("Added fd %d (handler %p) to epoll %d"), fd, handler, m_epollDescriptor); + + return true; +} + +bool wxEpollDispatcher::ModifyFD(int fd, wxFDIOHandler* handler, int flags) +{ + epoll_event ev; + ev.events = GetEpollMask(flags, fd); + ev.data.ptr = handler; + + const int ret = epoll_ctl(m_epollDescriptor, EPOLL_CTL_MOD, fd, &ev); + if ( ret != 0 ) + { + wxLogSysError(_("Failed to modify descriptor %d in epoll descriptor %d"), + fd, m_epollDescriptor); + + return false; + } + + wxLogTrace(wxEpollDispatcher_Trace, + wxT("Modified fd %d (handler: %p) on epoll %d"), fd, handler, m_epollDescriptor); + return true; +} + +bool wxEpollDispatcher::UnregisterFD(int fd) +{ + epoll_event ev; + ev.events = 0; + ev.data.ptr = NULL; + + if ( epoll_ctl(m_epollDescriptor, EPOLL_CTL_DEL, fd, &ev) != 0 ) + { + wxLogSysError(_("Failed to unregister descriptor %d from epoll descriptor %d"), + fd, m_epollDescriptor); + } + wxLogTrace(wxEpollDispatcher_Trace, + wxT("removed fd %d from %d"), fd, m_epollDescriptor); + return true; +} + +int +wxEpollDispatcher::DoPoll(epoll_event *events, int numEvents, int timeout) const +{ + // the code below relies on TIMEOUT_INFINITE being -1 so that we can pass + // timeout value directly to epoll_wait() which interprets -1 as meaning to + // wait forever and would need to be changed if the value of + // TIMEOUT_INFINITE ever changes + wxCOMPILE_TIME_ASSERT( TIMEOUT_INFINITE == -1, UpdateThisCode ); + + wxMilliClock_t timeEnd; + if ( timeout > 0 ) + timeEnd = wxGetLocalTimeMillis(); + + int rc; + for ( ;; ) + { + rc = epoll_wait(m_epollDescriptor, events, numEvents, timeout); + if ( rc != -1 || errno != EINTR ) + break; + + // we got interrupted, update the timeout and restart + if ( timeout > 0 ) + { + timeout = wxMilliClockToLong(timeEnd - wxGetLocalTimeMillis()); + if ( timeout < 0 ) + return 0; + } + } + + return rc; +} + +bool wxEpollDispatcher::HasPending() const +{ + epoll_event event; + + // NB: it's not really clear if epoll_wait() can return a number greater + // than the number of events passed to it but just in case it can, use + // >= instead of == here, see #10397 + return DoPoll(&event, 1, 0) >= 1; +} + +int wxEpollDispatcher::Dispatch(int timeout) +{ + epoll_event events[16]; + + const int rc = DoPoll(events, WXSIZEOF(events), timeout); + + if ( rc == -1 ) + { + wxLogSysError(_("Waiting for IO on epoll descriptor %d failed"), + m_epollDescriptor); + return -1; + } + + int numEvents = 0; + for ( epoll_event *p = events; p < events + rc; p++ ) + { + wxFDIOHandler * const handler = (wxFDIOHandler *)(p->data.ptr); + if ( !handler ) + { + wxFAIL_MSG( wxT("NULL handler in epoll_event?") ); + continue; + } + + // note that for compatibility with wxSelectDispatcher we call + // OnReadWaiting() on EPOLLHUP as this is what epoll_wait() returns + // when the write end of a pipe is closed while with select() the + // remaining pipe end becomes ready for reading when this happens + if ( p->events & (EPOLLIN | EPOLLHUP) ) + handler->OnReadWaiting(); + else if ( p->events & EPOLLOUT ) + handler->OnWriteWaiting(); + else if ( p->events & EPOLLERR ) + handler->OnExceptionWaiting(); + else + continue; + + numEvents++; + } + + return numEvents; +} + +#endif // wxUSE_EPOLL_DISPATCHER diff --git a/3rdparty/wxwidgets3.0/src/unix/evtloopunix.cpp b/3rdparty/wxwidgets3.0/src/unix/evtloopunix.cpp new file mode 100755 index 0000000000000..948a35441f7fb --- /dev/null +++ b/3rdparty/wxwidgets3.0/src/unix/evtloopunix.cpp @@ -0,0 +1,223 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: src/unix/evtloopunix.cpp +// Purpose: wxEventLoop implementation +// Author: Lukasz Michalski (lm@zork.pl) +// Created: 2007-05-07 +// Copyright: (c) 2006 Zork Lukasz Michalski +// (c) 2009, 2013 Vadim Zeitlin +// (c) 2013 Rob Bresalier +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// =========================================================================== +// declarations +// =========================================================================== + +// --------------------------------------------------------------------------- +// headers +// --------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#if wxUSE_CONSOLE_EVENTLOOP + +#include "wx/evtloop.h" + +#ifndef WX_PRECOMP + #include "wx/app.h" + #include "wx/log.h" +#endif + +#include "wx/apptrait.h" +#include "wx/scopedptr.h" +#include "wx/thread.h" +#include "wx/module.h" +#include "wx/unix/private/timer.h" +#include "wx/unix/private/epolldispatcher.h" +#include "wx/unix/private/wakeuppipe.h" +#include "wx/private/selectdispatcher.h" +#include "wx/private/eventloopsourcesmanager.h" +#include "wx/private/fdioeventloopsourcehandler.h" +#include "wx/private/eventloopsourcesmanager.h" + +#if wxUSE_EVENTLOOP_SOURCE + #include "wx/evtloopsrc.h" +#endif // wxUSE_EVENTLOOP_SOURCE + +// =========================================================================== +// wxEventLoop implementation +// =========================================================================== + +//----------------------------------------------------------------------------- +// initialization +//----------------------------------------------------------------------------- + +wxConsoleEventLoop::wxConsoleEventLoop() +{ + // Be pessimistic initially and assume that we failed to initialize. + m_dispatcher = NULL; + m_wakeupPipe = NULL; + m_wakeupSource = NULL; + + // Create the pipe. + wxScopedPtr wakeupPipe(new wxWakeUpPipeMT); + const int pipeFD = wakeupPipe->GetReadFd(); + if ( pipeFD == wxPipe::INVALID_FD ) + return; + + // And start monitoring it in our event loop. + m_wakeupSource = wxEventLoopBase::AddSourceForFD + ( + pipeFD, + wakeupPipe.get(), + wxFDIO_INPUT + ); + + if ( !m_wakeupSource ) + return; + + // This is a bit ugly but we know that AddSourceForFD() used the currently + // active dispatcher to register this source, so use the same one for our + // other operations. Of course, currently the dispatcher returned by + // wxFDIODispatcher::Get() is always the same one anyhow so it doesn't + // really matter, but if we started returning different things later, it + // would. + m_dispatcher = wxFDIODispatcher::Get(); + + m_wakeupPipe = wakeupPipe.release(); +} + +wxConsoleEventLoop::~wxConsoleEventLoop() +{ + if ( m_wakeupPipe ) + { + delete m_wakeupSource; + + delete m_wakeupPipe; + } +} + +//----------------------------------------------------------------------------- +// adding & removing sources +//----------------------------------------------------------------------------- + +#if wxUSE_EVENTLOOP_SOURCE + +class wxConsoleEventLoopSourcesManager : public wxEventLoopSourcesManagerBase +{ +public: + wxEventLoopSource* AddSourceForFD( int fd, + wxEventLoopSourceHandler *handler, + int flags) + { + wxCHECK_MSG( fd != -1, NULL, "can't monitor invalid fd" ); + + wxLogTrace(wxTRACE_EVT_SOURCE, + "Adding event loop source for fd=%d", fd); + + // we need a bridge to wxFDIODispatcher + // + // TODO: refactor the code so that only wxEventLoopSourceHandler is used + wxScopedPtr + fdioHandler(new wxFDIOEventLoopSourceHandler(handler)); + + if ( !wxFDIODispatcher::Get()->RegisterFD(fd, fdioHandler.get(), flags) ) + return NULL; + + return new wxUnixEventLoopSource(wxFDIODispatcher::Get(), fdioHandler.release(), + fd, handler, flags); + } +}; + +wxEventLoopSourcesManagerBase* wxAppTraits::GetEventLoopSourcesManager() +{ + static wxConsoleEventLoopSourcesManager s_eventLoopSourcesManager; + + return &s_eventLoopSourcesManager; +} + +wxUnixEventLoopSource::~wxUnixEventLoopSource() +{ + wxLogTrace(wxTRACE_EVT_SOURCE, + "Removing event loop source for fd=%d", m_fd); + + m_dispatcher->UnregisterFD(m_fd); + + delete m_fdioHandler; +} + +#endif // wxUSE_EVENTLOOP_SOURCE + +//----------------------------------------------------------------------------- +// events dispatch and loop handling +//----------------------------------------------------------------------------- + +bool wxConsoleEventLoop::Pending() const +{ + if ( m_dispatcher->HasPending() ) + return true; + +#if wxUSE_TIMER + wxUsecClock_t nextTimer; + if ( wxTimerScheduler::Get().GetNext(&nextTimer) && + !wxMilliClockToLong(nextTimer) ) + return true; +#endif // wxUSE_TIMER + + return false; +} + +bool wxConsoleEventLoop::Dispatch() +{ + DispatchTimeout(static_cast( + wxFDIODispatcher::TIMEOUT_INFINITE)); + + return true; +} + +int wxConsoleEventLoop::DispatchTimeout(unsigned long timeout) +{ +#if wxUSE_TIMER + // check if we need to decrease the timeout to account for a timer + wxUsecClock_t nextTimer; + if ( wxTimerScheduler::Get().GetNext(&nextTimer) ) + { + unsigned long timeUntilNextTimer = wxMilliClockToLong(nextTimer / 1000); + if ( timeUntilNextTimer < timeout ) + timeout = timeUntilNextTimer; + } +#endif // wxUSE_TIMER + + bool hadEvent = m_dispatcher->Dispatch(timeout) > 0; + +#if wxUSE_TIMER + if ( wxTimerScheduler::Get().NotifyExpired() ) + hadEvent = true; +#endif // wxUSE_TIMER + + return hadEvent ? 1 : -1; +} + +void wxConsoleEventLoop::WakeUp() +{ +#if wxUSE_THREADS + m_wakeupPipe->WakeUp(); +#else + m_wakeupPipe->WakeUpNoLock(); +#endif +} + +void wxConsoleEventLoop::OnNextIteration() +{ + // call the signal handlers for any signals we caught recently + wxTheApp->CheckSignal(); +} + + +wxEventLoopBase *wxConsoleAppTraits::CreateEventLoop() +{ + return new wxEventLoop(); +} + +#endif // wxUSE_CONSOLE_EVENTLOOP diff --git a/3rdparty/wxwidgets3.0/src/unix/fdiounix.cpp b/3rdparty/wxwidgets3.0/src/unix/fdiounix.cpp new file mode 100755 index 0000000000000..766316d6feeff --- /dev/null +++ b/3rdparty/wxwidgets3.0/src/unix/fdiounix.cpp @@ -0,0 +1,103 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: src/unix/fdiounix.cpp +// Purpose: wxFDIOManager implementation for console Unix applications +// Author: Vadim Zeitlin +// Created: 2009-08-17 +// Copyright: (c) 2009 Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// for compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_SOCKETS + +#include "wx/apptrait.h" +#include "wx/log.h" +#include "wx/private/fdiodispatcher.h" +#include "wx/unix/private/fdiounix.h" + +// ============================================================================ +// wxFDIOManagerUnix implementation +// ============================================================================ + +int wxFDIOManagerUnix::AddInput(wxFDIOHandler *handler, int fd, Direction d) +{ + wxFDIODispatcher * const dispatcher = wxFDIODispatcher::Get(); + wxCHECK_MSG( dispatcher, -1, "can't monitor FDs without FD IO dispatcher" ); + + // translate our direction to dispatcher flags + const int flag = d == INPUT ? wxFDIO_INPUT : wxFDIO_OUTPUT; + + // we need to either register this FD with the dispatcher or update an + // existing registration depending on whether it had been previously + // registered for anything or not + bool ok; + const int regmask = handler->GetRegisteredEvents(); + if ( !regmask ) + { + ok = dispatcher->RegisterFD(fd, handler, flag); + } + else + { + ok = dispatcher->ModifyFD(fd, handler, regmask | flag); + } + + if ( !ok ) + return -1; + + // update the stored mask of registered events + handler->SetRegisteredEvent(flag); + + return fd; +} + +void wxFDIOManagerUnix::RemoveInput(wxFDIOHandler *handler, int fd, Direction d) +{ + wxFDIODispatcher * const dispatcher = wxFDIODispatcher::Get(); + if ( !dispatcher ) + return; + + const int flag = d == INPUT ? wxFDIO_INPUT : wxFDIO_OUTPUT; + + // just as in AddInput() above we may need to either just modify the FD or + // remove it completely if we don't need to monitor it any more + bool ok; + const int regmask = handler->GetRegisteredEvents(); + if ( regmask == flag ) + { + ok = dispatcher->UnregisterFD(fd); + } + else + { + ok = dispatcher->ModifyFD(fd, handler, regmask & ~flag); + } + + if ( !ok ) + { + wxLogDebug("Failed to unregister %d in direction %d", fd, d); + } + + // do this even after a failure to unregister it, we still tried... + handler->ClearRegisteredEvent(flag); +} + +wxFDIOManager *wxAppTraits::GetFDIOManager() +{ + static wxFDIOManagerUnix s_manager; + return &s_manager; +} + +#endif // wxUSE_SOCKETS diff --git a/3rdparty/wxwidgets3.0/src/unix/stackwalk.cpp b/3rdparty/wxwidgets3.0/src/unix/stackwalk.cpp new file mode 100755 index 0000000000000..eccb910e11c0e --- /dev/null +++ b/3rdparty/wxwidgets3.0/src/unix/stackwalk.cpp @@ -0,0 +1,364 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: src/unix/stackwalk.cpp +// Purpose: wxStackWalker implementation for Unix/glibc +// Author: Vadim Zeitlin +// Modified by: +// Created: 2005-01-18 +// Copyright: (c) 2005 Vadim Zeitlin +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_STACKWALKER + +#ifndef WX_PRECOMP + #include "wx/string.h" + #include "wx/app.h" + #include "wx/log.h" + #include "wx/utils.h" +#endif + +#include "wx/stackwalk.h" +#include "wx/stdpaths.h" + +#include + +#ifdef HAVE_CXA_DEMANGLE + #include +#endif // HAVE_CXA_DEMANGLE + +// ---------------------------------------------------------------------------- +// tiny helper wrapper around popen/pclose() +// ---------------------------------------------------------------------------- + +class wxStdioPipe +{ +public: + // ctor parameters are passed to popen() + wxStdioPipe(const char *command, const char *type) + { + m_fp = popen(command, type); + } + + // conversion to stdio FILE + operator FILE *() const { return m_fp; } + + // dtor closes the pipe + ~wxStdioPipe() + { + if ( m_fp ) + pclose(m_fp); + } + +private: + FILE *m_fp; + + wxDECLARE_NO_COPY_CLASS(wxStdioPipe); +}; + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxStackFrame +// ---------------------------------------------------------------------------- + +void wxStackFrame::OnGetName() +{ + if ( !m_name.empty() ) + return; + + // we already tried addr2line in wxStackWalker::InitFrames: it always + // gives us demangled names (even if __cxa_demangle is not available) when + // the function is part of the ELF (when it's in a shared object addr2line + // will give "??") and because it seems less error-prone. + // when it works, backtrace_symbols() sometimes returns incorrect results + + // format is: "module(funcname+offset) [address]" but the part in + // parentheses can be not present + wxString syminfo = wxString::FromAscii(m_syminfo); + const size_t posOpen = syminfo.find(wxT('(')); + if ( posOpen != wxString::npos ) + { + const size_t posPlus = syminfo.find(wxT('+'), posOpen + 1); + if ( posPlus != wxString::npos ) + { + const size_t posClose = syminfo.find(wxT(')'), posPlus + 1); + if ( posClose != wxString::npos ) + { + if ( m_name.empty() ) + { + m_name.assign(syminfo, posOpen + 1, posPlus - posOpen - 1); + +#ifdef HAVE_CXA_DEMANGLE + int rc = -1; + char *cppfunc = __cxxabiv1::__cxa_demangle + ( + m_name.mb_str(), + NULL, // output buffer (none, alloc it) + NULL, // [out] len of output buffer + &rc + ); + if ( rc == 0 ) + m_name = wxString::FromAscii(cppfunc); + + free(cppfunc); +#endif // HAVE_CXA_DEMANGLE + } + + unsigned long ofs; + if ( wxString(syminfo, posPlus + 1, posClose - posPlus - 1). + ToULong(&ofs, 0) ) + m_offset = ofs; + } + } + + m_module.assign(syminfo, posOpen); + } +#ifndef __WXOSX__ + else // not in "module(funcname+offset)" format + { + m_module = syminfo; + } +#endif // !__WXOSX__ +} + + +// ---------------------------------------------------------------------------- +// wxStackWalker +// ---------------------------------------------------------------------------- + +// that many frames should be enough for everyone +#define MAX_FRAMES 200 + +// we need a char buffer big enough to contain a call to addr2line with +// up to MAX_FRAMES addresses ! +// NB: %p specifier will print the pointer in hexadecimal form +// and thus will require 2 chars for each byte + 3 for the +// " 0x" prefix +#define CHARS_PER_FRAME (sizeof(void*) * 2 + 3) + +// BUFSIZE will be 2250 for 32 bit machines +#define BUFSIZE (50 + MAX_FRAMES*CHARS_PER_FRAME) + +// static data +void *wxStackWalker::ms_addresses[MAX_FRAMES]; +char **wxStackWalker::ms_symbols = NULL; +int wxStackWalker::m_depth = 0; +wxString wxStackWalker::ms_exepath; +static char g_buf[BUFSIZE]; + + +void wxStackWalker::SaveStack(size_t maxDepth) +{ + // read all frames required + maxDepth = wxMin(WXSIZEOF(ms_addresses)/sizeof(void*), maxDepth); + m_depth = backtrace(ms_addresses, maxDepth*sizeof(void*)); + if ( !m_depth ) + return; + + ms_symbols = backtrace_symbols(ms_addresses, m_depth); +} + +void wxStackWalker::ProcessFrames(size_t skip) +{ + wxStackFrame frames[MAX_FRAMES]; + + if (!ms_symbols || !m_depth) + return; + + // we are another level down from Walk(), so adjust the number of stack + // frames to skip accordingly + skip += 1; + + // call addr2line only once since this call may be very slow + // (it has to load in memory the entire EXE of this app which may be quite + // big, especially if it contains debug info and is compiled statically!) + int numFrames = InitFrames(frames, m_depth - skip, + &ms_addresses[skip], &ms_symbols[skip]); + + // now do user-defined operations on each frame + for ( int n = 0; n < numFrames; n++ ) + OnStackFrame(frames[n]); +} + +void wxStackWalker::FreeStack() +{ + // ms_symbols has been allocated by backtrace_symbols() and it's the responsibility + // of the caller, i.e. us, to free that pointer + if (ms_symbols) + free( ms_symbols ); + ms_symbols = NULL; + m_depth = 0; +} + +namespace +{ + +// Helper function to read a line from the file and return it without the +// trailing newline. Line number is only used for error reporting. +bool ReadLine(FILE* fp, unsigned long num, wxString* line) +{ + if ( !fgets(g_buf, WXSIZEOF(g_buf), fp) ) + { + wxUnusedVar(num); // could be unused if debug tracing is disabled + + wxLogDebug(wxS("cannot read address information for stack frame #%lu"), + num); + return false; + } + + *line = wxString::FromAscii(g_buf); + line->RemoveLast(); + + return true; +} + +} // anonymous namespace + +int wxStackWalker::InitFrames(wxStackFrame *arr, size_t n, void **addresses, char **syminfo) +{ + // we need to launch addr2line tool to get this information and we need to + // have the program name for this + wxString exepath = wxStackWalker::GetExePath(); + if ( exepath.empty() ) + { + exepath = wxStandardPaths::Get().GetExecutablePath(); + if ( exepath.empty() ) + { + wxLogDebug(wxT("Cannot parse stack frame because the executable ") + wxT("path could not be detected")); + return 0; + } + } + + // build the command line for executing addr2line or atos under OS X using + // char* directly to avoid the conversions from Unicode +#ifdef __WXOSX__ + int len = snprintf(g_buf, BUFSIZE, "atos -p %d", (int)getpid()); +#else + int len = snprintf(g_buf, BUFSIZE, "addr2line -C -f -e \"%s\"", (const char*) exepath.mb_str()); +#endif + len = (len <= 0) ? strlen(g_buf) : len; // in case snprintf() is broken + for (size_t i=0; i +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// for compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_STDPATHS + +#include "wx/stdpaths.h" + +#ifndef WX_PRECOMP + #include "wx/app.h" + #include "wx/wxcrt.h" + #include "wx/utils.h" +#endif //WX_PRECOMP + +#include "wx/filename.h" +#include "wx/log.h" +#include "wx/textfile.h" + +#if defined( __LINUX__ ) || defined( __VMS ) + #include +#endif + +// ============================================================================ +// common VMS/Unix part of wxStandardPaths implementation +// ============================================================================ + +void wxStandardPaths::SetInstallPrefix(const wxString& prefix) +{ + m_prefix = prefix; +} + +wxString wxStandardPaths::GetUserConfigDir() const +{ + return wxFileName::GetHomeDir(); +} + + +// ============================================================================ +// wxStandardPaths implementation for VMS +// ============================================================================ + +#ifdef __VMS + +wxString wxStandardPaths::GetInstallPrefix() const +{ + if ( m_prefix.empty() ) + { + const_cast(this)->m_prefix = wxT("/sys$system"); + } + + return m_prefix; +} + +wxString wxStandardPaths::GetConfigDir() const +{ + return wxT("/sys$manager"); +} + +wxString wxStandardPaths::GetDataDir() const +{ + return AppendAppInfo(GetInstallPrefix() + wxT("/sys$share")); +} + +wxString wxStandardPaths::GetLocalDataDir() const +{ + return AppendAppInfo(wxT("/sys$manager")); +} + +wxString wxStandardPaths::GetUserDataDir() const +{ + return wxFileName::GetHomeDir(); +} + +wxString wxStandardPaths::GetPluginsDir() const +{ + return wxString(); // TODO: this is wrong, it should return something +} + +wxString +wxStandardPaths::GetLocalizedResourcesDir(const wxString& lang, + ResourceCat category) const +{ + return wxStandardPathsBase::GetLocalizedResourcesDir(lang, category); +} + +wxString wxStandardPaths::GetExecutablePath() const +{ + return wxStandardPathsBase::GetExecutablePath(); +} + +#else // !__VMS + +// ============================================================================ +// wxStandardPaths implementation for Unix +// ============================================================================ + +wxString wxStandardPaths::GetExecutablePath() const +{ +#ifdef __LINUX__ + wxString exeStr; + + char buf[4096]; + int result = readlink("/proc/self/exe", buf, WXSIZEOF(buf) - 1); + if ( result != -1 ) + { + buf[result] = '\0'; // readlink() doesn't NUL-terminate the buffer + + // if the /proc/self/exe symlink has been dropped by the kernel for + // some reason, then readlink() could also return success but + // "(deleted)" as link destination... + if ( strcmp(buf, "(deleted)") != 0 ) + exeStr = wxString(buf, wxConvLibc); + } + + if ( exeStr.empty() ) + { + // UPX-specific hack: when using UPX on linux, the kernel will drop the + // /proc/self/exe link; in this case we try to look for a special + // environment variable called " " which is created by UPX to save + // /proc/self/exe contents. See + // http://sf.net/tracker/?func=detail&atid=309863&aid=1565357&group_id=9863 + // for more information about this issue. + wxGetEnv(wxT(" "), &exeStr); + } + + if ( !exeStr.empty() ) + return exeStr; +#endif // __LINUX__ + + return wxStandardPathsBase::GetExecutablePath(); +} + +void wxStandardPaths::DetectPrefix() +{ + // we can try to infer the prefix from the location of the executable + wxString exeStr = GetExecutablePath(); + if ( !exeStr.empty() ) + { + // consider that we're in the last "bin" subdirectory of our prefix + size_t pos = exeStr.rfind(wxT("/bin/")); + if ( pos != wxString::npos ) + m_prefix.assign(exeStr, 0, pos); + } + + if ( m_prefix.empty() ) + { + m_prefix = wxT("/usr/local"); + } +} + +wxString wxStandardPaths::GetInstallPrefix() const +{ + if ( m_prefix.empty() ) + { + wxStandardPaths *pathPtr = const_cast(this); + pathPtr->DetectPrefix(); + } + + return m_prefix; +} + +// ---------------------------------------------------------------------------- +// public functions +// ---------------------------------------------------------------------------- + +wxString wxStandardPaths::GetConfigDir() const +{ + return wxT("/etc"); +} + +wxString wxStandardPaths::GetDataDir() const +{ + // allow to override the location of the data directory by setting + // WX_APPNAME_DATA_DIR environment variable: this is very useful in + // practice for running well-written (and so using wxStandardPaths to find + // their files) wx applications without installing them + static const wxString + envOverride( + getenv( + ("WX_" + wxTheApp->GetAppName().Upper() + "_DATA_DIR").c_str() + ) + ); + + if ( !envOverride.empty() ) + return envOverride; + + return AppendAppInfo(GetInstallPrefix() + wxT("/share")); +} + +wxString wxStandardPaths::GetLocalDataDir() const +{ + return AppendAppInfo(wxT("/etc")); +} + +wxString wxStandardPaths::GetUserDataDir() const +{ + return AppendAppInfo(wxFileName::GetHomeDir() + wxT("/.")); +} + +wxString wxStandardPaths::GetPluginsDir() const +{ + return AppendAppInfo(GetInstallPrefix() + wxT("/lib")); +} + +wxString +wxStandardPaths::GetLocalizedResourcesDir(const wxString& lang, + ResourceCat category) const +{ + if ( category != ResourceCat_Messages ) + return wxStandardPathsBase::GetLocalizedResourcesDir(lang, category); + + return GetInstallPrefix() + wxT("/share/locale/") + lang + wxT("/LC_MESSAGES"); +} + +wxString wxStandardPaths::GetDocumentsDir() const +{ + { + wxLogNull logNull; + wxString homeDir = wxFileName::GetHomeDir(); + wxString configPath; + if (wxGetenv(wxT("XDG_CONFIG_HOME"))) + configPath = wxGetenv(wxT("XDG_CONFIG_HOME")); + else + configPath = homeDir + wxT("/.config"); + wxString dirsFile = configPath + wxT("/user-dirs.dirs"); + if (wxFileExists(dirsFile)) + { + wxTextFile textFile; + if (textFile.Open(dirsFile)) + { + size_t i; + for (i = 0; i < textFile.GetLineCount(); i++) + { + wxString line(textFile[i]); + int pos = line.Find(wxT("XDG_DOCUMENTS_DIR")); + if (pos != wxNOT_FOUND) + { + wxString value = line.AfterFirst(wxT('=')); + value.Replace(wxT("$HOME"), homeDir); + value.Trim(true); + value.Trim(false); + if (!value.IsEmpty() && wxDirExists(value)) + return value; + else + break; + } + } + } + } + } + + return wxStandardPathsBase::GetDocumentsDir(); +} + +#endif // __VMS/!__VMS + +#endif // wxUSE_STDPATHS diff --git a/3rdparty/wxwidgets3.0/src/unix/threadpsx.cpp b/3rdparty/wxwidgets3.0/src/unix/threadpsx.cpp new file mode 100755 index 0000000000000..643acef269f3f --- /dev/null +++ b/3rdparty/wxwidgets3.0/src/unix/threadpsx.cpp @@ -0,0 +1,1904 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: src/unix/threadpsx.cpp +// Purpose: wxThread (Posix) Implementation +// Author: Original from Wolfram Gloger/Guilhem Lavaux +// Modified by: K. S. Sreeram (2002): POSIXified wxCondition, added wxSemaphore +// Created: 04/22/98 +// Copyright: (c) Wolfram Gloger (1996, 1997) +// Guilhem Lavaux (1998) +// Vadim Zeitlin (1999-2002) +// Robert Roebling (1999) +// K. S. Sreeram (2002) +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declaration +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// for compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#if wxUSE_THREADS + +#include "wx/thread.h" +#include "wx/except.h" + +#ifndef WX_PRECOMP + #include "wx/app.h" + #include "wx/dynarray.h" + #include "wx/intl.h" + #include "wx/log.h" + #include "wx/utils.h" + #include "wx/timer.h" + #include "wx/stopwatch.h" + #include "wx/module.h" +#endif + +#include +#include +#include +#include +#include +#include // needed for at least __QNX__ +#ifdef HAVE_SCHED_H + #include +#endif + +#ifdef HAVE_THR_SETCONCURRENCY + #include +#endif + +#ifdef HAVE_ABI_FORCEDUNWIND + #include +#endif + +#ifdef HAVE_SETPRIORITY + #include // for setpriority() +#endif + +// we use wxFFile under Linux in GetCPUCount() +#ifdef __LINUX__ + #include "wx/ffile.h" +#endif + +#define THR_ID_CAST(id) (reinterpret_cast(id)) +#define THR_ID(thr) THR_ID_CAST((thr)->GetId()) + +// ---------------------------------------------------------------------------- +// constants +// ---------------------------------------------------------------------------- + +// the possible states of the thread and transitions from them +enum wxThreadState +{ + STATE_NEW, // didn't start execution yet (=> RUNNING) + STATE_RUNNING, // running (=> PAUSED or EXITED) + STATE_PAUSED, // suspended (=> RUNNING or EXITED) + STATE_EXITED // thread doesn't exist any more +}; + +// the exit value of a thread which has been cancelled +static const wxThread::ExitCode EXITCODE_CANCELLED = (wxThread::ExitCode)-1; + +// trace mask for wxThread operations +#define TRACE_THREADS wxT("thread") + +// you can get additional debugging messages for the semaphore operations +#define TRACE_SEMA wxT("semaphore") + +// ---------------------------------------------------------------------------- +// private functions +// ---------------------------------------------------------------------------- + +static void ScheduleThreadForDeletion(); +static void DeleteThread(wxThread *This); + +// ---------------------------------------------------------------------------- +// private classes +// ---------------------------------------------------------------------------- + +// an (non owning) array of pointers to threads +WX_DEFINE_ARRAY_PTR(wxThread *, wxArrayThread); + +// an entry for a thread we can wait for + +// ----------------------------------------------------------------------------- +// global data +// ----------------------------------------------------------------------------- + +// we keep the list of all threads created by the application to be able to +// terminate them on exit if there are some left - otherwise the process would +// be left in memory +static wxArrayThread gs_allThreads; + +// a mutex to protect gs_allThreads +static wxMutex *gs_mutexAllThreads = NULL; + +// the id of the main thread +// +// we suppose that 0 is not a valid pthread_t value but in principle this might +// be false (e.g. if it's a selector-like value), wxThread::IsMain() would need +// to be updated in such case +wxThreadIdType wxThread::ms_idMainThread = 0; + +// the key for the pointer to the associated wxThread object +static pthread_key_t gs_keySelf; + +// the number of threads which are being deleted - the program won't exit +// until there are any left +static size_t gs_nThreadsBeingDeleted = 0; + +// a mutex to protect gs_nThreadsBeingDeleted +static wxMutex *gs_mutexDeleteThread = NULL; + +// and a condition variable which will be signaled when all +// gs_nThreadsBeingDeleted will have been deleted +static wxCondition *gs_condAllDeleted = NULL; + +#ifndef __WXOSX__ +// this mutex must be acquired before any call to a GUI function +// (it's not inside #if wxUSE_GUI because this file is compiled as part +// of wxBase) +static wxMutex *gs_mutexGui = NULL; +#endif + +// when we wait for a thread to exit, we're blocking on a condition which the +// thread signals in its SignalExit() method -- but this condition can't be a +// member of the thread itself as a detached thread may delete itself at any +// moment and accessing the condition member of the thread after this would +// result in a disaster +// +// so instead we maintain a global list of the structs below for the threads +// we're interested in waiting on + +// ============================================================================ +// wxMutex implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxMutexInternal +// ---------------------------------------------------------------------------- + +// this is a simple wrapper around pthread_mutex_t which provides error +// checking +class wxMutexInternal +{ +public: + wxMutexInternal(wxMutexType mutexType); + ~wxMutexInternal(); + + wxMutexError Lock(); + wxMutexError Lock(unsigned long ms); + wxMutexError TryLock(); + wxMutexError Unlock(); + + bool IsOk() const { return m_isOk; } + +private: + // convert the result of pthread_mutex_[timed]lock() call to wx return code + wxMutexError HandleLockResult(int err); + +private: + pthread_mutex_t m_mutex; + bool m_isOk; + wxMutexType m_type; + unsigned long m_owningThread; + + // wxConditionInternal uses our m_mutex + friend class wxConditionInternal; +}; + +#if defined(HAVE_PTHREAD_MUTEXATTR_T) && \ + wxUSE_UNIX && !defined(HAVE_PTHREAD_MUTEXATTR_SETTYPE_DECL) +// on some systems pthread_mutexattr_settype() is not in the headers (but it is +// in the library, otherwise we wouldn't compile this code at all) +extern "C" int pthread_mutexattr_settype(pthread_mutexattr_t *, int); +#endif + +wxMutexInternal::wxMutexInternal(wxMutexType mutexType) +{ + m_type = mutexType; + m_owningThread = 0; + + int err; + switch ( mutexType ) + { + case wxMUTEX_RECURSIVE: + // support recursive locks like Win32, i.e. a thread can lock a + // mutex which it had itself already locked + // + // unfortunately initialization of recursive mutexes is non + // portable, so try several methods +#ifdef HAVE_PTHREAD_MUTEXATTR_T + { + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + + err = pthread_mutex_init(&m_mutex, &attr); + } +#elif defined(HAVE_PTHREAD_RECURSIVE_MUTEX_INITIALIZER) + // we can use this only as initializer so we have to assign it + // first to a temp var - assigning directly to m_mutex wouldn't + // even compile + { + pthread_mutex_t mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; + m_mutex = mutex; + } +#else // no recursive mutexes + err = EINVAL; +#endif // HAVE_PTHREAD_MUTEXATTR_T/... + break; + + default: + wxFAIL_MSG( wxT("unknown mutex type") ); + // fall through + + case wxMUTEX_DEFAULT: + err = pthread_mutex_init(&m_mutex, NULL); + break; + } + + m_isOk = err == 0; + if ( !m_isOk ) + { + wxLogApiError( wxT("pthread_mutex_init()"), err); + } +} + +wxMutexInternal::~wxMutexInternal() +{ + if ( m_isOk ) + { + int err = pthread_mutex_destroy(&m_mutex); + if ( err != 0 ) + { + wxLogApiError( wxT("pthread_mutex_destroy()"), err); + } + } +} + +wxMutexError wxMutexInternal::Lock() +{ + if ((m_type == wxMUTEX_DEFAULT) && (m_owningThread != 0)) + { + if (m_owningThread == wxThread::GetCurrentId()) + return wxMUTEX_DEAD_LOCK; + } + + return HandleLockResult(pthread_mutex_lock(&m_mutex)); +} + +wxMutexError wxMutexInternal::Lock(unsigned long ms) +{ +#ifdef HAVE_PTHREAD_MUTEX_TIMEDLOCK + static const long MSEC_IN_SEC = 1000; + static const long NSEC_IN_MSEC = 1000000; + static const long NSEC_IN_USEC = 1000; + static const long NSEC_IN_SEC = MSEC_IN_SEC * NSEC_IN_MSEC; + + time_t seconds = ms/MSEC_IN_SEC; + long nanoseconds = (ms % MSEC_IN_SEC) * NSEC_IN_MSEC; + timespec ts = { 0, 0 }; + + // normally we should use clock_gettime(CLOCK_REALTIME) here but this + // function is in librt and we don't link with it currently, so use + // gettimeofday() instead -- if it turns out that this is really too + // imprecise, we should modify configure to check if clock_gettime() is + // available and whether it requires -lrt and use it instead +#if 0 + if ( clock_gettime(CLOCK_REALTIME, &ts) == 0 ) + { + } +#else + struct timeval tv; + if ( wxGetTimeOfDay(&tv) != -1 ) + { + ts.tv_sec = tv.tv_sec; + ts.tv_nsec = tv.tv_usec*NSEC_IN_USEC; + } +#endif + else // fall back on system timer + { + ts.tv_sec = time(NULL); + } + + ts.tv_sec += seconds; + ts.tv_nsec += nanoseconds; + if ( ts.tv_nsec > NSEC_IN_SEC ) + { + ts.tv_sec += 1; + ts.tv_nsec -= NSEC_IN_SEC; + } + + return HandleLockResult(pthread_mutex_timedlock(&m_mutex, &ts)); +#else // !HAVE_PTHREAD_MUTEX_TIMEDLOCK + wxUnusedVar(ms); + + return wxMUTEX_MISC_ERROR; +#endif // HAVE_PTHREAD_MUTEX_TIMEDLOCK/!HAVE_PTHREAD_MUTEX_TIMEDLOCK +} + +wxMutexError wxMutexInternal::HandleLockResult(int err) +{ + // wxPrintf( "err %d\n", err ); + + switch ( err ) + { + case EDEADLK: + // only error checking mutexes return this value and so it's an + // unexpected situation -- hence use assert, not wxLogDebug + wxFAIL_MSG( wxT("mutex deadlock prevented") ); + return wxMUTEX_DEAD_LOCK; + + case EINVAL: + wxLogDebug(wxT("pthread_mutex_[timed]lock(): mutex not initialized")); + break; + + case ETIMEDOUT: + return wxMUTEX_TIMEOUT; + + case 0: + if (m_type == wxMUTEX_DEFAULT) + m_owningThread = wxThread::GetCurrentId(); + return wxMUTEX_NO_ERROR; + + default: + wxLogApiError(wxT("pthread_mutex_[timed]lock()"), err); + } + + return wxMUTEX_MISC_ERROR; +} + + +wxMutexError wxMutexInternal::TryLock() +{ + int err = pthread_mutex_trylock(&m_mutex); + switch ( err ) + { + case EBUSY: + // not an error: mutex is already locked, but we're prepared for + // this + return wxMUTEX_BUSY; + + case EINVAL: + wxLogDebug(wxT("pthread_mutex_trylock(): mutex not initialized.")); + break; + + case 0: + if (m_type == wxMUTEX_DEFAULT) + m_owningThread = wxThread::GetCurrentId(); + return wxMUTEX_NO_ERROR; + + default: + wxLogApiError(wxT("pthread_mutex_trylock()"), err); + } + + return wxMUTEX_MISC_ERROR; +} + +wxMutexError wxMutexInternal::Unlock() +{ + m_owningThread = 0; + + int err = pthread_mutex_unlock(&m_mutex); + switch ( err ) + { + case EPERM: + // we don't own the mutex + return wxMUTEX_UNLOCKED; + + case EINVAL: + wxLogDebug(wxT("pthread_mutex_unlock(): mutex not initialized.")); + break; + + case 0: + return wxMUTEX_NO_ERROR; + + default: + wxLogApiError(wxT("pthread_mutex_unlock()"), err); + } + + return wxMUTEX_MISC_ERROR; +} + +// =========================================================================== +// wxCondition implementation +// =========================================================================== + +// --------------------------------------------------------------------------- +// wxConditionInternal +// --------------------------------------------------------------------------- + +// this is a wrapper around pthread_cond_t associated with a wxMutex (and hence +// with a pthread_mutex_t) +class wxConditionInternal +{ +public: + wxConditionInternal(wxMutex& mutex); + ~wxConditionInternal(); + + bool IsOk() const { return m_isOk && m_mutex.IsOk(); } + + wxCondError Wait(); + wxCondError WaitTimeout(unsigned long milliseconds); + + wxCondError Signal(); + wxCondError Broadcast(); + +private: + // get the POSIX mutex associated with us + pthread_mutex_t *GetPMutex() const { return &m_mutex.m_internal->m_mutex; } + + wxMutex& m_mutex; + pthread_cond_t m_cond; + + bool m_isOk; +}; + +wxConditionInternal::wxConditionInternal(wxMutex& mutex) + : m_mutex(mutex) +{ + int err = pthread_cond_init(&m_cond, NULL /* default attributes */); + + m_isOk = err == 0; + + if ( !m_isOk ) + { + wxLogApiError(wxT("pthread_cond_init()"), err); + } +} + +wxConditionInternal::~wxConditionInternal() +{ + if ( m_isOk ) + { + int err = pthread_cond_destroy(&m_cond); + if ( err != 0 ) + { + wxLogApiError(wxT("pthread_cond_destroy()"), err); + } + } +} + +wxCondError wxConditionInternal::Wait() +{ + int err = pthread_cond_wait(&m_cond, GetPMutex()); + if ( err != 0 ) + { + wxLogApiError(wxT("pthread_cond_wait()"), err); + + return wxCOND_MISC_ERROR; + } + + return wxCOND_NO_ERROR; +} + +wxCondError wxConditionInternal::WaitTimeout(unsigned long milliseconds) +{ + wxLongLong curtime = wxGetUTCTimeMillis(); + curtime += milliseconds; + wxLongLong temp = curtime / 1000; + int sec = temp.GetLo(); + temp *= 1000; + temp = curtime - temp; + int millis = temp.GetLo(); + + timespec tspec; + + tspec.tv_sec = sec; + tspec.tv_nsec = millis * 1000L * 1000L; + + int err = pthread_cond_timedwait( &m_cond, GetPMutex(), &tspec ); + switch ( err ) + { + case ETIMEDOUT: + return wxCOND_TIMEOUT; + + case 0: + return wxCOND_NO_ERROR; + + default: + wxLogApiError(wxT("pthread_cond_timedwait()"), err); + } + + return wxCOND_MISC_ERROR; +} + +wxCondError wxConditionInternal::Signal() +{ + int err = pthread_cond_signal(&m_cond); + if ( err != 0 ) + { + wxLogApiError(wxT("pthread_cond_signal()"), err); + + return wxCOND_MISC_ERROR; + } + + return wxCOND_NO_ERROR; +} + +wxCondError wxConditionInternal::Broadcast() +{ + int err = pthread_cond_broadcast(&m_cond); + if ( err != 0 ) + { + wxLogApiError(wxT("pthread_cond_broadcast()"), err); + + return wxCOND_MISC_ERROR; + } + + return wxCOND_NO_ERROR; +} + +// =========================================================================== +// wxSemaphore implementation +// =========================================================================== + +// --------------------------------------------------------------------------- +// wxSemaphoreInternal +// --------------------------------------------------------------------------- + +// we implement the semaphores using mutexes and conditions instead of using +// the sem_xxx() POSIX functions because they're not widely available and also +// because it's impossible to implement WaitTimeout() using them +class wxSemaphoreInternal +{ +public: + wxSemaphoreInternal(int initialcount, int maxcount); + + bool IsOk() const { return m_isOk; } + + wxSemaError Wait(); + wxSemaError TryWait(); + wxSemaError WaitTimeout(unsigned long milliseconds); + + wxSemaError Post(); + +private: + wxMutex m_mutex; + wxCondition m_cond; + + size_t m_count, + m_maxcount; + + bool m_isOk; +}; + +wxSemaphoreInternal::wxSemaphoreInternal(int initialcount, int maxcount) + : m_cond(m_mutex) +{ + + if ( (initialcount < 0 || maxcount < 0) || + ((maxcount > 0) && (initialcount > maxcount)) ) + { + wxFAIL_MSG( wxT("wxSemaphore: invalid initial or maximal count") ); + + m_isOk = false; + } + else + { + m_maxcount = (size_t)maxcount; + m_count = (size_t)initialcount; + } + + m_isOk = m_mutex.IsOk() && m_cond.IsOk(); +} + +wxSemaError wxSemaphoreInternal::Wait() +{ + wxMutexLocker locker(m_mutex); + + while ( m_count == 0 ) + { + wxLogTrace(TRACE_SEMA, + wxT("Thread %p waiting for semaphore to become signalled"), + THR_ID_CAST(wxThread::GetCurrentId())); + + if ( m_cond.Wait() != wxCOND_NO_ERROR ) + return wxSEMA_MISC_ERROR; + + wxLogTrace(TRACE_SEMA, + wxT("Thread %p finished waiting for semaphore, count = %lu"), + THR_ID_CAST(wxThread::GetCurrentId()), (unsigned long)m_count); + } + + m_count--; + + return wxSEMA_NO_ERROR; +} + +wxSemaError wxSemaphoreInternal::TryWait() +{ + wxMutexLocker locker(m_mutex); + + if ( m_count == 0 ) + return wxSEMA_BUSY; + + m_count--; + + return wxSEMA_NO_ERROR; +} + +wxSemaError wxSemaphoreInternal::WaitTimeout(unsigned long milliseconds) +{ + wxMutexLocker locker(m_mutex); + + wxLongLong startTime = wxGetLocalTimeMillis(); + + while ( m_count == 0 ) + { + wxLongLong elapsed = wxGetLocalTimeMillis() - startTime; + long remainingTime = (long)milliseconds - (long)elapsed.GetLo(); + if ( remainingTime <= 0 ) + { + // timeout + return wxSEMA_TIMEOUT; + } + + switch ( m_cond.WaitTimeout(remainingTime) ) + { + case wxCOND_TIMEOUT: + return wxSEMA_TIMEOUT; + + default: + return wxSEMA_MISC_ERROR; + + case wxCOND_NO_ERROR: + ; + } + } + + m_count--; + + return wxSEMA_NO_ERROR; +} + +wxSemaError wxSemaphoreInternal::Post() +{ + wxMutexLocker locker(m_mutex); + + if ( m_maxcount > 0 && m_count == m_maxcount ) + { + return wxSEMA_OVERFLOW; + } + + m_count++; + + wxLogTrace(TRACE_SEMA, + wxT("Thread %p about to signal semaphore, count = %lu"), + THR_ID_CAST(wxThread::GetCurrentId()), (unsigned long)m_count); + + return m_cond.Signal() == wxCOND_NO_ERROR ? wxSEMA_NO_ERROR + : wxSEMA_MISC_ERROR; +} + +// =========================================================================== +// wxThread implementation +// =========================================================================== + +// the thread callback functions must have the C linkage +extern "C" +{ + +#ifdef wxHAVE_PTHREAD_CLEANUP + // thread exit function + void wxPthreadCleanup(void *ptr); +#endif // wxHAVE_PTHREAD_CLEANUP + +void *wxPthreadStart(void *ptr); + +} // extern "C" + +// ---------------------------------------------------------------------------- +// wxThreadInternal +// ---------------------------------------------------------------------------- + +class wxThreadInternal +{ +public: + wxThreadInternal(); + ~wxThreadInternal(); + + // thread entry function + static void *PthreadStart(wxThread *thread); + + // thread actions + // create the thread + wxThreadError Create(wxThread *thread, unsigned int stackSize); + // start the thread + wxThreadError Run(); + // unblock the thread allowing it to run + void SignalRun() { m_semRun.Post(); } + // ask the thread to terminate + void Wait(); + // go to sleep until Resume() is called + void Pause(); + // resume the thread + void Resume(); + + // accessors + // priority + int GetPriority() const { return m_prio; } + void SetPriority(int prio) { m_prio = prio; } + // state + wxThreadState GetState() const { return m_state; } + void SetState(wxThreadState state) + { +#if wxUSE_LOG_TRACE + static const wxChar *const stateNames[] = + { + wxT("NEW"), + wxT("RUNNING"), + wxT("PAUSED"), + wxT("EXITED"), + }; + + wxLogTrace(TRACE_THREADS, wxT("Thread %p: %s => %s."), + THR_ID(this), stateNames[m_state], stateNames[state]); +#endif // wxUSE_LOG_TRACE + + m_state = state; + } + // id + pthread_t GetId() const { return m_threadId; } + pthread_t *GetIdPtr() { return &m_threadId; } + // "created" flag + bool WasCreated() const { return m_created; } + // "cancelled" flag + void SetCancelFlag() { m_cancelled = true; } + bool WasCancelled() const { return m_cancelled; } + // exit code + void SetExitCode(wxThread::ExitCode exitcode) { m_exitcode = exitcode; } + wxThread::ExitCode GetExitCode() const { return m_exitcode; } + + // the pause flag + void SetReallyPaused(bool paused) { m_isPaused = paused; } + bool IsReallyPaused() const { return m_isPaused; } + + // tell the thread that it is a detached one + void Detach() + { + wxCriticalSectionLocker lock(m_csJoinFlag); + + m_shouldBeJoined = false; + m_isDetached = true; + } + +#ifdef wxHAVE_PTHREAD_CLEANUP + // this is used by wxPthreadCleanup() only + static void Cleanup(wxThread *thread); +#endif // wxHAVE_PTHREAD_CLEANUP + +private: + pthread_t m_threadId; // id of the thread + wxThreadState m_state; // see wxThreadState enum + int m_prio; // in wxWidgets units: from 0 to 100 + + // this flag is set when the thread was successfully created + bool m_created; + + // this flag is set when the thread should terminate + bool m_cancelled; + + // this flag is set when the thread is blocking on m_semSuspend + bool m_isPaused; + + // the thread exit code - only used for joinable (!detached) threads and + // is only valid after the thread termination + wxThread::ExitCode m_exitcode; + + // many threads may call Wait(), but only one of them should call + // pthread_join(), so we have to keep track of this + wxCriticalSection m_csJoinFlag; + bool m_shouldBeJoined; + bool m_isDetached; + + // this semaphore is posted by Run() and the threads Entry() is not + // called before it is done + wxSemaphore m_semRun; + + // this one is signaled when the thread should resume after having been + // Pause()d + wxSemaphore m_semSuspend; +}; + +// ---------------------------------------------------------------------------- +// thread startup and exit functions +// ---------------------------------------------------------------------------- + +void *wxPthreadStart(void *ptr) +{ + return wxThreadInternal::PthreadStart((wxThread *)ptr); +} + +void *wxThreadInternal::PthreadStart(wxThread *thread) +{ + wxThreadInternal *pthread = thread->m_internal; + + wxLogTrace(TRACE_THREADS, wxT("Thread %p started."), THR_ID(pthread)); + + // associate the thread pointer with the newly created thread so that + // wxThread::This() will work + int rc = pthread_setspecific(gs_keySelf, thread); + if ( rc != 0 ) + { + wxLogSysError(rc, _("Cannot start thread: error writing TLS.")); + + return (void *)-1; + } + + // have to declare this before pthread_cleanup_push() which defines a + // block! + bool dontRunAtAll; + +#ifdef wxHAVE_PTHREAD_CLEANUP + // install the cleanup handler which will be called if the thread is + // cancelled + pthread_cleanup_push(wxPthreadCleanup, thread); +#endif // wxHAVE_PTHREAD_CLEANUP + + // wait for the semaphore to be posted from Run() + pthread->m_semRun.Wait(); + + // test whether we should run the run at all - may be it was deleted + // before it started to Run()? + { + wxCriticalSectionLocker lock(thread->m_critsect); + + dontRunAtAll = pthread->GetState() == STATE_NEW && + pthread->WasCancelled(); + } + + if ( !dontRunAtAll ) + { + // call the main entry + wxLogTrace(TRACE_THREADS, + wxT("Thread %p about to enter its Entry()."), + THR_ID(pthread)); + + wxTRY + { + pthread->m_exitcode = thread->CallEntry(); + + wxLogTrace(TRACE_THREADS, + wxT("Thread %p Entry() returned %lu."), + THR_ID(pthread), wxPtrToUInt(pthread->m_exitcode)); + } +#ifndef wxNO_EXCEPTIONS +#ifdef HAVE_ABI_FORCEDUNWIND + // When using common C++ ABI under Linux we must always rethrow this + // special exception used to unwind the stack when the thread was + // cancelled, otherwise the thread library would simply terminate the + // program, see http://udrepper.livejournal.com/21541.html + catch ( abi::__forced_unwind& ) + { + wxCriticalSectionLocker lock(thread->m_critsect); + pthread->SetState(STATE_EXITED); + throw; + } +#endif // HAVE_ABI_FORCEDUNWIND + catch ( ... ) + { + wxTheApp->OnUnhandledException(); + } +#endif // !wxNO_EXCEPTIONS + + { + wxCriticalSectionLocker lock(thread->m_critsect); + + // change the state of the thread to "exited" so that + // wxPthreadCleanup handler won't do anything from now (if it's + // called before we do pthread_cleanup_pop below) + pthread->SetState(STATE_EXITED); + } + } + + // NB: pthread_cleanup_push/pop() are macros and pop contains the matching + // '}' for the '{' in push, so they must be used in the same block! +#ifdef wxHAVE_PTHREAD_CLEANUP + #ifdef __DECCXX + // under Tru64 we get a warning from macro expansion + #pragma message save + #pragma message disable(declbutnotref) + #endif + + // remove the cleanup handler without executing it + pthread_cleanup_pop(FALSE); + + #ifdef __DECCXX + #pragma message restore + #endif +#endif // wxHAVE_PTHREAD_CLEANUP + + if ( dontRunAtAll ) + { + // FIXME: deleting a possibly joinable thread here??? + delete thread; + + return EXITCODE_CANCELLED; + } + else + { + // terminate the thread + thread->Exit(pthread->m_exitcode); + + wxFAIL_MSG(wxT("wxThread::Exit() can't return.")); + + return NULL; + } +} + +#ifdef wxHAVE_PTHREAD_CLEANUP + +// this handler is called when the thread is cancelled +extern "C" void wxPthreadCleanup(void *ptr) +{ + wxThreadInternal::Cleanup((wxThread *)ptr); +} + +void wxThreadInternal::Cleanup(wxThread *thread) +{ + if (pthread_getspecific(gs_keySelf) == 0) return; + { + wxCriticalSectionLocker lock(thread->m_critsect); + if ( thread->m_internal->GetState() == STATE_EXITED ) + { + // thread is already considered as finished. + return; + } + } + + // exit the thread gracefully + thread->Exit(EXITCODE_CANCELLED); +} + +#endif // wxHAVE_PTHREAD_CLEANUP + +// ---------------------------------------------------------------------------- +// wxThreadInternal +// ---------------------------------------------------------------------------- + +wxThreadInternal::wxThreadInternal() +{ + m_state = STATE_NEW; + m_created = false; + m_cancelled = false; + m_prio = wxPRIORITY_DEFAULT; + m_threadId = 0; + m_exitcode = 0; + + // set to true only when the thread starts waiting on m_semSuspend + m_isPaused = false; + + // defaults for joinable threads + m_shouldBeJoined = true; + m_isDetached = false; +} + +wxThreadInternal::~wxThreadInternal() +{ +} + +#ifdef HAVE_PTHREAD_ATTR_SETSTACKSIZE + #define WXUNUSED_STACKSIZE(identifier) identifier +#else + #define WXUNUSED_STACKSIZE(identifier) WXUNUSED(identifier) +#endif + +wxThreadError wxThreadInternal::Create(wxThread *thread, + unsigned int WXUNUSED_STACKSIZE(stackSize)) +{ + if ( GetState() != STATE_NEW ) + { + // don't recreate thread + return wxTHREAD_RUNNING; + } + + // set up the thread attribute: right now, we only set thread priority + pthread_attr_t attr; + pthread_attr_init(&attr); + +#ifdef HAVE_PTHREAD_ATTR_SETSTACKSIZE + if (stackSize) + pthread_attr_setstacksize(&attr, stackSize); +#endif + +#ifdef HAVE_THREAD_PRIORITY_FUNCTIONS + int policy; + if ( pthread_attr_getschedpolicy(&attr, &policy) != 0 ) + { + wxLogError(_("Cannot retrieve thread scheduling policy.")); + } + +#ifdef __VMS__ + /* the pthread.h contains too many spaces. This is a work-around */ +# undef sched_get_priority_max +#undef sched_get_priority_min +#define sched_get_priority_max(_pol_) \ + (_pol_ == SCHED_OTHER ? PRI_FG_MAX_NP : PRI_FIFO_MAX) +#define sched_get_priority_min(_pol_) \ + (_pol_ == SCHED_OTHER ? PRI_FG_MIN_NP : PRI_FIFO_MIN) +#endif + + int max_prio = sched_get_priority_max(policy), + min_prio = sched_get_priority_min(policy), + prio = GetPriority(); + + if ( min_prio == -1 || max_prio == -1 ) + { + wxLogError(_("Cannot get priority range for scheduling policy %d."), + policy); + } + else if ( max_prio == min_prio ) + { + if ( prio != wxPRIORITY_DEFAULT ) + { + // notify the programmer that this doesn't work here + wxLogWarning(_("Thread priority setting is ignored.")); + } + //else: we have default priority, so don't complain + + // anyhow, don't do anything because priority is just ignored + } + else + { + struct sched_param sp; + if ( pthread_attr_getschedparam(&attr, &sp) != 0 ) + { + wxFAIL_MSG(wxT("pthread_attr_getschedparam() failed")); + } + + sp.sched_priority = min_prio + (prio*(max_prio - min_prio))/100; + + if ( pthread_attr_setschedparam(&attr, &sp) != 0 ) + { + wxFAIL_MSG(wxT("pthread_attr_setschedparam(priority) failed")); + } + } +#endif // HAVE_THREAD_PRIORITY_FUNCTIONS + +#ifdef HAVE_PTHREAD_ATTR_SETSCOPE + // this will make the threads created by this process really concurrent + if ( pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM) != 0 ) + { + wxFAIL_MSG(wxT("pthread_attr_setscope(PTHREAD_SCOPE_SYSTEM) failed")); + } +#endif // HAVE_PTHREAD_ATTR_SETSCOPE + + // VZ: assume that this one is always available (it's rather fundamental), + // if this function is ever missing we should try to use + // pthread_detach() instead (after thread creation) + if ( thread->IsDetached() ) + { + if ( pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) != 0 ) + { + wxFAIL_MSG(wxT("pthread_attr_setdetachstate(DETACHED) failed")); + } + + // never try to join detached threads + Detach(); + } + //else: threads are created joinable by default, it's ok + + // create the new OS thread object + int rc = pthread_create + ( + GetIdPtr(), + &attr, + wxPthreadStart, + (void *)thread + ); + + if ( pthread_attr_destroy(&attr) != 0 ) + { + wxFAIL_MSG(wxT("pthread_attr_destroy() failed")); + } + + if ( rc != 0 ) + { + SetState(STATE_EXITED); + + return wxTHREAD_NO_RESOURCE; + } + + m_created = true; + return wxTHREAD_NO_ERROR; +} + +wxThreadError wxThreadInternal::Run() +{ + wxCHECK_MSG( GetState() == STATE_NEW, wxTHREAD_RUNNING, + wxT("thread may only be started once after Create()") ); + + SetState(STATE_RUNNING); + + // wake up threads waiting for our start + SignalRun(); + + return wxTHREAD_NO_ERROR; +} + +void wxThreadInternal::Wait() +{ + wxCHECK_RET( !m_isDetached, wxT("can't wait for a detached thread") ); + + // if the thread we're waiting for is waiting for the GUI mutex, we will + // deadlock so make sure we release it temporarily + if ( wxThread::IsMain() ) + { +#ifdef __WXOSX__ + // give the thread we're waiting for chance to do the GUI call + // it might be in, we don't do this conditionally as the to be waited on + // thread might have to acquire the mutex later but before terminating + if ( wxGuiOwnedByMainThread() ) + wxMutexGuiLeave(); +#else + wxMutexGuiLeave(); +#endif + } + + wxLogTrace(TRACE_THREADS, + wxT("Starting to wait for thread %p to exit."), + THR_ID(this)); + + // to avoid memory leaks we should call pthread_join(), but it must only be + // done once so use a critical section to serialize the code below + { + wxCriticalSectionLocker lock(m_csJoinFlag); + + if ( m_shouldBeJoined ) + { + // FIXME shouldn't we set cancellation type to DISABLED here? If + // we're cancelled inside pthread_join(), things will almost + // certainly break - but if we disable the cancellation, we + // might deadlock + if ( pthread_join(GetId(), &m_exitcode) != 0 ) + { + // this is a serious problem, so use wxLogError and not + // wxLogDebug: it is possible to bring the system to its knees + // by creating too many threads and not joining them quite + // easily + wxLogError(_("Failed to join a thread, potential memory leak detected - please restart the program")); + } + + m_shouldBeJoined = false; + } + } + +#ifndef __WXOSX__ + // reacquire GUI mutex + if ( wxThread::IsMain() ) + wxMutexGuiEnter(); +#endif +} + +void wxThreadInternal::Pause() +{ + // the state is set from the thread which pauses us first, this function + // is called later so the state should have been already set + wxCHECK_RET( m_state == STATE_PAUSED, + wxT("thread must first be paused with wxThread::Pause().") ); + + wxLogTrace(TRACE_THREADS, + wxT("Thread %p goes to sleep."), THR_ID(this)); + + // wait until the semaphore is Post()ed from Resume() + m_semSuspend.Wait(); +} + +void wxThreadInternal::Resume() +{ + wxCHECK_RET( m_state == STATE_PAUSED, + wxT("can't resume thread which is not suspended.") ); + + // the thread might be not actually paused yet - if there were no call to + // TestDestroy() since the last call to Pause() for example + if ( IsReallyPaused() ) + { + wxLogTrace(TRACE_THREADS, + wxT("Waking up thread %p"), THR_ID(this)); + + // wake up Pause() + m_semSuspend.Post(); + + // reset the flag + SetReallyPaused(false); + } + else + { + wxLogTrace(TRACE_THREADS, + wxT("Thread %p is not yet really paused"), THR_ID(this)); + } + + SetState(STATE_RUNNING); +} + +// ----------------------------------------------------------------------------- +// wxThread static functions +// ----------------------------------------------------------------------------- + +wxThread *wxThread::This() +{ + return (wxThread *)pthread_getspecific(gs_keySelf); +} + +void wxThread::Yield() +{ +#ifdef HAVE_SCHED_YIELD + sched_yield(); +#endif +} + +int wxThread::GetCPUCount() +{ +#if defined(_SC_NPROCESSORS_ONLN) + // this works for Solaris and Linux 2.6 + int rc = sysconf(_SC_NPROCESSORS_ONLN); + if ( rc != -1 ) + { + return rc; + } +#elif defined(__LINUX__) && wxUSE_FFILE + // read from proc (can't use wxTextFile here because it's a special file: + // it has 0 size but still can be read from) + wxLogNull nolog; + + wxFFile file(wxT("/proc/cpuinfo")); + if ( file.IsOpened() ) + { + // slurp the whole file + wxString s; + if ( file.ReadAll(&s) ) + { + // (ab)use Replace() to find the number of "processor: num" strings + size_t count = s.Replace(wxT("processor\t:"), wxT("")); + if ( count > 0 ) + { + return count; + } + + wxLogDebug(wxT("failed to parse /proc/cpuinfo")); + } + else + { + wxLogDebug(wxT("failed to read /proc/cpuinfo")); + } + } +#endif // different ways to get number of CPUs + + // unknown + return -1; +} + +wxThreadIdType wxThread::GetCurrentId() +{ + return (wxThreadIdType)pthread_self(); +} + + +bool wxThread::SetConcurrency(size_t level) +{ +#ifdef HAVE_PTHREAD_SET_CONCURRENCY + int rc = pthread_setconcurrency( level ); +#elif defined(HAVE_THR_SETCONCURRENCY) + int rc = thr_setconcurrency(level); +#else // !HAVE_THR_SETCONCURRENCY + // ok only for the default value + int rc = level == 0 ? 0 : -1; +#endif // HAVE_THR_SETCONCURRENCY/!HAVE_THR_SETCONCURRENCY + + if ( rc != 0 ) + { + wxLogSysError(rc, _("Failed to set thread concurrency level to %lu"), + static_cast(level)); + return false; + } + + return true; +} + +// ----------------------------------------------------------------------------- +// creating thread +// ----------------------------------------------------------------------------- + +wxThread::wxThread(wxThreadKind kind) +{ + // add this thread to the global list of all threads + { + wxMutexLocker lock(*gs_mutexAllThreads); + + gs_allThreads.Add(this); + } + + m_internal = new wxThreadInternal(); + + m_isDetached = kind == wxTHREAD_DETACHED; +} + +wxThreadError wxThread::Create(unsigned int stackSize) +{ + wxCriticalSectionLocker lock(m_critsect); + + return m_internal->Create(this, stackSize); +} + +wxThreadError wxThread::Run() +{ + wxCriticalSectionLocker lock(m_critsect); + + // Create the thread if it wasn't created yet with an explicit + // Create() call: + if ( !m_internal->WasCreated() ) + { + wxThreadError rv = m_internal->Create(this, 0); + if ( rv != wxTHREAD_NO_ERROR ) + return rv; + } + + return m_internal->Run(); +} + +// ----------------------------------------------------------------------------- +// misc accessors +// ----------------------------------------------------------------------------- + +void wxThread::SetPriority(unsigned int prio) +{ + wxCHECK_RET( wxPRIORITY_MIN <= prio && prio <= wxPRIORITY_MAX, + wxT("invalid thread priority") ); + + wxCriticalSectionLocker lock(m_critsect); + + switch ( m_internal->GetState() ) + { + case STATE_NEW: + // thread not yet started, priority will be set when it is + m_internal->SetPriority(prio); + break; + + case STATE_RUNNING: + case STATE_PAUSED: +#ifdef HAVE_THREAD_PRIORITY_FUNCTIONS +#if defined(__LINUX__) + // On Linux, pthread_setschedparam with SCHED_OTHER does not allow + // a priority other than 0. Instead, we use the BSD setpriority + // which alllows us to set a 'nice' value between 20 to -20. Only + // super user can set a value less than zero (more negative yields + // higher priority). setpriority set the static priority of a + // process, but this is OK since Linux is configured as a thread + // per process. + // + // FIXME this is not true for 2.6!! + + // map wx priorites 0..100 to Unix priorities 20..-20 + if ( setpriority(PRIO_PROCESS, 0, -(2*(int)prio)/5 + 20) == -1 ) + { + wxLogError(_("Failed to set thread priority %d."), prio); + } +#else // __LINUX__ + { + struct sched_param sparam; + sparam.sched_priority = prio; + + if ( pthread_setschedparam(m_internal->GetId(), + SCHED_OTHER, &sparam) != 0 ) + { + wxLogError(_("Failed to set thread priority %d."), prio); + } + } +#endif // __LINUX__ +#endif // HAVE_THREAD_PRIORITY_FUNCTIONS + break; + + case STATE_EXITED: + default: + wxFAIL_MSG(wxT("impossible to set thread priority in this state")); + } +} + +unsigned int wxThread::GetPriority() const +{ + wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); + + return m_internal->GetPriority(); +} + +wxThreadIdType wxThread::GetId() const +{ + return (wxThreadIdType) m_internal->GetId(); +} + +// ----------------------------------------------------------------------------- +// pause/resume +// ----------------------------------------------------------------------------- + +wxThreadError wxThread::Pause() +{ + wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR, + wxT("a thread can't pause itself") ); + + wxCriticalSectionLocker lock(m_critsect); + + if ( m_internal->GetState() != STATE_RUNNING ) + { + wxLogDebug(wxT("Can't pause thread which is not running.")); + + return wxTHREAD_NOT_RUNNING; + } + + // just set a flag, the thread will be really paused only during the next + // call to TestDestroy() + m_internal->SetState(STATE_PAUSED); + + return wxTHREAD_NO_ERROR; +} + +wxThreadError wxThread::Resume() +{ + wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR, + wxT("a thread can't resume itself") ); + + wxCriticalSectionLocker lock(m_critsect); + + wxThreadState state = m_internal->GetState(); + + switch ( state ) + { + case STATE_PAUSED: + wxLogTrace(TRACE_THREADS, wxT("Thread %p suspended, resuming."), + THR_ID(this)); + + m_internal->Resume(); + + return wxTHREAD_NO_ERROR; + + case STATE_EXITED: + wxLogTrace(TRACE_THREADS, wxT("Thread %p exited, won't resume."), + THR_ID(this)); + return wxTHREAD_NO_ERROR; + + default: + wxLogDebug(wxT("Attempt to resume a thread which is not paused.")); + + return wxTHREAD_MISC_ERROR; + } +} + +// ----------------------------------------------------------------------------- +// exiting thread +// ----------------------------------------------------------------------------- + +wxThread::ExitCode wxThread::Wait(wxThreadWait WXUNUSED(waitMode)) +{ + wxCHECK_MSG( This() != this, (ExitCode)-1, + wxT("a thread can't wait for itself") ); + + wxCHECK_MSG( !m_isDetached, (ExitCode)-1, + wxT("can't wait for detached thread") ); + + m_internal->Wait(); + + return m_internal->GetExitCode(); +} + +wxThreadError wxThread::Delete(ExitCode *rc, wxThreadWait WXUNUSED(waitMode)) +{ + wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR, + wxT("a thread can't delete itself") ); + + bool isDetached = m_isDetached; + + m_critsect.Enter(); + wxThreadState state = m_internal->GetState(); + + // ask the thread to stop + m_internal->SetCancelFlag(); + + m_critsect.Leave(); + + OnDelete(); + + switch ( state ) + { + case STATE_NEW: + // we need to wake up the thread so that PthreadStart() will + // terminate - right now it's blocking on run semaphore in + // PthreadStart() + m_internal->SignalRun(); + + // fall through + + case STATE_EXITED: + // nothing to do + break; + + case STATE_PAUSED: + // resume the thread first + m_internal->Resume(); + + // fall through + + default: + if ( !isDetached ) + { + // wait until the thread stops + m_internal->Wait(); + + if ( rc ) + { + // return the exit code of the thread + *rc = m_internal->GetExitCode(); + } + } + //else: can't wait for detached threads + } + + if (state == STATE_NEW) + return wxTHREAD_MISC_ERROR; + // for coherency with the MSW implementation, signal the user that + // Delete() was called on a thread which didn't start to run yet. + + return wxTHREAD_NO_ERROR; +} + +wxThreadError wxThread::Kill() +{ + wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR, + wxT("a thread can't kill itself") ); + + OnKill(); + + switch ( m_internal->GetState() ) + { + case STATE_NEW: + case STATE_EXITED: + return wxTHREAD_NOT_RUNNING; + + case STATE_PAUSED: + // resume the thread first + Resume(); + + // fall through + + default: +#ifdef HAVE_PTHREAD_CANCEL + if ( pthread_cancel(m_internal->GetId()) != 0 ) +#endif // HAVE_PTHREAD_CANCEL + { + wxLogError(_("Failed to terminate a thread.")); + + return wxTHREAD_MISC_ERROR; + } + +#ifdef HAVE_PTHREAD_CANCEL + if ( m_isDetached ) + { + // if we use cleanup function, this will be done from + // wxPthreadCleanup() +#ifndef wxHAVE_PTHREAD_CLEANUP + ScheduleThreadForDeletion(); + + // don't call OnExit() here, it can only be called in the + // threads context and we're in the context of another thread + + DeleteThread(this); +#endif // wxHAVE_PTHREAD_CLEANUP + } + else + { + m_internal->SetExitCode(EXITCODE_CANCELLED); + } + + return wxTHREAD_NO_ERROR; +#endif // HAVE_PTHREAD_CANCEL + } +} + +void wxThread::Exit(ExitCode status) +{ + wxASSERT_MSG( This() == this, + wxT("wxThread::Exit() can only be called in the context of the same thread") ); + + if ( m_isDetached ) + { + // from the moment we call OnExit(), the main program may terminate at + // any moment, so mark this thread as being already in process of being + // deleted or wxThreadModule::OnExit() will try to delete it again + ScheduleThreadForDeletion(); + } + + // don't enter m_critsect before calling OnExit() because the user code + // might deadlock if, for example, it signals a condition in OnExit() (a + // common case) while the main thread calls any of functions entering + // m_critsect on us (almost all of them do) + wxTRY + { + OnExit(); + } + wxCATCH_ALL( wxTheApp->OnUnhandledException(); ) + + // delete C++ thread object if this is a detached thread - user is + // responsible for doing this for joinable ones + if ( m_isDetached ) + { + // FIXME I'm feeling bad about it - what if another thread function is + // called (in another thread context) now? It will try to access + // half destroyed object which will probably result in something + // very bad - but we can't protect this by a crit section unless + // we make it a global object, but this would mean that we can + // only call one thread function at a time :-( + DeleteThread(this); + pthread_setspecific(gs_keySelf, 0); + } + else + { + m_critsect.Enter(); + m_internal->SetState(STATE_EXITED); + m_critsect.Leave(); + } + + // terminate the thread (pthread_exit() never returns) + pthread_exit(status); + + wxFAIL_MSG(wxT("pthread_exit() failed")); +} + +// also test whether we were paused +bool wxThread::TestDestroy() +{ + wxASSERT_MSG( This() == this, + wxT("wxThread::TestDestroy() can only be called in the context of the same thread") ); + + m_critsect.Enter(); + + if ( m_internal->GetState() == STATE_PAUSED ) + { + m_internal->SetReallyPaused(true); + + // leave the crit section or the other threads will stop too if they + // try to call any of (seemingly harmless) IsXXX() functions while we + // sleep + m_critsect.Leave(); + + m_internal->Pause(); + } + else + { + // thread wasn't requested to pause, nothing to do + m_critsect.Leave(); + } + + return m_internal->WasCancelled(); +} + +wxThread::~wxThread() +{ + m_critsect.Enter(); + + // check that the thread either exited or couldn't be created + if ( m_internal->GetState() != STATE_EXITED && + m_internal->GetState() != STATE_NEW ) + { + wxLogDebug(wxT("The thread %p is being destroyed although it is still running! The application may crash."), + THR_ID(this)); + } + + m_critsect.Leave(); + + delete m_internal; + + // remove this thread from the global array + { + wxMutexLocker lock(*gs_mutexAllThreads); + + gs_allThreads.Remove(this); + } +} + +// ----------------------------------------------------------------------------- +// state tests +// ----------------------------------------------------------------------------- + +bool wxThread::IsRunning() const +{ + wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); + + return m_internal->GetState() == STATE_RUNNING; +} + +bool wxThread::IsAlive() const +{ + wxCriticalSectionLocker lock((wxCriticalSection&)m_critsect); + + switch ( m_internal->GetState() ) + { + case STATE_RUNNING: + case STATE_PAUSED: + return true; + + default: + return false; + } +} + +bool wxThread::IsPaused() const +{ + wxCriticalSectionLocker lock((wxCriticalSection&)m_critsect); + + return (m_internal->GetState() == STATE_PAUSED); +} + +//-------------------------------------------------------------------- +// wxThreadModule +//-------------------------------------------------------------------- + +#ifdef __WXOSX__ +void wxOSXThreadModuleOnInit(); +void wxOSXThreadModuleOnExit(); +#endif + +class wxThreadModule : public wxModule +{ +public: + virtual bool OnInit(); + virtual void OnExit(); + +private: + DECLARE_DYNAMIC_CLASS(wxThreadModule) +}; + +IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule) + +bool wxThreadModule::OnInit() +{ + int rc = pthread_key_create(&gs_keySelf, NULL /* dtor function */); + if ( rc != 0 ) + { + wxLogSysError(rc, _("Thread module initialization failed: failed to create thread key")); + + return false; + } + + wxThread::ms_idMainThread = wxThread::GetCurrentId(); + + gs_mutexAllThreads = new wxMutex(); + +#ifdef __WXOSX__ + wxOSXThreadModuleOnInit(); +#else + gs_mutexGui = new wxMutex(); + gs_mutexGui->Lock(); +#endif + + gs_mutexDeleteThread = new wxMutex(); + gs_condAllDeleted = new wxCondition(*gs_mutexDeleteThread); + + return true; +} + +void wxThreadModule::OnExit() +{ + wxASSERT_MSG( wxThread::IsMain(), wxT("only main thread can be here") ); + + // are there any threads left which are being deleted right now? + size_t nThreadsBeingDeleted; + + { + wxMutexLocker lock( *gs_mutexDeleteThread ); + nThreadsBeingDeleted = gs_nThreadsBeingDeleted; + + if ( nThreadsBeingDeleted > 0 ) + { + wxLogTrace(TRACE_THREADS, + wxT("Waiting for %lu threads to disappear"), + (unsigned long)nThreadsBeingDeleted); + + // have to wait until all of them disappear + gs_condAllDeleted->Wait(); + } + } + + size_t count; + + { + wxMutexLocker lock(*gs_mutexAllThreads); + + // terminate any threads left + count = gs_allThreads.GetCount(); + if ( count != 0u ) + { + wxLogDebug(wxT("%lu threads were not terminated by the application."), + (unsigned long)count); + } + } // unlock mutex before deleting the threads as they lock it in their dtor + + for ( size_t n = 0u; n < count; n++ ) + { + // Delete calls the destructor which removes the current entry. We + // should only delete the first one each time. + gs_allThreads[0]->Delete(); + } + + delete gs_mutexAllThreads; + +#ifdef __WXOSX__ + wxOSXThreadModuleOnExit(); +#else + // destroy GUI mutex + gs_mutexGui->Unlock(); + delete gs_mutexGui; +#endif + + // and free TLD slot + (void)pthread_key_delete(gs_keySelf); + + delete gs_condAllDeleted; + delete gs_mutexDeleteThread; +} + +// ---------------------------------------------------------------------------- +// global functions +// ---------------------------------------------------------------------------- + +static void ScheduleThreadForDeletion() +{ + wxMutexLocker lock( *gs_mutexDeleteThread ); + + gs_nThreadsBeingDeleted++; + + wxLogTrace(TRACE_THREADS, wxT("%lu thread%s waiting to be deleted"), + (unsigned long)gs_nThreadsBeingDeleted, + gs_nThreadsBeingDeleted == 1 ? wxT("") : wxT("s")); +} + +static void DeleteThread(wxThread *This) +{ + wxLogTrace(TRACE_THREADS, wxT("Thread %p auto deletes."), THR_ID(This)); + + delete This; + + // only lock gs_mutexDeleteThread after deleting the thread to avoid + // calling out into user code with it locked as this may result in + // deadlocks if the thread dtor deletes another thread (see #11501) + wxMutexLocker locker( *gs_mutexDeleteThread ); + + wxCHECK_RET( gs_nThreadsBeingDeleted > 0, + wxT("no threads scheduled for deletion, yet we delete one?") ); + + wxLogTrace(TRACE_THREADS, wxT("%lu threads remain scheduled for deletion."), + (unsigned long)gs_nThreadsBeingDeleted - 1); + + if ( !--gs_nThreadsBeingDeleted ) + { + // no more threads left, signal it + gs_condAllDeleted->Signal(); + } +} + +#ifndef __DARWIN__ + +void wxMutexGuiEnterImpl() +{ + gs_mutexGui->Lock(); +} + +void wxMutexGuiLeaveImpl() +{ + gs_mutexGui->Unlock(); +} + +#endif + +// ---------------------------------------------------------------------------- +// include common implementation code +// ---------------------------------------------------------------------------- + +#include "wx/thrimpl.cpp" + +#endif // wxUSE_THREADS diff --git a/3rdparty/wxwidgets3.0/src/unix/timerunx.cpp b/3rdparty/wxwidgets3.0/src/unix/timerunx.cpp new file mode 100755 index 0000000000000..1d99805f540d4 --- /dev/null +++ b/3rdparty/wxwidgets3.0/src/unix/timerunx.cpp @@ -0,0 +1,273 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: src/unix/timerunx.cpp +// Purpose: wxTimer implementation for non-GUI applications under Unix +// Author: Lukasz Michalski +// Created: 15/01/2005 +// Copyright: (c) 2007 Lukasz Michalski +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +#include "wx/wxprec.h" + +#if wxUSE_TIMER + +#ifndef WX_PRECOMP + #include "wx/log.h" + #include "wx/module.h" + #include "wx/app.h" + #include "wx/list.h" + #include "wx/hashmap.h" + #include "wx/event.h" +#endif + +#include "wx/apptrait.h" +#include "wx/longlong.h" +#include "wx/time.h" +#include "wx/vector.h" + +#include +#include + +#include "wx/unix/private/timer.h" + +#include "wx/listimpl.cpp" +WX_DEFINE_LIST(wxTimerList) + +// trace mask for the debugging messages used here +#define wxTrace_Timer wxT("timer") + +// ---------------------------------------------------------------------------- +// local functions +// ---------------------------------------------------------------------------- + +// helper function to format wxUsecClock_t +static inline wxString wxUsecClockAsString(wxUsecClock_t usec) +{ + #if wxUSE_LONGLONG + return usec.ToString(); + #else // wxUsecClock_t == double + return wxString::Format(wxT("%.0f"), usec); + #endif +} + +// ============================================================================ +// wxTimerScheduler implementation +// ============================================================================ + +wxTimerScheduler *wxTimerScheduler::ms_instance = NULL; + +wxTimerScheduler::~wxTimerScheduler() +{ + for ( wxTimerList::iterator node = m_timers.begin(); + node != m_timers.end(); + ++node ) + { + delete *node; + } +} + +void wxTimerScheduler::AddTimer(wxUnixTimerImpl *timer, wxUsecClock_t expiration) +{ + DoAddTimer(new wxTimerSchedule(timer, expiration)); +} + +void wxTimerScheduler::DoAddTimer(wxTimerSchedule *s) +{ + // do an insertion sort to keep the list sorted in expiration order + wxTimerList::iterator node; + for ( node = m_timers.begin(); node != m_timers.end(); ++node ) + { + wxASSERT_MSG( (*node)->m_timer != s->m_timer, + wxT("adding the same timer twice?") ); + + if ( (*node)->m_expiration > s->m_expiration ) + break; + } + + m_timers.insert(node, s); + + wxLogTrace(wxTrace_Timer, wxT("Inserted timer %d expiring at %s"), + s->m_timer->GetId(), + wxUsecClockAsString(s->m_expiration).c_str()); +} + +void wxTimerScheduler::RemoveTimer(wxUnixTimerImpl *timer) +{ + wxLogTrace(wxTrace_Timer, wxT("Removing timer %d"), timer->GetId()); + + for ( wxTimerList::iterator node = m_timers.begin(); + node != m_timers.end(); + ++node ) + { + if ( (*node)->m_timer == timer ) + { + delete *node; + m_timers.erase(node); + return; + } + } + + wxFAIL_MSG( wxT("removing inexistent timer?") ); +} + +bool wxTimerScheduler::GetNext(wxUsecClock_t *remaining) const +{ + if ( m_timers.empty() ) + return false; + + wxCHECK_MSG( remaining, false, wxT("NULL pointer") ); + + *remaining = (*m_timers.begin())->m_expiration - wxGetUTCTimeUSec(); + if ( *remaining < 0 ) + { + // timer already expired, don't wait at all before notifying it + *remaining = 0; + } + + return true; +} + +bool wxTimerScheduler::NotifyExpired() +{ + if ( m_timers.empty() ) + return false; + + const wxUsecClock_t now = wxGetUTCTimeUSec(); + + typedef wxVector TimerImpls; + TimerImpls toNotify; + for ( wxTimerList::iterator next, + cur = m_timers.begin(); cur != m_timers.end(); cur = next ) + { + wxTimerSchedule * const s = *cur; + if ( s->m_expiration > now ) + { + // as the list is sorted by expiration time, we can skip the rest + break; + } + + // remember next as we will delete the node pointed to by cur + next = cur; + ++next; + + m_timers.erase(cur); + + // check whether we need to keep this timer + wxUnixTimerImpl * const timer = s->m_timer; + if ( timer->IsOneShot() ) + { + // the timer needs to be stopped but don't call its Stop() from + // here as it would attempt to remove the timer from our list and + // we had already done it, so we just need to reset its state + timer->MarkStopped(); + + // don't need it any more + delete s; + } + else // reschedule the next timer expiration + { + // always keep the expiration time in the future, i.e. base it on + // the current time instead of just offsetting it from the current + // expiration time because it could happen that we're late and the + // current expiration time is (far) in the past + s->m_expiration = now + timer->GetInterval()*1000; + DoAddTimer(s); + } + + // we can't notify the timer from this loop as the timer event handler + // could modify m_timers (for example, but not only, by stopping this + // timer) which would render our iterators invalid, so do it after the + // loop end + toNotify.push_back(timer); + } + + if ( toNotify.empty() ) + return false; + + for ( TimerImpls::const_iterator i = toNotify.begin(), + end = toNotify.end(); + i != end; + ++i ) + { + (*i)->Notify(); + } + + return true; +} + +// ============================================================================ +// wxUnixTimerImpl implementation +// ============================================================================ + +wxUnixTimerImpl::wxUnixTimerImpl(wxTimer* timer) + : wxTimerImpl(timer) +{ + m_isRunning = false; +} + +bool wxUnixTimerImpl::Start(int milliseconds, bool oneShot) +{ + // notice that this will stop an already running timer + wxTimerImpl::Start(milliseconds, oneShot); + + wxTimerScheduler::Get().AddTimer(this, wxGetUTCTimeUSec() + m_milli*1000); + m_isRunning = true; + + return true; +} + +void wxUnixTimerImpl::Stop() +{ + if ( m_isRunning ) + { + wxTimerScheduler::Get().RemoveTimer(this); + + m_isRunning = false; + } +} + +bool wxUnixTimerImpl::IsRunning() const +{ + return m_isRunning; +} + +wxUnixTimerImpl::~wxUnixTimerImpl() +{ + wxASSERT_MSG( !m_isRunning, wxT("must have been stopped before") ); +} + +// ============================================================================ +// wxTimerUnixModule: responsible for freeing the global timer scheduler +// ============================================================================ + +class wxTimerUnixModule : public wxModule +{ +public: + wxTimerUnixModule() {} + virtual bool OnInit() { return true; } + virtual void OnExit() { wxTimerScheduler::Shutdown(); } + + DECLARE_DYNAMIC_CLASS(wxTimerUnixModule) +}; + +IMPLEMENT_DYNAMIC_CLASS(wxTimerUnixModule, wxModule) + +// ============================================================================ +// global functions +// ============================================================================ + +wxTimerImpl *wxConsoleAppTraits::CreateTimerImpl(wxTimer *timer) +{ + return new wxUnixTimerImpl(timer); +} + +#endif // wxUSE_TIMER + diff --git a/3rdparty/wxwidgets3.0/src/unix/utilsunx.cpp b/3rdparty/wxwidgets3.0/src/unix/utilsunx.cpp new file mode 100755 index 0000000000000..868d5e57d9851 --- /dev/null +++ b/3rdparty/wxwidgets3.0/src/unix/utilsunx.cpp @@ -0,0 +1,1679 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: src/unix/utilsunx.cpp +// Purpose: generic Unix implementation of many wx functions (for wxBase) +// Author: Vadim Zeitlin +// Copyright: (c) 1998 Robert Roebling, Vadim Zeitlin +// (c) 2013 Rob Bresalier, Vadim Zeitlin +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// for compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#include "wx/utils.h" + +#define USE_PUTENV (!defined(HAVE_SETENV) && defined(HAVE_PUTENV)) + +#ifndef WX_PRECOMP + #include "wx/string.h" + #include "wx/intl.h" + #include "wx/log.h" + #include "wx/app.h" + #include "wx/wxcrtvararg.h" + #if USE_PUTENV + #include "wx/module.h" + #include "wx/hashmap.h" + #endif +#endif + +#include "wx/apptrait.h" + +#include "wx/process.h" +#include "wx/scopedptr.h" +#include "wx/thread.h" + +#include "wx/cmdline.h" + +#include "wx/wfstream.h" + +#include "wx/private/selectdispatcher.h" +#include "wx/private/fdiodispatcher.h" +#include "wx/unix/execute.h" +#include "wx/unix/pipe.h" +#include "wx/unix/private.h" + +#include "wx/evtloop.h" +#include "wx/mstream.h" +#include "wx/private/fdioeventloopsourcehandler.h" + +#include +#include // waitpid() + +#ifdef HAVE_SYS_SELECT_H +# include +#endif + +#define HAS_PIPE_STREAMS (wxUSE_STREAMS && wxUSE_FILE) + +#if HAS_PIPE_STREAMS + +#include "wx/private/pipestream.h" +#include "wx/private/streamtempinput.h" +#include "wx/unix/private/executeiohandler.h" + +#endif // HAS_PIPE_STREAMS + +// not only the statfs syscall is called differently depending on platform, but +// one of its incarnations, statvfs(), takes different arguments under +// different platforms and even different versions of the same system (Solaris +// 7 and 8): if you want to test for this, don't forget that the problems only +// appear if the large files support is enabled +#ifdef HAVE_STATFS + #ifdef __BSD__ + #include + #include + #else // !__BSD__ + #include + #endif // __BSD__/!__BSD__ + + #define wxStatfs statfs + + #ifndef HAVE_STATFS_DECL + // some systems lack statfs() prototype in the system headers (AIX 4) + extern "C" int statfs(const char *path, struct statfs *buf); + #endif +#endif // HAVE_STATFS + +#ifdef HAVE_STATVFS + #include + + #define wxStatfs statvfs +#endif // HAVE_STATVFS + +#if defined(HAVE_STATFS) || defined(HAVE_STATVFS) + // WX_STATFS_T is detected by configure + #define wxStatfs_t WX_STATFS_T +#endif + +// SGI signal.h defines signal handler arguments differently depending on +// whether _LANGUAGE_C_PLUS_PLUS is set or not - do set it +#if defined(__SGI__) && !defined(_LANGUAGE_C_PLUS_PLUS) + #define _LANGUAGE_C_PLUS_PLUS 1 +#endif // SGI hack + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // nanosleep() and/or usleep() +#include // isspace() +#include // needed for FD_SETSIZE + +#ifdef HAVE_UNAME + #include // for uname() +#endif // HAVE_UNAME + +// Used by wxGetFreeMemory(). +#ifdef __SGI__ + #include + #include // for SAGET and MINFO structures +#endif + +#ifdef HAVE_SETPRIORITY + #include // for setpriority() +#endif + +// ---------------------------------------------------------------------------- +// conditional compilation +// ---------------------------------------------------------------------------- + +// many versions of Unices have this function, but it is not defined in system +// headers - please add your system here if it is the case for your OS. +// SunOS < 5.6 (i.e. Solaris < 2.6) and DG-UX are like this. +#if !defined(HAVE_USLEEP) && \ + ((defined(__SUN__) && !defined(__SunOs_5_6) && \ + !defined(__SunOs_5_7) && !defined(__SUNPRO_CC)) || \ + defined(__osf__) || defined(__EMX__)) + extern "C" + { + #ifdef __EMX__ + /* I copied this from the XFree86 diffs. AV. */ + #define INCL_DOSPROCESS + #include + inline void usleep(unsigned long delay) + { + DosSleep(delay ? (delay/1000l) : 1l); + } + #else // Unix + int usleep(unsigned int usec); + #endif // __EMX__/Unix + }; + + #define HAVE_USLEEP 1 +#endif // Unices without usleep() + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// sleeping +// ---------------------------------------------------------------------------- + +void wxSleep(int nSecs) +{ + sleep(nSecs); +} + +void wxMicroSleep(unsigned long microseconds) +{ +#if defined(HAVE_NANOSLEEP) + timespec tmReq; + tmReq.tv_sec = (time_t)(microseconds / 1000000); + tmReq.tv_nsec = (microseconds % 1000000) * 1000; + + // we're not interested in remaining time nor in return value + (void)nanosleep(&tmReq, NULL); +#elif defined(HAVE_USLEEP) + // uncomment this if you feel brave or if you are sure that your version + // of Solaris has a safe usleep() function but please notice that usleep() + // is known to lead to crashes in MT programs in Solaris 2.[67] and is not + // documented as MT-Safe + #if defined(__SUN__) && wxUSE_THREADS + #error "usleep() cannot be used in MT programs under Solaris." + #endif // Sun + + usleep(microseconds); +#elif defined(HAVE_SLEEP) + // under BeOS sleep() takes seconds (what about other platforms, if any?) + sleep(microseconds * 1000000); +#else // !sleep function + #error "usleep() or nanosleep() function required for wxMicroSleep" +#endif // sleep function +} + +void wxMilliSleep(unsigned long milliseconds) +{ + wxMicroSleep(milliseconds*1000); +} + +// ---------------------------------------------------------------------------- +// process management +// ---------------------------------------------------------------------------- + +int wxKill(long pid, wxSignal sig, wxKillError *rc, int flags) +{ + int err = kill((pid_t) (flags & wxKILL_CHILDREN) ? -pid : pid, (int)sig); + if ( rc ) + { + switch ( err ? errno : 0 ) + { + case 0: + *rc = wxKILL_OK; + break; + + case EINVAL: + *rc = wxKILL_BAD_SIGNAL; + break; + + case EPERM: + *rc = wxKILL_ACCESS_DENIED; + break; + + case ESRCH: + *rc = wxKILL_NO_PROCESS; + break; + + default: + // this goes against Unix98 docs so log it + wxLogDebug(wxT("unexpected kill(2) return value %d"), err); + + // something else... + *rc = wxKILL_ERROR; + } + } + + return err; +} + +// Shutdown or reboot the PC +bool wxShutdown(int flags) +{ + flags &= ~wxSHUTDOWN_FORCE; + + wxChar level; + switch ( flags ) + { + case wxSHUTDOWN_POWEROFF: + level = wxT('0'); + break; + + case wxSHUTDOWN_REBOOT: + level = wxT('6'); + break; + + case wxSHUTDOWN_LOGOFF: + // TODO: use dcop to log off? + return false; + + default: + wxFAIL_MSG( wxT("unknown wxShutdown() flag") ); + return false; + } + + return system(wxString::Format("init %c", level).mb_str()) == 0; +} + +// ---------------------------------------------------------------------------- +// wxStream classes to support IO redirection in wxExecute +// ---------------------------------------------------------------------------- + +#if HAS_PIPE_STREAMS + +bool wxPipeInputStream::CanRead() const +{ + if ( m_lasterror == wxSTREAM_EOF ) + return false; + + // check if there is any input available + struct timeval tv; + tv.tv_sec = 0; + tv.tv_usec = 0; + + const int fd = m_file->fd(); + + fd_set readfds; + + wxFD_ZERO(&readfds); + wxFD_SET(fd, &readfds); + + switch ( select(fd + 1, &readfds, NULL, NULL, &tv) ) + { + case -1: + wxLogSysError(_("Impossible to get child process input")); + // fall through + + case 0: + return false; + + default: + wxFAIL_MSG(wxT("unexpected select() return value")); + // still fall through + + case 1: + // input available -- or maybe not, as select() returns 1 when a + // read() will complete without delay, but it could still not read + // anything + return !Eof(); + } +} + +size_t wxPipeOutputStream::OnSysWrite(const void *buffer, size_t size) +{ + // We need to suppress error logging here, because on writing to a pipe + // which is full, wxFile::Write reports a system error. However, this is + // not an extraordinary situation, and it should not be reported to the + // user (but if really needed, the program can recognize it by checking + // whether LastRead() == 0.) Other errors will be reported below. + size_t ret; + { + wxLogNull logNo; + ret = m_file->Write(buffer, size); + } + + switch ( m_file->GetLastError() ) + { + // pipe is full +#ifdef EAGAIN + case EAGAIN: +#endif +#if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN) + case EWOULDBLOCK: +#endif + // do not treat it as an error + m_file->ClearLastError(); + // fall through + + // no error + case 0: + break; + + // some real error + default: + wxLogSysError(_("Can't write to child process's stdin")); + m_lasterror = wxSTREAM_WRITE_ERROR; + } + + return ret; +} + +#endif // HAS_PIPE_STREAMS + +// ---------------------------------------------------------------------------- +// wxShell +// ---------------------------------------------------------------------------- + +static wxString wxMakeShellCommand(const wxString& command) +{ + wxString cmd; + if ( !command ) + { + // just an interactive shell + cmd = wxT("xterm"); + } + else + { + // execute command in a shell + cmd << wxT("/bin/sh -c '") << command << wxT('\''); + } + + return cmd; +} + +bool wxShell(const wxString& command) +{ + return wxExecute(wxMakeShellCommand(command), wxEXEC_SYNC) == 0; +} + +bool wxShell(const wxString& command, wxArrayString& output) +{ + wxCHECK_MSG( !command.empty(), false, wxT("can't exec shell non interactively") ); + + return wxExecute(wxMakeShellCommand(command), output); +} + +namespace +{ + +// helper class for storing arguments as char** array suitable for passing to +// execvp(), whatever form they were passed to us +class ArgsArray +{ +public: + ArgsArray(const wxArrayString& args) + { + Init(args.size()); + + for ( int i = 0; i < m_argc; i++ ) + { + m_argv[i] = wxStrdup(args[i]); + } + } + +#if wxUSE_UNICODE + ArgsArray(wchar_t **wargv) + { + int argc = 0; + while ( wargv[argc] ) + argc++; + + Init(argc); + + for ( int i = 0; i < m_argc; i++ ) + { + m_argv[i] = wxSafeConvertWX2MB(wargv[i]).release(); + } + } +#endif // wxUSE_UNICODE + + ~ArgsArray() + { + for ( int i = 0; i < m_argc; i++ ) + { + free(m_argv[i]); + } + + delete [] m_argv; + } + + operator char**() const { return m_argv; } + +private: + void Init(int argc) + { + m_argc = argc; + m_argv = new char *[m_argc + 1]; + m_argv[m_argc] = NULL; + } + + int m_argc; + char **m_argv; + + wxDECLARE_NO_COPY_CLASS(ArgsArray); +}; + +} // anonymous namespace + +// ---------------------------------------------------------------------------- +// wxExecute implementations +// ---------------------------------------------------------------------------- + +#if defined(__DARWIN__) +bool wxMacLaunch(char **argv); +#endif + +long wxExecute(const wxString& command, int flags, wxProcess *process, + const wxExecuteEnv *env) +{ + ArgsArray argv(wxCmdLineParser::ConvertStringToArgs(command, + wxCMD_LINE_SPLIT_UNIX)); + + return wxExecute(argv, flags, process, env); +} + +#if wxUSE_UNICODE + +long wxExecute(wchar_t **wargv, int flags, wxProcess *process, + const wxExecuteEnv *env) +{ + ArgsArray argv(wargv); + + return wxExecute(argv, flags, process, env); +} + +#endif // wxUSE_UNICODE + +namespace +{ + +// Helper function of wxExecute(): wait for the process termination without +// dispatching any events. +// +// This is used in wxEXEC_NOEVENTS case. +int BlockUntilChildExit(wxExecuteData& execData) +{ + wxCHECK_MSG( wxTheApp, -1, + wxS("Can't block until child exit without wxTheApp") ); + +#if wxUSE_SELECT_DISPATCHER + + // Even if we don't want to dispatch events, we still need to handle + // child IO notifications and process termination concurrently, i.e. + // we can't simply block waiting for the child to terminate as we would + // dead lock if it writes more than the pipe buffer size (typically + // 4KB) bytes of output -- it would then block waiting for us to read + // the data while we'd block waiting for it to terminate. + // + // So while we don't use the full blown event loop, we still do use a + // dispatcher with which we register just the 3 FDs we're interested + // in: the child stdout and stderr and the pipe written to by the + // signal handler so that we could react to the child process + // termination too. + + // Notice that we must create a new dispatcher object here instead of + // reusing the global wxFDIODispatcher::Get() because we want to + // monitor only the events on the FDs explicitly registered with this + // one and not all the other ones that could be registered with the + // global dispatcher (think about the case of nested wxExecute() calls). + wxSelectDispatcher dispatcher; + + // Do register all the FDs we want to monitor here: first, the one used to + // handle the signals asynchronously. + wxScopedPtr + signalHandler(wxTheApp->RegisterSignalWakeUpPipe(dispatcher)); + +#if wxUSE_STREAMS + // And then the two for the child output and error streams if necessary. + wxScopedPtr + stdoutHandler, + stderrHandler; + if ( execData.IsRedirected() ) + { + stdoutHandler.reset(new wxExecuteFDIOHandler + ( + dispatcher, + execData.fdOut, + execData.bufOut + )); + stderrHandler.reset(new wxExecuteFDIOHandler + ( + dispatcher, + execData.fdErr, + execData.bufErr + )); + } +#endif // wxUSE_STREAMS + + // And dispatch until the PID is reset from wxExecuteData::OnExit(). + while ( execData.pid ) + { + dispatcher.Dispatch(); + } + + return execData.exitcode; +#else // !wxUSE_SELECT_DISPATCHER + wxFAIL_MSG( wxS("Can't block until child exit without wxSelectDispatcher") ); + + return -1; +#endif // wxUSE_SELECT_DISPATCHER/!wxUSE_SELECT_DISPATCHER +} + +} // anonymous namespace + +// wxExecute: the real worker function +long wxExecute(char **argv, int flags, wxProcess *process, + const wxExecuteEnv *env) +{ + // for the sync execution, we return -1 to indicate failure, but for async + // case we return 0 which is never a valid PID + // + // we define this as a macro, not a variable, to avoid compiler warnings + // about "ERROR_RETURN_CODE value may be clobbered by fork()" + #define ERROR_RETURN_CODE ((flags & wxEXEC_SYNC) ? -1 : 0) + + wxCHECK_MSG( *argv, ERROR_RETURN_CODE, wxT("can't exec empty command") ); + +#if wxUSE_THREADS + // fork() doesn't mix well with POSIX threads: on many systems the program + // deadlocks or crashes for some reason. Probably our code is buggy and + // doesn't do something which must be done to allow this to work, but I + // don't know what yet, so for now just warn the user (this is the least we + // can do) about it + wxASSERT_MSG( wxThread::IsMain(), + wxT("wxExecute() can be called only from the main thread") ); +#endif // wxUSE_THREADS + +#if defined(__WXCOCOA__) || ( defined(__WXOSX_MAC__) && wxOSX_USE_COCOA_OR_CARBON ) + // wxMacLaunch() only executes app bundles and only does it asynchronously. + // It returns false if the target is not an app bundle, thus falling + // through to the regular code for non app bundles. + if ( !(flags & wxEXEC_SYNC) && wxMacLaunch(argv) ) + { + // we don't have any PID to return so just make up something non null + return -1; + } +#endif // __DARWIN__ + + // this struct contains all information which we use for housekeeping + wxScopedPtr execDataPtr(new wxExecuteData); + wxExecuteData& execData = *execDataPtr; + + execData.flags = flags; + execData.process = process; + + // create pipes for inter process communication + wxPipe pipeIn, // stdin + pipeOut, // stdout + pipeErr; // stderr + + if ( process && process->IsRedirected() ) + { + if ( !pipeIn.Create() || !pipeOut.Create() || !pipeErr.Create() ) + { + wxLogError( _("Failed to execute '%s'\n"), *argv ); + + return ERROR_RETURN_CODE; + } + } + + // priority: we need to map wxWidgets priority which is in the range 0..100 + // to Unix nice value which is in the range -20..19. As there is an odd + // number of elements in our range and an even number in the Unix one, we + // have to do it in this rather ugly way to guarantee that: + // 1. wxPRIORITY_{MIN,DEFAULT,MAX} map to -20, 0 and 19 respectively. + // 2. The mapping is monotonously increasing. + // 3. The mapping is onto the target range. + int prio = process ? int(process->GetPriority()) : int(wxPRIORITY_DEFAULT); + if ( prio <= 50 ) + prio = (2*prio)/5 - 20; + else if ( prio < 55 ) + prio = 1; + else + prio = (2*prio)/5 - 21; + + // fork the process + // + // NB: do *not* use vfork() here, it completely breaks this code for some + // reason under Solaris (and maybe others, although not under Linux) + // But on OpenVMS we do not have fork so we have to use vfork and + // cross our fingers that it works. +#ifdef __VMS + pid_t pid = vfork(); +#else + pid_t pid = fork(); +#endif + if ( pid == -1 ) // error? + { + wxLogSysError( _("Fork failed") ); + + return ERROR_RETURN_CODE; + } + else if ( pid == 0 ) // we're in child + { + // NB: we used to close all the unused descriptors of the child here + // but this broke some programs which relied on e.g. FD 1 being + // always opened so don't do it any more, after all there doesn't + // seem to be any real problem with keeping them opened + +#if !defined(__VMS) && !defined(__EMX__) + if ( flags & wxEXEC_MAKE_GROUP_LEADER ) + { + // Set process group to child process' pid. Then killing -pid + // of the parent will kill the process and all of its children. + setsid(); + } +#endif // !__VMS + +#if defined(HAVE_SETPRIORITY) + if ( prio && setpriority(PRIO_PROCESS, 0, prio) != 0 ) + { + wxLogSysError(_("Failed to set process priority")); + } +#endif // HAVE_SETPRIORITY + + // redirect stdin, stdout and stderr + if ( pipeIn.IsOk() ) + { + if ( dup2(pipeIn[wxPipe::Read], STDIN_FILENO) == -1 || + dup2(pipeOut[wxPipe::Write], STDOUT_FILENO) == -1 || + dup2(pipeErr[wxPipe::Write], STDERR_FILENO) == -1 ) + { + wxLogSysError(_("Failed to redirect child process input/output")); + } + + pipeIn.Close(); + pipeOut.Close(); + pipeErr.Close(); + } + + // Close all (presumably accidentally) inherited file descriptors to + // avoid descriptor leaks. This means that we don't allow inheriting + // them purposefully but this seems like a lesser evil in wx code. + // Ideally we'd provide some flag to indicate that none (or some?) of + // the descriptors do not need to be closed but for now this is better + // than never closing them at all as wx code never used FD_CLOEXEC. + +#ifdef __DARWIN__ + // TODO: Iterating up to FD_SETSIZE is both inefficient (because it may + // be quite big) and incorrect (because in principle we could + // have more opened descriptions than this number). Unfortunately + // there is no good portable solution for closing all descriptors + // above a certain threshold but non-portable solutions exist for + // most platforms, see [http://stackoverflow.com/questions/899038/ + // getting-the-highest-allocated-file-descriptor] + // + // Unfortunately, we cannot do this safely on OS X, because libdispatch + // may crash when we do this: + // Exception Type: EXC_BAD_INSTRUCTION (SIGILL) + // Exception Codes: 0x0000000000000001, 0x0000000000000000 + // + // Application Specific Information: + // BUG IN CLIENT OF LIBDISPATCH: Do not close random Unix descriptors + for ( int fd = 0; fd < (int)FD_SETSIZE; ++fd ) + { + if ( fd != STDIN_FILENO && + fd != STDOUT_FILENO && + fd != STDERR_FILENO ) + { + close(fd); + } + } +#endif // !__DARWIN__ + + + // Process additional options if we have any + if ( env ) + { + // Change working directory if it is specified + if ( !env->cwd.empty() ) + wxSetWorkingDirectory(env->cwd); + + // Change environment if needed. + // + // NB: We can't use execve() currently because we allow using + // non full paths to wxExecute(), i.e. we want to search for + // the program in PATH. However it just might be simpler/better + // to do the search manually and use execve() envp parameter to + // set up the environment of the child process explicitly + // instead of doing what we do below. + if ( !env->env.empty() ) + { + wxEnvVariableHashMap oldenv; + wxGetEnvMap(&oldenv); + + // Remove unwanted variables + wxEnvVariableHashMap::const_iterator it; + for ( it = oldenv.begin(); it != oldenv.end(); ++it ) + { + if ( env->env.find(it->first) == env->env.end() ) + wxUnsetEnv(it->first); + } + + // And add the new ones (possibly replacing the old values) + for ( it = env->env.begin(); it != env->env.end(); ++it ) + wxSetEnv(it->first, it->second); + } + } + + execvp(*argv, argv); + + fprintf(stderr, "execvp("); + for ( char **a = argv; *a; a++ ) + fprintf(stderr, "%s%s", a == argv ? "" : ", ", *a); + fprintf(stderr, ") failed with error %d!\n", errno); + + // there is no return after successful exec() + _exit(-1); + + // some compilers complain about missing return - of course, they + // should know that exit() doesn't return but what else can we do if + // they don't? + // + // and, sure enough, other compilers complain about unreachable code + // after exit() call, so we can just always have return here... +#if defined(__VMS) || defined(__INTEL_COMPILER) + return 0; +#endif + } + else // we're in parent + { + execData.OnStart(pid); + + // prepare for IO redirection + +#if HAS_PIPE_STREAMS + + if ( process && process->IsRedirected() ) + { + // Avoid deadlocks which could result from trying to write to the + // child input pipe end while the child itself is writing to its + // output end and waiting for us to read from it. + if ( !pipeIn.MakeNonBlocking(wxPipe::Write) ) + { + // This message is not terrible useful for the user but what + // else can we do? Also, should we fail here or take the risk + // to continue and deadlock? Currently we choose the latter but + // it might not be the best idea. + wxLogSysError(_("Failed to set up non-blocking pipe, " + "the program might hang.")); +#if wxUSE_LOG + wxLog::FlushActive(); +#endif + } + + wxOutputStream *inStream = + new wxPipeOutputStream(pipeIn.Detach(wxPipe::Write)); + + const int fdOut = pipeOut.Detach(wxPipe::Read); + wxPipeInputStream *outStream = new wxPipeInputStream(fdOut); + + const int fdErr = pipeErr.Detach(wxPipe::Read); + wxPipeInputStream *errStream = new wxPipeInputStream(fdErr); + + process->SetPipeStreams(outStream, inStream, errStream); + + if ( flags & wxEXEC_SYNC ) + { + execData.bufOut.Init(outStream); + execData.bufErr.Init(errStream); + + execData.fdOut = fdOut; + execData.fdErr = fdErr; + } + } +#endif // HAS_PIPE_STREAMS + + if ( pipeIn.IsOk() ) + { + pipeIn.Close(); + pipeOut.Close(); + pipeErr.Close(); + } + + // For the asynchronous case we don't have to do anything else, just + // let the process run. + if ( !(flags & wxEXEC_SYNC) ) + { + // Ensure that the housekeeping data is kept alive, it will be + // destroyed only when the child terminates. + execDataPtr.release(); + + return execData.pid; + } + + + // If we don't need to dispatch any events, things are relatively + // simple and we don't need to delegate to wxAppTraits. + if ( flags & wxEXEC_NOEVENTS ) + { + return BlockUntilChildExit(execData); + } + + + // If we do need to dispatch events, enter a local event loop waiting + // until the child exits. As the exact kind of event loop depends on + // the sort of application we're in (console or GUI), we delegate this + // to wxAppTraits which virtualizes all the differences between the + // console and the GUI programs. + return wxApp::GetValidTraits().WaitForChild(execData); + } + +#if !defined(__VMS) && !defined(__INTEL_COMPILER) + return ERROR_RETURN_CODE; +#endif +} + +#undef ERROR_RETURN_CODE + +// ---------------------------------------------------------------------------- +// file and directory functions +// ---------------------------------------------------------------------------- + +const wxChar* wxGetHomeDir( wxString *home ) +{ + *home = wxGetUserHome(); + wxString tmp; + if ( home->empty() ) + *home = wxT("/"); +#ifdef __VMS + tmp = *home; + if ( tmp.Last() != wxT(']')) + if ( tmp.Last() != wxT('/')) *home << wxT('/'); +#endif + return home->c_str(); +} + +wxString wxGetUserHome( const wxString &user ) +{ + struct passwd *who = (struct passwd *) NULL; + + if ( !user ) + { + wxChar *ptr; + + if ((ptr = wxGetenv(wxT("HOME"))) != NULL) + { + return ptr; + } + + if ((ptr = wxGetenv(wxT("USER"))) != NULL || + (ptr = wxGetenv(wxT("LOGNAME"))) != NULL) + { + who = getpwnam(wxSafeConvertWX2MB(ptr)); + } + + // make sure the user exists! + if ( !who ) + { + who = getpwuid(getuid()); + } + } + else + { + who = getpwnam (user.mb_str()); + } + + return wxSafeConvertMB2WX(who ? who->pw_dir : 0); +} + +// ---------------------------------------------------------------------------- +// network and user id routines +// ---------------------------------------------------------------------------- + +// Private utility function which returns output of the given command, removing +// the trailing newline. +// +// Note that by default use Latin-1 just to ensure that we never fail, but if +// the encoding is known (e.g. UTF-8 for lsb_release), it should be explicitly +// used instead. +static wxString +wxGetCommandOutput(const wxString &cmd, wxMBConv& conv = wxConvISO8859_1) +{ + // Suppress stderr from the shell to avoid outputting errors if the command + // doesn't exist. + FILE *f = popen((cmd + " 2>/dev/null").ToAscii(), "r"); + if ( !f ) + { + // Notice that this doesn't happen simply if the command doesn't exist, + // but only in case of some really catastrophic failure inside popen() + // so we should really notify the user about this as this is not normal. + wxLogSysError(wxT("Executing \"%s\" failed"), cmd); + return wxString(); + } + + wxString s; + char buf[256]; + while ( !feof(f) ) + { + if ( !fgets(buf, sizeof(buf), f) ) + break; + + s += wxString(buf, conv); + } + + pclose(f); + + if ( !s.empty() && s.Last() == wxT('\n') ) + s.RemoveLast(); + + return s; +} + +// retrieve either the hostname or FQDN depending on platform (caller must +// check whether it's one or the other, this is why this function is for +// private use only) +static bool wxGetHostNameInternal(wxChar *buf, int sz) +{ + wxCHECK_MSG( buf, false, wxT("NULL pointer in wxGetHostNameInternal") ); + + *buf = wxT('\0'); + + // we're using uname() which is POSIX instead of less standard sysinfo() +#if defined(HAVE_UNAME) + struct utsname uts; + bool ok = uname(&uts) != -1; + if ( ok ) + { + wxStrlcpy(buf, wxSafeConvertMB2WX(uts.nodename), sz); + } +#elif defined(HAVE_GETHOSTNAME) + char cbuf[sz]; + bool ok = gethostname(cbuf, sz) != -1; + if ( ok ) + { + wxStrlcpy(buf, wxSafeConvertMB2WX(cbuf), sz); + } +#else // no uname, no gethostname + wxFAIL_MSG(wxT("don't know host name for this machine")); + + bool ok = false; +#endif // uname/gethostname + + if ( !ok ) + { + wxLogSysError(_("Cannot get the hostname")); + } + + return ok; +} + +bool wxGetHostName(wxChar *buf, int sz) +{ + bool ok = wxGetHostNameInternal(buf, sz); + + if ( ok ) + { + // BSD systems return the FQDN, we only want the hostname, so extract + // it (we consider that dots are domain separators) + wxChar *dot = wxStrchr(buf, wxT('.')); + if ( dot ) + { + // nuke it + *dot = wxT('\0'); + } + } + + return ok; +} + +bool wxGetFullHostName(wxChar *buf, int sz) +{ + bool ok = wxGetHostNameInternal(buf, sz); + + if ( ok ) + { + if ( !wxStrchr(buf, wxT('.')) ) + { + struct hostent *host = gethostbyname(wxSafeConvertWX2MB(buf)); + if ( !host ) + { + wxLogSysError(_("Cannot get the official hostname")); + + ok = false; + } + else + { + // the canonical name + wxStrlcpy(buf, wxSafeConvertMB2WX(host->h_name), sz); + } + } + //else: it's already a FQDN (BSD behaves this way) + } + + return ok; +} + +bool wxGetUserId(wxChar *buf, int sz) +{ + struct passwd *who; + + *buf = wxT('\0'); + if ((who = getpwuid(getuid ())) != NULL) + { + wxStrlcpy (buf, wxSafeConvertMB2WX(who->pw_name), sz); + return true; + } + + return false; +} + +bool wxGetUserName(wxChar *buf, int sz) +{ +#ifdef HAVE_PW_GECOS + struct passwd *who; + + *buf = wxT('\0'); + if ((who = getpwuid (getuid ())) != NULL) + { + char *comma = strchr(who->pw_gecos, ','); + if (comma) + *comma = '\0'; // cut off non-name comment fields + wxStrlcpy(buf, wxSafeConvertMB2WX(who->pw_gecos), sz); + return true; + } + + return false; +#else // !HAVE_PW_GECOS + return wxGetUserId(buf, sz); +#endif // HAVE_PW_GECOS/!HAVE_PW_GECOS +} + +bool wxIsPlatform64Bit() +{ + const wxString machine = wxGetCommandOutput(wxT("uname -m")); + + // the test for "64" is obviously not 100% reliable but seems to work fine + // in practice + return machine.Contains(wxT("64")) || + machine.Contains(wxT("alpha")); +} + +#ifdef __LINUX__ + +static bool +wxGetValueFromLSBRelease(wxString arg, const wxString& lhs, wxString* rhs) +{ + // lsb_release seems to just read a global file which is always in UTF-8 + // and hence its output is always in UTF-8 as well, regardless of the + // locale currently configured by our environment. + return wxGetCommandOutput(wxS("lsb_release ") + arg, wxConvUTF8) + .StartsWith(lhs, rhs); +} + +wxLinuxDistributionInfo wxGetLinuxDistributionInfo() +{ + wxLinuxDistributionInfo ret; + + if ( !wxGetValueFromLSBRelease(wxS("--id"), wxS("Distributor ID:\t"), + &ret.Id) ) + { + // Don't bother to continue, lsb_release is probably not available. + return ret; + } + + wxGetValueFromLSBRelease(wxS("--description"), wxS("Description:\t"), + &ret.Description); + wxGetValueFromLSBRelease(wxS("--release"), wxS("Release:\t"), + &ret.Release); + wxGetValueFromLSBRelease(wxS("--codename"), wxS("Codename:\t"), + &ret.CodeName); + + return ret; +} +#endif // __LINUX__ + +// these functions are in src/osx/utilsexc_base.cpp for wxMac +#ifndef __DARWIN__ + +wxOperatingSystemId wxGetOsVersion(int *verMaj, int *verMin) +{ + // get OS version + int major, minor; + wxString release = wxGetCommandOutput(wxT("uname -r")); + if ( release.empty() || + wxSscanf(release.c_str(), wxT("%d.%d"), &major, &minor) != 2 ) + { + // failed to get version string or unrecognized format + major = + minor = -1; + } + + if ( verMaj ) + *verMaj = major; + if ( verMin ) + *verMin = minor; + + // try to understand which OS are we running + wxString kernel = wxGetCommandOutput(wxT("uname -s")); + if ( kernel.empty() ) + kernel = wxGetCommandOutput(wxT("uname -o")); + + if ( kernel.empty() ) + return wxOS_UNKNOWN; + + return wxPlatformInfo::GetOperatingSystemId(kernel); +} + +wxString wxGetOsDescription() +{ + return wxGetCommandOutput(wxT("uname -s -r -m")); +} + +#endif // !__DARWIN__ + +unsigned long wxGetProcessId() +{ + return (unsigned long)getpid(); +} + +wxMemorySize wxGetFreeMemory() +{ +#if defined(__LINUX__) + // get it from /proc/meminfo + FILE *fp = fopen("/proc/meminfo", "r"); + if ( fp ) + { + wxMemorySize memFreeBytes = (wxMemorySize)-1; + + char buf[1024]; + if ( fgets(buf, WXSIZEOF(buf), fp) && fgets(buf, WXSIZEOF(buf), fp) ) + { + // /proc/meminfo changed its format in kernel 2.6 + if ( wxPlatformInfo().CheckOSVersion(2, 6) ) + { + unsigned long memFree; + if ( sscanf(buf, "MemFree: %lu", &memFree) == 1 ) + { + // We consider memory used by the IO buffers and cache as + // being "free" too as Linux aggressively uses free memory + // for caching and the amount of memory reported as really + // free is far too low for lightly loaded system. + if ( fgets(buf, WXSIZEOF(buf), fp) ) + { + unsigned long buffers; + if ( sscanf(buf, "Buffers: %lu", &buffers) == 1 ) + memFree += buffers; + } + + if ( fgets(buf, WXSIZEOF(buf), fp) ) + { + unsigned long cached; + if ( sscanf(buf, "Cached: %lu", &cached) == 1 ) + memFree += cached; + } + + // values here are always expressed in kB and we want bytes + memFreeBytes = memFree; + memFreeBytes *= 1024; + } + } + else // Linux 2.4 (or < 2.6, anyhow) + { + long memTotal, memUsed, memFree; + if ( sscanf(buf, "Mem: %ld %ld %ld", + &memTotal, &memUsed, &memFree) == 3 ) + { + memFreeBytes = memFree; + } + } + } + + fclose(fp); + + return memFreeBytes; + } +#elif defined(__SGI__) + struct rminfo realmem; + if ( sysmp(MP_SAGET, MPSA_RMINFO, &realmem, sizeof realmem) == 0 ) + return ((wxMemorySize)realmem.physmem * sysconf(_SC_PAGESIZE)); +#elif defined(_SC_AVPHYS_PAGES) + return ((wxMemorySize)sysconf(_SC_AVPHYS_PAGES))*sysconf(_SC_PAGESIZE); +//#elif defined(__FREEBSD__) -- might use sysctl() to find it out, probably +#endif + + // can't find it out + return -1; +} + +bool wxGetDiskSpace(const wxString& path, wxDiskspaceSize_t *pTotal, wxDiskspaceSize_t *pFree) +{ +#if defined(HAVE_STATFS) || defined(HAVE_STATVFS) + // the case to "char *" is needed for AIX 4.3 + wxStatfs_t fs; + if ( wxStatfs((char *)(const char*)path.fn_str(), &fs) != 0 ) + { + wxLogSysError( wxT("Failed to get file system statistics") ); + + return false; + } + + // under Solaris we also have to use f_frsize field instead of f_bsize + // which is in general a multiple of f_frsize +#ifdef HAVE_STATVFS + wxDiskspaceSize_t blockSize = fs.f_frsize; +#else // HAVE_STATFS + wxDiskspaceSize_t blockSize = fs.f_bsize; +#endif // HAVE_STATVFS/HAVE_STATFS + + if ( pTotal ) + { + *pTotal = wxDiskspaceSize_t(fs.f_blocks) * blockSize; + } + + if ( pFree ) + { + *pFree = wxDiskspaceSize_t(fs.f_bavail) * blockSize; + } + + return true; +#else // !HAVE_STATFS && !HAVE_STATVFS + return false; +#endif // HAVE_STATFS +} + +// ---------------------------------------------------------------------------- +// env vars +// ---------------------------------------------------------------------------- + +#if USE_PUTENV + +WX_DECLARE_STRING_HASH_MAP(char *, wxEnvVars); + +static wxEnvVars gs_envVars; + +class wxSetEnvModule : public wxModule +{ +public: + virtual bool OnInit() { return true; } + virtual void OnExit() + { + for ( wxEnvVars::const_iterator i = gs_envVars.begin(); + i != gs_envVars.end(); + ++i ) + { + free(i->second); + } + + gs_envVars.clear(); + } + + DECLARE_DYNAMIC_CLASS(wxSetEnvModule) +}; + +IMPLEMENT_DYNAMIC_CLASS(wxSetEnvModule, wxModule) + +#endif // USE_PUTENV + +bool wxGetEnv(const wxString& var, wxString *value) +{ + // wxGetenv is defined as getenv() + char *p = wxGetenv(var); + if ( !p ) + return false; + + if ( value ) + { + *value = p; + } + + return true; +} + +static bool wxDoSetEnv(const wxString& variable, const char *value) +{ +#if defined(HAVE_SETENV) + if ( !value ) + { +#ifdef HAVE_UNSETENV + // don't test unsetenv() return value: it's void on some systems (at + // least Darwin) + unsetenv(variable.mb_str()); + return true; +#else + value = ""; // we can't pass NULL to setenv() +#endif + } + + return setenv(variable.mb_str(), value, 1 /* overwrite */) == 0; +#elif defined(HAVE_PUTENV) + wxString s = variable; + if ( value ) + s << wxT('=') << value; + + // transform to ANSI + const wxWX2MBbuf p = s.mb_str(); + + char *buf = (char *)malloc(strlen(p) + 1); + strcpy(buf, p); + + // store the string to free() it later + wxEnvVars::iterator i = gs_envVars.find(variable); + if ( i != gs_envVars.end() ) + { + free(i->second); + i->second = buf; + } + else // this variable hadn't been set before + { + gs_envVars[variable] = buf; + } + + return putenv(buf) == 0; +#else // no way to set an env var + return false; +#endif +} + +bool wxSetEnv(const wxString& variable, const wxString& value) +{ + return wxDoSetEnv(variable, value.mb_str()); +} + +bool wxUnsetEnv(const wxString& variable) +{ + return wxDoSetEnv(variable, NULL); +} + +// ---------------------------------------------------------------------------- +// signal handling +// ---------------------------------------------------------------------------- + +#if wxUSE_ON_FATAL_EXCEPTION + +#include + +extern "C" void wxFatalSignalHandler(wxTYPE_SA_HANDLER) +{ + if ( wxTheApp ) + { + // give the user a chance to do something special about this + wxTheApp->OnFatalException(); + } + + abort(); +} + +bool wxHandleFatalExceptions(bool doit) +{ + // old sig handlers + static bool s_savedHandlers = false; + static struct sigaction s_handlerFPE, + s_handlerILL, + s_handlerBUS, + s_handlerSEGV; + + bool ok = true; + if ( doit && !s_savedHandlers ) + { + // install the signal handler + struct sigaction act; + + // some systems extend it with non std fields, so zero everything + memset(&act, 0, sizeof(act)); + + act.sa_handler = wxFatalSignalHandler; + sigemptyset(&act.sa_mask); + act.sa_flags = 0; + + ok &= sigaction(SIGFPE, &act, &s_handlerFPE) == 0; + ok &= sigaction(SIGILL, &act, &s_handlerILL) == 0; + ok &= sigaction(SIGBUS, &act, &s_handlerBUS) == 0; + ok &= sigaction(SIGSEGV, &act, &s_handlerSEGV) == 0; + if ( !ok ) + { + wxLogDebug(wxT("Failed to install our signal handler.")); + } + + s_savedHandlers = true; + } + else if ( s_savedHandlers ) + { + // uninstall the signal handler + ok &= sigaction(SIGFPE, &s_handlerFPE, NULL) == 0; + ok &= sigaction(SIGILL, &s_handlerILL, NULL) == 0; + ok &= sigaction(SIGBUS, &s_handlerBUS, NULL) == 0; + ok &= sigaction(SIGSEGV, &s_handlerSEGV, NULL) == 0; + if ( !ok ) + { + wxLogDebug(wxT("Failed to uninstall our signal handler.")); + } + + s_savedHandlers = false; + } + //else: nothing to do + + return ok; +} + +#endif // wxUSE_ON_FATAL_EXCEPTION + +// ---------------------------------------------------------------------------- +// wxExecute support +// ---------------------------------------------------------------------------- + +int wxAppTraits::WaitForChild(wxExecuteData& execData) +{ +#if wxUSE_CONSOLE_EVENTLOOP + wxConsoleEventLoop loop; + return RunLoopUntilChildExit(execData, loop); +#else // !wxUSE_CONSOLE_EVENTLOOP + wxFAIL_MSG( wxS("Can't wait for child process without wxConsoleEventLoop") ); + + return -1; +#endif // wxUSE_CONSOLE_EVENTLOOP/!wxUSE_CONSOLE_EVENTLOOP +} + +// This function is common code for both console and GUI applications and used +// by wxExecute() to wait for the child exit while dispatching events. +// +// Notice that it should not be used for all the other cases, e.g. when we +// don't need to wait for the child (wxEXEC_ASYNC) or when the events must not +// dispatched (wxEXEC_NOEVENTS). +int +wxAppTraits::RunLoopUntilChildExit(wxExecuteData& execData, + wxEventLoopBase& loop) +{ + // It is possible that wxExecuteData::OnExit() had already been called + // and reset the PID to 0, in which case we don't need to do anything + // at all. + if ( !execData.pid ) + return execData.exitcode; + +#if wxUSE_STREAMS + // Monitor the child streams if necessary. + wxScopedPtr + stdoutHandler, + stderrHandler; + if ( execData.IsRedirected() ) + { + stdoutHandler.reset(new wxExecuteEventLoopSourceHandler + ( + execData.fdOut, execData.bufOut + )); + stderrHandler.reset(new wxExecuteEventLoopSourceHandler + ( + execData.fdErr, execData.bufErr + )); + } +#endif // wxUSE_STREAMS + + // Store the event loop in the data associated with the child + // process so that it could exit the loop when the child exits. + execData.syncEventLoop = &loop; + + // And run it. + loop.Run(); + + // The exit code will have been set when the child termination was detected. + return execData.exitcode; +} + +// ---------------------------------------------------------------------------- +// wxExecuteData +// ---------------------------------------------------------------------------- + +namespace +{ + +// Helper function that checks whether the child with the given PID has exited +// and fills the provided parameter with its return code if it did. +bool CheckForChildExit(int pid, int* exitcodeOut) +{ + wxASSERT_MSG( pid > 0, "invalid PID" ); + + int status, rc; + + // loop while we're getting EINTR + for ( ;; ) + { + rc = waitpid(pid, &status, WNOHANG); + + if ( rc != -1 || errno != EINTR ) + break; + } + + switch ( rc ) + { + case 0: + // No error but the child is still running. + return false; + + case -1: + // Checking child status failed. Invalid PID? + wxLogLastError(wxString::Format("waitpid(%d)", pid)); + return false; + + default: + // Child did terminate. + wxASSERT_MSG( rc == pid, "unexpected waitpid() return value" ); + + // notice that the caller expects the exit code to be signed, e.g. -1 + // instead of 255 so don't assign WEXITSTATUS() to an int + signed char exitcode; + if ( WIFEXITED(status) ) + exitcode = WEXITSTATUS(status); + else if ( WIFSIGNALED(status) ) + exitcode = -WTERMSIG(status); + else + { + wxLogError("Child process (PID %d) exited for unknown reason, " + "status = %d", pid, status); + exitcode = -1; + } + + if ( exitcodeOut ) + *exitcodeOut = exitcode; + + return true; + } +} + +} // anonymous namespace + +wxExecuteData::ChildProcessesData wxExecuteData::ms_childProcesses; + +/* static */ +void wxExecuteData::OnSomeChildExited(int WXUNUSED(sig)) +{ + // We know that some child process has terminated, but we don't know which + // one, so check all of them (notice that more than one could have exited). + // + // An alternative approach would be to call waitpid(-1, &status, WNOHANG) + // (in a loop to take care of the multiple children exiting case) and + // perhaps this would be more efficient. But for now this seems to work. + + + // Make a copy of the list before iterating over it to avoid problems due + // to deleting entries from it in the process. + const ChildProcessesData allChildProcesses = ms_childProcesses; + for ( ChildProcessesData::const_iterator it = allChildProcesses.begin(); + it != allChildProcesses.end(); + ++it ) + { + const int pid = it->first; + + // Check whether this child exited. + int exitcode; + if ( !CheckForChildExit(pid, &exitcode) ) + continue; + + // And handle its termination if it did. + // + // Notice that this will implicitly remove it from ms_childProcesses. + it->second->OnExit(exitcode); + } +} + +void wxExecuteData::OnStart(int pid_) +{ + wxCHECK_RET( wxTheApp, + wxS("Ensure wxTheApp is set before calling wxExecute()") ); + + // Setup the signal handler for SIGCHLD to be able to detect the child + // termination. + // + // Notice that SetSignalHandler() is idempotent, so it's fine to call + // it more than once with the same handler. + wxTheApp->SetSignalHandler(SIGCHLD, OnSomeChildExited); + + + // Remember the child PID to be able to wait for it later. + pid = pid_; + + // Also save it in wxProcess where it will be accessible to the user code. + if ( process ) + process->SetPid(pid); + + // Finally, add this object itself to the list of child processes so that + // we can check for its termination the next time we get SIGCHLD. + ms_childProcesses[pid] = this; +} + +void wxExecuteData::OnExit(int exitcode_) +{ + // Remove this process from the hash list of child processes that are + // still open as soon as possible to ensure we don't process it again even + // if another SIGCHLD happens. + if ( !ms_childProcesses.erase(pid) ) + { + wxFAIL_MSG(wxString::Format(wxS("Data for PID %d not in the list?"), pid)); + } + + + exitcode = exitcode_; + +#if wxUSE_STREAMS + if ( IsRedirected() ) + { + // Read the remaining data in a blocking way: this is fine because the + // child has already exited and hence all the data must be already + // available in the streams buffers. + bufOut.ReadAll(); + bufErr.ReadAll(); + } +#endif // wxUSE_STREAMS + + // Notify user about termination if required + if ( !(flags & wxEXEC_SYNC) ) + { + if ( process ) + process->OnTerminate(pid, exitcode); + + // in case of asynchronous execution we don't need this object any more + // after the child terminates + delete this; + } + else // sync execution + { + // let wxExecute() know that the process has terminated + pid = 0; + + // Stop the event loop for synchronous wxExecute() if we're running one. + if ( syncEventLoop ) + syncEventLoop->ScheduleExit(); + } +} diff --git a/3rdparty/wxwidgets3.0/src/unix/wakeuppipe.cpp b/3rdparty/wxwidgets3.0/src/unix/wakeuppipe.cpp new file mode 100755 index 0000000000000..1bd33d60210ab --- /dev/null +++ b/3rdparty/wxwidgets3.0/src/unix/wakeuppipe.cpp @@ -0,0 +1,128 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: src/unix/wakeuppipe.cpp +// Purpose: Implementation of wxWakeUpPipe class. +// Author: Vadim Zeitlin +// Created: 2013-06-09 (extracted from src/unix/evtloopunix.cpp) +// Copyright: (c) 2013 Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// for compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#ifndef WX_PRECOMP +#endif // WX_PRECOMP + +#include "wx/unix/private/wakeuppipe.h" + +#include + +// ---------------------------------------------------------------------------- +// constants +// ---------------------------------------------------------------------------- + +#define TRACE_EVENTS wxT("events") + +// ============================================================================ +// wxWakeUpPipe implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// initialization +// ---------------------------------------------------------------------------- + +wxWakeUpPipe::wxWakeUpPipe() +{ + m_pipeIsEmpty = true; + + if ( !m_pipe.Create() ) + { + wxLogError(_("Failed to create wake up pipe used by event loop.")); + return; + } + + + if ( !m_pipe.MakeNonBlocking(wxPipe::Read) ) + { + wxLogSysError(_("Failed to switch wake up pipe to non-blocking mode")); + return; + } + + wxLogTrace(TRACE_EVENTS, wxT("Wake up pipe (%d, %d) created"), + m_pipe[wxPipe::Read], m_pipe[wxPipe::Write]); +} + +// ---------------------------------------------------------------------------- +// wakeup handling +// ---------------------------------------------------------------------------- + +void wxWakeUpPipe::WakeUpNoLock() +{ + // No need to do anything if the pipe already contains something. + if ( !m_pipeIsEmpty ) + return; + + if ( write(m_pipe[wxPipe::Write], "s", 1) != 1 ) + { + // don't use wxLog here, we can be in another thread and this could + // result in dead locks + perror("write(wake up pipe)"); + } + else + { + // We just wrote to it, so it's not empty any more. + m_pipeIsEmpty = false; + } +} + +void wxWakeUpPipe::OnReadWaiting() +{ + // got wakeup from child thread, remove the data that provoked it from the + // pipe + + char buf[4]; + for ( ;; ) + { + const int size = read(GetReadFd(), buf, WXSIZEOF(buf)); + + if ( size > 0 ) + { + wxASSERT_MSG( size == 1, "Too many writes to wake-up pipe?" ); + + break; + } + + if ( size == 0 || (size == -1 && errno == EAGAIN) ) + { + // No data available, not an error (but still surprising, + // spurious wakeup?) + break; + } + + if ( errno == EINTR ) + { + // We were interrupted, try again. + continue; + } + + wxLogSysError(_("Failed to read from wake-up pipe")); + + return; + } + + // The pipe is empty now, so future calls to WakeUp() would need to write + // to it again. + m_pipeIsEmpty = true; +} diff --git a/3rdparty/xz/CMakeLists.txt b/3rdparty/xz/CMakeLists.txt new file mode 100644 index 0000000000000..ba8332298d3bb --- /dev/null +++ b/3rdparty/xz/CMakeLists.txt @@ -0,0 +1,156 @@ +add_library(lzma + xz/src/common/tuklib_cpucores.c + xz/src/common/tuklib_physmem.c + xz/src/liblzma/check/check.c + xz/src/liblzma/check/crc32_fast.c + xz/src/liblzma/check/crc32_table.c + xz/src/liblzma/check/crc64_fast.c + xz/src/liblzma/check/crc64_table.c + xz/src/liblzma/check/sha256.c + xz/src/liblzma/common/alone_decoder.c + xz/src/liblzma/common/alone_encoder.c + xz/src/liblzma/common/auto_decoder.c + xz/src/liblzma/common/block_buffer_decoder.c + xz/src/liblzma/common/block_buffer_encoder.c + xz/src/liblzma/common/block_decoder.c + xz/src/liblzma/common/block_encoder.c + xz/src/liblzma/common/block_header_decoder.c + xz/src/liblzma/common/block_header_encoder.c + xz/src/liblzma/common/block_util.c + xz/src/liblzma/common/common.c + xz/src/liblzma/common/easy_buffer_encoder.c + xz/src/liblzma/common/easy_decoder_memusage.c + xz/src/liblzma/common/easy_encoder.c + xz/src/liblzma/common/easy_encoder_memusage.c + xz/src/liblzma/common/easy_preset.c + xz/src/liblzma/common/filter_buffer_decoder.c + xz/src/liblzma/common/filter_buffer_encoder.c + xz/src/liblzma/common/filter_common.c + xz/src/liblzma/common/filter_decoder.c + xz/src/liblzma/common/filter_encoder.c + xz/src/liblzma/common/filter_flags_decoder.c + xz/src/liblzma/common/filter_flags_encoder.c + xz/src/liblzma/common/hardware_cputhreads.c + xz/src/liblzma/common/hardware_physmem.c + xz/src/liblzma/common/index.c + xz/src/liblzma/common/index_decoder.c + xz/src/liblzma/common/index_encoder.c + xz/src/liblzma/common/index_hash.c + xz/src/liblzma/common/outqueue.c + xz/src/liblzma/common/stream_buffer_decoder.c + xz/src/liblzma/common/stream_buffer_encoder.c + xz/src/liblzma/common/stream_decoder.c + xz/src/liblzma/common/stream_encoder.c + xz/src/liblzma/common/stream_encoder_mt.c + xz/src/liblzma/common/stream_flags_common.c + xz/src/liblzma/common/stream_flags_decoder.c + xz/src/liblzma/common/stream_flags_encoder.c + xz/src/liblzma/common/vli_decoder.c + xz/src/liblzma/common/vli_encoder.c + xz/src/liblzma/common/vli_size.c + xz/src/liblzma/delta/delta_common.c + xz/src/liblzma/delta/delta_decoder.c + xz/src/liblzma/delta/delta_encoder.c + xz/src/liblzma/lzma/fastpos_table.c + xz/src/liblzma/lzma/lzma2_decoder.c + xz/src/liblzma/lzma/lzma2_encoder.c + xz/src/liblzma/lzma/lzma_decoder.c + xz/src/liblzma/lzma/lzma_encoder.c + xz/src/liblzma/lzma/lzma_encoder_optimum_fast.c + xz/src/liblzma/lzma/lzma_encoder_optimum_normal.c + xz/src/liblzma/lzma/lzma_encoder_presets.c + xz/src/liblzma/lz/lz_decoder.c + xz/src/liblzma/lz/lz_encoder.c + xz/src/liblzma/lz/lz_encoder_mf.c + xz/src/liblzma/rangecoder/price_table.c + xz/src/liblzma/simple/arm.c + xz/src/liblzma/simple/armthumb.c + xz/src/liblzma/simple/ia64.c + xz/src/liblzma/simple/powerpc.c + xz/src/liblzma/simple/simple_coder.c + xz/src/liblzma/simple/simple_decoder.c + xz/src/liblzma/simple/simple_encoder.c + xz/src/liblzma/simple/sparc.c + xz/src/liblzma/simple/x86.c + + xz/src/common/mythread.h + xz/src/common/sysdefs.h + xz/src/common/tuklib_common.h + xz/src/common/tuklib_config.h + xz/src/common/tuklib_cpucores.h + xz/src/common/tuklib_integer.h + xz/src/common/tuklib_physmem.h + xz/src/liblzma/api/lzma.h + xz/src/liblzma/api/lzma/base.h + xz/src/liblzma/api/lzma/bcj.h + xz/src/liblzma/api/lzma/block.h + xz/src/liblzma/api/lzma/check.h + xz/src/liblzma/api/lzma/container.h + xz/src/liblzma/api/lzma/delta.h + xz/src/liblzma/api/lzma/filter.h + xz/src/liblzma/api/lzma/hardware.h + xz/src/liblzma/api/lzma/index.h + xz/src/liblzma/api/lzma/index_hash.h + xz/src/liblzma/api/lzma/lzma12.h + xz/src/liblzma/api/lzma/stream_flags.h + xz/src/liblzma/api/lzma/version.h + xz/src/liblzma/api/lzma/vli.h + xz/src/liblzma/check/check.h + xz/src/liblzma/check/crc32_table_be.h + xz/src/liblzma/check/crc32_table_le.h + xz/src/liblzma/check/crc64_table_be.h + xz/src/liblzma/check/crc64_table_le.h + xz/src/liblzma/check/crc_macros.h + xz/src/liblzma/common/alone_decoder.h + xz/src/liblzma/common/block_buffer_encoder.h + xz/src/liblzma/common/block_decoder.h + xz/src/liblzma/common/block_encoder.h + xz/src/liblzma/common/common.h + xz/src/liblzma/common/easy_preset.h + xz/src/liblzma/common/filter_common.h + xz/src/liblzma/common/filter_decoder.h + xz/src/liblzma/common/filter_encoder.h + xz/src/liblzma/common/index.h + xz/src/liblzma/common/index_encoder.h + xz/src/liblzma/common/memcmplen.h + xz/src/liblzma/common/outqueue.h + xz/src/liblzma/common/stream_decoder.h + xz/src/liblzma/common/stream_flags_common.h + xz/src/liblzma/delta/delta_common.h + xz/src/liblzma/delta/delta_decoder.h + xz/src/liblzma/delta/delta_encoder.h + xz/src/liblzma/delta/delta_private.h + xz/src/liblzma/lzma/fastpos.h + xz/src/liblzma/lzma/lzma2_decoder.h + xz/src/liblzma/lzma/lzma2_encoder.h + xz/src/liblzma/lzma/lzma_common.h + xz/src/liblzma/lzma/lzma_decoder.h + xz/src/liblzma/lzma/lzma_encoder.h + xz/src/liblzma/lzma/lzma_encoder_private.h + xz/src/liblzma/lz/lz_decoder.h + xz/src/liblzma/lz/lz_encoder.h + xz/src/liblzma/lz/lz_encoder_hash.h + xz/src/liblzma/lz/lz_encoder_hash_table.h + xz/src/liblzma/rangecoder/price.h + xz/src/liblzma/rangecoder/range_common.h + xz/src/liblzma/rangecoder/range_decoder.h + xz/src/liblzma/rangecoder/range_encoder.h + xz/src/liblzma/simple/simple_coder.h + xz/src/liblzma/simple/simple_decoder.h + xz/src/liblzma/simple/simple_encoder.h + xz/src/liblzma/simple/simple_private.h + config.h +) +target_include_directories(lzma PRIVATE + . + xz/src/liblzma/common + xz/src/common + xz/src/liblzma/api + xz/src/liblzma/check + xz/src/liblzma/delta + xz/src/liblzma/lz + xz/src/liblzma/lzma + xz/src/liblzma/rangecoder + xz/src/liblzma/simple) + +target_compile_definitions(lzma PRIVATE -DHAVE_CONFIG_H) diff --git a/3rdparty/zlib/CMakeLists.txt b/3rdparty/zlib/CMakeLists.txt new file mode 100644 index 0000000000000..a2b61c5f06118 --- /dev/null +++ b/3rdparty/zlib/CMakeLists.txt @@ -0,0 +1,34 @@ +add_library(z + adler32.c + compress.c + crc32.c + deflate.c + gzclose.c + gzlib.c + gzread.c + gzwrite.c + infback.c + inffast.c + inflate.c + inftrees.c + trees.c + uncompr.c + zutil.c + + + crc32.h + deflate.h + inffast.h + inffixed.h + inflate.h + inftrees.h + trees.h + zconf.h + zlib.h + zutil.h +) + +target_compile_definitions(z PRIVATE -D_CRT_SECURE_NO_WARNINGS -D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_WARNINGS) +if(WIN32) + target_compile_definitions(z PRIVATE -D__WIN32__ -DWIN32 -D_WINDOWS -DWINAPI_FAMILY=WINAPI_FAMILY_DESKTOP_APP) +endif() diff --git a/CMakeLists.txt b/CMakeLists.txt index c9671d71cb5b8..23e84f7bc5e5a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,3 +1,5 @@ +cmake_policy(SET CMP0048 NEW) + # Project Name project(Pcsx2) @@ -21,6 +23,13 @@ include(Pcsx2Utils) check_no_parenthesis_in_path() detectOperatingSystem() check_compiler_version("7.0" "7.0") +if(NOT MSVC) + find_program(CCACHE_FOUND ccache) + if(CCACHE_FOUND) + set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ${CCACHE_FOUND}) + set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ${CCACHE_FOUND}) + endif() +endif() #------------------------------------------------------------------------------- # Include specific module @@ -41,6 +50,10 @@ if(EXISTS "${CMAKE_SOURCE_DIR}/locales") endif() endif() +if(LIBRETRO) + add_subdirectory(3rdparty/wxwidgets3.0) +endif() + # make common if(common_libs) add_subdirectory(common/src/Utilities) diff --git a/cmake/BuildParameters.cmake b/cmake/BuildParameters.cmake index 195315e12ea74..3c59dacebefb1 100644 --- a/cmake/BuildParameters.cmake +++ b/cmake/BuildParameters.cmake @@ -22,8 +22,16 @@ #------------------------------------------------------------------------------- option(DISABLE_BUILD_DATE "Disable including the binary compile date") option(ENABLE_TESTS "Enables building the unit tests" ON) +option(LIBRETRO "Enables building the libretro core" OFF) -if(DISABLE_BUILD_DATE OR openSUSE) +if(LIBRETRO) + set(ENABLE_TESTS OFF) + set(CMAKE_BUILD_PO FALSE) + set(BUILD_REPLAY_LOADERS FALSE) + add_definitions(-D__LIBRETRO__ -DDISABLE_RECORDING -DwxUSE_GUI=0) +endif() + +if(DISABLE_BUILD_DATE OR openSUSE OR CCACHE_FOUND) message(STATUS "Disabling the inclusion of the binary compile date.") add_definitions(-DDISABLE_BUILD_DATE) endif() @@ -92,6 +100,9 @@ elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Intel") elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") set(USE_GCC TRUE) message(STATUS "Building with GNU GCC") +elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") + set(USE_MSVC TRUE) + message(STATUS "Building with Microsoft's CL") else() message(FATAL_ERROR "Unknown compiler: ${CMAKE_CXX_COMPILER_ID}") endif() @@ -101,11 +112,13 @@ endif() #------------------------------------------------------------------------------- option(BUILTIN_GS "Disable support of GS plugin (developer option)") option(BUILTIN_PAD "Disable support of PAD plugin (developer option)") -option(BUILTIN_SPU2 "Disable support of SPU2 plugin (developer option)") option(BUILTIN_USB "Disable support of USB plugin (developer option)") -option(BUILTIN_FW "Disable support of FW plugin (developer option)") option(BUILTIN_DEV9 "Disable support of DEV9 plugin (developer option)") -option(BUILTIN_CDVD "Disable support of CDVD plugin (developer option)") + +set(BUILTIN_GS TRUE) +set(BUILTIN_PAD TRUE) +set(BUILTIN_USB TRUE) +set(BUILTIN_DEV9 TRUE) set(PLUGIN_SUPPORT "") if(BUILTIN_GS) @@ -114,20 +127,11 @@ endif() if(BUILTIN_PAD) set(PLUGIN_SUPPORT "${PLUGIN_SUPPORT} -DBUILTIN_PAD_PLUGIN") endif() -if(BUILTIN_SPU2) - set(PLUGIN_SUPPORT "${PLUGIN_SUPPORT} -DBUILTIN_SPU2_PLUGIN") -endif() if(BUILTIN_USB) set(PLUGIN_SUPPORT "${PLUGIN_SUPPORT} -DBUILTIN_USB_PLUGIN") endif() -if(BUILTIN_FW) - set(PLUGIN_SUPPORT "${PLUGIN_SUPPORT} -DBUILTIN_FW_PLUGIN") -endif() -if(BUILTIN_DEV) - set(PLUGIN_SUPPORT "${PLUGIN_SUPPORT} -DBUILTIN_DEV_PLUGIN") -endif() -if(BUILTIN_CDVD) - set(PLUGIN_SUPPORT "${PLUGIN_SUPPORT} -DBUILTIN_CDVD_PLUGIN") +if(BUILTIN_DEV9) + set(PLUGIN_SUPPORT "${PLUGIN_SUPPORT} -DBUILTIN_DEV9_PLUGIN") endif() #------------------------------------------------------------------------------- @@ -233,6 +237,32 @@ else() message(FATAL_ERROR "Unsupported architecture: ${PCSX2_TARGET_ARCHITECTURES}") endif() +if(MSVC) + set(ARCH_FLAG) + # add_compile_options(/permissive-) + # add_compile_options(/Zc:inline) + # add_compile_options(/Zc:throwingNew) + # add_compile_options(/volatile:iso) + #string(APPEND CMAKE_EXE_LINKER_FLAGS " /NXCOMPAT") +# add_compile_options(/EHsc) + add_compile_options(/EHa) + add_compile_options(/MP) + if(CMAKE_BUILD_TYPE MATCHES "Release") + add_definitions(-DNDEBUG) + else() + if(CMAKE_BUILD_TYPE MATCHES "Debug") + add_definitions(-D_DEBUG -DPCSX2_DEVBUILD -DPCSX2_DEBUG) + else() + add_definitions(-DNDEBUG -DPCSX2_DEVBUILD -D_DEVEL) + endif() + add_compile_options(/Zi) + add_link_options(/DEBUG) + endif() + add_definitions(-D__WIN32__ -DWIN32 -D_WINDOWS -D_CRT_SECURE_NO_WARNINGS -D_CRT_SECURE_NO_DEPRECATE) + add_definitions(${PLUGIN_SUPPORT}) + add_definitions(-D_ARCH_64=1 -D_M_X86_64 -D__M_X86_64) + add_definitions(/wd4063 /wd4100 /wd4267 /wd4244 /wd4244 /wd4312 /wd4334) +else(MSVC) #------------------------------------------------------------------------------- # Control GCC flags #------------------------------------------------------------------------------- @@ -287,8 +317,7 @@ if(USE_VTUNE) endif() # Remove FORTIFY_SOURCE when compiling as debug, because it spams a lot of warnings on clang due to no optimization. -# Should probably be checked on gcc as well, as the USE_CLANG might not be needed. -if (USE_CLANG AND CMAKE_BUILD_TYPE MATCHES "Debug") +if (CMAKE_BUILD_TYPE MATCHES "Debug") set(HARDENING_FLAG "-Wformat -Wformat-security") else() set(HARDENING_FLAG "-D_FORTIFY_SOURCE=2 -Wformat -Wformat-security") @@ -345,7 +374,7 @@ endif() if(USE_PGO_OPTIMIZE) set(PGO_FLAGS "${PGO_FLAGS} -fprofile-use") endif() - +endif(MSVC) if(CMAKE_BUILD_TYPE MATCHES "Debug") set(DEBUG_FLAG "${DBG} -DPCSX2_DEVBUILD -DPCSX2_DEBUG -D_DEBUG") elseif(CMAKE_BUILD_TYPE MATCHES "Devel") @@ -365,11 +394,11 @@ endif() if(NOT DEFINED OPTIMIZATION_FLAG) if (CMAKE_BUILD_TYPE STREQUAL Debug) - if (USE_GCC) - set(OPTIMIZATION_FLAG -Og) - else() +# if (USE_GCC) +# set(OPTIMIZATION_FLAG -Og) +# else() set(OPTIMIZATION_FLAG -O0) - endif() +# endif() else() set(OPTIMIZATION_FLAG -O2) endif() @@ -391,8 +420,9 @@ endif() # Note: -DGTK_DISABLE_DEPRECATED can be used to test a build without gtk deprecated feature. It could be useful to port to a newer API set(DEFAULT_GCC_FLAG "${ARCH_FLAG} ${COMMON_FLAG} ${DEFAULT_WARNINGS} ${AGGRESSIVE_WARNING} ${HARDENING_FLAG} ${DEBUG_FLAG} ${ASAN_FLAG} ${OPTIMIZATION_FLAG} ${LTO_FLAGS} ${PGO_FLAGS} ${PLUGIN_SUPPORT}") # c++ only flags +if(NOT MSVC) set(DEFAULT_CPP_FLAG "${DEFAULT_GCC_FLAG} -Wno-invalid-offsetof") - +endif() #------------------------------------------------------------------------------- # Allow user to set some default flags # Note: string STRIP must be used to remove trailing and leading spaces. @@ -471,4 +501,4 @@ if(CMAKE_SYSTEM_NAME MATCHES "Darwin") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-dead_strip,-dead_strip_dylibs") set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,-dead_strip,-dead_strip_dylibs") -endif() \ No newline at end of file +endif() diff --git a/cmake/SearchForStuff.cmake b/cmake/SearchForStuff.cmake index 7a3871535f8fa..2e339d907f1bb 100644 --- a/cmake/SearchForStuff.cmake +++ b/cmake/SearchForStuff.cmake @@ -7,7 +7,11 @@ if (Linux) find_package(PCAP) find_package(LibXml2) endif() -find_package(Freetype) # GSdx OSD +if (LIBRETRO) + set(FREETYPE_LIBRARIES) +else() + find_package(Freetype) # GSdx OSD +endif() find_package(Gettext) # translation tool if(EXISTS ${PROJECT_SOURCE_DIR}/.git) find_package(Git) @@ -20,6 +24,10 @@ set(OpenGL_GL_PREFERENCE GLVND) find_package(OpenGL) find_package(PNG) find_package(Vtune) +if(LIBRETRO) + set(wxWidgets_FOUND 1) + set(wxWidgets_USE_FILE 3rdparty/wxwidgets3.0/UsewxWidgets.cmake) +else(LIBRETRO) # The requirement of wxWidgets is checked in SelectPcsx2Plugins module # Does not require the module (allow to compile non-wx plugins) # Force the unicode build (the variable is only supported on cmake 2.8.3 and above) @@ -72,10 +80,13 @@ else() endif() find_package(wxWidgets COMPONENTS base core adv) +endif(LIBRETRO) find_package(ZLIB) ## Use pcsx2 package to find module -include(FindLibc) +if (NOT MSVC) + include(FindLibc) +endif() ## Only needed by the extra plugins if(EXTRA_PLUGINS) @@ -100,6 +111,7 @@ if(Linux) check_lib(LIBUDEV libudev libudev.h) endif() endif() +if(NOT LIBRETRO) if(PORTAUDIO_API) check_lib(PORTAUDIO portaudio portaudio.h pa_linux_alsa.h) endif() @@ -112,8 +124,18 @@ else() set(SDL_BUILDING_LIBRARY TRUE) find_package(SDL) endif() +endif(NOT LIBRETRO) if(UNIX) + if(LIBRETRO) + pkg_check_modules(PC_GLIB QUIET glib-2.0) + find_library(GLIB_LIBRARIES NAMES glib-2.0 HINTS ${PC_GLIB_LIBRARY_DIRS}) + get_filename_component(_GLIB_LIBRARY_DIR ${GLIB_LIBRARIES} PATH) + find_path(GLIBCONFIG_INCLUDE_DIR NAMES glibconfig.h HINTS ${PC_LIBRARY_DIRS} ${_GLIB_LIBRARY_DIR} PATH_SUFFIXES glib-2.0/include) + find_path(GLIB_INCLUDE_DIR NAMES glib.h HINTS ${PC_GLIB_INCLUDE_DIRS} PATH_SUFFIXES glib-2.0) + set(GLIB_INCLUDE_DIRS ${GLIB_INCLUDE_DIR} ${GLIBCONFIG_INCLUDE_DIR}) + find_library(GLIB_GIO_LIBRARIES NAMES gio-2.0 HINTS ${_GLIB_LIBRARY_DIR}) + else(LIBRETRO) find_package(X11) # Most plugins (if not all) and PCSX2 core need gtk2, so set the required flags if (GTK3_API) @@ -125,6 +147,7 @@ if(UNIX) else() find_package(GTK2 REQUIRED gtk) endif() + endif(LIBRETRO) endif() #---------------------------------------- @@ -186,14 +209,38 @@ endif() if(ZLIB_FOUND) include_directories(${ZLIB_INCLUDE_DIRS}) +else() + set(ZLIB_FOUND TRUE) + set(ZLIB_LIBRARIES z) + add_subdirectory(${CMAKE_SOURCE_DIR}/3rdparty/zlib) + include_directories(${CMAKE_SOURCE_DIR}/3rdparty) + include_directories(${CMAKE_SOURCE_DIR}/3rdparty/zlib) endif() -find_package(HarfBuzz) +if (NOT LIBRETRO) + find_package(HarfBuzz) +endif() if(HarfBuzz_FOUND) include_directories(${HarfBuzz_INCLUDE_DIRS}) endif() +if(NOT LIBLZMA_FOUND) + set(LIBLZMA_FOUND 1) + add_definitions(-DLZMA_API_STATIC) + set(LIBLZMA_LIBRARIES lzma) + add_subdirectory(${CMAKE_SOURCE_DIR}/3rdparty/xz) +endif() + +if(MSVC) + add_definitions(-DPTW32_STATIC_LIB) +# add_definitions(-D__CLEANUP_SEH) + add_subdirectory(${CMAKE_SOURCE_DIR}/3rdparty/pthreads4w) + include_directories(${CMAKE_SOURCE_DIR}/3rdparty/pthreads4w/include) + add_subdirectory(${CMAKE_SOURCE_DIR}/3rdparty/baseclasses) +# include_directories(${CMAKE_SOURCE_DIR}/3rdparty/baseclasses) +endif() + set(ACTUALLY_ENABLE_TESTS ${ENABLE_TESTS}) if(ENABLE_TESTS) if(NOT EXISTS "${CMAKE_SOURCE_DIR}/3rdparty/gtest/CMakeLists.txt") diff --git a/cmake/SelectPcsx2Plugins.cmake b/cmake/SelectPcsx2Plugins.cmake index 4d826cedf3169..68285afe512f8 100644 --- a/cmake/SelectPcsx2Plugins.cmake +++ b/cmake/SelectPcsx2Plugins.cmake @@ -67,7 +67,7 @@ else() print_dep("Skip build of pcsx2 core: missing dependencies" "${msg_dep_pcsx2}") endif() # Linux, BSD, use gtk2, but not OSX -if(UNIX AND pcsx2_core AND NOT GTKn_FOUND AND NOT APPLE) +if(UNIX AND pcsx2_core AND NOT GTKn_FOUND AND NOT APPLE AND NOT LIBRETRO) set(pcsx2_core FALSE) print_dep("Skip build of pcsx2 core: missing dependencies" "${msg_dep_pcsx2}") endif() @@ -85,14 +85,14 @@ endif() #--------------------------------------- # dev9null #--------------------------------------- -if(GTKn_FOUND) +if(GTKn_FOUND OR LIBRETRO) set(dev9null TRUE) endif() #--------------------------------------- # dev9ghzdrk #--------------------------------------- -if(NOT DISABLE_DEV9GHZDRK) +if(NOT DISABLE_DEV9GHZDRK AND NOT LIBRETRO) if(GTKn_FOUND AND PCAP_FOUND AND LIBXML2_FOUND) set(dev9ghzdrk TRUE) list(APPEND CMAKE_MODULE_PATH @@ -121,7 +121,7 @@ endif() # -X11 # -zlib #--------------------------------------- -if(OPENGL_FOUND AND X11_FOUND AND GTKn_FOUND AND ZLIB_FOUND AND PNG_FOUND AND FREETYPE_FOUND AND LIBLZMA_FOUND AND EGL_FOUND AND X11_XCB_FOUND) +if(LIBRETRO OR (OPENGL_FOUND AND X11_FOUND AND GTKn_FOUND AND ZLIB_FOUND AND PNG_FOUND AND FREETYPE_FOUND AND LIBLZMA_FOUND AND EGL_FOUND AND X11_XCB_FOUND)) set(GSdx TRUE) elseif(NOT EXISTS "${CMAKE_SOURCE_DIR}/plugins/GSdx") set(GSdx FALSE) @@ -157,7 +157,7 @@ endif() # requires: -SDL2 # -X11 #--------------------------------------- -if(wxWidgets_FOUND AND GTKn_FOUND AND SDL2_FOUND AND X11_FOUND) +if(LIBRETRO OR (wxWidgets_FOUND AND GTKn_FOUND AND SDL2_FOUND AND X11_FOUND)) set(onepad TRUE) elseif(NOT EXISTS "${CMAKE_SOURCE_DIR}/plugins/onepad") set(onepad FALSE) @@ -168,9 +168,9 @@ endif() # old version of the plugin that still supports SDL1 # Was never ported to macOS -if(wxWidgets_FOUND AND GTKn_FOUND AND SDLn_FOUND AND X11_FOUND AND NOT APPLE) +if(wxWidgets_FOUND AND GTKn_FOUND AND SDLn_FOUND AND X11_FOUND AND NOT APPLE AND NOT LIBRETRO) set(onepad_legacy TRUE) -elseif(NOT EXISTS "${CMAKE_SOURCE_DIR}/plugins/onepad_legacy" OR APPLE) +elseif(NOT EXISTS "${CMAKE_SOURCE_DIR}/plugins/onepad_legacy" OR APPLE OR LIBRETRO) set(onepad_legacy FALSE) else() set(onepad_legacy FALSE) @@ -181,7 +181,7 @@ endif() #--------------------------------------- # USBnull #--------------------------------------- -if(GTKn_FOUND) +if(GTKn_FOUND OR LIBRETRO) set(USBnull TRUE) endif() #--------------------------------------- diff --git a/common/include/PS2Edefs.h b/common/include/PS2Edefs.h index 9c5b4093e2d03..067773ec93bf3 100644 --- a/common/include/PS2Edefs.h +++ b/common/include/PS2Edefs.h @@ -148,8 +148,12 @@ extern "C" { // basic funcs +void CALLBACK GSosdLog(const char *utf8, u32 color); +void CALLBACK GSosdMonitor(const char *key, const char *value, u32 color); + s32 CALLBACK GSinit(); s32 CALLBACK GSopen(void *pDsp, const char *Title, int multithread); +s32 CALLBACK GSopen2(void *pDsp, u32 flags); void CALLBACK GSclose(); void CALLBACK GSshutdown(); void CALLBACK GSsetSettingsDir(const char *dir); @@ -181,10 +185,13 @@ void CALLBACK GSsetGameCRC(int crc, int gameoptions); // controls frame skipping in the GS, if this routine isn't present, frame skipping won't be done void CALLBACK GSsetFrameSkip(int frameskip); +void CALLBACK GSsetVsync(int enabled); +void CALLBACK GSsetExclusive(int isExclusive); + // if start is 1, starts recording spu2 data, else stops // returns a non zero value if successful // for now, pData is not used -int CALLBACK GSsetupRecording(int start, void *pData); +void* CALLBACK GSsetupRecording(int start); void CALLBACK GSreset(); //deprecated: GSgetTitleInfo was used in PCSX2 but no plugin supported it prior to r4070: @@ -212,6 +219,8 @@ void CALLBACK PADclose(); void CALLBACK PADshutdown(); void CALLBACK PADsetSettingsDir(const char *dir); void CALLBACK PADsetLogDir(const char *dir); +s32 CALLBACK PADfreeze(int mode, freezeData *data); + // PADkeyEvent is called every vsync (return NULL if no event) keyEvent *CALLBACK PADkeyEvent(); @@ -239,6 +248,8 @@ void CALLBACK PADWriteEvent(keyEvent &evt); // extended funcs void CALLBACK PADgsDriverInfo(GSdriverInfo *info); +s32 CALLBACK PADsetSlot(u8 port, u8 slot); +s32 CALLBACK PADqueryMtap(u8 port); void CALLBACK PADconfigure(); void CALLBACK PADabout(); s32 CALLBACK PADtest(); @@ -261,6 +272,7 @@ void CALLBACK DEV9close(); void CALLBACK DEV9shutdown(); void CALLBACK DEV9setSettingsDir(const char *dir); void CALLBACK DEV9setLogDir(const char *dir); +void CALLBACK DEV9keyEvent(keyEvent *ev); u8 CALLBACK DEV9read8(u32 addr); u16 CALLBACK DEV9read16(u32 addr); @@ -275,6 +287,7 @@ void CALLBACK DEV9writeDMA8Mem(u32 *pMem, int size); // if callback returns 1 the irq is triggered, else not void CALLBACK DEV9irqCallback(DEV9callback callback); DEV9handler CALLBACK DEV9irqHandler(void); +void CALLBACK DEV9async(u32 cycles); // extended funcs @@ -299,6 +312,7 @@ void CALLBACK USBclose(); void CALLBACK USBshutdown(); void CALLBACK USBsetSettingsDir(const char *dir); void CALLBACK USBsetLogDir(const char *dir); +void CALLBACK USBkeyEvent(keyEvent *ev); u8 CALLBACK USBread8(u32 addr); u16 CALLBACK USBread16(u32 addr); diff --git a/common/include/PS2Eext.h b/common/include/PS2Eext.h index 2666fca96e709..eccdca246791a 100644 --- a/common/include/PS2Eext.h +++ b/common/include/PS2Eext.h @@ -27,14 +27,19 @@ #include #include #include +#undef Yield #define EXPORT_C_(type) extern "C" type CALLBACK #elif defined(__unix__) #include +#include +#if wxUSE_GUI #include - +#else +#include "Utilities/Console.h" +#endif #define EXPORT_C_(type) extern "C" __attribute__((stdcall, externally_visible, visibility("default"))) type #else @@ -211,12 +216,15 @@ static void SysMessage(const char *fmt, ...) va_start(list, fmt); vsprintf(msg, fmt, list); va_end(list); - if (msg[strlen(msg) - 1] == '\n') msg[strlen(msg) - 1] = 0; +#if wxUSE_GUI wxMessageDialog dialog(nullptr, msg, "Info", wxOK); dialog.ShowModal(); +#else + Console.WriteLn(msg); +#endif } #define ENTRY_POINT /* We don't need no stinkin' entry point! */ diff --git a/common/include/PluginCallbacks.h b/common/include/PluginCallbacks.h index 678aecb4f7306..d2d58cf7b023d 100644 --- a/common/include/PluginCallbacks.h +++ b/common/include/PluginCallbacks.h @@ -122,7 +122,7 @@ typedef int BOOL; // on its HWND define that could be useful, and well it's probably good practice to use // platform available defines when they exist. // -#if defined(_WX_DEFS_H_) +#if defined(_WX_DEFS_H_) && wxUSE_GUI typedef WXWidget PS2E_HWND; #elif defined(_WINDEF_) // For Windows let's use HWND, since it has some type strictness applied to it. diff --git a/common/include/Utilities/AppTrait.h b/common/include/Utilities/AppTrait.h index 3816a9258ae78..2a31e01e4d155 100644 --- a/common/include/Utilities/AppTrait.h +++ b/common/include/Utilities/AppTrait.h @@ -25,14 +25,21 @@ // does cache an instance of the traits, so the object construction need not be trivial // (translation: it can be complicated-ish -- it won't affect performance). // +#if wxUSE_GUI class Pcsx2AppTraits : public wxGUIAppTraits { typedef wxGUIAppTraits _parent; - +#else +class Pcsx2AppTraits : public wxConsoleAppTraits +{ + typedef wxConsoleAppTraits _parent; +#endif public: virtual ~Pcsx2AppTraits() {} wxMessageOutput *CreateMessageOutput(); - +#ifdef __LIBRETRO__ + wxEventLoopBase* CreateEventLoop(); +#endif #ifdef wxUSE_STDPATHS wxStandardPaths &GetStandardPaths(); #endif diff --git a/common/include/Utilities/CheckedStaticBox.h b/common/include/Utilities/CheckedStaticBox.h index 1ae9c453ad13e..a8f4af739864f 100644 --- a/common/include/Utilities/CheckedStaticBox.h +++ b/common/include/Utilities/CheckedStaticBox.h @@ -14,7 +14,7 @@ */ #pragma once - +#include "PrecompiledHeader.h" #include "wxGuiTools.h" class CheckedStaticBox : public wxPanelWithHelpers diff --git a/common/include/Utilities/PersistentThread.h b/common/include/Utilities/PersistentThread.h index cb2235bf8f348..3618d294a013b 100644 --- a/common/include/Utilities/PersistentThread.h +++ b/common/include/Utilities/PersistentThread.h @@ -19,6 +19,8 @@ #include "ScopedPtrMT.h" #include "EventSource.h" +#undef Yield + namespace Threading { diff --git a/common/include/Utilities/pxEvents.h b/common/include/Utilities/pxEvents.h index d383063260d9f..825471d352bc4 100644 --- a/common/include/Utilities/pxEvents.h +++ b/common/include/Utilities/pxEvents.h @@ -14,6 +14,35 @@ */ #pragma once +#include "wx/windowid.h" +#include "wx/event.h" + +#if !wxUSE_GUI +class WXDLLIMPEXP_CORE wxCommandEvent : public wxEvent, + public wxEventBasicPayloadMixin +{ +public: + wxCommandEvent(wxEventType commandType = wxEVT_NULL, int winid = 0) + : wxEvent(winid, commandType) + { + m_clientData = NULL; + m_isCommandEvent = true; + + // the command events are propagated upwards by default + m_propagationLevel = wxEVENT_PROPAGATE_MAX; + } + + // Set/Get client data from controls + void SetClientData(void* clientData) { m_clientData = clientData; } + void *GetClientData() const { return m_clientData; } + + virtual wxEvent *Clone() const { return new wxCommandEvent(*this); } + virtual wxEventCategory GetEventCategory() const { return wxEVT_CATEGORY_USER_INPUT; } + +protected: + void* m_clientData; // Arbitrary client data +}; +#endif wxDECLARE_EVENT(pxEvt_StartIdleEventTimer, wxCommandEvent); wxDECLARE_EVENT(pxEvt_DeleteObject, wxCommandEvent); diff --git a/common/include/Utilities/wxAppWithHelpers.h b/common/include/Utilities/wxAppWithHelpers.h index 0b38bb7490084..2b5337708c78a 100644 --- a/common/include/Utilities/wxAppWithHelpers.h +++ b/common/include/Utilities/wxAppWithHelpers.h @@ -42,7 +42,7 @@ extern ConsoleLogSource_App pxConLog_App; #define pxAppLog pxConLog_App.IsActive() && pxConLog_App - +#if wxUSE_GUI // -------------------------------------------------------------------------------------- // ModalButtonPanel // -------------------------------------------------------------------------------------- @@ -57,7 +57,7 @@ class ModalButtonPanel : public wxPanelWithHelpers virtual void OnActionButtonClicked(wxCommandEvent &evt); }; - +#endif typedef std::list wxEventList; // -------------------------------------------------------------------------------------- @@ -143,3 +143,5 @@ namespace Msgbox extern int ShowModal(BaseMessageBoxEvent &evt); extern int ShowModal(const wxString &title, const wxString &content, const MsgButtons &buttons); } + +extern wxString pxGetAppName(); diff --git a/common/include/api/GSApi.h b/common/include/api/GSApi.h index cc42d0698ed9f..0e76d39bc6108 100644 --- a/common/include/api/GSApi.h +++ b/common/include/api/GSApi.h @@ -91,7 +91,7 @@ GSsetFrameSkip(int frameskip); // if start is true, starts recording spu2 data, else stops // returns true if successful // for now, pData is not used -EXPORT_C_(bool) +EXPORT_C_(void *) GSsetupRecording(bool start); EXPORT_C_(void) @@ -113,4 +113,4 @@ GSabout(); EXPORT_C_(s32) GStest(); -#endif // __GSAPI_H__ \ No newline at end of file +#endif // __GSAPI_H__ diff --git a/common/include/null/config.inl b/common/include/null/config.inl index f617bc3442967..b8f90184231ff 100644 --- a/common/include/null/config.inl +++ b/common/include/null/config.inl @@ -22,9 +22,9 @@ #endif #include -PluginLog g_plugin_log; +static PluginLog g_plugin_log; -#if defined(_WIN32) +#if defined(_WIN32) && !defined(__LIBRETRO__) static HINSTANCE s_hinstance; @@ -60,15 +60,16 @@ static INT_PTR CALLBACK ConfigureDialogProc(HWND dialog, UINT message, WPARAM wp } } -void ConfigureLogging() +static void ConfigureLogging() { DialogBox(s_hinstance, MAKEINTRESOURCE(IDD_DIALOG), GetActiveWindow(), ConfigureDialogProc); } -#elif defined(__unix__) || defined(__APPLE__) +#elif (defined(__unix__) || defined(__APPLE__)) && !defined(__LIBRETRO__) -void ConfigureLogging() +static void ConfigureLogging() { +#if wxUSE_GUI auto *dialog = new wxDialog; dialog->Create(nullptr, wxID_ANY, "Config", wxDefaultPosition, wxDefaultSize, wxCAPTION | wxCLOSE_BOX); @@ -92,17 +93,18 @@ void ConfigureLogging() g_plugin_log.WriteToFile = file_check->GetValue(); } wxDELETE(dialog); +#endif } #else -void ConfigureLogging() +static void ConfigureLogging() { } #endif -void SaveConfig(const std::string &pathname) +static void SaveConfig(const std::string &pathname) { PluginConf ini; if (!ini.Open(pathname, WRITE_FILE)) { @@ -115,7 +117,7 @@ void SaveConfig(const std::string &pathname) ini.Close(); } -void LoadConfig(const std::string &pathname) +static void LoadConfig(const std::string &pathname) { PluginConf ini; if (!ini.Open(pathname, READ_FILE)) { diff --git a/common/src/Utilities/CMakeLists.txt b/common/src/Utilities/CMakeLists.txt index 21355b8254606..34c99ed13e133 100644 --- a/common/src/Utilities/CMakeLists.txt +++ b/common/src/Utilities/CMakeLists.txt @@ -16,36 +16,46 @@ set(UtilitiesFinalFlags ${CommonFlags}) # variable with all sources of this library set(UtilitiesSources VirtualMemory.cpp - AlignedMalloc.cpp ../../include/Utilities/FixedPointTypes.inl ../../include/Utilities/EventSource.inl ../../include/Utilities/SafeArray.inl - CheckedStaticBox.cpp Console.cpp - EventSource.cpp Exceptions.cpp FastFormatString.cpp IniInterface.cpp - Linux/LnxHostSys.cpp Mutex.cpp PathUtils.cpp PrecompiledHeader.cpp Perf.cpp - pxCheckBox.cpp - pxRadioPanel.cpp - pxStaticText.cpp pxStreams.cpp pxTranslate.cpp - pxWindowTextWriter.cpp RwMutex.cpp StringHelpers.cpp - ThreadingDialogs.cpp ThreadTools.cpp wxAppWithHelpers.cpp - wxGuiTools.cpp - wxHelpers.cpp ) +if(NOT MSVC) + set(UtilitiesSources ${UtilitiesSources} + AlignedMalloc.cpp + Linux/LnxHostSys.cpp + ) +endif() + +if(NOT LIBRETRO) + set(UtilitiesSources ${UtilitiesSources} + CheckedStaticBox.cpp + EventSource.cpp + pxCheckBox.cpp + pxRadioPanel.cpp + pxStaticText.cpp + pxWindowTextWriter.cpp + ThreadingDialogs.cpp + wxGuiTools.cpp + wxHelpers.cpp + ) +endif() + # variable with all headers of this library set(UtilitiesHeaders ../../include/Utilities/Assertions.h @@ -91,11 +101,16 @@ if(APPLE) ) elseif(Windows) LIST(APPEND UtilitiesSources - x86/MemcpyFast.cpp Windows/WinThreads.cpp Windows/WinHostSys.cpp Windows/WinMisc.cpp + Semaphore.cpp ) + if(NOT _M_X86_64) + LIST(APPEND UtilitiesSources + x86/MemcpyFast.cpp + ) + endif() else() LIST(APPEND UtilitiesSources Linux/LnxThreads.cpp @@ -114,10 +129,15 @@ set(UtilitiesFinalLibs ${wxWidgets_LIBRARIES} ) +if(MSVC) + set(UtilitiesFinalLibs ${UtilitiesFinalLibs} pthread) +endif() + + add_pcsx2_lib(${Output} "${UtilitiesFinalSources}" "${UtilitiesFinalLibs}" "${UtilitiesFinalFlags}") add_pcsx2_lib(${Output}_NO_TLS "${UtilitiesFinalSources}" "${UtilitiesFinalLibs}" "${UtilitiesFinalFlags} -DPCSX2_THREAD_LOCAL=0") -if(COMMAND target_precompile_headers) +if(COMMAND target_precompile_headers AND NOT CCACHE_FOUND) target_precompile_headers(${Output} PRIVATE PrecompiledHeader.h) target_precompile_headers(${Output}_NO_TLS PRIVATE PrecompiledHeader.h) endif() diff --git a/common/src/Utilities/Darwin/DarwinSemaphore.cpp b/common/src/Utilities/Darwin/DarwinSemaphore.cpp index dea234ca7d9b1..96e3fde6f986f 100644 --- a/common/src/Utilities/Darwin/DarwinSemaphore.cpp +++ b/common/src/Utilities/Darwin/DarwinSemaphore.cpp @@ -97,7 +97,9 @@ void Threading::Semaphore::Post(int multiple) void Threading::Semaphore::WaitWithoutYield() { +#ifndef __LIBRETRO__ pxAssertMsg(!wxThread::IsMain(), "Unyielding semaphore wait issued from the main/gui thread. Please use Wait() instead."); +#endif MACH_CHECK(semaphore_wait(m_sema)); __atomic_sub_fetch(&m_counter, 1, __ATOMIC_SEQ_CST); } diff --git a/common/src/Utilities/Mutex.cpp b/common/src/Utilities/Mutex.cpp index 2b968dd066881..436678e47cce5 100644 --- a/common/src/Utilities/Mutex.cpp +++ b/common/src/Utilities/Mutex.cpp @@ -170,7 +170,9 @@ bool Threading::Mutex::RecreateIfLocked() // other than the main thread. void Threading::Mutex::AcquireWithoutYield() { +#ifndef __LIBRETRO__ pxAssertMsg(!wxThread::IsMain(), "Unyielding mutex acquire issued from the main/gui thread. Please use Acquire() instead."); +#endif pthread_mutex_lock(&m_mutex); } @@ -235,7 +237,7 @@ bool Threading::Mutex::Acquire(const wxTimeSpan &timeout) } #else - return AcquireWithoutYield(); + return AcquireWithoutYield(timeout); #endif } diff --git a/common/src/Utilities/PathUtils.cpp b/common/src/Utilities/PathUtils.cpp index 4fbdd5f16892e..c888be4043e82 100644 --- a/common/src/Utilities/PathUtils.cpp +++ b/common/src/Utilities/PathUtils.cpp @@ -192,7 +192,7 @@ wxString Path::GetRootDirectory(const wxString &src) else return wxString(src.begin(), src.begin() + pos); } - +#if wxUSE_GUI // ------------------------------------------------------------------------ // Launches the specified file according to its mime type // @@ -221,3 +221,4 @@ void pxExplore(const char *path) { pxExplore(fromUTF8(path)); } +#endif diff --git a/common/src/Utilities/Semaphore.cpp b/common/src/Utilities/Semaphore.cpp index 3f5a8fc6ef6aa..b3f9cb258c461 100644 --- a/common/src/Utilities/Semaphore.cpp +++ b/common/src/Utilities/Semaphore.cpp @@ -61,7 +61,9 @@ void Threading::Semaphore::Post(int multiple) void Threading::Semaphore::WaitWithoutYield() { +#ifndef __LIBRETRO__ pxAssertMsg(!wxThread::IsMain(), "Unyielding semaphore wait issued from the main/gui thread. Please use Wait() instead."); +#endif sem_wait(&m_sema); } diff --git a/common/src/Utilities/wxAppWithHelpers.cpp b/common/src/Utilities/wxAppWithHelpers.cpp index 53b1af9b64805..e7bf9ee3c8ae1 100644 --- a/common/src/Utilities/wxAppWithHelpers.cpp +++ b/common/src/Utilities/wxAppWithHelpers.cpp @@ -682,3 +682,9 @@ wxAppWithHelpers::wxAppWithHelpers() tls_insurance = 1; #endif } + +wxString pxGetAppName() +{ + pxAssert(wxTheApp); + return wxTheApp->GetAppName(); +} diff --git a/common/src/Utilities/wxGuiTools.cpp b/common/src/Utilities/wxGuiTools.cpp index 4b55363e75feb..f42bb5b1fabde 100644 --- a/common/src/Utilities/wxGuiTools.cpp +++ b/common/src/Utilities/wxGuiTools.cpp @@ -618,10 +618,3 @@ wxFont pxGetFixedFont(int ptsize, wxFontWeight weight, bool underline) #endif ); } - - -wxString pxGetAppName() -{ - pxAssert(wxTheApp); - return wxTheApp->GetAppName(); -} diff --git a/common/src/x86emitter/CMakeLists.txt b/common/src/x86emitter/CMakeLists.txt index 764af21874594..da2fae4ac0f20 100644 --- a/common/src/x86emitter/CMakeLists.txt +++ b/common/src/x86emitter/CMakeLists.txt @@ -74,6 +74,6 @@ set(x86emitterFinalLibs add_pcsx2_lib(${Output} "${x86emitterFinalSources}" "${x86emitterFinalLibs}" "${x86emitterFinalFlags}") -if(COMMAND target_precompile_headers) +if(COMMAND target_precompile_headers AND NOT CCACHE_FOUND) target_precompile_headers(${Output} PRIVATE PrecompiledHeader.h) endif() diff --git a/libretro/CMakeLists.txt b/libretro/CMakeLists.txt new file mode 100644 index 0000000000000..10b301c5ebda9 --- /dev/null +++ b/libretro/CMakeLists.txt @@ -0,0 +1,53 @@ + +add_library(pcsx2_libretro SHARED + main.cpp + options.cpp + input.cpp +) + +include_directories(${CMAKE_SOURCE_DIR}/pcsx2) +include_directories(${CMAKE_SOURCE_DIR}/pcsx2/gui) +include_directories(${CMAKE_SOURCE_DIR}/libretro) + +set(LIBRARY_OUTPUT_PATH "${CMAKE_BINARY_DIR}") + +set_target_properties(pcsx2_libretro PROPERTIES PREFIX "") +if(ANDROID) + target_sources(pcsx2_libretro PRIVATE + ) + set_target_properties(pcsx2_libretro PROPERTIES SUFFIX "_android.so") +endif() + +if(CMAKE_C_COMPILER_ID MATCHES "Clang") + set(CLANG 1) +endif() + +if(NOT MSVC AND NOT CLANG) + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--no-undefined") +endif() + +if(LIBRETRO_STATIC) + target_link_libraries(pcsx2_libretro PRIVATE + pcsx2Core + Utilities + x86emitter + ${wxWidgets_LIBRARIES} + ${GTK2_LIBRARIES} + ${ZLIB_LIBRARIES} + ${AIO_LIBRARIES} + ${GCOV_LIBRARIES} + ${ALSA_LIBRARIES} + ${SOUNDTOUCH_LIBRARIES} + ${SDL2_LIBRARIES} + ${PORTAUDIO_LIBRARIES} + ${LIBUDEV_LIBRARIES} + "${pcsx2FinalFlags}" + "-static-libgcc -static-libstdc++" + ) +else() + target_link_libraries(pcsx2_libretro PRIVATE + pcsx2Core + ${pcsx2FinalLibs} + "${pcsx2FinalFlags}" + ) +endif() diff --git a/libretro/input.cpp b/libretro/input.cpp new file mode 100644 index 0000000000000..f20fd99e3b2e8 --- /dev/null +++ b/libretro/input.cpp @@ -0,0 +1,243 @@ +#include +#include +#include +#include + +#include "input.h" +#include "PS2Edefs.h" + +#include "../plugins/onepad/GamePad.h" +#include "../plugins/onepad/onepad.h" +#include "../plugins/onepad/keyboard.h" +#include "../plugins/onepad/state_management.h" +#include "../plugins/onepad/KeyStatus.h" + +extern retro_environment_t environ_cb; +static retro_input_poll_t poll_cb; +static retro_input_state_t input_cb; +struct retro_rumble_interface rumble; + +static struct retro_input_descriptor desc[] = { + {0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_BUTTON, RETRO_DEVICE_ID_JOYPAD_LEFT, "Left"}, + {0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_BUTTON, RETRO_DEVICE_ID_JOYPAD_UP, "Up"}, + {0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_BUTTON, RETRO_DEVICE_ID_JOYPAD_DOWN, "Down"}, + {0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_BUTTON, RETRO_DEVICE_ID_JOYPAD_RIGHT, "Right"}, + {0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_BUTTON, RETRO_DEVICE_ID_JOYPAD_X, "Triangle"}, + {0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_BUTTON, RETRO_DEVICE_ID_JOYPAD_A, "Circle"}, + {0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_BUTTON, RETRO_DEVICE_ID_JOYPAD_B, "Cross"}, + {0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_BUTTON, RETRO_DEVICE_ID_JOYPAD_Y, "Square"}, + {0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_BUTTON, RETRO_DEVICE_ID_JOYPAD_L, "L"}, + {0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_BUTTON, RETRO_DEVICE_ID_JOYPAD_R, "R"}, + {0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_BUTTON, RETRO_DEVICE_ID_JOYPAD_L2, "L2"}, + {0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_BUTTON, RETRO_DEVICE_ID_JOYPAD_R2, "R2"}, + {0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_BUTTON, RETRO_DEVICE_ID_JOYPAD_L3, "L3"}, + {0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_BUTTON, RETRO_DEVICE_ID_JOYPAD_R3, "R3"}, + {0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_BUTTON, RETRO_DEVICE_ID_JOYPAD_START, "Start"}, + {0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_BUTTON, RETRO_DEVICE_ID_JOYPAD_SELECT, "Select"}, + {0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_X, "L-Analog X"}, + {0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_Y, "L-Analog Y"}, + {0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_X, "R-Analog X"}, + {0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_Y, "R-Analog Y"}, + + {1, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_BUTTON, RETRO_DEVICE_ID_JOYPAD_LEFT, "Left"}, + {1, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_BUTTON, RETRO_DEVICE_ID_JOYPAD_UP, "Up"}, + {1, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_BUTTON, RETRO_DEVICE_ID_JOYPAD_DOWN, "Down"}, + {1, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_BUTTON, RETRO_DEVICE_ID_JOYPAD_RIGHT, "Right"}, + {1, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_BUTTON, RETRO_DEVICE_ID_JOYPAD_X, "Triangle"}, + {1, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_BUTTON, RETRO_DEVICE_ID_JOYPAD_A, "Circle"}, + {1, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_BUTTON, RETRO_DEVICE_ID_JOYPAD_B, "Cross"}, + {1, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_BUTTON, RETRO_DEVICE_ID_JOYPAD_Y, "Square"}, + {1, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_BUTTON, RETRO_DEVICE_ID_JOYPAD_L, "L"}, + {1, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_BUTTON, RETRO_DEVICE_ID_JOYPAD_R, "R"}, + {1, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_BUTTON, RETRO_DEVICE_ID_JOYPAD_L2, "L2"}, + {1, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_BUTTON, RETRO_DEVICE_ID_JOYPAD_R2, "R2"}, + {1, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_BUTTON, RETRO_DEVICE_ID_JOYPAD_L3, "L3"}, + {1, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_BUTTON, RETRO_DEVICE_ID_JOYPAD_R3, "R3"}, + {1, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_BUTTON, RETRO_DEVICE_ID_JOYPAD_START, "Start"}, + {1, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_BUTTON, RETRO_DEVICE_ID_JOYPAD_SELECT, "Select"}, + {1, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_X, "L-Analog X"}, + {1, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_Y, "L-Analog Y"}, + {1, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_X, "R-Analog X"}, + {1, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_Y, "R-Analog Y"}, + + {0}, +}; + +namespace Input +{ + +void Init() +{ + environ_cb(RETRO_ENVIRONMENT_GET_RUMBLE_INTERFACE, &rumble); + static const struct retro_controller_description ds2_desc[] = { + {"DualShock 2", RETRO_DEVICE_ANALOG}, + }; + + static const struct retro_controller_info ports[] = { + {ds2_desc, sizeof(ds2_desc) / sizeof(*ds2_desc)}, + {ds2_desc, sizeof(ds2_desc) / sizeof(*ds2_desc)}, + {}, + }; + + environ_cb(RETRO_ENVIRONMENT_SET_CONTROLLER_INFO, (void*)ports); + // environ_cb(RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS, desc); +} + +void Shutdown() +{ +} + +void Update() +{ + poll_cb(); +#ifdef __ANDROID__ + /* Android doesn't support input polling on all threads by default + * this will force the poll for this frame to happen in the main thread + * in case the frontend is doing late-polling */ + input_cb(0, 0, 0, 0); +#endif + Pad::rumble_all(); +} + +} // namespace Input + +void retro_set_input_poll(retro_input_poll_t cb) +{ + poll_cb = cb; +} + +void retro_set_input_state(retro_input_state_t cb) +{ + input_cb = cb; +} + +void retro_set_controller_port_device(unsigned port, unsigned device) +{ + environ_cb(RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS, desc); +} + +EXPORT_C_(void) +PADabout() +{ +} + +EXPORT_C_(s32) +PADtest() +{ + return 0; +} + +s32 _PADopen(void* pDsp) +{ + return 0; +} + +void _PADclose() +{ +} + +EXPORT_C_(void) +PADupdate(int pad) +{ +} + +std::vector> s_vgamePad; + +void GamePad::EnumerateGamePads(std::vector>& vgamePad) +{ +} + +void GamePad::DoRumble(unsigned type, unsigned pad) +{ + if (pad >= GAMEPAD_NUMBER) + return; + + if (type == 0) + rumble.set_rumble_state(pad, RETRO_RUMBLE_WEAK, 0xFFFF); + else + rumble.set_rumble_state(pad, RETRO_RUMBLE_STRONG, 0xFFFF); +} + +EXPORT_C_(void) +PADconfigure() +{ +} + +void PADSaveConfig() +{ +} + +void PADLoadConfig() +{ +} + +void KeyStatus::Init() +{ +} + +static int keymap[] = + { + RETRO_DEVICE_ID_JOYPAD_L2, // PAD_L2 + RETRO_DEVICE_ID_JOYPAD_R2, // PAD_R2 + RETRO_DEVICE_ID_JOYPAD_L, // PAD_L1 + RETRO_DEVICE_ID_JOYPAD_R, // PAD_R1 + RETRO_DEVICE_ID_JOYPAD_X, // PAD_TRIANGLE + RETRO_DEVICE_ID_JOYPAD_A, // PAD_CIRCLE + RETRO_DEVICE_ID_JOYPAD_B, // PAD_CROSS + RETRO_DEVICE_ID_JOYPAD_Y, // PAD_SQUARE + RETRO_DEVICE_ID_JOYPAD_SELECT, // PAD_SELECT + RETRO_DEVICE_ID_JOYPAD_L3, // PAD_L3 + RETRO_DEVICE_ID_JOYPAD_R3, // PAD_R3 + RETRO_DEVICE_ID_JOYPAD_START, // PAD_START + RETRO_DEVICE_ID_JOYPAD_UP, // PAD_UP + RETRO_DEVICE_ID_JOYPAD_RIGHT, // PAD_RIGHT + RETRO_DEVICE_ID_JOYPAD_DOWN, // PAD_DOWN + RETRO_DEVICE_ID_JOYPAD_LEFT, // PAD_LEFT +}; + +u16 KeyStatus::get(u32 pad) +{ + u16 mask = input_cb(pad, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_MASK); + u16 new_mask = 0; + for (int i = 0; i < 16; i++) + new_mask |= !(mask & (1 << keymap[i])) << i; + + return new_mask; +} + +u8 KeyStatus::get(u32 pad, u32 index) +{ + int val = 0; + switch (index) + { + case PAD_R_LEFT: + case PAD_R_RIGHT: + val = input_cb(pad, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_X); + break; + + case PAD_R_DOWN: + case PAD_R_UP: + val = input_cb(pad, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_Y); + break; + + case PAD_L_LEFT: + case PAD_L_RIGHT: + val = input_cb(pad, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_X); + break; + + case PAD_L_DOWN: + case PAD_L_UP: + val = input_cb(pad, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_Y); + break; + + default: + if (index < 16) + val = input_cb(pad, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_BUTTON, keymap[index]); + break; + } + + if (index < 16) + return 0xFF - (val >> 7); + + return 0x80 + (val >> 8); +} diff --git a/libretro/input.h b/libretro/input.h new file mode 100644 index 0000000000000..c9535b4f7a671 --- /dev/null +++ b/libretro/input.h @@ -0,0 +1,9 @@ + +#pragma once + +namespace Input +{ +void Init(); +void Update(); +void Shutdown(); +} diff --git a/libretro/libretro.h b/libretro/libretro.h new file mode 100644 index 0000000000000..c8a3cb763c7a4 --- /dev/null +++ b/libretro/libretro.h @@ -0,0 +1,3026 @@ +/* Copyright (C) 2010-2020 The RetroArch team + * + * --------------------------------------------------------------------------------------- + * The following license statement only applies to this libretro API header (libretro.h). + * --------------------------------------------------------------------------------------- + * + * Permission is hereby granted, free of charge, + * to any person obtaining a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef LIBRETRO_H__ +#define LIBRETRO_H__ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __cplusplus +#if defined(_MSC_VER) && _MSC_VER < 1800 && !defined(SN_TARGET_PS3) +/* Hack applied for MSVC when compiling in C89 mode + * as it isn't C99-compliant. */ +#define bool unsigned char +#define true 1 +#define false 0 +#else +#include +#endif +#endif + +#ifndef RETRO_CALLCONV +# if defined(__GNUC__) && defined(__i386__) && !defined(__x86_64__) +# define RETRO_CALLCONV __attribute__((cdecl)) +# elif defined(_MSC_VER) && defined(_M_X86) && !defined(_M_X64) +# define RETRO_CALLCONV __cdecl +# else +# define RETRO_CALLCONV /* all other platforms only have one calling convention each */ +# endif +#endif + +#ifndef RETRO_API +# if defined(_WIN32) || defined(__CYGWIN__) || defined(__MINGW32__) +# ifdef RETRO_IMPORT_SYMBOLS +# ifdef __GNUC__ +# define RETRO_API RETRO_CALLCONV __attribute__((__dllimport__)) +# else +# define RETRO_API RETRO_CALLCONV __declspec(dllimport) +# endif +# else +# ifdef __GNUC__ +# define RETRO_API RETRO_CALLCONV __attribute__((__dllexport__)) +# else +# define RETRO_API RETRO_CALLCONV __declspec(dllexport) +# endif +# endif +# else +# if defined(__GNUC__) && __GNUC__ >= 4 && !defined(__CELLOS_LV2__) +# define RETRO_API RETRO_CALLCONV __attribute__((__visibility__("default"))) +# else +# define RETRO_API RETRO_CALLCONV +# endif +# endif +#endif + +/* Used for checking API/ABI mismatches that can break libretro + * implementations. + * It is not incremented for compatible changes to the API. + */ +#define RETRO_API_VERSION 1 + +/* + * Libretro's fundamental device abstractions. + * + * Libretro's input system consists of some standardized device types, + * such as a joypad (with/without analog), mouse, keyboard, lightgun + * and a pointer. + * + * The functionality of these devices are fixed, and individual cores + * map their own concept of a controller to libretro's abstractions. + * This makes it possible for frontends to map the abstract types to a + * real input device, and not having to worry about binding input + * correctly to arbitrary controller layouts. + */ + +#define RETRO_DEVICE_TYPE_SHIFT 8 +#define RETRO_DEVICE_MASK ((1 << RETRO_DEVICE_TYPE_SHIFT) - 1) +#define RETRO_DEVICE_SUBCLASS(base, id) (((id + 1) << RETRO_DEVICE_TYPE_SHIFT) | base) + +/* Input disabled. */ +#define RETRO_DEVICE_NONE 0 + +/* The JOYPAD is called RetroPad. It is essentially a Super Nintendo + * controller, but with additional L2/R2/L3/R3 buttons, similar to a + * PS1 DualShock. */ +#define RETRO_DEVICE_JOYPAD 1 + +/* The mouse is a simple mouse, similar to Super Nintendo's mouse. + * X and Y coordinates are reported relatively to last poll (poll callback). + * It is up to the libretro implementation to keep track of where the mouse + * pointer is supposed to be on the screen. + * The frontend must make sure not to interfere with its own hardware + * mouse pointer. + */ +#define RETRO_DEVICE_MOUSE 2 + +/* KEYBOARD device lets one poll for raw key pressed. + * It is poll based, so input callback will return with the current + * pressed state. + * For event/text based keyboard input, see + * RETRO_ENVIRONMENT_SET_KEYBOARD_CALLBACK. + */ +#define RETRO_DEVICE_KEYBOARD 3 + +/* LIGHTGUN device is similar to Guncon-2 for PlayStation 2. + * It reports X/Y coordinates in screen space (similar to the pointer) + * in the range [-0x8000, 0x7fff] in both axes, with zero being center and + * -0x8000 being out of bounds. + * As well as reporting on/off screen state. It features a trigger, + * start/select buttons, auxiliary action buttons and a + * directional pad. A forced off-screen shot can be requested for + * auto-reloading function in some games. + */ +#define RETRO_DEVICE_LIGHTGUN 4 + +/* The ANALOG device is an extension to JOYPAD (RetroPad). + * Similar to DualShock2 it adds two analog sticks and all buttons can + * be analog. This is treated as a separate device type as it returns + * axis values in the full analog range of [-0x7fff, 0x7fff], + * although some devices may return -0x8000. + * Positive X axis is right. Positive Y axis is down. + * Buttons are returned in the range [0, 0x7fff]. + * Only use ANALOG type when polling for analog values. + */ +#define RETRO_DEVICE_ANALOG 5 + +/* Abstracts the concept of a pointing mechanism, e.g. touch. + * This allows libretro to query in absolute coordinates where on the + * screen a mouse (or something similar) is being placed. + * For a touch centric device, coordinates reported are the coordinates + * of the press. + * + * Coordinates in X and Y are reported as: + * [-0x7fff, 0x7fff]: -0x7fff corresponds to the far left/top of the screen, + * and 0x7fff corresponds to the far right/bottom of the screen. + * The "screen" is here defined as area that is passed to the frontend and + * later displayed on the monitor. + * + * The frontend is free to scale/resize this screen as it sees fit, however, + * (X, Y) = (-0x7fff, -0x7fff) will correspond to the top-left pixel of the + * game image, etc. + * + * To check if the pointer coordinates are valid (e.g. a touch display + * actually being touched), PRESSED returns 1 or 0. + * + * If using a mouse on a desktop, PRESSED will usually correspond to the + * left mouse button, but this is a frontend decision. + * PRESSED will only return 1 if the pointer is inside the game screen. + * + * For multi-touch, the index variable can be used to successively query + * more presses. + * If index = 0 returns true for _PRESSED, coordinates can be extracted + * with _X, _Y for index = 0. One can then query _PRESSED, _X, _Y with + * index = 1, and so on. + * Eventually _PRESSED will return false for an index. No further presses + * are registered at this point. */ +#define RETRO_DEVICE_POINTER 6 + +/* Buttons for the RetroPad (JOYPAD). + * The placement of these is equivalent to placements on the + * Super Nintendo controller. + * L2/R2/L3/R3 buttons correspond to the PS1 DualShock. + * Also used as id values for RETRO_DEVICE_INDEX_ANALOG_BUTTON */ +#define RETRO_DEVICE_ID_JOYPAD_B 0 +#define RETRO_DEVICE_ID_JOYPAD_Y 1 +#define RETRO_DEVICE_ID_JOYPAD_SELECT 2 +#define RETRO_DEVICE_ID_JOYPAD_START 3 +#define RETRO_DEVICE_ID_JOYPAD_UP 4 +#define RETRO_DEVICE_ID_JOYPAD_DOWN 5 +#define RETRO_DEVICE_ID_JOYPAD_LEFT 6 +#define RETRO_DEVICE_ID_JOYPAD_RIGHT 7 +#define RETRO_DEVICE_ID_JOYPAD_A 8 +#define RETRO_DEVICE_ID_JOYPAD_X 9 +#define RETRO_DEVICE_ID_JOYPAD_L 10 +#define RETRO_DEVICE_ID_JOYPAD_R 11 +#define RETRO_DEVICE_ID_JOYPAD_L2 12 +#define RETRO_DEVICE_ID_JOYPAD_R2 13 +#define RETRO_DEVICE_ID_JOYPAD_L3 14 +#define RETRO_DEVICE_ID_JOYPAD_R3 15 + +#define RETRO_DEVICE_ID_JOYPAD_MASK 256 + +/* Index / Id values for ANALOG device. */ +#define RETRO_DEVICE_INDEX_ANALOG_LEFT 0 +#define RETRO_DEVICE_INDEX_ANALOG_RIGHT 1 +#define RETRO_DEVICE_INDEX_ANALOG_BUTTON 2 +#define RETRO_DEVICE_ID_ANALOG_X 0 +#define RETRO_DEVICE_ID_ANALOG_Y 1 + +/* Id values for MOUSE. */ +#define RETRO_DEVICE_ID_MOUSE_X 0 +#define RETRO_DEVICE_ID_MOUSE_Y 1 +#define RETRO_DEVICE_ID_MOUSE_LEFT 2 +#define RETRO_DEVICE_ID_MOUSE_RIGHT 3 +#define RETRO_DEVICE_ID_MOUSE_WHEELUP 4 +#define RETRO_DEVICE_ID_MOUSE_WHEELDOWN 5 +#define RETRO_DEVICE_ID_MOUSE_MIDDLE 6 +#define RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELUP 7 +#define RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELDOWN 8 +#define RETRO_DEVICE_ID_MOUSE_BUTTON_4 9 +#define RETRO_DEVICE_ID_MOUSE_BUTTON_5 10 + +/* Id values for LIGHTGUN. */ +#define RETRO_DEVICE_ID_LIGHTGUN_SCREEN_X 13 /*Absolute Position*/ +#define RETRO_DEVICE_ID_LIGHTGUN_SCREEN_Y 14 /*Absolute*/ +#define RETRO_DEVICE_ID_LIGHTGUN_IS_OFFSCREEN 15 /*Status Check*/ +#define RETRO_DEVICE_ID_LIGHTGUN_TRIGGER 2 +#define RETRO_DEVICE_ID_LIGHTGUN_RELOAD 16 /*Forced off-screen shot*/ +#define RETRO_DEVICE_ID_LIGHTGUN_AUX_A 3 +#define RETRO_DEVICE_ID_LIGHTGUN_AUX_B 4 +#define RETRO_DEVICE_ID_LIGHTGUN_START 6 +#define RETRO_DEVICE_ID_LIGHTGUN_SELECT 7 +#define RETRO_DEVICE_ID_LIGHTGUN_AUX_C 8 +#define RETRO_DEVICE_ID_LIGHTGUN_DPAD_UP 9 +#define RETRO_DEVICE_ID_LIGHTGUN_DPAD_DOWN 10 +#define RETRO_DEVICE_ID_LIGHTGUN_DPAD_LEFT 11 +#define RETRO_DEVICE_ID_LIGHTGUN_DPAD_RIGHT 12 +/* deprecated */ +#define RETRO_DEVICE_ID_LIGHTGUN_X 0 /*Relative Position*/ +#define RETRO_DEVICE_ID_LIGHTGUN_Y 1 /*Relative*/ +#define RETRO_DEVICE_ID_LIGHTGUN_CURSOR 3 /*Use Aux:A*/ +#define RETRO_DEVICE_ID_LIGHTGUN_TURBO 4 /*Use Aux:B*/ +#define RETRO_DEVICE_ID_LIGHTGUN_PAUSE 5 /*Use Start*/ + +/* Id values for POINTER. */ +#define RETRO_DEVICE_ID_POINTER_X 0 +#define RETRO_DEVICE_ID_POINTER_Y 1 +#define RETRO_DEVICE_ID_POINTER_PRESSED 2 +#define RETRO_DEVICE_ID_POINTER_COUNT 3 + +/* Returned from retro_get_region(). */ +#define RETRO_REGION_NTSC 0 +#define RETRO_REGION_PAL 1 + +/* Id values for LANGUAGE */ +enum retro_language +{ + RETRO_LANGUAGE_ENGLISH = 0, + RETRO_LANGUAGE_JAPANESE = 1, + RETRO_LANGUAGE_FRENCH = 2, + RETRO_LANGUAGE_SPANISH = 3, + RETRO_LANGUAGE_GERMAN = 4, + RETRO_LANGUAGE_ITALIAN = 5, + RETRO_LANGUAGE_DUTCH = 6, + RETRO_LANGUAGE_PORTUGUESE_BRAZIL = 7, + RETRO_LANGUAGE_PORTUGUESE_PORTUGAL = 8, + RETRO_LANGUAGE_RUSSIAN = 9, + RETRO_LANGUAGE_KOREAN = 10, + RETRO_LANGUAGE_CHINESE_TRADITIONAL = 11, + RETRO_LANGUAGE_CHINESE_SIMPLIFIED = 12, + RETRO_LANGUAGE_ESPERANTO = 13, + RETRO_LANGUAGE_POLISH = 14, + RETRO_LANGUAGE_VIETNAMESE = 15, + RETRO_LANGUAGE_ARABIC = 16, + RETRO_LANGUAGE_GREEK = 17, + RETRO_LANGUAGE_TURKISH = 18, + RETRO_LANGUAGE_SLOVAK = 19, + RETRO_LANGUAGE_PERSIAN = 20, + RETRO_LANGUAGE_HEBREW = 21, + RETRO_LANGUAGE_ASTURIAN = 22, + RETRO_LANGUAGE_LAST, + + /* Ensure sizeof(enum) == sizeof(int) */ + RETRO_LANGUAGE_DUMMY = INT_MAX +}; + +/* Passed to retro_get_memory_data/size(). + * If the memory type doesn't apply to the + * implementation NULL/0 can be returned. + */ +#define RETRO_MEMORY_MASK 0xff + +/* Regular save RAM. This RAM is usually found on a game cartridge, + * backed up by a battery. + * If save game data is too complex for a single memory buffer, + * the SAVE_DIRECTORY (preferably) or SYSTEM_DIRECTORY environment + * callback can be used. */ +#define RETRO_MEMORY_SAVE_RAM 0 + +/* Some games have a built-in clock to keep track of time. + * This memory is usually just a couple of bytes to keep track of time. + */ +#define RETRO_MEMORY_RTC 1 + +/* System ram lets a frontend peek into a game systems main RAM. */ +#define RETRO_MEMORY_SYSTEM_RAM 2 + +/* Video ram lets a frontend peek into a game systems video RAM (VRAM). */ +#define RETRO_MEMORY_VIDEO_RAM 3 + +/* Keysyms used for ID in input state callback when polling RETRO_KEYBOARD. */ +enum retro_key +{ + RETROK_UNKNOWN = 0, + RETROK_FIRST = 0, + RETROK_BACKSPACE = 8, + RETROK_TAB = 9, + RETROK_CLEAR = 12, + RETROK_RETURN = 13, + RETROK_PAUSE = 19, + RETROK_ESCAPE = 27, + RETROK_SPACE = 32, + RETROK_EXCLAIM = 33, + RETROK_QUOTEDBL = 34, + RETROK_HASH = 35, + RETROK_DOLLAR = 36, + RETROK_AMPERSAND = 38, + RETROK_QUOTE = 39, + RETROK_LEFTPAREN = 40, + RETROK_RIGHTPAREN = 41, + RETROK_ASTERISK = 42, + RETROK_PLUS = 43, + RETROK_COMMA = 44, + RETROK_MINUS = 45, + RETROK_PERIOD = 46, + RETROK_SLASH = 47, + RETROK_0 = 48, + RETROK_1 = 49, + RETROK_2 = 50, + RETROK_3 = 51, + RETROK_4 = 52, + RETROK_5 = 53, + RETROK_6 = 54, + RETROK_7 = 55, + RETROK_8 = 56, + RETROK_9 = 57, + RETROK_COLON = 58, + RETROK_SEMICOLON = 59, + RETROK_LESS = 60, + RETROK_EQUALS = 61, + RETROK_GREATER = 62, + RETROK_QUESTION = 63, + RETROK_AT = 64, + RETROK_LEFTBRACKET = 91, + RETROK_BACKSLASH = 92, + RETROK_RIGHTBRACKET = 93, + RETROK_CARET = 94, + RETROK_UNDERSCORE = 95, + RETROK_BACKQUOTE = 96, + RETROK_a = 97, + RETROK_b = 98, + RETROK_c = 99, + RETROK_d = 100, + RETROK_e = 101, + RETROK_f = 102, + RETROK_g = 103, + RETROK_h = 104, + RETROK_i = 105, + RETROK_j = 106, + RETROK_k = 107, + RETROK_l = 108, + RETROK_m = 109, + RETROK_n = 110, + RETROK_o = 111, + RETROK_p = 112, + RETROK_q = 113, + RETROK_r = 114, + RETROK_s = 115, + RETROK_t = 116, + RETROK_u = 117, + RETROK_v = 118, + RETROK_w = 119, + RETROK_x = 120, + RETROK_y = 121, + RETROK_z = 122, + RETROK_LEFTBRACE = 123, + RETROK_BAR = 124, + RETROK_RIGHTBRACE = 125, + RETROK_TILDE = 126, + RETROK_DELETE = 127, + + RETROK_KP0 = 256, + RETROK_KP1 = 257, + RETROK_KP2 = 258, + RETROK_KP3 = 259, + RETROK_KP4 = 260, + RETROK_KP5 = 261, + RETROK_KP6 = 262, + RETROK_KP7 = 263, + RETROK_KP8 = 264, + RETROK_KP9 = 265, + RETROK_KP_PERIOD = 266, + RETROK_KP_DIVIDE = 267, + RETROK_KP_MULTIPLY = 268, + RETROK_KP_MINUS = 269, + RETROK_KP_PLUS = 270, + RETROK_KP_ENTER = 271, + RETROK_KP_EQUALS = 272, + + RETROK_UP = 273, + RETROK_DOWN = 274, + RETROK_RIGHT = 275, + RETROK_LEFT = 276, + RETROK_INSERT = 277, + RETROK_HOME = 278, + RETROK_END = 279, + RETROK_PAGEUP = 280, + RETROK_PAGEDOWN = 281, + + RETROK_F1 = 282, + RETROK_F2 = 283, + RETROK_F3 = 284, + RETROK_F4 = 285, + RETROK_F5 = 286, + RETROK_F6 = 287, + RETROK_F7 = 288, + RETROK_F8 = 289, + RETROK_F9 = 290, + RETROK_F10 = 291, + RETROK_F11 = 292, + RETROK_F12 = 293, + RETROK_F13 = 294, + RETROK_F14 = 295, + RETROK_F15 = 296, + + RETROK_NUMLOCK = 300, + RETROK_CAPSLOCK = 301, + RETROK_SCROLLOCK = 302, + RETROK_RSHIFT = 303, + RETROK_LSHIFT = 304, + RETROK_RCTRL = 305, + RETROK_LCTRL = 306, + RETROK_RALT = 307, + RETROK_LALT = 308, + RETROK_RMETA = 309, + RETROK_LMETA = 310, + RETROK_LSUPER = 311, + RETROK_RSUPER = 312, + RETROK_MODE = 313, + RETROK_COMPOSE = 314, + + RETROK_HELP = 315, + RETROK_PRINT = 316, + RETROK_SYSREQ = 317, + RETROK_BREAK = 318, + RETROK_MENU = 319, + RETROK_POWER = 320, + RETROK_EURO = 321, + RETROK_UNDO = 322, + RETROK_OEM_102 = 323, + + RETROK_LAST, + + RETROK_DUMMY = INT_MAX /* Ensure sizeof(enum) == sizeof(int) */ +}; + +enum retro_mod +{ + RETROKMOD_NONE = 0x0000, + + RETROKMOD_SHIFT = 0x01, + RETROKMOD_CTRL = 0x02, + RETROKMOD_ALT = 0x04, + RETROKMOD_META = 0x08, + + RETROKMOD_NUMLOCK = 0x10, + RETROKMOD_CAPSLOCK = 0x20, + RETROKMOD_SCROLLOCK = 0x40, + + RETROKMOD_DUMMY = INT_MAX /* Ensure sizeof(enum) == sizeof(int) */ +}; + +/* If set, this call is not part of the public libretro API yet. It can + * change or be removed at any time. */ +#define RETRO_ENVIRONMENT_EXPERIMENTAL 0x10000 +/* Environment callback to be used internally in frontend. */ +#define RETRO_ENVIRONMENT_PRIVATE 0x20000 + +/* Environment commands. */ +#define RETRO_ENVIRONMENT_SET_ROTATION 1 /* const unsigned * -- + * Sets screen rotation of graphics. + * Valid values are 0, 1, 2, 3, which rotates screen by 0, 90, 180, + * 270 degrees counter-clockwise respectively. + */ +#define RETRO_ENVIRONMENT_GET_OVERSCAN 2 /* bool * -- + * NOTE: As of 2019 this callback is considered deprecated in favor of + * using core options to manage overscan in a more nuanced, core-specific way. + * + * Boolean value whether or not the implementation should use overscan, + * or crop away overscan. + */ +#define RETRO_ENVIRONMENT_GET_CAN_DUPE 3 /* bool * -- + * Boolean value whether or not frontend supports frame duping, + * passing NULL to video frame callback. + */ + + /* Environ 4, 5 are no longer supported (GET_VARIABLE / SET_VARIABLES), + * and reserved to avoid possible ABI clash. + */ + +#define RETRO_ENVIRONMENT_SET_MESSAGE 6 /* const struct retro_message * -- + * Sets a message to be displayed in implementation-specific manner + * for a certain amount of 'frames'. + * Should not be used for trivial messages, which should simply be + * logged via RETRO_ENVIRONMENT_GET_LOG_INTERFACE (or as a + * fallback, stderr). + */ +#define RETRO_ENVIRONMENT_SHUTDOWN 7 /* N/A (NULL) -- + * Requests the frontend to shutdown. + * Should only be used if game has a specific + * way to shutdown the game from a menu item or similar. + */ +#define RETRO_ENVIRONMENT_SET_PERFORMANCE_LEVEL 8 + /* const unsigned * -- + * Gives a hint to the frontend how demanding this implementation + * is on a system. E.g. reporting a level of 2 means + * this implementation should run decently on all frontends + * of level 2 and up. + * + * It can be used by the frontend to potentially warn + * about too demanding implementations. + * + * The levels are "floating". + * + * This function can be called on a per-game basis, + * as certain games an implementation can play might be + * particularly demanding. + * If called, it should be called in retro_load_game(). + */ +#define RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY 9 + /* const char ** -- + * Returns the "system" directory of the frontend. + * This directory can be used to store system specific + * content such as BIOSes, configuration data, etc. + * The returned value can be NULL. + * If so, no such directory is defined, + * and it's up to the implementation to find a suitable directory. + * + * NOTE: Some cores used this folder also for "save" data such as + * memory cards, etc, for lack of a better place to put it. + * This is now discouraged, and if possible, cores should try to + * use the new GET_SAVE_DIRECTORY. + */ +#define RETRO_ENVIRONMENT_SET_PIXEL_FORMAT 10 + /* const enum retro_pixel_format * -- + * Sets the internal pixel format used by the implementation. + * The default pixel format is RETRO_PIXEL_FORMAT_0RGB1555. + * This pixel format however, is deprecated (see enum retro_pixel_format). + * If the call returns false, the frontend does not support this pixel + * format. + * + * This function should be called inside retro_load_game() or + * retro_get_system_av_info(). + */ +#define RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS 11 + /* const struct retro_input_descriptor * -- + * Sets an array of retro_input_descriptors. + * It is up to the frontend to present this in a usable way. + * The array is terminated by retro_input_descriptor::description + * being set to NULL. + * This function can be called at any time, but it is recommended + * to call it as early as possible. + */ +#define RETRO_ENVIRONMENT_SET_KEYBOARD_CALLBACK 12 + /* const struct retro_keyboard_callback * -- + * Sets a callback function used to notify core about keyboard events. + */ +#define RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE 13 + /* const struct retro_disk_control_callback * -- + * Sets an interface which frontend can use to eject and insert + * disk images. + * This is used for games which consist of multiple images and + * must be manually swapped out by the user (e.g. PSX). + */ +#define RETRO_ENVIRONMENT_SET_HW_RENDER 14 + /* struct retro_hw_render_callback * -- + * Sets an interface to let a libretro core render with + * hardware acceleration. + * Should be called in retro_load_game(). + * If successful, libretro cores will be able to render to a + * frontend-provided framebuffer. + * The size of this framebuffer will be at least as large as + * max_width/max_height provided in get_av_info(). + * If HW rendering is used, pass only RETRO_HW_FRAME_BUFFER_VALID or + * NULL to retro_video_refresh_t. + */ +#define RETRO_ENVIRONMENT_GET_VARIABLE 15 + /* struct retro_variable * -- + * Interface to acquire user-defined information from environment + * that cannot feasibly be supported in a multi-system way. + * 'key' should be set to a key which has already been set by + * SET_VARIABLES. + * 'data' will be set to a value or NULL. + */ +#define RETRO_ENVIRONMENT_SET_VARIABLES 16 + /* const struct retro_variable * -- + * Allows an implementation to signal the environment + * which variables it might want to check for later using + * GET_VARIABLE. + * This allows the frontend to present these variables to + * a user dynamically. + * This should be called the first time as early as + * possible (ideally in retro_set_environment). + * Afterward it may be called again for the core to communicate + * updated options to the frontend, but the number of core + * options must not change from the number in the initial call. + * + * 'data' points to an array of retro_variable structs + * terminated by a { NULL, NULL } element. + * retro_variable::key should be namespaced to not collide + * with other implementations' keys. E.g. A core called + * 'foo' should use keys named as 'foo_option'. + * retro_variable::value should contain a human readable + * description of the key as well as a '|' delimited list + * of expected values. + * + * The number of possible options should be very limited, + * i.e. it should be feasible to cycle through options + * without a keyboard. + * + * First entry should be treated as a default. + * + * Example entry: + * { "foo_option", "Speed hack coprocessor X; false|true" } + * + * Text before first ';' is description. This ';' must be + * followed by a space, and followed by a list of possible + * values split up with '|'. + * + * Only strings are operated on. The possible values will + * generally be displayed and stored as-is by the frontend. + */ +#define RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE 17 + /* bool * -- + * Result is set to true if some variables are updated by + * frontend since last call to RETRO_ENVIRONMENT_GET_VARIABLE. + * Variables should be queried with GET_VARIABLE. + */ +#define RETRO_ENVIRONMENT_SET_SUPPORT_NO_GAME 18 + /* const bool * -- + * If true, the libretro implementation supports calls to + * retro_load_game() with NULL as argument. + * Used by cores which can run without particular game data. + * This should be called within retro_set_environment() only. + */ +#define RETRO_ENVIRONMENT_GET_LIBRETRO_PATH 19 + /* const char ** -- + * Retrieves the absolute path from where this libretro + * implementation was loaded. + * NULL is returned if the libretro was loaded statically + * (i.e. linked statically to frontend), or if the path cannot be + * determined. + * Mostly useful in cooperation with SET_SUPPORT_NO_GAME as assets can + * be loaded without ugly hacks. + */ + + /* Environment 20 was an obsolete version of SET_AUDIO_CALLBACK. + * It was not used by any known core at the time, + * and was removed from the API. */ +#define RETRO_ENVIRONMENT_SET_FRAME_TIME_CALLBACK 21 + /* const struct retro_frame_time_callback * -- + * Lets the core know how much time has passed since last + * invocation of retro_run(). + * The frontend can tamper with the timing to fake fast-forward, + * slow-motion, frame stepping, etc. + * In this case the delta time will use the reference value + * in frame_time_callback.. + */ +#define RETRO_ENVIRONMENT_SET_AUDIO_CALLBACK 22 + /* const struct retro_audio_callback * -- + * Sets an interface which is used to notify a libretro core about audio + * being available for writing. + * The callback can be called from any thread, so a core using this must + * have a thread safe audio implementation. + * It is intended for games where audio and video are completely + * asynchronous and audio can be generated on the fly. + * This interface is not recommended for use with emulators which have + * highly synchronous audio. + * + * The callback only notifies about writability; the libretro core still + * has to call the normal audio callbacks + * to write audio. The audio callbacks must be called from within the + * notification callback. + * The amount of audio data to write is up to the implementation. + * Generally, the audio callback will be called continously in a loop. + * + * Due to thread safety guarantees and lack of sync between audio and + * video, a frontend can selectively disallow this interface based on + * internal configuration. A core using this interface must also + * implement the "normal" audio interface. + * + * A libretro core using SET_AUDIO_CALLBACK should also make use of + * SET_FRAME_TIME_CALLBACK. + */ +#define RETRO_ENVIRONMENT_GET_RUMBLE_INTERFACE 23 + /* struct retro_rumble_interface * -- + * Gets an interface which is used by a libretro core to set + * state of rumble motors in controllers. + * A strong and weak motor is supported, and they can be + * controlled indepedently. + */ +#define RETRO_ENVIRONMENT_GET_INPUT_DEVICE_CAPABILITIES 24 + /* uint64_t * -- + * Gets a bitmask telling which device type are expected to be + * handled properly in a call to retro_input_state_t. + * Devices which are not handled or recognized always return + * 0 in retro_input_state_t. + * Example bitmask: caps = (1 << RETRO_DEVICE_JOYPAD) | (1 << RETRO_DEVICE_ANALOG). + * Should only be called in retro_run(). + */ +#define RETRO_ENVIRONMENT_GET_SENSOR_INTERFACE (25 | RETRO_ENVIRONMENT_EXPERIMENTAL) + /* struct retro_sensor_interface * -- + * Gets access to the sensor interface. + * The purpose of this interface is to allow + * setting state related to sensors such as polling rate, + * enabling/disable it entirely, etc. + * Reading sensor state is done via the normal + * input_state_callback API. + */ +#define RETRO_ENVIRONMENT_GET_CAMERA_INTERFACE (26 | RETRO_ENVIRONMENT_EXPERIMENTAL) + /* struct retro_camera_callback * -- + * Gets an interface to a video camera driver. + * A libretro core can use this interface to get access to a + * video camera. + * New video frames are delivered in a callback in same + * thread as retro_run(). + * + * GET_CAMERA_INTERFACE should be called in retro_load_game(). + * + * Depending on the camera implementation used, camera frames + * will be delivered as a raw framebuffer, + * or as an OpenGL texture directly. + * + * The core has to tell the frontend here which types of + * buffers can be handled properly. + * An OpenGL texture can only be handled when using a + * libretro GL core (SET_HW_RENDER). + * It is recommended to use a libretro GL core when + * using camera interface. + * + * The camera is not started automatically. The retrieved start/stop + * functions must be used to explicitly + * start and stop the camera driver. + */ +#define RETRO_ENVIRONMENT_GET_LOG_INTERFACE 27 + /* struct retro_log_callback * -- + * Gets an interface for logging. This is useful for + * logging in a cross-platform way + * as certain platforms cannot use stderr for logging. + * It also allows the frontend to + * show logging information in a more suitable way. + * If this interface is not used, libretro cores should + * log to stderr as desired. + */ +#define RETRO_ENVIRONMENT_GET_PERF_INTERFACE 28 + /* struct retro_perf_callback * -- + * Gets an interface for performance counters. This is useful + * for performance logging in a cross-platform way and for detecting + * architecture-specific features, such as SIMD support. + */ +#define RETRO_ENVIRONMENT_GET_LOCATION_INTERFACE 29 + /* struct retro_location_callback * -- + * Gets access to the location interface. + * The purpose of this interface is to be able to retrieve + * location-based information from the host device, + * such as current latitude / longitude. + */ +#define RETRO_ENVIRONMENT_GET_CONTENT_DIRECTORY 30 /* Old name, kept for compatibility. */ +#define RETRO_ENVIRONMENT_GET_CORE_ASSETS_DIRECTORY 30 + /* const char ** -- + * Returns the "core assets" directory of the frontend. + * This directory can be used to store specific assets that the + * core relies upon, such as art assets, + * input data, etc etc. + * The returned value can be NULL. + * If so, no such directory is defined, + * and it's up to the implementation to find a suitable directory. + */ +#define RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY 31 + /* const char ** -- + * Returns the "save" directory of the frontend, unless there is no + * save directory available. The save directory should be used to + * store SRAM, memory cards, high scores, etc, if the libretro core + * cannot use the regular memory interface (retro_get_memory_data()). + * + * If the frontend cannot designate a save directory, it will return + * NULL to indicate that the core should attempt to operate without a + * save directory set. + * + * NOTE: early libretro cores used the system directory for save + * files. Cores that need to be backwards-compatible can still check + * GET_SYSTEM_DIRECTORY. + */ +#define RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO 32 + /* const struct retro_system_av_info * -- + * Sets a new av_info structure. This can only be called from + * within retro_run(). + * This should *only* be used if the core is completely altering the + * internal resolutions, aspect ratios, timings, sampling rate, etc. + * Calling this can require a full reinitialization of video/audio + * drivers in the frontend, + * + * so it is important to call it very sparingly, and usually only with + * the users explicit consent. + * An eventual driver reinitialize will happen so that video and + * audio callbacks + * happening after this call within the same retro_run() call will + * target the newly initialized driver. + * + * This callback makes it possible to support configurable resolutions + * in games, which can be useful to + * avoid setting the "worst case" in max_width/max_height. + * + * ***HIGHLY RECOMMENDED*** Do not call this callback every time + * resolution changes in an emulator core if it's + * expected to be a temporary change, for the reasons of possible + * driver reinitialization. + * This call is not a free pass for not trying to provide + * correct values in retro_get_system_av_info(). If you need to change + * things like aspect ratio or nominal width/height, + * use RETRO_ENVIRONMENT_SET_GEOMETRY, which is a softer variant + * of SET_SYSTEM_AV_INFO. + * + * If this returns false, the frontend does not acknowledge a + * changed av_info struct. + */ +#define RETRO_ENVIRONMENT_SET_PROC_ADDRESS_CALLBACK 33 + /* const struct retro_get_proc_address_interface * -- + * Allows a libretro core to announce support for the + * get_proc_address() interface. + * This interface allows for a standard way to extend libretro where + * use of environment calls are too indirect, + * e.g. for cases where the frontend wants to call directly into the core. + * + * If a core wants to expose this interface, SET_PROC_ADDRESS_CALLBACK + * **MUST** be called from within retro_set_environment(). + */ +#define RETRO_ENVIRONMENT_SET_SUBSYSTEM_INFO 34 + /* const struct retro_subsystem_info * -- + * This environment call introduces the concept of libretro "subsystems". + * A subsystem is a variant of a libretro core which supports + * different kinds of games. + * The purpose of this is to support e.g. emulators which might + * have special needs, e.g. Super Nintendo's Super GameBoy, Sufami Turbo. + * It can also be used to pick among subsystems in an explicit way + * if the libretro implementation is a multi-system emulator itself. + * + * Loading a game via a subsystem is done with retro_load_game_special(), + * and this environment call allows a libretro core to expose which + * subsystems are supported for use with retro_load_game_special(). + * A core passes an array of retro_game_special_info which is terminated + * with a zeroed out retro_game_special_info struct. + * + * If a core wants to use this functionality, SET_SUBSYSTEM_INFO + * **MUST** be called from within retro_set_environment(). + */ +#define RETRO_ENVIRONMENT_SET_CONTROLLER_INFO 35 + /* const struct retro_controller_info * -- + * This environment call lets a libretro core tell the frontend + * which controller subclasses are recognized in calls to + * retro_set_controller_port_device(). + * + * Some emulators such as Super Nintendo support multiple lightgun + * types which must be specifically selected from. It is therefore + * sometimes necessary for a frontend to be able to tell the core + * about a special kind of input device which is not specifcally + * provided by the Libretro API. + * + * In order for a frontend to understand the workings of those devices, + * they must be defined as a specialized subclass of the generic device + * types already defined in the libretro API. + * + * The core must pass an array of const struct retro_controller_info which + * is terminated with a blanked out struct. Each element of the + * retro_controller_info struct corresponds to the ascending port index + * that is passed to retro_set_controller_port_device() when that function + * is called to indicate to the core that the frontend has changed the + * active device subclass. SEE ALSO: retro_set_controller_port_device() + * + * The ascending input port indexes provided by the core in the struct + * are generally presented by frontends as ascending User # or Player #, + * such as Player 1, Player 2, Player 3, etc. Which device subclasses are + * supported can vary per input port. + * + * The first inner element of each entry in the retro_controller_info array + * is a retro_controller_description struct that specifies the names and + * codes of all device subclasses that are available for the corresponding + * User or Player, beginning with the generic Libretro device that the + * subclasses are derived from. The second inner element of each entry is the + * total number of subclasses that are listed in the retro_controller_description. + * + * NOTE: Even if special device types are set in the libretro core, + * libretro should only poll input based on the base input device types. + */ +#define RETRO_ENVIRONMENT_SET_MEMORY_MAPS (36 | RETRO_ENVIRONMENT_EXPERIMENTAL) + /* const struct retro_memory_map * -- + * This environment call lets a libretro core tell the frontend + * about the memory maps this core emulates. + * This can be used to implement, for example, cheats in a core-agnostic way. + * + * Should only be used by emulators; it doesn't make much sense for + * anything else. + * It is recommended to expose all relevant pointers through + * retro_get_memory_* as well. + * + * Can be called from retro_init and retro_load_game. + */ +#define RETRO_ENVIRONMENT_SET_GEOMETRY 37 + /* const struct retro_game_geometry * -- + * This environment call is similar to SET_SYSTEM_AV_INFO for changing + * video parameters, but provides a guarantee that drivers will not be + * reinitialized. + * This can only be called from within retro_run(). + * + * The purpose of this call is to allow a core to alter nominal + * width/heights as well as aspect ratios on-the-fly, which can be + * useful for some emulators to change in run-time. + * + * max_width/max_height arguments are ignored and cannot be changed + * with this call as this could potentially require a reinitialization or a + * non-constant time operation. + * If max_width/max_height are to be changed, SET_SYSTEM_AV_INFO is required. + * + * A frontend must guarantee that this environment call completes in + * constant time. + */ +#define RETRO_ENVIRONMENT_GET_USERNAME 38 + /* const char ** + * Returns the specified username of the frontend, if specified by the user. + * This username can be used as a nickname for a core that has online facilities + * or any other mode where personalization of the user is desirable. + * The returned value can be NULL. + * If this environ callback is used by a core that requires a valid username, + * a default username should be specified by the core. + */ +#define RETRO_ENVIRONMENT_GET_LANGUAGE 39 + /* unsigned * -- + * Returns the specified language of the frontend, if specified by the user. + * It can be used by the core for localization purposes. + */ +#define RETRO_ENVIRONMENT_GET_CURRENT_SOFTWARE_FRAMEBUFFER (40 | RETRO_ENVIRONMENT_EXPERIMENTAL) + /* struct retro_framebuffer * -- + * Returns a preallocated framebuffer which the core can use for rendering + * the frame into when not using SET_HW_RENDER. + * The framebuffer returned from this call must not be used + * after the current call to retro_run() returns. + * + * The goal of this call is to allow zero-copy behavior where a core + * can render directly into video memory, avoiding extra bandwidth cost by copying + * memory from core to video memory. + * + * If this call succeeds and the core renders into it, + * the framebuffer pointer and pitch can be passed to retro_video_refresh_t. + * If the buffer from GET_CURRENT_SOFTWARE_FRAMEBUFFER is to be used, + * the core must pass the exact + * same pointer as returned by GET_CURRENT_SOFTWARE_FRAMEBUFFER; + * i.e. passing a pointer which is offset from the + * buffer is undefined. The width, height and pitch parameters + * must also match exactly to the values obtained from GET_CURRENT_SOFTWARE_FRAMEBUFFER. + * + * It is possible for a frontend to return a different pixel format + * than the one used in SET_PIXEL_FORMAT. This can happen if the frontend + * needs to perform conversion. + * + * It is still valid for a core to render to a different buffer + * even if GET_CURRENT_SOFTWARE_FRAMEBUFFER succeeds. + * + * A frontend must make sure that the pointer obtained from this function is + * writeable (and readable). + */ +#define RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE (41 | RETRO_ENVIRONMENT_EXPERIMENTAL) + /* const struct retro_hw_render_interface ** -- + * Returns an API specific rendering interface for accessing API specific data. + * Not all HW rendering APIs support or need this. + * The contents of the returned pointer is specific to the rendering API + * being used. See the various headers like libretro_vulkan.h, etc. + * + * GET_HW_RENDER_INTERFACE cannot be called before context_reset has been called. + * Similarly, after context_destroyed callback returns, + * the contents of the HW_RENDER_INTERFACE are invalidated. + */ +#define RETRO_ENVIRONMENT_SET_SUPPORT_ACHIEVEMENTS (42 | RETRO_ENVIRONMENT_EXPERIMENTAL) + /* const bool * -- + * If true, the libretro implementation supports achievements + * either via memory descriptors set with RETRO_ENVIRONMENT_SET_MEMORY_MAPS + * or via retro_get_memory_data/retro_get_memory_size. + * + * This must be called before the first call to retro_run. + */ +#define RETRO_ENVIRONMENT_SET_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE (43 | RETRO_ENVIRONMENT_EXPERIMENTAL) + /* const struct retro_hw_render_context_negotiation_interface * -- + * Sets an interface which lets the libretro core negotiate with frontend how a context is created. + * The semantics of this interface depends on which API is used in SET_HW_RENDER earlier. + * This interface will be used when the frontend is trying to create a HW rendering context, + * so it will be used after SET_HW_RENDER, but before the context_reset callback. + */ +#define RETRO_ENVIRONMENT_SET_SERIALIZATION_QUIRKS 44 + /* uint64_t * -- + * Sets quirk flags associated with serialization. The frontend will zero any flags it doesn't + * recognize or support. Should be set in either retro_init or retro_load_game, but not both. + */ +#define RETRO_ENVIRONMENT_SET_HW_SHARED_CONTEXT (44 | RETRO_ENVIRONMENT_EXPERIMENTAL) + /* N/A (null) * -- + * The frontend will try to use a 'shared' hardware context (mostly applicable + * to OpenGL) when a hardware context is being set up. + * + * Returns true if the frontend supports shared hardware contexts and false + * if the frontend does not support shared hardware contexts. + * + * This will do nothing on its own until SET_HW_RENDER env callbacks are + * being used. + */ +#define RETRO_ENVIRONMENT_GET_VFS_INTERFACE (45 | RETRO_ENVIRONMENT_EXPERIMENTAL) + /* struct retro_vfs_interface_info * -- + * Gets access to the VFS interface. + * VFS presence needs to be queried prior to load_game or any + * get_system/save/other_directory being called to let front end know + * core supports VFS before it starts handing out paths. + * It is recomended to do so in retro_set_environment + */ +#define RETRO_ENVIRONMENT_GET_LED_INTERFACE (46 | RETRO_ENVIRONMENT_EXPERIMENTAL) + /* struct retro_led_interface * -- + * Gets an interface which is used by a libretro core to set + * state of LEDs. + */ +#define RETRO_ENVIRONMENT_GET_AUDIO_VIDEO_ENABLE (47 | RETRO_ENVIRONMENT_EXPERIMENTAL) + /* int * -- + * Tells the core if the frontend wants audio or video. + * If disabled, the frontend will discard the audio or video, + * so the core may decide to skip generating a frame or generating audio. + * This is mainly used for increasing performance. + * Bit 0 (value 1): Enable Video + * Bit 1 (value 2): Enable Audio + * Bit 2 (value 4): Use Fast Savestates. + * Bit 3 (value 8): Hard Disable Audio + * Other bits are reserved for future use and will default to zero. + * If video is disabled: + * * The frontend wants the core to not generate any video, + * including presenting frames via hardware acceleration. + * * The frontend's video frame callback will do nothing. + * * After running the frame, the video output of the next frame should be + * no different than if video was enabled, and saving and loading state + * should have no issues. + * If audio is disabled: + * * The frontend wants the core to not generate any audio. + * * The frontend's audio callbacks will do nothing. + * * After running the frame, the audio output of the next frame should be + * no different than if audio was enabled, and saving and loading state + * should have no issues. + * Fast Savestates: + * * Guaranteed to be created by the same binary that will load them. + * * Will not be written to or read from the disk. + * * Suggest that the core assumes loading state will succeed. + * * Suggest that the core updates its memory buffers in-place if possible. + * * Suggest that the core skips clearing memory. + * * Suggest that the core skips resetting the system. + * * Suggest that the core may skip validation steps. + * Hard Disable Audio: + * * Used for a secondary core when running ahead. + * * Indicates that the frontend will never need audio from the core. + * * Suggests that the core may stop synthesizing audio, but this should not + * compromise emulation accuracy. + * * Audio output for the next frame does not matter, and the frontend will + * never need an accurate audio state in the future. + * * State will never be saved when using Hard Disable Audio. + */ +#define RETRO_ENVIRONMENT_GET_MIDI_INTERFACE (48 | RETRO_ENVIRONMENT_EXPERIMENTAL) + /* struct retro_midi_interface ** -- + * Returns a MIDI interface that can be used for raw data I/O. + */ + +#define RETRO_ENVIRONMENT_GET_FASTFORWARDING (49 | RETRO_ENVIRONMENT_EXPERIMENTAL) + /* bool * -- + * Boolean value that indicates whether or not the frontend is in + * fastforwarding mode. + */ + +#define RETRO_ENVIRONMENT_GET_TARGET_REFRESH_RATE (50 | RETRO_ENVIRONMENT_EXPERIMENTAL) + /* float * -- + * Float value that lets us know what target refresh rate + * is curently in use by the frontend. + * + * The core can use the returned value to set an ideal + * refresh rate/framerate. + */ + +#define RETRO_ENVIRONMENT_GET_INPUT_BITMASKS (51 | RETRO_ENVIRONMENT_EXPERIMENTAL) + /* bool * -- + * Boolean value that indicates whether or not the frontend supports + * input bitmasks being returned by retro_input_state_t. The advantage + * of this is that retro_input_state_t has to be only called once to + * grab all button states instead of multiple times. + * + * If it returns true, you can pass RETRO_DEVICE_ID_JOYPAD_MASK as 'id' + * to retro_input_state_t (make sure 'device' is set to RETRO_DEVICE_JOYPAD). + * It will return a bitmask of all the digital buttons. + */ + +#define RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION 52 + /* unsigned * -- + * Unsigned value is the API version number of the core options + * interface supported by the frontend. If callback return false, + * API version is assumed to be 0. + * + * In legacy code, core options are set by passing an array of + * retro_variable structs to RETRO_ENVIRONMENT_SET_VARIABLES. + * This may be still be done regardless of the core options + * interface version. + * + * If version is >= 1 however, core options may instead be set by + * passing an array of retro_core_option_definition structs to + * RETRO_ENVIRONMENT_SET_CORE_OPTIONS, or a 2D array of + * retro_core_option_definition structs to RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL. + * This allows the core to additionally set option sublabel information + * and/or provide localisation support. + */ + +#define RETRO_ENVIRONMENT_SET_CORE_OPTIONS 53 + /* const struct retro_core_option_definition ** -- + * Allows an implementation to signal the environment + * which variables it might want to check for later using + * GET_VARIABLE. + * This allows the frontend to present these variables to + * a user dynamically. + * This should only be called if RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION + * returns an API version of >= 1. + * This should be called instead of RETRO_ENVIRONMENT_SET_VARIABLES. + * This should be called the first time as early as + * possible (ideally in retro_set_environment). + * Afterwards it may be called again for the core to communicate + * updated options to the frontend, but the number of core + * options must not change from the number in the initial call. + * + * 'data' points to an array of retro_core_option_definition structs + * terminated by a { NULL, NULL, NULL, {{0}}, NULL } element. + * retro_core_option_definition::key should be namespaced to not collide + * with other implementations' keys. e.g. A core called + * 'foo' should use keys named as 'foo_option'. + * retro_core_option_definition::desc should contain a human readable + * description of the key. + * retro_core_option_definition::info should contain any additional human + * readable information text that a typical user may need to + * understand the functionality of the option. + * retro_core_option_definition::values is an array of retro_core_option_value + * structs terminated by a { NULL, NULL } element. + * > retro_core_option_definition::values[index].value is an expected option + * value. + * > retro_core_option_definition::values[index].label is a human readable + * label used when displaying the value on screen. If NULL, + * the value itself is used. + * retro_core_option_definition::default_value is the default core option + * setting. It must match one of the expected option values in the + * retro_core_option_definition::values array. If it does not, or the + * default value is NULL, the first entry in the + * retro_core_option_definition::values array is treated as the default. + * + * The number of possible options should be very limited, + * and must be less than RETRO_NUM_CORE_OPTION_VALUES_MAX. + * i.e. it should be feasible to cycle through options + * without a keyboard. + * + * Example entry: + * { + * "foo_option", + * "Speed hack coprocessor X", + * "Provides increased performance at the expense of reduced accuracy", + * { + * { "false", NULL }, + * { "true", NULL }, + * { "unstable", "Turbo (Unstable)" }, + * { NULL, NULL }, + * }, + * "false" + * } + * + * Only strings are operated on. The possible values will + * generally be displayed and stored as-is by the frontend. + */ + +#define RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL 54 + /* const struct retro_core_options_intl * -- + * Allows an implementation to signal the environment + * which variables it might want to check for later using + * GET_VARIABLE. + * This allows the frontend to present these variables to + * a user dynamically. + * This should only be called if RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION + * returns an API version of >= 1. + * This should be called instead of RETRO_ENVIRONMENT_SET_VARIABLES. + * This should be called the first time as early as + * possible (ideally in retro_set_environment). + * Afterwards it may be called again for the core to communicate + * updated options to the frontend, but the number of core + * options must not change from the number in the initial call. + * + * This is fundamentally the same as RETRO_ENVIRONMENT_SET_CORE_OPTIONS, + * with the addition of localisation support. The description of the + * RETRO_ENVIRONMENT_SET_CORE_OPTIONS callback should be consulted + * for further details. + * + * 'data' points to a retro_core_options_intl struct. + * + * retro_core_options_intl::us is a pointer to an array of + * retro_core_option_definition structs defining the US English + * core options implementation. It must point to a valid array. + * + * retro_core_options_intl::local is a pointer to an array of + * retro_core_option_definition structs defining core options for + * the current frontend language. It may be NULL (in which case + * retro_core_options_intl::us is used by the frontend). Any items + * missing from this array will be read from retro_core_options_intl::us + * instead. + * + * NOTE: Default core option values are always taken from the + * retro_core_options_intl::us array. Any default values in + * retro_core_options_intl::local array will be ignored. + */ + +#define RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY 55 + /* struct retro_core_option_display * -- + * + * Allows an implementation to signal the environment to show + * or hide a variable when displaying core options. This is + * considered a *suggestion*. The frontend is free to ignore + * this callback, and its implementation not considered mandatory. + * + * 'data' points to a retro_core_option_display struct + * + * retro_core_option_display::key is a variable identifier + * which has already been set by SET_VARIABLES/SET_CORE_OPTIONS. + * + * retro_core_option_display::visible is a boolean, specifying + * whether variable should be displayed + * + * Note that all core option variables will be set visible by + * default when calling SET_VARIABLES/SET_CORE_OPTIONS. + */ + +#define RETRO_ENVIRONMENT_GET_PREFERRED_HW_RENDER 56 + /* unsigned * -- + * + * Allows an implementation to ask frontend preferred hardware + * context to use. Core should use this information to deal + * with what specific context to request with SET_HW_RENDER. + * + * 'data' points to an unsigned variable + */ + +#define RETRO_ENVIRONMENT_GET_DISK_CONTROL_INTERFACE_VERSION 57 + /* unsigned * -- + * Unsigned value is the API version number of the disk control + * interface supported by the frontend. If callback return false, + * API version is assumed to be 0. + * + * In legacy code, the disk control interface is defined by passing + * a struct of type retro_disk_control_callback to + * RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE. + * This may be still be done regardless of the disk control + * interface version. + * + * If version is >= 1 however, the disk control interface may + * instead be defined by passing a struct of type + * retro_disk_control_ext_callback to + * RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE. + * This allows the core to provide additional information about + * disk images to the frontend and/or enables extra + * disk control functionality by the frontend. + */ + +#define RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE 58 + /* const struct retro_disk_control_ext_callback * -- + * Sets an interface which frontend can use to eject and insert + * disk images, and also obtain information about individual + * disk image files registered by the core. + * This is used for games which consist of multiple images and + * must be manually swapped out by the user (e.g. PSX, floppy disk + * based systems). + */ + +#define RETRO_ENVIRONMENT_GET_MESSAGE_INTERFACE_VERSION 59 + /* unsigned * -- + * Unsigned value is the API version number of the message + * interface supported by the frontend. If callback returns + * false, API version is assumed to be 0. + * + * In legacy code, messages may be displayed in an + * implementation-specific manner by passing a struct + * of type retro_message to RETRO_ENVIRONMENT_SET_MESSAGE. + * This may be still be done regardless of the message + * interface version. + * + * If version is >= 1 however, messages may instead be + * displayed by passing a struct of type retro_message_ext + * to RETRO_ENVIRONMENT_SET_MESSAGE_EXT. This allows the + * core to specify message logging level, priority and + * destination (OSD, logging interface or both). + */ + +#define RETRO_ENVIRONMENT_SET_MESSAGE_EXT 60 + /* const struct retro_message_ext * -- + * Sets a message to be displayed in an implementation-specific + * manner for a certain amount of 'frames'. Additionally allows + * the core to specify message logging level, priority and + * destination (OSD, logging interface or both). + * Should not be used for trivial messages, which should simply be + * logged via RETRO_ENVIRONMENT_GET_LOG_INTERFACE (or as a + * fallback, stderr). + */ + +#define RETRO_ENVIRONMENT_GET_INPUT_MAX_USERS 61 + /* unsigned * -- + * Unsigned value is the number of active input devices + * provided by the frontend. This may change between + * frames, but will remain constant for the duration + * of each frame. + * If callback returns true, a core need not poll any + * input device with an index greater than or equal to + * the number of active devices. + * If callback returns false, the number of active input + * devices is unknown. In this case, all input devices + * should be considered active. + */ + +/* VFS functionality */ + +/* File paths: + * File paths passed as parameters when using this API shall be well formed UNIX-style, + * using "/" (unquoted forward slash) as directory separator regardless of the platform's native separator. + * Paths shall also include at least one forward slash ("game.bin" is an invalid path, use "./game.bin" instead). + * Other than the directory separator, cores shall not make assumptions about path format: + * "C:/path/game.bin", "http://example.com/game.bin", "#game/game.bin", "./game.bin" (without quotes) are all valid paths. + * Cores may replace the basename or remove path components from the end, and/or add new components; + * however, cores shall not append "./", "../" or multiple consecutive forward slashes ("//") to paths they request to front end. + * The frontend is encouraged to make such paths work as well as it can, but is allowed to give up if the core alters paths too much. + * Frontends are encouraged, but not required, to support native file system paths (modulo replacing the directory separator, if applicable). + * Cores are allowed to try using them, but must remain functional if the front rejects such requests. + * Cores are encouraged to use the libretro-common filestream functions for file I/O, + * as they seamlessly integrate with VFS, deal with directory separator replacement as appropriate + * and provide platform-specific fallbacks in cases where front ends do not support VFS. */ + +/* Opaque file handle + * Introduced in VFS API v1 */ +struct retro_vfs_file_handle; + +/* Opaque directory handle + * Introduced in VFS API v3 */ +struct retro_vfs_dir_handle; + +/* File open flags + * Introduced in VFS API v1 */ +#define RETRO_VFS_FILE_ACCESS_READ (1 << 0) /* Read only mode */ +#define RETRO_VFS_FILE_ACCESS_WRITE (1 << 1) /* Write only mode, discard contents and overwrites existing file unless RETRO_VFS_FILE_ACCESS_UPDATE is also specified */ +#define RETRO_VFS_FILE_ACCESS_READ_WRITE (RETRO_VFS_FILE_ACCESS_READ | RETRO_VFS_FILE_ACCESS_WRITE) /* Read-write mode, discard contents and overwrites existing file unless RETRO_VFS_FILE_ACCESS_UPDATE is also specified*/ +#define RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING (1 << 2) /* Prevents discarding content of existing files opened for writing */ + +/* These are only hints. The frontend may choose to ignore them. Other than RAM/CPU/etc use, + and how they react to unlikely external interference (for example someone else writing to that file, + or the file's server going down), behavior will not change. */ +#define RETRO_VFS_FILE_ACCESS_HINT_NONE (0) +/* Indicate that the file will be accessed many times. The frontend should aggressively cache everything. */ +#define RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS (1 << 0) + +/* Seek positions */ +#define RETRO_VFS_SEEK_POSITION_START 0 +#define RETRO_VFS_SEEK_POSITION_CURRENT 1 +#define RETRO_VFS_SEEK_POSITION_END 2 + +/* stat() result flags + * Introduced in VFS API v3 */ +#define RETRO_VFS_STAT_IS_VALID (1 << 0) +#define RETRO_VFS_STAT_IS_DIRECTORY (1 << 1) +#define RETRO_VFS_STAT_IS_CHARACTER_SPECIAL (1 << 2) + +/* Get path from opaque handle. Returns the exact same path passed to file_open when getting the handle + * Introduced in VFS API v1 */ +typedef const char *(RETRO_CALLCONV *retro_vfs_get_path_t)(struct retro_vfs_file_handle *stream); + +/* Open a file for reading or writing. If path points to a directory, this will + * fail. Returns the opaque file handle, or NULL for error. + * Introduced in VFS API v1 */ +typedef struct retro_vfs_file_handle *(RETRO_CALLCONV *retro_vfs_open_t)(const char *path, unsigned mode, unsigned hints); + +/* Close the file and release its resources. Must be called if open_file returns non-NULL. Returns 0 on success, -1 on failure. + * Whether the call succeeds ot not, the handle passed as parameter becomes invalid and should no longer be used. + * Introduced in VFS API v1 */ +typedef int (RETRO_CALLCONV *retro_vfs_close_t)(struct retro_vfs_file_handle *stream); + +/* Return the size of the file in bytes, or -1 for error. + * Introduced in VFS API v1 */ +typedef int64_t (RETRO_CALLCONV *retro_vfs_size_t)(struct retro_vfs_file_handle *stream); + +/* Truncate file to specified size. Returns 0 on success or -1 on error + * Introduced in VFS API v2 */ +typedef int64_t (RETRO_CALLCONV *retro_vfs_truncate_t)(struct retro_vfs_file_handle *stream, int64_t length); + +/* Get the current read / write position for the file. Returns -1 for error. + * Introduced in VFS API v1 */ +typedef int64_t (RETRO_CALLCONV *retro_vfs_tell_t)(struct retro_vfs_file_handle *stream); + +/* Set the current read/write position for the file. Returns the new position, -1 for error. + * Introduced in VFS API v1 */ +typedef int64_t (RETRO_CALLCONV *retro_vfs_seek_t)(struct retro_vfs_file_handle *stream, int64_t offset, int seek_position); + +/* Read data from a file. Returns the number of bytes read, or -1 for error. + * Introduced in VFS API v1 */ +typedef int64_t (RETRO_CALLCONV *retro_vfs_read_t)(struct retro_vfs_file_handle *stream, void *s, uint64_t len); + +/* Write data to a file. Returns the number of bytes written, or -1 for error. + * Introduced in VFS API v1 */ +typedef int64_t (RETRO_CALLCONV *retro_vfs_write_t)(struct retro_vfs_file_handle *stream, const void *s, uint64_t len); + +/* Flush pending writes to file, if using buffered IO. Returns 0 on sucess, or -1 on failure. + * Introduced in VFS API v1 */ +typedef int (RETRO_CALLCONV *retro_vfs_flush_t)(struct retro_vfs_file_handle *stream); + +/* Delete the specified file. Returns 0 on success, -1 on failure + * Introduced in VFS API v1 */ +typedef int (RETRO_CALLCONV *retro_vfs_remove_t)(const char *path); + +/* Rename the specified file. Returns 0 on success, -1 on failure + * Introduced in VFS API v1 */ +typedef int (RETRO_CALLCONV *retro_vfs_rename_t)(const char *old_path, const char *new_path); + +/* Stat the specified file. Retruns a bitmask of RETRO_VFS_STAT_* flags, none are set if path was not valid. + * Additionally stores file size in given variable, unless NULL is given. + * Introduced in VFS API v3 */ +typedef int (RETRO_CALLCONV *retro_vfs_stat_t)(const char *path, int32_t *size); + +/* Create the specified directory. Returns 0 on success, -1 on unknown failure, -2 if already exists. + * Introduced in VFS API v3 */ +typedef int (RETRO_CALLCONV *retro_vfs_mkdir_t)(const char *dir); + +/* Open the specified directory for listing. Returns the opaque dir handle, or NULL for error. + * Support for the include_hidden argument may vary depending on the platform. + * Introduced in VFS API v3 */ +typedef struct retro_vfs_dir_handle *(RETRO_CALLCONV *retro_vfs_opendir_t)(const char *dir, bool include_hidden); + +/* Read the directory entry at the current position, and move the read pointer to the next position. + * Returns true on success, false if already on the last entry. + * Introduced in VFS API v3 */ +typedef bool (RETRO_CALLCONV *retro_vfs_readdir_t)(struct retro_vfs_dir_handle *dirstream); + +/* Get the name of the last entry read. Returns a string on success, or NULL for error. + * The returned string pointer is valid until the next call to readdir or closedir. + * Introduced in VFS API v3 */ +typedef const char *(RETRO_CALLCONV *retro_vfs_dirent_get_name_t)(struct retro_vfs_dir_handle *dirstream); + +/* Check if the last entry read was a directory. Returns true if it was, false otherwise (or on error). + * Introduced in VFS API v3 */ +typedef bool (RETRO_CALLCONV *retro_vfs_dirent_is_dir_t)(struct retro_vfs_dir_handle *dirstream); + +/* Close the directory and release its resources. Must be called if opendir returns non-NULL. Returns 0 on success, -1 on failure. + * Whether the call succeeds ot not, the handle passed as parameter becomes invalid and should no longer be used. + * Introduced in VFS API v3 */ +typedef int (RETRO_CALLCONV *retro_vfs_closedir_t)(struct retro_vfs_dir_handle *dirstream); + +struct retro_vfs_interface +{ + /* VFS API v1 */ + retro_vfs_get_path_t get_path; + retro_vfs_open_t open; + retro_vfs_close_t close; + retro_vfs_size_t size; + retro_vfs_tell_t tell; + retro_vfs_seek_t seek; + retro_vfs_read_t read; + retro_vfs_write_t write; + retro_vfs_flush_t flush; + retro_vfs_remove_t remove; + retro_vfs_rename_t rename; + /* VFS API v2 */ + retro_vfs_truncate_t truncate; + /* VFS API v3 */ + retro_vfs_stat_t stat; + retro_vfs_mkdir_t mkdir; + retro_vfs_opendir_t opendir; + retro_vfs_readdir_t readdir; + retro_vfs_dirent_get_name_t dirent_get_name; + retro_vfs_dirent_is_dir_t dirent_is_dir; + retro_vfs_closedir_t closedir; +}; + +struct retro_vfs_interface_info +{ + /* Set by core: should this be higher than the version the front end supports, + * front end will return false in the RETRO_ENVIRONMENT_GET_VFS_INTERFACE call + * Introduced in VFS API v1 */ + uint32_t required_interface_version; + + /* Frontend writes interface pointer here. The frontend also sets the actual + * version, must be at least required_interface_version. + * Introduced in VFS API v1 */ + struct retro_vfs_interface *iface; +}; + +enum retro_hw_render_interface_type +{ + RETRO_HW_RENDER_INTERFACE_VULKAN = 0, + RETRO_HW_RENDER_INTERFACE_D3D9 = 1, + RETRO_HW_RENDER_INTERFACE_D3D10 = 2, + RETRO_HW_RENDER_INTERFACE_D3D11 = 3, + RETRO_HW_RENDER_INTERFACE_D3D12 = 4, + RETRO_HW_RENDER_INTERFACE_GSKIT_PS2 = 5, + RETRO_HW_RENDER_INTERFACE_DUMMY = INT_MAX +}; + +/* Base struct. All retro_hw_render_interface_* types + * contain at least these fields. */ +struct retro_hw_render_interface +{ + enum retro_hw_render_interface_type interface_type; + unsigned interface_version; +}; + +typedef void (RETRO_CALLCONV *retro_set_led_state_t)(int led, int state); +struct retro_led_interface +{ + retro_set_led_state_t set_led_state; +}; + +/* Retrieves the current state of the MIDI input. + * Returns true if it's enabled, false otherwise. */ +typedef bool (RETRO_CALLCONV *retro_midi_input_enabled_t)(void); + +/* Retrieves the current state of the MIDI output. + * Returns true if it's enabled, false otherwise */ +typedef bool (RETRO_CALLCONV *retro_midi_output_enabled_t)(void); + +/* Reads next byte from the input stream. + * Returns true if byte is read, false otherwise. */ +typedef bool (RETRO_CALLCONV *retro_midi_read_t)(uint8_t *byte); + +/* Writes byte to the output stream. + * 'delta_time' is in microseconds and represent time elapsed since previous write. + * Returns true if byte is written, false otherwise. */ +typedef bool (RETRO_CALLCONV *retro_midi_write_t)(uint8_t byte, uint32_t delta_time); + +/* Flushes previously written data. + * Returns true if successful, false otherwise. */ +typedef bool (RETRO_CALLCONV *retro_midi_flush_t)(void); + +struct retro_midi_interface +{ + retro_midi_input_enabled_t input_enabled; + retro_midi_output_enabled_t output_enabled; + retro_midi_read_t read; + retro_midi_write_t write; + retro_midi_flush_t flush; +}; + +enum retro_hw_render_context_negotiation_interface_type +{ + RETRO_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_VULKAN = 0, + RETRO_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_DUMMY = INT_MAX +}; + +/* Base struct. All retro_hw_render_context_negotiation_interface_* types + * contain at least these fields. */ +struct retro_hw_render_context_negotiation_interface +{ + enum retro_hw_render_context_negotiation_interface_type interface_type; + unsigned interface_version; +}; + +/* Serialized state is incomplete in some way. Set if serialization is + * usable in typical end-user cases but should not be relied upon to + * implement frame-sensitive frontend features such as netplay or + * rerecording. */ +#define RETRO_SERIALIZATION_QUIRK_INCOMPLETE (1 << 0) +/* The core must spend some time initializing before serialization is + * supported. retro_serialize() will initially fail; retro_unserialize() + * and retro_serialize_size() may or may not work correctly either. */ +#define RETRO_SERIALIZATION_QUIRK_MUST_INITIALIZE (1 << 1) +/* Serialization size may change within a session. */ +#define RETRO_SERIALIZATION_QUIRK_CORE_VARIABLE_SIZE (1 << 2) +/* Set by the frontend to acknowledge that it supports variable-sized + * states. */ +#define RETRO_SERIALIZATION_QUIRK_FRONT_VARIABLE_SIZE (1 << 3) +/* Serialized state can only be loaded during the same session. */ +#define RETRO_SERIALIZATION_QUIRK_SINGLE_SESSION (1 << 4) +/* Serialized state cannot be loaded on an architecture with a different + * endianness from the one it was saved on. */ +#define RETRO_SERIALIZATION_QUIRK_ENDIAN_DEPENDENT (1 << 5) +/* Serialized state cannot be loaded on a different platform from the one it + * was saved on for reasons other than endianness, such as word size + * dependence */ +#define RETRO_SERIALIZATION_QUIRK_PLATFORM_DEPENDENT (1 << 6) + +#define RETRO_MEMDESC_CONST (1 << 0) /* The frontend will never change this memory area once retro_load_game has returned. */ +#define RETRO_MEMDESC_BIGENDIAN (1 << 1) /* The memory area contains big endian data. Default is little endian. */ +#define RETRO_MEMDESC_SYSTEM_RAM (1 << 2) /* The memory area is system RAM. This is main RAM of the gaming system. */ +#define RETRO_MEMDESC_SAVE_RAM (1 << 3) /* The memory area is save RAM. This RAM is usually found on a game cartridge, backed up by a battery. */ +#define RETRO_MEMDESC_VIDEO_RAM (1 << 4) /* The memory area is video RAM (VRAM) */ +#define RETRO_MEMDESC_ALIGN_2 (1 << 16) /* All memory access in this area is aligned to their own size, or 2, whichever is smaller. */ +#define RETRO_MEMDESC_ALIGN_4 (2 << 16) +#define RETRO_MEMDESC_ALIGN_8 (3 << 16) +#define RETRO_MEMDESC_MINSIZE_2 (1 << 24) /* All memory in this region is accessed at least 2 bytes at the time. */ +#define RETRO_MEMDESC_MINSIZE_4 (2 << 24) +#define RETRO_MEMDESC_MINSIZE_8 (3 << 24) +struct retro_memory_descriptor +{ + uint64_t flags; + + /* Pointer to the start of the relevant ROM or RAM chip. + * It's strongly recommended to use 'offset' if possible, rather than + * doing math on the pointer. + * + * If the same byte is mapped my multiple descriptors, their descriptors + * must have the same pointer. + * If 'start' does not point to the first byte in the pointer, put the + * difference in 'offset' instead. + * + * May be NULL if there's nothing usable here (e.g. hardware registers and + * open bus). No flags should be set if the pointer is NULL. + * It's recommended to minimize the number of descriptors if possible, + * but not mandatory. */ + void *ptr; + size_t offset; + + /* This is the location in the emulated address space + * where the mapping starts. */ + size_t start; + + /* Which bits must be same as in 'start' for this mapping to apply. + * The first memory descriptor to claim a certain byte is the one + * that applies. + * A bit which is set in 'start' must also be set in this. + * Can be zero, in which case each byte is assumed mapped exactly once. + * In this case, 'len' must be a power of two. */ + size_t select; + + /* If this is nonzero, the set bits are assumed not connected to the + * memory chip's address pins. */ + size_t disconnect; + + /* This one tells the size of the current memory area. + * If, after start+disconnect are applied, the address is higher than + * this, the highest bit of the address is cleared. + * + * If the address is still too high, the next highest bit is cleared. + * Can be zero, in which case it's assumed to be infinite (as limited + * by 'select' and 'disconnect'). */ + size_t len; + + /* To go from emulated address to physical address, the following + * order applies: + * Subtract 'start', pick off 'disconnect', apply 'len', add 'offset'. */ + + /* The address space name must consist of only a-zA-Z0-9_-, + * should be as short as feasible (maximum length is 8 plus the NUL), + * and may not be any other address space plus one or more 0-9A-F + * at the end. + * However, multiple memory descriptors for the same address space is + * allowed, and the address space name can be empty. NULL is treated + * as empty. + * + * Address space names are case sensitive, but avoid lowercase if possible. + * The same pointer may exist in multiple address spaces. + * + * Examples: + * blank+blank - valid (multiple things may be mapped in the same namespace) + * 'Sp'+'Sp' - valid (multiple things may be mapped in the same namespace) + * 'A'+'B' - valid (neither is a prefix of each other) + * 'S'+blank - valid ('S' is not in 0-9A-F) + * 'a'+blank - valid ('a' is not in 0-9A-F) + * 'a'+'A' - valid (neither is a prefix of each other) + * 'AR'+blank - valid ('R' is not in 0-9A-F) + * 'ARB'+blank - valid (the B can't be part of the address either, because + * there is no namespace 'AR') + * blank+'B' - not valid, because it's ambigous which address space B1234 + * would refer to. + * The length can't be used for that purpose; the frontend may want + * to append arbitrary data to an address, without a separator. */ + const char *addrspace; + + /* TODO: When finalizing this one, add a description field, which should be + * "WRAM" or something roughly equally long. */ + + /* TODO: When finalizing this one, replace 'select' with 'limit', which tells + * which bits can vary and still refer to the same address (limit = ~select). + * TODO: limit? range? vary? something else? */ + + /* TODO: When finalizing this one, if 'len' is above what 'select' (or + * 'limit') allows, it's bankswitched. Bankswitched data must have both 'len' + * and 'select' != 0, and the mappings don't tell how the system switches the + * banks. */ + + /* TODO: When finalizing this one, fix the 'len' bit removal order. + * For len=0x1800, pointer 0x1C00 should go to 0x1400, not 0x0C00. + * Algorithm: Take bits highest to lowest, but if it goes above len, clear + * the most recent addition and continue on the next bit. + * TODO: Can the above be optimized? Is "remove the lowest bit set in both + * pointer and 'len'" equivalent? */ + + /* TODO: Some emulators (MAME?) emulate big endian systems by only accessing + * the emulated memory in 32-bit chunks, native endian. But that's nothing + * compared to Darek Mihocka + * (section Emulation 103 - Nearly Free Byte Reversal) - he flips the ENTIRE + * RAM backwards! I'll want to represent both of those, via some flags. + * + * I suspect MAME either didn't think of that idea, or don't want the #ifdef. + * Not sure which, nor do I really care. */ + + /* TODO: Some of those flags are unused and/or don't really make sense. Clean + * them up. */ +}; + +/* The frontend may use the largest value of 'start'+'select' in a + * certain namespace to infer the size of the address space. + * + * If the address space is larger than that, a mapping with .ptr=NULL + * should be at the end of the array, with .select set to all ones for + * as long as the address space is big. + * + * Sample descriptors (minus .ptr, and RETRO_MEMFLAG_ on the flags): + * SNES WRAM: + * .start=0x7E0000, .len=0x20000 + * (Note that this must be mapped before the ROM in most cases; some of the + * ROM mappers + * try to claim $7E0000, or at least $7E8000.) + * SNES SPC700 RAM: + * .addrspace="S", .len=0x10000 + * SNES WRAM mirrors: + * .flags=MIRROR, .start=0x000000, .select=0xC0E000, .len=0x2000 + * .flags=MIRROR, .start=0x800000, .select=0xC0E000, .len=0x2000 + * SNES WRAM mirrors, alternate equivalent descriptor: + * .flags=MIRROR, .select=0x40E000, .disconnect=~0x1FFF + * (Various similar constructions can be created by combining parts of + * the above two.) + * SNES LoROM (512KB, mirrored a couple of times): + * .flags=CONST, .start=0x008000, .select=0x408000, .disconnect=0x8000, .len=512*1024 + * .flags=CONST, .start=0x400000, .select=0x400000, .disconnect=0x8000, .len=512*1024 + * SNES HiROM (4MB): + * .flags=CONST, .start=0x400000, .select=0x400000, .len=4*1024*1024 + * .flags=CONST, .offset=0x8000, .start=0x008000, .select=0x408000, .len=4*1024*1024 + * SNES ExHiROM (8MB): + * .flags=CONST, .offset=0, .start=0xC00000, .select=0xC00000, .len=4*1024*1024 + * .flags=CONST, .offset=4*1024*1024, .start=0x400000, .select=0xC00000, .len=4*1024*1024 + * .flags=CONST, .offset=0x8000, .start=0x808000, .select=0xC08000, .len=4*1024*1024 + * .flags=CONST, .offset=4*1024*1024+0x8000, .start=0x008000, .select=0xC08000, .len=4*1024*1024 + * Clarify the size of the address space: + * .ptr=NULL, .select=0xFFFFFF + * .len can be implied by .select in many of them, but was included for clarity. + */ + +struct retro_memory_map +{ + const struct retro_memory_descriptor *descriptors; + unsigned num_descriptors; +}; + +struct retro_controller_description +{ + /* Human-readable description of the controller. Even if using a generic + * input device type, this can be set to the particular device type the + * core uses. */ + const char *desc; + + /* Device type passed to retro_set_controller_port_device(). If the device + * type is a sub-class of a generic input device type, use the + * RETRO_DEVICE_SUBCLASS macro to create an ID. + * + * E.g. RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_JOYPAD, 1). */ + unsigned id; +}; + +struct retro_controller_info +{ + const struct retro_controller_description *types; + unsigned num_types; +}; + +struct retro_subsystem_memory_info +{ + /* The extension associated with a memory type, e.g. "psram". */ + const char *extension; + + /* The memory type for retro_get_memory(). This should be at + * least 0x100 to avoid conflict with standardized + * libretro memory types. */ + unsigned type; +}; + +struct retro_subsystem_rom_info +{ + /* Describes what the content is (SGB BIOS, GB ROM, etc). */ + const char *desc; + + /* Same definition as retro_get_system_info(). */ + const char *valid_extensions; + + /* Same definition as retro_get_system_info(). */ + bool need_fullpath; + + /* Same definition as retro_get_system_info(). */ + bool block_extract; + + /* This is set if the content is required to load a game. + * If this is set to false, a zeroed-out retro_game_info can be passed. */ + bool required; + + /* Content can have multiple associated persistent + * memory types (retro_get_memory()). */ + const struct retro_subsystem_memory_info *memory; + unsigned num_memory; +}; + +struct retro_subsystem_info +{ + /* Human-readable string of the subsystem type, e.g. "Super GameBoy" */ + const char *desc; + + /* A computer friendly short string identifier for the subsystem type. + * This name must be [a-z]. + * E.g. if desc is "Super GameBoy", this can be "sgb". + * This identifier can be used for command-line interfaces, etc. + */ + const char *ident; + + /* Infos for each content file. The first entry is assumed to be the + * "most significant" content for frontend purposes. + * E.g. with Super GameBoy, the first content should be the GameBoy ROM, + * as it is the most "significant" content to a user. + * If a frontend creates new file paths based on the content used + * (e.g. savestates), it should use the path for the first ROM to do so. */ + const struct retro_subsystem_rom_info *roms; + + /* Number of content files associated with a subsystem. */ + unsigned num_roms; + + /* The type passed to retro_load_game_special(). */ + unsigned id; +}; + +typedef void (RETRO_CALLCONV *retro_proc_address_t)(void); + +/* libretro API extension functions: + * (None here so far). + * + * Get a symbol from a libretro core. + * Cores should only return symbols which are actual + * extensions to the libretro API. + * + * Frontends should not use this to obtain symbols to standard + * libretro entry points (static linking or dlsym). + * + * The symbol name must be equal to the function name, + * e.g. if void retro_foo(void); exists, the symbol must be called "retro_foo". + * The returned function pointer must be cast to the corresponding type. + */ +typedef retro_proc_address_t (RETRO_CALLCONV *retro_get_proc_address_t)(const char *sym); + +struct retro_get_proc_address_interface +{ + retro_get_proc_address_t get_proc_address; +}; + +enum retro_log_level +{ + RETRO_LOG_DEBUG = 0, + RETRO_LOG_INFO, + RETRO_LOG_WARN, + RETRO_LOG_ERROR, + + RETRO_LOG_DUMMY = INT_MAX +}; + +/* Logging function. Takes log level argument as well. */ +typedef void (RETRO_CALLCONV *retro_log_printf_t)(enum retro_log_level level, + const char *fmt, ...); + +struct retro_log_callback +{ + retro_log_printf_t log; +}; + +/* Performance related functions */ + +/* ID values for SIMD CPU features */ +#define RETRO_SIMD_SSE (1 << 0) +#define RETRO_SIMD_SSE2 (1 << 1) +#define RETRO_SIMD_VMX (1 << 2) +#define RETRO_SIMD_VMX128 (1 << 3) +#define RETRO_SIMD_AVX (1 << 4) +#define RETRO_SIMD_NEON (1 << 5) +#define RETRO_SIMD_SSE3 (1 << 6) +#define RETRO_SIMD_SSSE3 (1 << 7) +#define RETRO_SIMD_MMX (1 << 8) +#define RETRO_SIMD_MMXEXT (1 << 9) +#define RETRO_SIMD_SSE4 (1 << 10) +#define RETRO_SIMD_SSE42 (1 << 11) +#define RETRO_SIMD_AVX2 (1 << 12) +#define RETRO_SIMD_VFPU (1 << 13) +#define RETRO_SIMD_PS (1 << 14) +#define RETRO_SIMD_AES (1 << 15) +#define RETRO_SIMD_VFPV3 (1 << 16) +#define RETRO_SIMD_VFPV4 (1 << 17) +#define RETRO_SIMD_POPCNT (1 << 18) +#define RETRO_SIMD_MOVBE (1 << 19) +#define RETRO_SIMD_CMOV (1 << 20) +#define RETRO_SIMD_ASIMD (1 << 21) + +typedef uint64_t retro_perf_tick_t; +typedef int64_t retro_time_t; + +struct retro_perf_counter +{ + const char *ident; + retro_perf_tick_t start; + retro_perf_tick_t total; + retro_perf_tick_t call_cnt; + + bool registered; +}; + +/* Returns current time in microseconds. + * Tries to use the most accurate timer available. + */ +typedef retro_time_t (RETRO_CALLCONV *retro_perf_get_time_usec_t)(void); + +/* A simple counter. Usually nanoseconds, but can also be CPU cycles. + * Can be used directly if desired (when creating a more sophisticated + * performance counter system). + * */ +typedef retro_perf_tick_t (RETRO_CALLCONV *retro_perf_get_counter_t)(void); + +/* Returns a bit-mask of detected CPU features (RETRO_SIMD_*). */ +typedef uint64_t (RETRO_CALLCONV *retro_get_cpu_features_t)(void); + +/* Asks frontend to log and/or display the state of performance counters. + * Performance counters can always be poked into manually as well. + */ +typedef void (RETRO_CALLCONV *retro_perf_log_t)(void); + +/* Register a performance counter. + * ident field must be set with a discrete value and other values in + * retro_perf_counter must be 0. + * Registering can be called multiple times. To avoid calling to + * frontend redundantly, you can check registered field first. */ +typedef void (RETRO_CALLCONV *retro_perf_register_t)(struct retro_perf_counter *counter); + +/* Starts a registered counter. */ +typedef void (RETRO_CALLCONV *retro_perf_start_t)(struct retro_perf_counter *counter); + +/* Stops a registered counter. */ +typedef void (RETRO_CALLCONV *retro_perf_stop_t)(struct retro_perf_counter *counter); + +/* For convenience it can be useful to wrap register, start and stop in macros. + * E.g.: + * #ifdef LOG_PERFORMANCE + * #define RETRO_PERFORMANCE_INIT(perf_cb, name) static struct retro_perf_counter name = {#name}; if (!name.registered) perf_cb.perf_register(&(name)) + * #define RETRO_PERFORMANCE_START(perf_cb, name) perf_cb.perf_start(&(name)) + * #define RETRO_PERFORMANCE_STOP(perf_cb, name) perf_cb.perf_stop(&(name)) + * #else + * ... Blank macros ... + * #endif + * + * These can then be used mid-functions around code snippets. + * + * extern struct retro_perf_callback perf_cb; * Somewhere in the core. + * + * void do_some_heavy_work(void) + * { + * RETRO_PERFORMANCE_INIT(cb, work_1; + * RETRO_PERFORMANCE_START(cb, work_1); + * heavy_work_1(); + * RETRO_PERFORMANCE_STOP(cb, work_1); + * + * RETRO_PERFORMANCE_INIT(cb, work_2); + * RETRO_PERFORMANCE_START(cb, work_2); + * heavy_work_2(); + * RETRO_PERFORMANCE_STOP(cb, work_2); + * } + * + * void retro_deinit(void) + * { + * perf_cb.perf_log(); * Log all perf counters here for example. + * } + */ + +struct retro_perf_callback +{ + retro_perf_get_time_usec_t get_time_usec; + retro_get_cpu_features_t get_cpu_features; + + retro_perf_get_counter_t get_perf_counter; + retro_perf_register_t perf_register; + retro_perf_start_t perf_start; + retro_perf_stop_t perf_stop; + retro_perf_log_t perf_log; +}; + +/* FIXME: Document the sensor API and work out behavior. + * It will be marked as experimental until then. + */ +enum retro_sensor_action +{ + RETRO_SENSOR_ACCELEROMETER_ENABLE = 0, + RETRO_SENSOR_ACCELEROMETER_DISABLE, + RETRO_SENSOR_GYROSCOPE_ENABLE, + RETRO_SENSOR_GYROSCOPE_DISABLE, + RETRO_SENSOR_ILLUMINANCE_ENABLE, + RETRO_SENSOR_ILLUMINANCE_DISABLE, + + RETRO_SENSOR_DUMMY = INT_MAX +}; + +/* Id values for SENSOR types. */ +#define RETRO_SENSOR_ACCELEROMETER_X 0 +#define RETRO_SENSOR_ACCELEROMETER_Y 1 +#define RETRO_SENSOR_ACCELEROMETER_Z 2 +#define RETRO_SENSOR_GYROSCOPE_X 3 +#define RETRO_SENSOR_GYROSCOPE_Y 4 +#define RETRO_SENSOR_GYROSCOPE_Z 5 +#define RETRO_SENSOR_ILLUMINANCE 6 + +typedef bool (RETRO_CALLCONV *retro_set_sensor_state_t)(unsigned port, + enum retro_sensor_action action, unsigned rate); + +typedef float (RETRO_CALLCONV *retro_sensor_get_input_t)(unsigned port, unsigned id); + +struct retro_sensor_interface +{ + retro_set_sensor_state_t set_sensor_state; + retro_sensor_get_input_t get_sensor_input; +}; + +enum retro_camera_buffer +{ + RETRO_CAMERA_BUFFER_OPENGL_TEXTURE = 0, + RETRO_CAMERA_BUFFER_RAW_FRAMEBUFFER, + + RETRO_CAMERA_BUFFER_DUMMY = INT_MAX +}; + +/* Starts the camera driver. Can only be called in retro_run(). */ +typedef bool (RETRO_CALLCONV *retro_camera_start_t)(void); + +/* Stops the camera driver. Can only be called in retro_run(). */ +typedef void (RETRO_CALLCONV *retro_camera_stop_t)(void); + +/* Callback which signals when the camera driver is initialized + * and/or deinitialized. + * retro_camera_start_t can be called in initialized callback. + */ +typedef void (RETRO_CALLCONV *retro_camera_lifetime_status_t)(void); + +/* A callback for raw framebuffer data. buffer points to an XRGB8888 buffer. + * Width, height and pitch are similar to retro_video_refresh_t. + * First pixel is top-left origin. + */ +typedef void (RETRO_CALLCONV *retro_camera_frame_raw_framebuffer_t)(const uint32_t *buffer, + unsigned width, unsigned height, size_t pitch); + +/* A callback for when OpenGL textures are used. + * + * texture_id is a texture owned by camera driver. + * Its state or content should be considered immutable, except for things like + * texture filtering and clamping. + * + * texture_target is the texture target for the GL texture. + * These can include e.g. GL_TEXTURE_2D, GL_TEXTURE_RECTANGLE, and possibly + * more depending on extensions. + * + * affine points to a packed 3x3 column-major matrix used to apply an affine + * transform to texture coordinates. (affine_matrix * vec3(coord_x, coord_y, 1.0)) + * After transform, normalized texture coord (0, 0) should be bottom-left + * and (1, 1) should be top-right (or (width, height) for RECTANGLE). + * + * GL-specific typedefs are avoided here to avoid relying on gl.h in + * the API definition. + */ +typedef void (RETRO_CALLCONV *retro_camera_frame_opengl_texture_t)(unsigned texture_id, + unsigned texture_target, const float *affine); + +struct retro_camera_callback +{ + /* Set by libretro core. + * Example bitmask: caps = (1 << RETRO_CAMERA_BUFFER_OPENGL_TEXTURE) | (1 << RETRO_CAMERA_BUFFER_RAW_FRAMEBUFFER). + */ + uint64_t caps; + + /* Desired resolution for camera. Is only used as a hint. */ + unsigned width; + unsigned height; + + /* Set by frontend. */ + retro_camera_start_t start; + retro_camera_stop_t stop; + + /* Set by libretro core if raw framebuffer callbacks will be used. */ + retro_camera_frame_raw_framebuffer_t frame_raw_framebuffer; + + /* Set by libretro core if OpenGL texture callbacks will be used. */ + retro_camera_frame_opengl_texture_t frame_opengl_texture; + + /* Set by libretro core. Called after camera driver is initialized and + * ready to be started. + * Can be NULL, in which this callback is not called. + */ + retro_camera_lifetime_status_t initialized; + + /* Set by libretro core. Called right before camera driver is + * deinitialized. + * Can be NULL, in which this callback is not called. + */ + retro_camera_lifetime_status_t deinitialized; +}; + +/* Sets the interval of time and/or distance at which to update/poll + * location-based data. + * + * To ensure compatibility with all location-based implementations, + * values for both interval_ms and interval_distance should be provided. + * + * interval_ms is the interval expressed in milliseconds. + * interval_distance is the distance interval expressed in meters. + */ +typedef void (RETRO_CALLCONV *retro_location_set_interval_t)(unsigned interval_ms, + unsigned interval_distance); + +/* Start location services. The device will start listening for changes to the + * current location at regular intervals (which are defined with + * retro_location_set_interval_t). */ +typedef bool (RETRO_CALLCONV *retro_location_start_t)(void); + +/* Stop location services. The device will stop listening for changes + * to the current location. */ +typedef void (RETRO_CALLCONV *retro_location_stop_t)(void); + +/* Get the position of the current location. Will set parameters to + * 0 if no new location update has happened since the last time. */ +typedef bool (RETRO_CALLCONV *retro_location_get_position_t)(double *lat, double *lon, + double *horiz_accuracy, double *vert_accuracy); + +/* Callback which signals when the location driver is initialized + * and/or deinitialized. + * retro_location_start_t can be called in initialized callback. + */ +typedef void (RETRO_CALLCONV *retro_location_lifetime_status_t)(void); + +struct retro_location_callback +{ + retro_location_start_t start; + retro_location_stop_t stop; + retro_location_get_position_t get_position; + retro_location_set_interval_t set_interval; + + retro_location_lifetime_status_t initialized; + retro_location_lifetime_status_t deinitialized; +}; + +enum retro_rumble_effect +{ + RETRO_RUMBLE_STRONG = 0, + RETRO_RUMBLE_WEAK = 1, + + RETRO_RUMBLE_DUMMY = INT_MAX +}; + +/* Sets rumble state for joypad plugged in port 'port'. + * Rumble effects are controlled independently, + * and setting e.g. strong rumble does not override weak rumble. + * Strength has a range of [0, 0xffff]. + * + * Returns true if rumble state request was honored. + * Calling this before first retro_run() is likely to return false. */ +typedef bool (RETRO_CALLCONV *retro_set_rumble_state_t)(unsigned port, + enum retro_rumble_effect effect, uint16_t strength); + +struct retro_rumble_interface +{ + retro_set_rumble_state_t set_rumble_state; +}; + +/* Notifies libretro that audio data should be written. */ +typedef void (RETRO_CALLCONV *retro_audio_callback_t)(void); + +/* True: Audio driver in frontend is active, and callback is + * expected to be called regularily. + * False: Audio driver in frontend is paused or inactive. + * Audio callback will not be called until set_state has been + * called with true. + * Initial state is false (inactive). + */ +typedef void (RETRO_CALLCONV *retro_audio_set_state_callback_t)(bool enabled); + +struct retro_audio_callback +{ + retro_audio_callback_t callback; + retro_audio_set_state_callback_t set_state; +}; + +/* Notifies a libretro core of time spent since last invocation + * of retro_run() in microseconds. + * + * It will be called right before retro_run() every frame. + * The frontend can tamper with timing to support cases like + * fast-forward, slow-motion and framestepping. + * + * In those scenarios the reference frame time value will be used. */ +typedef int64_t retro_usec_t; +typedef void (RETRO_CALLCONV *retro_frame_time_callback_t)(retro_usec_t usec); +struct retro_frame_time_callback +{ + retro_frame_time_callback_t callback; + /* Represents the time of one frame. It is computed as + * 1000000 / fps, but the implementation will resolve the + * rounding to ensure that framestepping, etc is exact. */ + retro_usec_t reference; +}; + +/* Pass this to retro_video_refresh_t if rendering to hardware. + * Passing NULL to retro_video_refresh_t is still a frame dupe as normal. + * */ +#define RETRO_HW_FRAME_BUFFER_VALID ((void*)-1) + +/* Invalidates the current HW context. + * Any GL state is lost, and must not be deinitialized explicitly. + * If explicit deinitialization is desired by the libretro core, + * it should implement context_destroy callback. + * If called, all GPU resources must be reinitialized. + * Usually called when frontend reinits video driver. + * Also called first time video driver is initialized, + * allowing libretro core to initialize resources. + */ +typedef void (RETRO_CALLCONV *retro_hw_context_reset_t)(void); + +/* Gets current framebuffer which is to be rendered to. + * Could change every frame potentially. + */ +typedef uintptr_t (RETRO_CALLCONV *retro_hw_get_current_framebuffer_t)(void); + +/* Get a symbol from HW context. */ +typedef retro_proc_address_t (RETRO_CALLCONV *retro_hw_get_proc_address_t)(const char *sym); + +enum retro_hw_context_type +{ + RETRO_HW_CONTEXT_NONE = 0, + /* OpenGL 2.x. Driver can choose to use latest compatibility context. */ + RETRO_HW_CONTEXT_OPENGL = 1, + /* OpenGL ES 2.0. */ + RETRO_HW_CONTEXT_OPENGLES2 = 2, + /* Modern desktop core GL context. Use version_major/ + * version_minor fields to set GL version. */ + RETRO_HW_CONTEXT_OPENGL_CORE = 3, + /* OpenGL ES 3.0 */ + RETRO_HW_CONTEXT_OPENGLES3 = 4, + /* OpenGL ES 3.1+. Set version_major/version_minor. For GLES2 and GLES3, + * use the corresponding enums directly. */ + RETRO_HW_CONTEXT_OPENGLES_VERSION = 5, + + /* Vulkan, see RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE. */ + RETRO_HW_CONTEXT_VULKAN = 6, + + /* Direct3D, set version_major to select the type of interface + * returned by RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE */ + RETRO_HW_CONTEXT_DIRECT3D = 7, + + RETRO_HW_CONTEXT_DUMMY = INT_MAX +}; + +struct retro_hw_render_callback +{ + /* Which API to use. Set by libretro core. */ + enum retro_hw_context_type context_type; + + /* Called when a context has been created or when it has been reset. + * An OpenGL context is only valid after context_reset() has been called. + * + * When context_reset is called, OpenGL resources in the libretro + * implementation are guaranteed to be invalid. + * + * It is possible that context_reset is called multiple times during an + * application lifecycle. + * If context_reset is called without any notification (context_destroy), + * the OpenGL context was lost and resources should just be recreated + * without any attempt to "free" old resources. + */ + retro_hw_context_reset_t context_reset; + + /* Set by frontend. + * TODO: This is rather obsolete. The frontend should not + * be providing preallocated framebuffers. */ + retro_hw_get_current_framebuffer_t get_current_framebuffer; + + /* Set by frontend. + * Can return all relevant functions, including glClear on Windows. */ + retro_hw_get_proc_address_t get_proc_address; + + /* Set if render buffers should have depth component attached. + * TODO: Obsolete. */ + bool depth; + + /* Set if stencil buffers should be attached. + * TODO: Obsolete. */ + bool stencil; + + /* If depth and stencil are true, a packed 24/8 buffer will be added. + * Only attaching stencil is invalid and will be ignored. */ + + /* Use conventional bottom-left origin convention. If false, + * standard libretro top-left origin semantics are used. + * TODO: Move to GL specific interface. */ + bool bottom_left_origin; + + /* Major version number for core GL context or GLES 3.1+. */ + unsigned version_major; + + /* Minor version number for core GL context or GLES 3.1+. */ + unsigned version_minor; + + /* If this is true, the frontend will go very far to avoid + * resetting context in scenarios like toggling fullscreen, etc. + * TODO: Obsolete? Maybe frontend should just always assume this ... + */ + bool cache_context; + + /* The reset callback might still be called in extreme situations + * such as if the context is lost beyond recovery. + * + * For optimal stability, set this to false, and allow context to be + * reset at any time. + */ + + /* A callback to be called before the context is destroyed in a + * controlled way by the frontend. */ + retro_hw_context_reset_t context_destroy; + + /* OpenGL resources can be deinitialized cleanly at this step. + * context_destroy can be set to NULL, in which resources will + * just be destroyed without any notification. + * + * Even when context_destroy is non-NULL, it is possible that + * context_reset is called without any destroy notification. + * This happens if context is lost by external factors (such as + * notified by GL_ARB_robustness). + * + * In this case, the context is assumed to be already dead, + * and the libretro implementation must not try to free any OpenGL + * resources in the subsequent context_reset. + */ + + /* Creates a debug context. */ + bool debug_context; +}; + +/* Callback type passed in RETRO_ENVIRONMENT_SET_KEYBOARD_CALLBACK. + * Called by the frontend in response to keyboard events. + * down is set if the key is being pressed, or false if it is being released. + * keycode is the RETROK value of the char. + * character is the text character of the pressed key. (UTF-32). + * key_modifiers is a set of RETROKMOD values or'ed together. + * + * The pressed/keycode state can be indepedent of the character. + * It is also possible that multiple characters are generated from a + * single keypress. + * Keycode events should be treated separately from character events. + * However, when possible, the frontend should try to synchronize these. + * If only a character is posted, keycode should be RETROK_UNKNOWN. + * + * Similarily if only a keycode event is generated with no corresponding + * character, character should be 0. + */ +typedef void (RETRO_CALLCONV *retro_keyboard_event_t)(bool down, unsigned keycode, + uint32_t character, uint16_t key_modifiers); + +struct retro_keyboard_callback +{ + retro_keyboard_event_t callback; +}; + +/* Callbacks for RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE & + * RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE. + * Should be set for implementations which can swap out multiple disk + * images in runtime. + * + * If the implementation can do this automatically, it should strive to do so. + * However, there are cases where the user must manually do so. + * + * Overview: To swap a disk image, eject the disk image with + * set_eject_state(true). + * Set the disk index with set_image_index(index). Insert the disk again + * with set_eject_state(false). + */ + +/* If ejected is true, "ejects" the virtual disk tray. + * When ejected, the disk image index can be set. + */ +typedef bool (RETRO_CALLCONV *retro_set_eject_state_t)(bool ejected); + +/* Gets current eject state. The initial state is 'not ejected'. */ +typedef bool (RETRO_CALLCONV *retro_get_eject_state_t)(void); + +/* Gets current disk index. First disk is index 0. + * If return value is >= get_num_images(), no disk is currently inserted. + */ +typedef unsigned (RETRO_CALLCONV *retro_get_image_index_t)(void); + +/* Sets image index. Can only be called when disk is ejected. + * The implementation supports setting "no disk" by using an + * index >= get_num_images(). + */ +typedef bool (RETRO_CALLCONV *retro_set_image_index_t)(unsigned index); + +/* Gets total number of images which are available to use. */ +typedef unsigned (RETRO_CALLCONV *retro_get_num_images_t)(void); + +struct retro_game_info; + +/* Replaces the disk image associated with index. + * Arguments to pass in info have same requirements as retro_load_game(). + * Virtual disk tray must be ejected when calling this. + * + * Replacing a disk image with info = NULL will remove the disk image + * from the internal list. + * As a result, calls to get_image_index() can change. + * + * E.g. replace_image_index(1, NULL), and previous get_image_index() + * returned 4 before. + * Index 1 will be removed, and the new index is 3. + */ +typedef bool (RETRO_CALLCONV *retro_replace_image_index_t)(unsigned index, + const struct retro_game_info *info); + +/* Adds a new valid index (get_num_images()) to the internal disk list. + * This will increment subsequent return values from get_num_images() by 1. + * This image index cannot be used until a disk image has been set + * with replace_image_index. */ +typedef bool (RETRO_CALLCONV *retro_add_image_index_t)(void); + +/* Sets initial image to insert in drive when calling + * core_load_game(). + * Since we cannot pass the initial index when loading + * content (this would require a major API change), this + * is set by the frontend *before* calling the core's + * retro_load_game()/retro_load_game_special() implementation. + * A core should therefore cache the index/path values and handle + * them inside retro_load_game()/retro_load_game_special(). + * - If 'index' is invalid (index >= get_num_images()), the + * core should ignore the set value and instead use 0 + * - 'path' is used purely for error checking - i.e. when + * content is loaded, the core should verify that the + * disk specified by 'index' has the specified file path. + * This is to guard against auto selecting the wrong image + * if (for example) the user should modify an existing M3U + * playlist. We have to let the core handle this because + * set_initial_image() must be called before loading content, + * i.e. the frontend cannot access image paths in advance + * and thus cannot perform the error check itself. + * If set path and content path do not match, the core should + * ignore the set 'index' value and instead use 0 + * Returns 'false' if index or 'path' are invalid, or core + * does not support this functionality + */ +typedef bool (RETRO_CALLCONV *retro_set_initial_image_t)(unsigned index, const char *path); + +/* Fetches the path of the specified disk image file. + * Returns 'false' if index is invalid (index >= get_num_images()) + * or path is otherwise unavailable. + */ +typedef bool (RETRO_CALLCONV *retro_get_image_path_t)(unsigned index, char *path, size_t len); + +/* Fetches a core-provided 'label' for the specified disk + * image file. In the simplest case this may be a file name + * (without extension), but for cores with more complex + * content requirements information may be provided to + * facilitate user disk swapping - for example, a core + * running floppy-disk-based content may uniquely label + * save disks, data disks, level disks, etc. with names + * corresponding to in-game disk change prompts (so the + * frontend can provide better user guidance than a 'dumb' + * disk index value). + * Returns 'false' if index is invalid (index >= get_num_images()) + * or label is otherwise unavailable. + */ +typedef bool (RETRO_CALLCONV *retro_get_image_label_t)(unsigned index, char *label, size_t len); + +struct retro_disk_control_callback +{ + retro_set_eject_state_t set_eject_state; + retro_get_eject_state_t get_eject_state; + + retro_get_image_index_t get_image_index; + retro_set_image_index_t set_image_index; + retro_get_num_images_t get_num_images; + + retro_replace_image_index_t replace_image_index; + retro_add_image_index_t add_image_index; +}; + +struct retro_disk_control_ext_callback +{ + retro_set_eject_state_t set_eject_state; + retro_get_eject_state_t get_eject_state; + + retro_get_image_index_t get_image_index; + retro_set_image_index_t set_image_index; + retro_get_num_images_t get_num_images; + + retro_replace_image_index_t replace_image_index; + retro_add_image_index_t add_image_index; + + /* NOTE: Frontend will only attempt to record/restore + * last used disk index if both set_initial_image() + * and get_image_path() are implemented */ + retro_set_initial_image_t set_initial_image; /* Optional - may be NULL */ + + retro_get_image_path_t get_image_path; /* Optional - may be NULL */ + retro_get_image_label_t get_image_label; /* Optional - may be NULL */ +}; + +enum retro_pixel_format +{ + /* 0RGB1555, native endian. + * 0 bit must be set to 0. + * This pixel format is default for compatibility concerns only. + * If a 15/16-bit pixel format is desired, consider using RGB565. */ + RETRO_PIXEL_FORMAT_0RGB1555 = 0, + + /* XRGB8888, native endian. + * X bits are ignored. */ + RETRO_PIXEL_FORMAT_XRGB8888 = 1, + + /* RGB565, native endian. + * This pixel format is the recommended format to use if a 15/16-bit + * format is desired as it is the pixel format that is typically + * available on a wide range of low-power devices. + * + * It is also natively supported in APIs like OpenGL ES. */ + RETRO_PIXEL_FORMAT_RGB565 = 2, + + /* Ensure sizeof() == sizeof(int). */ + RETRO_PIXEL_FORMAT_UNKNOWN = INT_MAX +}; + +struct retro_message +{ + const char *msg; /* Message to be displayed. */ + unsigned frames; /* Duration in frames of message. */ +}; + +enum retro_message_target +{ + RETRO_MESSAGE_TARGET_ALL = 0, + RETRO_MESSAGE_TARGET_OSD, + RETRO_MESSAGE_TARGET_LOG +}; + +enum retro_message_type +{ + RETRO_MESSAGE_TYPE_NOTIFICATION = 0, + RETRO_MESSAGE_TYPE_NOTIFICATION_ALT, + RETRO_MESSAGE_TYPE_STATUS, + RETRO_MESSAGE_TYPE_PROGRESS +}; + +struct retro_message_ext +{ + /* Message string to be displayed/logged */ + const char *msg; + /* Duration (in ms) of message when targeting the OSD */ + unsigned duration; + /* Message priority when targeting the OSD + * > When multiple concurrent messages are sent to + * the frontend and the frontend does not have the + * capacity to display them all, messages with the + * *highest* priority value should be shown + * > There is no upper limit to a message priority + * value (within the bounds of the unsigned data type) + * > In the reference frontend (RetroArch), the same + * priority values are used for frontend-generated + * notifications, which are typically assigned values + * between 0 and 3 depending upon importance */ + unsigned priority; + /* Message logging level (info, warn, error, etc.) */ + enum retro_log_level level; + /* Message destination: OSD, logging interface or both */ + enum retro_message_target target; + /* Message 'type' when targeting the OSD + * > RETRO_MESSAGE_TYPE_NOTIFICATION: Specifies that a + * message should be handled in identical fashion to + * a standard frontend-generated notification + * > RETRO_MESSAGE_TYPE_NOTIFICATION_ALT: Specifies that + * message is a notification that requires user attention + * or action, but that it should be displayed in a manner + * that differs from standard frontend-generated notifications. + * This would typically correspond to messages that should be + * displayed immediately (independently from any internal + * frontend message queue), and/or which should be visually + * distinguishable from frontend-generated notifications. + * For example, a core may wish to inform the user of + * information related to a disk-change event. It is + * expected that the frontend itself may provide a + * notification in this case; if the core sends a + * message of type RETRO_MESSAGE_TYPE_NOTIFICATION, an + * uncomfortable 'double-notification' may occur. A message + * of RETRO_MESSAGE_TYPE_NOTIFICATION_ALT should therefore + * be presented such that visual conflict with regular + * notifications does not occur + * > RETRO_MESSAGE_TYPE_STATUS: Indicates that message + * is not a standard notification. This typically + * corresponds to 'status' indicators, such as a core's + * internal FPS, which are intended to be displayed + * either permanently while a core is running, or in + * a manner that does not suggest user attention or action + * is required. 'Status' type messages should therefore be + * displayed in a different on-screen location and in a manner + * easily distinguishable from both standard frontend-generated + * notifications and messages of type RETRO_MESSAGE_TYPE_NOTIFICATION_ALT + * > RETRO_MESSAGE_TYPE_PROGRESS: Indicates that message reports + * the progress of an internal core task. For example, in cases + * where a core itself handles the loading of content from a file, + * this may correspond to the percentage of the file that has been + * read. Alternatively, an audio/video playback core may use a + * message of type RETRO_MESSAGE_TYPE_PROGRESS to display the current + * playback position as a percentage of the runtime. 'Progress' type + * messages should therefore be displayed as a literal progress bar, + * where: + * - 'retro_message_ext.msg' is the progress bar title/label + * - 'retro_message_ext.progress' determines the length of + * the progress bar + * NOTE: Message type is a *hint*, and may be ignored + * by the frontend. If a frontend lacks support for + * displaying messages via alternate means than standard + * frontend-generated notifications, it will treat *all* + * messages as having the type RETRO_MESSAGE_TYPE_NOTIFICATION */ + enum retro_message_type type; + /* Task progress when targeting the OSD and message is + * of type RETRO_MESSAGE_TYPE_PROGRESS + * > -1: Unmetered/indeterminate + * > 0-100: Current progress percentage + * NOTE: Since message type is a hint, a frontend may ignore + * progress values. Where relevant, a core should therefore + * include progress percentage within the message string, + * such that the message intent remains clear when displayed + * as a standard frontend-generated notification */ + int8_t progress; +}; + +/* Describes how the libretro implementation maps a libretro input bind + * to its internal input system through a human readable string. + * This string can be used to better let a user configure input. */ +struct retro_input_descriptor +{ + /* Associates given parameters with a description. */ + unsigned port; + unsigned device; + unsigned index; + unsigned id; + + /* Human readable description for parameters. + * The pointer must remain valid until + * retro_unload_game() is called. */ + const char *description; +}; + +struct retro_system_info +{ + /* All pointers are owned by libretro implementation, and pointers must + * remain valid until retro_deinit() is called. */ + + const char *library_name; /* Descriptive name of library. Should not + * contain any version numbers, etc. */ + const char *library_version; /* Descriptive version of core. */ + + const char *valid_extensions; /* A string listing probably content + * extensions the core will be able to + * load, separated with pipe. + * I.e. "bin|rom|iso". + * Typically used for a GUI to filter + * out extensions. */ + + /* Libretro cores that need to have direct access to their content + * files, including cores which use the path of the content files to + * determine the paths of other files, should set need_fullpath to true. + * + * Cores should strive for setting need_fullpath to false, + * as it allows the frontend to perform patching, etc. + * + * If need_fullpath is true and retro_load_game() is called: + * - retro_game_info::path is guaranteed to have a valid path + * - retro_game_info::data and retro_game_info::size are invalid + * + * If need_fullpath is false and retro_load_game() is called: + * - retro_game_info::path may be NULL + * - retro_game_info::data and retro_game_info::size are guaranteed + * to be valid + * + * See also: + * - RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY + * - RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY + */ + bool need_fullpath; + + /* If true, the frontend is not allowed to extract any archives before + * loading the real content. + * Necessary for certain libretro implementations that load games + * from zipped archives. */ + bool block_extract; +}; + +struct retro_game_geometry +{ + unsigned base_width; /* Nominal video width of game. */ + unsigned base_height; /* Nominal video height of game. */ + unsigned max_width; /* Maximum possible width of game. */ + unsigned max_height; /* Maximum possible height of game. */ + + float aspect_ratio; /* Nominal aspect ratio of game. If + * aspect_ratio is <= 0.0, an aspect ratio + * of base_width / base_height is assumed. + * A frontend could override this setting, + * if desired. */ +}; + +struct retro_system_timing +{ + double fps; /* FPS of video content. */ + double sample_rate; /* Sampling rate of audio. */ +}; + +struct retro_system_av_info +{ + struct retro_game_geometry geometry; + struct retro_system_timing timing; +}; + +struct retro_variable +{ + /* Variable to query in RETRO_ENVIRONMENT_GET_VARIABLE. + * If NULL, obtains the complete environment string if more + * complex parsing is necessary. + * The environment string is formatted as key-value pairs + * delimited by semicolons as so: + * "key1=value1;key2=value2;..." + */ + const char *key; + + /* Value to be obtained. If key does not exist, it is set to NULL. */ + const char *value; +}; + +struct retro_core_option_display +{ + /* Variable to configure in RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY */ + const char *key; + + /* Specifies whether variable should be displayed + * when presenting core options to the user */ + bool visible; +}; + +/* Maximum number of values permitted for a core option + * > Note: We have to set a maximum value due the limitations + * of the C language - i.e. it is not possible to create an + * array of structs each containing a variable sized array, + * so the retro_core_option_definition values array must + * have a fixed size. The size limit of 128 is a balancing + * act - it needs to be large enough to support all 'sane' + * core options, but setting it too large may impact low memory + * platforms. In practise, if a core option has more than + * 128 values then the implementation is likely flawed. + * To quote the above API reference: + * "The number of possible options should be very limited + * i.e. it should be feasible to cycle through options + * without a keyboard." + */ +#define RETRO_NUM_CORE_OPTION_VALUES_MAX 128 + +struct retro_core_option_value +{ + /* Expected option value */ + const char *value; + + /* Human-readable value label. If NULL, value itself + * will be displayed by the frontend */ + const char *label; +}; + +struct retro_core_option_definition +{ + /* Variable to query in RETRO_ENVIRONMENT_GET_VARIABLE. */ + const char *key; + + /* Human-readable core option description (used as menu label) */ + const char *desc; + + /* Human-readable core option information (used as menu sublabel) */ + const char *info; + + /* Array of retro_core_option_value structs, terminated by NULL */ + struct retro_core_option_value values[RETRO_NUM_CORE_OPTION_VALUES_MAX]; + + /* Default core option value. Must match one of the values + * in the retro_core_option_value array, otherwise will be + * ignored */ + const char *default_value; +}; + +struct retro_core_options_intl +{ + /* Pointer to an array of retro_core_option_definition structs + * - US English implementation + * - Must point to a valid array */ + struct retro_core_option_definition *us; + + /* Pointer to an array of retro_core_option_definition structs + * - Implementation for current frontend language + * - May be NULL */ + struct retro_core_option_definition *local; +}; + +struct retro_game_info +{ + const char *path; /* Path to game, UTF-8 encoded. + * Sometimes used as a reference for building other paths. + * May be NULL if game was loaded from stdin or similar, + * but in this case some cores will be unable to load `data`. + * So, it is preferable to fabricate something here instead + * of passing NULL, which will help more cores to succeed. + * retro_system_info::need_fullpath requires + * that this path is valid. */ + const void *data; /* Memory buffer of loaded game. Will be NULL + * if need_fullpath was set. */ + size_t size; /* Size of memory buffer. */ + const char *meta; /* String of implementation specific meta-data. */ +}; + +#define RETRO_MEMORY_ACCESS_WRITE (1 << 0) + /* The core will write to the buffer provided by retro_framebuffer::data. */ +#define RETRO_MEMORY_ACCESS_READ (1 << 1) + /* The core will read from retro_framebuffer::data. */ +#define RETRO_MEMORY_TYPE_CACHED (1 << 0) + /* The memory in data is cached. + * If not cached, random writes and/or reading from the buffer is expected to be very slow. */ +struct retro_framebuffer +{ + void *data; /* The framebuffer which the core can render into. + Set by frontend in GET_CURRENT_SOFTWARE_FRAMEBUFFER. + The initial contents of data are unspecified. */ + unsigned width; /* The framebuffer width used by the core. Set by core. */ + unsigned height; /* The framebuffer height used by the core. Set by core. */ + size_t pitch; /* The number of bytes between the beginning of a scanline, + and beginning of the next scanline. + Set by frontend in GET_CURRENT_SOFTWARE_FRAMEBUFFER. */ + enum retro_pixel_format format; /* The pixel format the core must use to render into data. + This format could differ from the format used in + SET_PIXEL_FORMAT. + Set by frontend in GET_CURRENT_SOFTWARE_FRAMEBUFFER. */ + + unsigned access_flags; /* How the core will access the memory in the framebuffer. + RETRO_MEMORY_ACCESS_* flags. + Set by core. */ + unsigned memory_flags; /* Flags telling core how the memory has been mapped. + RETRO_MEMORY_TYPE_* flags. + Set by frontend in GET_CURRENT_SOFTWARE_FRAMEBUFFER. */ +}; + +/* Callbacks */ + +/* Environment callback. Gives implementations a way of performing + * uncommon tasks. Extensible. */ +typedef bool (RETRO_CALLCONV *retro_environment_t)(unsigned cmd, void *data); + +/* Render a frame. Pixel format is 15-bit 0RGB1555 native endian + * unless changed (see RETRO_ENVIRONMENT_SET_PIXEL_FORMAT). + * + * Width and height specify dimensions of buffer. + * Pitch specifices length in bytes between two lines in buffer. + * + * For performance reasons, it is highly recommended to have a frame + * that is packed in memory, i.e. pitch == width * byte_per_pixel. + * Certain graphic APIs, such as OpenGL ES, do not like textures + * that are not packed in memory. + */ +typedef void (RETRO_CALLCONV *retro_video_refresh_t)(const void *data, unsigned width, + unsigned height, size_t pitch); + +/* Renders a single audio frame. Should only be used if implementation + * generates a single sample at a time. + * Format is signed 16-bit native endian. + */ +typedef void (RETRO_CALLCONV *retro_audio_sample_t)(int16_t left, int16_t right); + +/* Renders multiple audio frames in one go. + * + * One frame is defined as a sample of left and right channels, interleaved. + * I.e. int16_t buf[4] = { l, r, l, r }; would be 2 frames. + * Only one of the audio callbacks must ever be used. + */ +typedef size_t (RETRO_CALLCONV *retro_audio_sample_batch_t)(const int16_t *data, + size_t frames); + +/* Polls input. */ +typedef void (RETRO_CALLCONV *retro_input_poll_t)(void); + +/* Queries for input for player 'port'. device will be masked with + * RETRO_DEVICE_MASK. + * + * Specialization of devices such as RETRO_DEVICE_JOYPAD_MULTITAP that + * have been set with retro_set_controller_port_device() + * will still use the higher level RETRO_DEVICE_JOYPAD to request input. + */ +typedef int16_t (RETRO_CALLCONV *retro_input_state_t)(unsigned port, unsigned device, + unsigned index, unsigned id); + +/* Sets callbacks. retro_set_environment() is guaranteed to be called + * before retro_init(). + * + * The rest of the set_* functions are guaranteed to have been called + * before the first call to retro_run() is made. */ +RETRO_API void retro_set_environment(retro_environment_t); +RETRO_API void retro_set_video_refresh(retro_video_refresh_t); +RETRO_API void retro_set_audio_sample(retro_audio_sample_t); +RETRO_API void retro_set_audio_sample_batch(retro_audio_sample_batch_t); +RETRO_API void retro_set_input_poll(retro_input_poll_t); +RETRO_API void retro_set_input_state(retro_input_state_t); + +/* Library global initialization/deinitialization. */ +RETRO_API void retro_init(void); +RETRO_API void retro_deinit(void); + +/* Must return RETRO_API_VERSION. Used to validate ABI compatibility + * when the API is revised. */ +RETRO_API unsigned retro_api_version(void); + +/* Gets statically known system info. Pointers provided in *info + * must be statically allocated. + * Can be called at any time, even before retro_init(). */ +RETRO_API void retro_get_system_info(struct retro_system_info *info); + +/* Gets information about system audio/video timings and geometry. + * Can be called only after retro_load_game() has successfully completed. + * NOTE: The implementation of this function might not initialize every + * variable if needed. + * E.g. geom.aspect_ratio might not be initialized if core doesn't + * desire a particular aspect ratio. */ +RETRO_API void retro_get_system_av_info(struct retro_system_av_info *info); + +/* Sets device to be used for player 'port'. + * By default, RETRO_DEVICE_JOYPAD is assumed to be plugged into all + * available ports. + * Setting a particular device type is not a guarantee that libretro cores + * will only poll input based on that particular device type. It is only a + * hint to the libretro core when a core cannot automatically detect the + * appropriate input device type on its own. It is also relevant when a + * core can change its behavior depending on device type. + * + * As part of the core's implementation of retro_set_controller_port_device, + * the core should call RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS to notify the + * frontend if the descriptions for any controls have changed as a + * result of changing the device type. + */ +RETRO_API void retro_set_controller_port_device(unsigned port, unsigned device); + +/* Resets the current game. */ +RETRO_API void retro_reset(void); + +/* Runs the game for one video frame. + * During retro_run(), input_poll callback must be called at least once. + * + * If a frame is not rendered for reasons where a game "dropped" a frame, + * this still counts as a frame, and retro_run() should explicitly dupe + * a frame if GET_CAN_DUPE returns true. + * In this case, the video callback can take a NULL argument for data. + */ +RETRO_API void retro_run(void); + +/* Returns the amount of data the implementation requires to serialize + * internal state (save states). + * Between calls to retro_load_game() and retro_unload_game(), the + * returned size is never allowed to be larger than a previous returned + * value, to ensure that the frontend can allocate a save state buffer once. + */ +RETRO_API size_t retro_serialize_size(void); + +/* Serializes internal state. If failed, or size is lower than + * retro_serialize_size(), it should return false, true otherwise. */ +RETRO_API bool retro_serialize(void *data, size_t size); +RETRO_API bool retro_unserialize(const void *data, size_t size); + +RETRO_API void retro_cheat_reset(void); +RETRO_API void retro_cheat_set(unsigned index, bool enabled, const char *code); + +/* Loads a game. + * Return true to indicate successful loading and false to indicate load failure. + */ +RETRO_API bool retro_load_game(const struct retro_game_info *game); + +/* Loads a "special" kind of game. Should not be used, + * except in extreme cases. */ +RETRO_API bool retro_load_game_special( + unsigned game_type, + const struct retro_game_info *info, size_t num_info +); + +/* Unloads the currently loaded game. Called before retro_deinit(void). */ +RETRO_API void retro_unload_game(void); + +/* Gets region of game. */ +RETRO_API unsigned retro_get_region(void); + +/* Gets region of memory. */ +RETRO_API void *retro_get_memory_data(unsigned id); +RETRO_API size_t retro_get_memory_size(unsigned id); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libretro/libretro_d3d.h b/libretro/libretro_d3d.h new file mode 100644 index 0000000000000..05c7c99df2325 --- /dev/null +++ b/libretro/libretro_d3d.h @@ -0,0 +1,56 @@ +/* Copyright (C) 2010-2016 The RetroArch team + * + * --------------------------------------------------------------------------------------------- + * The following license statement only applies to this libretro API header (libretro_vulkan.h) + * --------------------------------------------------------------------------------------------- + * + * Permission is hereby granted, free of charge, + * to any person obtaining a copy of this software and associated documentation files (the + * "Software"), + * to deal in the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef LIBRETRO_DIRECT3D_H__ +#define LIBRETRO_DIRECT3D_H__ + +#include "libretro.h" + +#include +#include + +#define RETRO_HW_RENDER_INTERFACE_D3D11_VERSION 1 + +struct retro_hw_render_interface_d3d11 +{ + /* Must be set to RETRO_HW_RENDER_INTERFACE_D3D11. */ + enum retro_hw_render_interface_type interface_type; + /* Must be set to RETRO_HW_RENDER_INTERFACE_D3D11_VERSION. */ + unsigned interface_version; + + /* Opaque handle to the d3d11 backend in the frontend + * which must be passed along to all function pointers + * in this interface. + */ + void* handle; + ID3D11Device *device; + ID3D11DeviceContext *context; + D3D_FEATURE_LEVEL featureLevel; + pD3DCompile D3DCompile; +}; + + +#endif /* LIBRETRO_DIRECT3D_H__ */ diff --git a/libretro/main.cpp b/libretro/main.cpp new file mode 100644 index 0000000000000..c8beb48e34394 --- /dev/null +++ b/libretro/main.cpp @@ -0,0 +1,845 @@ + +#include "PrecompiledHeader.h" + +#ifdef WIN32 +#include +#undef Yield +#endif + +#include "AppCommon.h" +#include "App.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "GS.h" +#include "GSFrame.h" +#include "options.h" +#include "input.h" +#include "svnrev.h" +#include "SPU2/Global.h" +#include "ps2/BiosTools.h" +#include "CDVD/CDVD.h" +#include "MTVU.h" +#include "Counters.h" + +#define THREADED_AUDIO + +//#define PERF_TEST +#ifdef PERF_TEST +static struct retro_perf_callback perf_cb; + +#define RETRO_PERFORMANCE_INIT(name) \ + retro_perf_tick_t current_ticks; \ + static struct retro_perf_counter name = {#name}; \ + if (!name.registered) \ + perf_cb.perf_register(&(name)); \ + current_ticks = name.total + +#define RETRO_PERFORMANCE_START(name) perf_cb.perf_start(&(name)) +#define RETRO_PERFORMANCE_STOP(name) \ + perf_cb.perf_stop(&(name)); \ + current_ticks = name.total - current_ticks; +#else +#define RETRO_PERFORMANCE_INIT(name) +#define RETRO_PERFORMANCE_START(name) +#define RETRO_PERFORMANCE_STOP(name) +#endif + +namespace Options +{ +static Option bios("pcsx2_bios", "Bios"); // will be filled in retro_init() +static Option fast_boot("pcsx2_fastboot", "Fast Boot", true); + +GfxOption renderer("pcsx2_renderer", "Renderer", {"Auto", "OpenGL", +#ifdef _WIN32 + "D3D11", +#endif + "Software", "Null"}); + +static GfxOption frameskip("pcsx2_frameskip", "Frameskip", false); +static GfxOption frames_to_draw("pcsx2_frames_to_draw", "Frameskip: Frames to Draw", 1, 10); +static GfxOption frames_to_skip("pcsx2_frames_to_skip", "Frameskip: Frames to Skip", 1, 10); +} // namespace Options + +retro_environment_t environ_cb; +retro_video_refresh_t video_cb; +struct retro_hw_render_callback hw_render; +static ConsoleColors log_color = Color_Default; +static retro_log_printf_t log_cb; +static retro_audio_sample_batch_t batch_cb; +static retro_audio_sample_t sample_cb; + +int Interpolation = 4; +bool EffectsDisabled = false; +bool postprocess_filter_dealias = false; +unsigned int delayCycles = 4; +#ifndef THREADED_AUDIO +static const int samples_max = 0x800; +static int write_pos = 0; +static s16 snd_buffer[samples_max << 1]; +static Threading::Mutex snd_mutex; +#endif + +// renderswitch - tells GSdx to go into dx9 sw if "renderswitch" is set. +bool renderswitch = false; +uint renderswitch_delay = 0; +static Pcsx2App* pcsx2; +static wxFileName bios_dir; + +void retro_set_video_refresh(retro_video_refresh_t cb) +{ + video_cb = cb; +} + +void retro_set_audio_sample_batch(retro_audio_sample_batch_t cb) +{ + batch_cb = cb; +} + +void retro_set_audio_sample(retro_audio_sample_t cb) +{ + sample_cb = cb; +} + +static void _Core_Pause() +{ + CoreThread.Pause(); +} + +void SndBuffer::Write(const StereoOut32& Sample) +{ +#ifdef THREADED_AUDIO + sample_cb(Sample.Left >> 12, Sample.Right >> 12); +#else + ScopedLock locker(snd_mutex); + if (write_pos < (samples_max << 1)) + { + snd_buffer[write_pos++] = Sample.Left >> 12; + snd_buffer[write_pos++] = Sample.Right >> 12; + } +#endif +} + +void retro_set_environment(retro_environment_t cb) +{ + environ_cb = cb; + bool no_game = true; + environ_cb(RETRO_ENVIRONMENT_SET_SUPPORT_NO_GAME, &no_game); +#ifdef PERF_TEST + environ_cb(RETRO_ENVIRONMENT_GET_PERF_INTERFACE, &perf_cb); +#endif +} + +static void RetroLog_DoSetColor(ConsoleColors color) +{ + if (color != Color_Current) + log_color = color; +} + +static void RetroLog_DoWrite(const wxString& fmt) +{ + retro_log_level level = RETRO_LOG_INFO; + switch (log_color) + { + case Color_StrongRed: // intended for errors + level = RETRO_LOG_ERROR; + break; + case Color_StrongOrange: // intended for warnings + level = RETRO_LOG_WARN; + break; + case Color_Cyan: // faint visibility, intended for logging PS2/IOP output + case Color_Yellow: // faint visibility, intended for logging PS2/IOP output + case Color_White: // faint visibility, intended for logging PS2/IOP output + level = RETRO_LOG_DEBUG; + break; + default: + case Color_Default: + case Color_Black: + case Color_Green: + case Color_Red: + case Color_Blue: + case Color_Magenta: + case Color_Orange: + case Color_Gray: + case Color_StrongBlack: + case Color_StrongGreen: // intended for infrequent state information + case Color_StrongBlue: // intended for block headings + case Color_StrongMagenta: + case Color_StrongGray: + case Color_StrongCyan: + case Color_StrongYellow: + case Color_StrongWhite: + break; + } + + log_cb(level, "%s", (const char*)fmt); +} + +static void RetroLog_SetTitle(const wxString& title) +{ + RetroLog_DoWrite(title + L"\n"); +} + +static void RetroLog_Newline() +{ + // RetroLog_DoWrite(L"\n"); +} + +static void RetroLog_DoWriteLn(const wxString& fmt) +{ + RetroLog_DoWrite(fmt + L"\n"); +} + +static const IConsoleWriter ConsoleWriter_Libretro = + { + RetroLog_DoWrite, + RetroLog_DoWriteLn, + RetroLog_DoSetColor, + + RetroLog_DoWrite, + RetroLog_Newline, + RetroLog_SetTitle, + + 0, // instance-level indentation (should always be 0) +}; + +static std::vector disk_images; +static int image_index = 0; +static bool eject_state; +static bool RETRO_CALLCONV set_eject_state(bool ejected) +{ + if (eject_state == ejected) + return false; + + eject_state = ejected; + + GetSysExecutorThread().Rpc_TryInvokeAsync(_Core_Pause, L"AppCoreThread::Pause"); + GetMTGS().SignalVsync(); + CoreThread.Pause(); + + if (ejected) + cdvdCtrlTrayOpen(); + else + { + if (image_index < 0 || image_index >= (int)disk_images.size()) + g_Conf->CdvdSource = CDVD_SourceType::NoDisc; + else + { + g_Conf->CurrentIso = disk_images[image_index]; + g_Conf->CdvdSource = CDVD_SourceType::Iso; + CDVDsys_SetFile(CDVD_SourceType::Iso, g_Conf->CurrentIso); + } + cdvdCtrlTrayClose(); + } + + CoreThread.Resume(); + return true; +} +static bool RETRO_CALLCONV get_eject_state(void) +{ + return eject_state; +} + +static unsigned RETRO_CALLCONV get_image_index(void) +{ + return image_index; +} +static bool RETRO_CALLCONV set_image_index(unsigned index) +{ + if (eject_state) + image_index = index; + + return eject_state; +} +static unsigned RETRO_CALLCONV get_num_images(void) +{ + return disk_images.size(); +} + +static bool RETRO_CALLCONV replace_image_index(unsigned index, const struct retro_game_info* info) +{ + if (index >= disk_images.size()) + return false; + + if (!info->path) + { + disk_images.erase(disk_images.begin() + index); + if (!disk_images.size()) + image_index = -1; + else if (image_index > (int)index) + image_index--; + } + else + disk_images[index] = info->path; + + return true; +} + +static bool RETRO_CALLCONV add_image_index(void) +{ + disk_images.push_back(nullptr); + return true; +} + +static bool RETRO_CALLCONV set_initial_image(unsigned index, const char* path) +{ + if (index >= disk_images.size()) + index = 0; + + image_index = index; + + return true; +} + +static bool RETRO_CALLCONV get_image_path(unsigned index, char* path, size_t len) +{ + if (index >= disk_images.size()) + return false; + + if (!disk_images[index]) + return false; + + strncpy(path, disk_images[index], len); + return true; +} +static bool RETRO_CALLCONV get_image_label(unsigned index, char* label, size_t len) +{ + if (index >= disk_images.size()) + return false; + + if (!disk_images[index]) + return false; + + strncpy(label, disk_images[index], len); + return true; +} + +void retro_init(void) +{ + enum retro_pixel_format xrgb888 = RETRO_PIXEL_FORMAT_XRGB8888; + environ_cb(RETRO_ENVIRONMENT_SET_PIXEL_FORMAT, &xrgb888); + struct retro_log_callback log; + if (environ_cb(RETRO_ENVIRONMENT_GET_LOG_INTERFACE, &log)) + { + log_cb = log.log; +#if 0 + Console_SetActiveHandler(ConsoleWriter_Libretro); +#endif + } + + if (!pcsx2) + { + // pcsx2 = new Pcsx2App; + // wxApp::SetInstance(pcsx2); + pcsx2 = &wxGetApp(); +#if 0 + int argc = 0; + pcsx2->Initialize(argc, (wchar_t**)nullptr); + wxModule::RegisterModules(); + wxModule::InitializeModules(); +#endif + + InitCPUTicks(); + // pxDoAssert = AppDoAssert; + pxDoAssert = NULL; + pxDoOutOfMemory = SysOutOfMemory_EmergencyResponse; + g_Conf = std::make_unique(); + GetSysExecutorThread().Start(); + pcsx2->DetectCpuAndUserMode(); + pcsx2->AllocateCoreStuffs(); + // pcsx2->GetGameDatabase(); + } + else + GetSysExecutorThread().Start(); + + vu1Thread.Reset(); + + g_Conf->BaseFilenames.Plugins[PluginId_GS] = "Built-in"; + g_Conf->BaseFilenames.Plugins[PluginId_PAD] = "Built-in"; + g_Conf->BaseFilenames.Plugins[PluginId_USB] = "Built-in"; + g_Conf->BaseFilenames.Plugins[PluginId_DEV9] = "Built-in"; + + if (Options::bios.empty()) + { + const char* system = nullptr; + environ_cb(RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY, &system); + bios_dir = Path::Combine(system, "pcsx2/bios"); + + wxArrayString bios_list; + wxDir::GetAllFiles(bios_dir.GetFullPath(), &bios_list, L"*.*", wxDIR_FILES); + + for (wxString bios_file : bios_list) + { + wxString description; + if (IsBIOS(bios_file, description)) + Options::bios.push_back((const char*)description, (const char*)bios_file); + } + } + + Options::SetVariables(); + + static retro_disk_control_ext_callback disk_control = { + set_eject_state, + get_eject_state, + get_image_index, + set_image_index, + get_num_images, + replace_image_index, + add_image_index, + set_initial_image, + get_image_path, + get_image_label, + }; + + environ_cb(RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE, &disk_control); +} + +void retro_deinit(void) +{ + // GetCoreThread().Cancel(true); + + // WIN32 doesn't allow canceling threads from global constructors/destructors in a shared library. + vu1Thread.Cancel(); + // GetSysExecutorThread().ShutdownQueue(); + GetSysExecutorThread().Cancel(); +// GetVmMemory().ReleaseAll(); +// pcsx2->CleanupOnExit(); +#ifdef PERF_TEST + perf_cb.perf_log(); +#endif +} + +void retro_get_system_info(retro_system_info* info) +{ +#ifdef GIT_REV + info->library_version = GIT_REV; +#else + static char version[] = "#.#.#"; + version[0] = '0' + PCSX2_VersionHi; + version[2] = '0' + PCSX2_VersionMid; + version[4] = '0' + PCSX2_VersionLo; + info->library_version = version; +#endif + + info->library_name = "pcsx2"; + info->valid_extensions = "elf|iso|ciso|cue|bin|gz"; + info->need_fullpath = true; + info->block_extract = true; +} + +void retro_get_system_av_info(retro_system_av_info* info) +{ + if (Options::renderer == "Software" || Options::renderer == "Null") + { + info->geometry.base_width = 640; + info->geometry.base_height = 448; + } + else + { + info->geometry.base_width = 640 * Options::upscale_multiplier; + info->geometry.base_height = 448 * Options::upscale_multiplier; + } + + info->geometry.max_width = info->geometry.base_width; + info->geometry.max_height = info->geometry.base_height; + + info->geometry.aspect_ratio = 4.0f / 3.0f; + info->timing.fps = (retro_get_region() == RETRO_REGION_NTSC) ? (60.0f / 1.001f) : 50.0f; + info->timing.sample_rate = 48000; +} + +void retro_reset(void) +{ + GetMTGS().ClosePlugin(); + GetCoreThread().ResetQuick(); + GetMTGS().OpenPlugin(); + GetCoreThread().Resume(); + eject_state = false; +#ifndef THREADED_AUDIO + write_pos = 0; +#endif +} + +static void context_reset() +{ + printf("Context reset\n"); + GetMTGS().OpenPlugin(); + GetCoreThread().Resume(); +} +static void context_destroy() +{ + GetSysExecutorThread().Rpc_TryInvokeAsync(_Core_Pause, L"AppCoreThread::Pause"); + GetMTGS().Flush(); + GetMTGS().ClosePlugin(); + CoreThread.Pause(); + printf("Context destroy\n"); +} + +static bool set_hw_render(retro_hw_context_type type) +{ + hw_render.context_type = type; + hw_render.context_reset = context_reset; + hw_render.context_destroy = context_destroy; + hw_render.bottom_left_origin = true; + hw_render.depth = true; + hw_render.cache_context = true; + + switch (type) + { +#ifdef _WIN32 + case RETRO_HW_CONTEXT_DIRECT3D: + hw_render.version_major = 11; + hw_render.version_minor = 0; + break; +#endif + case RETRO_HW_CONTEXT_OPENGL_CORE: + hw_render.version_major = 3; + hw_render.version_minor = 3; + hw_render.cache_context = false; + break; + + case RETRO_HW_CONTEXT_OPENGL: + hw_render.version_major = 3; + hw_render.version_minor = 0; + break; + + case RETRO_HW_CONTEXT_OPENGLES3: + hw_render.version_major = 3; + hw_render.version_minor = 0; + break; + + case RETRO_HW_CONTEXT_NONE: + return true; + + default: + return false; + } + + return environ_cb(RETRO_ENVIRONMENT_SET_HW_RENDER, &hw_render); +} + +bool retro_load_game(const struct retro_game_info* game) +{ + if (Options::bios.empty()) + { + log_cb(RETRO_LOG_ERROR, "Could not find any valid PS2 Bios File in %s\n", (const char*)bios_dir.GetFullPath()); + return false; + } + + const char* system = nullptr; + environ_cb(RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY, &system); + + // pcsx2->Overrides.Gamefixes.Set( id, true); + + // By default no IRX injection + g_Conf->CurrentIRX = ""; + g_Conf->BaseFilenames.Bios = Options::bios.Get(); + eject_state = false; +#ifndef THREADED_AUDIO + write_pos = 0; +#endif + + Options::renderer.UpdateAndLock(); // disallow changes to Options::renderer outside of retro_load_game. + + u32 magic = 0; + if (game) + { + FILE* fp = fopen(game->path, "rb"); + if (!fp) + { + log_cb(RETRO_LOG_ERROR, "Could not open File: %s\n", game->path); + return false; + } + + fread(&magic, 4, 1, fp); + fclose(fp); + } + + if (magic == 0x464C457F) // elf + { + // g_Conf->CurrentIRX = ""; + g_Conf->EmuOptions.UseBOOT2Injection = true; + pcsx2->SysExecute(CDVD_SourceType::NoDisc, game->path); + } + else + { + g_Conf->EmuOptions.UseBOOT2Injection = Options::fast_boot; + g_Conf->CdvdSource = game ? CDVD_SourceType::Iso : CDVD_SourceType::NoDisc; + g_Conf->CurrentIso = game ? game->path : ""; + pcsx2->SysExecute(g_Conf->CdvdSource); + } + + // g_Conf->CurrentGameArgs = ""; + g_Conf->EmuOptions.GS.FrameLimitEnable = false; + // g_Conf->EmuOptions.GS.SynchronousMTGS = true; + + Input::Init(); + + if (Options::renderer == "Auto") + { + retro_hw_context_type context_type = RETRO_HW_CONTEXT_OPENGL_CORE; + environ_cb(RETRO_ENVIRONMENT_GET_PREFERRED_HW_RENDER, &context_type); + if (set_hw_render(context_type)) + return true; + } +#ifdef _WIN32 + if (Options::renderer == "D3D11") + return set_hw_render(RETRO_HW_CONTEXT_DIRECT3D); +#endif + if (Options::renderer == "Null") + return set_hw_render(RETRO_HW_CONTEXT_NONE); + + if (set_hw_render(RETRO_HW_CONTEXT_OPENGL_CORE)) + return true; + if (set_hw_render(RETRO_HW_CONTEXT_OPENGL)) + return true; + if (set_hw_render(RETRO_HW_CONTEXT_OPENGLES3)) + return true; +#ifdef _WIN32 + if (set_hw_render(RETRO_HW_CONTEXT_DIRECT3D)) + return true; +#endif + return false; +} + +bool retro_load_game_special(unsigned game_type, const struct retro_game_info* info, + size_t num_info) +{ + return false; +} + +void retro_unload_game(void) +{ + GetSysExecutorThread().Rpc_TryInvokeAsync(_Core_Pause, L"AppCoreThread::Pause"); + GetMTGS().ClosePlugin(); + GetCoreThread().Suspend(); + GetCoreThread().Cancel(true); + new (&GetMTGS()) SysMtgsThread(); +} + + +void retro_run(void) +{ + Options::CheckVariables(); + SetGSConfig().FrameSkipEnable = Options::frameskip; + SetGSConfig().FramesToDraw = Options::frames_to_draw; + SetGSConfig().FramesToSkip = Options::frames_to_skip; + + Input::Update(); + + if (Options::upscale_multiplier.Updated()) + { + retro_system_av_info av_info; + retro_get_system_av_info(&av_info); +#if 1 + environ_cb(RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO, &av_info); +#else + environ_cb(RETRO_ENVIRONMENT_SET_GEOMETRY, &av_info.geometry); + GetMTGS().ClosePlugin(); + GetMTGS().OpenPlugin(); +#endif + } + + // GetCoreThread().Resume(); + GetMTGS().OpenPlugin(); + + RETRO_PERFORMANCE_INIT(pcsx2_run); + RETRO_PERFORMANCE_START(pcsx2_run); + + GetMTGS().StepFrame(); +#ifndef THREADED_AUDIO + if (write_pos > (0x200 << 1)) + { + ScopedLock locker(snd_mutex); + batch_cb(snd_buffer, write_pos >> 1); + write_pos = 0; + } +#endif + + RETRO_PERFORMANCE_STOP(pcsx2_run); +} + +size_t retro_serialize_size(void) +{ + return Ps2MemSize::MainRam + Ps2MemSize::Scratch + Ps2MemSize::Hardware + + Ps2MemSize::IopRam + Ps2MemSize::IopHardware + + VU0_PROGSIZE + VU0_MEMSIZE + VU1_PROGSIZE + VU1_MEMSIZE + + _8mb; // + SPU2Savestate::SizeIt(); +} + +bool retro_serialize(void* data, size_t size) +{ + GetSysExecutorThread().Rpc_TryInvokeAsync(_Core_Pause, L"AppCoreThread::Pause"); + GetMTGS().Flush(); + CoreThread.Pause(); + + VmStateBuffer buffer; + memSavingState saveme(buffer); + + saveme.FreezeAll(); + + memcpy(data, buffer.GetPtr(), buffer.GetLength()); + SPU2Savestate::FreezeIt(*(SPU2Savestate::DataBlock*)((u8*)data + buffer.GetLength())); + + CoreThread.Resume(); + return true; +} + +bool retro_unserialize(const void* data, size_t size) +{ + GetSysExecutorThread().Rpc_TryInvokeAsync(_Core_Pause, L"AppCoreThread::Pause"); + GetMTGS().Flush(); + CoreThread.Pause(); + + VmStateBuffer buffer; + buffer.MakeRoomFor(size); + memcpy(buffer.GetPtr(), data, size); + + memLoadingState loadme(buffer); + + loadme.FreezeAll(); + SPU2Savestate::ThawIt(*(SPU2Savestate::DataBlock*)loadme.GetBlockPtr()); + + CoreThread.Resume(); + return true; +} + +unsigned retro_get_region(void) +{ + return RETRO_REGION_NTSC; +} + +unsigned retro_api_version() +{ + return RETRO_API_VERSION; +} + +size_t retro_get_memory_size(unsigned id) +{ + return 0; +} + +void* retro_get_memory_data(unsigned id) +{ + return NULL; +} + +void retro_cheat_reset(void) +{ +} + +void retro_cheat_set(unsigned index, bool enabled, const char* code) +{ +} + +void SndBuffer::Init() +{ +#ifndef THREADED_AUDIO + write_pos = 0; +#endif +} + +void SndBuffer::Cleanup() +{ +} + +s32 SndBuffer::Test() +{ + return 0; +} + +void SndBuffer::ClearContents() +{ +} + +void DspUpdate() +{ +} + +s32 DspLoadLibrary(wchar_t* fileName, int modnum) +{ + return 0; +} + +void ReadSettings() +{ +} +#ifndef _WIN32 +void SysMessage(const char* fmt, ...) +{ + va_list list; + va_start(list, fmt); + vprintf(fmt, list); + va_end(list); +} +#endif +wxEventLoopBase* Pcsx2AppTraits::CreateEventLoop() +{ + return new wxEventLoop(); + // return new wxGUIEventLoop(); + // return new wxConsoleEventLoop(); +} + +#ifdef wxUSE_STDPATHS +class Pcsx2StandardPaths : public wxStandardPaths +{ +public: + virtual wxString GetExecutablePath() const + { + const char* system = nullptr; + environ_cb(RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY, &system); + return Path::Combine(system, "pcsx2/PCSX2"); + } + wxString GetUserLocalDataDir() const + { + const char* savedir = nullptr; + environ_cb(RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY, &savedir); + return Path::Combine(savedir, "pcsx2"); + } +}; + +wxStandardPaths& Pcsx2AppTraits::GetStandardPaths() +{ + static Pcsx2StandardPaths stdPaths; + return stdPaths; +} +#endif + +void SaveStateBase::InputRecordingFreeze() +{ +#if 0 + FreezeTag("InputRecording"); + Freeze(g_FrameCount); +#endif +} + +void Pcsx2App::enterDebugMode() +{ +} + +void Pcsx2App::leaveDebugMode() +{ +} + +void Pcsx2App::resetDebugger() +{ +} + +void Pcsx2App::BuildCommandHash() +{ +} + +void UI_EnableSysActions() +{ +} + +LimiterModeType g_LimiterMode = Limit_Nominal; +std::string s_strIniPath = "inis"; +std::string s_strLogPath = "logs"; +bool _visual_debug_enabled = false; // windows only feature diff --git a/libretro/options.cpp b/libretro/options.cpp new file mode 100644 index 0000000000000..3018e840f0e4e --- /dev/null +++ b/libretro/options.cpp @@ -0,0 +1,44 @@ + +#include +#include "options.h" + +namespace Options +{ +static std::vector& GetOptionGroup(Groups group) +{ + /* this garentees that 'list' is constructed first before being accessed other global constructors.*/ + static std::vector list[OPTIONS_GROUPS_MAX]; + return list[group]; +} + +void OptionBase::Register(Groups group) +{ + GetOptionGroup(group).push_back(this); +} + +void SetVariables() +{ + std::vector vars; + for (int grp = 0; grp < OPTIONS_GROUPS_MAX; grp++) + for (OptionBase* option : GetOptionGroup((Groups)grp)) + if (!option->empty()) + vars.push_back(option->getVariable()); + + if (vars.empty()) + return; + + vars.push_back({}); + environ_cb(RETRO_ENVIRONMENT_SET_VARIABLES, (void*)vars.data()); +} + +void CheckVariables() +{ + bool updated = false; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE, &updated) && !updated) + return; + + for (int grp = 0; grp < OPTIONS_GROUPS_MAX; grp++) + for (OptionBase* option : GetOptionGroup((Groups)grp)) + option->SetDirty(); +} +} // namespace Options diff --git a/libretro/options.h b/libretro/options.h new file mode 100644 index 0000000000000..ae68df4cd8312 --- /dev/null +++ b/libretro/options.h @@ -0,0 +1,203 @@ +#pragma once + +#include +#include +#include +#include + +extern retro_environment_t environ_cb; + +namespace Options +{ + +enum Groups +{ + OPTIONS_BASE, + OPTIONS_GFX, + OPTIONS_EMU, + OPTIONS_GROUPS_MAX +}; + +class OptionBase +{ +public: + void SetDirty() { m_dirty = true; } + retro_variable getVariable() { return {m_id, m_options.c_str()}; } + virtual bool empty() = 0; + +protected: + OptionBase(const char* id, const char* name, Groups group) + : m_id(id) + , m_name(name) + { + m_options = m_name; + m_options.push_back(';'); + Register(group); + } + + const char* m_id; + const char* m_name; + bool m_dirty = true; + std::string m_options; + +private: + void Register(Groups group); +}; + +template +class Option : public OptionBase +{ + static_assert(group < OPTIONS_GROUPS_MAX, "invalid option group index"); + Option(Option&) = delete; + Option(Option&&) = delete; + Option& operator=(Option&) = delete; + +public: + Option(const char* id, const char* name) + : OptionBase(id, name, group) + { + } + + Option(const char* id, const char* name, T initial) + : OptionBase(id, name, group) + { + push_back(initial ? "enabled" : "disabled", initial); + push_back(!initial ? "enabled" : "disabled", !initial); + } + + Option(const char* id, const char* name, std::initializer_list> list) + : OptionBase(id, name, group) + { + for (auto option : list) + push_back(option.first, option.second); + } + + Option(const char* id, const char* name, std::initializer_list list) + : OptionBase(id, name, group) + { + for (auto option : list) + push_back(option); + } + + Option(const char* id, const char* name, T first, std::initializer_list list) + : OptionBase(id, name, group) + { + for (auto option : list) + push_back(option, first + (int)m_list.size()); + } + + Option(const char* id, const char* name, T first, int count, int step = 1) + : OptionBase(id, name, group) + { + for (T i = first; i < first + count; i += step) + push_back(std::to_string(i), i); + } + + void push_back(std::string option, T value) + { + if (m_list.empty()) + { + m_options += std::string(" ") + option; + m_value = value; + } + else + m_options += std::string("|") + option; + + m_list.push_back({option, value}); + } + + template () && std::is_constructible()> + void push_back(const char* option) + { + push_back(option, option); + } +#if 0 + template <> + void push_back(const char* option) + { + if (m_list.empty()) + push_back(option, 0); + else + push_back(option, m_list.back().second + 1); + } +#endif + bool Updated() + { + if (m_dirty && !m_locked) + { + m_dirty = false; + + retro_variable var{m_id}; + T value = m_list.front().second; + + if (environ_cb && environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + for (auto option : m_list) + { + if (option.first == var.value) + { + value = option.second; + break; + } + } + } + + if (m_value != value) + { + m_value = value; + return true; + } + } + + return false; + } + + void UpdateAndLock() + { + m_locked = false; + Updated(); + m_locked = true; + } + + operator T() + { + Updated(); + return m_value; + } + + T Get() + { + return (T) * this; + } + + template + bool operator==(S value) + { + return (T) * this == value; + } + + template + bool operator!=(S value) + { + return (T) * this != value; + } + + virtual bool empty() override { return m_list.empty(); } + +private: + bool m_locked = false; + T m_value; + std::vector> m_list; +}; + +template +using EmuOption = Option; +template +using GfxOption = Option; + +void SetVariables(); +void CheckVariables(); + +extern GfxOption upscale_multiplier; +extern GfxOption renderer; +} // namespace Options diff --git a/pcsx2/CDVD/CDVD.cpp b/pcsx2/CDVD/CDVD.cpp index 6dae09280c6ee..213a525de3e96 100644 --- a/pcsx2/CDVD/CDVD.cpp +++ b/pcsx2/CDVD/CDVD.cpp @@ -993,7 +993,7 @@ void cdvdVsync() if (cdvd.RTCcount < (GetVerticalFrequency().ToIntRounded())) return; cdvd.RTCcount = 0; - +#ifndef __LIBRETRO__ if (cdvd.Status == CDVD_STATUS_TRAY_OPEN) { cdvd.TrayTimeout++; @@ -1003,7 +1003,7 @@ void cdvdVsync() cdvdCtrlTrayClose(); cdvd.TrayTimeout = 0; } - +#endif cdvd.RTC.second++; if (cdvd.RTC.second < 60) return; diff --git a/pcsx2/CMakeLists.txt b/pcsx2/CMakeLists.txt index 969ef71d92c53..fad1eddd2a9ae 100644 --- a/pcsx2/CMakeLists.txt +++ b/pcsx2/CMakeLists.txt @@ -17,9 +17,14 @@ set(CommonFlags -Wstrict-aliasing # Allow to track strict aliasing issue. -Wno-parentheses -Wno-missing-braces - -DWX_PRECOMP ) +if(CCACHE_FOUND) + set(CommonFlags ${CommonFlags} -Werror=date-time) +else() + set(CommonFlags ${CommonFlags} -DWX_PRECOMP) +endif() + # Largely turning off because LegacyPluginAPI_Common in Plugins.h spams really badly in gcc 8 due to the memzero initialization. # Should probably be fixed properly, but for now this should work. if(GCC_VERSION VERSION_EQUAL "8.0" OR GCC_VERSION VERSION_GREATER "8.0") @@ -45,7 +50,11 @@ if(XDG_STD) set(pcsx2FinalFlags ${pcsx2FinalFlags} -DXDG_STD) endif() -set(Output PCSX2) +if(LIBRETRO) + set(Output pcsx2_libretro) +else() + set(Output PCSX2) +endif() # Main pcsx2 source set(pcsx2Sources @@ -235,23 +244,43 @@ set(pcsx2SPU2Sources SPU2/RegLog.cpp SPU2/RegTable.cpp SPU2/Reverb.cpp - SPU2/SndOut.cpp - SPU2/SndOut_SDL.cpp - SPU2/SndOut_Portaudio.cpp SPU2/spu2freeze.cpp SPU2/spu2replay.cpp SPU2/spu2sys.cpp - SPU2/Timestretcher.cpp SPU2/Wavedump_wav.cpp SPU2/WavFile.cpp - SPU2/Linux/Alsa.cpp - SPU2/Linux/CfgHelpers.cpp - SPU2/Linux/Config.cpp - SPU2/Linux/ConfigDebug.cpp - SPU2/Linux/ConfigSoundTouch.cpp - SPU2/Linux/Dialogs.cpp - SPU2/wx/wxConfig.cpp - ) + ) + +if(MSVC) + set(pcsx2SPU2Sources ${pcsx2SPU2Sources} + SPU2/Windows/RealtimeDebugger.cpp + SPU2/Windows/CfgHelpers.cpp + SPU2/Windows/ConfigDebug.cpp + ) +else() + set(pcsx2SPU2Sources ${pcsx2SPU2Sources} + SPU2/Linux/CfgHelpers.cpp + SPU2/Linux/ConfigDebug.cpp + ) +endif() + +if(NOT LIBRETRO) + set(pcsx2SPU2Sources ${pcsx2SPU2Sources} + SPU2/SndOut.cpp + SPU2/SndOut_SDL.cpp + SPU2/SndOut_Portaudio.cpp + SPU2/Timestretcher.cpp + SPU2/wx/wxConfig.cpp + ) + if(NOT MSVC) + set(pcsx2SPU2Sources ${pcsx2SPU2Sources} + SPU2/Linux/Alsa.cpp + SPU2/Linux/Config.cpp + SPU2/Linux/ConfigSoundTouch.cpp + SPU2/Linux/Dialogs.cpp + ) + endif() +endif() # SPU2 headers set(pcsx2SPU2Headers @@ -321,7 +350,15 @@ set(pcsx2GuiSources gui/AppMain.cpp gui/AppRes.cpp gui/ConsoleLogger.cpp - gui/CpuUsageProvider.cpp + gui/ExecutorThread.cpp + gui/i18n.cpp + gui/MemoryCardFile.cpp + gui/MemoryCardFolder.cpp + gui/MSWstuff.cpp + ) + +if(NOT LIBRETRO) +set(pcsx2GuiSources ${pcsx2GuiSources} gui/Dialogs/AboutBoxDialog.cpp gui/Dialogs/AssertionDialog.cpp gui/Dialogs/BaseConfigurationDialog.cpp @@ -341,18 +378,14 @@ set(pcsx2GuiSources gui/Debugger/DebuggerLists.cpp gui/Debugger/DisassemblyDialog.cpp gui/Debugger/DebugEvents.cpp + gui/CpuUsageProvider.cpp gui/DriveList.cpp - gui/ExecutorThread.cpp gui/FrameForGS.cpp gui/GlobalCommands.cpp - gui/i18n.cpp gui/IsoDropTarget.cpp gui/MainFrame.cpp gui/MainMenuClicks.cpp - gui/MemoryCardFile.cpp - gui/MemoryCardFolder.cpp gui/MessageBoxes.cpp - gui/MSWstuff.cpp gui/Panels/BaseApplicableConfigPanel.cpp gui/Panels/BiosSelectorPanel.cpp gui/Panels/CpuPanel.cpp @@ -372,6 +405,7 @@ set(pcsx2GuiSources gui/SysState.cpp gui/UpdateUI.cpp ) +endif(NOT LIBRETRO) # gui headers set(pcsx2GuiHeaders @@ -415,6 +449,7 @@ set(pcsx2GuiHeaders gui/Saveslots.h ) +if(NOT MSVC) # Warning: the declaration of the .h are mandatory in case of resources files. It will ensure the creation # from the bin2cpp tools at right good moment (ie .h must be created before the pcsx2 compilation) # Gui resources headers @@ -437,7 +472,7 @@ set(pcsx2GuiResources ${res_bin}/Breakpoint_Active.h ${res_bin}/Breakpoint_Inactive.h ) - +endif() # IPU sources set(pcsx2IPUSources IPU/IPU.cpp @@ -462,11 +497,15 @@ set(pcsx2IPUHeaders set(pcsx2LinuxSources CDVD/Linux/DriveUtility.cpp CDVD/Linux/IOCtlSrc.cpp - gui/CpuUsageProviderLnx.cpp Linux/LnxConsolePipe.cpp - Linux/LnxKeyCodes.cpp Linux/LnxFlatFileReader.cpp ) +if(NOT LIBRETRO) + set(pcsx2LinuxSources ${pcsx2LinuxSources} + gui/CpuUsageProviderLnx.cpp + Linux/LnxKeyCodes.cpp + ) +endif() set(pcsx2OSXSources CDVD/Linux/DriveUtility.cpp @@ -582,7 +621,8 @@ set(pcsx2RecordingVirtualPadResources # System sources set(pcsx2SystemSources System/SysCoreThread.cpp - System/SysThreadBase.cpp) + System/SysThreadBase.cpp + System/SysFakeThread.cpp) # System headers set(pcsx2SystemHeaders @@ -614,13 +654,16 @@ set(pcsx2WindowsSources gui/CpuUsageProviderMSW.cpp windows/FlatFileReaderWindows.cpp windows/Optimus.cpp - windows/PatchBrowser.cpp windows/VCprojects/IopSif.cpp windows/WinCompressNTFS.cpp windows/WinConsolePipe.cpp windows/WinKeyCodes.cpp ) - +if(NOT LIBRETRO) + set(pcsx2WindowsSources ${pcsx2WindowsSources} + windows/PatchBrowser.cpp + ) +endif() # Windows headers set(pcsx2WindowsHeaders windows/resource.h @@ -713,17 +756,21 @@ set(Common ${pcsx2IPUHeaders} ${pcsx2ps2Sources} ${pcsx2ps2Headers} - ${pcsx2RecordingSources} - ${pcsx2RecordingVirtualPadResources} - ${pcsx2RecordingHeaders} ${pcsx2SystemSources} ${pcsx2SystemHeaders} ${pcsx2UtilitiesSources} ${pcsx2UtilitiesHeaders} ${pcsx2x86Sources} ${pcsx2x86Headers} - ${pcsx2ZipToolsSources} +# ${pcsx2ZipToolsSources} ${pcsx2ZipToolsHeaders}) +if(NOT LIBRETRO) + set(Common ${Common} + ${pcsx2RecordingSources} + ${pcsx2RecordingVirtualPadResources} + ${pcsx2RecordingHeaders} + ) +endif() # platform sources # Linux @@ -768,6 +815,8 @@ set(pcsx2FinalLibs x86emitter ${wxWidgets_LIBRARIES} ${GTK2_LIBRARIES} + ${GLIB_LIBRARIES} + ${GLIB_GIO_LIBRARIES} ${ZLIB_LIBRARIES} ${AIO_LIBRARIES} ${GCOV_LIBRARIES} @@ -779,22 +828,19 @@ set(pcsx2FinalLibs ) if(BUILTIN_GS) - set(pcsx2FinalLibs "${pcsx2FinalLibs} GSdx") + set(pcsx2FinalLibs ${pcsx2FinalLibs} GSdx) + if(MSVC) + set(pcsx2FinalSources ${pcsx2FinalSources} ${CMAKE_SOURCE_DIR}/plugins/GSdx/GSdx.rc) + endif() endif() if(BUILTIN_PAD) - set(pcsx2FinalLibs "${pcsx2FinalLibs} onepad-1.2.0") + set(pcsx2FinalLibs ${pcsx2FinalLibs} onepad) endif() if(BUILTIN_USB) - set(pcsx2FinalLibs "${pcsx2FinalLibs} USBnull-0.7.0") -endif() -if(BUILTIN_FW) - set(pcsx2FinalLibs "${pcsx2FinalLibs} FWnull-0.7.0") -endif() -if(BUILTIN_DEV) - set(pcsx2FinalLibs "${pcsx2FinalLibs} dev9null-0.5.0") + set(pcsx2FinalLibs ${pcsx2FinalLibs} USBnull-0.7.0) endif() -if(BUILTIN_CDVD) - set(pcsx2FinalLibs "${pcsx2FinalLibs} CDVDnull") +if(BUILTIN_DEV9) + set(pcsx2FinalLibs ${pcsx2FinalLibs} dev9null-0.5.0) endif() # additonal include directories @@ -804,6 +850,7 @@ include_directories( ${CMAKE_BINARY_DIR}/pcsx2/gui ) +if(NOT MSVC) ### Generate the resources files file(MAKE_DIRECTORY ${res_bin}) @@ -821,15 +868,55 @@ foreach(res_file IN ITEMS r1Pressed r2Pressed r3Pressed rightPressed selectPressed squarePressed startPressed trianglePressed upPressed) add_custom_command(OUTPUT "${res_rec_vp_src}/${res_file}.h" COMMAND perl ${CMAKE_SOURCE_DIR}/linux_various/hex2h.pl "${res_rec_vp_src}/${res_file}.png" "${res_rec_vp_src}/${res_file}" ) endforeach() +endif() if(USE_VTUNE) set(pcsx2FinalLibs ${pcsx2FinalLibs} ${VTUNE_LIBRARIES}) endif() -add_pcsx2_executable(${Output} "${pcsx2FinalSources}" "${pcsx2FinalLibs}" "${pcsx2FinalFlags}") +if(MSVC) +# include_directories(x86/ix86-32 IPU System) +# add_definitions(-D_ARCH_32=1 -D_M_X86_32) #32-bit + add_definitions(-D_M_X86 -D__i386__ -DTIXML_USE_STL -D_SCL_SECURE_NO_WARNINGS) + add_definitions(-D_ARCH_64=1 -D_M_X86_64 -D__M_X86_64) #64-bit + set(pcsx2FinalLibs ${pcsx2FinalLibs} baseclasses) + set(pcsx2FinalLibs ${pcsx2FinalLibs} comctl32 ws2_32 shlwapi winmm rpcrt4) +endif() + +if(LIBRETRO) +# add_link_options(-fuse-ld=gold) +# add_link_options(-Wl,--gc-sections,--print-symbol-counts,sym.log) + + add_library(${Output} SHARED + ${CMAKE_SOURCE_DIR}/libretro/main.cpp + ${CMAKE_SOURCE_DIR}/libretro/options.cpp + ${CMAKE_SOURCE_DIR}/libretro/input.cpp + ${pcsx2FinalSources} + ) + include_directories(. ${CMAKE_SOURCE_DIR}/libretro) +# set(LIBRARY_OUTPUT_PATH "${CMAKE_BINARY_DIR}") + set_target_properties(pcsx2_libretro PROPERTIES PREFIX "") + + if(CMAKE_C_COMPILER_ID MATCHES "Clang") + set(CLANG 1) + endif() + + if(NOT MSVC AND NOT CLANG) + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--no-undefined") + endif() + + target_link_libraries(pcsx2_libretro PRIVATE ${pcsx2FinalLibs}) + if(PACKAGE_MODE) + install(TARGETS ${Output} DESTINATION ${BIN_DIR}) + else(PACKAGE_MODE) + install(TARGETS ${Output} DESTINATION ${CMAKE_SOURCE_DIR}/bin) + endif(PACKAGE_MODE) +else() + add_pcsx2_executable(${Output} "${pcsx2FinalSources}" "${pcsx2FinalLibs}" "${pcsx2FinalFlags}") +endif() target_compile_features(${Output} PRIVATE cxx_std_17) -if(COMMAND target_precompile_headers) +if(COMMAND target_precompile_headers AND NOT CCACHE_FOUND) message("Using precompiled headers.") target_precompile_headers(${Output} PRIVATE PrecompiledHeader.h) endif() @@ -864,10 +951,10 @@ if (APPLE) add_dependencies(pcsx2-postprocess-bundle ${Output}) endif() -if(dev9ghzdrk) - if(PACKAGE_MODE) - install(CODE "execute_process(COMMAND /bin/bash -c \"echo 'Enabling networking capability on Linux...';set -x; [ -f ${BIN_DIR}/${Output} ] && sudo setcap 'CAP_NET_RAW+eip CAP_NET_ADMIN+eip' ${BIN_DIR}/${Output}; set +x\")") - else() - install(CODE "execute_process(COMMAND /bin/bash -c \"echo 'Enabling networking capability on Linux...';set -x; [ -f ${CMAKE_SOURCE_DIR}/bin/${Output} ] && sudo setcap 'CAP_NET_RAW+eip CAP_NET_ADMIN+eip' ${CMAKE_SOURCE_DIR}/bin/${Output}; set +x\")") - endif() -endif() \ No newline at end of file +#if(dev9ghzdrk) +# if(PACKAGE_MODE) +# install(CODE "execute_process(COMMAND /bin/bash -c \"echo 'Enabling networking capability on Linux...';set -x; [ -f ${BIN_DIR}/${Output} ] && sudo setcap 'CAP_NET_RAW+eip CAP_NET_ADMIN+eip' ${BIN_DIR}/${Output}; set +x\")") +# else() +# install(CODE "execute_process(COMMAND /bin/bash -c \"echo 'Enabling networking capability on Linux...';set -x; [ -f ${CMAKE_SOURCE_DIR}/bin/${Output} ] && sudo setcap 'CAP_NET_RAW+eip CAP_NET_ADMIN+eip' ${CMAKE_SOURCE_DIR}/bin/${Output}; set +x\")") +# endif() +#endif() diff --git a/pcsx2/Config.h b/pcsx2/Config.h index 1bfd034948b0c..1803f5cae74bc 100644 --- a/pcsx2/Config.h +++ b/pcsx2/Config.h @@ -15,6 +15,7 @@ #pragma once +#include "PrecompiledHeader.h" #include "x86emitter/tools.h" class IniInterface; diff --git a/pcsx2/DebugTools/Breakpoints.cpp b/pcsx2/DebugTools/Breakpoints.cpp index 8ac1984037181..c02ecc220e33b 100644 --- a/pcsx2/DebugTools/Breakpoints.cpp +++ b/pcsx2/DebugTools/Breakpoints.cpp @@ -383,8 +383,9 @@ const std::vector CBreakPoints::GetBreakpoints() // including them earlier causes some ambiguities #include "App.h" +#if wxUSE_GUI #include "Debugger/DisassemblyDialog.h" - +#endif void CBreakPoints::Update(u32 addr) { bool resume = false; @@ -401,7 +402,9 @@ void CBreakPoints::Update(u32 addr) if (resume) r5900Debug.resumeCpu(); +#if wxUSE_GUI auto disassembly_window = wxGetApp().GetDisassemblyPtr(); if (disassembly_window) // make sure that valid pointer is recieved to prevent potential NULL dereference. disassembly_window->update(); +#endif } diff --git a/pcsx2/GS.cpp b/pcsx2/GS.cpp index 235f2c6891684..fbac39af0eca2 100644 --- a/pcsx2/GS.cpp +++ b/pcsx2/GS.cpp @@ -58,6 +58,7 @@ void gsReset() void gsUpdateFrequency(Pcsx2Config& config) { +#ifndef __LIBRETRO__ switch (g_LimiterMode) { case LimiterModeType::Limit_Nominal: @@ -73,6 +74,7 @@ void gsUpdateFrequency(Pcsx2Config& config) pxAssert("Unknown framelimiter mode!"); } UpdateVSyncRate(); +#endif } static __fi void gsCSRwrite( const tGS_CSR& csr ) diff --git a/pcsx2/GS.h b/pcsx2/GS.h index 326fe21941eaa..6d9e0c6342f8c 100644 --- a/pcsx2/GS.h +++ b/pcsx2/GS.h @@ -307,9 +307,15 @@ struct MTGS_FreezeData // -------------------------------------------------------------------------------------- // SysMtgsThread // -------------------------------------------------------------------------------------- +#ifdef __LIBRETRO__ +class SysMtgsThread : public SysFakeThread +{ + typedef SysFakeThread _parent; +#else class SysMtgsThread : public SysThreadBase { typedef SysThreadBase _parent; +#endif public: // note: when m_ReadPos == m_WritePos, the fifo is empty @@ -377,10 +383,16 @@ class SysMtgsThread : public SysThreadBase bool IsPluginOpened() const { return m_PluginOpened; } -protected: +#ifdef __LIBRETRO__ + void StepFrame(); + void Flush(); + void SignalVsync(); + void ExecuteTaskInThread(bool flush_all = false); +#endif void OpenPlugin(); void ClosePlugin(); +protected: void OnStart(); void OnResumeReady(); @@ -393,7 +405,9 @@ class SysMtgsThread : public SysThreadBase // Used internally by SendSimplePacket type functions void _FinishSimplePacket(); +#ifndef __LIBRETRO__ void ExecuteTaskInThread(); +#endif }; // GetMTGS() is a required external implementation. This function is *NOT* provided diff --git a/pcsx2/IPC.h b/pcsx2/IPC.h index 43789ce0b6f9f..bfe403cd4c1b0 100644 --- a/pcsx2/IPC.h +++ b/pcsx2/IPC.h @@ -18,6 +18,10 @@ #pragma once +#if _WIN32 +#include +#endif + #include "Utilities/PersistentThread.h" #include "System/SysThreads.h" diff --git a/pcsx2/MTGS.cpp b/pcsx2/MTGS.cpp index 1c4a0ee2db16a..770e97eae3681 100644 --- a/pcsx2/MTGS.cpp +++ b/pcsx2/MTGS.cpp @@ -50,7 +50,11 @@ std::list ringposStack; #endif SysMtgsThread::SysMtgsThread() : +#ifdef __LIBRETRO__ + SysFakeThread() +#else SysThreadBase() +#endif #ifdef RINGBUF_DEBUG_STACK , m_lock_Stack() #endif @@ -188,6 +192,9 @@ static void dummyIrqCallback() void SysMtgsThread::OpenPlugin() { +#ifdef __LIBRETRO__ + m_thread = pthread_self(); +#endif if( m_PluginOpened ) return; @@ -271,7 +278,11 @@ class RingBufferLock { } }; +#ifdef __LIBRETRO__ +void SysMtgsThread::ExecuteTaskInThread(bool flush_all) +#else void SysMtgsThread::ExecuteTaskInThread() +#endif { // Threading info: run in MTGS thread // m_ReadPos is only update by the MTGS thread so it is safe to load it with a relaxed atomic @@ -445,7 +456,10 @@ void SysMtgsThread::ExecuteTaskInThread() ((GSRegSIGBLID&)RingBuffer.Regs[0x1080]) = (GSRegSIGBLID&)remainder[2]; // CSR & 0x2000; is the pageflip id. - GSvsync(((u32&)RingBuffer.Regs[0x1000]) & 0x2000); +#ifdef __LIBRETRO__ + if(!flush_all) +#endif + GSvsync(((u32&)RingBuffer.Regs[0x1000]) & 0x2000); gsFrameSkip(); // if we're not using GSOpen2, then the GS window is on this thread (MTGS thread), @@ -499,13 +513,17 @@ void SysMtgsThread::ExecuteTaskInThread() case GS_RINGTYPE_INIT_READ_FIFO1: MTGS_LOG( "(MTGS Packet Read) ringtype=Fifo1" ); +#ifndef BUILTIN_GS_PLUGIN if (GSinitReadFIFO) +#endif GSinitReadFIFO( (u64*)tag.pointer); break; case GS_RINGTYPE_INIT_READ_FIFO2: MTGS_LOG( "(MTGS Packet Read) ringtype=Fifo2, size=%d", tag.data[0] ); +#ifndef BUILTIN_GS_PLUGIN if (GSinitReadFIFO2) +#endif GSinitReadFIFO2( (u64*)tag.pointer, tag.data[0]); break; @@ -540,9 +558,24 @@ void SysMtgsThread::ExecuteTaskInThread() // Make sure to post the signal after the m_ReadPos has been updated... m_SignalRingEnable.store(false, std::memory_order_release); m_sem_OnRingReset.Post(); +#ifndef __LIBRETRO__ continue; +#endif } } +#ifdef __LIBRETRO__ + if(!flush_all && tag.command == GS_RINGTYPE_VSYNC) { + busy.Release(); + return; + } + if(flush_all && + !gifUnit.gifPath[GIF_PATH_1].getReadAmount() && + !gifUnit.gifPath[GIF_PATH_2].getReadAmount() && + !gifUnit.gifPath[GIF_PATH_3].getReadAmount()){ + busy.Release(); + return; + } +#endif } busy.Release(); @@ -564,9 +597,48 @@ void SysMtgsThread::ExecuteTaskInThread() //Console.Warning( "(MTGS Thread) Nothing to do! ringpos=0x%06x", m_ReadPos ); } } +#ifdef __LIBRETRO__ +void SysMtgsThread::StepFrame() +{ + pxAssert(IsSelf()); + ExecuteTaskInThread(false); +} + +void SysMtgsThread::Flush() +{ + if (m_VsyncSignalListener.exchange(false)) + m_sem_Vsync.Post(); + + pxAssert(IsSelf()); + if(!gifUnit.gifPath[GIF_PATH_1].getReadAmount() && + !gifUnit.gifPath[GIF_PATH_2].getReadAmount() && + !gifUnit.gifPath[GIF_PATH_3].getReadAmount()) + return; + + SetEvent(); + ExecuteTaskInThread(true); +} +void SysMtgsThread::SignalVsync() +{ + if (m_VsyncSignalListener.exchange(false)) + m_sem_Vsync.Post(); +} + +#endif void SysMtgsThread::ClosePlugin() { +#ifdef __LIBRETRO__ + if( m_SignalRingEnable.exchange(false) ) + { + //Console.Warning( "(MTGS Thread) Dangling RingSignal on empty buffer! signalpos=0x%06x", m_SignalRingPosition.exchange(0) ) ); + m_SignalRingPosition.store(0, std::memory_order_release); + m_sem_OnRingReset.Post(); + } + if (m_VsyncSignalListener.exchange(false)) + m_sem_Vsync.Post(); +// m_thread = {}; +#endif if( !m_PluginOpened ) return; m_PluginOpened = false; GetCorePlugins().Close( PluginId_GS ); @@ -598,7 +670,15 @@ void SysMtgsThread::OnCleanupInThread() // If isMTVU, then this implies this function is being called from the MTVU thread... void SysMtgsThread::WaitGS(bool syncRegs, bool weakWait, bool isMTVU) { +#ifdef __LIBRETRO__ + if(IsSelf()) + { + GetMTGS().Flush(); + return; + } +#else pxAssertDev( !IsSelf(), "This method is only allowed from threads *not* named MTGS." ); +#endif if( m_ExecMode == ExecMode_NoThreadYet || !IsRunning() ) return; if( !pxAssertDev( IsOpen(), "MTGS Warning! WaitGS issued on a closed thread." ) ) return; @@ -883,6 +963,14 @@ void SysMtgsThread::WaitForOpen() void SysMtgsThread::Freeze( int mode, MTGS_FreezeData& data ) { +#ifdef __LIBRETRO__ + if(IsSelf()) + { + Flush(); + data.retval = GetCorePlugins().DoFreeze( PluginId_GS, mode, data.fdata ); + return; + } +#endif GetCorePlugins().Open( PluginId_GS ); SendPointerPacket( GS_RINGTYPE_FREEZE, mode, &data ); Resume(); diff --git a/pcsx2/MTVU.cpp b/pcsx2/MTVU.cpp index 72a70cd1fc19d..1e2dc0922c328 100644 --- a/pcsx2/MTVU.cpp +++ b/pcsx2/MTVU.cpp @@ -64,7 +64,9 @@ VU_Thread::VU_Thread(BaseVUmicroCPU*& _vuCPU, VURegs& _vuRegs) : vuCPU(_vuCPU), vuRegs(_vuRegs) { m_name = L"MTVU"; +#ifndef __LIBRETRO__ /* can't call thread functions/locks from dlload in windows */ Reset(); +#endif } VU_Thread::~VU_Thread() diff --git a/pcsx2/PathDefs.h b/pcsx2/PathDefs.h index 01e85661cf6ef..f46db984dc4c5 100644 --- a/pcsx2/PathDefs.h +++ b/pcsx2/PathDefs.h @@ -15,6 +15,8 @@ #pragma once +#include "PrecompiledHeader.h" + enum FoldersEnum_t { // FIXME : Plugins and Settings folders are no longer part of the user-local diff --git a/pcsx2/PluginManager.cpp b/pcsx2/PluginManager.cpp index f4538a161077b..8ccd9096cd3c1 100644 --- a/pcsx2/PluginManager.cpp +++ b/pcsx2/PluginManager.cpp @@ -876,7 +876,9 @@ void SysCorePlugins::Load( const wxString (&folders)[PluginId_Count] ) indent.LeaveScope(); // Hack for PAD's stupid parameter passed on Init +#ifndef BUILTIN_PAD_PLUGIN PADinit = (_PADinit)m_info[PluginId_PAD]->CommonBindings.Init; +#endif m_info[PluginId_PAD]->CommonBindings.Init = _hack_PADinit; Console.WriteLn( Color_StrongBlue, "Plugins loaded successfully.\n" ); diff --git a/pcsx2/SPU2/Mixer.cpp b/pcsx2/SPU2/Mixer.cpp index a9af262138b56..517a40280ea29 100644 --- a/pcsx2/SPU2/Mixer.cpp +++ b/pcsx2/SPU2/Mixer.cpp @@ -783,7 +783,7 @@ StereoOut32 Apply_Frequency_Response_Filter(StereoOut32& SoundStream) StereoOut32 Apply_Dealias_Filter(StereoOut32& SoundStream) { - static StereoOut32 Old = StereoOut32::Empty; + static StereoOut32 Old; s32 l, r; @@ -823,7 +823,7 @@ __forceinline /*(PlayMode&4) ? StereoOut32::Empty : */ ApplyVolume(Cores[0].ReadInput(), Cores[0].InpVol), // CDDA is on Core 1: - (PlayMode & 8) ? StereoOut32::Empty : ApplyVolume(Cores[1].ReadInput(), Cores[1].InpVol)}; + (PlayMode & 8) ? StereoOut32(0, 0) : ApplyVolume(Cores[1].ReadInput(), Cores[1].InpVol)}; WaveDump::WriteCore(0, CoreSrc_Input, InputData[0]); WaveDump::WriteCore(1, CoreSrc_Input, InputData[1]); @@ -833,10 +833,10 @@ __forceinline MixCoreVoices(VoiceData[0], 0); MixCoreVoices(VoiceData[1], 1); - StereoOut32 Ext(Cores[0].Mix(VoiceData[0], InputData[0], StereoOut32::Empty)); + StereoOut32 Ext(Cores[0].Mix(VoiceData[0], InputData[0], StereoOut32(0, 0))); if ((PlayMode & 4) || (Cores[0].Mute != 0)) - Ext = StereoOut32::Empty; + Ext = StereoOut32(0, 0); else { Ext = clamp_mix(ApplyVolume(Ext, Cores[0].MasterVol)); @@ -886,11 +886,11 @@ __forceinline // Good thing though that this code gets the volume exactly right, as per tests :) Out = clamp_mix(Out, SndOutVolumeShift); } - +#ifndef __LIBRETRO__ // Configurable output volume Out.Left *= FinalVolume; Out.Right *= FinalVolume; - +#endif SndBuffer::Write(Out); // Update AutoDMA output positioning diff --git a/pcsx2/SPU2/Reverb.cpp b/pcsx2/SPU2/Reverb.cpp index 66f91fe48d60b..984cc52f7b010 100644 --- a/pcsx2/SPU2/Reverb.cpp +++ b/pcsx2/SPU2/Reverb.cpp @@ -52,7 +52,7 @@ StereoOut32 V_Core::DoReverb(const StereoOut32& Input) { if (EffectsBufferSize <= 0) { - return StereoOut32::Empty; + return StereoOut32(0, 0); } bool R = Cycles & 1; diff --git a/pcsx2/SPU2/spu2.cpp b/pcsx2/SPU2/spu2.cpp index 4bc9b38d2da91..ea78e4e54e722 100644 --- a/pcsx2/SPU2/spu2.cpp +++ b/pcsx2/SPU2/spu2.cpp @@ -66,7 +66,7 @@ static bool CheckSSE() return true; #endif } - +#ifndef __LIBRETRO__ void SPU2configure() { if (!CheckSSE()) @@ -76,7 +76,7 @@ void SPU2configure() configure(); paused_core.AllowResume(); } - +#endif // -------------------------------------------------------------------------------------- // DMA 4/7 Callbacks from Core Emulator // -------------------------------------------------------------------------------------- @@ -371,7 +371,7 @@ s32 SPU2open(void* pDsp) { SndBuffer::Init(); -#ifndef __POSIX__ +#if !defined(__POSIX__) && !defined(__LIBRETRO__) DspLoadLibrary(dspPlugin, dspPluginModule); #endif WaveDump::Open(); @@ -396,7 +396,7 @@ void SPU2close() FileLog("[%10d] SPU2 Close\n", Cycles); -#ifndef __POSIX__ +#if !defined(__POSIX__) && !defined(__LIBRETRO__) DspCloseLibrary(); #endif diff --git a/pcsx2/SPU2/spu2sys.cpp b/pcsx2/SPU2/spu2sys.cpp index d66ecc7d6393c..4aba2d9f6bbb5 100644 --- a/pcsx2/SPU2/spu2sys.cpp +++ b/pcsx2/SPU2/spu2sys.cpp @@ -399,7 +399,7 @@ __forceinline void TimeUpdate(u32 cClocks) dClocks = TickInterval * SanityInterval; lClocks = cClocks - dClocks; } - +#ifndef __LIBRETRO__ // Visual debug display showing all core's activity! Disabled via #define on release builds. #ifdef _WIN32 UpdateDebugDialog(); @@ -409,7 +409,7 @@ __forceinline void TimeUpdate(u32 cClocks) SndBuffer::UpdateTempoChangeAsyncMixing(); else TickInterval = 768; // Reset to default, in case the user hotswitched from async to something else. - +#endif //Update Mixing Progress while (dClocks >= TickInterval) { diff --git a/pcsx2/System.cpp b/pcsx2/System.cpp index 37246ca2e5014..f736dff888172 100644 --- a/pcsx2/System.cpp +++ b/pcsx2/System.cpp @@ -78,7 +78,9 @@ void RecompiledCodeReserve::Reset() bool RecompiledCodeReserve::Commit() { bool status = _parent::Commit(); - +#if defined(_WIN32) && defined(__LIBRETRO__) // TODO: investigate +#define IsDevBuild true +#endif if (IsDevBuild && m_baseptr) { // Clear the recompiled code block to 0xcc (INT3) -- this helps disasm tools show diff --git a/pcsx2/System/SysFakeThread.cpp b/pcsx2/System/SysFakeThread.cpp new file mode 100644 index 0000000000000..a58ac0c3f4374 --- /dev/null +++ b/pcsx2/System/SysFakeThread.cpp @@ -0,0 +1,338 @@ +/* PCSX2 - PS2 Emulator for PCs + * Copyright (C) 2002-2010 PCSX2 Dev Team + * + * PCSX2 is free software: you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with PCSX2. + * If not, see . + */ +#ifdef __LIBRETRO__ +#include "PrecompiledHeader.h" + +#include "System.h" +#include "SysThreads.h" + +// -------------------------------------------------------------------------------------- +// SysFakeThread *External Thread* Implementations +// (Called form outside the context of this thread) +// -------------------------------------------------------------------------------------- + +SysFakeThread::SysFakeThread() : + m_ExecMode( ExecMode_NoThreadYet ) +, m_ExecModeMutex() + , m_thread{} +{ +} + +void SysFakeThread::Start() +{ +// Sleep( 1 ); + m_running = true; +// m_sem_event.Post(); + OnStart(); +} + +void SysFakeThread::OnStart() +{ + if( !pxAssertDev( m_ExecMode == ExecMode_NoThreadYet, "SysFakeThread:Start(): Invalid execution mode" ) ) return; + + m_sem_Resume.Reset(); + m_sem_ChangingExecMode.Reset(); + + m_ExecModeMutex.RecreateIfLocked(); + m_RunningLock.RecreateIfLocked(); + m_sem_event.Reset(); + m_ExecMode = ExecMode_Closed; +// StateCheckInThread(); +} + +// Suspends emulation and closes the emulation state (including plugins) at the next PS2 vsync, +// and returns control to the calling thread; or does nothing if the core is already suspended. +// +// Parameters: +// isNonblocking - if set to true then the function will not block for emulation suspension. +// Defaults to false if parameter is not specified. Performing non-blocking suspension +// is mostly useful for starting certain non-Emu related gui activities (improves gui +// responsiveness). +// +// Returns: +// The previous suspension state; true if the thread was running or false if it was +// suspended. +// +// Exceptions: +// CancelEvent - thrown if the thread is already in a Paused or Closing state. Because +// actions that pause emulation typically rely on plugins remaining loaded/active, +// Suspension must cancel itself forcefully or risk crashing whatever other action is +// in progress. +// +void SysFakeThread::Suspend( bool isBlocking ) +{ + if (!pxAssertDev(!IsSelf(),"Suspend/Resume are not allowed from this thread.")) return; + if (!IsRunning()) return; + + // shortcut ExecMode check to avoid deadlocking on redundant calls to Suspend issued + // from Resume or OnResumeReady code. + if( m_ExecMode == ExecMode_Closed ) return; + + { + ScopedLock locker( m_ExecModeMutex ); + + switch( m_ExecMode.load() ) + { + // Invalid thread state, nothing to suspend + case ExecMode_NoThreadYet: + // Check again -- status could have changed since above. + case ExecMode_Closed: return; + + case ExecMode_Pausing: + case ExecMode_Paused: + if( !isBlocking ) + throw Exception::CancelEvent( L"Cannot suspend in non-blocking fashion: Another thread is pausing the VM state." ); + + m_ExecMode = ExecMode_Closing; + m_sem_Resume.Post(); + m_sem_ChangingExecMode.Wait(); + break; + + case ExecMode_Opened: + m_ExecMode = ExecMode_Closing; + break; + + case ExecMode_Closing: + break; + } + + pxAssertDev( m_ExecMode == ExecMode_Closing, "ExecMode should be nothing other than Closing..." ); + m_sem_event.Post(); + } + + if( isBlocking ) + m_RunningLock.Wait(); +} + +// Returns: +// The previous suspension state; true if the thread was running or false if it was +// closed, not running, or paused. +// +void SysFakeThread::Pause(bool debug) +{ + if( IsSelf() || !IsRunning() ) return; + + // shortcut ExecMode check to avoid deadlocking on redundant calls to Suspend issued + // from Resume or OnResumeReady code. + if( (m_ExecMode == ExecMode_Closed) || (m_ExecMode == ExecMode_Paused) ) return; + + { + ScopedLock locker( m_ExecModeMutex ); + + // Check again -- status could have changed since above. + if( (m_ExecMode == ExecMode_Closed) || (m_ExecMode == ExecMode_Paused) ) return; + + if( m_ExecMode == ExecMode_Opened ) + m_ExecMode = ExecMode_Pausing; + + pxAssertDev( m_ExecMode == ExecMode_Pausing, "ExecMode should be nothing other than Pausing..." ); + + if (debug) + OnPauseDebug(); + else + OnPause(); + m_sem_event.Post(); + } + + m_RunningLock.Wait(); +} + +void SysFakeThread::PauseSelf() +{ + if( !IsSelf() || !IsRunning() ) return; + + { + ScopedLock locker( m_ExecModeMutex ); + + if( m_ExecMode == ExecMode_Opened ) + m_ExecMode = ExecMode_Pausing; + + OnPause(); + m_sem_event.Post(); + } +} + +void SysFakeThread::PauseSelfDebug() +{ + if (!IsSelf() || !IsRunning()) return; + + { + ScopedLock locker(m_ExecModeMutex); + + if (m_ExecMode == ExecMode_Opened) + m_ExecMode = ExecMode_Pausing; + + OnPauseDebug(); + m_sem_event.Post(); + } +} + +// Resumes the core execution state, or does nothing is the core is already running. If +// settings were changed, resets will be performed as needed and emulation state resumed from +// memory savestates. +// +// Note that this is considered a non-blocking action. Most times the state is safely resumed +// on return, but in the case of re-entrant or nested message handling the function may return +// before the thread has resumed. If you need explicit behavior tied to the completion of the +// Resume, you'll need to bind callbacks to either OnResumeReady or OnResumeInThread. +// +// Exceptions: +// PluginInitError - thrown if a plugin fails init (init is performed on the current thread +// on the first time the thread is resumed from it's initial idle state) +// ThreadCreationError - Insufficient system resources to create thread. +// +void SysFakeThread::Resume() +{ + if( IsSelf() ) return; + if( m_ExecMode == ExecMode_Opened ) return; + + ScopedLock locker( m_ExecModeMutex ); + + // Implementation Note: + // The entire state coming out of a Wait is indeterminate because of user input + // and pending messages being handled. So after each call we do some seemingly redundant + // sanity checks against m_ExecMode/m_Running status, and if something doesn't feel + // right, we should abort; the user may have canceled the action before it even finished. + + switch( m_ExecMode.load() ) + { + case ExecMode_Opened: return; + + case ExecMode_NoThreadYet: + { + Start(); + if( m_ExecMode == ExecMode_Opened ) return; + } + // fall through... + + case ExecMode_Closing: + case ExecMode_Pausing: + // we need to make sure and wait for the emuThread to enter a fully suspended + // state before continuing... + + m_RunningLock.Wait(); + if( !m_running ) return; + if( (m_ExecMode != ExecMode_Closed) && (m_ExecMode != ExecMode_Paused) ) return; + if( !GetCorePlugins().AreLoaded() ) return; + break; + + case ExecMode_Paused: + case ExecMode_Closed: + break; + } + + pxAssertDev( (m_ExecMode == ExecMode_Closed) || (m_ExecMode == ExecMode_Paused), + "SysFakeThread is not in a closed/paused state? wtf!" ); + + OnResumeReady(); + m_ExecMode = ExecMode_Opened; + m_sem_Resume.Post(); +} + + +// -------------------------------------------------------------------------------------- +// SysFakeThread *Worker* Implementations +// (Called from the context of this thread only) +// -------------------------------------------------------------------------------------- + +void SysFakeThread::OnStartInThread() +{ + m_RunningLock.Acquire(); +// m_detached = false; + m_running = true; +// m_native_id = (uptr)pthread_self(); + m_ExecMode = ExecMode_Closing; +} + +void SysFakeThread::OnCleanupInThread() +{ + m_ExecMode = ExecMode_NoThreadYet; + m_RunningLock.Release(); +} + +void SysFakeThread::OnSuspendInThread() {} +void SysFakeThread::OnResumeInThread( bool isSuspended ) {} + +// Tests for Pause and Suspend/Close requests. If the thread is trying to be paused or +// closed, it will enter a wait/holding pattern here in this method until the managing +// thread releases it. Use the return value to detect if changes to the thread's state +// may have been changed (based on the rule that other threads are not allowed to modify +// this thread's state without pausing or closing it first, to prevent race conditions). +// +// Return value: +// TRUE if the thread was paused or closed; FALSE if the thread +// continued execution unimpeded. +bool SysFakeThread::StateCheckInThread() +{ + switch( m_ExecMode.load() ) + { + + #ifdef PCSX2_DEVBUILD // optimize out handlers for these cases in release builds. + case ExecMode_NoThreadYet: + // threads should never have this state set while the thread is in any way + // active or alive. (for obvious reasons!!) + pxFailDev( "Invalid execution state detected." ); + return false; + #endif + + case ExecMode_Opened: + return false; + + // ------------------------------------- + case ExecMode_Pausing: + { + OnPauseInThread(); + m_ExecMode = ExecMode_Paused; + m_RunningLock.Release(); + } + // fallthrough... + + case ExecMode_Paused: + while( m_ExecMode == ExecMode_Paused ) + m_sem_Resume.WaitWithoutYield(); + + m_RunningLock.Acquire(); + if( m_ExecMode != ExecMode_Closing ) + { + OnResumeInThread( false ); + break; + } + m_sem_ChangingExecMode.Post(); + + // fallthrough if we're switching to closing state... + + // ------------------------------------- + case ExecMode_Closing: + { + OnSuspendInThread(); + m_ExecMode = ExecMode_Closed; + m_RunningLock.Release(); + } + // Fall through + + case ExecMode_Closed: + while( m_ExecMode == ExecMode_Closed ) + m_sem_Resume.WaitWithoutYield(); + + m_RunningLock.Acquire(); + OnResumeInThread( true ); + break; + + jNO_DEFAULT; + } + + return true; +} +#endif diff --git a/pcsx2/System/SysThreads.h b/pcsx2/System/SysThreads.h index 790f47f37aff6..ddc81c72e9d17 100644 --- a/pcsx2/System/SysThreads.h +++ b/pcsx2/System/SysThreads.h @@ -156,8 +156,149 @@ class SysThreadBase : public pxThread // FALSE if it's returning from a paused state. virtual void OnResumeInThread( bool isSuspended )=0; }; +#ifdef __LIBRETRO__ +// -------------------------------------------------------------------------------------- +// SysFakeThread +// -------------------------------------------------------------------------------------- + +class SysFakeThread +{ + +public: + // Important: The order of these enumerations matters! Optimized tests are used for both + // Closed and Paused states. + enum ExecutionMode + { + // Thread has not been created yet. Typically this is the same as IsRunning() + // returning FALSE. + ExecMode_NoThreadYet, + + // Thread is safely paused, with plugins in a "closed" state, and waiting for a + // resume/open signal. + ExecMode_Closed, + + // Thread is safely paused, with plugins in an "open" state, and waiting for a + // resume/open signal. + ExecMode_Paused, + + // Thread is active and running, with pluigns in an "open" state. + ExecMode_Opened, + // Close signal has been sent to the thread, but the thread's response is still + // pending (thread is busy/running). + ExecMode_Closing, + + // Pause signal has been sent to the thread, but the thread's response is still + // pending (thread is busy/running). + ExecMode_Pausing, + }; + +protected: + std::atomic m_ExecMode; + + // This lock is used to avoid simultaneous requests to Suspend/Resume/Pause from + // contending threads. + MutexRecursive m_ExecModeMutex; + + // Used to wake up the thread from sleeping when it's in a suspended state. + Semaphore m_sem_Resume; + + // Used to synchronize inline changes from paused to suspended status. + Semaphore m_sem_ChangingExecMode; + + // Locked whenever the thread is not in a suspended state (either closed or paused). + // Issue a Wait against this mutex for performing actions that require the thread + // to be suspended. + Mutex m_RunningLock; + + Semaphore m_sem_event; // general wait event that's needed by most threads + std::atomic m_running; // set true by Start(), and set false by Cancel(), Block(), etc. + wxString m_name; // diagnostic name for our thread. + pthread_t m_thread; +public: + explicit SysFakeThread(); + virtual ~SysFakeThread() = default; + + // Thread safety for IsOpen / IsClosed: The execution mode can change at any time on + // any thread, so the actual status may have already changed by the time this function + // returns its result. Typically this isn't of major concern. However if you need + // more assured execution mode status, issue a lock against the ExecutionModeMutex() + // first. + bool IsRunning() const { return m_running; } + bool IsSelf() const { return pthread_self() == m_thread; } + + bool IsOpen() const + { + return IsRunning() && (m_ExecMode > ExecMode_Closed); + } + bool IsClosed() const { return !IsOpen(); } + bool IsPaused() const { return !IsRunning() || (m_ExecMode <= ExecMode_Paused); } + + bool IsClosing() const + { + return !IsRunning() || (m_ExecMode <= ExecMode_Closed) || (m_ExecMode == ExecMode_Closing); + } + + bool HasPendingStateChangeRequest() const + { + return m_ExecMode >= ExecMode_Closing; + } + + ExecutionMode GetExecutionMode() const { return m_ExecMode.load(); } + Mutex& ExecutionModeMutex() { return m_ExecModeMutex; } + + virtual void Suspend( bool isBlocking = true ); + virtual void Resume(); + virtual void Pause(bool debug = false); + virtual void PauseSelf(); + virtual void PauseSelfDebug(); + virtual void Cancel(bool isBlocking = true) { m_running = false; } + virtual void RethrowException() const {} + + u64 GetCpuTime() const { return GetThreadCpuTime(); } + bool HasPendingException() const { return false; } + +protected: + virtual void OnStart(); + + // This function is called by Resume immediately prior to releasing the suspension of + // the core emulation thread. You should overload this rather than Resume(), since + // Resume() has a lot of checks and balances to prevent re-entrance and race conditions. + virtual void OnResumeReady() {} + virtual void OnPause() {} + virtual void OnPauseDebug() {} + + virtual bool StateCheckInThread(); + virtual void OnCleanupInThread(); + virtual void OnStartInThread(); + + // Used internally from Resume(), so let's make it private here. + virtual void Start(); + + // Extending classes should implement this, but should not call it. The parent class + // handles invocation by the following guidelines: Called *in thread* from StateCheckInThread() + // prior to suspending the thread (ie, when Suspend() has been called on a separate + // thread, requesting this thread suspend itself temporarily). After this is called, + // the thread enters a waiting state on the m_sem_Resume semaphore. + virtual void OnSuspendInThread()=0; + + // Extending classes should implement this, but should not call it. The parent class + // handles invocation by the following guidelines: Called *in thread* from StateCheckInThread() + // prior to pausing the thread (ie, when Pause() has been called on a separate thread, + // requesting this thread pause itself temporarily). After this is called, the thread + // enters a waiting state on the m_sem_Resume semaphore. + virtual void OnPauseInThread()=0; + + // Extending classes should implement this, but should not call it. The parent class + // handles invocation by the following guidelines: Called from StateCheckInThread() after the + // thread has been suspended and then subsequently resumed. + // Parameter: + // isSuspended - set to TRUE if the thread is returning from a suspended state, or + // FALSE if it's returning from a paused state. + virtual void OnResumeInThread( bool isSuspended )=0; +}; +#endif // -------------------------------------------------------------------------------------- // SysCoreThread class // -------------------------------------------------------------------------------------- diff --git a/pcsx2/gui/App.h b/pcsx2/gui/App.h index f19a1e8720811..304cd74aeb8af 100644 --- a/pcsx2/gui/App.h +++ b/pcsx2/gui/App.h @@ -25,9 +25,10 @@ #include "AppCommon.h" #include "AppCoreThread.h" +#if wxUSE_GUI #include "RecentIsoList.h" #include "DriveList.h" - +#endif #ifndef DISABLE_RECORDING # include "Recording/VirtualPad/VirtualPad.h" # include "Recording/NewRecordingFrame.h" @@ -285,12 +286,13 @@ class pxAppResources { public: AppImageIds ImageId; - +#ifndef __LIBRETRO__ std::unique_ptr ConfigImages; std::unique_ptr ToolbarImages; std::unique_ptr IconBundle; std::unique_ptr Bitmap_Logo; std::unique_ptr ScreenshotBitmap; +#endif std::unique_ptr GameDB; pxAppResources(); @@ -422,9 +424,14 @@ class CommandlineOverrides // ===================================================================================================== // Pcsx2App - main wxApp class // ===================================================================================================== +#if defined(__LIBRETRO__) && 0 +class Pcsx2App +{ +#else class Pcsx2App : public wxAppWithHelpers { typedef wxAppWithHelpers _parent; +#endif // ---------------------------------------------------------------------------- // Event Sources! @@ -518,9 +525,10 @@ class Pcsx2App : public wxAppWithHelpers public: FramerateManager FpsManager; +#ifndef __LIBRETRO__ std::unique_ptr GlobalCommands; std::unique_ptr GlobalAccels; - +#endif StartupOptions Startup; CommandlineOverrides Overrides; @@ -530,8 +538,10 @@ class Pcsx2App : public wxAppWithHelpers std::unique_ptr m_StdoutRedirHandle; std::unique_ptr m_StderrRedirHandle; +#if wxUSE_GUI std::unique_ptr m_RecentIsoList; std::unique_ptr m_DriveList; +#endif std::unique_ptr m_Resources; public: @@ -552,9 +562,9 @@ class Pcsx2App : public wxAppWithHelpers wxWindowID m_id_VirtualPad[2]; wxWindowID m_id_NewRecordingFrame; #endif - +#if wxUSE_GUI wxKeyEvent m_kevt; - +#endif public: Pcsx2App(); virtual ~Pcsx2App(); @@ -572,11 +582,11 @@ class Pcsx2App : public wxAppWithHelpers GSFrame& GetGsFrame() const; MainEmuFrame& GetMainFrame() const; - +#if wxUSE_GUI GSFrame* GetGsFramePtr() const { return (GSFrame*)wxWindow::FindWindowById( m_id_GsFrame ); } MainEmuFrame* GetMainFramePtr() const { return (MainEmuFrame*)wxWindow::FindWindowById( m_id_MainFrame ); } DisassemblyDialog* GetDisassemblyPtr() const { return (DisassemblyDialog*)wxWindow::FindWindowById(m_id_Disassembler); } - +#endif #ifndef DISABLE_RECORDING VirtualPad* GetVirtualPadPtr(int port) const { return (VirtualPad*)wxWindow::FindWindowById(m_id_VirtualPad[port]); } NewRecordingFrame* GetNewRecordingFramePtr() const { return (NewRecordingFrame*)wxWindow::FindWindowById(m_id_NewRecordingFrame); } @@ -585,8 +595,11 @@ class Pcsx2App : public wxAppWithHelpers void enterDebugMode(); void leaveDebugMode(); void resetDebugger(); - +#if wxUSE_GUI bool HasMainFrame() const { return GetMainFramePtr() != NULL; } +#else + bool HasMainFrame() const { return false; } +#endif void OpenGsPanel(); void CloseGsPanel(); @@ -620,18 +633,17 @@ class Pcsx2App : public wxAppWithHelpers // -------------------------------------------------------------------------- // All of these accessors cache the resources on first use and retain them in // memory until the program exits. - + pxAppResources& GetResourceCache(); +#if wxUSE_GUI wxMenu& GetRecentIsoMenu(); RecentIsoManager& GetRecentIsoManager(); wxMenu& GetDriveListMenu(); - - pxAppResources& GetResourceCache(); const wxIconBundle& GetIconBundle(); const wxBitmap& GetLogoBitmap(); const wxBitmap& GetScreenshotBitmap(); wxImageList& GetImgList_Config(); wxImageList& GetImgList_Toolbars(); - +#endif const AppImageIds& GetImgId() const; AppGameDatabase* GetGameDatabase(); @@ -668,15 +680,15 @@ class Pcsx2App : public wxAppWithHelpers void DisableDiskLogging() const; void OnProgramLogClosed( wxWindowID id ); + void AllocateCoreStuffs(); + void CleanupOnExit(); protected: bool AppRpc_TryInvoke( FnPtr_Pcsx2App method ); bool AppRpc_TryInvokeAsync( FnPtr_Pcsx2App method ); - void AllocateCoreStuffs(); void InitDefaultGlobalAccelerators(); void BuildCommandHash(); bool TryOpenConfigCwd(); - void CleanupOnExit(); void OpenWizardConsole(); void PadKeyDispatch( const keyEvent& ev ); @@ -685,8 +697,8 @@ class Pcsx2App : public wxAppWithHelpers void HandleEvent(wxEvtHandler* handler, wxEventFunction func, wxEvent& event); void OnScheduledTermination( wxTimerEvent& evt ); - void OnEmuKeyDown( wxKeyEvent& evt ); void OnSysExecutorTaskTimeout( wxTimerEvent& evt ); + void OnEmuKeyDown( wxKeyEvent& evt ); void OnDestroyWindow( wxWindowDestroyEvent& evt ); // ---------------------------------------------------------------------------- @@ -730,7 +742,7 @@ wxDECLARE_APP(Pcsx2App); // #define sApp \ if( Pcsx2App* __app_ = (Pcsx2App*)wxApp::GetInstance() ) (*__app_) - +#if wxUSE_GUI #define sLogFrame \ if( ConsoleLogFrame* __conframe_ = wxGetApp().GetProgramLog() ) (*__conframe_) @@ -794,7 +806,7 @@ int AppOpenModalDialog(wxString panel_name, wxWindow* parent = NULL) } else return DialogType(parent).ShowModal(); } - +#endif extern pxDoAssertFnType AppDoAssert; // -------------------------------------------------------------------------------------- diff --git a/pcsx2/gui/AppAssert.cpp b/pcsx2/gui/AppAssert.cpp index 4ce151f86f8ea..6c93893a23a69 100644 --- a/pcsx2/gui/AppAssert.cpp +++ b/pcsx2/gui/AppAssert.cpp @@ -142,10 +142,14 @@ bool AppDoAssert( const DiagnosticOrigin& origin, const wxChar *msg ) else if( origin.condition != NULL ) windowmsg += origin.condition; +#if wxUSE_GUI int retval = Msgbox::Assertion( windowmsg, dbgmsg + L"\nStacktrace:\n" + trace ); if( retval == wxID_YES ) return true; if( retval == wxID_IGNORE ) disableAsserts = true; return false; +#else + return true; +#endif } diff --git a/pcsx2/gui/AppCommon.h b/pcsx2/gui/AppCommon.h index 082fb56a86039..78b68d169ef60 100644 --- a/pcsx2/gui/AppCommon.h +++ b/pcsx2/gui/AppCommon.h @@ -18,13 +18,13 @@ #include "Utilities/SafeArray.h" #include "Utilities/EventSource.h" #include "Utilities/PersistentThread.h" - +#if wxUSE_GUI #include "Utilities/wxGuiTools.h" #include "Utilities/pxRadioPanel.h" #include "Utilities/pxCheckBox.h" #include "Utilities/pxStaticText.h" #include "Utilities/CheckedStaticBox.h" - +#endif #include "AppForwardDefs.h" #include "AppConfig.h" #include "AppEventListeners.h" diff --git a/pcsx2/gui/AppConfig.cpp b/pcsx2/gui/AppConfig.cpp index 4322a6cb4a81f..d9219b7d28c8e 100644 --- a/pcsx2/gui/AppConfig.cpp +++ b/pcsx2/gui/AppConfig.cpp @@ -26,6 +26,9 @@ #include "DebugTools/Debug.h" #include +#if !wxUSE_GUI +const wxPoint wxDefaultPosition(wxDefaultCoord, wxDefaultCoord); +#endif ////////////////////////////////////////////////////////////////////////////////////////// // PathDefs Namespace -- contains default values for various pcsx2 path names and locations. // @@ -843,7 +846,7 @@ AppConfig::GSWindowOptions::GSWindowOptions() void AppConfig::GSWindowOptions::SanityCheck() { // Ensure Conformation of various options... - +#if wxUSE_GUI WindowSize.x = std::max( WindowSize.x, 8 ); WindowSize.x = std::min( WindowSize.x, wxGetDisplayArea().GetWidth()-16 ); @@ -857,6 +860,7 @@ void AppConfig::GSWindowOptions::SanityCheck() if( (uint)AspectRatio >= (uint)AspectRatio_MaxCount ) AspectRatio = AspectRatio_4_3; +#endif } void AppConfig::GSWindowOptions::LoadSave( IniInterface& ini ) @@ -989,7 +993,7 @@ int AppConfig::GetMaxPresetIndex() { return 5; } - +#if wxUSE_GUI bool AppConfig::isOkGetPresetTextAndColor( int n, wxString& label, wxColor& c ) { const wxString presetNamesAndColors[][2] = @@ -1009,7 +1013,7 @@ bool AppConfig::isOkGetPresetTextAndColor( int n, wxString& label, wxColor& c ) return true; } - +#endif // Apply one of several (currently 6) configuration subsets. // The scope of the subset which each preset controlls is hardcoded here. @@ -1120,6 +1124,7 @@ wxFileConfig* OpenFileConfig( const wxString& filename ) void RelocateLogfile() { +#ifndef __LIBRETRO__ g_Conf->Folders.Logs.Mkdir(); wxString newlogname( Path::Combine( g_Conf->Folders.Logs.ToString(), L"emuLog.txt" ) ); @@ -1140,6 +1145,7 @@ void RelocateLogfile() } wxGetApp().EnableAllLogging(); +#endif } // Parameters: @@ -1267,8 +1273,9 @@ static void LoadUiSettings() { AppIniLoader loader; ConLog_LoadSaveSettings( loader ); +#if wxUSE_GUI SysTraceLog_LoadSaveSettings( loader ); - +#endif g_Conf = std::make_unique(); g_Conf->LoadSave( loader ); @@ -1335,13 +1342,15 @@ static void SaveUiSettings() g_Conf->Folders.RunDisc.Clear(); } #endif - +#ifndef __LIBRETRO__ sApp.GetRecentIsoManager().Add( g_Conf->CurrentIso ); - +#endif AppIniSaver saver; g_Conf->LoadSave( saver ); ConLog_LoadSaveSettings( saver ); +#if wxUSE_GUI SysTraceLog_LoadSaveSettings( saver ); +#endif sApp.DispatchUiSettingsEvent( saver ); } diff --git a/pcsx2/gui/AppConfig.h b/pcsx2/gui/AppConfig.h index 872b6d9d45efc..a42f4505b3b67 100644 --- a/pcsx2/gui/AppConfig.h +++ b/pcsx2/gui/AppConfig.h @@ -18,6 +18,7 @@ #include "AppForwardDefs.h" #include "PathDefs.h" #include "CDVD/CDVDaccess.h" +#include #include enum DocsModeType @@ -376,7 +377,9 @@ class AppConfig void LoadSaveMemcards( IniInterface& ini ); static int GetMaxPresetIndex(); +#if wxUSE_GUI static bool isOkGetPresetTextAndColor(int n, wxString& label, wxColor& c); +#endif bool IsOkApplyPreset(int n, bool ignoreMTVU); diff --git a/pcsx2/gui/AppCoreThread.cpp b/pcsx2/gui/AppCoreThread.cpp index 0d389427ba590..757ffe683c540 100644 --- a/pcsx2/gui/AppCoreThread.cpp +++ b/pcsx2/gui/AppCoreThread.cpp @@ -153,6 +153,10 @@ void AppCoreThread::Suspend(bool isBlocking) bool result = GetSysExecutorThread().Rpc_TryInvokeAsync(_Suspend, L"AppCoreThread::Suspend"); pxAssert(result); } +#ifdef __LIBRETRO__ + if(!isBlocking && !GetSysExecutorThread().Rpc_TryInvokeAsync(_Suspend, L"AppCoreThread::Suspend")) + _parent::Suspend(false); +#endif else if (!GetSysExecutorThread().Rpc_TryInvoke(_Suspend, L"AppCoreThread::Suspend")) _parent::Suspend(true); } @@ -506,7 +510,7 @@ void LoadAllPatchesAndStuff(const Pcsx2Config& cfg) _ApplySettings(cfg, dummy); // And I'm hacking in updating the UI here too. -#ifdef USE_SAVESLOT_UI_UPDATES +#if defined(USE_SAVESLOT_UI_UPDATES) && !defined(__LIBRETRO__) UI_UpdateSysControls(); #endif } @@ -557,7 +561,9 @@ void AppCoreThread::OnResumeInThread(bool isSuspended) if (m_resetCdvd) { CDVDsys_ChangeSource(g_Conf->CdvdSource); +#ifndef __LIBRETRO__ cdvdCtrlTrayOpen(); +#endif m_resetCdvd = false; } @@ -584,7 +590,9 @@ void AppCoreThread::OnCleanupInThread() void AppCoreThread::VsyncInThread() { +#ifndef __LIBRETRO__ wxGetApp().LogicalVsync(); +#endif _parent::VsyncInThread(); } @@ -854,6 +862,7 @@ ScopedCoreThreadPause::~ScopedCoreThreadPause() ScopedCoreThreadPopup::ScopedCoreThreadPopup() { +#ifndef BUILTIN_GS_PLUGIN // The old style GUI (without GSopen2) must use a full close of the CoreThread, in order to // ensure that the GS window isn't blocking the popup, and to avoid crashes if the GS window // is maximized or fullscreen. @@ -861,6 +870,7 @@ ScopedCoreThreadPopup::ScopedCoreThreadPopup() if (!GSopen2) m_scoped_core = std::unique_ptr(new ScopedCoreThreadClose()); else +#endif m_scoped_core = std::unique_ptr(new ScopedCoreThreadPause()); }; diff --git a/pcsx2/gui/AppEventSources.cpp b/pcsx2/gui/AppEventSources.cpp index ae1f14278b814..38bb302323880 100644 --- a/pcsx2/gui/AppEventSources.cpp +++ b/pcsx2/gui/AppEventSources.cpp @@ -149,13 +149,15 @@ void Pcsx2App::DispatchEvent( CoreThreadStatus evt ) // Clear the sticky key statuses, because hell knows what'll change while the PAD // plugin is suspended. - +#if wxUSE_GUI m_kevt.m_shiftDown = false; m_kevt.m_controlDown = false; m_kevt.m_altDown = false; - +#endif m_evtsrc_CoreThreadStatus.Dispatch( evt ); +#if wxUSE_GUI ScopedBusyCursor::SetDefault( Cursor_NotBusy ); +#endif CoreThread.RethrowException(); } diff --git a/pcsx2/gui/AppInit.cpp b/pcsx2/gui/AppInit.cpp index 9f23c232ce3e6..7d9993e1bb497 100644 --- a/pcsx2/gui/AppInit.cpp +++ b/pcsx2/gui/AppInit.cpp @@ -14,8 +14,10 @@ */ #include "PrecompiledHeader.h" +#if wxUSE_GUI #include "MainFrame.h" #include "AppAccelerators.h" +#endif #include "ConsoleLogger.h" #include "MSWstuff.h" #include "MTVU.h" // for thread cancellation on shutdown @@ -35,9 +37,9 @@ #include #include #include - +#if wxUSE_GUI using namespace pxSizerFlags; - +#endif void Pcsx2App::DetectCpuAndUserMode() { AffinityAssert_AllowFrom_MainUI(); @@ -64,7 +66,7 @@ void Pcsx2App::DetectCpuAndUserMode() ShutdownPlugins(); UnloadPlugins(); } - +#ifndef __LIBRETRO__ void Pcsx2App::OpenMainFrame() { if( AppRpc_TryInvokeAsync( &Pcsx2App::OpenMainFrame ) ) return; @@ -132,6 +134,7 @@ void Pcsx2App::OpenProgramLog() } */ } +#endif void Pcsx2App::AllocateCoreStuffs() { @@ -154,7 +157,7 @@ void Pcsx2App::AllocateCoreStuffs() // HadSomeFailures only returns 'true' if an *enabled* cpu type fails to init. If // the user already has all interps configured, for example, then no point in // popping up this dialog. - +#if wxUSE_GUI wxDialogWithHelpers exconf( NULL, _("PCSX2 Recompiler Error(s)") ); wxTextCtrl* scrollableTextArea = new wxTextCtrl( @@ -168,38 +171,49 @@ void Pcsx2App::AllocateCoreStuffs() exconf += 6; exconf += scrollableTextArea | pxExpand.Border(wxALL, 16); +#endif Pcsx2Config::RecompilerOptions& recOps = g_Conf->EmuOptions.Cpu.Recompiler; if( BaseException* ex = m_CpuProviders->GetException_EE() ) { +#if wxUSE_GUI scrollableTextArea->AppendText( L"* R5900 (EE)\n\t" + ex->FormatDisplayMessage() + L"\n\n" ); +#endif recOps.EnableEE = false; } if( BaseException* ex = m_CpuProviders->GetException_IOP() ) { +#if wxUSE_GUI scrollableTextArea->AppendText( L"* R3000A (IOP)\n\t" + ex->FormatDisplayMessage() + L"\n\n" ); +#endif recOps.EnableIOP = false; } if( BaseException* ex = m_CpuProviders->GetException_MicroVU0() ) { +#if wxUSE_GUI scrollableTextArea->AppendText( L"* microVU0\n\t" + ex->FormatDisplayMessage() + L"\n\n" ); +#endif recOps.UseMicroVU0 = false; recOps.EnableVU0 = false; } if( BaseException* ex = m_CpuProviders->GetException_MicroVU1() ) { +#if wxUSE_GUI scrollableTextArea->AppendText( L"* microVU1\n\t" + ex->FormatDisplayMessage() + L"\n\n" ); +#endif recOps.UseMicroVU1 = false; recOps.EnableVU1 = false; } +#if wxUSE_GUI exconf += exconf.Heading(pxE( L"Note: Recompilers are not necessary for PCSX2 to run, however they typically improve emulation speed substantially. You may have to manually re-enable the recompilers listed above, if you resolve the errors." )); pxIssueConfirmation( exconf, MsgButtons().OK() ); +#endif } } @@ -296,6 +310,7 @@ bool Pcsx2App::ParseOverrides( wxCmdLineParser& parser ) { if( wxFileExists( dest ) ) Console.Warning( pi->GetShortname() + L" override: " + dest ); +#ifndef __LIBRETRO__ else { wxDialogWithHelpers okcan( NULL, AddAppName(_("Plugin Override Error - %s")) ); @@ -310,8 +325,9 @@ bool Pcsx2App::ParseOverrides( wxCmdLineParser& parser ) okcan += okcan.GetCharHeight(); okcan += okcan.Heading(AddAppName(_("Press OK to use the default configured plugin, or Cancel to close %s."))); - if( wxID_CANCEL == pxIssueConfirmation( okcan, MsgButtons().OKCancel() ) ) parsed = false; + if( wxID_CANCEL == pxIssueConfirmation( okcan, MsgButtons().OKCancel() ) ) parsed = false; } +#endif if (parsed) Overrides.Filenames.Plugins[pi->id] = dest; } @@ -322,6 +338,7 @@ bool Pcsx2App::ParseOverrides( wxCmdLineParser& parser ) bool Pcsx2App::OnCmdLineParsed( wxCmdLineParser& parser ) { +#ifndef __LIBRETRO__ if( parser.Found(L"console") ) { Startup.ForceConsole = true; @@ -333,7 +350,7 @@ bool Pcsx2App::OnCmdLineParsed( wxCmdLineParser& parser ) m_UseGUI = !parser.Found(L"nogui"); m_NoGuiExitPrompt = parser.Found(L"noguiprompt"); // by default no prompt for exit with nogui. - +#endif if( !ParseOverrides(parser) ) return false; // --- Parse Startup/Autoboot options --- @@ -425,6 +442,7 @@ class GameDatabaseLoaderThread : public pxThread bool Pcsx2App::OnInit() { +#ifndef __LIBRETRO__ EnableAllLogging(); Console.WriteLn("Interface is initializing. Entering Pcsx2App::OnInit!"); @@ -547,6 +565,7 @@ bool Pcsx2App::OnInit() CleanupOnExit(); return false; } +#endif return true; } @@ -646,7 +665,9 @@ void Pcsx2App::CleanupOnExit() void Pcsx2App::CleanupResources() { +#if wxUSE_GUI ScopedBusyCursor cursor( Cursor_ReallyBusy ); +#endif //delete wxConfigBase::Set( NULL ); while( wxGetLocale() != NULL ) @@ -662,7 +683,7 @@ int Pcsx2App::OnExit() CleanupOnExit(); return wxApp::OnExit(); } - +#ifndef __LIBRETRO__ void Pcsx2App::OnDestroyWindow( wxWindowDestroyEvent& evt ) { // Precautions: @@ -680,7 +701,7 @@ void Pcsx2App::OnDestroyWindow( wxWindowDestroyEvent& evt ) OnGsFrameClosed( evt.GetId() ); evt.Skip(); } - +#endif // -------------------------------------------------------------------------------------- // SysEventHandler // -------------------------------------------------------------------------------------- @@ -694,7 +715,9 @@ class SysEvtHandler : public pxEvtQueue // the menus and make sure they're all consistent to the current emulation states. void _DoIdle() { +#ifndef __LIBRETRO__ UI_UpdateSysControls(); +#endif } }; @@ -758,8 +781,9 @@ void Pcsx2App::CleanUp() { CleanupResources(); m_Resources = NULL; +#if wxUSE_GUI m_RecentIsoList = NULL; - +#endif DisableDiskLogging(); if( emuLog != NULL ) diff --git a/pcsx2/gui/AppMain.cpp b/pcsx2/gui/AppMain.cpp index 9110a3bd0f537..4965ab5443634 100644 --- a/pcsx2/gui/AppMain.cpp +++ b/pcsx2/gui/AppMain.cpp @@ -20,16 +20,19 @@ #include "GS.h" #include "AppSaveStates.h" #include "AppGameDatabase.h" -#include "AppAccelerators.h" #include "Plugins.h" #include "ps2/BiosTools.h" - +#if wxUSE_GUI +#include "AppAccelerators.h" #include "Dialogs/ModalPopups.h" #include "Dialogs/ConfigurationDialog.h" #include "Dialogs/LogOptionsDialog.h" #include "Debugger/DisassemblyDialog.h" +#endif +#include "DebugTools/Breakpoints.h" +#include "DebugTools/SymbolMap.h" #ifndef DISABLE_RECORDING # include "Recording/InputRecordingControls.h" @@ -63,8 +66,15 @@ #undef ECX #include // needed to implement the app! #endif - +#ifdef __LIBRETRO__ +Pcsx2App& wxGetApp() { + static Pcsx2App pcsx2; + return pcsx2; +} +#else wxIMPLEMENT_APP(Pcsx2App); +#endif + std::unique_ptr g_Conf; @@ -73,6 +83,7 @@ bool switchAR; static bool HandlePluginError( BaseException& ex ) { +#if wxUSE_GUI if (!pxDialogExists(L"Dialog:" + Dialogs::ComponentsConfigDialog::GetNameStatic())) { if( !Msgbox::OkCancel( ex.FormatDisplayMessage() + @@ -90,6 +101,9 @@ static bool HandlePluginError( BaseException& ex ) // TODO: Send a message to the panel to select the failed plugin. return AppOpenModalDialog(L"Plugins") != wxID_CANCEL; +#else + return false; +#endif } class PluginErrorEvent : public pxExceptionEvent @@ -133,7 +147,9 @@ void PluginErrorEvent::InvokeEvent() if( !HandlePluginError( *deleteMe ) ) { Console.Error( L"User-canceled plugin configuration; Plugins not loaded!" ); +#if wxUSE_GUI Msgbox::Alert( _("Warning! System plugins have not been loaded. PCSX2 may be inoperable.") ); +#endif } } @@ -147,7 +163,9 @@ void PluginInitErrorEvent::InvokeEvent() if( !HandlePluginError( *deleteMe ) ) { Console.Error( L"User-canceled plugin configuration after plugin initialization failure. Plugins unloaded." ); +#if wxUSE_GUI Msgbox::Alert( _("Warning! System plugins have not been loaded. PCSX2 may be inoperable.") ); +#endif } } @@ -178,6 +196,7 @@ class BIOSLoadErrorEvent : public pxExceptionEvent static bool HandleBIOSError(BaseException& ex) { +#if wxUSE_GUI if (!pxDialogExists(L"Dialog:" + Dialogs::ComponentsConfigDialog::GetNameStatic())) { if (!Msgbox::OkCancel(ex.FormatDisplayMessage() + L"\n\n" + BIOS_GetMsg_Required() @@ -192,6 +211,9 @@ static bool HandleBIOSError(BaseException& ex) g_Conf->ComponentsTabName = L"BIOS"; return AppOpenModalDialog(L"BIOS") != wxID_CANCEL; +#else + return false; +#endif } void BIOSLoadErrorEvent::InvokeEvent() @@ -204,10 +226,12 @@ void BIOSLoadErrorEvent::InvokeEvent() if (!HandleBIOSError(*deleteMe)) { Console.Warning("User canceled BIOS configuration."); +#if wxUSE_GUI Msgbox::Alert(_("Warning! Valid BIOS has not been selected. PCSX2 may be inoperable.")); +#endif } } - +#if wxUSE_GUI // Allows for activating menu actions from anywhere in PCSX2. // And it's Thread Safe! void Pcsx2App::PostMenuAction( MenuIdentifiers menu_id ) const @@ -221,7 +245,7 @@ void Pcsx2App::PostMenuAction( MenuIdentifiers menu_id ) const else mainFrame->GetEventHandler()->AddPendingEvent( joe ); } - +#endif // -------------------------------------------------------------------------------------- // Pcsx2AppMethodEvent // -------------------------------------------------------------------------------------- @@ -274,6 +298,7 @@ class Pcsx2AppMethodEvent : public pxActionEvent wxIMPLEMENT_DYNAMIC_CLASS( Pcsx2AppMethodEvent, pxActionEvent ); +#if wxUSE_GUI #ifdef __WXMSW__ extern int TranslateVKToWXK( u32 keysym ); #elif defined( __WXGTK__ ) @@ -329,7 +354,7 @@ void Pcsx2App::PadKeyDispatch( const keyEvent& ev ) } } } - +#endif // -------------------------------------------------------------------------------------- // Pcsx2AppTraits (implementations) [includes pxMessageOutputMessageBox] // -------------------------------------------------------------------------------------- @@ -343,7 +368,7 @@ void Pcsx2App::PadKeyDispatch( const keyEvent& ev ) // command line help message in cmd/powershell/mingw bash. It can be done in English // locales ( using AttachConsole, WriteConsole, FreeConsole combined with // wxMessageOutputStderr), but completely fails for some other languages (i.e. Japanese). -#ifdef _WIN32 +#if wxUSE_GUI && defined(_WIN32) class pxMessageOutputMessageBox : public wxMessageOutput { public: @@ -406,7 +431,7 @@ void pxMessageOutputMessageBox::Output(const wxString& out) wxMessageOutput* Pcsx2AppTraits::CreateMessageOutput() { -#ifdef __UNIX__ +#if defined(__UNIX__) || defined(__LIBRETRO__) return _parent::CreateMessageOutput(); #else return new pxMessageOutputMessageBox; @@ -416,7 +441,7 @@ wxMessageOutput* Pcsx2AppTraits::CreateMessageOutput() // -------------------------------------------------------------------------------------- // Pcsx2StandardPaths // -------------------------------------------------------------------------------------- -#ifdef wxUSE_STDPATHS +#if defined(wxUSE_STDPATHS) && !defined(__LIBRETRO__) class Pcsx2StandardPaths : public wxStandardPaths { public: @@ -530,11 +555,12 @@ void DoFmvSwitch(bool on) } else { switchAR = false; } +#if wxUSE_GUI if (GSFrame* gsFrame = wxGetApp().GetGsFramePtr()) if (GSPanel* viewport = gsFrame->GetViewport()) viewport->DoResize(); +#endif } - if (EmuConfig.Gamefixes.FMVinSoftwareHack) { ScopedCoreThreadPause paused_core(new SysExecEvent_SaveSinglePlugin(PluginId_GS)); renderswitch = !renderswitch; @@ -571,6 +597,7 @@ void Pcsx2App::LogicalVsync() renderswitch_delay >>= 1; +#ifndef __LIBRETRO__ // Only call PADupdate here if we're using GSopen2. Legacy GSopen plugins have the // GS window belonging to the MTGS thread. if( (PADupdate != NULL) && (GSopen2 != NULL) && (wxGetApp().GetGsFramePtr() != NULL) ) @@ -586,8 +613,9 @@ void Pcsx2App::LogicalVsync() if( !GetCorePlugins().KeyEvent( *ev ) ) PadKeyDispatch( *ev ); } +#endif } - +#ifndef __LIBRETRO__ void Pcsx2App::OnEmuKeyDown( wxKeyEvent& evt ) { const GlobalCommandDescriptor* cmd = NULL; @@ -607,7 +635,7 @@ void Pcsx2App::OnEmuKeyDown( wxKeyEvent& evt ) DbgCon.WriteLn( "(app) Invoking command: %s", cmd->Id ); cmd->Invoke(); } - +#endif void Pcsx2App::HandleEvent(wxEvtHandler* handler, wxEventFunction func, wxEvent& event) const { const_cast(this)->HandleEvent( handler, func, event ); @@ -649,13 +677,16 @@ void Pcsx2App::HandleEvent(wxEvtHandler* handler, wxEventFunction func, wxEvent& { // Commandline 'nogui' users will not receive an error message, but at least PCSX2 will // terminate properly. +#ifndef __LIBRETRO__ GSFrame* gsframe = wxGetApp().GetGsFramePtr(); gsframe->Close(); +#endif Console.Error(ex.FormatDiagnosticMessage()); - +#ifndef __LIBRETRO__ if (wxGetApp().HasGUI()) AddIdleEvent(BIOSLoadErrorEvent(ex)); +#endif } // ---------------------------------------------------------------------------- catch( Exception::SaveStateLoadError& ex) @@ -676,20 +707,26 @@ void Pcsx2App::HandleEvent(wxEvtHandler* handler, wxEventFunction func, wxEvent& // PCSX2. This probably happened in the BIOS error case above as well. // So the idea is to explicitly close the gsFrame before the modal MessageBox appears and // intercepts the close message. Only for wx3.0 though - it sometimes breaks linux wx2.8. - +#ifndef __LIBRETRO__ if (GSFrame* gsframe = wxGetApp().GetGsFramePtr()) gsframe->Close(); - +#endif Console.Error(ex.FormatDiagnosticMessage()); - +#ifndef __LIBRETRO__ // Make sure it terminates properly for nogui users. if (wxGetApp().HasGUI()) AddIdleEvent(PluginInitErrorEvent(ex)); +#endif } // ---------------------------------------------------------------------------- catch( Exception::PluginInitError& ex ) { +#ifdef __LIBRETRO__ + CoreThread.Cancel(); + CorePlugins.Shutdown(); +#else ShutdownPlugins(); +#endif Console.Error( ex.FormatDiagnosticMessage() ); AddIdleEvent( PluginInitErrorEvent(ex) ); @@ -697,7 +734,12 @@ void Pcsx2App::HandleEvent(wxEvtHandler* handler, wxEventFunction func, wxEvent& // ---------------------------------------------------------------------------- catch( Exception::PluginError& ex ) { +#ifdef __LIBRETRO__ + CoreThread.Cancel(); + CorePlugins.Unload(); +#else UnloadPlugins(); +#endif Console.Error( ex.FormatDiagnosticMessage() ); AddIdleEvent( PluginErrorEvent(ex) ); @@ -749,13 +791,17 @@ void Pcsx2App::HandleEvent(wxEvtHandler* handler, wxEventFunction func, wxEvent& // Test case (Windows only, Linux has an uncaught exception for some // reason): Run PSX ISO using fast boot +#ifndef __LIBRETRO__ if (GSFrame* gsframe = wxGetApp().GetGsFramePtr()) gsframe->Close(); +#endif Console.Error( ex.FormatDiagnosticMessage() ); +#ifndef __LIBRETRO__ // I should probably figure out how to have the error message as well. if (wxGetApp().HasGUI()) Msgbox::Alert( ex.FormatDisplayMessage() ); +#endif } } @@ -791,6 +837,7 @@ void Pcsx2App::ClearPendingSave() } } +#ifndef __LIBRETRO__ // This method generates debug assertions if the MainFrame handle is NULL (typically // indicating that PCSX2 is running in NoGUI mode, or that the main frame has been // closed). In most cases you'll want to use HasMainFrame() to test for thread @@ -832,7 +879,7 @@ void Pcsx2App::resetDebugger() if (dlg) dlg->reset(); } - +#endif // NOTE: Plugins are *not* applied by this function. Changes to plugins need to handled // manually. The PluginSelectorPanel does this, for example. void AppApplySettings( const AppConfig* oldconf ) @@ -853,7 +900,7 @@ void AppApplySettings( const AppConfig* oldconf ) g_Conf->Folders.CheatsWS.Mkdir(); g_Conf->EmuOptions.BiosFilename = g_Conf->FullpathToBios(); - +#ifndef __LIBRETRO__ RelocateLogfile(); if( (oldconf == NULL) || (oldconf->LanguageCode.CmpNoCase(g_Conf->LanguageCode)) ) @@ -861,6 +908,7 @@ void AppApplySettings( const AppConfig* oldconf ) wxDoNotLogInThisScope please; i18n_SetLanguage( g_Conf->LanguageId, g_Conf->LanguageCode ); } +#endif CorePlugins.SetSettingsFolder( GetSettingsFolder().ToString() ); @@ -938,6 +986,7 @@ SysMainMemory& Pcsx2App::GetVmReserve() void Pcsx2App::OpenGsPanel() { +#if wxUSE_GUI if( AppRpc_TryInvoke( &Pcsx2App::OpenGsPanel ) ) return; GSFrame* gsFrame = GetGsFramePtr(); @@ -1026,10 +1075,12 @@ void Pcsx2App::OpenGsPanel() sMainFrame.enableRecordingMenuItem(MenuId_Recording_TogglePause, true); sMainFrame.enableRecordingMenuItem(MenuId_Recording_ToggleRecordingMode, g_InputRecording.IsActive()); #endif +#endif } void Pcsx2App::CloseGsPanel() { +#if wxUSE_GUI if( AppRpc_TryInvoke( &Pcsx2App::CloseGsPanel ) ) return; if (CloseViewportWithPlugins) @@ -1044,8 +1095,10 @@ void Pcsx2App::CloseGsPanel() sMainFrame.enableRecordingMenuItem(MenuId_Recording_TogglePause, false); sMainFrame.enableRecordingMenuItem(MenuId_Recording_ToggleRecordingMode, false); #endif +#endif } +#ifndef __LIBRETRO__ void Pcsx2App::OnGsFrameClosed( wxWindowID id ) { if( (m_id_GsFrame == wxID_ANY) || (m_id_GsFrame != id) ) return; @@ -1083,7 +1136,7 @@ void Pcsx2App::OnMainFrameClosed( wxWindowID id ) if( m_id_MainFrame != id ) return; m_id_MainFrame = wxID_ANY; } - +#endif // -------------------------------------------------------------------------------------- // SysExecEvent_Execute // -------------------------------------------------------------------------------------- @@ -1179,7 +1232,7 @@ __fi bool SysHasValidState() { return CoreThread.HasActiveMachine(); } - +#ifndef __LIBRETRO__ // Writes text to console and updates the window status bar and/or HUD or whateverness. // FIXME: This probably isn't thread safe. >_< void SysStatus( const wxString& text ) @@ -1230,6 +1283,7 @@ MainEmuFrame* GetMainFramePtr() { return wxTheApp ? wxGetApp().GetMainFramePtr() : NULL; } +#endif SysMainMemory& GetVmMemory() { diff --git a/pcsx2/gui/AppRes.cpp b/pcsx2/gui/AppRes.cpp index 835ec61c2279b..817f3cef10fdc 100644 --- a/pcsx2/gui/AppRes.cpp +++ b/pcsx2/gui/AppRes.cpp @@ -14,7 +14,10 @@ */ #include "PrecompiledHeader.h" +#include "App.h" +#if wxUSE_GUI #include "MainFrame.h" +#endif #include "AppGameDatabase.h" #include @@ -23,7 +26,7 @@ #include #include "MSWstuff.h" - +#if wxUSE_GUI #include "Utilities/EmbeddedImage.h" #include "Resources/BackgroundLogo.h" #include "Resources/ButtonIcon_Camera.h" @@ -39,7 +42,8 @@ #include "Resources/AppIcon16.h" #include "Resources/AppIcon32.h" #include "Resources/AppIcon64.h" - +#endif +#ifndef __LIBRETRO__ RecentIsoList::RecentIsoList(int firstIdForMenuItems_or_wxID_ANY) { Menu = std::unique_ptr(new wxMenu()); @@ -49,13 +53,14 @@ RecentIsoList::RecentIsoList(int firstIdForMenuItems_or_wxID_ANY) Menu->Check( MenuId_Ask_On_Booting, g_Conf->AskOnBoot ); Manager = std::unique_ptr(new RecentIsoManager( Menu.get(), firstIdForMenuItems_or_wxID_ANY )); } +#endif pxAppResources::pxAppResources() { } pxAppResources::~pxAppResources() = default; - +#ifndef __LIBRETRO__ wxMenu& Pcsx2App::GetRecentIsoMenu() { if (!m_RecentIsoList) m_RecentIsoList = std::unique_ptr(new RecentIsoList( MenuId_RecentIsos_reservedStart )); @@ -77,7 +82,7 @@ wxMenu& Pcsx2App::GetDriveListMenu() return *m_DriveList->Menu; } - +#endif pxAppResources& Pcsx2App::GetResourceCache() { ScopedLock lock( m_mtx_Resources ); @@ -86,7 +91,7 @@ pxAppResources& Pcsx2App::GetResourceCache() return *m_Resources; } - +#ifndef __LIBRETRO__ const wxIconBundle& Pcsx2App::GetIconBundle() { std::unique_ptr& bundle( GetResourceCache().IconBundle ); @@ -177,3 +182,4 @@ const AppImageIds& Pcsx2App::GetImgId() const { return m_Resources->ImageId; } +#endif diff --git a/pcsx2/gui/AppUserMode.cpp b/pcsx2/gui/AppUserMode.cpp index 614bc17bc6b5f..99b9d76625c34 100644 --- a/pcsx2/gui/AppUserMode.cpp +++ b/pcsx2/gui/AppUserMode.cpp @@ -14,9 +14,14 @@ */ #include "PrecompiledHeader.h" +#include "App.h" +#if wxUSE_GUI #include "MainFrame.h" +#endif #include "Utilities/IniInterface.h" +#ifndef __LIBRETRO__ #include "Dialogs/ModalPopups.h" +#endif #include @@ -133,7 +138,7 @@ wxConfigBase* Pcsx2App::TestForPortableInstall() { wxString accessFailedStr, createFailedStr; if (TestUserPermissionsRights( portableDocsFolder, createFailedStr, accessFailedStr )) break; - +#ifndef __LIBRETRO__ wxDialogWithHelpers dialog( NULL, AddAppName(_("Portable mode error - %s")) ); wxTextCtrl* scrollText = new wxTextCtrl( @@ -175,7 +180,9 @@ wxConfigBase* Pcsx2App::TestForPortableInstall() return NULL; } - +#else + return NULL; +#endif } // Success -- all user-based folders have write access. PCSX2 should be able to run error-free! @@ -210,6 +217,7 @@ void Pcsx2App::WipeUserModeSettings() static void DoFirstTimeWizard() { +#ifndef __LIBRETRO__ // first time startup, so give the user the choice of user mode: while(true) { @@ -223,6 +231,7 @@ static void DoFirstTimeWizard() Console.WriteLn( Color_StrongBlack, "Restarting First Time Wizard!" ); } +#endif } wxConfigBase* Pcsx2App::OpenInstallSettingsFile() diff --git a/pcsx2/gui/ApplyState.h b/pcsx2/gui/ApplyState.h index 2b8e821ba8b1f..cd292893899a4 100644 --- a/pcsx2/gui/ApplyState.h +++ b/pcsx2/gui/ApplyState.h @@ -12,7 +12,7 @@ * You should have received a copy of the GNU General Public License along with PCSX2. * If not, see . */ - +#ifndef __LIBRETRO__ #pragma once #include @@ -241,3 +241,4 @@ class ApplicableWizardPage : public wxWizardPageSimple, public IApplyState virtual bool PrepForApply(); }; +#endif diff --git a/pcsx2/gui/ConsoleLogger.cpp b/pcsx2/gui/ConsoleLogger.cpp index 6469564a0232a..cd47ed89231f1 100644 --- a/pcsx2/gui/ConsoleLogger.cpp +++ b/pcsx2/gui/ConsoleLogger.cpp @@ -15,7 +15,9 @@ #include "PrecompiledHeader.h" #include "App.h" +#if wxUSE_GUI #include "MainFrame.h" +#endif #include "ConsoleLogger.h" #include "MSWstuff.h" @@ -79,7 +81,7 @@ void pxLogConsole::DoLogRecord(wxLogLevel level, const wxString &message, const } } - +#ifndef __LIBRETRO__ // ---------------------------------------------------------------------------- void ConsoleTestThread::ExecuteTaskInThread() { @@ -298,7 +300,7 @@ enum MenuId_LogSources_Offset MenuId_LogSources_Offset_recordingConsole = 10, MenuId_LogSources_Offset_controlInfo }; - +#endif // WARNING ConsoleLogSources & ConLogDefaults must have the same size static ConsoleLogSource* const ConLogSources[] = { @@ -364,7 +366,7 @@ void ConLog_LoadSaveSettings( IniInterface& ini ) ConLogInitialized = true; } - +#if wxUSE_GUI // -------------------------------------------------------------------------------------- // ConsoleLogFrame (implementations) // -------------------------------------------------------------------------------------- @@ -1063,7 +1065,12 @@ void Pcsx2App::ProgramLog_PostEvent( wxEvent& evt ) if( ConsoleLogFrame* proglog = GetProgramLog() ) proglog->GetEventHandler()->AddPendingEvent( evt ); } - +#else +const ConsoleLogFrame* Pcsx2App::GetProgramLog() const +{ + return NULL; +} +#endif // -------------------------------------------------------------------------------------- // ConsoleImpl_ToFile // -------------------------------------------------------------------------------------- @@ -1122,6 +1129,7 @@ const IConsoleWriter ConsoleWriter_File = 0 }; +#if wxUSE_GUI Mutex& Pcsx2App::GetProgramLogLock() { return m_mtx_ProgramLog; @@ -1207,9 +1215,15 @@ static const IConsoleWriter ConsoleWriter_WindowAndFile = 0 }; +#else +static const IConsoleWriter& ConsoleWriter_Window = ConsoleWriter_Stdout; +#endif void Pcsx2App::EnableAllLogging() { +#ifdef __LIBRETRO__ + return; +#else AffinityAssert_AllowFrom_MainUI(); const bool logBoxOpen = (m_ptr_ProgramLog != NULL); @@ -1232,7 +1246,8 @@ void Pcsx2App::EnableAllLogging() else newHandler = &ConsoleWriter_Stdout; } - Console_SetActiveHandler( *newHandler ); + Console_SetActiveHandler( *newHandler ); +#endif } // Used to disable the emuLog disk logger, typically used when disabling or re-initializing the @@ -1265,16 +1280,18 @@ void Pcsx2App::DisableWindowLogging() const void OSDlog(ConsoleColors color, bool console, const std::string& str) { +#if wxUSE_GUI if (GSosdLog) GSosdLog(str.c_str(), wxGetApp().GetProgramLog()->GetRGBA(color)); - +#endif if (console) Console.WriteLn(color, str.c_str()); } - +#if wxUSE_GUI void OSDmonitor(ConsoleColors color, const std::string key, const std::string value) { if(!GSosdMonitor) return; GSosdMonitor(wxString(key).utf8_str(), wxString(value).utf8_str(), wxGetApp().GetProgramLog()->GetRGBA(color)); } +#endif diff --git a/pcsx2/gui/ConsoleLogger.h b/pcsx2/gui/ConsoleLogger.h index 6cec648b26f4e..925ddf304a2fe 100644 --- a/pcsx2/gui/ConsoleLogger.h +++ b/pcsx2/gui/ConsoleLogger.h @@ -59,7 +59,7 @@ class pxLogConsole : public wxLog virtual void DoLogRecord(wxLogLevel level, const wxString &message, const wxLogRecordInfo &info); }; - +#ifndef __LIBRETRO__ // -------------------------------------------------------------------------------------- // ConsoleThreadTest -- useful class for unit testing the thread safety and general performance // of the console logger. @@ -230,12 +230,16 @@ class ConsoleLogFrame : public wxFrame void OnLoggingChanged(); }; - +#endif void OSDlog(ConsoleColors color, bool console, const std::string& str); template void OSDlog(ConsoleColors color, bool console, const std::string& format, Args ... args) { +#ifdef BUILTIN_GS_PLUGIN + if (!console) return; +#else if (!GSosdLog && !console) return; +#endif size_t size = snprintf( nullptr, 0, format.c_str(), args ... ) + 1; // Extra space for '\0' std::vector buf(size); diff --git a/pcsx2/gui/Debugger/DisassemblyDialog.h b/pcsx2/gui/Debugger/DisassemblyDialog.h index f0f6270e4b6a2..b2c4839731df7 100644 --- a/pcsx2/gui/Debugger/DisassemblyDialog.h +++ b/pcsx2/gui/Debugger/DisassemblyDialog.h @@ -12,7 +12,7 @@ * You should have received a copy of the GNU General Public License along with PCSX2. * If not, see . */ - +#if wxUSE_GUI #pragma once #include #include @@ -117,3 +117,4 @@ class DisassemblyDialog : public wxFrame wxBoxSizer* topSizer; wxButton *breakRunButton, *stepIntoButton, *stepOverButton, *stepOutButton, *breakpointButton, *helpButton; }; +#endif diff --git a/pcsx2/gui/Dialogs/LogOptionsDialog.h b/pcsx2/gui/Dialogs/LogOptionsDialog.h index 29d20eb2ced6a..555f07bd148f8 100644 --- a/pcsx2/gui/Dialogs/LogOptionsDialog.h +++ b/pcsx2/gui/Dialogs/LogOptionsDialog.h @@ -15,6 +15,7 @@ #pragma once +#if wxUSE_GUI #include "App.h" #include "ConfigurationDialog.h" @@ -45,3 +46,4 @@ class LogOptionsDialog : public BaseConfigurationDialog }; } // end namespace Dialogs +#endif diff --git a/pcsx2/gui/Dialogs/ModalPopups.h b/pcsx2/gui/Dialogs/ModalPopups.h index 27814bd4912dd..f3de77e8581e9 100644 --- a/pcsx2/gui/Dialogs/ModalPopups.h +++ b/pcsx2/gui/Dialogs/ModalPopups.h @@ -12,7 +12,7 @@ * You should have received a copy of the GNU General Public License along with PCSX2. * If not, see . */ - +#if wxUSE_GUI #pragma once #include "App.h" @@ -105,3 +105,4 @@ namespace Dialogs wxWindowID pxIssueConfirmation( wxDialogWithHelpers& confirmDlg, const MsgButtons& buttons ); wxWindowID pxIssueConfirmation( wxDialogWithHelpers& confirmDlg, const MsgButtons& buttons, const wxString& disablerKey ); +#endif diff --git a/pcsx2/gui/ExecutorThread.cpp b/pcsx2/gui/ExecutorThread.cpp index 4c46c092a26a7..3bd4948743f4e 100644 --- a/pcsx2/gui/ExecutorThread.cpp +++ b/pcsx2/gui/ExecutorThread.cpp @@ -16,9 +16,9 @@ #include "PrecompiledHeader.h" #include "App.h" #include - +#if wxUSE_GUI using namespace pxSizerFlags; - +#endif // -------------------------------------------------------------------------------------- // ConsoleLogSource_Event (implementations) // -------------------------------------------------------------------------------------- @@ -480,7 +480,10 @@ void ExecutorThread::ExecuteTaskInThread() while( true ) { if( !pxAssertDev( m_EvtHandler, "Event handler has been deallocated during SysExecutor thread execution." ) ) return; - +#ifdef __LIBRETRO__ + while(wxGetApp().HasPendingEvents()) + wxGetApp().ProcessPendingEvents(); +#endif m_EvtHandler->Idle(); m_EvtHandler->ProcessPendingEvents(); if( m_EvtHandler->IsShuttingDown() ) break; diff --git a/pcsx2/gui/GSFrame.h b/pcsx2/gui/GSFrame.h index 8569908b4da33..c15e2c363148a 100644 --- a/pcsx2/gui/GSFrame.h +++ b/pcsx2/gui/GSFrame.h @@ -30,6 +30,7 @@ enum LimiterModeType extern LimiterModeType g_LimiterMode; +#if wxUSE_GUI // -------------------------------------------------------------------------------------- // GSPanel // -------------------------------------------------------------------------------------- @@ -133,3 +134,4 @@ class GSFrame : public wxFrame // #define sGSFrame \ if( GSFrame* __gsframe_ = wxGetApp().GetGsFramePtr() ) (*__gsframe_) +#endif diff --git a/pcsx2/gui/GlobalCommands.cpp b/pcsx2/gui/GlobalCommands.cpp index ce98facc1e130..d8985c9690200 100644 --- a/pcsx2/gui/GlobalCommands.cpp +++ b/pcsx2/gui/GlobalCommands.cpp @@ -384,7 +384,7 @@ namespace Implementations void Sys_TakeSnapshot() { - GSmakeSnapshot(g_Conf->Folders.Snapshots.ToUTF8()); + GSmakeSnapshot(g_Conf->Folders.Snapshots.ToUTF8().data()); } void Sys_RenderToggle() @@ -464,7 +464,7 @@ namespace Implementations { // GSsetupRecording can be aborted/canceled by the user. Don't go on to record the audio if that happens. std::wstring* filename = nullptr; - if (filename = GSsetupRecording(g_Pcsx2Recording)) + if (filename = (std::wstring*) GSsetupRecording(g_Pcsx2Recording)) { SPU2setupRecording(g_Pcsx2Recording, filename); delete filename; diff --git a/pcsx2/gui/MSWstuff.cpp b/pcsx2/gui/MSWstuff.cpp index cb80736c78df1..33f73abfa3b83 100644 --- a/pcsx2/gui/MSWstuff.cpp +++ b/pcsx2/gui/MSWstuff.cpp @@ -20,14 +20,14 @@ #ifdef __WXMSW__ # include // needed for OutputDebugString #endif - +#if wxUSE_GUI void MSW_SetWindowAfter( WXWidget hwnd, WXWidget hwndAfter ) { #ifdef __WXMSW__ SetWindowPos( (HWND)hwnd, (HWND)hwndAfter, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOMOVE ); #endif } - +#endif // Text scales automatically on Windows but that's about it. The dialog widths // and images need to be scaled manually. float MSW_GetDPIScale() diff --git a/pcsx2/gui/MSWstuff.h b/pcsx2/gui/MSWstuff.h index 4779c37650cea..25b406d9253fe 100644 --- a/pcsx2/gui/MSWstuff.h +++ b/pcsx2/gui/MSWstuff.h @@ -14,8 +14,9 @@ */ #pragma once - +#if wxUSE_GUI // FIXME: Missing some includes. extern void MSW_SetWindowAfter( WXWidget hwnd, WXWidget hwndAfter ); +#endif extern void MSW_OutputDebugString( const wxString& text ); extern float MSW_GetDPIScale(); diff --git a/pcsx2/gui/MainFrame.h b/pcsx2/gui/MainFrame.h index aeefaedb37b84..41377a1cd9bb2 100644 --- a/pcsx2/gui/MainFrame.h +++ b/pcsx2/gui/MainFrame.h @@ -12,7 +12,7 @@ * You should have received a copy of the GNU General Public License along with PCSX2. * If not, see . */ - +#if wxUSE_GUI #pragma once #include "App.h" @@ -275,3 +275,4 @@ class MainEmuFrame : public wxFrame, }; extern int GetPluginMenuId_Settings(PluginsEnum_t pid); +#endif diff --git a/pcsx2/gui/MainMenuClicks.cpp b/pcsx2/gui/MainMenuClicks.cpp index 133af104b3d98..5326b654b50de 100644 --- a/pcsx2/gui/MainMenuClicks.cpp +++ b/pcsx2/gui/MainMenuClicks.cpp @@ -867,7 +867,7 @@ void MainEmuFrame::VideoCaptureUpdate() { // GSsetupRecording can be aborted/canceled by the user. Don't go on to record the audio if that happens std::wstring* filename = nullptr; - if (filename = GSsetupRecording(m_capturingVideo)) + if (filename = (std::wstring*)GSsetupRecording(m_capturingVideo)) { SPU2setupRecording(m_capturingVideo, filename); delete filename; @@ -913,7 +913,7 @@ void MainEmuFrame::Menu_Capture_Screenshot_Screenshot_Click(wxCommandEvent& even { return; } - GSmakeSnapshot(g_Conf->Folders.Snapshots.ToAscii()); + GSmakeSnapshot(g_Conf->Folders.Snapshots.ToAscii().data()); } #ifndef DISABLE_RECORDING diff --git a/pcsx2/gui/MemoryCardFile.cpp b/pcsx2/gui/MemoryCardFile.cpp index 28167a6888d22..596edd982b006 100644 --- a/pcsx2/gui/MemoryCardFile.cpp +++ b/pcsx2/gui/MemoryCardFile.cpp @@ -192,10 +192,12 @@ void FileMemoryCard::Open() if( !Create( str, 8 ) ) { +#ifndef __LIBRETRO__ Msgbox::Alert( wxsFormat(_( "Could not create a memory card: \n\n%s\n\n" ), str.c_str()) + GetDisabledMessage( slot ) ); +#endif } } @@ -208,12 +210,14 @@ void FileMemoryCard::Open() if( !m_file[slot].Open( str.c_str(), L"r+b" ) ) { +#ifndef __LIBRETRO__ // Translation note: detailed description should mention that the memory card will be disabled // for the duration of this session. Msgbox::Alert( wxsFormat(_( "Access denied to memory card: \n\n%s\n\n" ), str.c_str()) + GetDisabledMessage( slot ) ); +#endif } else // Load checksum { diff --git a/pcsx2/windows/Optimus.cpp b/pcsx2/windows/Optimus.cpp index 4ead3a6d38d2d..8a35302eaca48 100644 --- a/pcsx2/windows/Optimus.cpp +++ b/pcsx2/windows/Optimus.cpp @@ -16,6 +16,7 @@ #include "PrecompiledHeader.h" #ifdef _WIN32 +#include //This ensures that the nVidia graphics card is used for PCSX2 on an Optimus-enabled system. //302 or higher driver required. diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 505cddc504246..2e95a50f75d9b 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -10,7 +10,7 @@ if(EXISTS "${CMAKE_SOURCE_DIR}/plugins/dev9null" AND dev9null) add_subdirectory(dev9null) endif() -if(EXISTS "${CMAKE_SOURCE_DIR}/plugins/dev9ghzdrk" AND dev9ghzdrk) +if(EXISTS "${CMAKE_SOURCE_DIR}/plugins/dev9ghzdrk" AND dev9ghzdrk AND NOT LIBRETRO) add_subdirectory(dev9ghzdrk) endif() @@ -22,7 +22,7 @@ if(EXISTS "${CMAKE_SOURCE_DIR}/plugins/GSnull" AND GSnull) add_subdirectory(GSnull) endif() -if(EXISTS "${CMAKE_SOURCE_DIR}/plugins/LilyPad" AND LilyPad) +if(EXISTS "${CMAKE_SOURCE_DIR}/plugins/LilyPad" AND LilyPad AND NOT LIBRETRO) add_subdirectory(LilyPad) endif() @@ -30,7 +30,7 @@ if(EXISTS "${CMAKE_SOURCE_DIR}/plugins/onepad" AND onepad) add_subdirectory(onepad) endif() -if(EXISTS "${CMAKE_SOURCE_DIR}/plugins/onepad_legacy" AND onepad_legacy) +if(EXISTS "${CMAKE_SOURCE_DIR}/plugins/onepad_legacy" AND onepad_legacy AND NOT LIBRETRO) add_subdirectory(onepad_legacy) endif() diff --git a/plugins/GSdx/CMakeLists.txt b/plugins/GSdx/CMakeLists.txt index 3f1a9bc862f45..d1cbd05e126b7 100644 --- a/plugins/GSdx/CMakeLists.txt +++ b/plugins/GSdx/CMakeLists.txt @@ -8,14 +8,14 @@ endif() # plugin name (no version number to ease future version bump and bisect) set(Output GSdx) - +if (NOT MSVC) set(CommonFlags -fno-operator-names # because Xbyak uses and()/xor()/or()/not() function -Wno-unknown-pragmas -Wno-parentheses -Wunused-variable # __dummy variable need to be investigated ) - +endif() # The next two need to be looked at, but spam really badly in gcc 8. # Largely class alignment in GSDevice.h and memcpy in GSVector*.h. if(GCC_VERSION VERSION_EQUAL "8.0" OR GCC_VERSION VERSION_GREATER "8.0") @@ -48,7 +48,6 @@ set(GSdxSources GS.cpp GSAlignedClass.cpp GSBlock.cpp - GSCapture.cpp GSClut.cpp GSCodeBuffer.cpp GSCrc.cpp @@ -57,18 +56,15 @@ set(GSdxSources GSLocalMemory.cpp GSLzma.cpp GSPerfMon.cpp - GSPng.cpp GSState.cpp GSTables.cpp GSUtil.cpp GSVector.cpp GSdx.cpp - GSdxResources.cpp stdafx.cpp Renderers/Common/GSDevice.cpp Renderers/Common/GSDirtyRect.cpp Renderers/Common/GSFunctionMap.cpp - Renderers/Common/GSOsdManager.cpp Renderers/Common/GSRenderer.cpp Renderers/Common/GSTexture.cpp Renderers/Common/GSVertexTrace.cpp @@ -108,6 +104,20 @@ set(GSdxSources Window/GSWnd.cpp ) +if(MSVC) + set(GSdxSources ${GSdxSources} GSdx.rc) +else() + set(GSdxSources ${GSdxSources} GSdxResources.cpp) +endif() + +if(NOT LIBRETRO) + set(GSdxSources ${GSdxSources} + GSCapture.cpp + GSPng.cpp + Renderers/Common/GSOsdManager.cpp + ) +endif() + set(GSdxHeaders config.h GSAlignedClass.h @@ -120,7 +130,6 @@ set(GSdxHeaders GSDrawingEnvironment.h GSDump.h GSdx.h - GSdxResources.h GS.h GSLocalMemory.h GSLzma.h @@ -181,6 +190,10 @@ set(GSdxHeaders xbyak/xbyak_util.h ) +if(NOT MSVC) + set(GSdxHeaders ${GSdxHeaders} GSdxResources.h) +endif() + if(Windows) LIST(APPEND GSdxSources Renderers/DX11/GSDevice11.cpp @@ -189,12 +202,10 @@ if(Windows) Renderers/DX11/GSTexture11.cpp Renderers/DX11/GSTextureCache11.cpp Renderers/DX11/GSTextureFX11.cpp - GSVertexList.cpp +# GSVertexList.cpp Renderers/SW/GSVertexSW.cpp Window/GSCaptureDlg.cpp - Window/GSSettingsDlg.cpp - Window/GSWndDX.cpp - Window/GSWndWGL.cpp + Window/GSSettingsDlg.cpp ) LIST(APPEND GSdxHeaders @@ -207,15 +218,31 @@ if(Windows) resource.h targetver.h ) -else() - LIST(APPEND GSdxSources - Window/GSLinuxDialog.cpp - Window/GSWndEGL.cpp - ) +endif() +if(LIBRETRO) + LIST(APPEND GSdxSources + Window/GSWndRetro.cpp + ) LIST(APPEND GSdxHeaders - Window/GSWndEGL.h - ) + Window/GSWndRetro.h + ) + include_directories(${CMAKE_SOURCE_DIR}/libretro) +else() + if(Windows) + LIST(APPEND GSdxSources + Window/GSWndDX.cpp + Window/GSWndWGL.cpp + ) + else() + LIST(APPEND GSdxSources + Window/GSLinuxDialog.cpp + Window/GSWndEGL.cpp + ) + LIST(APPEND GSdxHeaders + Window/GSWndEGL.h + ) + endif() endif() @@ -240,6 +267,9 @@ if(USE_VTUNE) set(GSdxFinalLibs ${GSdxFinalLibs} ${VTUNE_LIBRARIES}) endif() +if(MSVC) + set(GSdxFinalLibs ${GSdxFinalLibs} d3dcompiler d3d11 dxgi dxguid winmm strmiids opengl32 comsuppw comctl32) +else(MSVC) set(RESOURCE_FILES res/logo-ogl.bmp res/fxaa.fx @@ -252,8 +282,17 @@ set(RESOURCE_FILES res/glsl/tfx_vgs.glsl) add_custom_glib_res("GSdxResources" "gsdx-res.xml" "GSdx_res" ${RESOURCE_FILES}) +endif(MSVC) include_directories(${CMAKE_CURRENT_BINARY_DIR}) +if(MSVC) + include_directories(${CMAKE_SOURCE_DIR}/3rdparty ${CMAKE_SOURCE_DIR}/3rdparty/libpng ${CMAKE_SOURCE_DIR}/3rdparty/baseclasses ${CMAKE_SOURCE_DIR}/3rdparty/xz/xz/src/liblzma/api) + add_definitions(/wd4456 /wd4458 /wd4996 /wd4995 /wd4324 /wd4100 /wd4101 /wd4201 /wd4556 /wd4127 /wd4512) +endif() + +if(NOT GTKn_FOUND) + include_directories(${FREETYPE_INCLUDE_DIR_ft2build} ${FREETYPE_INCLUDE_DIR_freetype2} ${GLIB_INCLUDE_DIRS}) +endif() if(BUILTIN_GS) add_pcsx2_lib(${Output} "${GSdxFinalSources}" "${GSdxFinalLibs}" "${GSdxFinalFlags}") diff --git a/plugins/GSdx/GS.cpp b/plugins/GSdx/GS.cpp index 351e4e7360357..4a3a8451097c0 100644 --- a/plugins/GSdx/GS.cpp +++ b/plugins/GSdx/GS.cpp @@ -47,6 +47,17 @@ extern bool RunLinuxDialog(); #endif +#ifdef __LIBRETRO__ +#include "Window/GSWndRetro.h" +#include "options.h" +namespace Options { +GfxOption upscale_multiplier("pcsx2_upscale_multiplier", "Internal Resolution", + {{"Native PS2", 1}, {"2x Native ~720p", 2}, {"3x Native ~1080p", 3},{"4x Native ~1440p 2K", 4}, + {"5x Native ~1620p 3K", 5}, {"6x Native ~2160p 4K", 6}, {"8x Native ~2880p 5K", 8}}); +static GfxOption sw_renderer_threads("pcsx2_sw_renderer_threads", "Software Renderer Threads", 2, 10); +} +#endif + #define PS2E_LT_GS 0x01 #define PS2E_GS_VERSION 0x0006 #define PS2E_X86 0x01 // 32 bit @@ -106,6 +117,10 @@ EXPORT_C GSsetSettingsDir(const char* dir) theApp.SetConfigDir(dir); } +EXPORT_C_(void) GSsetLogDir(const char *dir) +{ +} + EXPORT_C_(int) GSinit() { if(!GSUtil::CheckSSE()) @@ -198,7 +213,9 @@ static int _GSopen(void** dsp, const char* title, GSRendererType renderer, int t renderer = GSUtil::GetBestRenderer(); #endif } - +#ifdef __LIBRETRO__ + threads = Options::sw_renderer_threads; +#endif if(threads == -1) { threads = theApp.GetConfigI("extrathreads"); @@ -223,6 +240,18 @@ static int _GSopen(void** dsp, const char* title, GSRendererType renderer, int t { // Select the window first to detect the GL requirement std::vector> wnds; +#ifdef __LIBRETRO__ + switch (renderer) + { + case GSRendererType::OGL_HW: + case GSRendererType::OGL_SW: + wnds.push_back(std::make_shared()); + break; + default: + wnds.push_back(std::make_shared()); + break; + } +#else switch (renderer) { case GSRendererType::OGL_HW: @@ -256,7 +285,7 @@ static int _GSopen(void** dsp, const char* title, GSRendererType renderer, int t #endif break; } - +#endif int w = theApp.GetConfigI("ModeWidth"); int h = theApp.GetConfigI("ModeHeight"); #if defined(__unix__) @@ -404,19 +433,42 @@ static int _GSopen(void** dsp, const char* title, GSRendererType renderer, int t EXPORT_C_(void) GSosdLog(const char *utf8, uint32 color) { +#ifndef __LIBRETRO__ if(s_gs && s_gs->m_dev) s_gs->m_dev->m_osd.Log(utf8); +#endif } EXPORT_C_(void) GSosdMonitor(const char *key, const char *value, uint32 color) { +#ifndef __LIBRETRO__ if(s_gs && s_gs->m_dev) s_gs->m_dev->m_osd.Monitor(key, value); +#endif } EXPORT_C_(int) GSopen2(void** dsp, uint32 flags) { static bool stored_toggle_state = false; const bool toggle_state = !!(flags & 4); +#ifdef __LIBRETRO__ + switch (hw_render.context_type) + { + case RETRO_HW_CONTEXT_DIRECT3D: + theApp.SetCurrentRendererType(GSRendererType::DX1011_HW); + break; + case RETRO_HW_CONTEXT_NONE: + theApp.SetCurrentRendererType(GSRendererType::Null); + break; + default: + if(Options::renderer == "Software") + theApp.SetCurrentRendererType(GSRendererType::OGL_SW); + else + theApp.SetCurrentRendererType(GSRendererType::OGL_HW); + break; + } +// theApp.SetCurrentRendererType(GSRendererType::OGL_SW); + theApp.SetConfig("upscale_multiplier", Options::upscale_multiplier); +#endif auto current_renderer = theApp.GetCurrentRendererType(); if (current_renderer != GSRendererType::Undefined && stored_toggle_state != toggle_state) @@ -499,6 +551,11 @@ EXPORT_C_(int) GSopen(void** dsp, const char* title, int mt) return retval; } +GSVector2i GSgetInternalResolution() +{ + return s_gs->GetInternalResolution(); +} + EXPORT_C GSreset() { try @@ -670,6 +727,14 @@ EXPORT_C GSvsync(int field) } } +EXPORT_C_(void) GSchangeSaveState(int, const char *filename) +{ +} + +EXPORT_C_(void) GSmakeSnapshot2(char *pathname, int *snapdone, int savejpg) +{ +} + EXPORT_C_(uint32) GSmakeSnapshot(char* path) { try @@ -735,6 +800,7 @@ EXPORT_C GSconfigure() theApp.Init(); +#ifndef __LIBRETRO__ #ifdef _WIN32 GSDialog::InitCommonControls(); if(GSSettingsDlg().DoModal() == IDOK) @@ -750,7 +816,7 @@ EXPORT_C GSconfigure() // Force a reload of the gs state theApp.SetCurrentRendererType(GSRendererType::Undefined); } - +#endif #endif } catch (GSDXRecoverableError) diff --git a/plugins/GSdx/GSdx.cpp b/plugins/GSdx/GSdx.cpp index dddb0b1d228b0..4ad01d7e6794e 100644 --- a/plugins/GSdx/GSdx.cpp +++ b/plugins/GSdx/GSdx.cpp @@ -24,10 +24,13 @@ #include "GS.h" #include -static void* s_hModule; - #ifdef _WIN32 +#ifdef BUILTIN_GS_PLUGIN +EXTERN_C IMAGE_DOS_HEADER __ImageBase; +static void* s_hModule = &__ImageBase; +#else +static void* s_hModule; BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { switch(ul_reason_for_call) @@ -42,6 +45,7 @@ BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserv return TRUE; } +#endif bool GSdxApp::LoadResource(int id, std::vector& buff, const char* type) { @@ -482,7 +486,11 @@ void GSdxApp::BuildConfigurationMap(const char* lpFileName) void* GSdxApp::GetModuleHandlePtr() { +#ifdef _WIN32 return s_hModule; +#else + return nullptr; +#endif } void GSdxApp::SetConfigDir(const char* dir) diff --git a/plugins/GSdx/Renderers/Common/GSDevice.h b/plugins/GSdx/Renderers/Common/GSDevice.h index 4c11911139765..b58785ea40695 100644 --- a/plugins/GSdx/Renderers/Common/GSDevice.h +++ b/plugins/GSdx/Renderers/Common/GSDevice.h @@ -26,8 +26,9 @@ #include "GSTexture.h" #include "GSVertex.h" #include "GSAlignedClass.h" +#ifndef __LIBRETRO__ #include "GSOsdManager.h" - +#endif enum ShaderConvert { ShaderConvert_COPY = 0, @@ -173,8 +174,9 @@ class GSDevice : public GSAlignedClass<32> virtual uint16 ConvertBlendEnum(uint16 generic) = 0; // Convert blend factors/ops from the generic enum to DX11/OGl specific. public: +#ifndef __LIBRETRO__ GSOsdManager m_osd; - +#endif GSDevice(); virtual ~GSDevice(); @@ -187,7 +189,11 @@ class GSDevice : public GSAlignedClass<32> virtual bool IsLost(bool update = false) {return false;} virtual void Present(const GSVector4i& r, int shader); virtual void Present(GSTexture* sTex, GSTexture* dTex, const GSVector4& dRect, int shader = 0); +#ifdef __LIBRETRO__ + virtual void Flip() { m_wnd->Flip(); } +#else virtual void Flip() {} +#endif virtual void SetVSync(int vsync) {m_vsync = vsync;} diff --git a/plugins/GSdx/Renderers/Common/GSRenderer.cpp b/plugins/GSdx/Renderers/Common/GSRenderer.cpp index d5ce6f4bc37e2..279583a2249fb 100644 --- a/plugins/GSdx/Renderers/Common/GSRenderer.cpp +++ b/plugins/GSdx/Renderers/Common/GSRenderer.cpp @@ -395,12 +395,12 @@ void GSRenderer::VSync(int field) s = format("%dx%d | %s", GetInternalResolution().x, GetInternalResolution().y, theApp.m_gs_interlace[m_interlace].name.c_str()); } - +#ifndef __LIBRETRO__ if(m_capture.IsCapturing()) { s += " | Recording..."; } - +#endif if(m_wnd->IsManaged()) { m_wnd->SetWindowText(s.c_str()); @@ -432,13 +432,13 @@ void GSRenderer::VSync(int field) } // present - +#ifndef __LIBRETRO__ // This will scale the OSD to the window's size. // Will maintiain the font size no matter what size the window is. GSVector4i window_size = m_wnd->GetClientRect(); m_dev->m_osd.m_real_size.x = window_size.v[2]; m_dev->m_osd.m_real_size.y = window_size.v[3]; - +#endif m_dev->Present(m_wnd->GetClientRect().fit(m_aspectratio), m_shader); // snapshot @@ -472,7 +472,7 @@ void GSRenderer::VSync(int field) if(m_dump->VSync(field, !m_control_key, m_regs)) m_dump.reset(); } - +#ifndef __LIBRETRO__ // capture if(m_capture.IsCapturing()) @@ -496,6 +496,7 @@ void GSRenderer::VSync(int field) } } } +#endif } bool GSRenderer::MakeSnapshot(const std::string& path) @@ -531,15 +532,21 @@ bool GSRenderer::MakeSnapshot(const std::string& path) std::wstring* GSRenderer::BeginCapture() { +#ifdef __LIBRETRO__ + return nullptr; +#else GSVector4i disp = m_wnd->GetClientRect().fit(m_aspectratio); float aspect = (float)disp.width() / std::max(1, disp.height()); return m_capture.BeginCapture(GetTvRefreshRate(), GetInternalResolution(), aspect); +#endif } void GSRenderer::EndCapture() { +#ifndef __LIBRETRO__ m_capture.EndCapture(); +#endif } void GSRenderer::KeyEvent(GSKeyEventData* e) diff --git a/plugins/GSdx/Renderers/Common/GSRenderer.h b/plugins/GSdx/Renderers/Common/GSRenderer.h index f64bd987aa987..492580eb8ff7c 100644 --- a/plugins/GSdx/Renderers/Common/GSRenderer.h +++ b/plugins/GSdx/Renderers/Common/GSRenderer.h @@ -28,7 +28,9 @@ class GSRenderer : public GSState { +#ifndef __LIBRETRO__ GSCapture m_capture; +#endif std::string m_snapshot; int m_shader; diff --git a/plugins/GSdx/Renderers/DX11/GSDevice11.cpp b/plugins/GSdx/Renderers/DX11/GSDevice11.cpp index d0e96158306f3..18c75049a2dff 100644 --- a/plugins/GSdx/Renderers/DX11/GSDevice11.cpp +++ b/plugins/GSdx/Renderers/DX11/GSDevice11.cpp @@ -103,6 +103,22 @@ bool GSDevice11::Create(const std::shared_ptr &wnd) D3D11_RASTERIZER_DESC rd; D3D11_BLEND_DESC bsd; +#ifdef __LIBRETRO__ + retro_hw_render_interface_d3d11 *d3d11 = nullptr; + if (!environ_cb(RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE, (void **)&d3d11) || !d3d11) { + printf("Failed to get HW rendering interface!\n"); + return false; + } + + if (d3d11->interface_version != RETRO_HW_RENDER_INTERFACE_D3D11_VERSION) { + printf("HW render interface mismatch, expected %u, got %u!\n", RETRO_HW_RENDER_INTERFACE_D3D11_VERSION, d3d11->interface_version); + return false; + } + + m_dev = d3d11->device; + m_ctx = d3d11->context; + D3D_FEATURE_LEVEL level = d3d11->featureLevel; +#else // create factory { const HRESULT result = CreateDXGIFactory2(0, IID_PPV_ARGS(&m_factory)); @@ -201,7 +217,7 @@ bool GSDevice11::Create(const std::shared_ptr &wnd) return false; } } - +#endif if(!SetFeatureLevel(level, true)) return false; @@ -434,13 +450,13 @@ bool GSDevice11::Create(const std::shared_ptr &wnd) memset(&blend, 0, sizeof(blend)); m_dev->CreateBlendState(&blend, &m_date.bs); - +#ifndef __LIBRETRO__ GSVector2i tex_font = m_osd.get_texture_font_size(); m_font = std::unique_ptr( CreateSurface(GSTexture::Texture, tex_font.x, tex_font.y, DXGI_FORMAT_R8_UNORM) ); - +#endif return true; } @@ -448,7 +464,34 @@ bool GSDevice11::Reset(int w, int h) { if(!__super::Reset(w, h)) return false; +#ifdef __LIBRETRO__ + D3D11_TEXTURE2D_DESC desc{}; + desc.Width = w; + desc.Height = h; + desc.MipLevels = 1; + desc.ArraySize = 1; + desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + desc.SampleDesc.Count = 1; + desc.SampleDesc.Quality = 0; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE; + desc.CPUAccessFlags = 0; + desc.MiscFlags = 0; + + D3D11_SUBRESOURCE_DATA srsc = {}; + srsc.pSysMem = malloc(w*h*4); + srsc.SysMemPitch = w * 4; + srsc.SysMemSlicePitch = w * h * 4; + memset((void*)srsc.pSysMem, 0xFF, w*h*3); + + + CComPtr texture; + if (FAILED(m_dev->CreateTexture2D(&desc, nullptr, &texture))) + return false; + free((void*)srsc.pSysMem); + m_backbuffer = new GSTexture11(texture); +#else if(m_swapchain) { DXGI_SWAP_CHAIN_DESC scd; @@ -467,6 +510,7 @@ bool GSDevice11::Reset(int w, int h) m_backbuffer = new GSTexture11(backbuffer); } +#endif return true; } @@ -475,11 +519,53 @@ void GSDevice11::SetVSync(int vsync) { m_vsync = vsync ? 1 : 0; } - +#ifdef __LIBRETRO__ +void GSDevice11::Flip() +{ +// if(!m_current) +// return; + + ID3D11RenderTargetView *nullView = nullptr; + m_ctx->OMSetRenderTargets(1, &nullView, nullptr); + + ID3D11ShaderResourceView* srv = *(GSTexture11*)m_backbuffer; + m_ctx->PSSetShaderResources(0, 1, &srv); + + extern retro_video_refresh_t video_cb; + video_cb(RETRO_HW_FRAME_BUFFER_VALID, m_backbuffer->GetWidth(), m_backbuffer->GetHeight(), 0); + + /* restore State */ + uint32 stride = m_state.vb_stride; + uint32 offset = 0; + m_ctx->IASetVertexBuffers(0, 1, &m_state.vb, &stride, &offset); + m_ctx->IASetIndexBuffer(m_state.ib, DXGI_FORMAT_R32_UINT, 0); + m_ctx->IASetInputLayout(m_state.layout); + m_ctx->IASetPrimitiveTopology(m_state.topology); + m_ctx->VSSetShader(m_state.vs, NULL, 0); + m_ctx->VSSetConstantBuffers(0, 1, &m_state.vs_cb); + m_ctx->GSSetShader(m_state.gs, NULL, 0); + m_ctx->GSSetConstantBuffers(0, 1, &m_state.gs_cb); + m_ctx->PSSetShader(m_state.ps, NULL, 0); + m_ctx->PSSetConstantBuffers(0, 1, &m_state.ps_cb); + m_ctx->PSSetShaderResources(0, m_state.ps_sr_views.size(), m_state.ps_sr_views.data()); + m_ctx->PSSetSamplers(0, countof(m_state.ps_ss), m_state.ps_ss); + m_ctx->OMSetDepthStencilState(m_state.dss, m_state.sref); + float BlendFactor[] = {m_state.bf, m_state.bf, m_state.bf, 0}; + m_ctx->OMSetBlendState(m_state.bs, BlendFactor, 0xffffffff); +#if 0 + m_ctx->OMSetRenderTargets(1, &m_state.rt_view, m_state.dsv); + D3D11_VIEWPORT vp = {m_hack_topleft_offset, m_hack_topleft_offset, + (float)m_state.viewport.x, (float)m_state.viewport.y, 0.0f, 1.0f}; + m_ctx->RSSetViewports(1, &vp); + m_ctx->RSSetScissorRects(1, m_state.scissor); +#endif +} +#else void GSDevice11::Flip() { m_swapchain->Present(m_vsync, 0); } +#endif void GSDevice11::BeforeDraw() { @@ -833,6 +919,7 @@ void GSDevice11::StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* void GSDevice11::RenderOsd(GSTexture* dt) { +#ifndef __LIBRETRO__ BeginScene(); // om @@ -870,6 +957,7 @@ void GSDevice11::RenderOsd(GSTexture* dt) DrawPrimitive(); EndScene(); +#endif } void GSDevice11::DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, const GSVector4& c) @@ -1532,4 +1620,4 @@ uint16 GSDevice11::ConvertBlendEnum(uint16 generic) case OP_REV_SUBTRACT : return D3D11_BLEND_OP_REV_SUBTRACT; default : ASSERT(0); return 0; } -} \ No newline at end of file +} diff --git a/plugins/GSdx/Renderers/DX11/GSDevice11.h b/plugins/GSdx/Renderers/DX11/GSDevice11.h index d8ea9a07b7ef0..be82feb2bbc50 100644 --- a/plugins/GSdx/Renderers/DX11/GSDevice11.h +++ b/plugins/GSdx/Renderers/DX11/GSDevice11.h @@ -25,6 +25,11 @@ #include "GSVector.h" #include "Renderers/Common/GSDevice.h" +#ifdef __LIBRETRO__ +#include "libretro_d3d.h" +extern retro_environment_t environ_cb; +#endif + struct GSVertexShader11 { CComPtr vs; @@ -387,7 +392,9 @@ class GSDevice11 final : public GSDevice CComPtr m_factory; CComPtr m_dev; CComPtr m_ctx; +#ifndef __LIBRETRO__ CComPtr m_swapchain; +#endif CComPtr m_vb; CComPtr m_vb_old; CComPtr m_ib; @@ -492,9 +499,9 @@ class GSDevice11 final : public GSDevice VSConstantBuffer m_vs_cb_cache; GSConstantBuffer m_gs_cb_cache; PSConstantBuffer m_ps_cb_cache; - +#ifndef __LIBRETRO__ std::unique_ptr m_font; - +#endif protected: struct {D3D_FEATURE_LEVEL level; std::string model, vs, gs, ps, cs;} m_shader; public: diff --git a/plugins/GSdx/Renderers/DX11/GSTexture11.cpp b/plugins/GSdx/Renderers/DX11/GSTexture11.cpp index 7010caab51c8a..c8971fb82321c 100644 --- a/plugins/GSdx/Renderers/DX11/GSTexture11.cpp +++ b/plugins/GSdx/Renderers/DX11/GSTexture11.cpp @@ -105,6 +105,9 @@ void GSTexture11::Unmap() bool GSTexture11::Save(const std::string& fn) { +#ifdef __LIBRETRO__ + return true; +#else CComPtr res; D3D11_TEXTURE2D_DESC desc; @@ -198,6 +201,7 @@ bool GSTexture11::Save(const std::string& fn) m_ctx->Unmap(res, 0); return success; +#endif } GSTexture11::operator ID3D11Texture2D*() diff --git a/plugins/GSdx/Renderers/HW/GSRendererHW.cpp b/plugins/GSdx/Renderers/HW/GSRendererHW.cpp index c867387e90b77..2b127d22065bb 100644 --- a/plugins/GSdx/Renderers/HW/GSRendererHW.cpp +++ b/plugins/GSdx/Renderers/HW/GSRendererHW.cpp @@ -21,6 +21,9 @@ #include "stdafx.h" #include "GSRendererHW.h" +#ifdef __LIBRETRO__ +#include "options.h" +#endif const float GSRendererHW::SSR_UV_TOLERANCE = 1e-3f; @@ -81,6 +84,9 @@ GSRendererHW::GSRendererHW(GSTextureCache* tc) void GSRendererHW::SetScaling() { +#ifdef __LIBRETRO__ + m_upscale_multiplier = Options::upscale_multiplier; +#endif if (!m_upscale_multiplier) { CustomResolutionScaling(); diff --git a/plugins/GSdx/Renderers/HW/GSTextureCache.cpp b/plugins/GSdx/Renderers/HW/GSTextureCache.cpp index 632aea6b8953d..3cb5bdd647f8b 100644 --- a/plugins/GSdx/Renderers/HW/GSTextureCache.cpp +++ b/plugins/GSdx/Renderers/HW/GSTextureCache.cpp @@ -465,7 +465,12 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const GIFRegTEX0& TEX0, con void GSTextureCache::ScaleTexture(GSTexture* texture) { if (!m_renderer->CanUpscale()) + { +#ifdef __LIBRETRO__ + texture->SetScale({1,1}); +#endif return; + } float multiplier = static_cast(m_renderer->GetUpscaleMultiplier()); bool custom_resolution = (multiplier == 0); diff --git a/plugins/GSdx/Renderers/OpenGL/GSDeviceOGL.cpp b/plugins/GSdx/Renderers/OpenGL/GSDeviceOGL.cpp index e172808418c08..b7e3dcb7a766b 100644 --- a/plugins/GSdx/Renderers/OpenGL/GSDeviceOGL.cpp +++ b/plugins/GSdx/Renderers/OpenGL/GSDeviceOGL.cpp @@ -331,13 +331,13 @@ bool GSDeviceOGL::Create(const std::shared_ptr &wnd) OMSetFBO(m_fbo); GLenum target[1] = {GL_COLOR_ATTACHMENT0}; glDrawBuffers(1, target); - OMSetFBO(0); + OMSetFBO(GL_DEFAULT_FRAMEBUFFER); glGenFramebuffers(1, &m_fbo_read); // Always read from the first buffer glBindFramebuffer(GL_READ_FRAMEBUFFER, m_fbo_read); glReadBuffer(GL_COLOR_ATTACHMENT0); - glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); + glBindFramebuffer(GL_READ_FRAMEBUFFER, GL_DEFAULT_FRAMEBUFFER); // Some timers to help profiling if (GLLoader::in_replayer) { @@ -551,7 +551,7 @@ bool GSDeviceOGL::Create(const std::shared_ptr &wnd) GLState::available_vram = (int64)(vram[0]) * 1024ul * 2ul; fprintf(stdout, "Available VRAM/RAM:%lldMB for textures\n", GLState::available_vram >> 20u); - +#ifndef __LIBRETRO__ // **************************************************************** // Texture Font (OSD) // **************************************************************** @@ -560,7 +560,7 @@ bool GSDeviceOGL::Create(const std::shared_ptr &wnd) m_font = std::unique_ptr( new GSTextureOGL(GSTextureOGL::Texture, tex_font.x, tex_font.y, GL_R8, m_fbo_read, false) ); - +#endif // **************************************************************** // Finish window setup and backbuffer // **************************************************************** @@ -708,7 +708,7 @@ void GSDeviceOGL::ClearRenderTarget(GSTexture* t, const GSVector4& c) OMSetColorMaskState(); if (T->IsBackbuffer()) { - OMSetFBO(0); + OMSetFBO(GL_DEFAULT_FRAMEBUFFER); // glDrawBuffer(GL_BACK); // this is the default when there is no FB // 0 will select the first drawbuffer ie GL_BACK @@ -1233,7 +1233,7 @@ void GSDeviceOGL::CopyRectConv(GSTexture* sTex, GSTexture* dTex, const GSVector4 else glCopyTextureSubImage2D(did, GL_TEX_LEVEL_0, r.x, r.y, r.x, r.y, r.width(), r.height()); - glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); + glBindFramebuffer(GL_READ_FRAMEBUFFER, GL_DEFAULT_FRAMEBUFFER); } // Copy a sub part of a texture into another @@ -1390,6 +1390,7 @@ void GSDeviceOGL::StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture void GSDeviceOGL::RenderOsd(GSTexture* dt) { +#ifndef __LIBRETRO__ BeginScene(); m_shader->BindPipeline(m_convert.ps[ShaderConvert_OSD]); @@ -1416,6 +1417,7 @@ void GSDeviceOGL::RenderOsd(GSTexture* dt) DrawPrimitive(); EndScene(); +#endif } void GSDeviceOGL::DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, const GSVector4& c) @@ -1793,7 +1795,7 @@ void GSDeviceOGL::OMSetRenderTargets(GSTexture* rt, GSTexture* ds, const GSVecto } else { // Render in the backbuffer - OMSetFBO(0); + OMSetFBO(GL_DEFAULT_FRAMEBUFFER); } @@ -2014,4 +2016,4 @@ uint16 GSDeviceOGL::ConvertBlendEnum(uint16 generic) case OP_REV_SUBTRACT : return GL_FUNC_REVERSE_SUBTRACT; default : ASSERT(0); return 0; } -} \ No newline at end of file +} diff --git a/plugins/GSdx/Renderers/OpenGL/GSDeviceOGL.h b/plugins/GSdx/Renderers/OpenGL/GSDeviceOGL.h index 7610410ef4deb..f6e691dd99786 100644 --- a/plugins/GSdx/Renderers/OpenGL/GSDeviceOGL.h +++ b/plugins/GSdx/Renderers/OpenGL/GSDeviceOGL.h @@ -502,9 +502,9 @@ class GSDeviceOGL final : public GSDevice VSConstantBuffer m_vs_cb_cache; PSConstantBuffer m_ps_cb_cache; MiscConstantBuffer m_misc_cb_cache; - +#ifndef __LIBRETRO__ std::unique_ptr m_font; - +#endif GSTexture* CreateSurface(int type, int w, int h, int format); GSTexture* FetchSurface(int type, int w, int h, int format); diff --git a/plugins/GSdx/Renderers/OpenGL/GSTextureOGL.cpp b/plugins/GSdx/Renderers/OpenGL/GSTextureOGL.cpp index 60f500a9513ed..f44a549dac1a3 100644 --- a/plugins/GSdx/Renderers/OpenGL/GSTextureOGL.cpp +++ b/plugins/GSdx/Renderers/OpenGL/GSTextureOGL.cpp @@ -460,7 +460,7 @@ bool GSTextureOGL::Map(GSMap& m, const GSVector4i* _r, int layer) glReadPixels(r.x, r.y, r.width(), r.height(), m_int_format, m_int_type, m_local_buffer); - glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); + glBindFramebuffer(GL_READ_FRAMEBUFFER, GL_DEFAULT_FRAMEBUFFER); #endif @@ -555,6 +555,9 @@ void GSTextureOGL::CommitPages(const GSVector2i& region, bool commit) bool GSTextureOGL::Save(const std::string& fn) { +#ifdef __LIBRETRO__ + return true; +#else // Collect the texture data uint32 pitch = 4 * m_committed_size.x; uint32 buf_size = pitch * m_committed_size.y * 2;// Note *2 for security (depth/stencil) @@ -573,7 +576,7 @@ bool GSTextureOGL::Save(const std::string& fn) glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, m_texture_id, 0); glReadPixels(0, 0, m_committed_size.x, m_committed_size.y, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, image.get()); - glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); + glBindFramebuffer(GL_READ_FRAMEBUFFER, GL_DEFAULT_FRAMEBUFFER); fmt = GSPng::RGB_A_PNG; } else if(m_format == GL_R32I) { @@ -601,11 +604,12 @@ bool GSTextureOGL::Save(const std::string& fn) glReadPixels(0, 0, m_committed_size.x, m_committed_size.y, GL_RED, GL_UNSIGNED_BYTE, image.get()); } - glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); + glBindFramebuffer(GL_READ_FRAMEBUFFER, GL_DEFAULT_FRAMEBUFFER); } int compression = theApp.GetConfigI("png_compression_level"); return GSPng::Save(fmt, fn, image.get(), m_committed_size.x, m_committed_size.y, pitch, compression); +#endif } uint32 GSTextureOGL::GetMemUsage() diff --git a/plugins/GSdx/Renderers/SW/GSTextureSW.cpp b/plugins/GSdx/Renderers/SW/GSTextureSW.cpp index b8c69f09cd91e..94c6310b2a5b5 100644 --- a/plugins/GSdx/Renderers/SW/GSTextureSW.cpp +++ b/plugins/GSdx/Renderers/SW/GSTextureSW.cpp @@ -87,6 +87,9 @@ void GSTextureSW::Unmap() bool GSTextureSW::Save(const std::string& fn) { +#ifdef __LIBRETRO__ + return true; +#else #ifdef ENABLE_OGL_DEBUG GSPng::Format fmt = GSPng::RGB_A_PNG; #else @@ -94,4 +97,5 @@ bool GSTextureSW::Save(const std::string& fn) #endif int compression = theApp.GetConfigI("png_compression_level"); return GSPng::Save(fmt, fn, static_cast(m_data), m_size.x, m_size.y, m_pitch, compression); +#endif } diff --git a/plugins/GSdx/Window/GSSetting.h b/plugins/GSdx/Window/GSSetting.h index a6a6ac81c2d70..c325fd24981d8 100644 --- a/plugins/GSdx/Window/GSSetting.h +++ b/plugins/GSdx/Window/GSSetting.h @@ -21,7 +21,7 @@ #pragma once -#include "stdafx.h" +#include "../stdafx.h" struct GSSetting { diff --git a/plugins/GSdx/Window/GSWndRetro.cpp b/plugins/GSdx/Window/GSWndRetro.cpp new file mode 100644 index 0000000000000..78b590b888e1f --- /dev/null +++ b/plugins/GSdx/Window/GSWndRetro.cpp @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2007-2012 Gabest + * http://www.gabest.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "../stdafx.h" +#include "GSWndRetro.h" +#include +#include "options.h" + +extern struct retro_hw_render_callback hw_render; +extern retro_video_refresh_t video_cb; +extern retro_environment_t environ_cb; + +// static method +int GSWndRetroGL::SelectPlatform() +{ + return 0; +} + + +GSWndRetroGL::GSWndRetroGL() +{ +} + +void GSWndRetroGL::CreateContext(int major, int minor) +{ +} + +void GSWndRetroGL::AttachContext() +{ + m_ctx_attached = true; +} + +void GSWndRetroGL::DetachContext() +{ + m_ctx_attached = false; +} + +void GSWndRetroGL::PopulateWndGlFunction() +{ +} + +void GSWndRetroGL::BindAPI() +{ +} + +bool GSWndRetroGL::Attach(void* handle, bool managed) +{ + m_managed = managed; + return true; +} + +void GSWndRetroGL::Detach() +{ + DetachContext(); + DestroyNativeResources(); +} + +bool GSWndRetroGL::Create(const std::string& title, int w, int h) +{ + m_managed = true; + FullContextInit(); + return true; +} + +void* GSWndRetroGL::GetProcAddress(const char* name, bool opt) +{ + void* ptr = (void*)hw_render.get_proc_address(name); + if (ptr == nullptr) + { + if (theApp.GetConfigB("debug_opengl")) + fprintf(stderr, "Failed to find %s\n", name); + + if (!opt) + throw GSDXRecoverableError(); + } + return ptr; +} +GSVector2i GSgetInternalResolution(); +GSVector4i GSWndRetroGL::GetClientRect() +{ + return GSVector4i(0, 0, GSgetInternalResolution().x, GSgetInternalResolution().y); +} + +void GSWndRetroGL::SetSwapInterval() +{ +} + +void GSWndRetroGL::Flip() +{ + video_cb(RETRO_HW_FRAME_BUFFER_VALID, GSgetInternalResolution().x, GSgetInternalResolution().y, 0); +} + + +void* GSWndRetroGL::CreateNativeDisplay() +{ + return nullptr; +} + +void* GSWndRetroGL::CreateNativeWindow(int w, int h) +{ + return nullptr; +} + +void* GSWndRetroGL::AttachNativeWindow(void* handle) +{ + return handle; +} + +void GSWndRetroGL::DestroyNativeResources() +{ +} + +bool GSWndRetroGL::SetWindowText(const char* title) +{ + return true; +} + +bool GSWndRetro::Create(const std::string& title, int w, int h) +{ + m_managed = true; + + return true; +} + +bool GSWndRetro::Attach(void* handle, bool managed) +{ + m_managed = managed; + return true; +} + +void GSWndRetro::Detach() +{ + m_managed = true; +} + +GSVector4i GSWndRetro::GetClientRect() +{ +// return GSVector4i(0, 0, 640 , 480); + return GSVector4i(0, 0, 640 * Options::upscale_multiplier, 480 * Options::upscale_multiplier); +// return GSVector4i(0, 0, GSgetInternalResolution().x, GSgetInternalResolution().y); +} + +bool GSWndRetro::SetWindowText(const char* title) +{ + if (!m_managed) + return false; + return true; +} + +void GSWndRetro::Flip() +{ + video_cb(NULL, GSgetInternalResolution().x, GSgetInternalResolution().y, 0); +} diff --git a/plugins/GSdx/Window/GSWndRetro.h b/plugins/GSdx/Window/GSWndRetro.h new file mode 100644 index 0000000000000..7013c9e6395b4 --- /dev/null +++ b/plugins/GSdx/Window/GSWndRetro.h @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2007-2012 Gabest + * http://www.gabest.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ +#ifdef __LIBRETRO__ + +#include "GSWnd.h" + +#define GS_EGL_X11 1 +#define GS_EGL_WL 0 + +class GSWndRetroGL : public GSWndGL +{ + void PopulateWndGlFunction(); + void CreateContext(int major, int minor); + void BindAPI(); + void SetSwapInterval() final; + bool HasLateVsyncSupport() final { return false; } + void OpenEGLDisplay(); + void CloseEGLDisplay(); + +public: + GSWndRetroGL(); + virtual ~GSWndRetroGL() {} + + bool Create(const std::string& title, int w, int h) final; + bool Attach(void* handle, bool managed = true) final; + void Detach() final; + + virtual void* CreateNativeDisplay(); + virtual void* CreateNativeWindow(int w, int h); + virtual void* AttachNativeWindow(void* handle); + virtual void DestroyNativeResources(); + + GSVector4i GetClientRect(); + virtual bool SetWindowText(const char* title); + + void AttachContext() final; + void DetachContext() final; + void* GetProcAddress(const char* name, bool opt = false) final; + + void Flip() final; + + void Show() final {} + void Hide() final {} + void HideFrame() final {} + + void* GetDisplay() final { return (void*)-1; } // GSopen1 API + void* GetHandle() final { return (void*)-1; } // DX API + + + // Static to allow to query supported the platform + // before object creation + static int SelectPlatform(); +}; + +class GSWndRetro : public GSWnd +{ +public: + GSWndRetro() {} + virtual ~GSWndRetro() {} + + bool Create(const std::string& title, int w, int h); + bool Attach(void* handle, bool managed = true); + void Detach(); + + void* GetDisplay() {return (void*)-1;} + void* GetHandle() {return (void*)-1;} + GSVector4i GetClientRect(); + bool SetWindowText(const char* title); + + void Show() {} + void Hide() {} + void HideFrame() {} + + void Flip() final; +}; + +#endif diff --git a/plugins/GSdx/stdafx.cpp b/plugins/GSdx/stdafx.cpp index ce8fda9dc8e5c..11b716447628e 100644 --- a/plugins/GSdx/stdafx.cpp +++ b/plugins/GSdx/stdafx.cpp @@ -80,7 +80,7 @@ void* fifo_alloc(size_t size, size_t repeat) ASSERT(s_fh == NULL); if (repeat >= countof(s_Next)) { - fprintf(stderr, "Memory mapping overflow (%zu >= %u)\n", repeat, countof(s_Next)); + fprintf(stderr, "Memory mapping overflow (%zu >= %u)\n", repeat, (unsigned int)countof(s_Next)); return vmalloc(size * repeat, false); // Fallback to default vmalloc } diff --git a/plugins/GSdx/stdafx.h b/plugins/GSdx/stdafx.h index 78a5cf80797d3..b902b63b6ed2b 100644 --- a/plugins/GSdx/stdafx.h +++ b/plugins/GSdx/stdafx.h @@ -426,3 +426,11 @@ struct GLAutoPop { // Helper path to dump texture extern const std::string root_sw; extern const std::string root_hw; + +#ifdef __LIBRETRO__ +#include +extern retro_hw_render_callback hw_render; +#define GL_DEFAULT_FRAMEBUFFER hw_render.get_current_framebuffer() +#else +#define GL_DEFAULT_FRAMEBUFFER 0 +#endif diff --git a/plugins/USBnull/CMakeLists.txt b/plugins/USBnull/CMakeLists.txt index f37d2cfc031c3..066dba5781770 100644 --- a/plugins/USBnull/CMakeLists.txt +++ b/plugins/USBnull/CMakeLists.txt @@ -8,13 +8,13 @@ endif() # plugin name set(Output USBnull-0.7.0) - +if(NOT MSVC) set(USBnullFinalFlags -fvisibility=hidden -Wall -Wno-parentheses ) - +endif() # USBnull sources set(USBnullSources USB.cpp) @@ -58,4 +58,4 @@ else() add_pcsx2_plugin(${Output} "${USBnullFinalSources}" "${USBnullFinalLibs}" "${USBnullFinalFlags}") endif() -target_compile_features(${Output} PRIVATE cxx_std_17) \ No newline at end of file +target_compile_features(${Output} PRIVATE cxx_std_17) diff --git a/plugins/USBnull/USB.cpp b/plugins/USBnull/USB.cpp index 69b4ba126fbcd..290f23088205f 100644 --- a/plugins/USBnull/USB.cpp +++ b/plugins/USBnull/USB.cpp @@ -18,10 +18,13 @@ #include "svnrev.h" #include "USB.h" #include "null/config.inl" - +#ifdef BUILTIN_USB_PLUGIN +extern std::string s_strIniPath; +extern std::string s_strLogPath; +#else std::string s_strIniPath = "inis"; std::string s_strLogPath = "logs"; - +#endif const unsigned char version = PS2E_USB_VERSION; const unsigned char revision = 0; const unsigned char build = 7; // increase that with each version @@ -41,7 +44,7 @@ USBconfigure() SaveConfig(ini_path); } -void LogInit() +void USBLogInit() { const std::string LogFile(s_strLogPath + "/USBnull.log"); g_plugin_log.Open(LogFile); @@ -55,9 +58,9 @@ USBsetLogDir(const char *dir) // Reload the log file after updated the path g_plugin_log.Close(); - LogInit(); + USBLogInit(); } - +#ifndef BUILTIN_USB_PLUGIN EXPORT_C_(u32) PS2EgetLibType() { @@ -76,12 +79,12 @@ PS2EgetLibVersion2(u32 type) { return (version << 16) | (revision << 8) | build; } - +#endif EXPORT_C_(s32) USBinit() { LoadConfig(s_strIniPath + "/USBnull.ini"); - LogInit(); + USBLogInit(); g_plugin_log.WriteLn("USBnull plugin version %d,%d", revision, build); g_plugin_log.WriteLn("Initializing USBnull"); @@ -264,6 +267,16 @@ USBsetSettingsDir(const char *dir) // extended funcs +EXPORT_C_(void) +USBkeyEvent(keyEvent *ev) +{ +} + +EXPORT_C_(void) +USBabout() +{ +} + EXPORT_C_(s32) USBfreeze(int mode, freezeData *data) { @@ -283,10 +296,10 @@ USBfreeze(int mode, freezeData *data) return 0; } -/*EXPORT_C_(void) USBasync(u32 cycles) +EXPORT_C_(void) USBasync(u32 cycles) { // Optional function: Called in IopCounter.cpp. -}*/ +} EXPORT_C_(s32) USBtest() diff --git a/plugins/dev9null/CMakeLists.txt b/plugins/dev9null/CMakeLists.txt index 087e62cf884b9..203807067ec7b 100644 --- a/plugins/dev9null/CMakeLists.txt +++ b/plugins/dev9null/CMakeLists.txt @@ -8,13 +8,13 @@ endif() # plugin name set(Output dev9null-0.5.0) - +if(NOT MSVC) set(dev9nullFinalFlags -fvisibility=hidden -Wall -Wno-parentheses ) - +endif() # dev9null sources set(dev9nullSources DEV9.cpp) @@ -56,4 +56,4 @@ else() add_pcsx2_plugin(${Output} "${dev9nullFinalSources}" "${dev9nullFinalLibs}" "${dev9nullFinalFlags}") endif() -target_compile_features(${Output} PRIVATE cxx_std_17) \ No newline at end of file +target_compile_features(${Output} PRIVATE cxx_std_17) diff --git a/plugins/dev9null/DEV9.cpp b/plugins/dev9null/DEV9.cpp index ec77d2d318182..a284dc34af430 100644 --- a/plugins/dev9null/DEV9.cpp +++ b/plugins/dev9null/DEV9.cpp @@ -33,9 +33,9 @@ #include "svnrev.h" #include "null/config.inl" -const unsigned char version = PS2E_DEV9_VERSION; -const unsigned char revision = 0; -const unsigned char build = 5; // increase that with each version +static const unsigned char version = PS2E_DEV9_VERSION; +static const unsigned char revision = 0; +static const unsigned char build = 5; // increase that with each version static char libraryName[256]; @@ -43,9 +43,18 @@ static char libraryName[256]; void (*DEV9irq)(int); __aligned16 s8 dev9regs[0x10000]; - +#ifdef BUILTIN_DEV9_PLUGIN +extern std::string s_strIniPath; +extern std::string s_strLogPath; +#else std::string s_strIniPath = "inis"; std::string s_strLogPath = "logs"; +#endif + +EXPORT_C_(void) +DEV9about() +{ +} EXPORT_C_(void) DEV9configure() @@ -56,7 +65,7 @@ DEV9configure() SaveConfig(ini_path); } -void LogInit() +void DEV9LogInit() { const std::string LogFile(s_strLogPath + "/dev9null.log"); g_plugin_log.Open(LogFile); @@ -70,9 +79,9 @@ DEV9setLogDir(const char *dir) // Reload the log file after updated the path g_plugin_log.Close(); - LogInit(); + DEV9LogInit(); } - +#ifndef BUILTIN_DEV9_PLUGIN EXPORT_C_(u32) PS2EgetLibType() { @@ -91,12 +100,12 @@ PS2EgetLibVersion2(u32 type) { return (version << 16) | (revision << 8) | build; } - +#endif EXPORT_C_(s32) DEV9init() { LoadConfig(s_strIniPath + "/Dev9null.ini"); - LogInit(); + DEV9LogInit(); g_plugin_log.WriteLn("dev9null plugin version %d,%d", revision, build); g_plugin_log.WriteLn("Initializing dev9null"); // Initialize anything that needs to be initialized. @@ -304,6 +313,11 @@ DEV9setSettingsDir(const char *dir) s_strIniPath = (dir == NULL) ? "inis" : dir; } +EXPORT_C_(void) +DEV9async(u32 cycles) +{ +} + // extended funcs EXPORT_C_(s32) @@ -312,6 +326,11 @@ DEV9test() return 0; } +EXPORT_C_(void) +DEV9keyEvent(keyEvent *ev) +{ +} + EXPORT_C_(s32) DEV9freeze(int mode, freezeData *data) { diff --git a/plugins/dev9null/DEV9.h b/plugins/dev9null/DEV9.h index fc877fd780f81..2b67b09847460 100644 --- a/plugins/dev9null/DEV9.h +++ b/plugins/dev9null/DEV9.h @@ -25,10 +25,6 @@ #include "PS2Edefs.h" #include "PS2Eext.h" -extern const unsigned char version; -extern const unsigned char revision; -extern const unsigned char build; - extern void (*DEV9irq)(int); extern __aligned16 s8 dev9regs[0x10000]; diff --git a/plugins/onepad/CMakeLists.txt b/plugins/onepad/CMakeLists.txt index 202a4d457a6d5..c650c455db5eb 100644 --- a/plugins/onepad/CMakeLists.txt +++ b/plugins/onepad/CMakeLists.txt @@ -11,7 +11,7 @@ set(linux_sources "Linux") set(linux_headers "Linux") set(wx_sources "wx_dialog") set(wx_headers "wx_dialog") - +if(NOT MSVC) set(onepadGuiResources ${compiled_images}/analog.h ${compiled_images}/circle.h @@ -37,25 +37,21 @@ set(onepadGuiResources ${compiled_images}/arrow_left.h ${compiled_images}/arrow_right.h ) - +endif() # plugin name set(Output onepad) - +if(NOT MSVC) set(onepadFinalFlags -fvisibility=hidden -Wall -Wno-parentheses ) - +endif() + # onepad sources set(onepadSources controller.cpp - GamePad.cpp - SDL/joystick.cpp - keyboard.cpp - KeyStatus.cpp onepad.cpp - resources.cpp state_management.cpp) # onepad headers @@ -67,9 +63,20 @@ set(onepadHeaders keyboard.h KeyStatus.h onepad.h - resources.h state_management.h) +if(NOT MSVC) + set(onepadSources ${onepadSources} resources.cpp) + set(onepadHeaders ${onepadHeaders} resources.h) +endif() + +if(NOT LIBRETRO) +set(onepadSources ${onepadSources} + GamePad.cpp + SDL/joystick.cpp + keyboard.cpp + KeyStatus.cpp) + # onepad wx sources set(onepadwxSources ${wx_sources}/dialog.cpp @@ -82,7 +89,7 @@ set(onepadwxHeaders ${wx_headers}/opPanel.h ${wx_headers}/GamepadConfiguration.h ${wx_headers}/JoystickConfiguration.h) - + # onepad Linux sources set(onepadLinuxSources ${linux_sources}/ini.cpp @@ -99,6 +106,7 @@ set(onepadWindowsHeaders) set(onepadFinalLibs ${SDL2_LIBRARIES}) add_definitions(-DSDL_BUILD) +endif(NOT LIBRETRO) set(onepadFinalLibs ${onepadFinalLibs} @@ -121,9 +129,14 @@ include_directories( ${CMAKE_BINARY_DIR}/plugins/onepad/ ) +if(NOT GTKn_FOUND) + include_directories(${GLIB_INCLUDE_DIRS}) +endif() + ### Generate the resources files file(MAKE_DIRECTORY ${compiled_images}) +if(NOT MSVC) foreach(result_file IN ITEMS analog circle cross dp_bottom dp_left dp_right dp_up dualshock2 joystick_cursor l1 r1 l2 r2 l3 r3 select square start triangle arrow_up @@ -136,7 +149,7 @@ endforeach() set(RESOURCE_FILES res/game_controller_db.txt) add_custom_glib_res("resources" "onepad-res.xml" "onepad_res" ${RESOURCE_FILES}) - +endif(NOT MSVC) if(BUILTIN_PAD) add_pcsx2_lib(${Output} "${onepadFinalSources}" "${onepadFinalLibs}" "${onepadFinalFlags}") diff --git a/plugins/onepad/Linux/ini.cpp b/plugins/onepad/Linux/ini.cpp index 41f27addca4e8..3321b555c6027 100644 --- a/plugins/onepad/Linux/ini.cpp +++ b/plugins/onepad/Linux/ini.cpp @@ -45,7 +45,7 @@ void DefaultKeyboardValues() set_keyboard_key(0, XK_s, PAD_LEFT); } -void SaveConfig() +void PADSaveConfig() { FILE *f; @@ -74,7 +74,7 @@ void SaveConfig() fclose(f); } -void LoadConfig() +void PADLoadConfig() { FILE *f; bool have_user_setting = false; @@ -85,7 +85,7 @@ void LoadConfig() f = fopen(iniFile.c_str(), "r"); if (f == NULL) { printf("OnePAD: failed to load ini %s\n", iniFile.c_str()); - SaveConfig(); //save and return + PADSaveConfig(); //save and return return; } diff --git a/plugins/onepad/Linux/linux.cpp b/plugins/onepad/Linux/linux.cpp index 8390212ce93f4..4cf7b073f53f2 100644 --- a/plugins/onepad/Linux/linux.cpp +++ b/plugins/onepad/Linux/linux.cpp @@ -134,7 +134,7 @@ PADupdate(int pad) EXPORT_C_(void) PADconfigure() { - LoadConfig(); + PADLoadConfig(); DisplayDialog(); return; diff --git a/plugins/onepad/onepad.cpp b/plugins/onepad/onepad.cpp index 33754728084af..dfce72ec2325f 100644 --- a/plugins/onepad/onepad.cpp +++ b/plugins/onepad/onepad.cpp @@ -43,8 +43,13 @@ static char libraryName[256]; keyEvent event; static keyEvent s_event; +#ifdef BUILTIN_PAD_PLUGIN +extern std::string s_strIniPath; +extern std::string s_strLogPath; +#else std::string s_strIniPath("inis/"); std::string s_strLogPath("logs/"); +#endif const u32 version = PS2E_PAD_VERSION; const u32 revision = 2; @@ -82,7 +87,7 @@ static void InitLibraryName() SVN_MODS ? "m" : ""); #endif } - +#ifndef BUILTIN_PAD_PLUGIN EXPORT_C_(u32) PS2EgetLibType() { @@ -126,7 +131,7 @@ void __LogToConsole(const char *fmt, ...) vprintf(fmt, list); va_end(list); } - +#endif void initLogging() { #ifdef PAD_LOG @@ -158,7 +163,7 @@ PADinit(u32 flags) { initLogging(); - LoadConfig(); + PADLoadConfig(); Pad::reset_all(); @@ -234,6 +239,12 @@ PADsetSlot(u8 port, u8 slot) return 1; } +EXPORT_C_(s32) +PADqueryMtap(u8 port) +{ + return 0; +} + EXPORT_C_(s32) PADfreeze(int mode, freezeData *data) { @@ -319,6 +330,7 @@ PADpoll(u8 value) EXPORT_C_(keyEvent *) PADkeyEvent() { +#ifndef __LIBRETRO__ #ifdef SDL_BUILD // Take the opportunity to handle hot plugging here SDL_Event events; @@ -343,16 +355,16 @@ PADkeyEvent() s_event = g_ev_fifo.dequeue(); AnalyzeKeyEvent(s_event); // PAD_LOG("Returning Event. Event Type: %d, Key: %d\n", s_event.evt, s_event.key); +#endif return &s_event; } - -#if defined(__unix__) EXPORT_C_(void) PADWriteEvent(keyEvent &evt) { +#if defined(__unix__) // if (evt.evt != 6) { // Skip mouse move events for logging // PAD_LOG("Pushing Event. Event Type: %d, Key: %d\n", evt.evt, evt.key); // } g_ev_fifo.push(evt); -} #endif +} diff --git a/plugins/onepad/onepad.h b/plugins/onepad/onepad.h index b20abd5290ba8..ef40b4422717f 100644 --- a/plugins/onepad/onepad.h +++ b/plugins/onepad/onepad.h @@ -109,12 +109,15 @@ enum gamePadValues { #include "KeyStatus.h" #include "mt_queue.h" +#ifdef BUILTIN_PAD_PLUGIN +#define EXPORT_C_(type) extern "C" type CALLBACK +#else #ifdef _MSC_VER #define EXPORT_C_(type) extern "C" __declspec(dllexport) type CALLBACK #else #define EXPORT_C_(type) extern "C" __attribute__((stdcall, externally_visible, visibility("default"))) type #endif - +#endif extern FILE *padLog; extern void initLogging(); @@ -130,8 +133,8 @@ void PADsetMode(int pad, int mode); void __Log(const char *fmt, ...); void __LogToConsole(const char *fmt, ...); -void LoadConfig(); -void SaveConfig(); +void PADLoadConfig(); +void PADSaveConfig(); void SysMessage(char *fmt, ...); diff --git a/plugins/onepad/wx_dialog/dialog.cpp b/plugins/onepad/wx_dialog/dialog.cpp index fa8cd93366076..7d3f0c664c6b0 100644 --- a/plugins/onepad/wx_dialog/dialog.cpp +++ b/plugins/onepad/wx_dialog/dialog.cpp @@ -185,7 +185,7 @@ static std::string KeyName(int pad, int key, int keysym) #endif // Construtor of Dialog -Dialog::Dialog() +PadDialog::PadDialog() : wxDialog(NULL, // Parent wxID_ANY, // ID _T("OnePad configuration"), // Title @@ -442,7 +442,7 @@ Dialog::Dialog() m_bt_gamepad[i][Analog]->Disable(); } - Bind(wxEVT_BUTTON, &Dialog::OnButtonClicked, this); + Bind(wxEVT_BUTTON, &PadDialog::OnButtonClicked, this); for (int i = 0; i < GAMEPAD_NUMBER; ++i) { for (int j = 0; j < NB_IMG; ++j) { @@ -451,10 +451,10 @@ Dialog::Dialog() } } -void Dialog::InitDialog() +void PadDialog::InitDialog() { GamePad::EnumerateGamePads(s_vgamePad); // activate gamepads - LoadConfig(); // Load configuration from the ini file + PADLoadConfig(); // Load configuration from the ini file repopulate(); // Set label and fit simulated key array } @@ -462,7 +462,7 @@ void Dialog::InitDialog() /*********** Events functions ***********/ /****************************************/ -void Dialog::OnButtonClicked(wxCommandEvent &event) +void PadDialog::OnButtonClicked(wxCommandEvent &event) { // Affichage d'un message à chaque clic sur le bouton wxButton *bt_tmp = (wxButton *)event.GetEventObject(); // get the button object @@ -556,10 +556,10 @@ void Dialog::OnButtonClicked(wxCommandEvent &event) usleep(500000); // give enough time to the user to release the button } } else if (bt_id == Ok) { // If the button ID is equals to the Ok button ID - SaveConfig(); // Save the configuration + PADSaveConfig(); // Save the configuration Close(); // Close the window } else if (bt_id == Apply) { // If the button ID is equals to the Apply button ID - SaveConfig(); // Save the configuration + PADSaveConfig(); // Save the configuration } else if (bt_id == Cancel) { // If the button ID is equals to the cancel button ID Close(); // Close the window } @@ -569,7 +569,7 @@ void Dialog::OnButtonClicked(wxCommandEvent &event) /*********** Methods functions **********/ /****************************************/ -void Dialog::config_key(int pad, int key) +void PadDialog::config_key(int pad, int key) { bool captured = false; u32 key_pressed = 0; @@ -590,7 +590,7 @@ void Dialog::config_key(int pad, int key) KeyName(pad, key, m_simulatedKeys[pad][key]).c_str()); } -void Dialog::clear_key(int pad, int key) +void PadDialog::clear_key(int pad, int key) { // Erase the keyboard binded key u32 keysim = m_simulatedKeys[pad][key]; @@ -602,7 +602,7 @@ void Dialog::clear_key(int pad, int key) // Set button values -void Dialog::repopulate() +void PadDialog::repopulate() { for (int gamepad_id = 0; gamepad_id < GAMEPAD_NUMBER; ++gamepad_id) { // keyboard/mouse key @@ -630,10 +630,10 @@ void DisplayDialog() ftw.ShowModal(); g_conf.ftw = 0; - SaveConfig(); + PADSaveConfig(); } - Dialog dialog; + PadDialog dialog; dialog.InitDialog(); dialog.ShowModal(); diff --git a/plugins/onepad/wx_dialog/dialog.h b/plugins/onepad/wx_dialog/dialog.h index ac0228b552987..0a43e22cecd6c 100644 --- a/plugins/onepad/wx_dialog/dialog.h +++ b/plugins/onepad/wx_dialog/dialog.h @@ -63,7 +63,7 @@ enum gui_buttons { #define DEFAULT_WIDTH 1000 #define DEFAULT_HEIGHT 740 -class Dialog : public wxDialog +class PadDialog : public wxDialog { // Panels opPanel *m_pan_tabs[GAMEPAD_NUMBER]; // Gamepad Tabs box @@ -88,7 +88,7 @@ class Dialog : public wxDialog void JoystickEvent(wxTimerEvent &); public: - Dialog(); + PadDialog(); void InitDialog(); void show(); };