diff --git a/binding/input-binding.cpp b/binding/input-binding.cpp index 892c187..3fff6c5 100644 --- a/binding/input-binding.cpp +++ b/binding/input-binding.cpp @@ -20,11 +20,13 @@ */ #include "binding-util.h" -#include "exception.h" -#include "input.h" +#include "util/exception.h" +#include "input/input.h" #include "sharedstate.h" #include "src/util/util.h" +#include "eventthread.h" + #include #include @@ -323,10 +325,10 @@ RB_METHOD(inputSetMode) { RB_METHOD(inputGets) { RB_UNUSED_PARAM; - + shState->eThread().lockText(true); VALUE ret = rb_utf8_str_new_cstr(shState->input().getText()); shState->input().clearText(); - + shState->eThread().lockText(false); return ret; } diff --git a/src/eventthread.cpp b/src/eventthread.cpp index 09fec70..295c60c 100644 --- a/src/eventthread.cpp +++ b/src/eventthread.cpp @@ -1,23 +1,23 @@ /* -** eventthread.cpp -** -** This file is part of mkxp. -** -** Copyright (C) 2013 Jonas Kulla -** -** mkxp 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 of the License, or -** (at your option) any later version. -** -** mkxp 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 mkxp. If not, see . -*/ + ** eventthread.cpp + ** + ** This file is part of mkxp. + ** + ** Copyright (C) 2013 Jonas Kulla + ** + ** mkxp 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 of the License, or + ** (at your option) any later version. + ** + ** mkxp 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 mkxp. If not, see . + */ #include "eventthread.h" @@ -52,26 +52,26 @@ typedef void (ALC_APIENTRY *LPALCDEVICEPAUSESOFT) (ALCdevice *device); typedef void (ALC_APIENTRY *LPALCDEVICERESUMESOFT) (ALCdevice *device); #define AL_DEVICE_PAUSE_FUN \ - AL_FUN(DevicePause, LPALCDEVICEPAUSESOFT) \ - AL_FUN(DeviceResume, LPALCDEVICERESUMESOFT) +AL_FUN(DevicePause, LPALCDEVICEPAUSESOFT) \ +AL_FUN(DeviceResume, LPALCDEVICERESUMESOFT) struct ALCFunctions { #define AL_FUN(name, type) type name; - AL_DEVICE_PAUSE_FUN + AL_DEVICE_PAUSE_FUN #undef AL_FUN } static alc; static void initALCFunctions(ALCdevice *alcDev) { - if (!strstr(alcGetString(alcDev, ALC_EXTENSIONS), "ALC_SOFT_pause_device")) - return; - - Debug() << "ALC_SOFT_pause_device present"; - + if (!strstr(alcGetString(alcDev, ALC_EXTENSIONS), "ALC_SOFT_pause_device")) + return; + + Debug() << "ALC_SOFT_pause_device present"; + #define AL_FUN(name, type) alc. name = (type) alcGetProcAddress(alcDev, "alc" #name "SOFT"); - AL_DEVICE_PAUSE_FUN; + AL_DEVICE_PAUSE_FUN; #undef AL_FUN } @@ -85,578 +85,592 @@ EventThread::TouchState EventThread::touchState; /* User event codes */ enum { - REQUEST_SETFULLSCREEN = 0, - REQUEST_WINRESIZE, + REQUEST_SETFULLSCREEN = 0, + REQUEST_WINRESIZE, REQUEST_WINREPOSITION, REQUEST_WINRENAME, REQUEST_WINCENTER, - REQUEST_MESSAGEBOX, - REQUEST_SETCURSORVISIBLE, + REQUEST_MESSAGEBOX, + REQUEST_SETCURSORVISIBLE, REQUEST_TEXTMODE, REQUEST_SETTINGS, - - UPDATE_FPS, - UPDATE_SCREEN_RECT, - - EVENT_COUNT + + UPDATE_FPS, + UPDATE_SCREEN_RECT, + + EVENT_COUNT }; static uint32_t usrIdStart; bool EventThread::allocUserEvents() { - usrIdStart = SDL_RegisterEvents(EVENT_COUNT); - - if (usrIdStart == (uint32_t) -1) - return false; - - return true; + usrIdStart = SDL_RegisterEvents(EVENT_COUNT); + + if (usrIdStart == (uint32_t) -1) + return false; + + return true; } EventThread::EventThread() - : js(0), - fullscreen(false), - showCursor(true), - joystickConnected(false) -{} +: js(0), +fullscreen(false), +showCursor(true), +joystickConnected(false) +{ + textInputLock = SDL_CreateMutex(); +} + +EventThread::~EventThread() +{ + SDL_DestroyMutex(textInputLock); +} void EventThread::process(RGSSThreadData &rtData) { - SDL_Event event; - SDL_Window *win = rtData.window; - UnidirMessage &windowSizeMsg = rtData.windowSizeMsg; - - initALCFunctions(rtData.alcDev); - - // XXX this function breaks input focus on OSX + SDL_Event event; + SDL_Window *win = rtData.window; + UnidirMessage &windowSizeMsg = rtData.windowSizeMsg; + + initALCFunctions(rtData.alcDev); + + // XXX this function breaks input focus on OSX #ifndef __MACOSX__ - SDL_SetEventFilter(eventFilter, &rtData); + SDL_SetEventFilter(eventFilter, &rtData); #endif - - fullscreen = rtData.config.fullscreen; - int toggleFSMod = rtData.config.anyAltToggleFS ? KMOD_ALT : KMOD_LALT; - - if (rtData.config.printFPS) - fps.sendUpdates.set(); - - bool displayingFPS = false; - - bool cursorInWindow = false; - /* Will be updated eventually */ - SDL_Rect gameScreen = { 0, 0, 0, 0 }; - - /* SDL doesn't send an initial FOCUS_GAINED event */ - bool windowFocused = true; - - bool terminate = false; - - if (SDL_NumJoysticks() > 0) - js = SDL_JoystickOpen(0); - - char buffer[128]; - - char pendingTitle[128]; - bool havePendingTitle = false; - - bool resetting = false; - - int winW, winH; - int i, rc; + + fullscreen = rtData.config.fullscreen; + int toggleFSMod = rtData.config.anyAltToggleFS ? KMOD_ALT : KMOD_LALT; + + if (rtData.config.printFPS) + fps.sendUpdates.set(); + + bool displayingFPS = false; + + bool cursorInWindow = false; + /* Will be updated eventually */ + SDL_Rect gameScreen = { 0, 0, 0, 0 }; + + /* SDL doesn't send an initial FOCUS_GAINED event */ + bool windowFocused = true; + + bool terminate = false; + + if (SDL_NumJoysticks() > 0) + js = SDL_JoystickOpen(0); + + char buffer[128]; + + char pendingTitle[128]; + bool havePendingTitle = false; + + bool resetting = false; + + int winW, winH; + int i, rc; SDL_DisplayMode dm = {0}; - - SDL_GetWindowSize(win, &winW, &winH); - + + SDL_GetWindowSize(win, &winW, &winH); + textInputBuffer.clear(); #ifndef MKXPZ_BUILD_XCODE - SettingsMenu *sMenu = 0; + SettingsMenu *sMenu = 0; #else // Will always be 0 void *sMenu = 0; #endif - - while (true) - { - if (!SDL_WaitEvent(&event)) - { - Debug() << "EventThread: Event error"; - break; - } -#ifndef MKXPZ_BUILD_XCODE - if (sMenu && sMenu->onEvent(event)) - { - if (sMenu->destroyReq()) - { - delete sMenu; - sMenu = 0; - - updateCursorState(cursorInWindow && windowFocused, gameScreen); - } - - continue; - } -#endif - - /* Preselect and discard unwanted events here */ - switch (event.type) - { - case SDL_MOUSEBUTTONDOWN : - case SDL_MOUSEBUTTONUP : - case SDL_MOUSEMOTION : - if (event.button.which == SDL_TOUCH_MOUSEID) - continue; - break; - - case SDL_FINGERDOWN : - case SDL_FINGERUP : - case SDL_FINGERMOTION : - if (event.tfinger.fingerId >= MAX_FINGERS) - continue; - break; - } - - /* Now process the rest */ - switch (event.type) - { - case SDL_WINDOWEVENT : - switch (event.window.event) - { - case SDL_WINDOWEVENT_SIZE_CHANGED : - winW = event.window.data1; - winH = event.window.data2; - - windowSizeMsg.post(Vec2i(winW, winH)); - resetInputStates(); - break; - - case SDL_WINDOWEVENT_ENTER : - cursorInWindow = true; - mouseState.inWindow = true; - updateCursorState(cursorInWindow && windowFocused && !sMenu, gameScreen); - - break; - - case SDL_WINDOWEVENT_LEAVE : - cursorInWindow = false; - mouseState.inWindow = false; - updateCursorState(cursorInWindow && windowFocused && !sMenu, gameScreen); - - break; - - case SDL_WINDOWEVENT_CLOSE : - terminate = true; - - break; - - case SDL_WINDOWEVENT_FOCUS_GAINED : - windowFocused = true; - updateCursorState(cursorInWindow && windowFocused && !sMenu, gameScreen); - - break; - - case SDL_WINDOWEVENT_FOCUS_LOST : - windowFocused = false; - updateCursorState(cursorInWindow && windowFocused && !sMenu, gameScreen); - resetInputStates(); - - break; - } - break; - - case SDL_TEXTINPUT : - if (textInputBuffer.size() < 512) - textInputBuffer += event.text.text; + + while (true) + { + if (!SDL_WaitEvent(&event)) + { + Debug() << "EventThread: Event error"; break; - - case SDL_QUIT : - terminate = true; - Debug() << "EventThread termination requested"; - - break; - - case SDL_KEYDOWN : - if (event.key.keysym.scancode == SDL_SCANCODE_RETURN && - (event.key.keysym.mod & toggleFSMod)) - { - setFullscreen(win, !fullscreen); - if (!fullscreen && havePendingTitle) - { - SDL_SetWindowTitle(win, pendingTitle); - pendingTitle[0] = '\0'; - havePendingTitle = false; - } - - break; - } - - if (event.key.keysym.scancode == SDL_SCANCODE_F1) - { + } #ifndef MKXPZ_BUILD_XCODE - if (!sMenu) - { - sMenu = new SettingsMenu(rtData); - updateCursorState(false, gameScreen); - } - - sMenu->raise(); -#else - openSettingsWindow(); + if (sMenu && sMenu->onEvent(event)) + { + if (sMenu->destroyReq()) + { + delete sMenu; + sMenu = 0; + + updateCursorState(cursorInWindow && windowFocused, gameScreen); + } + + continue; + } #endif - } - - if (event.key.keysym.scancode == SDL_SCANCODE_F2) - { - if (!displayingFPS) - { - - fps.sendUpdates.set(); - displayingFPS = true; - } - else - { - displayingFPS = false; - - if (!rtData.config.printFPS) - fps.sendUpdates.clear(); - - if (fullscreen) - { - /* Prevent fullscreen flicker */ - strncpy(pendingTitle, rtData.config.windowTitle.c_str(), - sizeof(pendingTitle)); - havePendingTitle = true; - - break; - } - - SDL_SetWindowTitle(win, rtData.config.windowTitle.c_str()); - } - - break; - } - - if (event.key.keysym.scancode == SDL_SCANCODE_F12) - { - if (!rtData.config.enableReset) - break; - - if (resetting) - break; - - resetting = true; - rtData.rqResetFinish.clear(); - rtData.rqReset.set(); - break; - } - - keyStates[event.key.keysym.scancode] = true; - break; - - case SDL_KEYUP : - if (event.key.keysym.scancode == SDL_SCANCODE_F12) - { - if (!rtData.config.enableReset) - break; - - resetting = false; - rtData.rqResetFinish.set(); - break; - } - - keyStates[event.key.keysym.scancode] = false; - break; - - case SDL_JOYBUTTONDOWN : - joyState.buttons[event.jbutton.button] = true; - break; - - case SDL_JOYBUTTONUP : - joyState.buttons[event.jbutton.button] = false; - break; - - case SDL_JOYHATMOTION : - joyState.hats[event.jhat.hat] = event.jhat.value; - break; - - case SDL_JOYAXISMOTION : - joyState.axes[event.jaxis.axis] = event.jaxis.value; - break; - - case SDL_JOYDEVICEADDED : - if (event.jdevice.which > 0) - break; - - js = SDL_JoystickOpen(0); - joystickConnected = true; - break; - - case SDL_JOYDEVICEREMOVED : - resetInputStates(); - joystickConnected = false; - break; - - case SDL_MOUSEBUTTONDOWN : - mouseState.buttons[event.button.button] = true; - break; - - case SDL_MOUSEBUTTONUP : - mouseState.buttons[event.button.button] = false; - break; - - case SDL_MOUSEMOTION : - mouseState.x = event.motion.x; - mouseState.y = event.motion.y; - updateCursorState(cursorInWindow, gameScreen); - break; - - case SDL_FINGERDOWN : - i = event.tfinger.fingerId; - touchState.fingers[i].down = true; - - case SDL_FINGERMOTION : - i = event.tfinger.fingerId; - touchState.fingers[i].x = event.tfinger.x * winW; - touchState.fingers[i].y = event.tfinger.y * winH; - break; - - case SDL_FINGERUP : - i = event.tfinger.fingerId; - memset(&touchState.fingers[i], 0, sizeof(touchState.fingers[0])); - break; - - default : - /* Handle user events */ - switch(event.type - usrIdStart) - { - case REQUEST_SETFULLSCREEN : - setFullscreen(win, static_cast(event.user.code)); - break; - - case REQUEST_WINRESIZE : - SDL_SetWindowSize(win, event.window.data1, event.window.data2); - break; - - case REQUEST_WINREPOSITION : - SDL_SetWindowPosition(win, event.window.data1, event.window.data2); + + /* Preselect and discard unwanted events here */ + switch (event.type) + { + case SDL_MOUSEBUTTONDOWN : + case SDL_MOUSEBUTTONUP : + case SDL_MOUSEMOTION : + if (event.button.which == SDL_TOUCH_MOUSEID) + continue; break; + + case SDL_FINGERDOWN : + case SDL_FINGERUP : + case SDL_FINGERMOTION : + if (event.tfinger.fingerId >= MAX_FINGERS) + continue; + break; + } + + /* Now process the rest */ + switch (event.type) + { + case SDL_WINDOWEVENT : + switch (event.window.event) + { + case SDL_WINDOWEVENT_SIZE_CHANGED : + winW = event.window.data1; + winH = event.window.data2; + + windowSizeMsg.post(Vec2i(winW, winH)); + resetInputStates(); + break; + + case SDL_WINDOWEVENT_ENTER : + cursorInWindow = true; + mouseState.inWindow = true; + updateCursorState(cursorInWindow && windowFocused && !sMenu, gameScreen); + + break; + + case SDL_WINDOWEVENT_LEAVE : + cursorInWindow = false; + mouseState.inWindow = false; + updateCursorState(cursorInWindow && windowFocused && !sMenu, gameScreen); + + break; + + case SDL_WINDOWEVENT_CLOSE : + terminate = true; + + break; + + case SDL_WINDOWEVENT_FOCUS_GAINED : + windowFocused = true; + updateCursorState(cursorInWindow && windowFocused && !sMenu, gameScreen); + + break; + + case SDL_WINDOWEVENT_FOCUS_LOST : + windowFocused = false; + updateCursorState(cursorInWindow && windowFocused && !sMenu, gameScreen); + resetInputStates(); + + break; + } + break; + + case SDL_TEXTINPUT : + lockText(true); + if (textInputBuffer.size() < 512) { + textInputBuffer += event.text.text; + } + lockText(false); + break; + + case SDL_QUIT : + terminate = true; + Debug() << "EventThread termination requested"; + + break; + + case SDL_KEYDOWN : + if (event.key.keysym.scancode == SDL_SCANCODE_RETURN && + (event.key.keysym.mod & toggleFSMod)) + { + setFullscreen(win, !fullscreen); + if (!fullscreen && havePendingTitle) + { + SDL_SetWindowTitle(win, pendingTitle); + pendingTitle[0] = '\0'; + havePendingTitle = false; + } - case REQUEST_WINCENTER : - rc = SDL_GetDesktopDisplayMode(SDL_GetWindowDisplayIndex(win), &dm); - if (!rc) - SDL_SetWindowPosition(win, - (dm.w / 2) - (winW / 2), - (dm.h / 2) - (winH / 2)); break; - - case REQUEST_WINRENAME : - rtData.config.windowTitle = (const char*)event.user.data1; - SDL_SetWindowTitle(win, rtData.config.windowTitle.c_str()); - break; - - case REQUEST_TEXTMODE : - if (event.user.code) - { - SDL_StartTextInput(); - textInputBuffer.clear(); - } - else - { - SDL_StopTextInput(); - textInputBuffer.clear(); - } - break; - - case REQUEST_MESSAGEBOX : - SDL_ShowSimpleMessageBox(event.user.code, - rtData.config.windowTitle.c_str(), - (const char*) event.user.data1, win); - free(event.user.data1); - msgBoxDone.set(); - break; - - case REQUEST_SETCURSORVISIBLE : - showCursor = event.user.code; - updateCursorState(cursorInWindow, gameScreen); - break; - - case REQUEST_SETTINGS : -#ifndef MKXPZ_BUILD_XCODE - if (!sMenu) - { - sMenu = new SettingsMenu(rtData); - updateCursorState(false, gameScreen); } - sMenu->raise(); + if (event.key.keysym.scancode == SDL_SCANCODE_F1) + { +#ifndef MKXPZ_BUILD_XCODE + if (!sMenu) + { + sMenu = new SettingsMenu(rtData); + updateCursorState(false, gameScreen); + } + + sMenu->raise(); #else - openSettingsWindow(); + openSettingsWindow(); #endif + } + + if (event.key.keysym.scancode == SDL_SCANCODE_F2) + { + if (!displayingFPS) + { + + fps.sendUpdates.set(); + displayingFPS = true; + } + else + { + displayingFPS = false; + + if (!rtData.config.printFPS) + fps.sendUpdates.clear(); + + if (fullscreen) + { + /* Prevent fullscreen flicker */ + strncpy(pendingTitle, rtData.config.windowTitle.c_str(), + sizeof(pendingTitle)); + havePendingTitle = true; + + break; + } + + SDL_SetWindowTitle(win, rtData.config.windowTitle.c_str()); + } + + break; + } + + if (event.key.keysym.scancode == SDL_SCANCODE_F12) + { + if (!rtData.config.enableReset) + break; + + if (resetting) + break; + + resetting = true; + rtData.rqResetFinish.clear(); + rtData.rqReset.set(); + break; + } + + keyStates[event.key.keysym.scancode] = true; break; - - case UPDATE_FPS : - if (rtData.config.printFPS) - Debug() << "FPS:" << event.user.code; - - if (!fps.sendUpdates) - break; - - snprintf(buffer, sizeof(buffer), "%s - %d FPS", - rtData.config.windowTitle.c_str(), event.user.code); - - /* Updating the window title in fullscreen - * mode seems to cause flickering */ - if (fullscreen) - { - strncpy(pendingTitle, buffer, sizeof(pendingTitle)); - havePendingTitle = true; - - break; - } - - SDL_SetWindowTitle(win, buffer); - break; - - case UPDATE_SCREEN_RECT : - gameScreen.x = event.user.windowID; - gameScreen.y = event.user.code; - gameScreen.w = reinterpret_cast(event.user.data1); - gameScreen.h = reinterpret_cast(event.user.data2); - updateCursorState(cursorInWindow, gameScreen); - - break; - } - } - - if (terminate) - break; - } - - /* Just in case */ - rtData.syncPoint.resumeThreads(); - - if (SDL_JoystickGetAttached(js)) - SDL_JoystickClose(js); - - delete sMenu; + + case SDL_KEYUP : + if (event.key.keysym.scancode == SDL_SCANCODE_F12) + { + if (!rtData.config.enableReset) + break; + + resetting = false; + rtData.rqResetFinish.set(); + break; + } + + keyStates[event.key.keysym.scancode] = false; + break; + + case SDL_JOYBUTTONDOWN : + joyState.buttons[event.jbutton.button] = true; + break; + + case SDL_JOYBUTTONUP : + joyState.buttons[event.jbutton.button] = false; + break; + + case SDL_JOYHATMOTION : + joyState.hats[event.jhat.hat] = event.jhat.value; + break; + + case SDL_JOYAXISMOTION : + joyState.axes[event.jaxis.axis] = event.jaxis.value; + break; + + case SDL_JOYDEVICEADDED : + if (event.jdevice.which > 0) + break; + + js = SDL_JoystickOpen(0); + joystickConnected = true; + break; + + case SDL_JOYDEVICEREMOVED : + resetInputStates(); + joystickConnected = false; + break; + + case SDL_MOUSEBUTTONDOWN : + mouseState.buttons[event.button.button] = true; + break; + + case SDL_MOUSEBUTTONUP : + mouseState.buttons[event.button.button] = false; + break; + + case SDL_MOUSEMOTION : + mouseState.x = event.motion.x; + mouseState.y = event.motion.y; + updateCursorState(cursorInWindow, gameScreen); + break; + + case SDL_FINGERDOWN : + i = event.tfinger.fingerId; + touchState.fingers[i].down = true; + + case SDL_FINGERMOTION : + i = event.tfinger.fingerId; + touchState.fingers[i].x = event.tfinger.x * winW; + touchState.fingers[i].y = event.tfinger.y * winH; + break; + + case SDL_FINGERUP : + i = event.tfinger.fingerId; + memset(&touchState.fingers[i], 0, sizeof(touchState.fingers[0])); + break; + + default : + /* Handle user events */ + switch(event.type - usrIdStart) + { + case REQUEST_SETFULLSCREEN : + setFullscreen(win, static_cast(event.user.code)); + break; + + case REQUEST_WINRESIZE : + SDL_SetWindowSize(win, event.window.data1, event.window.data2); + break; + + case REQUEST_WINREPOSITION : + SDL_SetWindowPosition(win, event.window.data1, event.window.data2); + break; + + case REQUEST_WINCENTER : + rc = SDL_GetDesktopDisplayMode(SDL_GetWindowDisplayIndex(win), &dm); + if (!rc) + SDL_SetWindowPosition(win, + (dm.w / 2) - (winW / 2), + (dm.h / 2) - (winH / 2)); + break; + + case REQUEST_WINRENAME : + rtData.config.windowTitle = (const char*)event.user.data1; + SDL_SetWindowTitle(win, rtData.config.windowTitle.c_str()); + break; + + case REQUEST_TEXTMODE : + if (event.user.code) + { + SDL_StartTextInput(); + lockText(true); + textInputBuffer.clear(); + lockText(false); + } + else + { + SDL_StopTextInput(); + lockText(true); + textInputBuffer.clear(); + lockText(false); + } + break; + + case REQUEST_MESSAGEBOX : + SDL_ShowSimpleMessageBox(event.user.code, + rtData.config.windowTitle.c_str(), + (const char*) event.user.data1, win); + free(event.user.data1); + msgBoxDone.set(); + break; + + case REQUEST_SETCURSORVISIBLE : + showCursor = event.user.code; + updateCursorState(cursorInWindow, gameScreen); + break; + + case REQUEST_SETTINGS : +#ifndef MKXPZ_BUILD_XCODE + if (!sMenu) + { + sMenu = new SettingsMenu(rtData); + updateCursorState(false, gameScreen); + } + + sMenu->raise(); +#else + openSettingsWindow(); +#endif + break; + + case UPDATE_FPS : + if (rtData.config.printFPS) + Debug() << "FPS:" << event.user.code; + + if (!fps.sendUpdates) + break; + + snprintf(buffer, sizeof(buffer), "%s - %d FPS", + rtData.config.windowTitle.c_str(), event.user.code); + + /* Updating the window title in fullscreen + * mode seems to cause flickering */ + if (fullscreen) + { + strncpy(pendingTitle, buffer, sizeof(pendingTitle)); + havePendingTitle = true; + + break; + } + + SDL_SetWindowTitle(win, buffer); + break; + + case UPDATE_SCREEN_RECT : + gameScreen.x = event.user.windowID; + gameScreen.y = event.user.code; + gameScreen.w = reinterpret_cast(event.user.data1); + gameScreen.h = reinterpret_cast(event.user.data2); + updateCursorState(cursorInWindow, gameScreen); + + break; + } + } + + if (terminate) + break; + } + + /* Just in case */ + rtData.syncPoint.resumeThreads(); + + if (SDL_JoystickGetAttached(js)) + SDL_JoystickClose(js); + + delete sMenu; } int EventThread::eventFilter(void *data, SDL_Event *event) { - RGSSThreadData &rtData = *static_cast(data); - - switch (event->type) - { - case SDL_APP_WILLENTERBACKGROUND : - Debug() << "SDL_APP_WILLENTERBACKGROUND"; - - if (HAVE_ALC_DEVICE_PAUSE) - alc.DevicePause(rtData.alcDev); - - rtData.syncPoint.haltThreads(); - - return 0; - - case SDL_APP_DIDENTERBACKGROUND : - Debug() << "SDL_APP_DIDENTERBACKGROUND"; - return 0; - - case SDL_APP_WILLENTERFOREGROUND : - Debug() << "SDL_APP_WILLENTERFOREGROUND"; - return 0; - - case SDL_APP_DIDENTERFOREGROUND : - Debug() << "SDL_APP_DIDENTERFOREGROUND"; - - if (HAVE_ALC_DEVICE_PAUSE) - alc.DeviceResume(rtData.alcDev); - - rtData.syncPoint.resumeThreads(); - - return 0; - - case SDL_APP_TERMINATING : - Debug() << "SDL_APP_TERMINATING"; - return 0; - - case SDL_APP_LOWMEMORY : - Debug() << "SDL_APP_LOWMEMORY"; - return 0; - -// case SDL_RENDER_TARGETS_RESET : -// Debug() << "****** SDL_RENDER_TARGETS_RESET"; -// return 0; - -// case SDL_RENDER_DEVICE_RESET : -// Debug() << "****** SDL_RENDER_DEVICE_RESET"; -// return 0; - } - - return 1; + RGSSThreadData &rtData = *static_cast(data); + + switch (event->type) + { + case SDL_APP_WILLENTERBACKGROUND : + Debug() << "SDL_APP_WILLENTERBACKGROUND"; + + if (HAVE_ALC_DEVICE_PAUSE) + alc.DevicePause(rtData.alcDev); + + rtData.syncPoint.haltThreads(); + + return 0; + + case SDL_APP_DIDENTERBACKGROUND : + Debug() << "SDL_APP_DIDENTERBACKGROUND"; + return 0; + + case SDL_APP_WILLENTERFOREGROUND : + Debug() << "SDL_APP_WILLENTERFOREGROUND"; + return 0; + + case SDL_APP_DIDENTERFOREGROUND : + Debug() << "SDL_APP_DIDENTERFOREGROUND"; + + if (HAVE_ALC_DEVICE_PAUSE) + alc.DeviceResume(rtData.alcDev); + + rtData.syncPoint.resumeThreads(); + + return 0; + + case SDL_APP_TERMINATING : + Debug() << "SDL_APP_TERMINATING"; + return 0; + + case SDL_APP_LOWMEMORY : + Debug() << "SDL_APP_LOWMEMORY"; + return 0; + + // case SDL_RENDER_TARGETS_RESET : + // Debug() << "****** SDL_RENDER_TARGETS_RESET"; + // return 0; + + // case SDL_RENDER_DEVICE_RESET : + // Debug() << "****** SDL_RENDER_DEVICE_RESET"; + // return 0; + } + + return 1; } void EventThread::cleanup() { - SDL_Event event; - - while (SDL_PollEvent(&event)) - if ((event.type - usrIdStart) == REQUEST_MESSAGEBOX) - free(event.user.data1); + SDL_Event event; + + while (SDL_PollEvent(&event)) + if ((event.type - usrIdStart) == REQUEST_MESSAGEBOX) + free(event.user.data1); } void EventThread::resetInputStates() { - memset(&keyStates, 0, sizeof(keyStates)); - memset(&joyState, 0, sizeof(joyState)); - memset(&mouseState.buttons, 0, sizeof(mouseState.buttons)); - memset(&touchState, 0, sizeof(touchState)); + memset(&keyStates, 0, sizeof(keyStates)); + memset(&joyState, 0, sizeof(joyState)); + memset(&mouseState.buttons, 0, sizeof(mouseState.buttons)); + memset(&touchState, 0, sizeof(touchState)); } void EventThread::setFullscreen(SDL_Window *win, bool mode) { - SDL_SetWindowFullscreen - (win, mode ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0); - fullscreen = mode; + SDL_SetWindowFullscreen + (win, mode ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0); + fullscreen = mode; } void EventThread::updateCursorState(bool inWindow, const SDL_Rect &screen) { - SDL_Point pos = { mouseState.x, mouseState.y }; - bool inScreen = inWindow && SDL_PointInRect(&pos, &screen); - - if (inScreen) - SDL_ShowCursor(showCursor ? SDL_TRUE : SDL_FALSE); - else - SDL_ShowCursor(SDL_TRUE); + SDL_Point pos = { mouseState.x, mouseState.y }; + bool inScreen = inWindow && SDL_PointInRect(&pos, &screen); + + if (inScreen) + SDL_ShowCursor(showCursor ? SDL_TRUE : SDL_FALSE); + else + SDL_ShowCursor(SDL_TRUE); } void EventThread::requestTerminate() { - SDL_Event event; - event.type = SDL_QUIT; - SDL_PushEvent(&event); + SDL_Event event; + event.type = SDL_QUIT; + SDL_PushEvent(&event); } void EventThread::requestFullscreenMode(bool mode) { - if (mode == fullscreen) - return; - - SDL_Event event; - event.type = usrIdStart + REQUEST_SETFULLSCREEN; - event.user.code = static_cast(mode); - SDL_PushEvent(&event); + if (mode == fullscreen) + return; + + SDL_Event event; + event.type = usrIdStart + REQUEST_SETFULLSCREEN; + event.user.code = static_cast(mode); + SDL_PushEvent(&event); } void EventThread::requestWindowResize(int width, int height) { - SDL_Event event; - event.type = usrIdStart + REQUEST_WINRESIZE; - event.window.data1 = width; - event.window.data2 = height; - SDL_PushEvent(&event); + SDL_Event event; + event.type = usrIdStart + REQUEST_WINRESIZE; + event.window.data1 = width; + event.window.data2 = height; + SDL_PushEvent(&event); } void EventThread::requestWindowReposition(int x, int y) @@ -685,10 +699,10 @@ void EventThread::requestWindowRename(const char *title) void EventThread::requestShowCursor(bool mode) { - SDL_Event event; - event.type = usrIdStart + REQUEST_SETCURSORVISIBLE; - event.user.code = mode; - SDL_PushEvent(&event); + SDL_Event event; + event.type = usrIdStart + REQUEST_SETCURSORVISIBLE; + event.user.code = mode; + SDL_PushEvent(&event); } void EventThread::requestTextInputMode(bool mode) @@ -708,28 +722,28 @@ void EventThread::requestSettingsMenu() void EventThread::showMessageBox(const char *body, int flags) { - msgBoxDone.clear(); - - SDL_Event event; - event.user.code = flags; - event.user.data1 = strdup(body); - event.type = usrIdStart + REQUEST_MESSAGEBOX; - SDL_PushEvent(&event); - - /* Keep repainting screen while box is open */ - shState->graphics().repaintWait(msgBoxDone); - /* Prevent endless loops */ - resetInputStates(); + msgBoxDone.clear(); + + SDL_Event event; + event.user.code = flags; + event.user.data1 = strdup(body); + event.type = usrIdStart + REQUEST_MESSAGEBOX; + SDL_PushEvent(&event); + + /* Keep repainting screen while box is open */ + shState->graphics().repaintWait(msgBoxDone); + /* Prevent endless loops */ + resetInputStates(); } bool EventThread::getFullscreen() const { - return fullscreen; + return fullscreen; } bool EventThread::getShowCursor() const { - return showCursor; + return showCursor; } bool EventThread::getJoystickConnected() const @@ -744,108 +758,113 @@ SDL_Joystick *EventThread::joystick() const void EventThread::notifyFrame() { - if (!fps.sendUpdates) - return; - - SDL_Event event; - event.user.code = round(shState->graphics().averageFrameRate()); - event.user.type = usrIdStart + UPDATE_FPS; - SDL_PushEvent(&event); + if (!fps.sendUpdates) + return; + + SDL_Event event; + event.user.code = round(shState->graphics().averageFrameRate()); + event.user.type = usrIdStart + UPDATE_FPS; + SDL_PushEvent(&event); } void EventThread::notifyGameScreenChange(const SDL_Rect &screen) { - /* We have to get a bit hacky here to fit the rectangle - * data into the user event struct */ - SDL_Event event; - event.type = usrIdStart + UPDATE_SCREEN_RECT; - event.user.windowID = screen.x; - event.user.code = screen.y; - event.user.data1 = reinterpret_cast(screen.w); - event.user.data2 = reinterpret_cast(screen.h); - SDL_PushEvent(&event); + /* We have to get a bit hacky here to fit the rectangle + * data into the user event struct */ + SDL_Event event; + event.type = usrIdStart + UPDATE_SCREEN_RECT; + event.user.windowID = screen.x; + event.user.code = screen.y; + event.user.data1 = reinterpret_cast(screen.w); + event.user.data2 = reinterpret_cast(screen.h); + SDL_PushEvent(&event); +} + +void EventThread::lockText(bool lock) +{ + lock ? SDL_LockMutex(textInputLock) : SDL_UnlockMutex(textInputLock); } void SyncPoint::haltThreads() { - if (mainSync.locked) - return; - - /* Lock the reply sync first to avoid races */ - reply.lock(); - - /* Lock main sync and sleep until RGSS thread - * reports back */ - mainSync.lock(); - reply.waitForUnlock(); - - /* Now that the RGSS thread is asleep, we can - * safely put the other threads to sleep as well - * without causing deadlocks */ - secondSync.lock(); + if (mainSync.locked) + return; + + /* Lock the reply sync first to avoid races */ + reply.lock(); + + /* Lock main sync and sleep until RGSS thread + * reports back */ + mainSync.lock(); + reply.waitForUnlock(); + + /* Now that the RGSS thread is asleep, we can + * safely put the other threads to sleep as well + * without causing deadlocks */ + secondSync.lock(); } void SyncPoint::resumeThreads() { - if (!mainSync.locked) - return; - - mainSync.unlock(false); - secondSync.unlock(true); + if (!mainSync.locked) + return; + + mainSync.unlock(false); + secondSync.unlock(true); } bool SyncPoint::mainSyncLocked() { - return mainSync.locked; + return mainSync.locked; } void SyncPoint::waitMainSync() { - reply.unlock(false); - mainSync.waitForUnlock(); + reply.unlock(false); + mainSync.waitForUnlock(); } void SyncPoint::passSecondarySync() { - if (!secondSync.locked) - return; - - secondSync.waitForUnlock(); + if (!secondSync.locked) + return; + + secondSync.waitForUnlock(); } SyncPoint::Util::Util() { - mut = SDL_CreateMutex(); - cond = SDL_CreateCond(); + mut = SDL_CreateMutex(); + cond = SDL_CreateCond(); } SyncPoint::Util::~Util() { - SDL_DestroyCond(cond); - SDL_DestroyMutex(mut); + SDL_DestroyCond(cond); + SDL_DestroyMutex(mut); } void SyncPoint::Util::lock() { - locked.set(); + locked.set(); } void SyncPoint::Util::unlock(bool multi) { - locked.clear(); - - if (multi) - SDL_CondBroadcast(cond); - else - SDL_CondSignal(cond); + locked.clear(); + + if (multi) + SDL_CondBroadcast(cond); + else + SDL_CondSignal(cond); } void SyncPoint::Util::waitForUnlock() { - SDL_LockMutex(mut); - - while (locked) - SDL_CondWait(cond, mut); - - SDL_UnlockMutex(mut); + SDL_LockMutex(mut); + + while (locked) + SDL_CondWait(cond, mut); + + SDL_UnlockMutex(mut); } diff --git a/src/eventthread.h b/src/eventthread.h index 8d32e97..856ee19 100644 --- a/src/eventthread.h +++ b/src/eventthread.h @@ -77,10 +77,13 @@ public: static TouchState touchState; std::string textInputBuffer; + void lockText(bool lock); + static bool allocUserEvents(); EventThread(); + ~EventThread(); void process(RGSSThreadData &rtData); void cleanup(); @@ -128,6 +131,8 @@ private: SDL_Joystick *js; AtomicFlag msgBoxDone; + + SDL_mutex *textInputLock; struct {