diff --git a/CHANGES b/CHANGES index b522ce84d..16c2ac409 100644 --- a/CHANGES +++ b/CHANGES @@ -44,6 +44,8 @@ Bugfixes: - SDL: Fix SDL build when OpenGL is missing - ARM7: Fix timing of multiplies to use N cycles - GBA: Fix calls to endian-independent loadstores + - GBA Video: Fix windows not affecting sprites + - VFS: Fix line-reading to return proper values Misc: - Qt: Handle saving input settings better - Debugger: Free watchpoints in addition to breakpoints @@ -73,6 +75,7 @@ Misc: - All: Threads are now named - Qt: Rename "Fullscreen" to "Toggle fullscreen" - Qt: Don't save window size when entering fullscreen + - Qt: Make the default fullscreen binding for Windows be Alt-Enter 0.2.1: (2015-05-13) Bugfixes: diff --git a/src/gba/renderers/video-software.c b/src/gba/renderers/video-software.c index 06fe436c0..f7370f9f9 100644 --- a/src/gba/renderers/video-software.c +++ b/src/gba/renderers/video-software.c @@ -1883,6 +1883,9 @@ static void _postprocessSprite(struct GBAVideoSoftwareRenderer* renderer, unsign if (objwinSlowPath) { objwinDisable = !GBAWindowControlIsObjEnable(renderer->objwin.packed); objwinOnly = !objwinDisable && !GBAWindowControlIsObjEnable(renderer->currentWindow.packed); + if (objwinDisable && !GBAWindowControlIsObjEnable(renderer->currentWindow.packed)) { + return; + } if (objwinDisable) { for (x = renderer->start; x < renderer->end; ++x, ++pixel) { @@ -1912,6 +1915,8 @@ static void _postprocessSprite(struct GBAVideoSoftwareRenderer* renderer, unsign } return; } + } else if (!GBAWindowControlIsObjEnable(renderer->currentWindow.packed)) { + return; } for (x = renderer->start; x < renderer->end; ++x, ++pixel) { uint32_t color = renderer->spriteLayer[x] & ~FLAG_OBJWIN; diff --git a/src/gba/supervisor/config.c b/src/gba/supervisor/config.c index a3e701c56..4c50653f8 100644 --- a/src/gba/supervisor/config.c +++ b/src/gba/supervisor/config.c @@ -6,6 +6,7 @@ #include "config.h" #include "util/formatting.h" +#include "util/string.h" #include "util/vfs.h" #include diff --git a/src/platform/commandline.c b/src/platform/commandline.c index 21591983c..3502df37c 100644 --- a/src/platform/commandline.c +++ b/src/platform/commandline.c @@ -17,6 +17,7 @@ #endif #include "gba/video.h" +#include "util/string.h" #include #include diff --git a/src/platform/imagemagick/imagemagick-gif-encoder.c b/src/platform/imagemagick/imagemagick-gif-encoder.c index e47451d00..ef1f741c7 100644 --- a/src/platform/imagemagick/imagemagick-gif-encoder.c +++ b/src/platform/imagemagick/imagemagick-gif-encoder.c @@ -6,6 +6,7 @@ #include "imagemagick-gif-encoder.h" #include "gba/video.h" +#include "util/string.h" static void _magickPostVideoFrame(struct GBAAVStream*, struct GBAVideoRenderer* renderer); static void _magickPostAudioFrame(struct GBAAVStream*, int16_t left, int16_t right); diff --git a/src/platform/perf-main.c b/src/platform/perf-main.c index 80aa60211..564765314 100644 --- a/src/platform/perf-main.c +++ b/src/platform/perf-main.c @@ -10,6 +10,7 @@ #include "gba/serialize.h" #include "platform/commandline.h" +#include "util/string.h" #include "util/vfs.h" #include diff --git a/src/platform/posix/threading.h b/src/platform/posix/threading.h new file mode 100644 index 000000000..7ca05ce15 --- /dev/null +++ b/src/platform/posix/threading.h @@ -0,0 +1,90 @@ +/* Copyright (c) 2013-2015 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/. */ +#ifndef POSIX_THREADING_H +#define POSIX_THREADING_H + +#include "util/common.h" + +#include +#include +#ifdef __FreeBSD__ +#include +#endif + +#define THREAD_ENTRY void* +typedef THREAD_ENTRY (*ThreadEntry)(void*); + +typedef pthread_t Thread; +typedef pthread_mutex_t Mutex; +typedef pthread_cond_t Condition; + +static inline int MutexInit(Mutex* mutex) { + return pthread_mutex_init(mutex, 0); +} + +static inline int MutexDeinit(Mutex* mutex) { + return pthread_mutex_destroy(mutex); +} + +static inline int MutexLock(Mutex* mutex) { + return pthread_mutex_lock(mutex); +} + +static inline int MutexUnlock(Mutex* mutex) { + return pthread_mutex_unlock(mutex); +} + +static inline int ConditionInit(Condition* cond) { + return pthread_cond_init(cond, 0); +} + +static inline int ConditionDeinit(Condition* cond) { + return pthread_cond_destroy(cond); +} + +static inline int ConditionWait(Condition* cond, Mutex* mutex) { + return pthread_cond_wait(cond, mutex); +} + +static inline int ConditionWaitTimed(Condition* cond, Mutex* mutex, int32_t timeoutMs) { + struct timespec ts; + struct timeval tv; + + gettimeofday(&tv, 0); + ts.tv_sec = tv.tv_sec; + ts.tv_nsec = (tv.tv_usec + timeoutMs * 1000L) * 1000L; + if (ts.tv_nsec >= 1000000000L) { + ts.tv_nsec -= 1000000000L; + ++ts.tv_sec; + } + + return pthread_cond_timedwait(cond, mutex, &ts); +} + +static inline int ConditionWake(Condition* cond) { + return pthread_cond_broadcast(cond); +} + +static inline int ThreadCreate(Thread* thread, ThreadEntry entry, void* context) { + return pthread_create(thread, 0, entry, context); +} + +static inline int ThreadJoin(Thread thread) { + return pthread_join(thread, 0); +} + +static inline int ThreadSetName(const char* name) { +#ifdef __APPLE__ + return pthread_setname_np(name); +#elif defined(__FreeBSD__) + pthread_set_name_np(pthread_self(), name); + return 0; +#else + return pthread_setname_np(pthread_self(), name); +#endif +} + +#endif diff --git a/src/platform/qt/Window.cpp b/src/platform/qt/Window.cpp index 536e7f4ac..c533c786e 100644 --- a/src/platform/qt/Window.cpp +++ b/src/platform/qt/Window.cpp @@ -826,7 +826,13 @@ void Window::setupMenu(QMenuBar* menubar) { }); addControlledAction(frameMenu, setSize, QString("frame%1x").arg(QString::number(i))); } - addControlledAction(frameMenu, frameMenu->addAction(tr("Toggle fullscreen"), this, SLOT(toggleFullScreen()), QKeySequence("Ctrl+F")), "fullscreen"); + QKeySequence fullscreenKeys; +#ifdef Q_OS_WIN + fullscreenKeys = QKeySequence("Alt+Enter"); +#else + fullscreenKeys = QKeySequence("Ctrl+F"); +#endif + addControlledAction(frameMenu, frameMenu->addAction(tr("Toggle fullscreen"), this, SLOT(toggleFullScreen()), fullscreenKeys), "fullscreen"); ConfigOption* lockAspectRatio = m_config->addOption("lockAspectRatio"); lockAspectRatio->addBoolean(tr("Lock aspect ratio"), avMenu); diff --git a/src/platform/windows/threading.h b/src/platform/windows/threading.h new file mode 100644 index 000000000..21d5c1971 --- /dev/null +++ b/src/platform/windows/threading.h @@ -0,0 +1,84 @@ +/* Copyright (c) 2013-2015 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/. */ +#ifndef WINDOWS_THREADING_H +#define WINDOWS_THREADING_H + +#include "util/common.h" + +#define _WIN32_WINNT 0x0600 +#include +#define THREAD_ENTRY DWORD WINAPI +typedef THREAD_ENTRY ThreadEntry(LPVOID); + +typedef HANDLE Thread; +typedef CRITICAL_SECTION Mutex; +typedef CONDITION_VARIABLE Condition; + +static inline int MutexInit(Mutex* mutex) { + InitializeCriticalSection(mutex); + return GetLastError(); +} + +static inline int MutexDeinit(Mutex* mutex) { + DeleteCriticalSection(mutex); + return GetLastError(); +} + +static inline int MutexLock(Mutex* mutex) { + EnterCriticalSection(mutex); + return GetLastError(); +} + +static inline int MutexUnlock(Mutex* mutex) { + LeaveCriticalSection(mutex); + return GetLastError(); +} + +static inline int ConditionInit(Condition* cond) { + InitializeConditionVariable(cond); + return GetLastError(); +} + +static inline int ConditionDeinit(Condition* cond) { + // This is a no-op on Windows + UNUSED(cond); + return 0; +} + +static inline int ConditionWait(Condition* cond, Mutex* mutex) { + SleepConditionVariableCS(cond, mutex, INFINITE); + return GetLastError(); +} + +static inline int ConditionWaitTimed(Condition* cond, Mutex* mutex, int32_t timeoutMs) { + SleepConditionVariableCS(cond, mutex, timeoutMs); + return GetLastError(); +} + +static inline int ConditionWake(Condition* cond) { + WakeAllConditionVariable(cond); + return GetLastError(); +} + +static inline int ThreadCreate(Thread* thread, ThreadEntry entry, void* context) { + *thread = CreateThread(NULL, 0, entry, context, 0, 0); + return GetLastError(); +} + +static inline int ThreadJoin(Thread thread) { + DWORD error = WaitForSingleObject(thread, INFINITE); + if (error == WAIT_FAILED) { + return GetLastError(); + } + return 0; +} + +static inline int ThreadSetName(const char* name) { + UNUSED(name); + return -1; +} + +#endif diff --git a/src/util/common.h b/src/util/common.h index 5fe0a9644..2a539c48b 100644 --- a/src/util/common.h +++ b/src/util/common.h @@ -19,16 +19,12 @@ #include #include +#include "version.h" + #ifdef _MSC_VER -#ifdef _WIN64 -typedef int64_t off_t; -typedef int64_t ssize_t; -#else -typedef int32_t off_t; -typedef int32_t ssize_t; -#endif +typedef intptr_t off_t; +typedef intptr_t ssize_t; #define restrict __restrict -#define SSIZE_MAX ((ssize_t) SIZE_MAX) #define strcasecmp _stricmp #define strncasecmp _strnicmp #define ftruncate _chsize @@ -40,7 +36,9 @@ typedef int32_t ssize_t; #include #endif -#include "version.h" +#ifndef SSIZE_MAX +#define SSIZE_MAX ((ssize_t) (SIZE_MAX >> 1)) +#endif #define UNUSED(V) (void)(V) diff --git a/src/util/configuration.c b/src/util/configuration.c index d9ccdac41..dd4efbb51 100644 --- a/src/util/configuration.c +++ b/src/util/configuration.c @@ -6,6 +6,7 @@ #include "configuration.h" #include "util/formatting.h" +#include "util/string.h" #include "util/vfs.h" #include "third-party/inih/ini.h" diff --git a/src/util/table.c b/src/util/table.c index 21a86fed4..9b0f62905 100644 --- a/src/util/table.c +++ b/src/util/table.c @@ -6,6 +6,7 @@ #include "table.h" #include "util/hash.h" +#include "util/string.h" #define LIST_INITIAL_SIZE 8 #define TABLE_INITIAL_SIZE 8 diff --git a/src/util/threading.h b/src/util/threading.h index 3aa9323fa..b65708720 100644 --- a/src/util/threading.h +++ b/src/util/threading.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2014 Jeffrey Pfau +/* Copyright (c) 2013-2015 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 @@ -10,158 +10,9 @@ #ifndef DISABLE_THREADING #ifdef USE_PTHREADS -#include -#include -#ifdef __FreeBSD__ -#include -#endif - -#define THREAD_ENTRY void* -typedef THREAD_ENTRY (*ThreadEntry)(void*); - -typedef pthread_t Thread; -typedef pthread_mutex_t Mutex; -typedef pthread_cond_t Condition; - -static inline int MutexInit(Mutex* mutex) { - return pthread_mutex_init(mutex, 0); -} - -static inline int MutexDeinit(Mutex* mutex) { - return pthread_mutex_destroy(mutex); -} - -static inline int MutexLock(Mutex* mutex) { - return pthread_mutex_lock(mutex); -} - -static inline int MutexUnlock(Mutex* mutex) { - return pthread_mutex_unlock(mutex); -} - -static inline int ConditionInit(Condition* cond) { - return pthread_cond_init(cond, 0); -} - -static inline int ConditionDeinit(Condition* cond) { - return pthread_cond_destroy(cond); -} - -static inline int ConditionWait(Condition* cond, Mutex* mutex) { - return pthread_cond_wait(cond, mutex); -} - -static inline int ConditionWaitTimed(Condition* cond, Mutex* mutex, int32_t timeoutMs) { - struct timespec ts; - struct timeval tv; - - gettimeofday(&tv, 0); - ts.tv_sec = tv.tv_sec; - ts.tv_nsec = (tv.tv_usec + timeoutMs * 1000L) * 1000L; - if (ts.tv_nsec >= 1000000000L) { - ts.tv_nsec -= 1000000000L; - ++ts.tv_sec; - } - - return pthread_cond_timedwait(cond, mutex, &ts); -} - -static inline int ConditionWake(Condition* cond) { - return pthread_cond_broadcast(cond); -} - -static inline int ThreadCreate(Thread* thread, ThreadEntry entry, void* context) { - return pthread_create(thread, 0, entry, context); -} - -static inline int ThreadJoin(Thread thread) { - return pthread_join(thread, 0); -} - -static inline int ThreadSetName(const char* name) { -#ifdef __APPLE__ - return pthread_setname_np(name); -#elif defined(__FreeBSD__) - pthread_set_name_np(pthread_self(), name); - return 0; -#else - return pthread_setname_np(pthread_self(), name); -#endif -} - +#include "platform/posix/threading.h" #elif _WIN32 -#define _WIN32_WINNT 0x0600 -#include -#define THREAD_ENTRY DWORD WINAPI -typedef THREAD_ENTRY ThreadEntry(LPVOID); - -typedef HANDLE Thread; -typedef CRITICAL_SECTION Mutex; -typedef CONDITION_VARIABLE Condition; - -static inline int MutexInit(Mutex* mutex) { - InitializeCriticalSection(mutex); - return GetLastError(); -} - -static inline int MutexDeinit(Mutex* mutex) { - DeleteCriticalSection(mutex); - return GetLastError(); -} - -static inline int MutexLock(Mutex* mutex) { - EnterCriticalSection(mutex); - return GetLastError(); -} - -static inline int MutexUnlock(Mutex* mutex) { - LeaveCriticalSection(mutex); - return GetLastError(); -} - -static inline int ConditionInit(Condition* cond) { - InitializeConditionVariable(cond); - return GetLastError(); -} - -static inline int ConditionDeinit(Condition* cond) { - // This is a no-op on Windows - UNUSED(cond); - return 0; -} - -static inline int ConditionWait(Condition* cond, Mutex* mutex) { - SleepConditionVariableCS(cond, mutex, INFINITE); - return GetLastError(); -} - -static inline int ConditionWaitTimed(Condition* cond, Mutex* mutex, int32_t timeoutMs) { - SleepConditionVariableCS(cond, mutex, timeoutMs); - return GetLastError(); -} - -static inline int ConditionWake(Condition* cond) { - WakeAllConditionVariable(cond); - return GetLastError(); -} - -static inline int ThreadCreate(Thread* thread, ThreadEntry entry, void* context) { - *thread = CreateThread(NULL, 0, entry, context, 0, 0); - return GetLastError(); -} - -static inline int ThreadJoin(Thread thread) { - DWORD error = WaitForSingleObject(thread, INFINITE); - if (error == WAIT_FAILED) { - return GetLastError(); - } - return 0; -} - -static inline int ThreadSetName(const char* name) { - UNUSED(name); - return -1; -} +#include "platform/windows/threading.h" #else #define DISABLE_THREADING #endif diff --git a/src/util/vfs.c b/src/util/vfs.c index 14492788c..36e59f617 100644 --- a/src/util/vfs.c +++ b/src/util/vfs.c @@ -6,43 +6,19 @@ #include "vfs.h" ssize_t VFileReadline(struct VFile* vf, char* buffer, size_t size) { - size_t bytesRead = 0; + ssize_t bytesRead = 0; while (bytesRead < size - 1) { - size_t newRead = vf->read(vf, &buffer[bytesRead], 1); + ssize_t newRead = vf->read(vf, &buffer[bytesRead], 1); + if (newRead <= 0) { + break; + } bytesRead += newRead; - if (!newRead || buffer[bytesRead] == '\n') { + if (buffer[bytesRead] == '\n') { break; } } - return buffer[bytesRead] = '\0'; -} - -struct VFile* VDirOptionalOpenFile(struct VDir* dir, const char* realPath, const char* prefix, const char* suffix, int mode) { - char path[PATH_MAX]; - path[PATH_MAX - 1] = '\0'; - struct VFile* vf; - if (!dir) { - if (!realPath) { - return 0; - } - char* dotPoint = strrchr(realPath, '.'); - if (dotPoint - realPath + 1 >= PATH_MAX - 1) { - return 0; - } - if (dotPoint > strrchr(realPath, '/')) { - int len = dotPoint - realPath; - strncpy(path, realPath, len); - path[len] = 0; - strncat(path + len, suffix, PATH_MAX - len - 1); - } else { - snprintf(path, PATH_MAX - 1, "%s%s", realPath, suffix); - } - vf = VFileOpen(path, mode); - } else { - snprintf(path, PATH_MAX - 1, "%s%s", prefix, suffix); - vf = dir->openFile(dir, path, mode); - } - return vf; + buffer[bytesRead] = '\0'; + return bytesRead; } ssize_t VFileWrite32LE(struct VFile* vf, int32_t word) { diff --git a/src/util/vfs/vfs-dirent.c b/src/util/vfs/vfs-dirent.c index 9632a7e3a..ae786ed0b 100644 --- a/src/util/vfs/vfs-dirent.c +++ b/src/util/vfs/vfs-dirent.c @@ -190,3 +190,31 @@ const char* _vdeName(struct VDirEntry* vde) { } return 0; } + +struct VFile* VDirOptionalOpenFile(struct VDir* dir, const char* realPath, const char* prefix, const char* suffix, int mode) { + char path[PATH_MAX]; + path[PATH_MAX - 1] = '\0'; + struct VFile* vf; + if (!dir) { + if (!realPath) { + return 0; + } + char* dotPoint = strrchr(realPath, '.'); + if (dotPoint - realPath + 1 >= PATH_MAX - 1) { + return 0; + } + if (dotPoint > strrchr(realPath, '/')) { + int len = dotPoint - realPath; + strncpy(path, realPath, len); + path[len] = 0; + strncat(path + len, suffix, PATH_MAX - len - 1); + } else { + snprintf(path, PATH_MAX - 1, "%s%s", realPath, suffix); + } + vf = VFileOpen(path, mode); + } else { + snprintf(path, PATH_MAX - 1, "%s%s", prefix, suffix); + vf = dir->openFile(dir, path, mode); + } + return vf; +}