From acce7ec9cff9566e2cf58c6503fe64cf06ae8b41 Mon Sep 17 00:00:00 2001 From: Brandon Schaefer Date: Tue, 16 Aug 2016 15:26:07 -0700 Subject: [PATCH] Mir: Add cursor mode support Implements a few other missing functions. Cleaning up naming convention as well. Fix FindMir.cmake was not finding the correct mirclient.so when you wanted something other then the system library. Closes #839. --- CMake/modules/FindMir.cmake | 29 ++++-- src/mir_init.c | 13 +-- src/mir_monitor.c | 12 +-- src/mir_platform.h | 19 ++-- src/mir_window.c | 171 +++++++++++++++++++++++++----------- 5 files changed, 167 insertions(+), 77 deletions(-) diff --git a/CMake/modules/FindMir.cmake b/CMake/modules/FindMir.cmake index b1a495ba..3f1fb0b3 100644 --- a/CMake/modules/FindMir.cmake +++ b/CMake/modules/FindMir.cmake @@ -2,17 +2,36 @@ # # This will define: # -# MIR_LIBRARIES - Link these to use Wayland -# MIR_INCLUDE_DIR - Include directory for Wayland -# -# Copyright (c) 2014 Brandon Schaefer +# MIR_FOUND - System has Mir +# MIR_LIBRARIES - Link these to use Mir +# MIR_INCLUDE_DIR - Include directory for Mir +# MIR_DEFINITIONS - Compiler switches required for using Mir if (NOT WIN32) find_package (PkgConfig) pkg_check_modules (PKG_MIR QUIET mirclient) + set(MIR_DEFINITIONS ${PKG_MIR_CFLAGS_OTHER}) + + find_path(MIR_INCLUDE_DIR + NAMES xkbcommon/xkbcommon.h + HINTS ${PC_XKBCOMMON_INCLUDE_DIR} ${PC_XKBCOMMON_INCLUDE_DIRS} + ) + + find_library(MIR_LIBRARY + NAMES mirclient + HINTS ${PKG_MIR_LIBRARIES} ${MIR_LIBRARY_DIRS} + ) set (MIR_INCLUDE_DIR ${PKG_MIR_INCLUDE_DIRS}) - set (MIR_LIBRARIES ${PKG_MIR_LIBRARIES}) + set (MIR_LIBRARIES ${MIR_LIBRARY}) + + include (FindPackageHandleStandardArgs) + find_package_handle_standard_args (MIR DEFAULT_MSG + MIR_LIBRARIES + MIR_INCLUDE_DIR + ) + + mark_as_advanced (MIR_LIBRARIES MIR_INCLUDE_DIR) endif () diff --git a/src/mir_init.c b/src/mir_init.c index dfe84f9e..d58ff4fc 100644 --- a/src/mir_init.c +++ b/src/mir_init.c @@ -198,12 +198,13 @@ int _glfwPlatformInit(void) _glfwInitTimerPOSIX(); // Need the default conf for when we set a NULL cursor - _glfw.mir.default_conf = mir_cursor_configuration_from_name(mir_arrow_cursor_name); + _glfw.mir.defaultConf = mir_cursor_configuration_from_name(mir_default_cursor_name); + _glfw.mir.disabledConf = mir_cursor_configuration_from_name(mir_disabled_cursor_name); - _glfw.mir.event_queue = calloc(1, sizeof(EventQueue)); - _glfwInitEventQueueMir(_glfw.mir.event_queue); + _glfw.mir.eventQueue = calloc(1, sizeof(EventQueue)); + _glfwInitEventQueueMir(_glfw.mir.eventQueue); - error = pthread_mutex_init(&_glfw.mir.event_mutex, NULL); + error = pthread_mutex_init(&_glfw.mir.eventMutex, NULL); if (error) { _glfwInputError(GLFW_PLATFORM_ERROR, @@ -221,9 +222,9 @@ void _glfwPlatformTerminate(void) _glfwTerminateJoysticksLinux(); _glfwTerminateThreadLocalStoragePOSIX(); - _glfwDeleteEventQueueMir(_glfw.mir.event_queue); + _glfwDeleteEventQueueMir(_glfw.mir.eventQueue); - pthread_mutex_destroy(&_glfw.mir.event_mutex); + pthread_mutex_destroy(&_glfw.mir.eventMutex); mir_connection_release(_glfw.mir.connection); } diff --git a/src/mir_monitor.c b/src/mir_monitor.c index 94c13137..0cb4438a 100644 --- a/src/mir_monitor.c +++ b/src/mir_monitor.c @@ -59,8 +59,8 @@ _GLFWmonitor** _glfwPlatformGetMonitors(int* count) monitors[i]->mir.x = out->position_x; monitors[i]->mir.y = out->position_y; - monitors[i]->mir.output_id = out->output_id; - monitors[i]->mir.cur_mode = out->current_mode; + monitors[i]->mir.outputId = out->output_id; + monitors[i]->mir.curMode = out->current_mode; monitors[i]->modes = _glfwPlatformGetVideoModes(monitors[i], &monitors[i]->modeCount); @@ -75,7 +75,7 @@ _GLFWmonitor** _glfwPlatformGetMonitors(int* count) GLFWbool _glfwPlatformIsSameMonitor(_GLFWmonitor* first, _GLFWmonitor* second) { - return first->mir.output_id == second->mir.output_id; + return first->mir.outputId == second->mir.outputId; } void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos) @@ -129,7 +129,7 @@ GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* found) for (i = 0; i < displayConfig->num_outputs; i++) { const MirDisplayOutput* out = displayConfig->outputs + i; - if (out->output_id != monitor->mir.output_id) + if (out->output_id != monitor->mir.outputId) continue; modes = calloc(out->num_modes, sizeof(GLFWvidmode)); @@ -153,7 +153,7 @@ GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* found) void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode) { - *mode = monitor->modes[monitor->mir.cur_mode]; + *mode = monitor->modes[monitor->mir.curMode]; } void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp) @@ -177,6 +177,6 @@ GLFWAPI int glfwGetMirMonitor(GLFWmonitor* handle) { _GLFWmonitor* monitor = (_GLFWmonitor*) handle; _GLFW_REQUIRE_INIT_OR_RETURN(0); - return monitor->mir.output_id; + return monitor->mir.outputId; } diff --git a/src/mir_platform.h b/src/mir_platform.h index fc483928..250d4c33 100644 --- a/src/mir_platform.h +++ b/src/mir_platform.h @@ -84,6 +84,7 @@ typedef struct _GLFWwindowMir int width; int height; MirEGLNativeWindowType window; + _GLFWcursor* currentCursor; } _GLFWwindowMir; @@ -91,8 +92,8 @@ typedef struct _GLFWwindowMir // typedef struct _GLFWmonitorMir { - int cur_mode; - int output_id; + int curMode; + int outputId; int x; int y; @@ -104,14 +105,18 @@ typedef struct _GLFWlibraryMir { MirConnection* connection; MirEGLNativeDisplayType display; - MirCursorConfiguration* default_conf; - EventQueue* event_queue; + MirCursorConfiguration* defaultConf; + MirCursorConfiguration* disabledConf; + EventQueue* eventQueue; short int publicKeys[256]; short int nativeKeys[GLFW_KEY_LAST + 1]; - pthread_mutex_t event_mutex; - pthread_cond_t event_cond; + pthread_mutex_t eventMutex; + pthread_cond_t eventCond; + + // The window whose disabled cursor mode is active + _GLFWwindow* disabledCursorWindow; } _GLFWlibraryMir; @@ -121,7 +126,7 @@ typedef struct _GLFWlibraryMir typedef struct _GLFWcursorMir { MirCursorConfiguration* conf; - MirBufferStream* custom_cursor; + MirBufferStream* customCursor; } _GLFWcursorMir; diff --git a/src/mir_window.c b/src/mir_window.c index 3420abc0..3f49cb0b 100644 --- a/src/mir_window.c +++ b/src/mir_window.c @@ -54,37 +54,37 @@ static GLFWbool emptyEventQueue(EventQueue* queue) // for single threaded event handling. static EventNode* newEventNode(const MirEvent* event, _GLFWwindow* context) { - EventNode* new_node = calloc(1, sizeof(EventNode)); - new_node->event = mir_event_ref(event); - new_node->window = context; + EventNode* newNode = calloc(1, sizeof(EventNode)); + newNode->event = mir_event_ref(event); + newNode->window = context; - return new_node; + return newNode; } static void enqueueEvent(const MirEvent* event, _GLFWwindow* context) { - pthread_mutex_lock(&_glfw.mir.event_mutex); + pthread_mutex_lock(&_glfw.mir.eventMutex); - EventNode* new_node = newEventNode(event, context); - TAILQ_INSERT_TAIL(&_glfw.mir.event_queue->head, new_node, entries); + EventNode* newNode = newEventNode(event, context); + TAILQ_INSERT_TAIL(&_glfw.mir.eventQueue->head, newNode, entries); - pthread_cond_signal(&_glfw.mir.event_cond); + pthread_cond_signal(&_glfw.mir.eventCond); - pthread_mutex_unlock(&_glfw.mir.event_mutex); + pthread_mutex_unlock(&_glfw.mir.eventMutex); } static EventNode* dequeueEvent(EventQueue* queue) { EventNode* node = NULL; - pthread_mutex_lock(&_glfw.mir.event_mutex); + pthread_mutex_lock(&_glfw.mir.eventMutex); node = queue->head.tqh_first; if (node) TAILQ_REMOVE(&queue->head, node, entries); - pthread_mutex_unlock(&_glfw.mir.event_mutex); + pthread_mutex_unlock(&_glfw.mir.eventMutex); return node; } @@ -201,16 +201,31 @@ static void handlePointerButton(_GLFWwindow* window, static void handlePointerMotion(_GLFWwindow* window, const MirPointerEvent* pointer_event) { - int current_x = window->virtualCursorPosX; - int current_y = window->virtualCursorPosY; - int x = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_x); - int y = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_y); - int dx = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_hscroll); - int dy = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_vscroll); + const int hscroll = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_hscroll); + const int vscroll = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_vscroll); - _glfwInputCursorPos(window, x, y); - if (dx != 0 || dy != 0) - _glfwInputScroll(window, dx, dy); + if (window->cursorMode == GLFW_CURSOR_DISABLED) + { + if (_glfw.mir.disabledCursorWindow != window) + return; + + const int dx = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_relative_x); + const int dy = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_relative_y); + const int current_x = window->virtualCursorPosX; + const int current_y = window->virtualCursorPosY; + + _glfwInputCursorPos(window, dx + current_x, dy + current_y); + } + else + { + const int x = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_x); + const int y = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_y); + + _glfwInputCursorPos(window, x, y); + } + + if (hscroll != 0 || vscroll != 0) + _glfwInputScroll(window, hscroll, vscroll); } static void handlePointerEvent(const MirPointerEvent* pointer_event, @@ -234,7 +249,6 @@ static void handlePointerEvent(const MirPointerEvent* pointer_event, break; default: break; - } } @@ -286,7 +300,7 @@ static GLFWbool createSurface(_GLFWwindow* window) "Mir: Unable to find a correct pixel format"); return GLFW_FALSE; } - + spec = mir_connection_create_spec_for_normal_surface(_glfw.mir.connection, window->mir.width, window->mir.height, @@ -312,6 +326,17 @@ static GLFWbool createSurface(_GLFWwindow* window) return GLFW_TRUE; } +static void setSurfaceConfinement(_GLFWwindow* window, MirPointerConfinementState state) +{ + MirSurfaceSpec* spec; + + spec = mir_connection_create_spec_for_changes(_glfw.mir.connection); + mir_surface_spec_set_pointer_confinement(spec, state); + + mir_surface_apply_spec(window->mir.surface, spec); + mir_surface_spec_release(spec); +} + ////////////////////////////////////////////////////////////////////////// ////// GLFW internal API ////// ////////////////////////////////////////////////////////////////////////// @@ -370,6 +395,7 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window, window->mir.width = wndconfig->width; window->mir.height = wndconfig->height; + window->mir.currentCursor = NULL; if (!createSurface(window)) return GLFW_FALSE; @@ -390,6 +416,9 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window, void _glfwPlatformDestroyWindow(_GLFWwindow* window) { + if (_glfw.mir.disabledCursorWindow == window) + _glfw.mir.disabledCursorWindow = NULL; + if (mir_surface_is_valid(window->mir.surface)) { mir_surface_release_sync(window->mir.surface); @@ -475,18 +504,35 @@ void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height) void _glfwPlatformIconifyWindow(_GLFWwindow* window) { - mir_surface_set_state(window->mir.surface, mir_surface_state_minimized); + MirSurfaceSpec* spec; + + spec = mir_connection_create_spec_for_changes(_glfw.mir.connection); + mir_surface_spec_set_state(spec, mir_surface_state_minimized); + + mir_surface_apply_spec(window->mir.surface, spec); + mir_surface_spec_release(spec); } void _glfwPlatformRestoreWindow(_GLFWwindow* window) { - mir_surface_set_state(window->mir.surface, mir_surface_state_restored); + MirSurfaceSpec* spec; + + spec = mir_connection_create_spec_for_changes(_glfw.mir.connection); + mir_surface_spec_set_state(spec, mir_surface_state_restored); + + mir_surface_apply_spec(window->mir.surface, spec); + mir_surface_spec_release(spec); } void _glfwPlatformMaximizeWindow(_GLFWwindow* window) { - _glfwInputError(GLFW_PLATFORM_ERROR, - "Mir: Unsupported function %s", __PRETTY_FUNCTION__); + MirSurfaceSpec* spec; + + spec = mir_connection_create_spec_for_changes(_glfw.mir.connection); + mir_surface_spec_set_state(spec, mir_surface_state_maximized); + + mir_surface_apply_spec(window->mir.surface, spec); + mir_surface_spec_release(spec); } void _glfwPlatformHideWindow(_GLFWwindow* window) @@ -529,9 +575,7 @@ void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, int _glfwPlatformWindowFocused(_GLFWwindow* window) { - _glfwInputError(GLFW_PLATFORM_ERROR, - "Mir: Unsupported function %s", __PRETTY_FUNCTION__); - return GLFW_FALSE; + return mir_surface_get_focus(window->mir.surface) == mir_surface_focused; } int _glfwPlatformWindowIconified(_GLFWwindow* window) @@ -548,48 +592,46 @@ int _glfwPlatformWindowVisible(_GLFWwindow* window) int _glfwPlatformWindowMaximized(_GLFWwindow* window) { - _glfwInputError(GLFW_PLATFORM_ERROR, - "Mir: Unsupported function %s", __PRETTY_FUNCTION__); - return GLFW_FALSE; + return mir_surface_get_state(window->mir.surface) == mir_surface_state_maximized; } void _glfwPlatformPollEvents(void) { EventNode* node = NULL; - while ((node = dequeueEvent(_glfw.mir.event_queue))) + while ((node = dequeueEvent(_glfw.mir.eventQueue))) { handleEvent(node->event, node->window); - deleteNode(_glfw.mir.event_queue, node); + deleteNode(_glfw.mir.eventQueue, node); } } void _glfwPlatformWaitEvents(void) { - pthread_mutex_lock(&_glfw.mir.event_mutex); + pthread_mutex_lock(&_glfw.mir.eventMutex); - if (emptyEventQueue(_glfw.mir.event_queue)) - pthread_cond_wait(&_glfw.mir.event_cond, &_glfw.mir.event_mutex); + if (emptyEventQueue(_glfw.mir.eventQueue)) + pthread_cond_wait(&_glfw.mir.eventCond, &_glfw.mir.eventMutex); - pthread_mutex_unlock(&_glfw.mir.event_mutex); + pthread_mutex_unlock(&_glfw.mir.eventMutex); _glfwPlatformPollEvents(); } void _glfwPlatformWaitEventsTimeout(double timeout) { - pthread_mutex_lock(&_glfw.mir.event_mutex); + pthread_mutex_lock(&_glfw.mir.eventMutex); - if (emptyEventQueue(_glfw.mir.event_queue)) + if (emptyEventQueue(_glfw.mir.eventQueue)) { struct timespec time; clock_gettime(CLOCK_REALTIME, &time); time.tv_sec += (long) timeout; time.tv_nsec += (long) ((timeout - (long) timeout) * 1e9); - pthread_cond_timedwait(&_glfw.mir.event_cond, &_glfw.mir.event_mutex, &time); + pthread_cond_timedwait(&_glfw.mir.eventCond, &_glfw.mir.eventMutex, &time); } - pthread_mutex_unlock(&_glfw.mir.event_mutex); + pthread_mutex_unlock(&_glfw.mir.eventMutex); _glfwPlatformPollEvents(); } @@ -606,7 +648,6 @@ void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* heigh *height = window->mir.height; } -// FIXME implement int _glfwPlatformCreateCursor(_GLFWcursor* cursor, const GLFWimage* image, int xhot, int yhot) @@ -654,7 +695,7 @@ int _glfwPlatformCreateCursor(_GLFWcursor* cursor, pixels += r_stride; } - cursor->mir.custom_cursor = stream; + cursor->mir.customCursor = stream; return GLFW_TRUE; } @@ -686,8 +727,8 @@ int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape) if (cursor_name) { - cursor->mir.conf = mir_cursor_configuration_from_name(cursor_name); - cursor->mir.custom_cursor = NULL; + cursor->mir.conf = mir_cursor_configuration_from_name(cursor_name); + cursor->mir.customCursor = NULL; return GLFW_TRUE; } @@ -699,23 +740,25 @@ void _glfwPlatformDestroyCursor(_GLFWcursor* cursor) { if (cursor->mir.conf) mir_cursor_configuration_destroy(cursor->mir.conf); - if (cursor->mir.custom_cursor) - mir_buffer_stream_release_sync(cursor->mir.custom_cursor); + if (cursor->mir.customCursor) + mir_buffer_stream_release_sync(cursor->mir.customCursor); } void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor) { if (cursor && cursor->mir.conf) { + window->mir.currentCursor = cursor; + mir_wait_for(mir_surface_configure_cursor(window->mir.surface, cursor->mir.conf)); - if (cursor->mir.custom_cursor) + if (cursor->mir.customCursor) { - mir_buffer_stream_swap_buffers_sync(cursor->mir.custom_cursor); + mir_buffer_stream_swap_buffers_sync(cursor->mir.customCursor); } } else { - mir_wait_for(mir_surface_configure_cursor(window->mir.surface, _glfw.mir.default_conf)); + mir_wait_for(mir_surface_configure_cursor(window->mir.surface, _glfw.mir.defaultConf)); } } @@ -733,8 +776,30 @@ void _glfwPlatformSetCursorPos(_GLFWwindow* window, double xpos, double ypos) void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode) { - _glfwInputError(GLFW_PLATFORM_ERROR, - "Mir: Unsupported function %s", __PRETTY_FUNCTION__); + if (mode == GLFW_CURSOR_DISABLED) + { + _glfw.mir.disabledCursorWindow = window; + setSurfaceConfinement(window, mir_pointer_confined_to_surface); + mir_wait_for(mir_surface_configure_cursor(window->mir.surface, _glfw.mir.disabledConf)); + } + else + { + // If we were disabled before lets undo that! + if (_glfw.mir.disabledCursorWindow == window) + { + _glfw.mir.disabledCursorWindow = NULL; + setSurfaceConfinement(window, mir_pointer_unconfined); + } + + if (window->cursorMode == GLFW_CURSOR_NORMAL) + { + _glfwPlatformSetCursor(window, window->mir.currentCursor); + } + else if (window->cursorMode == GLFW_CURSOR_HIDDEN) + { + mir_wait_for(mir_surface_configure_cursor(window->mir.surface, _glfw.mir.disabledConf)); + } + } } const char* _glfwPlatformGetKeyName(int key, int scancode)