diff options
author | Dmitri Shuralyov <shurcooL@gmail.com> | 2014-12-31 18:45:16 -0800 |
---|---|---|
committer | Dmitri Shuralyov <shurcooL@gmail.com> | 2015-02-21 18:51:42 -0800 |
commit | 580367ced74b6c4fedd851d3378b3537bd2a853b (patch) | |
tree | 6c9251cf3912a304085197059dee3a0f97f02728 | |
parent | d55884e36b8254966ef9daaee2ea2263e67d6eac (diff) | |
download | glfw-580367ced74b6c4fedd851d3378b3537bd2a853b.tar.gz |
Update to glfw/glfw@aa7f827e721d8fc4c856f10152ec945169e69665.
30 files changed, 1947 insertions, 647 deletions
diff --git a/GLFW_C_REVISION.txt b/GLFW_C_REVISION.txt index 3b98cb5..0ca9948 100644 --- a/GLFW_C_REVISION.txt +++ b/GLFW_C_REVISION.txt @@ -1 +1 @@ -3b9a14fc9c3845afc7b8788a62435bdc02a7daaf +aa7f827e721d8fc4c856f10152ec945169e69665 diff --git a/glfw/include/GLFW/glfw3.h b/glfw/include/GLFW/glfw3.h index 83b2ff0..2cba521 100644 --- a/glfw/include/GLFW/glfw3.h +++ b/glfw/include/GLFW/glfw3.h @@ -672,6 +672,42 @@ extern "C" { #define GLFW_RELEASE_BEHAVIOR_FLUSH 0x00035001 #define GLFW_RELEASE_BEHAVIOR_NONE 0x00035002 +/*! @defgroup shapes Standard cursor shapes + * @ingroup input + * @{ */ + +/*! @brief The regular arrow cursor shape. + * + * The regular arrow cursor. + */ +#define GLFW_ARROW_CURSOR 0x00036001 +/*! @brief The text input I-beam cursor shape. + * + * The text input I-beam cursor shape. + */ +#define GLFW_IBEAM_CURSOR 0x00036002 +/*! @brief The crosshair shape. + * + * The crosshair shape. + */ +#define GLFW_CROSSHAIR_CURSOR 0x00036003 +/*! @brief The hand shape. + * + * The hand shape. + */ +#define GLFW_HAND_CURSOR 0x00036004 +/*! @brief The horizontal resize arrow shape. + * + * The horizontal resize arrow shape. + */ +#define GLFW_HRESIZE_CURSOR 0x00036005 +/*! @brief The vertical resize arrow shape. + * + * The vertical resize arrow shape. + */ +#define GLFW_VRESIZE_CURSOR 0x00036006 +/*! @} */ + #define GLFW_CONNECTED 0x00040001 #define GLFW_DISCONNECTED 0x00040002 @@ -1013,8 +1049,6 @@ typedef struct GLFWgammaramp } GLFWgammaramp; /*! @brief Image data. - * - * @ingroup window */ typedef struct GLFWimage { @@ -1055,6 +1089,12 @@ typedef struct GLFWimage * bundle, if present. This can be disabled with a * [compile-time option](@ref compile_options_osx). * + * @remarks __X11:__ If the `LC_CTYPE` category of the current locale is set to + * `"C"` then the environment's locale will be applied to that category. This + * is done because character input will not function when `LC_CTYPE` is set to + * `"C"`. If another locale was set before this function was called, it will + * be left untouched. + * * @par Thread Safety * This function may only be called from the main thread. * @@ -1591,6 +1631,9 @@ GLFWAPI void glfwWindowHint(int target, int hint); * `GLFW_ICON,` it will be set as the icon for the window. If no such icon is * present, the `IDI_WINLOGO` icon will be used instead. * + * @remarks __Windows:__ The context to share resources with may not be current + * on any other thread. + * * @remarks __OS X:__ The GLFW window has no icon, as it is not a document * window, but the dock icon will be the same as the application bundle's icon. * For more information on bundles, see the @@ -1608,7 +1651,8 @@ GLFWAPI void glfwWindowHint(int target, int hint); * @remarks __X11:__ Some window managers will not respect the placement of * initially hidden windows. * - * @note This function may not be called from a callback. + * @par Reentrancy + * This function may not be called from a callback. * * @par Thread Safety * This function may only be called from the main thread. @@ -1636,11 +1680,12 @@ GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height, const char* title, G * * @param[in] window The window to destroy. * - * @note This function may not be called from a callback. - * * @note The context of the specified window must not be current on any other * thread when this function is called. * + * @par Reentrancy + * This function may not be called from a callback. + * * @par Thread Safety * This function may only be called from the main thread. * @@ -2302,7 +2347,8 @@ GLFWAPI GLFWframebuffersizefun glfwSetFramebufferSizeCallback(GLFWwindow* window * * Event processing is not required for joystick input to work. * - * @note This function may not be called from a callback. + * @par Reentrancy + * This function may not be called from a callback. * * @par Thread Safety * This function may only be called from the main thread. @@ -2345,11 +2391,12 @@ GLFWAPI void glfwPollEvents(void); * * Event processing is not required for joystick input to work. * - * @note This function may not be called from a callback. - * * @note On some platforms, certain callbacks may be called outside of a call * to one of the event processing functions. * + * @par Reentrancy + * This function may not be called from a callback. + * * @par Thread Safety * This function may only be called from the main thread. * @@ -2606,7 +2653,7 @@ GLFWAPI void glfwGetCursorPos(GLFWwindow* window, double* xpos, double* ypos); */ GLFWAPI void glfwSetCursorPos(GLFWwindow* window, double xpos, double ypos); -/*! @brief Creates a cursor. +/*! @brief Creates a custom cursor. * * Creates a new cursor that can be made the system cursor for a window with * @ref glfwSetCursor. The cursor can be destroyed with @ref @@ -2623,16 +2670,18 @@ GLFWAPI void glfwSetCursorPos(GLFWwindow* window, double xpos, double ypos); * @return A new cursor ready to use or `NULL` if an * [error](@ref error_handling) occurred. * - * @note This function may not be called from a callback. - * * @par Pointer Lifetime * The specified image data is copied before this function returns. * + * @par Reentrancy + * This function may not be called from a callback. + * * @par Thread Safety * This function may only be called from the main thread. * * @sa @ref input_cursor * @sa glfwDestroyCursor + * @sa glfwCreateStandardCursor * * @par History * Added in GLFW 3.1. @@ -2641,6 +2690,32 @@ GLFWAPI void glfwSetCursorPos(GLFWwindow* window, double xpos, double ypos); */ GLFWAPI GLFWcursor* glfwCreateCursor(const GLFWimage* image, int xhot, int yhot); +/*! @brief Creates a cursor with a standard shape. + * + * Returns a cursor with a [standard shape](@ref shapes), which can be made the + * system cursor for a window with @ref glfwSetCursor. + * + * @param[in] shape One of the [standard shapes](@ref shapes). + * + * @return A new cursor ready to use or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @par Reentrancy + * This function may not be called from a callback. + * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref input_cursor + * @sa glfwCreateCursor + * + * @par History + * Added in GLFW 3.1. + * + * @ingroup input + */ +GLFWAPI GLFWcursor* glfwCreateStandardCursor(int shape); + /*! @brief Destroys a cursor. * * This function destroys a cursor previously created with @ref @@ -2649,7 +2724,8 @@ GLFWAPI GLFWcursor* glfwCreateCursor(const GLFWimage* image, int xhot, int yhot) * * @param[in] cursor The cursor object to destroy. * - * @note This function may not be called from a callback. + * @par Reentrancy + * This function may not be called from a callback. * * @par Thread Safety * This function may only be called from the main thread. diff --git a/glfw/include/GLFW/glfw3native.h b/glfw/include/GLFW/glfw3native.h index c00d57c..881f504 100644 --- a/glfw/include/GLFW/glfw3native.h +++ b/glfw/include/GLFW/glfw3native.h @@ -108,9 +108,9 @@ extern "C" { *************************************************************************/ #if defined(GLFW_EXPOSE_NATIVE_WIN32) -/*! @brief Returns the display device name of the specified monitor. +/*! @brief Returns the adapter device name of the specified monitor. * - * @return The UTF-8 encoded display device name (`DISPLAY_DEVICE.DeviceName`) + * @return The UTF-8 encoded adapter device name (for example `\\.\DISPLAY1`) * of the specified monitor, or `NULL` if an [error](@ref error_handling) * occurred. * @@ -122,6 +122,22 @@ extern "C" { * * @ingroup native */ +GLFWAPI const char* glfwGetWin32Adapter(GLFWmonitor* monitor); + +/*! @brief Returns the display device name of the specified monitor. + * + * @return The UTF-8 encoded display device name (for example + * `\\.\DISPLAY1\Monitor0`) of the specified monitor, or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @par Thread Safety + * This function may be called from any thread. Access is not synchronized. + * + * @par History + * Added in GLFW 3.1. + * + * @ingroup native + */ GLFWAPI const char* glfwGetWin32Monitor(GLFWmonitor* monitor); /*! @brief Returns the `HWND` of the specified window. @@ -222,6 +238,21 @@ GLFWAPI id glfwGetNSGLContext(GLFWwindow* window); */ GLFWAPI Display* glfwGetX11Display(void); +/*! @brief Returns the `RRCrtc` of the specified monitor. + * + * @return The `RRCrtc` of the specified monitor, or `None` if an + * [error](@ref error_handling) occurred. + * + * @par Thread Safety + * This function may be called from any thread. Access is not synchronized. + * + * @par History + * Added in GLFW 3.1. + * + * @ingroup native + */ +GLFWAPI RRCrtc glfwGetX11Adapter(GLFWmonitor* monitor); + /*! @brief Returns the `RROutput` of the specified monitor. * * @return The `RROutput` of the specified monitor, or `None` if an diff --git a/glfw/src/CMakeLists.txt b/glfw/src/CMakeLists.txt index e006a8f..9ba9fc5 100644 --- a/glfw/src/CMakeLists.txt +++ b/glfw/src/CMakeLists.txt @@ -30,6 +30,11 @@ elseif (_GLFW_WAYLAND) posix_time.h posix_tls.h xkb_unicode.h) set(glfw_SOURCES ${common_SOURCES} wl_init.c wl_monitor.c wl_window.c linux_joystick.c posix_time.c posix_tls.c xkb_unicode.c) +elseif (_GLFW_MIR) + set(glfw_HEADERS ${common_HEADERS} mir_platform.h linux_joystick.h + posix_time.h posix_tls.h xkb_unicode.h) + set(glfw_SOURCES ${common_SOURCES} mir_init.c mir_monitor.c mir_window.c + linux_joystick.c posix_time.c posix_tls.c xkb_unicode.c) endif() if (_GLFW_EGL) diff --git a/glfw/src/cocoa_init.m b/glfw/src/cocoa_init.m index afb1a54..1bcee9d 100644 --- a/glfw/src/cocoa_init.m +++ b/glfw/src/cocoa_init.m @@ -68,6 +68,128 @@ static void changeToResourcesDirectory(void) #endif /* _GLFW_USE_CHDIR */ +// Create key code translation tables +// +static void createKeyTables(void) +{ + memset(_glfw.ns.publicKeys, -1, sizeof(_glfw.ns.publicKeys)); + + _glfw.ns.publicKeys[0x1D] = GLFW_KEY_0; + _glfw.ns.publicKeys[0x12] = GLFW_KEY_1; + _glfw.ns.publicKeys[0x13] = GLFW_KEY_2; + _glfw.ns.publicKeys[0x14] = GLFW_KEY_3; + _glfw.ns.publicKeys[0x15] = GLFW_KEY_4; + _glfw.ns.publicKeys[0x17] = GLFW_KEY_5; + _glfw.ns.publicKeys[0x16] = GLFW_KEY_6; + _glfw.ns.publicKeys[0x1A] = GLFW_KEY_7; + _glfw.ns.publicKeys[0x1C] = GLFW_KEY_8; + _glfw.ns.publicKeys[0x19] = GLFW_KEY_9; + _glfw.ns.publicKeys[0x00] = GLFW_KEY_A; + _glfw.ns.publicKeys[0x0B] = GLFW_KEY_B; + _glfw.ns.publicKeys[0x08] = GLFW_KEY_C; + _glfw.ns.publicKeys[0x02] = GLFW_KEY_D; + _glfw.ns.publicKeys[0x0E] = GLFW_KEY_E; + _glfw.ns.publicKeys[0x03] = GLFW_KEY_F; + _glfw.ns.publicKeys[0x05] = GLFW_KEY_G; + _glfw.ns.publicKeys[0x04] = GLFW_KEY_H; + _glfw.ns.publicKeys[0x22] = GLFW_KEY_I; + _glfw.ns.publicKeys[0x26] = GLFW_KEY_J; + _glfw.ns.publicKeys[0x28] = GLFW_KEY_K; + _glfw.ns.publicKeys[0x25] = GLFW_KEY_L; + _glfw.ns.publicKeys[0x2E] = GLFW_KEY_M; + _glfw.ns.publicKeys[0x2D] = GLFW_KEY_N; + _glfw.ns.publicKeys[0x1F] = GLFW_KEY_O; + _glfw.ns.publicKeys[0x23] = GLFW_KEY_P; + _glfw.ns.publicKeys[0x0C] = GLFW_KEY_Q; + _glfw.ns.publicKeys[0x0F] = GLFW_KEY_R; + _glfw.ns.publicKeys[0x01] = GLFW_KEY_S; + _glfw.ns.publicKeys[0x11] = GLFW_KEY_T; + _glfw.ns.publicKeys[0x20] = GLFW_KEY_U; + _glfw.ns.publicKeys[0x09] = GLFW_KEY_V; + _glfw.ns.publicKeys[0x0D] = GLFW_KEY_W; + _glfw.ns.publicKeys[0x07] = GLFW_KEY_X; + _glfw.ns.publicKeys[0x10] = GLFW_KEY_Y; + _glfw.ns.publicKeys[0x06] = GLFW_KEY_Z; + + _glfw.ns.publicKeys[0x27] = GLFW_KEY_APOSTROPHE; + _glfw.ns.publicKeys[0x2A] = GLFW_KEY_BACKSLASH; + _glfw.ns.publicKeys[0x2B] = GLFW_KEY_COMMA; + _glfw.ns.publicKeys[0x18] = GLFW_KEY_EQUAL; + _glfw.ns.publicKeys[0x32] = GLFW_KEY_GRAVE_ACCENT; + _glfw.ns.publicKeys[0x21] = GLFW_KEY_LEFT_BRACKET; + _glfw.ns.publicKeys[0x1B] = GLFW_KEY_MINUS; + _glfw.ns.publicKeys[0x2F] = GLFW_KEY_PERIOD; + _glfw.ns.publicKeys[0x1E] = GLFW_KEY_RIGHT_BRACKET; + _glfw.ns.publicKeys[0x29] = GLFW_KEY_SEMICOLON; + _glfw.ns.publicKeys[0x2C] = GLFW_KEY_SLASH; + _glfw.ns.publicKeys[0x0A] = GLFW_KEY_WORLD_1; + + _glfw.ns.publicKeys[0x33] = GLFW_KEY_BACKSPACE; + _glfw.ns.publicKeys[0x39] = GLFW_KEY_CAPS_LOCK; + _glfw.ns.publicKeys[0x75] = GLFW_KEY_DELETE; + _glfw.ns.publicKeys[0x7D] = GLFW_KEY_DOWN; + _glfw.ns.publicKeys[0x77] = GLFW_KEY_END; + _glfw.ns.publicKeys[0x24] = GLFW_KEY_ENTER; + _glfw.ns.publicKeys[0x35] = GLFW_KEY_ESCAPE; + _glfw.ns.publicKeys[0x7A] = GLFW_KEY_F1; + _glfw.ns.publicKeys[0x78] = GLFW_KEY_F2; + _glfw.ns.publicKeys[0x63] = GLFW_KEY_F3; + _glfw.ns.publicKeys[0x76] = GLFW_KEY_F4; + _glfw.ns.publicKeys[0x60] = GLFW_KEY_F5; + _glfw.ns.publicKeys[0x61] = GLFW_KEY_F6; + _glfw.ns.publicKeys[0x62] = GLFW_KEY_F7; + _glfw.ns.publicKeys[0x64] = GLFW_KEY_F8; + _glfw.ns.publicKeys[0x65] = GLFW_KEY_F9; + _glfw.ns.publicKeys[0x6D] = GLFW_KEY_F10; + _glfw.ns.publicKeys[0x67] = GLFW_KEY_F11; + _glfw.ns.publicKeys[0x6F] = GLFW_KEY_F12; + _glfw.ns.publicKeys[0x69] = GLFW_KEY_F13; + _glfw.ns.publicKeys[0x6B] = GLFW_KEY_F14; + _glfw.ns.publicKeys[0x71] = GLFW_KEY_F15; + _glfw.ns.publicKeys[0x6A] = GLFW_KEY_F16; + _glfw.ns.publicKeys[0x40] = GLFW_KEY_F17; + _glfw.ns.publicKeys[0x4F] = GLFW_KEY_F18; + _glfw.ns.publicKeys[0x50] = GLFW_KEY_F19; + _glfw.ns.publicKeys[0x5A] = GLFW_KEY_F20; + _glfw.ns.publicKeys[0x73] = GLFW_KEY_HOME; + _glfw.ns.publicKeys[0x72] = GLFW_KEY_INSERT; + _glfw.ns.publicKeys[0x7B] = GLFW_KEY_LEFT; + _glfw.ns.publicKeys[0x3A] = GLFW_KEY_LEFT_ALT; + _glfw.ns.publicKeys[0x3B] = GLFW_KEY_LEFT_CONTROL; + _glfw.ns.publicKeys[0x38] = GLFW_KEY_LEFT_SHIFT; + _glfw.ns.publicKeys[0x37] = GLFW_KEY_LEFT_SUPER; + _glfw.ns.publicKeys[0x6E] = GLFW_KEY_MENU; + _glfw.ns.publicKeys[0x47] = GLFW_KEY_NUM_LOCK; + _glfw.ns.publicKeys[0x79] = GLFW_KEY_PAGE_DOWN; + _glfw.ns.publicKeys[0x74] = GLFW_KEY_PAGE_UP; + _glfw.ns.publicKeys[0x7C] = GLFW_KEY_RIGHT; + _glfw.ns.publicKeys[0x3D] = GLFW_KEY_RIGHT_ALT; + _glfw.ns.publicKeys[0x3E] = GLFW_KEY_RIGHT_CONTROL; + _glfw.ns.publicKeys[0x3C] = GLFW_KEY_RIGHT_SHIFT; + _glfw.ns.publicKeys[0x36] = GLFW_KEY_RIGHT_SUPER; + _glfw.ns.publicKeys[0x31] = GLFW_KEY_SPACE; + _glfw.ns.publicKeys[0x30] = GLFW_KEY_TAB; + _glfw.ns.publicKeys[0x7E] = GLFW_KEY_UP; + + _glfw.ns.publicKeys[0x52] = GLFW_KEY_KP_0; + _glfw.ns.publicKeys[0x53] = GLFW_KEY_KP_1; + _glfw.ns.publicKeys[0x54] = GLFW_KEY_KP_2; + _glfw.ns.publicKeys[0x55] = GLFW_KEY_KP_3; + _glfw.ns.publicKeys[0x56] = GLFW_KEY_KP_4; + _glfw.ns.publicKeys[0x57] = GLFW_KEY_KP_5; + _glfw.ns.publicKeys[0x58] = GLFW_KEY_KP_6; + _glfw.ns.publicKeys[0x59] = GLFW_KEY_KP_7; + _glfw.ns.publicKeys[0x5B] = GLFW_KEY_KP_8; + _glfw.ns.publicKeys[0x5C] = GLFW_KEY_KP_9; + _glfw.ns.publicKeys[0x45] = GLFW_KEY_KP_ADD; + _glfw.ns.publicKeys[0x41] = GLFW_KEY_KP_DECIMAL; + _glfw.ns.publicKeys[0x4B] = GLFW_KEY_KP_DIVIDE; + _glfw.ns.publicKeys[0x4C] = GLFW_KEY_KP_ENTER; + _glfw.ns.publicKeys[0x51] = GLFW_KEY_KP_EQUAL; + _glfw.ns.publicKeys[0x43] = GLFW_KEY_KP_MULTIPLY; + _glfw.ns.publicKeys[0x4E] = GLFW_KEY_KP_SUBTRACT; +} + ////////////////////////////////////////////////////////////////////////// ////// GLFW platform API ////// @@ -81,6 +203,8 @@ int _glfwPlatformInit(void) changeToResourcesDirectory(); #endif + createKeyTables(); + _glfw.ns.eventSource = CGEventSourceCreate(kCGEventSourceStateHIDSystemState); if (!_glfw.ns.eventSource) return GL_FALSE; @@ -104,9 +228,12 @@ void _glfwPlatformTerminate(void) _glfw.ns.eventSource = NULL; } - [NSApp setDelegate:nil]; - [_glfw.ns.delegate release]; - _glfw.ns.delegate = nil; + id delegate = [NSApp delegate]; + if (delegate) + { + [delegate release]; + [NSApp setDelegate:nil]; + } [_glfw.ns.autoreleasePool release]; _glfw.ns.autoreleasePool = nil; diff --git a/glfw/src/cocoa_monitor.m b/glfw/src/cocoa_monitor.m index cfb76a7..db3cf71 100644 --- a/glfw/src/cocoa_monitor.m +++ b/glfw/src/cocoa_monitor.m @@ -204,7 +204,6 @@ GLboolean _glfwSetVideoMode(_GLFWmonitor* monitor, const GLFWvidmode* desired) monitor->ns.previousMode = CGDisplayCopyDisplayMode(monitor->ns.displayID); CGDisplayFadeReservationToken token = beginFadeReservation(); - CGDisplayCapture(monitor->ns.displayID); CGDisplaySetDisplayMode(monitor->ns.displayID, native, NULL); endFadeReservation(token); } @@ -231,7 +230,6 @@ void _glfwRestoreVideoMode(_GLFWmonitor* monitor) CGDisplayFadeReservationToken token = beginFadeReservation(); CGDisplaySetDisplayMode(monitor->ns.displayID, monitor->ns.previousMode, NULL); - CGDisplayRelease(monitor->ns.displayID); endFadeReservation(token); CGDisplayModeRelease(monitor->ns.previousMode); diff --git a/glfw/src/cocoa_platform.h b/glfw/src/cocoa_platform.h index 6b768c7..6aafa32 100644 --- a/glfw/src/cocoa_platform.h +++ b/glfw/src/cocoa_platform.h @@ -62,7 +62,6 @@ typedef struct _GLFWwindowNS id delegate; id view; unsigned int modifierFlags; - int cursorInside; } _GLFWwindowNS; @@ -72,10 +71,10 @@ typedef struct _GLFWwindowNS typedef struct _GLFWlibraryNS { CGEventSourceRef eventSource; - id delegate; id autoreleasePool; id cursor; + short int publicKeys[256]; char* clipboardString; } _GLFWlibraryNS; diff --git a/glfw/src/cocoa_window.m b/glfw/src/cocoa_window.m index a804d6d..7c04af9 100644 --- a/glfw/src/cocoa_window.m +++ b/glfw/src/cocoa_window.m @@ -32,6 +32,29 @@ #include <crt_externs.h> +// Returns the specified standard cursor +// +static NSCursor* getStandardCursor(int shape) +{ + switch (shape) + { + case GLFW_ARROW_CURSOR: + return [NSCursor arrowCursor]; + case GLFW_IBEAM_CURSOR: + return [NSCursor IBeamCursor]; + case GLFW_CROSSHAIR_CURSOR: + return [NSCursor crosshairCursor]; + case GLFW_HAND_CURSOR: + return [NSCursor pointingHandCursor]; + case GLFW_HRESIZE_CURSOR: + return [NSCursor resizeLeftRightCursor]; + case GLFW_VRESIZE_CURSOR: + return [NSCursor resizeUpDownCursor]; + } + + return nil; +} + // Center the cursor in the view of the window // static void centerCursor(_GLFWwindow *window) @@ -41,72 +64,42 @@ static void centerCursor(_GLFWwindow *window) _glfwPlatformSetCursorPos(window, width / 2.0, height / 2.0); } -// Get the cursor object that window uses in the specified cursor mode +// Update the cursor to match the specified cursor mode // -static NSCursor* getModeCursor(_GLFWwindow* window) +static void updateModeCursor(_GLFWwindow* window) { if (window->cursorMode == GLFW_CURSOR_NORMAL) { if (window->cursor) - return (NSCursor*) window->cursor->ns.object; + [(NSCursor*) window->cursor->ns.object set]; else - return [NSCursor arrowCursor]; + [[NSCursor arrowCursor] set]; } else - return (NSCursor*) _glfw.ns.cursor; -} - -// Update the cursor to match the specified cursor mode -// -static void updateModeCursor(_GLFWwindow* window) -{ - // This is required for the cursor to update if it's inside the window - [getModeCursor(window) set]; - - // This is required for the cursor to update if it's outside the window - [window->ns.object invalidateCursorRectsForView:window->ns.view]; + [(NSCursor*) _glfw.ns.cursor set]; } // Enter fullscreen mode // -static void enterFullscreenMode(_GLFWwindow* window) +static GLboolean enterFullscreenMode(_GLFWwindow* window) { - if ([window->ns.view isInFullScreenMode]) - return; - - _glfwSetVideoMode(window->monitor, &window->videoMode); + GLboolean status; - NSDictionary* options = [NSDictionary dictionaryWithObjectsAndKeys: - [NSNumber numberWithBool:NO], - NSFullScreenModeAllScreens, - nil]; + status = _glfwSetVideoMode(window->monitor, &window->videoMode); - [window->ns.view enterFullScreenMode:window->monitor->ns.screen - withOptions:options]; + // NOTE: The window is resized despite mode setting failure to make + // glfwSetWindowSize more robust + [window->ns.object setFrame:[window->monitor->ns.screen frame] + display:YES]; - // HACK: Synthesize focus event as window does not become key when the view - // is made full screen - // TODO: Remove this when moving to a full screen window - _glfwInputWindowFocus(window, GL_TRUE); + return status; } // Leave fullscreen mode // static void leaveFullscreenMode(_GLFWwindow* window) { - if (![window->ns.view isInFullScreenMode]) - return; - - // HACK: Synthesize focus event as window does not become key when the view - // is made full screen - // TODO: Remove this when moving to a full screen window - _glfwInputWindowFocus(window, GL_FALSE); - _glfwRestoreVideoMode(window->monitor); - - // Exit full screen after the video restore to avoid a nasty display - // flickering during the fade - [window->ns.view exitFullScreenModeWithOptions:nil]; } // Transforms the specified y-coordinate between the CG display and NS screen @@ -163,8 +156,6 @@ static NSRect convertRectToBacking(_GLFWwindow* window, NSRect contentRect) - (void)windowDidResize:(NSNotification *)notification { - [window->nsgl.context update]; - const NSRect contentRect = [window->ns.view frame]; const NSRect fbRect = convertRectToBacking(window, contentRect); @@ -178,8 +169,6 @@ static NSRect convertRectToBacking(_GLFWwindow* window, NSRect contentRect) - (void)windowDidMove:(NSNotification *)notification { - [window->nsgl.context update]; - int x, y; _glfwPlatformGetWindowPos(window, &x, &y); _glfwInputWindowPos(window, x, y); @@ -195,20 +184,23 @@ static NSRect convertRectToBacking(_GLFWwindow* window, NSRect contentRect) - (void)windowDidDeminiaturize:(NSNotification *)notification { - if (window->monitor) - enterFullscreenMode(window); - _glfwInputWindowIconify(window, GL_FALSE); } - (void)windowDidBecomeKey:(NSNotification *)notification { + if (window->monitor) + enterFullscreenMode(window); + _glfwInputWindowFocus(window, GL_TRUE); _glfwPlatformApplyCursorMode(window); } - (void)windowDidResignKey:(NSNotification *)notification { + if (window->monitor) + leaveFullscreenMode(window); + _glfwInputWindowFocus(window, GL_FALSE); } @@ -258,6 +250,13 @@ static NSRect convertRectToBacking(_GLFWwindow* window, NSRect contentRect) _glfwInputMonitorChange(); } +- (void)applicationDidFinishLaunching:(NSNotification *)notification +{ + [NSApp stop:nil]; + + _glfwPlatformPostEmptyEvent(); +} + @end // Translates OS X key modifiers into GLFW ones @@ -282,143 +281,10 @@ static int translateFlags(NSUInteger flags) // static int translateKey(unsigned int key) { - // Keyboard symbol translation table - static const unsigned int table[128] = - { - /* 00 */ GLFW_KEY_A, - /* 01 */ GLFW_KEY_S, - /* 02 */ GLFW_KEY_D, - /* 03 */ GLFW_KEY_F, - /* 04 */ GLFW_KEY_H, - /* 05 */ GLFW_KEY_G, - /* 06 */ GLFW_KEY_Z, - /* 07 */ GLFW_KEY_X, - /* 08 */ GLFW_KEY_C, - /* 09 */ GLFW_KEY_V, - /* 0a */ GLFW_KEY_WORLD_1, - /* 0b */ GLFW_KEY_B, - /* 0c */ GLFW_KEY_Q, - /* 0d */ GLFW_KEY_W, - /* 0e */ GLFW_KEY_E, - /* 0f */ GLFW_KEY_R, - /* 10 */ GLFW_KEY_Y, - /* 11 */ GLFW_KEY_T, - /* 12 */ GLFW_KEY_1, - /* 13 */ GLFW_KEY_2, - /* 14 */ GLFW_KEY_3, - /* 15 */ GLFW_KEY_4, - /* 16 */ GLFW_KEY_6, - /* 17 */ GLFW_KEY_5, - /* 18 */ GLFW_KEY_EQUAL, - /* 19 */ GLFW_KEY_9, - /* 1a */ GLFW_KEY_7, - /* 1b */ GLFW_KEY_MINUS, - /* 1c */ GLFW_KEY_8, - /* 1d */ GLFW_KEY_0, - /* 1e */ GLFW_KEY_RIGHT_BRACKET, - /* 1f */ GLFW_KEY_O, - /* 20 */ GLFW_KEY_U, - /* 21 */ GLFW_KEY_LEFT_BRACKET, - /* 22 */ GLFW_KEY_I, - /* 23 */ GLFW_KEY_P, - /* 24 */ GLFW_KEY_ENTER, - /* 25 */ GLFW_KEY_L, - /* 26 */ GLFW_KEY_J, - /* 27 */ GLFW_KEY_APOSTROPHE, - /* 28 */ GLFW_KEY_K, - /* 29 */ GLFW_KEY_SEMICOLON, - /* 2a */ GLFW_KEY_BACKSLASH, - /* 2b */ GLFW_KEY_COMMA, - /* 2c */ GLFW_KEY_SLASH, - /* 2d */ GLFW_KEY_N, - /* 2e */ GLFW_KEY_M, - /* 2f */ GLFW_KEY_PERIOD, - /* 30 */ GLFW_KEY_TAB, - /* 31 */ GLFW_KEY_SPACE, - /* 32 */ GLFW_KEY_GRAVE_ACCENT, - /* 33 */ GLFW_KEY_BACKSPACE, - /* 34 */ GLFW_KEY_UNKNOWN, - /* 35 */ GLFW_KEY_ESCAPE, - /* 36 */ GLFW_KEY_RIGHT_SUPER, - /* 37 */ GLFW_KEY_LEFT_SUPER, - /* 38 */ GLFW_KEY_LEFT_SHIFT, - /* 39 */ GLFW_KEY_CAPS_LOCK, - /* 3a */ GLFW_KEY_LEFT_ALT, - /* 3b */ GLFW_KEY_LEFT_CONTROL, - /* 3c */ GLFW_KEY_RIGHT_SHIFT, - /* 3d */ GLFW_KEY_RIGHT_ALT, - /* 3e */ GLFW_KEY_RIGHT_CONTROL, - /* 3f */ GLFW_KEY_UNKNOWN, /* Function */ - /* 40 */ GLFW_KEY_F17, - /* 41 */ GLFW_KEY_KP_DECIMAL, - /* 42 */ GLFW_KEY_UNKNOWN, - /* 43 */ GLFW_KEY_KP_MULTIPLY, - /* 44 */ GLFW_KEY_UNKNOWN, - /* 45 */ GLFW_KEY_KP_ADD, - /* 46 */ GLFW_KEY_UNKNOWN, - /* 47 */ GLFW_KEY_NUM_LOCK, /* Really KeypadClear... */ - /* 48 */ GLFW_KEY_UNKNOWN, /* VolumeUp */ - /* 49 */ GLFW_KEY_UNKNOWN, /* VolumeDown */ - /* 4a */ GLFW_KEY_UNKNOWN, /* Mute */ - /* 4b */ GLFW_KEY_KP_DIVIDE, - /* 4c */ GLFW_KEY_KP_ENTER, - /* 4d */ GLFW_KEY_UNKNOWN, - /* 4e */ GLFW_KEY_KP_SUBTRACT, - /* 4f */ GLFW_KEY_F18, - /* 50 */ GLFW_KEY_F19, - /* 51 */ GLFW_KEY_KP_EQUAL, - /* 52 */ GLFW_KEY_KP_0, - /* 53 */ GLFW_KEY_KP_1, - /* 54 */ GLFW_KEY_KP_2, - /* 55 */ GLFW_KEY_KP_3, - /* 56 */ GLFW_KEY_KP_4, - /* 57 */ GLFW_KEY_KP_5, - /* 58 */ GLFW_KEY_KP_6, - /* 59 */ GLFW_KEY_KP_7, - /* 5a */ GLFW_KEY_F20, - /* 5b */ GLFW_KEY_KP_8, - /* 5c */ GLFW_KEY_KP_9, - /* 5d */ GLFW_KEY_UNKNOWN, - /* 5e */ GLFW_KEY_UNKNOWN, - /* 5f */ GLFW_KEY_UNKNOWN, - /* 60 */ GLFW_KEY_F5, - /* 61 */ GLFW_KEY_F6, - /* 62 */ GLFW_KEY_F7, - /* 63 */ GLFW_KEY_F3, - /* 64 */ GLFW_KEY_F8, - /* 65 */ GLFW_KEY_F9, - /* 66 */ GLFW_KEY_UNKNOWN, - /* 67 */ GLFW_KEY_F11, - /* 68 */ GLFW_KEY_UNKNOWN, - /* 69 */ GLFW_KEY_F13, - /* 6a */ GLFW_KEY_F16, - /* 6b */ GLFW_KEY_F14, - /* 6c */ GLFW_KEY_UNKNOWN, - /* 6d */ GLFW_KEY_F10, - /* 6e */ GLFW_KEY_UNKNOWN, - /* 6f */ GLFW_KEY_F12, - /* 70 */ GLFW_KEY_UNKNOWN, - /* 71 */ GLFW_KEY_F15, - /* 72 */ GLFW_KEY_INSERT, /* Really Help... */ - /* 73 */ GLFW_KEY_HOME, - /* 74 */ GLFW_KEY_PAGE_UP, - /* 75 */ GLFW_KEY_DELETE, - /* 76 */ GLFW_KEY_F4, - /* 77 */ GLFW_KEY_END, - /* 78 */ GLFW_KEY_F2, - /* 79 */ GLFW_KEY_PAGE_DOWN, - /* 7a */ GLFW_KEY_F1, - /* 7b */ GLFW_KEY_LEFT, - /* 7c */ GLFW_KEY_RIGHT, - /* 7d */ GLFW_KEY_DOWN, - /* 7e */ GLFW_KEY_UP, - /* 7f */ GLFW_KEY_UNKNOWN, - }; - - if (key >= 128) + if (key >= sizeof(_glfw.ns.publicKeys) / sizeof(_glfw.ns.publicKeys[0])) return GLFW_KEY_UNKNOWN; - return table[key]; + return _glfw.ns.publicKeys[key]; } @@ -426,7 +292,7 @@ static int translateKey(unsigned int key) // Content view class for the GLFW window //------------------------------------------------------------------------ -@interface GLFWContentView : NSView +@interface GLFWContentView : NSOpenGLView { _GLFWwindow* window; NSTrackingArea* trackingArea; @@ -454,7 +320,8 @@ static int translateKey(unsigned int key) - (id)initWithGlfwWindow:(_GLFWwindow *)initWindow { - self = [super init]; + self = [super initWithFrame:NSMakeRect(0, 0, 1, 1) + pixelFormat:nil]; if (self != nil) { window = initWindow; @@ -572,13 +439,11 @@ static int translateKey(unsigned int key) - (void)mouseExited:(NSEvent *)event { - window->ns.cursorInside = GL_FALSE; _glfwInputCursorEnter(window, GL_FALSE); } - (void)mouseEntered:(NSEvent *)event { - window->ns.cursorInside = GL_TRUE; _glfwInputCursorEnter(window, GL_TRUE); } @@ -598,10 +463,12 @@ static int translateKey(unsigned int key) [trackingArea release]; } - NSTrackingAreaOptions options = NSTrackingMouseEnteredAndExited | - NSTrackingActiveInKeyWindow | - NSTrackingCursorUpdate | - NSTrackingInVisibleRect; + const NSTrackingAreaOptions options = NSTrackingMouseEnteredAndExited | + NSTrackingActiveInKeyWindow | + NSTrackingEnabledDuringMouseDrag | + NSTrackingCursorUpdate | + NSTrackingInVisibleRect | + NSTrackingAssumeInside; trackingArea = [[NSTrackingArea alloc] initWithRect:[self bounds] options:options @@ -624,7 +491,13 @@ static int translateKey(unsigned int key) const int plain = !(mods & GLFW_MOD_SUPER); for (i = 0; i < length; i++) - _glfwInputChar(window, [characters characterAtIndex:i], mods, plain); + { + const unichar codepoint = [characters characterAtIndex:i]; + if ((codepoint & 0xff00) == 0xf700) + continue; + + _glfwInputChar(window, codepoint, mods, plain); + } } - (void)flagsChanged:(NSEvent *)event @@ -686,11 +559,6 @@ static int translateKey(unsigned int key) _glfwInputScroll(window, deltaX, deltaY); } -- (void)resetCursorRects -{ - [self addCursorRect:[self bounds] cursor:getModeCursor(window)]; -} - - (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender { if ((NSDragOperationGeneric & [sender draggingSourceOperationMask]) @@ -925,7 +793,18 @@ static GLboolean initializeAppKit(void) createMenuBar(); #endif - [NSApp finishLaunching]; + // There can only be one application delegate, but we allocate it the + // first time a window is created to keep all window code in this file + id delegate = [[GLFWApplicationDelegate alloc] init]; + if (delegate == nil) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Cocoa: Failed to create application delegate"); + return GL_FALSE; + } + + [NSApp setDelegate:delegate]; + [NSApp run]; return GL_TRUE; } @@ -956,8 +835,15 @@ static GLboolean createWindow(_GLFWwindow* window, styleMask |= NSResizableWindowMask; } + NSRect contentRect; + + if (wndconfig->monitor) + contentRect = [wndconfig->monitor->ns.screen frame]; + else + contentRect = NSMakeRect(0, 0, wndconfig->width, wndconfig->height); + window->ns.object = [[GLFWWindow alloc] - initWithContentRect:NSMakeRect(0, 0, wndconfig->width, wndconfig->height) + initWithContentRect:contentRect styleMask:styleMask backing:NSBackingStoreBuffered defer:NO]; @@ -968,28 +854,30 @@ static GLboolean createWindow(_GLFWwindow* window, return GL_FALSE; } - window->ns.view = [[GLFWContentView alloc] initWithGlfwWindow:window]; - #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_6) { -#if defined(_GLFW_USE_RETINA) - [window->ns.view setWantsBestResolutionOpenGLSurface:YES]; -#endif - if (wndconfig->resizable) [window->ns.object setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary]; } #endif /*MAC_OS_X_VERSION_MAX_ALLOWED*/ - if (wndconfig->floating) - [window->ns.object setLevel:NSFloatingWindowLevel]; + if (wndconfig->monitor) + { + [window->ns.object setLevel:NSMainMenuWindowLevel + 1]; + [window->ns.object setHidesOnDeactivate:YES]; + } + else + { + [window->ns.object center]; + + if (wndconfig->floating) + [window->ns.object setLevel:NSFloatingWindowLevel]; + } [window->ns.object setTitle:[NSString stringWithUTF8String:wndconfig->title]]; - [window->ns.object setContentView:window->ns.view]; [window->ns.object setDelegate:window->ns.delegate]; [window->ns.object setAcceptsMouseMovedEvents:YES]; - [window->ns.object center]; #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_6) @@ -1012,31 +900,36 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window, if (!initializeAppKit()) return GL_FALSE; - // There can only be one application delegate, but we allocate it the - // first time a window is created to keep all window code in this file - if (_glfw.ns.delegate == nil) - { - _glfw.ns.delegate = [[GLFWApplicationDelegate alloc] init]; - if (_glfw.ns.delegate == nil) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "Cocoa: Failed to create application delegate"); - return GL_FALSE; - } - - [NSApp setDelegate:_glfw.ns.delegate]; - } - if (!createWindow(window, wndconfig)) return GL_FALSE; if (!_glfwCreateContext(window, ctxconfig, fbconfig)) return GL_FALSE; + window->ns.view = [[GLFWContentView alloc] initWithGlfwWindow:window]; + +#if defined(_GLFW_USE_RETINA) +#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 + if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_6) + [window->ns.view setWantsBestResolutionOpenGLSurface:YES]; +#endif /*MAC_OS_X_VERSION_MAX_ALLOWED*/ +#endif /*_GLFW_USE_RETINA*/ + + [window->ns.object setContentView:window->ns.view]; + // NOTE: If you set the pixel format before the context it creates another + // context, only to have it destroyed by the next line + // We cannot use the view to create the context because that interface + // does not support context resource sharing + [window->ns.view setOpenGLContext:window->nsgl.context]; + [window->ns.view setPixelFormat:window->nsgl.pixelFormat]; [window->nsgl.context setView:window->ns.view]; if (wndconfig->monitor) - enterFullscreenMode(window); + { + _glfwPlatformShowWindow(window); + if (!enterFullscreenMode(window)) + return GL_FALSE; + } return GL_TRUE; } @@ -1132,9 +1025,6 @@ void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window, void _glfwPlatformIconifyWindow(_GLFWwindow* window) { - if (window->monitor) - leaveFullscreenMode(window); - [window->ns.object miniaturize:nil]; } @@ -1152,7 +1042,6 @@ void _glfwPlatformShowWindow(_GLFWwindow* window) [NSApp activateIgnoringOtherApps:YES]; [window->ns.object makeKeyAndOrderFront:nil]; - _glfwInputWindowVisibility(window, GL_TRUE); } void _glfwPlatformUnhideWindow(_GLFWwindow* window) @@ -1288,6 +1177,19 @@ int _glfwPlatformCreateCursor(_GLFWcursor* cursor, return GL_TRUE; } +int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape) +{ + cursor->ns.object = getStandardCursor(shape); + if (!cursor->ns.object) + { + _glfwInputError(GLFW_INVALID_ENUM, "Cocoa: Invalid standard cursor"); + return GL_FALSE; + } + + [cursor->ns.object retain]; + return GL_TRUE; +} + void _glfwPlatformDestroyCursor(_GLFWcursor* cursor) { if (cursor->ns.object) @@ -1296,7 +1198,10 @@ void _glfwPlatformDestroyCursor(_GLFWcursor* cursor) void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor) { - if (window->cursorMode == GLFW_CURSOR_NORMAL && window->ns.cursorInside) + const NSPoint p = [window->ns.object mouseLocationOutsideOfEventStream]; + + if (window->cursorMode == GLFW_CURSOR_NORMAL && + [window->ns.view mouse:p inRect:[window->ns.view frame]]) { if (cursor) [(NSCursor*) cursor->ns.object set]; diff --git a/glfw/src/glfw_config.h.in b/glfw/src/glfw_config.h.in index 11c2aa7..485cac5 100644 --- a/glfw/src/glfw_config.h.in +++ b/glfw/src/glfw_config.h.in @@ -42,6 +42,8 @@ #cmakedefine _GLFW_COCOA // Define this to 1 if building GLFW for Wayland #cmakedefine _GLFW_WAYLAND +// Define this to 1 if building GLFW for Mir +#cmakedefine _GLFW_MIR // Define this to 1 if building GLFW for EGL #cmakedefine _GLFW_EGL diff --git a/glfw/src/init.c b/glfw/src/init.c index 7e5204a..4a044ed 100644 --- a/glfw/src/init.c +++ b/glfw/src/init.c @@ -129,7 +129,7 @@ GLFWAPI int glfwInit(void) } _glfw.monitors = _glfwPlatformGetMonitors(&_glfw.monitorCount); - if (_glfw.monitors == NULL) + if (!_glfw.monitorCount) { _glfwInputError(GLFW_PLATFORM_ERROR, "No monitors found"); _glfwPlatformTerminate(); @@ -153,11 +153,9 @@ GLFWAPI void glfwTerminate(void) memset(&_glfw.callbacks, 0, sizeof(_glfw.callbacks)); - // Close all remaining windows while (_glfw.windowListHead) glfwDestroyWindow((GLFWwindow*) _glfw.windowListHead); - // Destroy all cursors while (_glfw.cursorListHead) glfwDestroyCursor((GLFWcursor*) _glfw.cursorListHead); diff --git a/glfw/src/input.c b/glfw/src/input.c index a2d8ddc..b1ed02f 100644 --- a/glfw/src/input.c +++ b/glfw/src/input.c @@ -382,6 +382,25 @@ GLFWAPI GLFWcursor* glfwCreateCursor(const GLFWimage* image, int xhot, int yhot) return (GLFWcursor*) cursor; } +GLFWAPI GLFWcursor* glfwCreateStandardCursor(int shape) +{ + _GLFWcursor* cursor; + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + + cursor = calloc(1, sizeof(_GLFWcursor)); + cursor->next = _glfw.cursorListHead; + _glfw.cursorListHead = cursor; + + if (!_glfwPlatformCreateStandardCursor(cursor, shape)) + { + glfwDestroyCursor((GLFWcursor*) cursor); + return NULL; + } + + return (GLFWcursor*) cursor; +} + GLFWAPI void glfwDestroyCursor(GLFWcursor* handle) { _GLFWcursor* cursor = (_GLFWcursor*) handle; diff --git a/glfw/src/internal.h b/glfw/src/internal.h index 62504e4..26fcf2a 100644 --- a/glfw/src/internal.h +++ b/glfw/src/internal.h @@ -74,6 +74,8 @@ typedef struct _GLFWcursor _GLFWcursor; #include "x11_platform.h" #elif defined(_GLFW_WAYLAND) #include "wl_platform.h" +#elif defined(_GLFW_MIR) + #include "mir_platform.h" #else #error "No supported window creation API selected" #endif @@ -623,6 +625,11 @@ GLFWglproc _glfwPlatformGetProcAddress(const char* procname); */ int _glfwPlatformCreateCursor(_GLFWcursor* cursor, const GLFWimage* image, int xhot, int yhot); +/*! @copydoc glfwCreateStandardCursor + * @ingroup platform + */ +int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape); + /*! @copydoc glfwDestroyCursor * @ingroup platform */ diff --git a/glfw/src/linux_joystick.c b/glfw/src/linux_joystick.c index c0c4b3d..c93184e 100644 --- a/glfw/src/linux_joystick.c +++ b/glfw/src/linux_joystick.c @@ -27,14 +27,14 @@ #include "internal.h" -#ifdef __linux__ +#if defined(__linux__) #include <linux/joystick.h> #include <sys/types.h> #include <sys/stat.h> +#include <sys/inotify.h> #include <fcntl.h> #include <errno.h> -#include <regex.h> #include <dirent.h> #include <stdio.h> #include <stdlib.h> @@ -45,16 +45,34 @@ // Attempt to open the specified joystick device // -static int openJoystickDevice(int joy, const char* path) +static void openJoystickDevice(const char* path) { -#ifdef __linux__ +#if defined(__linux__) char axisCount, buttonCount; char name[256]; - int fd, version; + int joy, fd, version; + + for (joy = GLFW_JOYSTICK_1; joy <= GLFW_JOYSTICK_LAST; joy++) + { + if (!_glfw.linux_js[joy].present) + continue; + + if (strcmp(_glfw.linux_js[joy].path, path) == 0) + return; + } + + for (joy = GLFW_JOYSTICK_1; joy <= GLFW_JOYSTICK_LAST; joy++) + { + if (!_glfw.linux_js[joy].present) + break; + } + + if (joy > GLFW_JOYSTICK_LAST) + return; fd = open(path, O_RDONLY | O_NONBLOCK); if (fd == -1) - return GL_FALSE; + return; _glfw.linux_js[joy].fd = fd; @@ -64,13 +82,14 @@ static int openJoystickDevice(int joy, const char* path) { // It's an old 0.x interface (we don't support it) close(fd); - return GL_FALSE; + return; } if (ioctl(fd, JSIOCGNAME(sizeof(name)), name) < 0) strncpy(name, "Unknown", sizeof(name)); _glfw.linux_js[joy].name = strdup(name); + _glfw.linux_js[joy].path = strdup(path); ioctl(fd, JSIOCGAXES, &axisCount); _glfw.linux_js[joy].axisCount = (int) axisCount; @@ -83,18 +102,34 @@ static int openJoystickDevice(int joy, const char* path) _glfw.linux_js[joy].present = GL_TRUE; #endif // __linux__ - - return GL_TRUE; } // Polls for and processes events for all present joysticks // static void pollJoystickEvents(void) { -#ifdef __linux__ +#if defined(__linux__) int i; - ssize_t result; struct js_event e; + ssize_t offset = 0; + char buffer[16384]; + + const ssize_t size = read(_glfw.x11.inotify.fd, buffer, sizeof(buffer)); + + while (size > offset) + { + regmatch_t match; + const struct inotify_event* e = (struct inotify_event*) (buffer + offset); + + if (regexec(&_glfw.x11.inotify.regex, e->name, 1, &match, 0) == 0) + { + char path[20]; + snprintf(path, sizeof(path), "/dev/input/%s", e->name); + openJoystickDevice(path); + } + + offset += sizeof(struct inotify_event) + e->len; + } for (i = 0; i <= GLFW_JOYSTICK_LAST; i++) { @@ -105,19 +140,22 @@ static void pollJoystickEvents(void) for (;;) { errno = 0; - result = read(_glfw.linux_js[i].fd, &e, sizeof(e)); - - if (errno == ENODEV) + if (read(_glfw.linux_js[i].fd, &e, sizeof(e)) < 0) { - free(_glfw.linux_js[i].axes); - free(_glfw.linux_js[i].buttons); - free(_glfw.linux_js[i].name); + if (errno == ENODEV) + { + // The joystick was disconnected - memset(&_glfw.linux_js[i], 0, sizeof(_glfw.linux_js[i])); - } + free(_glfw.linux_js[i].axes); + free(_glfw.linux_js[i].buttons); + free(_glfw.linux_js[i].name); + free(_glfw.linux_js[i].path); + + memset(&_glfw.linux_js[i], 0, sizeof(_glfw.linux_js[i])); + } - if (result == -1) break; + } // We don't care if it's an init event or not e.type &= ~JS_EVENT_INIT; @@ -149,58 +187,69 @@ static void pollJoystickEvents(void) // Initialize joystick interface // -void _glfwInitJoysticks(void) +int _glfwInitJoysticks(void) { -#ifdef __linux__ - int joy = 0; - size_t i; - regex_t regex; +#if defined(__linux__) + const char* dirname = "/dev/input"; DIR* dir; - const char* dirs[] = - { - "/dev/input", - "/dev" - }; + struct dirent* entry; - if (regcomp(®ex, "^js[0-9]\\+$", 0) != 0) + _glfw.x11.inotify.fd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC); + if (_glfw.x11.inotify.fd == -1) { - _glfwInputError(GLFW_PLATFORM_ERROR, "X11: Failed to compile regex"); - return; + _glfwInputError(GLFW_PLATFORM_ERROR, "X11: Failed to initialize inotify"); + return GL_FALSE; } - for (i = 0; i < sizeof(dirs) / sizeof(dirs[0]); i++) + // HACK: Register for IN_ATTRIB as well to get notified when udev is done + // This works well in practice but the true way is libudev + + _glfw.x11.inotify.wd = inotify_add_watch(_glfw.x11.inotify.fd, + dirname, + IN_CREATE | IN_ATTRIB); + if (_glfw.x11.inotify.wd == -1) { - struct dirent* entry; + _glfwInputError(GLFW_PLATFORM_ERROR, + "X11: Failed to add watch to %s", dirname); + return GL_FALSE; + } - dir = opendir(dirs[i]); - if (!dir) - continue; + if (regcomp(&_glfw.x11.inotify.regex, "^js[0-9]\\+$", 0) != 0) + { + _glfwInputError(GLFW_PLATFORM_ERROR, "X11: Failed to compile regex"); + return GL_FALSE; + } - while ((entry = readdir(dir))) - { - char path[20]; - regmatch_t match; + dir = opendir(dirname); + if (!dir) + { + _glfwInputError(GLFW_PLATFORM_ERROR, "X11: Failed to open %s", dirname); + return GL_FALSE; + } - if (regexec(®ex, entry->d_name, 1, &match, 0) != 0) - continue; + while ((entry = readdir(dir))) + { + char path[20]; + regmatch_t match; - snprintf(path, sizeof(path), "%s/%s", dirs[i], entry->d_name); - if (openJoystickDevice(joy, path)) - joy++; - } + if (regexec(&_glfw.x11.inotify.regex, entry->d_name, 1, &match, 0) != 0) + continue; - closedir(dir); + snprintf(path, sizeof(path), "%s/%s", dirname, entry->d_name); + openJoystickDevice(path); } - regfree(®ex); + closedir(dir); #endif // __linux__ + + return GL_TRUE; } // Close all opened joystick handles // void _glfwTerminateJoysticks(void) { -#ifdef __linux__ +#if defined(__linux__) int i; for (i = 0; i <= GLFW_JOYSTICK_LAST; i++) @@ -211,8 +260,17 @@ void _glfwTerminateJoysticks(void) free(_glfw.linux_js[i].axes); free(_glfw.linux_js[i].buttons); free(_glfw.linux_js[i].name); + free(_glfw.linux_js[i].path); } } + + regfree(&_glfw.x11.inotify.regex); + + if (_glfw.x11.inotify.wd > 0) + close(_glfw.x11.inotify.wd); + + if (_glfw.x11.inotify.fd > 0) + close(_glfw.x11.inotify.fd); #endif // __linux__ } diff --git a/glfw/src/linux_joystick.h b/glfw/src/linux_joystick.h index 8f713d8..b74a67e 100644 --- a/glfw/src/linux_joystick.h +++ b/glfw/src/linux_joystick.h @@ -42,10 +42,11 @@ typedef struct _GLFWjoystickLinux unsigned char* buttons; int buttonCount; char* name; + char* path; } _GLFWjoystickLinux; -void _glfwInitJoysticks(void); +int _glfwInitJoysticks(void); void _glfwTerminateJoysticks(void); #endif // _linux_joystick_h_ diff --git a/glfw/src/mir_init.c b/glfw/src/mir_init.c new file mode 100644 index 0000000..fe02e62 --- /dev/null +++ b/glfw/src/mir_init.c @@ -0,0 +1,96 @@ +//======================================================================== +// GLFW 3.1 Mir - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2014 Brandon Schaefer <brandon.schaefer@canonical.com> +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + +#include <stdlib.h> + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +int _glfwPlatformInit(void) +{ + int error; + + _glfw.mir.connection = mir_connect_sync(NULL, __PRETTY_FUNCTION__); + + if (!mir_connection_is_valid(_glfw.mir.connection)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unable to connect to Server"); + return GL_FALSE; + } + + _glfw.mir.display = + mir_connection_get_egl_native_display(_glfw.mir.connection); + + if (!_glfwInitContextAPI()) + return GL_FALSE; + + _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; +} + +void _glfwPlatformTerminate(void) +{ + _glfwTerminateContextAPI(); + _glfwTerminateJoysticks(); + + _glfwDeleteEventQueue(_glfw.mir.event_queue); + + pthread_mutex_destroy(&_glfw.mir.event_mutex); + + mir_connection_release(_glfw.mir.connection); +} + +const char* _glfwPlatformGetVersionString(void) +{ + const char* version = _GLFW_VERSION_NUMBER " Mir EGL " +#if defined(_POSIX_TIMERS) && defined(_POSIX_MONOTONIC_CLOCK) + " clock_gettime" +#endif +#if defined(_GLFW_BUILD_DLL) + " shared" +#endif + ; + + return version; +} + diff --git a/glfw/src/mir_monitor.c b/glfw/src/mir_monitor.c new file mode 100644 index 0000000..bdf47bd --- /dev/null +++ b/glfw/src/mir_monitor.c @@ -0,0 +1,138 @@ +//======================================================================== +// GLFW 3.1 Mir - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2014 Brandon Schaefer <brandon.schaefer@canonical.com> +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + +#include <stdlib.h> + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +_GLFWmonitor** _glfwPlatformGetMonitors(int* count) +{ + int i, found = 0; + _GLFWmonitor** monitors = NULL; + MirDisplayConfiguration* displayConfig = + mir_connection_create_display_config(_glfw.mir.connection); + + *count = 0; + + for (i = 0; i < displayConfig->num_outputs; i++) + { + const MirDisplayOutput* out = displayConfig->outputs + i; + + if (out->used && + out->connected && + out->num_modes && + out->current_mode < out->num_modes) + { + found++; + monitors = realloc(monitors, sizeof(_GLFWmonitor*) * found); + monitors[i] = _glfwAllocMonitor("Unknown", + out->physical_width_mm, + out->physical_height_mm); + + 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]->modes = _glfwPlatformGetVideoModes(monitors[i], + &monitors[i]->modeCount); + } + } + + mir_display_config_destroy(displayConfig); + + *count = found; + return monitors; +} + +GLboolean _glfwPlatformIsSameMonitor(_GLFWmonitor* first, _GLFWmonitor* second) +{ + return first->mir.output_id == second->mir.output_id; +} + +void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos) +{ + if (xpos) + *xpos = monitor->mir.x; + if (ypos) + *ypos = monitor->mir.y; +} + +GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* found) +{ + int i; + GLFWvidmode* modes = NULL; + MirDisplayConfiguration* displayConfig = + mir_connection_create_display_config(_glfw.mir.connection); + + for (i = 0; i < displayConfig->num_outputs; i++) + { + const MirDisplayOutput* out = displayConfig->outputs + i; + if (out->output_id != monitor->mir.output_id) + continue; + + modes = calloc(out->num_modes, sizeof(GLFWvidmode)); + + for (*found = 0; *found < out->num_modes; (*found)++) + { + modes[*found].width = out->modes[*found].horizontal_resolution; + modes[*found].height = out->modes[*found].vertical_resolution; + modes[*found].refreshRate = out->modes[*found].refresh_rate; + modes[*found].redBits = 8; + modes[*found].greenBits = 8; + modes[*found].blueBits = 8; + } + + break; + } + + mir_display_config_destroy(displayConfig); + + return modes; +} + +void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode) +{ + *mode = monitor->modes[monitor->mir.cur_mode]; +} + +void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported Function %s!", __PRETTY_FUNCTION__); +} + +void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported Function %s!", __PRETTY_FUNCTION__); +} + diff --git a/glfw/src/mir_platform.h b/glfw/src/mir_platform.h new file mode 100644 index 0000000..7d477e9 --- /dev/null +++ b/glfw/src/mir_platform.h @@ -0,0 +1,110 @@ +//======================================================================== +// GLFW 3.1 Mir - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2014 Brandon Schaefer <brandon.schaefer@canonical.com> +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#ifndef _mir_platform_h_ +#define _mir_platform_h_ + +#include <mir_toolkit/mir_client_library.h> + +#include "posix_tls.h" +#include "posix_time.h" +#include "linux_joystick.h" + +#include <sys/queue.h> + +#include <pthread.h> + +#if defined(_GLFW_EGL) + #include "egl_context.h" +#else + #error "The Mir backend depends on EGL platform support" +#endif + +#define _GLFW_EGL_NATIVE_WINDOW window->mir.window +#define _GLFW_EGL_NATIVE_DISPLAY _glfw.mir.display + +#define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowMir mir +#define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorMir mir +#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 +// +typedef struct _GLFWwindowMir +{ + MirSurface* surface; + int width; + int height; + MirEGLNativeWindowType window; + +} _GLFWwindowMir; + + +// Mir-specific per-monitor data +// +typedef struct _GLFWmonitorMir +{ + int cur_mode; + int output_id; + int x; + int y; + +} _GLFWmonitorMir; + + +// Mir-specific global data +// +typedef struct _GLFWlibraryMir +{ + MirConnection* connection; + MirEGLNativeDisplayType display; + EventQueue* event_queue; + + pthread_mutex_t event_mutex; + pthread_cond_t event_cond; + +} _GLFWlibraryMir; + + +// Mir-specific per-cursor data +// TODO: Only system cursors are implemented in mir atm. Need to wait for support. +// +typedef struct _GLFWcursorMir +{ +} _GLFWcursorMir; + + +extern void _glfwInitEventQueue(EventQueue* queue); +extern void _glfwDeleteEventQueue(EventQueue* queue); + +#endif // _mir_platform_h_ diff --git a/glfw/src/mir_window.c b/glfw/src/mir_window.c new file mode 100644 index 0000000..2c8547f --- /dev/null +++ b/glfw/src/mir_window.c @@ -0,0 +1,658 @@ +//======================================================================== +// GLFW 3.1 Mir - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2014 Brandon Schaefer <brandon.schaefer@canonical.com> +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" +#include "xkb_unicode.h" + +#include <linux/input.h> +#include <stdlib.h> +#include <string.h> + + +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; + MirPixelFormat formats[size]; + + mir_connection_get_available_surface_formats(_glfw.mir.connection, formats, + size, &validFormats); + + for (i = 0; i < validFormats; i++) + { + if (formats[i] == mir_pixel_format_abgr_8888 || + formats[i] == mir_pixel_format_xbgr_8888 || + formats[i] == mir_pixel_format_argb_8888 || + formats[i] == mir_pixel_format_xrgb_8888) + { + return formats[i]; + } + } + + return mir_pixel_format_invalid; +} + +static int mirModToGLFWMod(uint32_t mods) +{ + int publicMods = 0x0; + + if (mods & mir_key_modifier_alt) + publicMods |= GLFW_MOD_ALT; + else if (mods & mir_key_modifier_shift) + publicMods |= GLFW_MOD_SHIFT; + else if (mods & mir_key_modifier_ctrl) + publicMods |= GLFW_MOD_CONTROL; + else if (mods & mir_key_modifier_meta) + publicMods |= GLFW_MOD_SUPER; + + return publicMods; +} + +// Taken from wl_init.c +static int toGLFWKeyCode(uint32_t key) +{ + switch (key) + { + case KEY_GRAVE: return GLFW_KEY_GRAVE_ACCENT; + case KEY_1: return GLFW_KEY_1; + case KEY_2: return GLFW_KEY_2; + case KEY_3: return GLFW_KEY_3; + case KEY_4: return GLFW_KEY_4; + case KEY_5: return GLFW_KEY_5; + case KEY_6: return GLFW_KEY_6; + case KEY_7: return GLFW_KEY_7; + case KEY_8: return GLFW_KEY_8; + case KEY_9: return GLFW_KEY_9; + case KEY_0: return GLFW_KEY_0; + case KEY_MINUS: return GLFW_KEY_MINUS; + case KEY_EQUAL: return GLFW_KEY_EQUAL; + case KEY_Q: return GLFW_KEY_Q; + case KEY_W: return GLFW_KEY_W; + case KEY_E: return GLFW_KEY_E; + case KEY_R: return GLFW_KEY_R; + case KEY_T: return GLFW_KEY_T; + case KEY_Y: return GLFW_KEY_Y; + case KEY_U: return GLFW_KEY_U; + case KEY_I: return GLFW_KEY_I; + case KEY_O: return GLFW_KEY_O; + case KEY_P: return GLFW_KEY_P; + case KEY_LEFTBRACE: return GLFW_KEY_LEFT_BRACKET; + case KEY_RIGHTBRACE: return GLFW_KEY_RIGHT_BRACKET; + case KEY_A: return GLFW_KEY_A; + case KEY_S: return GLFW_KEY_S; + case KEY_D: return GLFW_KEY_D; + case KEY_F: return GLFW_KEY_F; + case KEY_G: return GLFW_KEY_G; + case KEY_H: return GLFW_KEY_H; + case KEY_J: return GLFW_KEY_J; + case KEY_K: return GLFW_KEY_K; + case KEY_L: return GLFW_KEY_L; + case KEY_SEMICOLON: return GLFW_KEY_SEMICOLON; + case KEY_APOSTROPHE: return GLFW_KEY_APOSTROPHE; + case KEY_Z: return GLFW_KEY_Z; + case KEY_X: return GLFW_KEY_X; + case KEY_C: return GLFW_KEY_C; + case KEY_V: return GLFW_KEY_V; + case KEY_B: return GLFW_KEY_B; + case KEY_N: return GLFW_KEY_N; + case KEY_M: return GLFW_KEY_M; + case KEY_COMMA: return GLFW_KEY_COMMA; + case KEY_DOT: return GLFW_KEY_PERIOD; + case KEY_SLASH: return GLFW_KEY_SLASH; + case KEY_BACKSLASH: return GLFW_KEY_BACKSLASH; + case KEY_ESC: return GLFW_KEY_ESCAPE; + case KEY_TAB: return GLFW_KEY_TAB; + case KEY_LEFTSHIFT: return GLFW_KEY_LEFT_SHIFT; + case KEY_RIGHTSHIFT: return GLFW_KEY_RIGHT_SHIFT; + case KEY_LEFTCTRL: return GLFW_KEY_LEFT_CONTROL; + case KEY_RIGHTCTRL: return GLFW_KEY_RIGHT_CONTROL; + case KEY_LEFTALT: return GLFW_KEY_LEFT_ALT; + case KEY_RIGHTALT: return GLFW_KEY_RIGHT_ALT; + case KEY_LEFTMETA: return GLFW_KEY_LEFT_SUPER; + case KEY_RIGHTMETA: return GLFW_KEY_RIGHT_SUPER; + case KEY_MENU: return GLFW_KEY_MENU; + case KEY_NUMLOCK: return GLFW_KEY_NUM_LOCK; + case KEY_CAPSLOCK: return GLFW_KEY_CAPS_LOCK; + case KEY_PRINT: return GLFW_KEY_PRINT_SCREEN; + case KEY_SCROLLLOCK: return GLFW_KEY_SCROLL_LOCK; + case KEY_PAUSE: return GLFW_KEY_PAUSE; + case KEY_DELETE: return GLFW_KEY_DELETE; + case KEY_BACKSPACE: return GLFW_KEY_BACKSPACE; + case KEY_ENTER: return GLFW_KEY_ENTER; + case KEY_HOME: return GLFW_KEY_HOME; + case KEY_END: return GLFW_KEY_END; + case KEY_PAGEUP: return GLFW_KEY_PAGE_UP; + case KEY_PAGEDOWN: return GLFW_KEY_PAGE_DOWN; + case KEY_INSERT: return GLFW_KEY_INSERT; + case KEY_LEFT: return GLFW_KEY_LEFT; + case KEY_RIGHT: return GLFW_KEY_RIGHT; + case KEY_DOWN: return GLFW_KEY_DOWN; + case KEY_UP: return GLFW_KEY_UP; + case KEY_F1: return GLFW_KEY_F1; + case KEY_F2: return GLFW_KEY_F2; + case KEY_F3: return GLFW_KEY_F3; + case KEY_F4: return GLFW_KEY_F4; + case KEY_F5: return GLFW_KEY_F5; + case KEY_F6: return GLFW_KEY_F6; + case KEY_F7: return GLFW_KEY_F7; + case KEY_F8: return GLFW_KEY_F8; + case KEY_F9: return GLFW_KEY_F9; + case KEY_F10: return GLFW_KEY_F10; + case KEY_F11: return GLFW_KEY_F11; + case KEY_F12: return GLFW_KEY_F12; + case KEY_F13: return GLFW_KEY_F13; + case KEY_F14: return GLFW_KEY_F14; + case KEY_F15: return GLFW_KEY_F15; + case KEY_F16: return GLFW_KEY_F16; + case KEY_F17: return GLFW_KEY_F17; + case KEY_F18: return GLFW_KEY_F18; + case KEY_F19: return GLFW_KEY_F19; + case KEY_F20: return GLFW_KEY_F20; + case KEY_F21: return GLFW_KEY_F21; + case KEY_F22: return GLFW_KEY_F22; + case KEY_F23: return GLFW_KEY_F23; + case KEY_F24: return GLFW_KEY_F24; + case KEY_KPSLASH: return GLFW_KEY_KP_DIVIDE; + case KEY_KPDOT: return GLFW_KEY_KP_MULTIPLY; + case KEY_KPMINUS: return GLFW_KEY_KP_SUBTRACT; + case KEY_KPPLUS: return GLFW_KEY_KP_ADD; + case KEY_KP0: return GLFW_KEY_KP_0; + case KEY_KP1: return GLFW_KEY_KP_1; + case KEY_KP2: return GLFW_KEY_KP_2; + case KEY_KP3: return GLFW_KEY_KP_3; + case KEY_KP4: return GLFW_KEY_KP_4; + case KEY_KP5: return GLFW_KEY_KP_5; + case KEY_KP6: return GLFW_KEY_KP_6; + case KEY_KP7: return GLFW_KEY_KP_7; + case KEY_KP8: return GLFW_KEY_KP_8; + case KEY_KP9: return GLFW_KEY_KP_9; + case KEY_KPCOMMA: return GLFW_KEY_KP_DECIMAL; + case KEY_KPEQUAL: return GLFW_KEY_KP_EQUAL; + case KEY_KPENTER: return GLFW_KEY_KP_ENTER; + default: return GLFW_KEY_UNKNOWN; + } +} + +static void handleKeyEvent(const MirKeyEvent key, _GLFWwindow* window) +{ + const int pressed = key.action == mir_key_action_up ? GLFW_RELEASE : GLFW_PRESS; + const int mods = mirModToGLFWMod(key.modifiers); + const long text = _glfwKeySym2Unicode(key.key_code); + const int plain = !(mods & (GLFW_MOD_CONTROL | GLFW_MOD_ALT)); + + _glfwInputKey(window, toGLFWKeyCode(key.scan_code), key.scan_code, pressed, mods); + + if (text != -1) + _glfwInputChar(window, text, mods, plain); +} + +static void handleMouseButton(_GLFWwindow* window, + int pressed, int mods, MirMotionButton button) +{ + static int lastButton; + int publicButton; + const int publicMods = mirModToGLFWMod(mods); + + switch (button) + { + case mir_motion_button_primary: + publicButton = GLFW_MOUSE_BUTTON_LEFT; + break; + case mir_motion_button_secondary: + publicButton = GLFW_MOUSE_BUTTON_RIGHT; + break; + case mir_motion_button_tertiary: + publicButton = GLFW_MOUSE_BUTTON_MIDDLE; + break; + case mir_motion_button_forward: + // FIXME What is the forward button? + publicButton = GLFW_MOUSE_BUTTON_4; + break; + case mir_motion_button_back: + // FIXME What is the back button? + publicButton = GLFW_MOUSE_BUTTON_5; + break; + default: + publicButton = lastButton; + break; + } + + lastButton = publicButton; + + _glfwInputMouseClick(window, publicButton, pressed, publicMods); +} + +static void handleMouseMotion(_GLFWwindow* window, int x, int y) +{ + _glfwInputCursorMotion(window, x, y); +} + +static void handleMouseScroll(_GLFWwindow* window, int dx, int dy) +{ + _glfwInputScroll(window, dx, dy); +} + +static void handleMouseEvent(const MirMotionEvent motion, + int cord_index, + _GLFWwindow* window) +{ + switch (motion.action) + { + case mir_motion_action_down: + case mir_motion_action_pointer_down: + handleMouseButton(window, GLFW_PRESS, + motion.modifiers, motion.button_state); + break; + case mir_motion_action_up: + case mir_motion_action_pointer_up: + handleMouseButton(window, GLFW_RELEASE, + motion.modifiers, motion.button_state); + break; + case mir_motion_action_hover_move: + case mir_motion_action_move: + handleMouseMotion(window, + motion.pointer_coordinates[cord_index].x, + motion.pointer_coordinates[cord_index].y); + break; + case mir_motion_action_outside: + break; + case mir_motion_action_scroll: + handleMouseScroll(window, + motion.pointer_coordinates[cord_index].hscroll, + motion.pointer_coordinates[cord_index].vscroll); + break; + case mir_motion_action_cancel: + case mir_motion_action_hover_enter: + case mir_motion_action_hover_exit: + break; + default: + break; + + } +} + +static void handleMotionEvent(const MirMotionEvent motion, _GLFWwindow* window) +{ + int i; + for (i = 0; i < motion.pointer_count; i++) + handleMouseEvent(motion, i, window); +} + +static void handleInput(MirEvent const* event, _GLFWwindow* window) +{ + switch (event->type) + { + case mir_event_type_key: + handleKeyEvent(event->key, window); + break; + case mir_event_type_motion: + 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 = + { + .name = "MirSurface", + .width = window->mir.width, + .height = window->mir.height, + .pixel_format = mir_pixel_format_invalid, + .buffer_usage = mir_buffer_usage_hardware, + .output_id = mir_display_output_id_invalid + }; + + MirEventDelegate delegate = + { + addNewEvent, + window + }; + + params.pixel_format = findValidPixelFormat(); + if (params.pixel_format == mir_pixel_format_invalid) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unable to find a correct pixel format"); + return GL_FALSE; + } + + window->mir.surface = + mir_connection_create_surface_sync(_glfw.mir.connection, ¶ms); + if (!mir_surface_is_valid(window->mir.surface)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unable to create surface"); + return GL_FALSE; + } + + mir_surface_set_event_handler(window->mir.surface, &delegate); + + return GL_TRUE; +} + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +void _glfwInitEventQueue(EventQueue* queue) +{ + TAILQ_INIT(&queue->head); +} + +void _glfwDeleteEventQueue(EventQueue* queue) +{ + if (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; + } + + free(queue); + } +} + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +int _glfwPlatformCreateWindow(_GLFWwindow* window, + const _GLFWwndconfig* wndconfig, + const _GLFWctxconfig* ctxconfig, + const _GLFWfbconfig* fbconfig) +{ + if (!_glfwCreateContext(window, ctxconfig, fbconfig)) + return GL_FALSE; + + if (wndconfig->monitor) + { + GLFWvidmode mode; + _glfwPlatformGetVideoMode(wndconfig->monitor, &mode); + + mir_surface_set_type(window->mir.surface, mir_surface_state_fullscreen); + + if (wndconfig->width > mode.width || wndconfig->height > mode.height) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Requested surface size is to large (%i %i)", + wndconfig->width, wndconfig->height); + + return GL_FALSE; + } + } + + window->mir.width = wndconfig->width; + window->mir.height = wndconfig->height; + + if (!createSurface(window)) + return GL_FALSE; + + window->mir.window = mir_surface_get_egl_native_window(window->mir.surface); + + return GL_TRUE; +} + +void _glfwPlatformDestroyWindow(_GLFWwindow* window) +{ + if (mir_surface_is_valid(window->mir.surface)) + { + mir_surface_release_sync(window->mir.surface); + window->mir.surface = NULL; + } + + _glfwDestroyContext(window); +} + +void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported Function %s!", __PRETTY_FUNCTION__); +} + +void _glfwPlatformSetWindowPos(_GLFWwindow* window, int xpos, int ypos) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported Function %s!", __PRETTY_FUNCTION__); +} + +void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window, + int* left, int* top, + int* right, int* bottom) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported Function %s!", __PRETTY_FUNCTION__); +} + +void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported Function %s!", __PRETTY_FUNCTION__); +} + +void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported Function %s!", __PRETTY_FUNCTION__); +} + +void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height) +{ + if (width) + *width = window->mir.width; + if (height) + *height = window->mir.height; +} + +void _glfwPlatformIconifyWindow(_GLFWwindow* window) +{ + mir_surface_set_type(window->mir.surface, mir_surface_state_minimized); +} + +void _glfwPlatformRestoreWindow(_GLFWwindow* window) +{ + mir_surface_set_type(window->mir.surface, mir_surface_state_restored); +} + +void _glfwPlatformHideWindow(_GLFWwindow* window) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported Function %s!", __PRETTY_FUNCTION__); +} + +void _glfwPlatformShowWindow(_GLFWwindow* window) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported Function %s!", __PRETTY_FUNCTION__); +} + +void _glfwPlatformUnhideWindow(_GLFWwindow* window) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported Function %s!", __PRETTY_FUNCTION__); +} + +void _glfwPlatformPollEvents(void) +{ + EventNode* node = NULL; + + while ((node = dequeueEvent(_glfw.mir.event_queue))) + { + handleInput(node->event, node->window); + deleteNode(_glfw.mir.event_queue, node); + } +} + +void _glfwPlatformWaitEvents(void) +{ + 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) +{ +} + +void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height) +{ + if (width) + *width = window->mir.width; + if (height) + *height = window->mir.height; +} + +int _glfwPlatformCreateCursor(_GLFWcursor* cursor, + const GLFWimage* image, + int xhot, int yhot) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported Function %s!", __PRETTY_FUNCTION__); + + return GL_FALSE; +} + +int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported Function %s!", __PRETTY_FUNCTION__); + + return GL_FALSE; +} + +void _glfwPlatformDestroyCursor(_GLFWcursor* cursor) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported Function %s!", __PRETTY_FUNCTION__); +} + +void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported Function %s!", __PRETTY_FUNCTION__); +} + +void _glfwPlatformSetCursorPos(_GLFWwindow* window, double xpos, double ypos) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported Function %s!", __PRETTY_FUNCTION__); +} + +void _glfwPlatformApplyCursorMode(_GLFWwindow* window) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported Function %s!", __PRETTY_FUNCTION__); +} + +void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported Function %s!", __PRETTY_FUNCTION__); +} + +const char* _glfwPlatformGetClipboardString(_GLFWwindow* window) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported Function %s!", __PRETTY_FUNCTION__); + + return NULL; +} + diff --git a/glfw/src/nsgl_context.m b/glfw/src/nsgl_context.m index cbdf284..9800977 100644 --- a/glfw/src/nsgl_context.m +++ b/glfw/src/nsgl_context.m @@ -124,13 +124,42 @@ int _glfwCreateContext(_GLFWwindow* window, // Arbitrary array size here NSOpenGLPixelFormatAttribute attributes[40]; + ADD_ATTR(NSOpenGLPFAAccelerated); ADD_ATTR(NSOpenGLPFAClosestPolicy); #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 - if (ctxconfig->major > 2) +#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101000 + if (ctxconfig->major >= 4) + { + ADD_ATTR2(NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion4_1Core); + } + else +#endif /*MAC_OS_X_VERSION_MAX_ALLOWED*/ + if (ctxconfig->major >= 3) + { ADD_ATTR2(NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core); + } #endif /*MAC_OS_X_VERSION_MAX_ALLOWED*/ + if (ctxconfig->major <= 2) + { + if (fbconfig->auxBuffers != GLFW_DONT_CARE) + ADD_ATTR2(NSOpenGLPFAAuxBuffers, fbconfig->auxBuffers); + + if (fbconfig->accumRedBits != GLFW_DONT_CARE && + fbconfig->accumGreenBits != GLFW_DONT_CARE && + fbconfig->accumBlueBits != GLFW_DONT_CARE && + fbconfig->accumAlphaBits != GLFW_DONT_CARE) + { + const int accumBits = fbconfig->accumRedBits + + fbconfig->accumGreenBits + + fbconfig->accumBlueBits + + fbconfig->accumAlphaBits; + + ADD_ATTR2(NSOpenGLPFAAccumSize, accumBits); + } + } + if (fbconfig->redBits != GLFW_DONT_CARE && fbconfig->greenBits != GLFW_DONT_CARE && fbconfig->blueBits != GLFW_DONT_CARE) @@ -157,22 +186,6 @@ int _glfwCreateContext(_GLFWwindow* window, if (fbconfig->stencilBits != GLFW_DONT_CARE) ADD_ATTR2(NSOpenGLPFAStencilSize, fbconfig->stencilBits); - if (fbconfig->accumRedBits != GLFW_DONT_CARE && - fbconfig->accumGreenBits != GLFW_DONT_CARE && - fbconfig->accumBlueBits != GLFW_DONT_CARE && - fbconfig->accumAlphaBits != GLFW_DONT_CARE) - { - const int accumBits = fbconfig->accumRedBits + - fbconfig->accumGreenBits + - fbconfig->accumBlueBits + - fbconfig->accumAlphaBits; - - ADD_ATTR2(NSOpenGLPFAAccumSize, accumBits); - } - - if (fbconfig->auxBuffers != GLFW_DONT_CARE) - ADD_ATTR2(NSOpenGLPFAAuxBuffers, fbconfig->auxBuffers); - if (fbconfig->stereo) ADD_ATTR(NSOpenGLPFAStereo); diff --git a/glfw/src/win32_init.c b/glfw/src/win32_init.c index 5b1c18b..a963689 100644 --- a/glfw/src/win32_init.c +++ b/glfw/src/win32_init.c @@ -41,7 +41,7 @@ // Applications exporting this symbol with this value will be automatically // directed to the high-performance GPU on nVidia Optimus systems // -GLFWAPI DWORD NvOptimusEnablement = 0x00000001; +__declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001; #endif // _GLFW_USE_OPTIMUS_HPG @@ -120,6 +120,134 @@ static void terminateLibraries(void) FreeLibrary(_glfw.win32.dwmapi.instance); } +// Create key code translation tables +// +static void createKeyTables(void) +{ + memset(_glfw.win32.publicKeys, -1, sizeof(_glfw.win32.publicKeys)); + + _glfw.win32.publicKeys[0x00B] = GLFW_KEY_0; + _glfw.win32.publicKeys[0x002] = GLFW_KEY_1; + _glfw.win32.publicKeys[0x003] = GLFW_KEY_2; + _glfw.win32.publicKeys[0x004] = GLFW_KEY_3; + _glfw.win32.publicKeys[0x005] = GLFW_KEY_4; + _glfw.win32.publicKeys[0x006] = GLFW_KEY_5; + _glfw.win32.publicKeys[0x007] = GLFW_KEY_6; + _glfw.win32.publicKeys[0x008] = GLFW_KEY_7; + _glfw.win32.publicKeys[0x009] = GLFW_KEY_8; + _glfw.win32.publicKeys[0x00A] = GLFW_KEY_9; + _glfw.win32.publicKeys[0x01E] = GLFW_KEY_A; + _glfw.win32.publicKeys[0x030] = GLFW_KEY_B; + _glfw.win32.publicKeys[0x02E] = GLFW_KEY_C; + _glfw.win32.publicKeys[0x020] = GLFW_KEY_D; + _glfw.win32.publicKeys[0x012] = GLFW_KEY_E; + _glfw.win32.publicKeys[0x021] = GLFW_KEY_F; + _glfw.win32.publicKeys[0x022] = GLFW_KEY_G; + _glfw.win32.publicKeys[0x023] = GLFW_KEY_H; + _glfw.win32.publicKeys[0x017] = GLFW_KEY_I; + _glfw.win32.publicKeys[0x024] = GLFW_KEY_J; + _glfw.win32.publicKeys[0x025] = GLFW_KEY_K; + _glfw.win32.publicKeys[0x026] = GLFW_KEY_L; + _glfw.win32.publicKeys[0x032] = GLFW_KEY_M; + _glfw.win32.publicKeys[0x031] = GLFW_KEY_N; + _glfw.win32.publicKeys[0x018] = GLFW_KEY_O; + _glfw.win32.publicKeys[0x019] = GLFW_KEY_P; + _glfw.win32.publicKeys[0x010] = GLFW_KEY_Q; + _glfw.win32.publicKeys[0x013] = GLFW_KEY_R; + _glfw.win32.publicKeys[0x01F] = GLFW_KEY_S; + _glfw.win32.publicKeys[0x014] = GLFW_KEY_T; + _glfw.win32.publicKeys[0x016] = GLFW_KEY_U; + _glfw.win32.publicKeys[0x02F] = GLFW_KEY_V; + _glfw.win32.publicKeys[0x011] = GLFW_KEY_W; + _glfw.win32.publicKeys[0x02D] = GLFW_KEY_X; + _glfw.win32.publicKeys[0x015] = GLFW_KEY_Y; + _glfw.win32.publicKeys[0x02C] = GLFW_KEY_Z; + + _glfw.win32.publicKeys[0x028] = GLFW_KEY_APOSTROPHE; + _glfw.win32.publicKeys[0x02B] = GLFW_KEY_BACKSLASH; + _glfw.win32.publicKeys[0x033] = GLFW_KEY_COMMA; + _glfw.win32.publicKeys[0x00D] = GLFW_KEY_EQUAL; + _glfw.win32.publicKeys[0x029] = GLFW_KEY_GRAVE_ACCENT; + _glfw.win32.publicKeys[0x01A] = GLFW_KEY_LEFT_BRACKET; + _glfw.win32.publicKeys[0x00C] = GLFW_KEY_MINUS; + _glfw.win32.publicKeys[0x034] = GLFW_KEY_PERIOD; + _glfw.win32.publicKeys[0x01B] = GLFW_KEY_RIGHT_BRACKET; + _glfw.win32.publicKeys[0x027] = GLFW_KEY_SEMICOLON; + _glfw.win32.publicKeys[0x035] = GLFW_KEY_SLASH; + _glfw.win32.publicKeys[0x056] = GLFW_KEY_WORLD_2; + + _glfw.win32.publicKeys[0x00E] = GLFW_KEY_BACKSPACE; + _glfw.win32.publicKeys[0x153] = GLFW_KEY_DELETE; + _glfw.win32.publicKeys[0x14F] = GLFW_KEY_END; + _glfw.win32.publicKeys[0x01C] = GLFW_KEY_ENTER; + _glfw.win32.publicKeys[0x001] = GLFW_KEY_ESCAPE; + _glfw.win32.publicKeys[0x147] = GLFW_KEY_HOME; + _glfw.win32.publicKeys[0x152] = GLFW_KEY_INSERT; + _glfw.win32.publicKeys[0x15D] = GLFW_KEY_MENU; + _glfw.win32.publicKeys[0x151] = GLFW_KEY_PAGE_DOWN; + _glfw.win32.publicKeys[0x149] = GLFW_KEY_PAGE_UP; + _glfw.win32.publicKeys[0x045] = GLFW_KEY_PAUSE; + _glfw.win32.publicKeys[0x039] = GLFW_KEY_SPACE; + _glfw.win32.publicKeys[0x00F] = GLFW_KEY_TAB; + _glfw.win32.publicKeys[0x03A] = GLFW_KEY_CAPS_LOCK; + _glfw.win32.publicKeys[0x145] = GLFW_KEY_NUM_LOCK; + _glfw.win32.publicKeys[0x046] = GLFW_KEY_SCROLL_LOCK; + _glfw.win32.publicKeys[0x03B] = GLFW_KEY_F1; + _glfw.win32.publicKeys[0x03C] = GLFW_KEY_F2; + _glfw.win32.publicKeys[0x03D] = GLFW_KEY_F3; + _glfw.win32.publicKeys[0x03E] = GLFW_KEY_F4; + _glfw.win32.publicKeys[0x03F] = GLFW_KEY_F5; + _glfw.win32.publicKeys[0x040] = GLFW_KEY_F6; + _glfw.win32.publicKeys[0x041] = GLFW_KEY_F7; + _glfw.win32.publicKeys[0x042] = GLFW_KEY_F8; + _glfw.win32.publicKeys[0x043] = GLFW_KEY_F9; + _glfw.win32.publicKeys[0x044] = GLFW_KEY_F10; + _glfw.win32.publicKeys[0x057] = GLFW_KEY_F11; + _glfw.win32.publicKeys[0x058] = GLFW_KEY_F12; + _glfw.win32.publicKeys[0x064] = GLFW_KEY_F13; + _glfw.win32.publicKeys[0x065] = GLFW_KEY_F14; + _glfw.win32.publicKeys[0x066] = GLFW_KEY_F15; + _glfw.win32.publicKeys[0x067] = GLFW_KEY_F16; + _glfw.win32.publicKeys[0x068] = GLFW_KEY_F17; + _glfw.win32.publicKeys[0x069] = GLFW_KEY_F18; + _glfw.win32.publicKeys[0x06A] = GLFW_KEY_F19; + _glfw.win32.publicKeys[0x06B] = GLFW_KEY_F20; + _glfw.win32.publicKeys[0x06C] = GLFW_KEY_F21; + _glfw.win32.publicKeys[0x06D] = GLFW_KEY_F22; + _glfw.win32.publicKeys[0x06E] = GLFW_KEY_F23; + _glfw.win32.publicKeys[0x076] = GLFW_KEY_F24; + _glfw.win32.publicKeys[0x038] = GLFW_KEY_LEFT_ALT; + _glfw.win32.publicKeys[0x01D] = GLFW_KEY_LEFT_CONTROL; + _glfw.win32.publicKeys[0x02A] = GLFW_KEY_LEFT_SHIFT; + _glfw.win32.publicKeys[0x15B] = GLFW_KEY_LEFT_SUPER; + _glfw.win32.publicKeys[0x137] = GLFW_KEY_PRINT_SCREEN; + _glfw.win32.publicKeys[0x138] = GLFW_KEY_RIGHT_ALT; + _glfw.win32.publicKeys[0x11D] = GLFW_KEY_RIGHT_CONTROL; + _glfw.win32.publicKeys[0x036] = GLFW_KEY_RIGHT_SHIFT; + _glfw.win32.publicKeys[0x15C] = GLFW_KEY_RIGHT_SUPER; + _glfw.win32.publicKeys[0x150] = GLFW_KEY_DOWN; + _glfw.win32.publicKeys[0x14B] = GLFW_KEY_LEFT; + _glfw.win32.publicKeys[0x14D] = GLFW_KEY_RIGHT; + _glfw.win32.publicKeys[0x148] = GLFW_KEY_UP; + + _glfw.win32.publicKeys[0x052] = GLFW_KEY_KP_0; + _glfw.win32.publicKeys[0x04F] = GLFW_KEY_KP_1; + _glfw.win32.publicKeys[0x050] = GLFW_KEY_KP_2; + _glfw.win32.publicKeys[0x051] = GLFW_KEY_KP_3; + _glfw.win32.publicKeys[0x04B] = GLFW_KEY_KP_4; + _glfw.win32.publicKeys[0x04C] = GLFW_KEY_KP_5; + _glfw.win32.publicKeys[0x04D] = GLFW_KEY_KP_6; + _glfw.win32.publicKeys[0x047] = GLFW_KEY_KP_7; + _glfw.win32.publicKeys[0x048] = GLFW_KEY_KP_8; + _glfw.win32.publicKeys[0x049] = GLFW_KEY_KP_9; + _glfw.win32.publicKeys[0x04E] = GLFW_KEY_KP_ADD; + _glfw.win32.publicKeys[0x053] = GLFW_KEY_KP_DECIMAL; + _glfw.win32.publicKeys[0x135] = GLFW_KEY_KP_DIVIDE; + _glfw.win32.publicKeys[0x11C] = GLFW_KEY_KP_ENTER; + _glfw.win32.publicKeys[0x037] = GLFW_KEY_KP_MULTIPLY; + _glfw.win32.publicKeys[0x04A] = GLFW_KEY_KP_SUBTRACT; +} + ////////////////////////////////////////////////////////////////////////// ////// GLFW internal API ////// @@ -202,6 +330,8 @@ int _glfwPlatformInit(void) if (!initLibraries()) return GL_FALSE; + createKeyTables(); + if (_glfw_SetProcessDPIAware) _glfw_SetProcessDPIAware(); diff --git a/glfw/src/win32_monitor.c b/glfw/src/win32_monitor.c index ee44d5d..0690dc1 100644 --- a/glfw/src/win32_monitor.c +++ b/glfw/src/win32_monitor.c @@ -161,9 +161,15 @@ _GLFWmonitor** _glfwPlatformGetMonitors(int* count) wcscpy(monitors[found]->win32.displayName, display.DeviceName); WideCharToMultiByte(CP_UTF8, 0, + adapter.DeviceName, -1, + monitors[found]->win32.publicAdapterName, + sizeof(monitors[found]->win32.publicAdapterName), + NULL, NULL); + + WideCharToMultiByte(CP_UTF8, 0, display.DeviceName, -1, - monitors[found]->win32.nativeName, - sizeof(monitors[found]->win32.nativeName), + monitors[found]->win32.publicDisplayName, + sizeof(monitors[found]->win32.publicDisplayName), NULL, NULL); if (adapter.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE && @@ -326,10 +332,17 @@ void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp) ////// GLFW native API ////// ////////////////////////////////////////////////////////////////////////// +GLFWAPI const char* glfwGetWin32Adapter(GLFWmonitor* handle) +{ + _GLFWmonitor* monitor = (_GLFWmonitor*) handle; + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + return monitor->win32.publicAdapterName; +} + GLFWAPI const char* glfwGetWin32Monitor(GLFWmonitor* handle) { _GLFWmonitor* monitor = (_GLFWmonitor*) handle; _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - return monitor->win32.nativeName; + return monitor->win32.publicDisplayName; } diff --git a/glfw/src/win32_platform.h b/glfw/src/win32_platform.h index 465e487..564c861 100644 --- a/glfw/src/win32_platform.h +++ b/glfw/src/win32_platform.h @@ -172,6 +172,7 @@ typedef struct _GLFWlibraryWin32 { DWORD foregroundLockTimeout; char* clipboardString; + short int publicKeys[512]; // winmm.dll struct { @@ -205,7 +206,8 @@ typedef struct _GLFWmonitorWin32 // This size matches the static size of DISPLAY_DEVICE.DeviceName WCHAR adapterName[32]; WCHAR displayName[32]; - char nativeName[64]; + char publicAdapterName[64]; + char publicDisplayName[64]; GLboolean modeChanged; } _GLFWmonitorWin32; diff --git a/glfw/src/win32_window.c b/glfw/src/win32_window.c index f7c531d..c81f91d 100644 --- a/glfw/src/win32_window.c +++ b/glfw/src/win32_window.c @@ -112,6 +112,29 @@ static void restoreCursor(_GLFWwindow* window) } } +// Translates a GLFW standard cursor to a resource ID +// +static LPWSTR translateCursorShape(int shape) +{ + switch (shape) + { + case GLFW_ARROW_CURSOR: + return IDC_ARROW; + case GLFW_IBEAM_CURSOR: + return IDC_IBEAM; + case GLFW_CROSSHAIR_CURSOR: + return IDC_CROSS; + case GLFW_HAND_CURSOR: + return IDC_HAND; + case GLFW_HRESIZE_CURSOR: + return IDC_SIZEWE; + case GLFW_VRESIZE_CURSOR: + return IDC_SIZENS; + } + + return NULL; +} + // Retrieves and translates modifier keys // static int getKeyMods(void) @@ -152,242 +175,44 @@ static int getAsyncKeyMods(void) // static int translateKey(WPARAM wParam, LPARAM lParam) { - // Check for numeric keypad keys - // NOTE: This way we always force "NumLock = ON", which is intentional since - // the returned key code should correspond to a physical location. - if ((HIWORD(lParam) & 0x100) == 0) - { - switch (MapVirtualKey(HIWORD(lParam) & 0xFF, 1)) - { - case VK_INSERT: return GLFW_KEY_KP_0; - case VK_END: return GLFW_KEY_KP_1; - case VK_DOWN: return GLFW_KEY_KP_2; - case VK_NEXT: return GLFW_KEY_KP_3; - case VK_LEFT: return GLFW_KEY_KP_4; - case VK_CLEAR: return GLFW_KEY_KP_5; - case VK_RIGHT: return GLFW_KEY_KP_6; - case VK_HOME: return GLFW_KEY_KP_7; - case VK_UP: return GLFW_KEY_KP_8; - case VK_PRIOR: return GLFW_KEY_KP_9; - case VK_DIVIDE: return GLFW_KEY_KP_DIVIDE; - case VK_MULTIPLY: return GLFW_KEY_KP_MULTIPLY; - case VK_SUBTRACT: return GLFW_KEY_KP_SUBTRACT; - case VK_ADD: return GLFW_KEY_KP_ADD; - case VK_DELETE: return GLFW_KEY_KP_DECIMAL; - default: break; - } - } - - switch (HIWORD(lParam) & 0xFF) + if (wParam == VK_CONTROL) { - // handle printable chars except space in a language independent way, - // using scancodes rather than virtual keys - // as virtual keys are language dependent. - // Printable keys are mapped according to US layout. - - // Row 0: - case 0x29: return GLFW_KEY_GRAVE_ACCENT; - case 0x02: return GLFW_KEY_1; - case 0x03: return GLFW_KEY_2; - case 0x04: return GLFW_KEY_3; - case 0x05: return GLFW_KEY_4; - case 0x06: return GLFW_KEY_5; - case 0x07: return GLFW_KEY_6; - case 0x08: return GLFW_KEY_7; - case 0x09: return GLFW_KEY_8; - case 0x0A: return GLFW_KEY_9; - case 0x0B: return GLFW_KEY_0; - case 0x0C: return GLFW_KEY_MINUS; - case 0x0D: return GLFW_KEY_EQUAL; - - // Row 1: - case 0x10: return GLFW_KEY_Q; - case 0x11: return GLFW_KEY_W; - case 0x12: return GLFW_KEY_E; - case 0x13: return GLFW_KEY_R; - case 0x14: return GLFW_KEY_T; - case 0x15: return GLFW_KEY_Y; - case 0x16: return GLFW_KEY_U; - case 0x17: return GLFW_KEY_I; - case 0x18: return GLFW_KEY_O; - case 0x19: return GLFW_KEY_P; - case 0x1A: return GLFW_KEY_LEFT_BRACKET; - case 0x1B: return GLFW_KEY_RIGHT_BRACKET; - // We do not map 0x2B as this is only on US - use vKeys for this to prevent confusion with 0x56 - - // Row 2: - case 0x1E: return GLFW_KEY_A; - case 0x1F: return GLFW_KEY_S; - case 0x20: return GLFW_KEY_D; - case 0x21: return GLFW_KEY_F; - case 0x22: return GLFW_KEY_G; - case 0x23: return GLFW_KEY_H; - case 0x24: return GLFW_KEY_J; - case 0x25: return GLFW_KEY_K; - case 0x26: return GLFW_KEY_L; - case 0x27: return GLFW_KEY_SEMICOLON; - case 0x28: return GLFW_KEY_APOSTROPHE; - - // Row 3: - case 0x2C: return GLFW_KEY_Z; - case 0x2D: return GLFW_KEY_X; - case 0x2E: return GLFW_KEY_C; - case 0x2F: return GLFW_KEY_V; - case 0x30: return GLFW_KEY_B; - case 0x31: return GLFW_KEY_N; - case 0x32: return GLFW_KEY_M; - case 0x33: return GLFW_KEY_COMMA; - case 0x34: return GLFW_KEY_PERIOD; - case 0x35: return GLFW_KEY_SLASH; - default: break; - } - - // Check which key was pressed or released - switch (wParam) - { - // The SHIFT keys require special handling - case VK_SHIFT: - { - // Compare scan code for this key with that of VK_RSHIFT in - // order to determine which shift key was pressed (left or - // right) - const DWORD scancode = MapVirtualKey(VK_RSHIFT, 0); - if ((DWORD) ((lParam & 0x01ff0000) >> 16) == scancode) - return GLFW_KEY_RIGHT_SHIFT; - - return GLFW_KEY_LEFT_SHIFT; - } - // The CTRL keys require special handling - case VK_CONTROL: - { - MSG next; - DWORD time; - // Is this an extended key (i.e. right key)? - if (lParam & 0x01000000) - return GLFW_KEY_RIGHT_CONTROL; + MSG next; + DWORD time; + + // Is this an extended key (i.e. right key)? + if (lParam & 0x01000000) + return GLFW_KEY_RIGHT_CONTROL; - // Here is a trick: "Alt Gr" sends LCTRL, then RALT. We only - // want the RALT message, so we try to see if the next message - // is a RALT message. In that case, this is a false LCTRL! - time = GetMessageTime(); + // Here is a trick: "Alt Gr" sends LCTRL, then RALT. We only + // want the RALT message, so we try to see if the next message + // is a RALT message. In that case, this is a false LCTRL! + time = GetMessageTime(); - if (PeekMessageW(&next, NULL, 0, 0, PM_NOREMOVE)) + if (PeekMessageW(&next, NULL, 0, 0, PM_NOREMOVE)) + { + if (next.message == WM_KEYDOWN || + next.message == WM_SYSKEYDOWN || + next.message == WM_KEYUP || + next.message == WM_SYSKEYUP) { - if (next.message == WM_KEYDOWN || - next.message == WM_SYSKEYDOWN || - next.message == WM_KEYUP || - next.message == WM_SYSKEYUP) + if (next.wParam == VK_MENU && + (next.lParam & 0x01000000) && + next.time == time) { - if (next.wParam == VK_MENU && - (next.lParam & 0x01000000) && - next.time == time) - { - // Next message is a RALT down message, which - // means that this is not a proper LCTRL message - return _GLFW_KEY_INVALID; - } + // Next message is a RALT down message, which + // means that this is not a proper LCTRL message + return _GLFW_KEY_INVALID; } } - - return GLFW_KEY_LEFT_CONTROL; - } - - // The ALT keys require special handling - case VK_MENU: - { - // Is this an extended key (i.e. right key)? - if (lParam & 0x01000000) - return GLFW_KEY_RIGHT_ALT; - - return GLFW_KEY_LEFT_ALT; - } - - // The ENTER keys require special handling - case VK_RETURN: - { - // Is this an extended key (i.e. right key)? - if (lParam & 0x01000000) - return GLFW_KEY_KP_ENTER; - - return GLFW_KEY_ENTER; } - // Funcion keys (non-printable keys) - case VK_ESCAPE: return GLFW_KEY_ESCAPE; - case VK_TAB: return GLFW_KEY_TAB; - case VK_BACK: return GLFW_KEY_BACKSPACE; - case VK_HOME: return GLFW_KEY_HOME; - case VK_END: return GLFW_KEY_END; - case VK_PRIOR: return GLFW_KEY_PAGE_UP; - case VK_NEXT: return GLFW_KEY_PAGE_DOWN; - case VK_INSERT: return GLFW_KEY_INSERT; - case VK_DELETE: return GLFW_KEY_DELETE; - case VK_LEFT: return GLFW_KEY_LEFT; - case VK_UP: return GLFW_KEY_UP; - case VK_RIGHT: return GLFW_KEY_RIGHT; - case VK_DOWN: return GLFW_KEY_DOWN; - case VK_F1: return GLFW_KEY_F1; - case VK_F2: return GLFW_KEY_F2; - case VK_F3: return GLFW_KEY_F3; - case VK_F4: return GLFW_KEY_F4; - case VK_F5: return GLFW_KEY_F5; - case VK_F6: return GLFW_KEY_F6; - case VK_F7: return GLFW_KEY_F7; - case VK_F8: return GLFW_KEY_F8; - case VK_F9: return GLFW_KEY_F9; - case VK_F10: return GLFW_KEY_F10; - case VK_F11: return GLFW_KEY_F11; - case VK_F12: return GLFW_KEY_F12; - case VK_F13: return GLFW_KEY_F13; - case VK_F14: return GLFW_KEY_F14; - case VK_F15: return GLFW_KEY_F15; - case VK_F16: return GLFW_KEY_F16; - case VK_F17: return GLFW_KEY_F17; - case VK_F18: return GLFW_KEY_F18; - case VK_F19: return GLFW_KEY_F19; - case VK_F20: return GLFW_KEY_F20; - case VK_F21: return GLFW_KEY_F21; - case VK_F22: return GLFW_KEY_F22; - case VK_F23: return GLFW_KEY_F23; - case VK_F24: return GLFW_KEY_F24; - case VK_NUMLOCK: return GLFW_KEY_NUM_LOCK; - case VK_CAPITAL: return GLFW_KEY_CAPS_LOCK; - case VK_SNAPSHOT: return GLFW_KEY_PRINT_SCREEN; - case VK_SCROLL: return GLFW_KEY_SCROLL_LOCK; - case VK_PAUSE: return GLFW_KEY_PAUSE; - case VK_LWIN: return GLFW_KEY_LEFT_SUPER; - case VK_RWIN: return GLFW_KEY_RIGHT_SUPER; - case VK_APPS: return GLFW_KEY_MENU; - - // Numeric keypad - case VK_NUMPAD0: return GLFW_KEY_KP_0; - case VK_NUMPAD1: return GLFW_KEY_KP_1; - case VK_NUMPAD2: return GLFW_KEY_KP_2; - case VK_NUMPAD3: return GLFW_KEY_KP_3; - case VK_NUMPAD4: return GLFW_KEY_KP_4; - case VK_NUMPAD5: return GLFW_KEY_KP_5; - case VK_NUMPAD6: return GLFW_KEY_KP_6; - case VK_NUMPAD7: return GLFW_KEY_KP_7; - case VK_NUMPAD8: return GLFW_KEY_KP_8; - case VK_NUMPAD9: return GLFW_KEY_KP_9; - case VK_DIVIDE: return GLFW_KEY_KP_DIVIDE; - case VK_MULTIPLY: return GLFW_KEY_KP_MULTIPLY; - case VK_SUBTRACT: return GLFW_KEY_KP_SUBTRACT; - case VK_ADD: return GLFW_KEY_KP_ADD; - case VK_DECIMAL: return GLFW_KEY_KP_DECIMAL; - - // Printable keys are mapped according to US layout - case VK_SPACE: return GLFW_KEY_SPACE; - case 0xDC: return GLFW_KEY_BACKSLASH; - case 0xDF: return GLFW_KEY_WORLD_1; - case 0xE2: return GLFW_KEY_WORLD_2; - default: break; + return GLFW_KEY_LEFT_CONTROL; } - // No matching translation was found - return GLFW_KEY_UNKNOWN; + return _glfw.win32.publicKeys[HIWORD(lParam) & 0x1FF]; } // Enter fullscreen mode @@ -1221,6 +1046,8 @@ void _glfwPlatformPollEvents(void) if (msg.message == WM_QUIT) { // Treat WM_QUIT as a close on all windows + // While GLFW does not itself post WM_QUIT, other processes may post + // it to this one, for example Task Manager window = _glfw.windowListHead; while (window) @@ -1374,6 +1201,26 @@ int _glfwPlatformCreateCursor(_GLFWcursor* cursor, return GL_TRUE; } +int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape) +{ + LPCWSTR native = translateCursorShape(shape); + if (!native) + { + _glfwInputError(GLFW_INVALID_ENUM, "Win32: Invalid standard cursor"); + return GL_FALSE; + } + + cursor->win32.handle = CopyCursor(LoadCursorW(NULL, native)); + if (!cursor->win32.handle) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Win32: Failed to retrieve shared cursor"); + return GL_FALSE; + } + + return GL_TRUE; +} + void _glfwPlatformDestroyCursor(_GLFWcursor* cursor) { if (cursor->win32.handle) diff --git a/glfw/src/wl_init.c b/glfw/src/wl_init.c index 9105df7..0269ee3 100644 --- a/glfw/src/wl_init.c +++ b/glfw/src/wl_init.c @@ -600,6 +600,7 @@ int _glfwPlatformInit(void) void _glfwPlatformTerminate(void) { _glfwTerminateContextAPI(); + _glfwTerminateJoysticks(); if (_glfw.wl.cursorTheme) wl_cursor_theme_destroy(_glfw.wl.cursorTheme); diff --git a/glfw/src/wl_platform.h b/glfw/src/wl_platform.h index a498e38..66736b5 100644 --- a/glfw/src/wl_platform.h +++ b/glfw/src/wl_platform.h @@ -64,7 +64,6 @@ typedef struct _GLFWwindowWayland struct wl_surface* surface; struct wl_egl_window* native; struct wl_shell_surface* shell_surface; - EGLSurface egl_surface; struct wl_callback* callback; _GLFWcursor* currentCursor; } _GLFWwindowWayland; diff --git a/glfw/src/wl_window.c b/glfw/src/wl_window.c index 9ace38f..ce71dbd 100644 --- a/glfw/src/wl_window.c +++ b/glfw/src/wl_window.c @@ -422,6 +422,13 @@ int _glfwPlatformCreateCursor(_GLFWcursor* cursor, return GL_TRUE; } +int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape) +{ + // TODO + fprintf(stderr, "_glfwPlatformCreateStandardCursor not implemented yet\n"); + return GL_FALSE; +} + void _glfwPlatformDestroyCursor(_GLFWcursor* cursor) { wl_buffer_destroy(cursor->wl.buffer); diff --git a/glfw/src/x11_init.c b/glfw/src/x11_init.c index ea0b693..e2063a1 100644 --- a/glfw/src/x11_init.c +++ b/glfw/src/x11_init.c @@ -33,16 +33,17 @@ #include <string.h> #include <limits.h> #include <stdio.h> +#include <locale.h> // Translate an X11 key code to a GLFW key code. // -static int translateKey(int keyCode) +static int translateKey(int scancode) { int keySym; // Valid key code range is [8,255], according to the XLib manual - if (keyCode < 8 || keyCode > 255) + if (scancode < 8 || scancode > 255) return GLFW_KEY_UNKNOWN; if (_glfw.x11.xkb.available) @@ -51,7 +52,7 @@ static int translateKey(int keyCode) // Note: This way we always force "NumLock = ON", which is intentional // since the returned key code should correspond to a physical // location. - keySym = XkbKeycodeToKeysym(_glfw.x11.display, keyCode, 0, 1); + keySym = XkbKeycodeToKeysym(_glfw.x11.display, scancode, 0, 1); switch (keySym) { case XK_KP_0: return GLFW_KEY_KP_0; @@ -74,14 +75,14 @@ static int translateKey(int keyCode) // Now try pimary keysym for function keys (non-printable keys). These // should not be layout dependent (i.e. US layout and international // layouts should give the same result). - keySym = XkbKeycodeToKeysym(_glfw.x11.display, keyCode, 0, 0); + keySym = XkbKeycodeToKeysym(_glfw.x11.display, scancode, 0, 0); } else { int dummy; KeySym* keySyms; - keySyms = XGetKeyboardMapping(_glfw.x11.display, keyCode, 1, &dummy); + keySyms = XGetKeyboardMapping(_glfw.x11.display, scancode, 1, &dummy); keySym = keySyms[0]; XFree(keySyms); } @@ -226,106 +227,97 @@ static int translateKey(int keyCode) return GLFW_KEY_UNKNOWN; } -// Update the key code LUT +// Create key code translation tables // -static void updateKeyCodeLUT(void) +static void createKeyTables(void) { - int i, keyCode, keyCodeGLFW; - char name[XkbKeyNameLength + 1]; - XkbDescPtr descr; + int scancode, key; - // Clear the LUT - for (keyCode = 0; keyCode < 256; keyCode++) - _glfw.x11.keyCodeLUT[keyCode] = GLFW_KEY_UNKNOWN; + memset(_glfw.x11.publicKeys, -1, sizeof(_glfw.x11.publicKeys)); if (_glfw.x11.xkb.available) { // Use XKB to determine physical key locations independently of the current // keyboard layout - // Get keyboard description - descr = XkbGetKeyboard(_glfw.x11.display, - XkbAllComponentsMask, - XkbUseCoreKbd); + char name[XkbKeyNameLength + 1]; + XkbDescPtr descr = XkbGetKeyboard(_glfw.x11.display, + XkbAllComponentsMask, + XkbUseCoreKbd); // Find the X11 key code -> GLFW key code mapping - for (keyCode = descr->min_key_code; keyCode <= descr->max_key_code; ++keyCode) + for (scancode = descr->min_key_code; scancode <= descr->max_key_code; scancode++) { - // Get the key name - for (i = 0; i < XkbKeyNameLength; i++) - name[i] = descr->names->keys[keyCode].name[i]; - + memcpy(name, descr->names->keys[scancode].name, XkbKeyNameLength); name[XkbKeyNameLength] = 0; // Map the key name to a GLFW key code. Note: We only map printable // keys here, and we use the US keyboard layout. The rest of the // keys (function keys) are mapped using traditional KeySym // translations. - if (strcmp(name, "TLDE") == 0) keyCodeGLFW = GLFW_KEY_GRAVE_ACCENT; - else if (strcmp(name, "AE01") == 0) keyCodeGLFW = GLFW_KEY_1; - else if (strcmp(name, "AE02") == 0) keyCodeGLFW = GLFW_KEY_2; - else if (strcmp(name, "AE03") == 0) keyCodeGLFW = GLFW_KEY_3; - else if (strcmp(name, "AE04") == 0) keyCodeGLFW = GLFW_KEY_4; - else if (strcmp(name, "AE05") == 0) keyCodeGLFW = GLFW_KEY_5; - else if (strcmp(name, "AE06") == 0) keyCodeGLFW = GLFW_KEY_6; - else if (strcmp(name, "AE07") == 0) keyCodeGLFW = GLFW_KEY_7; - else if (strcmp(name, "AE08") == 0) keyCodeGLFW = GLFW_KEY_8; - else if (strcmp(name, "AE09") == 0) keyCodeGLFW = GLFW_KEY_9; - else if (strcmp(name, "AE10") == 0) keyCodeGLFW = GLFW_KEY_0; - else if (strcmp(name, "AE11") == 0) keyCodeGLFW = GLFW_KEY_MINUS; - else if (strcmp(name, "AE12") == 0) keyCodeGLFW = GLFW_KEY_EQUAL; - else if (strcmp(name, "AD01") == 0) keyCodeGLFW = GLFW_KEY_Q; - else if (strcmp(name, "AD02") == 0) keyCodeGLFW = GLFW_KEY_W; - else if (strcmp(name, "AD03") == 0) keyCodeGLFW = GLFW_KEY_E; - else if (strcmp(name, "AD04") == 0) keyCodeGLFW = GLFW_KEY_R; - else if (strcmp(name, "AD05") == 0) keyCodeGLFW = GLFW_KEY_T; - else if (strcmp(name, "AD06") == 0) keyCodeGLFW = GLFW_KEY_Y; - else if (strcmp(name, "AD07") == 0) keyCodeGLFW = GLFW_KEY_U; - else if (strcmp(name, "AD08") == 0) keyCodeGLFW = GLFW_KEY_I; - else if (strcmp(name, "AD09") == 0) keyCodeGLFW = GLFW_KEY_O; - else if (strcmp(name, "AD10") == 0) keyCodeGLFW = GLFW_KEY_P; - else if (strcmp(name, "AD11") == 0) keyCodeGLFW = GLFW_KEY_LEFT_BRACKET; - else if (strcmp(name, "AD12") == 0) keyCodeGLFW = GLFW_KEY_RIGHT_BRACKET; - else if (strcmp(name, "AC01") == 0) keyCodeGLFW = GLFW_KEY_A; - else if (strcmp(name, "AC02") == 0) keyCodeGLFW = GLFW_KEY_S; - else if (strcmp(name, "AC03") == 0) keyCodeGLFW = GLFW_KEY_D; - else if (strcmp(name, "AC04") == 0) keyCodeGLFW = GLFW_KEY_F; - else if (strcmp(name, "AC05") == 0) keyCodeGLFW = GLFW_KEY_G; - else if (strcmp(name, "AC06") == 0) keyCodeGLFW = GLFW_KEY_H; - else if (strcmp(name, "AC07") == 0) keyCodeGLFW = GLFW_KEY_J; - else if (strcmp(name, "AC08") == 0) keyCodeGLFW = GLFW_KEY_K; - else if (strcmp(name, "AC09") == 0) keyCodeGLFW = GLFW_KEY_L; - else if (strcmp(name, "AC10") == 0) keyCodeGLFW = GLFW_KEY_SEMICOLON; - else if (strcmp(name, "AC11") == 0) keyCodeGLFW = GLFW_KEY_APOSTROPHE; - else if (strcmp(name, "AB01") == 0) keyCodeGLFW = GLFW_KEY_Z; - else if (strcmp(name, "AB02") == 0) keyCodeGLFW = GLFW_KEY_X; - else if (strcmp(name, "AB03") == 0) keyCodeGLFW = GLFW_KEY_C; - else if (strcmp(name, "AB04") == 0) keyCodeGLFW = GLFW_KEY_V; - else if (strcmp(name, "AB05") == 0) keyCodeGLFW = GLFW_KEY_B; - else if (strcmp(name, "AB06") == 0) keyCodeGLFW = GLFW_KEY_N; - else if (strcmp(name, "AB07") == 0) keyCodeGLFW = GLFW_KEY_M; - else if (strcmp(name, "AB08") == 0) keyCodeGLFW = GLFW_KEY_COMMA; - else if (strcmp(name, "AB09") == 0) keyCodeGLFW = GLFW_KEY_PERIOD; - else if (strcmp(name, "AB10") == 0) keyCodeGLFW = GLFW_KEY_SLASH; - else if (strcmp(name, "BKSL") == 0) keyCodeGLFW = GLFW_KEY_BACKSLASH; - else if (strcmp(name, "LSGT") == 0) keyCodeGLFW = GLFW_KEY_WORLD_1; - else keyCodeGLFW = GLFW_KEY_UNKNOWN; - - // Update the key code LUT - if ((keyCode >= 0) && (keyCode < 256)) - _glfw.x11.keyCodeLUT[keyCode] = keyCodeGLFW; + if (strcmp(name, "TLDE") == 0) key = GLFW_KEY_GRAVE_ACCENT; + else if (strcmp(name, "AE01") == 0) key = GLFW_KEY_1; + else if (strcmp(name, "AE02") == 0) key = GLFW_KEY_2; + else if (strcmp(name, "AE03") == 0) key = GLFW_KEY_3; + else if (strcmp(name, "AE04") == 0) key = GLFW_KEY_4; + else if (strcmp(name, "AE05") == 0) key = GLFW_KEY_5; + else if (strcmp(name, "AE06") == 0) key = GLFW_KEY_6; + else if (strcmp(name, "AE07") == 0) key = GLFW_KEY_7; + else if (strcmp(name, "AE08") == 0) key = GLFW_KEY_8; + else if (strcmp(name, "AE09") == 0) key = GLFW_KEY_9; + else if (strcmp(name, "AE10") == 0) key = GLFW_KEY_0; + else if (strcmp(name, "AE11") == 0) key = GLFW_KEY_MINUS; + else if (strcmp(name, "AE12") == 0) key = GLFW_KEY_EQUAL; + else if (strcmp(name, "AD01") == 0) key = GLFW_KEY_Q; + else if (strcmp(name, "AD02") == 0) key = GLFW_KEY_W; + else if (strcmp(name, "AD03") == 0) key = GLFW_KEY_E; + else if (strcmp(name, "AD04") == 0) key = GLFW_KEY_R; + else if (strcmp(name, "AD05") == 0) key = GLFW_KEY_T; + else if (strcmp(name, "AD06") == 0) key = GLFW_KEY_Y; + else if (strcmp(name, "AD07") == 0) key = GLFW_KEY_U; + else if (strcmp(name, "AD08") == 0) key = GLFW_KEY_I; + else if (strcmp(name, "AD09") == 0) key = GLFW_KEY_O; + else if (strcmp(name, "AD10") == 0) key = GLFW_KEY_P; + else if (strcmp(name, "AD11") == 0) key = GLFW_KEY_LEFT_BRACKET; + else if (strcmp(name, "AD12") == 0) key = GLFW_KEY_RIGHT_BRACKET; + else if (strcmp(name, "AC01") == 0) key = GLFW_KEY_A; + else if (strcmp(name, "AC02") == 0) key = GLFW_KEY_S; + else if (strcmp(name, "AC03") == 0) key = GLFW_KEY_D; + else if (strcmp(name, "AC04") == 0) key = GLFW_KEY_F; + else if (strcmp(name, "AC05") == 0) key = GLFW_KEY_G; + else if (strcmp(name, "AC06") == 0) key = GLFW_KEY_H; + else if (strcmp(name, "AC07") == 0) key = GLFW_KEY_J; + else if (strcmp(name, "AC08") == 0) key = GLFW_KEY_K; + else if (strcmp(name, "AC09") == 0) key = GLFW_KEY_L; + else if (strcmp(name, "AC10") == 0) key = GLFW_KEY_SEMICOLON; + else if (strcmp(name, "AC11") == 0) key = GLFW_KEY_APOSTROPHE; + else if (strcmp(name, "AB01") == 0) key = GLFW_KEY_Z; + else if (strcmp(name, "AB02") == 0) key = GLFW_KEY_X; + else if (strcmp(name, "AB03") == 0) key = GLFW_KEY_C; + else if (strcmp(name, "AB04") == 0) key = GLFW_KEY_V; + else if (strcmp(name, "AB05") == 0) key = GLFW_KEY_B; + else if (strcmp(name, "AB06") == 0) key = GLFW_KEY_N; + else if (strcmp(name, "AB07") == 0) key = GLFW_KEY_M; + else if (strcmp(name, "AB08") == 0) key = GLFW_KEY_COMMA; + else if (strcmp(name, "AB09") == 0) key = GLFW_KEY_PERIOD; + else if (strcmp(name, "AB10") == 0) key = GLFW_KEY_SLASH; + else if (strcmp(name, "BKSL") == 0) key = GLFW_KEY_BACKSLASH; + else if (strcmp(name, "LSGT") == 0) key = GLFW_KEY_WORLD_1; + else key = GLFW_KEY_UNKNOWN; + + if ((scancode >= 0) && (scancode < 256)) + _glfw.x11.publicKeys[scancode] = key; } - // Free the keyboard description XkbFreeKeyboard(descr, 0, True); } // Translate the un-translated key codes using traditional X11 KeySym // lookups - for (keyCode = 0; keyCode < 256; keyCode++) + for (scancode = 0; scancode < 256; scancode++) { - if (_glfw.x11.keyCodeLUT[keyCode] < 0) - _glfw.x11.keyCodeLUT[keyCode] = translateKey(keyCode); + if (_glfw.x11.publicKeys[scancode] < 0) + _glfw.x11.publicKeys[scancode] = translateKey(scancode); } } @@ -585,7 +577,7 @@ static GLboolean initExtensions(void) // Update the key code LUT // FIXME: We should listen to XkbMapNotify events to track changes to // the keyboard mapping. - updateKeyCodeLUT(); + createKeyTables(); // Detect whether an EWMH-conformant window manager is running detectEWMH(); @@ -718,6 +710,9 @@ Cursor _glfwCreateCursor(const GLFWimage* image, int xhot, int yhot) int _glfwPlatformInit(void) { + if (strcmp(setlocale(LC_CTYPE, NULL), "C") == 0) + setlocale(LC_CTYPE, ""); + XInitThreads(); _glfw.x11.display = XOpenDisplay(NULL); @@ -754,8 +749,10 @@ int _glfwPlatformInit(void) if (!_glfwInitContextAPI()) return GL_FALSE; + if (!_glfwInitJoysticks()) + return GL_FALSE; + _glfwInitTimer(); - _glfwInitJoysticks(); return GL_TRUE; } diff --git a/glfw/src/x11_monitor.c b/glfw/src/x11_monitor.c index 36d914d..fb6b0ef 100644 --- a/glfw/src/x11_monitor.c +++ b/glfw/src/x11_monitor.c @@ -465,6 +465,13 @@ void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp) ////// GLFW native API ////// ////////////////////////////////////////////////////////////////////////// +GLFWAPI RRCrtc glfwGetX11Adapter(GLFWmonitor* handle) +{ + _GLFWmonitor* monitor = (_GLFWmonitor*) handle; + _GLFW_REQUIRE_INIT_OR_RETURN(None); + return monitor->x11.crtc; +} + GLFWAPI RROutput glfwGetX11Monitor(GLFWmonitor* handle) { _GLFWmonitor* monitor = (_GLFWmonitor*) handle; diff --git a/glfw/src/x11_platform.h b/glfw/src/x11_platform.h index a69705b..17503b7 100644 --- a/glfw/src/x11_platform.h +++ b/glfw/src/x11_platform.h @@ -31,6 +31,8 @@ #include <unistd.h> #include <signal.h> #include <stdint.h> +#include <regex.h> + #include <X11/Xlib.h> #include <X11/keysym.h> #include <X11/Xatom.h> @@ -115,11 +117,10 @@ typedef struct _GLFWlibraryX11 GLboolean hasEWMH; // Most recent error code received by X error handler int errorCode; - + // Clipboard string (while the selection is owned) char* clipboardString; - - // LUT for mapping X11 key codes to GLFW key codes - int keyCodeLUT[256]; + // X11 keycode to GLFW key LUT + short int publicKeys[256]; // Window manager atoms Atom WM_PROTOCOLS; @@ -215,6 +216,14 @@ typedef struct _GLFWlibraryX11 int versionMinor; } xinerama; +#if defined(__linux__) + struct { + int fd; + int wd; + regex_t regex; + } inotify; +#endif + } _GLFWlibraryX11; diff --git a/glfw/src/x11_window.c b/glfw/src/x11_window.c index 8fa6c97..8373487 100644 --- a/glfw/src/x11_window.c +++ b/glfw/src/x11_window.c @@ -27,6 +27,8 @@ #include "internal.h" +#include <X11/cursorfont.h> + #include <sys/select.h> #include <string.h> @@ -66,6 +68,29 @@ static Bool isFrameExtentsEvent(Display* display, XEvent* event, XPointer pointe event->xproperty.atom == _glfw.x11.NET_FRAME_EXTENTS; } +// Translates a GLFW standard cursor to a font cursor shape +// +static int translateCursorShape(int shape) +{ + switch (shape) + { + case GLFW_ARROW_CURSOR: + return XC_arrow; + case GLFW_IBEAM_CURSOR: + return XC_xterm; + case GLFW_CROSSHAIR_CURSOR: + return XC_crosshair; + case GLFW_HAND_CURSOR: + return XC_hand1; + case GLFW_HRESIZE_CURSOR: + return XC_sb_h_double_arrow; + case GLFW_VRESIZE_CURSOR: + return XC_sb_v_double_arrow; + } + + return 0; +} + // Translates an X event modifier state mask // static int translateState(int state) @@ -86,13 +111,13 @@ static int translateState(int state) // Translates an X Window key to internal coding // -static int translateKey(int keycode) +static int translateKey(int scancode) { - // Use the pre-filled LUT (see updateKeyCodeLUT() in x11_init.c) - if (keycode < 0 || keycode > 255) + // Use the pre-filled LUT (see createKeyTables() in x11_init.c) + if (scancode < 0 || scancode > 255) return GLFW_KEY_UNKNOWN; - return _glfw.x11.keyCodeLUT[keycode]; + return _glfw.x11.publicKeys[scancode]; } // Return the GLFW window corresponding to the specified X11 window @@ -777,14 +802,16 @@ static void enterFullscreenMode(_GLFWwindow* window) { // In override-redirect mode we have divorced ourselves from the // window manager, so we need to do everything manually - + int xpos, ypos; GLFWvidmode mode; + + _glfwPlatformGetMonitorPos(window->monitor, &xpos, &ypos); _glfwPlatformGetVideoMode(window->monitor, &mode); XRaiseWindow(_glfw.x11.display, window->x11.handle); XSetInputFocus(_glfw.x11.display, window->x11.handle, RevertToParent, CurrentTime); - XMoveWindow(_glfw.x11.display, window->x11.handle, 0, 0); + XMoveWindow(_glfw.x11.display, window->x11.handle, xpos, ypos); XResizeWindow(_glfw.x11.display, window->x11.handle, mode.width, mode.height); } @@ -1729,12 +1756,32 @@ int _glfwPlatformCreateCursor(_GLFWcursor* cursor, int xhot, int yhot) { cursor->x11.handle = _glfwCreateCursor(image, xhot, yhot); - if (cursor->x11.handle == None) + if (!cursor->x11.handle) return GL_FALSE; return GL_TRUE; } +int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape) +{ + const unsigned int native = translateCursorShape(shape); + if (!native) + { + _glfwInputError(GLFW_INVALID_ENUM, "X11: Invalid standard cursor"); + return GL_FALSE; + } + + cursor->x11.handle = XCreateFontCursor(_glfw.x11.display, native); + if (!cursor->x11.handle) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "X11: Failed to create standard cursor"); + return GL_FALSE; + } + + return GL_TRUE; +} + void _glfwPlatformDestroyCursor(_GLFWcursor* cursor) { if (cursor->x11.handle) |