mirror of https://github.com/mgba-emu/mgba.git
Merge branch 'master' (early part) into medusa
This commit is contained in:
commit
14405369cb
|
@ -33,7 +33,9 @@ int utfcmp(const uint16_t* utf16, const char* utf8, size_t utf16Length, size_t u
|
|||
char* utf16to8(const uint16_t* utf16, size_t length);
|
||||
uint32_t utf8Char(const char** unicode, size_t* length);
|
||||
uint32_t utf16Char(const uint16_t** unicode, size_t* length);
|
||||
char* latin1ToUtf8(const char* latin1, size_t length);
|
||||
char* gbkToUtf8(const char* gbk, size_t length);
|
||||
size_t utf8strlen(const char* string);
|
||||
|
||||
int hexDigit(char digit);
|
||||
const char* hex32(const char* line, uint32_t* out);
|
||||
|
|
|
@ -107,6 +107,7 @@ struct mCore {
|
|||
void (*setKeys)(struct mCore*, uint32_t keys);
|
||||
void (*addKeys)(struct mCore*, uint32_t keys);
|
||||
void (*clearKeys)(struct mCore*, uint32_t keys);
|
||||
uint32_t (*getKeys)(struct mCore*);
|
||||
|
||||
void (*setCursorLocation)(struct mCore*, int x, int y);
|
||||
void (*setCursorDown)(struct mCore*, bool down);
|
||||
|
|
|
@ -445,6 +445,11 @@ static void _DSCoreClearKeys(struct mCore* core, uint32_t keys) {
|
|||
dscore->keys &= ~keys;
|
||||
}
|
||||
|
||||
static uint32_t _DSCoreGetKeys(struct mCore* core) {
|
||||
struct DSCore* dscore = (struct DSCore*) core;
|
||||
return dscore->keys;
|
||||
}
|
||||
|
||||
static void _DSCoreSetCursorLocation(struct mCore* core, int x, int y) {
|
||||
struct DSCore* dscore = (struct DSCore*) core;
|
||||
dscore->cursorX = x;
|
||||
|
@ -735,6 +740,7 @@ struct mCore* DSCoreCreate(void) {
|
|||
core->setKeys = _DSCoreSetKeys;
|
||||
core->addKeys = _DSCoreAddKeys;
|
||||
core->clearKeys = _DSCoreClearKeys;
|
||||
core->getKeys = _DSCoreGetKeys;
|
||||
core->setCursorLocation = _DSCoreSetCursorLocation;
|
||||
core->setCursorDown = _DSCoreSetCursorDown;
|
||||
core->frameCounter = _DSCoreFrameCounter;
|
||||
|
|
|
@ -700,6 +700,11 @@ static void _GBCoreClearKeys(struct mCore* core, uint32_t keys) {
|
|||
gbcore->keys &= ~keys;
|
||||
}
|
||||
|
||||
static uint32_t _GBCoreGetKeys(struct mCore* core) {
|
||||
struct GBCore* gbcore = (struct GBCore*) core;
|
||||
return gbcore->keys;
|
||||
}
|
||||
|
||||
static void _GBCoreSetCursorLocation(struct mCore* core, int x, int y) {
|
||||
UNUSED(core);
|
||||
UNUSED(x);
|
||||
|
@ -1114,6 +1119,7 @@ struct mCore* GBCoreCreate(void) {
|
|||
core->setKeys = _GBCoreSetKeys;
|
||||
core->addKeys = _GBCoreAddKeys;
|
||||
core->clearKeys = _GBCoreClearKeys;
|
||||
core->getKeys = _GBCoreGetKeys;
|
||||
core->setCursorLocation = _GBCoreSetCursorLocation;
|
||||
core->setCursorDown = _GBCoreSetCursorDown;
|
||||
core->frameCounter = _GBCoreFrameCounter;
|
||||
|
|
|
@ -229,6 +229,9 @@ static void GBSramDeinit(struct GB* gb) {
|
|||
bool GBLoadSave(struct GB* gb, struct VFile* vf) {
|
||||
GBSramDeinit(gb);
|
||||
gb->sramVf = vf;
|
||||
if (gb->sramRealVf && gb->sramRealVf != vf) {
|
||||
gb->sramRealVf->close(gb->sramRealVf);
|
||||
}
|
||||
gb->sramRealVf = vf;
|
||||
if (gb->sramSize) {
|
||||
GBResizeSram(gb, gb->sramSize);
|
||||
|
|
|
@ -734,6 +734,11 @@ static void _GBACoreClearKeys(struct mCore* core, uint32_t keys) {
|
|||
GBATestKeypadIRQ(gba);
|
||||
}
|
||||
|
||||
static uint32_t _GBACoreGetKeys(struct mCore* core) {
|
||||
struct GBA* gba = core->board;
|
||||
return gba->keysActive;
|
||||
}
|
||||
|
||||
static void _GBACoreSetCursorLocation(struct mCore* core, int x, int y) {
|
||||
UNUSED(core);
|
||||
UNUSED(x);
|
||||
|
@ -1231,6 +1236,7 @@ struct mCore* GBACoreCreate(void) {
|
|||
core->setKeys = _GBACoreSetKeys;
|
||||
core->addKeys = _GBACoreAddKeys;
|
||||
core->clearKeys = _GBACoreClearKeys;
|
||||
core->getKeys = _GBACoreGetKeys;
|
||||
core->setCursorLocation = _GBACoreSetCursorLocation;
|
||||
core->setCursorDown = _GBACoreSetCursorDown;
|
||||
core->frameCounter = _GBACoreFrameCounter;
|
||||
|
|
|
@ -75,6 +75,8 @@ static void GBAInit(void* cpu, struct mCPUComponent* component) {
|
|||
GBAMemoryInit(gba);
|
||||
|
||||
gba->memory.savedata.timing = &gba->timing;
|
||||
gba->memory.savedata.vf = NULL;
|
||||
gba->memory.savedata.realVf = NULL;
|
||||
GBASavedataInit(&gba->memory.savedata, NULL);
|
||||
|
||||
gba->video.p = gba;
|
||||
|
|
|
@ -45,6 +45,9 @@ void GBASavedataInit(struct GBASavedata* savedata, struct VFile* vf) {
|
|||
savedata->command = EEPROM_COMMAND_NULL;
|
||||
savedata->flashState = FLASH_STATE_RAW;
|
||||
savedata->vf = vf;
|
||||
if (savedata->realVf && savedata->realVf != vf) {
|
||||
savedata->realVf->close(savedata->realVf);
|
||||
}
|
||||
savedata->realVf = vf;
|
||||
savedata->mapMode = MAP_WRITE;
|
||||
savedata->maskWriteback = false;
|
||||
|
|
|
@ -24,14 +24,17 @@ set(CMAKE_AUTOMOC ON)
|
|||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/input)
|
||||
|
||||
set(QT_LIBRARIES)
|
||||
|
||||
find_package(Qt5 COMPONENTS Core Widgets Network Multimedia)
|
||||
set(QT Qt5)
|
||||
|
||||
if(NOT BUILD_GL AND NOT BUILD_GLES2 AND NOT BUILD_GLES3)
|
||||
message(WARNING "OpenGL is recommended to build the Qt port")
|
||||
endif()
|
||||
|
||||
set(FOUND_QT ${Qt5Widgets_FOUND} PARENT_SCOPE)
|
||||
if(NOT Qt5Widgets_FOUND)
|
||||
set(FOUND_QT ${${QT}Widgets_FOUND} PARENT_SCOPE)
|
||||
if(NOT ${QT}Widgets_FOUND)
|
||||
message(WARNING "Cannot find Qt modules")
|
||||
return()
|
||||
endif()
|
||||
|
@ -42,7 +45,9 @@ if(APPLE)
|
|||
list(APPEND QT_DEFINES USE_SHARE_WIDGET)
|
||||
endif()
|
||||
|
||||
if(Qt5Widgets_VERSION MATCHES "^5.15")
|
||||
if(Qt6Widgets_VERSION)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mmacosx-version-min=10.14")
|
||||
elseif(Qt5Widgets_VERSION MATCHES "^5.15")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mmacosx-version-min=10.13")
|
||||
elseif(Qt5Widgets_VERSION MATCHES "^5.1[234]")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mmacosx-version-min=10.12")
|
||||
|
@ -64,7 +69,7 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
|||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-deprecated-declarations")
|
||||
endif()
|
||||
|
||||
get_target_property(QT_TYPE Qt5::Core TYPE)
|
||||
get_target_property(QT_TYPE ${QT}::Core TYPE)
|
||||
if(QT_TYPE STREQUAL STATIC_LIBRARY)
|
||||
set(QT_STATIC ON)
|
||||
list(APPEND QT_DEFINES QT_STATIC)
|
||||
|
@ -184,7 +189,6 @@ set(GB_SRC
|
|||
GBOverride.cpp
|
||||
PrinterView.cpp)
|
||||
|
||||
set(QT_LIBRARIES)
|
||||
set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS},libqt5widgets5")
|
||||
|
||||
set(AUDIO_SRC)
|
||||
|
@ -200,17 +204,17 @@ if(M_CORE_GB)
|
|||
list(APPEND PLATFORM_SRC ${GB_SRC})
|
||||
endif()
|
||||
|
||||
if(Qt5Multimedia_FOUND)
|
||||
if(${QT}Multimedia_FOUND)
|
||||
list(APPEND AUDIO_SRC
|
||||
AudioProcessorQt.cpp
|
||||
AudioDevice.cpp)
|
||||
list(APPEND SOURCE_FILES
|
||||
VideoDumper.cpp)
|
||||
if (WIN32 AND QT_STATIC)
|
||||
list(APPEND QT_LIBRARIES Qt5::QWindowsAudioPlugin Qt5::DSServicePlugin Qt5::QWindowsVistaStylePlugin
|
||||
list(APPEND QT_LIBRARIES ${QT}::QWindowsAudioPlugin ${QT}::DSServicePlugin ${QT}::QWindowsVistaStylePlugin
|
||||
strmiids mfuuid mfplat mf ksguid dxva2 evr d3d9)
|
||||
endif()
|
||||
list(APPEND QT_LIBRARIES Qt5::Multimedia)
|
||||
list(APPEND QT_LIBRARIES ${QT}::Multimedia)
|
||||
list(APPEND QT_DEFINES BUILD_QT_MULTIMEDIA)
|
||||
set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS},libqt5multimedia5")
|
||||
endif()
|
||||
|
@ -245,10 +249,18 @@ if(USE_DISCORD_RPC)
|
|||
list(APPEND SOURCE_FILES DiscordCoordinator.cpp)
|
||||
endif()
|
||||
|
||||
qt5_add_resources(RESOURCES resources.qrc)
|
||||
if(TARGET Qt6::Core)
|
||||
qt_add_resources(RESOURCES resources.qrc)
|
||||
else()
|
||||
qt5_add_resources(RESOURCES resources.qrc)
|
||||
endif()
|
||||
if(BUILD_UPDATER)
|
||||
file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/updater.qrc INPUT ${CMAKE_CURRENT_SOURCE_DIR}/updater.qrc.in)
|
||||
qt5_add_resources(UPDATER_RESOURCES ${CMAKE_CURRENT_BINARY_DIR}/updater.qrc)
|
||||
if(TARGET Qt6::Core)
|
||||
qt_add_resources(UPDATER_RESOURCES ${CMAKE_CURRENT_BINARY_DIR}/updater.qrc)
|
||||
else()
|
||||
qt5_add_resources(UPDATER_RESOURCES ${CMAKE_CURRENT_BINARY_DIR}/updater.qrc)
|
||||
endif()
|
||||
set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/updater.qrc PROPERTIES GENERATED ON)
|
||||
list(APPEND RESOURCES ${UPDATER_RESOURCES})
|
||||
endif()
|
||||
|
@ -290,21 +302,29 @@ if(NOT WIN32 AND NOT APPLE)
|
|||
endif()
|
||||
endif()
|
||||
|
||||
find_package(Qt5LinguistTools)
|
||||
if(Qt5LinguistTools_FOUND)
|
||||
find_package(${QT}LinguistTools)
|
||||
if(${QT}LinguistTools_FOUND)
|
||||
set(TRANSLATION_FILES)
|
||||
set(TRANSLATION_QRC "${CMAKE_CURRENT_BINARY_DIR}/ts.qrc")
|
||||
file(GLOB TS_FILES "${CMAKE_CURRENT_SOURCE_DIR}/ts/${BINARY_NAME}-*.ts")
|
||||
if(UPDATE_TRANSLATIONS)
|
||||
qt5_create_translation(TRANSLATION_FILES ${SOURCE_FILES} ${UI_FILES} ${TS_FILES} OPTIONS -locations absolute -no-obsolete)
|
||||
if(TARGET Qt6::Core)
|
||||
qt_create_translation(TRANSLATION_FILES ${SOURCE_FILES} ${UI_FILES} ${TS_FILES} OPTIONS -locations absolute -no-obsolete)
|
||||
else()
|
||||
qt5_create_translation(TRANSLATION_FILES ${SOURCE_FILES} ${UI_FILES} ${TS_FILES} OPTIONS -locations absolute -no-obsolete)
|
||||
endif()
|
||||
list(REMOVE_ITEM TS_FILES "${CMAKE_CURRENT_SOURCE_DIR}/ts/${BINARY_NAME}-template.ts")
|
||||
else()
|
||||
list(REMOVE_ITEM TS_FILES "${CMAKE_CURRENT_SOURCE_DIR}/ts/${BINARY_NAME}-template.ts")
|
||||
qt5_add_translation(TRANSLATION_FILES ${TS_FILES})
|
||||
if(TARGET Qt6::Core)
|
||||
qt_add_translation(TRANSLATION_FILES ${TS_FILES})
|
||||
else()
|
||||
qt5_add_translation(TRANSLATION_FILES ${TS_FILES})
|
||||
endif()
|
||||
endif()
|
||||
set(QT_QM_FILES)
|
||||
if(QT_STATIC)
|
||||
get_target_property(QT_CORE_LOCATION Qt5::Core LOCATION)
|
||||
get_target_property(QT_CORE_LOCATION ${QT}::Core LOCATION)
|
||||
get_filename_component(QT_CORE_LOCATION ${QT_CORE_LOCATION} DIRECTORY)
|
||||
get_filename_component(QT_QM_LOCATION "${QT_CORE_LOCATION}/../translations" ABSOLUTE)
|
||||
foreach(TS ${TS_FILES})
|
||||
|
@ -320,11 +340,19 @@ if(Qt5LinguistTools_FOUND)
|
|||
add_custom_command(OUTPUT ${TRANSLATION_QRC}
|
||||
COMMAND ${CMAKE_COMMAND} -DTRANSLATION_QRC:FILEPATH="${TRANSLATION_QRC}" -DQM_BASE="${CMAKE_CURRENT_BINARY_DIR}" "-DTRANSLATION_FILES='${TRANSLATION_FILES}'" -P "${CMAKE_CURRENT_SOURCE_DIR}/ts.cmake"
|
||||
DEPENDS ${TRANSLATION_FILES})
|
||||
qt5_add_resources(TRANSLATION_RESOURCES ${TRANSLATION_QRC})
|
||||
if(TARGET Qt6::Core)
|
||||
qt_add_resources(TRANSLATION_RESOURCES ${TRANSLATION_QRC})
|
||||
else()
|
||||
qt5_add_resources(TRANSLATION_RESOURCES ${TRANSLATION_QRC})
|
||||
endif()
|
||||
list(APPEND RESOURCES ${TRANSLATION_RESOURCES})
|
||||
endif()
|
||||
|
||||
qt5_wrap_ui(UI_SRC ${UI_FILES})
|
||||
if(TARGET Qt6::Core)
|
||||
qt_wrap_ui(UI_SRC ${UI_FILES})
|
||||
else()
|
||||
qt5_wrap_ui(UI_SRC ${UI_FILES})
|
||||
endif()
|
||||
|
||||
add_executable(${BINARY_NAME}-qt WIN32 MACOSX_BUNDLE main.cpp ${CMAKE_SOURCE_DIR}/res/icon.icns ${SOURCE_FILES} ${PLATFORM_SRC} ${UI_SRC} ${AUDIO_SRC} ${RESOURCES})
|
||||
set_target_properties(${BINARY_NAME}-qt PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_SOURCE_DIR}/res/info.plist.in COMPILE_DEFINITIONS "${FEATURE_DEFINES};${FUNCTION_DEFINES};${OS_DEFINES};${QT_DEFINES}" COMPILE_OPTIONS "${FEATURE_FLAGS}")
|
||||
|
@ -336,7 +364,7 @@ if(WIN32)
|
|||
endif()
|
||||
endif()
|
||||
|
||||
list(APPEND QT_LIBRARIES Qt5::Widgets Qt5::Network)
|
||||
list(APPEND QT_LIBRARIES ${QT}::Widgets ${QT}::Network)
|
||||
if(BUILD_GL OR BUILD_GLES2 OR BUILD_EPOXY)
|
||||
list(APPEND QT_LIBRARIES ${OPENGL_LIBRARY} ${OPENGLES2_LIBRARY})
|
||||
endif()
|
||||
|
@ -344,20 +372,20 @@ if(QT_STATIC)
|
|||
find_library(QTPCRE NAMES qtpcre2 qtpcre)
|
||||
if(WIN32)
|
||||
if(CMAKE_CROSSCOMPILING)
|
||||
set(QWINDOWS_DEPS Qt5EventDispatcherSupport Qt5FontDatabaseSupport Qt5ThemeSupport Qt5WindowsUIAutomationSupport)
|
||||
set(QWINDOWS_DEPS ${QT}EventDispatcherSupport ${QT}FontDatabaseSupport ${QT}ThemeSupport ${QT}WindowsUIAutomationSupport)
|
||||
endif()
|
||||
list(APPEND QT_LIBRARIES Qt5::QWindowsIntegrationPlugin ${QWINDOWS_DEPS} amstrmid dwmapi uxtheme imm32 -static-libgcc -static-libstdc++)
|
||||
set_target_properties(Qt5::Core PROPERTIES INTERFACE_LINK_LIBRARIES "${QTPCRE};version;winmm;ssl;crypto;ws2_32;iphlpapi;crypt32;userenv;netapi32;wtsapi32")
|
||||
set_target_properties(Qt5::Gui PROPERTIES INTERFACE_LINK_LIBRARIES ${OPENGL_LIBRARY} ${OPENGLES2_LIBRARY})
|
||||
list(APPEND QT_LIBRARIES ${QT}::QWindowsIntegrationPlugin ${QWINDOWS_DEPS} amstrmid dwmapi uxtheme imm32 -static-libgcc -static-libstdc++)
|
||||
set_target_properties(${QT}::Core PROPERTIES INTERFACE_LINK_LIBRARIES "${QTPCRE};version;winmm;ssl;crypto;ws2_32;iphlpapi;crypt32;userenv;netapi32;wtsapi32")
|
||||
set_target_properties(${QT}::Gui PROPERTIES INTERFACE_LINK_LIBRARIES ${OPENGL_LIBRARY} ${OPENGLES2_LIBRARY})
|
||||
elseif(APPLE)
|
||||
find_package(Cups)
|
||||
find_package(Qt5PrintSupport)
|
||||
list(APPEND QT_LIBRARIES Cups Qt5::PrintSupport Qt5::QCocoaIntegrationPlugin Qt5::CoreAudioPlugin Qt5::AVFServicePlugin Qt5::QCocoaPrinterSupportPlugin)
|
||||
list(APPEND QT_LIBRARIES Qt5AccessibilitySupport Qt5CglSupport Qt5ClipboardSupport Qt5FontDatabaseSupport Qt5GraphicsSupport Qt5ThemeSupport)
|
||||
find_package(${QT}PrintSupport)
|
||||
list(APPEND QT_LIBRARIES Cups ${QT}::PrintSupport ${QT}::QCocoaIntegrationPlugin ${QT}::CoreAudioPlugin ${QT}::AVFServicePlugin ${QT}::QCocoaPrinterSupportPlugin)
|
||||
list(APPEND QT_LIBRARIES ${QT}AccessibilitySupport ${QT}CglSupport ${QT}ClipboardSupport ${QT}FontDatabaseSupport ${QT}GraphicsSupport ${QT}ThemeSupport)
|
||||
list(APPEND QT_LIBRARIES "-framework AVFoundation" "-framework CoreMedia" "-framework SystemConfiguration" "-framework Security")
|
||||
set_target_properties(Qt5::Core PROPERTIES INTERFACE_LINK_LIBRARIES "${QTPCRE}")
|
||||
set_target_properties(${QT}::Core PROPERTIES INTERFACE_LINK_LIBRARIES "${QTPCRE}")
|
||||
elseif(UNIX)
|
||||
list(APPEND QT_LIBRARIES Qt5::FontDatabaseSupport Qt5::XcbQpa)
|
||||
list(APPEND QT_LIBRARIES ${QT}::FontDatabaseSupport ${QT}::XcbQpa)
|
||||
endif()
|
||||
endif()
|
||||
target_link_libraries(${BINARY_NAME}-qt ${PLATFORM_LIBRARY} ${BINARY_NAME} ${QT_LIBRARIES})
|
||||
|
@ -377,9 +405,9 @@ if(APPLE OR WIN32)
|
|||
endif()
|
||||
if(APPLE)
|
||||
if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin")
|
||||
get_target_property(QTCOCOA Qt5::QCocoaIntegrationPlugin LOCATION)
|
||||
get_target_property(COREAUDIO Qt5::CoreAudioPlugin LOCATION)
|
||||
get_target_property(QTAVFSERVICE Qt5::AVFServicePlugin LOCATION)
|
||||
get_target_property(QTCOCOA ${QT}::QCocoaIntegrationPlugin LOCATION)
|
||||
get_target_property(COREAUDIO ${QT}::CoreAudioPlugin LOCATION)
|
||||
get_target_property(QTAVFSERVICE ${QT}::AVFServicePlugin LOCATION)
|
||||
set(BUNDLE_PATH ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.app)
|
||||
target_sources(${BINARY_NAME}-qt PRIVATE "${PLUGINS}")
|
||||
set_source_files_properties("${QTCOCOA}" PROPERTIES MACOSX_PACKAGE_LOCATION Contents/PlugIns)
|
||||
|
|
|
@ -88,8 +88,8 @@ void DisplayQt::resizeContext() {
|
|||
if (m_width != size.width() || m_height != size.height()) {
|
||||
m_width = size.width();
|
||||
m_height = size.height();
|
||||
m_oldBacking = std::move(QImage());
|
||||
m_backing = std::move(QImage());
|
||||
m_oldBacking = QImage();
|
||||
m_backing = QImage();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -61,7 +61,6 @@ public:
|
|||
QFont monospaceFont() { return m_monospace; }
|
||||
|
||||
QList<Window*> windows() { return m_windows; }
|
||||
Window* newWindow();
|
||||
|
||||
QString getOpenFileName(QWidget* owner, const QString& title, const QString& filter = {});
|
||||
QStringList getOpenFileNames(QWidget* owner, const QString& title, const QString& filter = {});
|
||||
|
@ -81,6 +80,7 @@ public:
|
|||
|
||||
public slots:
|
||||
void restartForUpdate();
|
||||
Window* newWindow();
|
||||
|
||||
signals:
|
||||
void jobFinished(qint64 jobId);
|
||||
|
|
|
@ -13,8 +13,6 @@ using namespace QGBA;
|
|||
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
|
||||
#define endl Qt::endl
|
||||
#else
|
||||
#define endl std::endl
|
||||
#endif
|
||||
|
||||
LogController LogController::s_global(mLOG_ALL);
|
||||
|
|
|
@ -678,7 +678,7 @@ void MemoryModel::adjustCursor(int adjust, bool shift) {
|
|||
}
|
||||
int cursorPosition = m_top;
|
||||
if (shift) {
|
||||
uint32_t absolute;
|
||||
uint32_t absolute = adjust;
|
||||
if (m_selectionAnchor == m_selection.first) {
|
||||
if (adjust < 0 && m_base - adjust > m_selection.second) {
|
||||
absolute = m_base - m_selection.second + m_align;
|
||||
|
|
|
@ -1093,7 +1093,7 @@ void Window::reloadDisplayDriver() {
|
|||
m_display->stopDrawing();
|
||||
detachWidget(m_display.get());
|
||||
}
|
||||
m_display = std::unique_ptr<Display>(Display::create(this));
|
||||
m_display = std::unique_ptr<QGBA::Display>(Display::create(this));
|
||||
if (!m_display) {
|
||||
LOG(QT, ERROR) << tr("Failed to create an appropriate display device, falling back to software display. "
|
||||
"Games may run slowly, especially with larger windows.");
|
||||
|
@ -1105,12 +1105,12 @@ void Window::reloadDisplayDriver() {
|
|||
m_shaderView = std::make_unique<ShaderSelector>(m_display.get(), m_config);
|
||||
#endif
|
||||
|
||||
connect(m_display.get(), &Display::hideCursor, [this]() {
|
||||
connect(m_display.get(), &QGBA::Display::hideCursor, [this]() {
|
||||
if (static_cast<QStackedLayout*>(m_screenWidget->layout())->currentWidget() == m_display.get()) {
|
||||
m_screenWidget->setCursor(Qt::BlankCursor);
|
||||
}
|
||||
});
|
||||
connect(m_display.get(), &Display::showCursor, [this]() {
|
||||
connect(m_display.get(), &QGBA::Display::showCursor, [this]() {
|
||||
m_screenWidget->unsetCursor();
|
||||
});
|
||||
|
||||
|
@ -1459,9 +1459,7 @@ void Window::setupMenu(QMenuBar* menubar) {
|
|||
}
|
||||
|
||||
m_actions.addSeparator("file");
|
||||
m_multiWindow = m_actions.addAction(tr("New multiplayer window"), "multiWindow", [this]() {
|
||||
GBAApp::app()->newWindow();
|
||||
}, "file");
|
||||
m_multiWindow = m_actions.addAction(tr("New multiplayer window"), "multiWindow", GBAApp::app(), &GBAApp::newWindow, "file");
|
||||
|
||||
#ifdef M_CORE_GBA
|
||||
Action* dolphin = m_actions.addAction(tr("Connect to Dolphin..."), "connectDolphin", openNamedTView<DolphinConnector>(&m_dolphinView, this), "file");
|
||||
|
@ -1973,7 +1971,7 @@ Action* Window::addGameAction(const QString& visibleName, const QString& name, A
|
|||
|
||||
template<typename T, typename V>
|
||||
Action* Window::addGameAction(const QString& visibleName, const QString& name, T* obj, V (T::*method)(), const QString& menu, const QKeySequence& shortcut) {
|
||||
return addGameAction(visibleName, name, [this, obj, method]() {
|
||||
return addGameAction(visibleName, name, [obj, method]() {
|
||||
(obj->*method)();
|
||||
}, menu, shortcut);
|
||||
}
|
||||
|
@ -2161,7 +2159,7 @@ void Window::setController(CoreController* controller, const QString& fname) {
|
|||
|
||||
void Window::attachDisplay() {
|
||||
m_display->attach(m_controller);
|
||||
connect(m_display.get(), &Display::drawingStarted, this, &Window::changeRenderer);
|
||||
connect(m_display.get(), &QGBA::Display::drawingStarted, this, &Window::changeRenderer);
|
||||
m_display->startDrawing(m_controller);
|
||||
}
|
||||
|
||||
|
|
|
@ -28,6 +28,8 @@ set(GUI_FILES
|
|||
gui/menu.c)
|
||||
|
||||
set(TEST_FILES
|
||||
test/string-parser.c
|
||||
test/string-utf8.c
|
||||
test/text-codec.c
|
||||
test/vfs.c)
|
||||
|
||||
|
|
|
@ -183,7 +183,7 @@ bool ConfigurationWrite(const struct Configuration* configuration, const char* p
|
|||
}
|
||||
bool res = ConfigurationWriteVFile(configuration, vf);
|
||||
vf->close(vf);
|
||||
return true;
|
||||
return res;
|
||||
}
|
||||
|
||||
bool ConfigurationWriteVFile(const struct Configuration* configuration, struct VFile* vf) {
|
||||
|
|
|
@ -108,11 +108,30 @@ uint32_t utf16Char(const uint16_t** unicode, size_t* length) {
|
|||
return (highSurrogate << 10) + lowSurrogate + 0x10000;
|
||||
}
|
||||
|
||||
static const uint8_t _utf8len[0x40] = {
|
||||
/* 0000 xxxx */ 1, 1, 1, 1,
|
||||
/* 0001 xxxx */ 1, 1, 1, 1,
|
||||
/* 0010 xxxx */ 1, 1, 1, 1,
|
||||
/* 0011 xxxx */ 1, 1, 1, 1,
|
||||
/* 0100 xxxx */ 1, 1, 1, 1,
|
||||
/* 0101 xxxx */ 1, 1, 1, 1,
|
||||
/* 0110 xxxx */ 1, 1, 1, 1,
|
||||
/* 0111 xxxx */ 1, 1, 1, 1,
|
||||
/* 1000 xxxx */ 0, 0, 0, 0,
|
||||
/* 1001 xxxx */ 0, 0, 0, 0,
|
||||
/* 1010 xxxx */ 0, 0, 0, 0,
|
||||
/* 1011 xxxx */ 0, 0, 0, 0,
|
||||
/* 1100 xxxx */ 2, 2, 2, 2,
|
||||
/* 1101 xxxx */ 2, 2, 2, 2,
|
||||
/* 1110 xxxx */ 3, 3, 3, 3,
|
||||
/* 1111 xxxx */ 4, 4, 0, 0
|
||||
};
|
||||
|
||||
uint32_t utf8Char(const char** unicode, size_t* length) {
|
||||
if (*length == 0) {
|
||||
return 0;
|
||||
}
|
||||
char byte = **unicode;
|
||||
unsigned char byte = **unicode;
|
||||
--*length;
|
||||
++*unicode;
|
||||
if (!(byte & 0x80)) {
|
||||
|
@ -120,23 +139,17 @@ uint32_t utf8Char(const char** unicode, size_t* length) {
|
|||
}
|
||||
uint32_t unichar;
|
||||
static const int tops[4] = { 0xC0, 0xE0, 0xF0, 0xF8 };
|
||||
size_t numBytes;
|
||||
for (numBytes = 0; numBytes < 3; ++numBytes) {
|
||||
if ((byte & tops[numBytes + 1]) == tops[numBytes]) {
|
||||
break;
|
||||
}
|
||||
size_t numBytes = _utf8len[byte >> 2];
|
||||
unichar = byte & ~tops[numBytes - 1];
|
||||
if (numBytes == 0) {
|
||||
return 0xFFFD;
|
||||
}
|
||||
unichar = byte & ~tops[numBytes];
|
||||
if (numBytes == 3) {
|
||||
return 0;
|
||||
}
|
||||
++numBytes;
|
||||
if (*length < numBytes) {
|
||||
*length = 0;
|
||||
return 0;
|
||||
return 0xFFFD;
|
||||
}
|
||||
size_t i;
|
||||
for (i = 0; i < numBytes; ++i) {
|
||||
for (i = 1; i < numBytes; ++i) {
|
||||
unichar <<= 6;
|
||||
byte = **unicode;
|
||||
--*length;
|
||||
|
@ -272,6 +285,54 @@ char* utf16to8(const uint16_t* utf16, size_t length) {
|
|||
return newUTF8;
|
||||
}
|
||||
|
||||
char* latin1ToUtf8(const char* latin1, size_t length) {
|
||||
char* utf8 = NULL;
|
||||
char* utf8Offset = NULL;
|
||||
size_t offset;
|
||||
char buffer[4];
|
||||
size_t utf8TotalBytes = 0;
|
||||
size_t utf8Length = 0;
|
||||
for (offset = 0; offset < length; ++offset) {
|
||||
if (length == 0) {
|
||||
break;
|
||||
}
|
||||
uint8_t unichar = latin1[offset];
|
||||
size_t bytes = toUtf8(unichar, buffer);
|
||||
utf8Length += bytes;
|
||||
if (!utf8) {
|
||||
utf8 = malloc(length);
|
||||
if (!utf8) {
|
||||
return NULL;
|
||||
}
|
||||
utf8TotalBytes = length;
|
||||
memcpy(utf8, buffer, bytes);
|
||||
utf8Offset = utf8 + bytes;
|
||||
} else if (utf8Length < utf8TotalBytes) {
|
||||
memcpy(utf8Offset, buffer, bytes);
|
||||
utf8Offset += bytes;
|
||||
} else if (utf8Length >= utf8TotalBytes) {
|
||||
ptrdiff_t o = utf8Offset - utf8;
|
||||
char* newUTF8 = realloc(utf8, utf8TotalBytes * 2);
|
||||
utf8Offset = o + newUTF8;
|
||||
if (!newUTF8) {
|
||||
free(utf8);
|
||||
return 0;
|
||||
}
|
||||
utf8 = newUTF8;
|
||||
memcpy(utf8Offset, buffer, bytes);
|
||||
utf8Offset += bytes;
|
||||
}
|
||||
}
|
||||
|
||||
char* newUTF8 = realloc(utf8, utf8Length + 1);
|
||||
if (!newUTF8) {
|
||||
free(utf8);
|
||||
return 0;
|
||||
}
|
||||
newUTF8[utf8Length] = '\0';
|
||||
return newUTF8;
|
||||
}
|
||||
|
||||
extern const uint16_t gbkUnicodeTable[];
|
||||
|
||||
char* gbkToUtf8(const char* gbk, size_t length) {
|
||||
|
@ -341,6 +402,29 @@ char* gbkToUtf8(const char* gbk, size_t length) {
|
|||
return newUTF8;
|
||||
}
|
||||
|
||||
size_t utf8strlen(const char* string) {
|
||||
size_t size = 0;
|
||||
for (size = 0; *string; ++size) {
|
||||
size_t numBytes = 1;
|
||||
if (*string & 0x80) {
|
||||
numBytes = _utf8len[((uint8_t) *string) >> 2];
|
||||
if (!numBytes) {
|
||||
numBytes = 1;
|
||||
} else {
|
||||
size_t i;
|
||||
for (i = 1; i < numBytes; ++i) {
|
||||
if ((string[i] & 0xC0) != 0x80) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
numBytes = i;
|
||||
}
|
||||
}
|
||||
string += numBytes;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
int hexDigit(char digit) {
|
||||
switch (digit) {
|
||||
case '0':
|
||||
|
|
|
@ -0,0 +1,132 @@
|
|||
/* Copyright (c) 2013-2022 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#include "util/test/suite.h"
|
||||
|
||||
#include <mgba-util/string.h>
|
||||
|
||||
M_TEST_DEFINE(strlenASCII) {
|
||||
assert_int_equal(utf8strlen(""), 0);
|
||||
assert_int_equal(utf8strlen("a"), 1);
|
||||
assert_int_equal(utf8strlen("aa"), 2);
|
||||
assert_int_equal(utf8strlen("aaa"), 3);
|
||||
}
|
||||
|
||||
M_TEST_DEFINE(strlenMultibyte) {
|
||||
assert_int_equal(utf8strlen("\300\200"), 1);
|
||||
assert_int_equal(utf8strlen("a\300\200"), 2);
|
||||
assert_int_equal(utf8strlen("\300\200a"), 2);
|
||||
assert_int_equal(utf8strlen("a\300\200a"), 3);
|
||||
|
||||
assert_int_equal(utf8strlen("\300\200\300\200"), 2);
|
||||
assert_int_equal(utf8strlen("a\300\200\300\200"), 3);
|
||||
assert_int_equal(utf8strlen("\300\200a\300\200"), 3);
|
||||
assert_int_equal(utf8strlen("\300\200\300\200a"), 3);
|
||||
|
||||
assert_int_equal(utf8strlen("\340\200\200"), 1);
|
||||
assert_int_equal(utf8strlen("a\340\200\200"), 2);
|
||||
assert_int_equal(utf8strlen("\340\200\200a"), 2);
|
||||
assert_int_equal(utf8strlen("a\340\200\200a"), 3);
|
||||
|
||||
assert_int_equal(utf8strlen("\340\200\200\340\200\200"), 2);
|
||||
assert_int_equal(utf8strlen("a\340\200\200\340\200\200"), 3);
|
||||
assert_int_equal(utf8strlen("\340\200\200a\340\200\200"), 3);
|
||||
assert_int_equal(utf8strlen("\340\200\200\340\200\200a"), 3);
|
||||
|
||||
assert_int_equal(utf8strlen("\340\200\200\300\200"), 2);
|
||||
assert_int_equal(utf8strlen("\300\200\340\200\200"), 2);
|
||||
|
||||
assert_int_equal(utf8strlen("\360\200\200\200"), 1);
|
||||
assert_int_equal(utf8strlen("a\360\200\200\200"), 2);
|
||||
assert_int_equal(utf8strlen("\360\200\200\200a"), 2);
|
||||
assert_int_equal(utf8strlen("a\360\200\200\200a"), 3);
|
||||
|
||||
assert_int_equal(utf8strlen("\360\200\200\200\360\200\200\200"), 2);
|
||||
assert_int_equal(utf8strlen("a\360\200\200\200\360\200\200\200"), 3);
|
||||
assert_int_equal(utf8strlen("\360\200\200\200a\360\200\200\200"), 3);
|
||||
assert_int_equal(utf8strlen("\360\200\200\200\360\200\200\200a"), 3);
|
||||
|
||||
assert_int_equal(utf8strlen("\360\200\200\200\300\200"), 2);
|
||||
assert_int_equal(utf8strlen("\300\200\360\200\200\200"), 2);
|
||||
|
||||
assert_int_equal(utf8strlen("\360\200\200\200\340\200\200"), 2);
|
||||
assert_int_equal(utf8strlen("\340\200\200\360\200\200\200"), 2);
|
||||
}
|
||||
|
||||
M_TEST_DEFINE(strlenDegenerate) {
|
||||
assert_int_equal(utf8strlen("\200"), 1);
|
||||
assert_int_equal(utf8strlen("\200a"), 2);
|
||||
|
||||
assert_int_equal(utf8strlen("\300"), 1);
|
||||
assert_int_equal(utf8strlen("\300a"), 2);
|
||||
|
||||
assert_int_equal(utf8strlen("\300\300"), 2);
|
||||
assert_int_equal(utf8strlen("\300\300a"), 3);
|
||||
assert_int_equal(utf8strlen("\300\300\200"), 2);
|
||||
|
||||
assert_int_equal(utf8strlen("\300\200\200"), 2);
|
||||
assert_int_equal(utf8strlen("\300\200\200a"), 3);
|
||||
|
||||
assert_int_equal(utf8strlen("\340"), 1);
|
||||
assert_int_equal(utf8strlen("\340a"), 2);
|
||||
assert_int_equal(utf8strlen("\340\300"), 2);
|
||||
assert_int_equal(utf8strlen("\340\300a"), 3);
|
||||
assert_int_equal(utf8strlen("\340\300\200"), 2);
|
||||
assert_int_equal(utf8strlen("\340\200"), 1);
|
||||
assert_int_equal(utf8strlen("\340\200a"), 2);
|
||||
assert_int_equal(utf8strlen("\340\200\200\200"), 2);
|
||||
assert_int_equal(utf8strlen("\340\200\200\200a"), 3);
|
||||
|
||||
assert_int_equal(utf8strlen("\360"), 1);
|
||||
assert_int_equal(utf8strlen("\360a"), 2);
|
||||
assert_int_equal(utf8strlen("\360\300"), 2);
|
||||
assert_int_equal(utf8strlen("\360\300a"), 3);
|
||||
assert_int_equal(utf8strlen("\360\300\200"), 2);
|
||||
assert_int_equal(utf8strlen("\360\200"), 1);
|
||||
assert_int_equal(utf8strlen("\360\200a"), 2);
|
||||
assert_int_equal(utf8strlen("\360\200\300"), 2);
|
||||
assert_int_equal(utf8strlen("\360\200\300a"), 3);
|
||||
assert_int_equal(utf8strlen("\360\200\300\200"), 2);
|
||||
assert_int_equal(utf8strlen("\360\200\200"), 1);
|
||||
assert_int_equal(utf8strlen("\360\200\200a"), 2);
|
||||
|
||||
assert_int_equal(utf8strlen("\370"), 1);
|
||||
assert_int_equal(utf8strlen("\370a"), 2);
|
||||
assert_int_equal(utf8strlen("\370\200"), 2);
|
||||
assert_int_equal(utf8strlen("\370\200a"), 3);
|
||||
assert_int_equal(utf8strlen("\374"), 1);
|
||||
assert_int_equal(utf8strlen("\374a"), 2);
|
||||
assert_int_equal(utf8strlen("\374\200"), 2);
|
||||
assert_int_equal(utf8strlen("\374\200a"), 3);
|
||||
assert_int_equal(utf8strlen("\376"), 1);
|
||||
assert_int_equal(utf8strlen("\376a"), 2);
|
||||
assert_int_equal(utf8strlen("\376\200"), 2);
|
||||
assert_int_equal(utf8strlen("\376\200a"), 3);
|
||||
assert_int_equal(utf8strlen("\377"), 1);
|
||||
assert_int_equal(utf8strlen("\377a"), 2);
|
||||
assert_int_equal(utf8strlen("\377\200"), 2);
|
||||
assert_int_equal(utf8strlen("\377\200a"), 3);
|
||||
}
|
||||
|
||||
M_TEST_DEFINE(roundtrip) {
|
||||
uint32_t unichar;
|
||||
char buf[8] = {0};
|
||||
for (unichar = 0; unichar < 0x110000; ++unichar) {
|
||||
memset(buf, 0, sizeof(buf));
|
||||
size_t len = toUtf8(unichar, buf) + 1;
|
||||
const char* ptr = buf;
|
||||
assert_true(len);
|
||||
assert_false(buf[len]);
|
||||
assert_int_equal(utf8Char(&ptr, &len), unichar);
|
||||
assert_int_equal(len, 1);
|
||||
}
|
||||
}
|
||||
|
||||
M_TEST_SUITE_DEFINE(StringUTF8,
|
||||
cmocka_unit_test(strlenASCII),
|
||||
cmocka_unit_test(strlenMultibyte),
|
||||
cmocka_unit_test(strlenDegenerate),
|
||||
cmocka_unit_test(roundtrip),
|
||||
)
|
Loading…
Reference in New Issue