diff --git a/src/mir_init.c b/src/mir_init.c index ab16861d..fe02e627 100644 --- a/src/mir_init.c +++ b/src/mir_init.c @@ -26,6 +26,7 @@ #include "internal.h" +#include ////////////////////////////////////////////////////////////////////////// ////// GLFW internal API ////// @@ -33,6 +34,8 @@ int _glfwPlatformInit(void) { + int error; + _glfw.mir.connection = mir_connect_sync(NULL, __PRETTY_FUNCTION__); if (!mir_connection_is_valid(_glfw.mir.connection)) @@ -51,6 +54,17 @@ int _glfwPlatformInit(void) _glfwInitTimer(); _glfwInitJoysticks(); + _glfw.mir.event_queue = calloc(1, sizeof(EventQueue)); + _glfwInitEventQueue(_glfw.mir.event_queue); + + error = pthread_mutex_init(&_glfw.mir.event_mutex, NULL); + if (error) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Failed to create Event Mutex Error: %i\n", error); + return GL_FALSE; + } + return GL_TRUE; } @@ -59,6 +73,10 @@ void _glfwPlatformTerminate(void) _glfwTerminateContextAPI(); _glfwTerminateJoysticks(); + _glfwDeleteEventQueue(_glfw.mir.event_queue); + + pthread_mutex_destroy(&_glfw.mir.event_mutex); + mir_connection_release(_glfw.mir.connection); } diff --git a/src/mir_platform.h b/src/mir_platform.h index 4a3ebfb8..7d477e90 100644 --- a/src/mir_platform.h +++ b/src/mir_platform.h @@ -33,6 +33,10 @@ #include "posix_time.h" #include "linux_joystick.h" +#include + +#include + #if defined(_GLFW_EGL) #include "egl_context.h" #else @@ -47,6 +51,12 @@ #define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryMir mir #define _GLFW_PLATFORM_CURSOR_STATE _GLFWcursorMir mir +// Mir-specific Event Queue +// +typedef struct EventQueue +{ + TAILQ_HEAD(, EventNode) head; +} EventQueue; // Mir-specific per-window data // @@ -78,6 +88,10 @@ typedef struct _GLFWlibraryMir { MirConnection* connection; MirEGLNativeDisplayType display; + EventQueue* event_queue; + + pthread_mutex_t event_mutex; + pthread_cond_t event_cond; } _GLFWlibraryMir; @@ -89,4 +103,8 @@ typedef struct _GLFWcursorMir { } _GLFWcursorMir; + +extern void _glfwInitEventQueue(EventQueue* queue); +extern void _glfwDeleteEventQueue(EventQueue* queue); + #endif // _mir_platform_h_ diff --git a/src/mir_window.c b/src/mir_window.c index 0a637453..8dd033b5 100644 --- a/src/mir_window.c +++ b/src/mir_window.c @@ -28,8 +28,66 @@ #include "xkb_unicode.h" #include +#include +#include +typedef struct EventNode +{ + TAILQ_ENTRY(EventNode) entries; + MirEvent* event; + _GLFWwindow* window; +} EventNode; + +static void deleteNode(EventQueue* queue, EventNode* node) +{ + free(node->event); + free(node); +} + +static int emptyEventQueue(EventQueue* queue) +{ + return queue->head.tqh_first == NULL ? GL_TRUE : GL_FALSE; +} + +static EventNode* newEventNode(MirEvent const* event, _GLFWwindow* context) +{ + EventNode* new_node = calloc(1, sizeof(EventNode)); + new_node->event = calloc(1, sizeof(MirEvent)); + new_node->window = context; + + memcpy(new_node->event, event, sizeof(MirEvent)); + return new_node; +} + +static void enqueueEvent(MirEvent const* event, _GLFWwindow* context) +{ + pthread_mutex_lock(&_glfw.mir.event_mutex); + + EventNode* new_node = newEventNode(event, context); + TAILQ_INSERT_TAIL(&_glfw.mir.event_queue->head, new_node, entries); + + pthread_cond_signal(&_glfw.mir.event_cond); + + pthread_mutex_unlock(&_glfw.mir.event_mutex); +} + +static EventNode* dequeueEvent(EventQueue* queue) +{ + EventNode* node = NULL; + + pthread_mutex_lock(&_glfw.mir.event_mutex); + + node = queue->head.tqh_first; + + if (node) + TAILQ_REMOVE(&queue->head, node, entries); + + pthread_mutex_unlock(&_glfw.mir.event_mutex); + + return node; +} + static MirPixelFormat findValidPixelFormat(void) { unsigned int i, validFormats, size = 32; @@ -298,21 +356,26 @@ static void handleMotionEvent(const MirMotionEvent motion, _GLFWwindow* window) handleMouseEvent(motion, i, window); } -static void handleInput(MirSurface* surface, const MirEvent* event, void* context) +static void handleInput(MirEvent const* event, _GLFWwindow* window) { switch (event->type) { case mir_event_type_key: - handleKeyEvent(event->key, (_GLFWwindow*) context); + handleKeyEvent(event->key, window); break; case mir_event_type_motion: - handleMotionEvent(event->motion, (_GLFWwindow*) context); + handleMotionEvent(event->motion, window); break; default: break; } } +static void addNewEvent(MirSurface* surface, MirEvent const* event, void* context) +{ + enqueueEvent(event, context); +} + static int createSurface(_GLFWwindow* window) { MirSurfaceParameters params = @@ -327,7 +390,7 @@ static int createSurface(_GLFWwindow* window) MirEventDelegate delegate = { - handleInput, + addNewEvent, window }; @@ -353,6 +416,30 @@ static int createSurface(_GLFWwindow* window) return GL_TRUE; } +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +void _glfwInitEventQueue(EventQueue* queue) +{ + TAILQ_INIT(&queue->head); +} + +void _glfwDeleteEventQueue(EventQueue* queue) +{ + EventNode* node, *node_next; + node = queue->head.tqh_first; + + while (node != NULL) + { + node_next = node->entries.tqe_next; + + TAILQ_REMOVE(&queue->head, node, entries); + deleteNode(queue, node); + + node = node_next; + } +} ////////////////////////////////////////////////////////////////////////// ////// GLFW platform API ////// @@ -475,14 +562,25 @@ void _glfwPlatformUnhideWindow(_GLFWwindow* window) void _glfwPlatformPollEvents(void) { - // Mir does event handling in a different thread, so windows get events - // directly as they happen + EventNode* node = NULL; + + while ((node = dequeueEvent(_glfw.mir.event_queue))) + { + handleInput(node->event, node->window); + deleteNode(_glfw.mir.event_queue, node); + } } void _glfwPlatformWaitEvents(void) { - // Mir does event handling in a different thread, so windows get events - // directly as they happen + pthread_mutex_lock(&_glfw.mir.event_mutex); + + if (emptyEventQueue(_glfw.mir.event_queue)) + pthread_cond_wait(&_glfw.mir.event_cond, &_glfw.mir.event_mutex); + + pthread_mutex_unlock(&_glfw.mir.event_mutex); + + _glfwPlatformPollEvents(); } void _glfwPlatformPostEmptyEvent(void)