diff --git a/CMakeLists.txt b/CMakeLists.txt index 4ca8de957..f9f81dc55 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,15 +1,9 @@ -cmake_minimum_required(VERSION 2.8.12) +cmake_minimum_required(VERSION 3.0) project(GLFW C) set(CMAKE_LEGACY_CYGWIN_WIN32 OFF) -if (NOT CMAKE_VERSION VERSION_LESS "3.0") - # Until all major package systems have moved to CMake 3, - # we stick with the older INSTALL_NAME_DIR mechanism - cmake_policy(SET CMP0042 OLD) -endif() - if (NOT CMAKE_VERSION VERSION_LESS "3.1") cmake_policy(SET CMP0054 NEW) endif() diff --git a/docs/intro.dox b/docs/intro.dox index e8adf5357..58ab8fd5d 100644 --- a/docs/intro.dox +++ b/docs/intro.dox @@ -365,10 +365,10 @@ allow calls from any thread in future releases. @subsection compatibility Version compatibility -GLFW guarantees source and binary backward compatibility with earlier minor -versions of the API. This means that you can drop in a newer version of the -library and existing programs will continue to compile and existing binaries -will continue to run. +GLFW uses [Semantic Versioning](https://semver.org/). This guarantees source +and binary backward compatibility with earlier minor versions of the API. This +means that you can drop in a newer version of the library and existing programs +will continue to compile and existing binaries will continue to run. Once a function or constant has been added, the signature of that function or value of that constant will remain unchanged until the next major version of diff --git a/examples/wave.c b/examples/wave.c index f5af37914..1de7e6fad 100644 --- a/examples/wave.c +++ b/examples/wave.c @@ -455,6 +455,7 @@ int main(int argc, char* argv[]) glfwPollEvents(); } + glfwTerminate(); exit(EXIT_SUCCESS); } diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index b6d9f341f..00256d4df 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -4697,7 +4697,7 @@ GLFWAPI const char* glfwGetJoystickGUID(int jid); * This function may be called from the joystick callback, even for a joystick * that is being disconnected. * - * @param[in] joystick The joystick whose pointer to set. + * @param[in] jid The joystick whose pointer to set. * @param[in] pointer The new value. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. @@ -4722,7 +4722,7 @@ GLFWAPI void glfwSetJoystickUserPointer(int jid, void* pointer); * This function may be called from the joystick callback, even for a joystick * that is being disconnected. * - * @param[in] joystick The joystick whose pointer to return. + * @param[in] jid The joystick whose pointer to return. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * diff --git a/src/cocoa_window.m b/src/cocoa_window.m index a54624cc5..7cf4a593d 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -128,6 +128,32 @@ static void updateCursorImage(_GLFWwindow* window) hideCursor(window); } +// Apply chosen cursor mode to a focused window +// +static void updateCursorMode(_GLFWwindow* window) +{ + if (window->cursorMode == GLFW_CURSOR_DISABLED) + { + _glfw.ns.disabledCursorWindow = window; + _glfwPlatformGetCursorPos(window, + &_glfw.ns.restoreCursorPosX, + &_glfw.ns.restoreCursorPosY); + centerCursor(window); + CGAssociateMouseAndMouseCursorPosition(false); + } + else if (_glfw.ns.disabledCursorWindow == window) + { + _glfw.ns.disabledCursorWindow = NULL; + CGAssociateMouseAndMouseCursorPosition(true); + _glfwPlatformSetCursorPos(window, + _glfw.ns.restoreCursorPosX, + _glfw.ns.restoreCursorPosY); + } + + if (cursorInClientArea(window)) + updateCursorImage(window); +} + // Transforms the specified y-coordinate between the CG display and NS screen // coordinate systems // @@ -321,7 +347,7 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; centerCursor(window); _glfwInputWindowFocus(window, GLFW_TRUE); - _glfwPlatformSetCursorMode(window, window->cursorMode); + updateCursorMode(window); } - (void)windowDidResignKey:(NSNotification *)notification @@ -1638,26 +1664,8 @@ void _glfwPlatformSetCursorPos(_GLFWwindow* window, double x, double y) void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode) { - if (mode == GLFW_CURSOR_DISABLED) - { - _glfw.ns.disabledCursorWindow = window; - _glfwPlatformGetCursorPos(window, - &_glfw.ns.restoreCursorPosX, - &_glfw.ns.restoreCursorPosY); - centerCursor(window); - CGAssociateMouseAndMouseCursorPosition(false); - } - else if (_glfw.ns.disabledCursorWindow == window) - { - _glfw.ns.disabledCursorWindow = NULL; - CGAssociateMouseAndMouseCursorPosition(true); - _glfwPlatformSetCursorPos(window, - _glfw.ns.restoreCursorPosX, - _glfw.ns.restoreCursorPosY); - } - - if (cursorInClientArea(window)) - updateCursorImage(window); + if (_glfwPlatformWindowFocused(window)) + updateCursorMode(window); } const char* _glfwPlatformGetScancodeName(int scancode) diff --git a/src/init.c b/src/init.c index 4ed929511..9e670d423 100644 --- a/src/init.c +++ b/src/init.c @@ -57,37 +57,6 @@ static _GLFWinitconfig _glfwInitHints = } }; -// Returns a generic string representation of the specified error -// -static const char* getErrorString(int code) -{ - switch (code) - { - case GLFW_NOT_INITIALIZED: - return "The GLFW library is not initialized"; - case GLFW_NO_CURRENT_CONTEXT: - return "There is no current context"; - case GLFW_INVALID_ENUM: - return "Invalid argument for enum parameter"; - case GLFW_INVALID_VALUE: - return "Invalid value for parameter"; - case GLFW_OUT_OF_MEMORY: - return "Out of memory"; - case GLFW_API_UNAVAILABLE: - return "The requested API is unavailable"; - case GLFW_VERSION_UNAVAILABLE: - return "The requested API version is unavailable"; - case GLFW_PLATFORM_ERROR: - return "An undocumented platform-specific error occurred"; - case GLFW_FORMAT_UNAVAILABLE: - return "The requested format is unavailable"; - case GLFW_NO_WINDOW_CONTEXT: - return "The specified window has no context"; - default: - return "ERROR: UNKNOWN GLFW ERROR"; - } -} - // Terminate the library // static void terminate(void) @@ -173,7 +142,30 @@ void _glfwInputError(int code, const char* format, ...) description[sizeof(description) - 1] = '\0'; } else - strcpy(description, getErrorString(code)); + { + if (code == GLFW_NOT_INITIALIZED) + strcpy(description, "The GLFW library is not initialized"); + else if (code == GLFW_NO_CURRENT_CONTEXT) + strcpy(description, "There is no current context"); + else if (code == GLFW_INVALID_ENUM) + strcpy(description, "Invalid argument for enum parameter"); + else if (code == GLFW_INVALID_VALUE) + strcpy(description, "Invalid value for parameter"); + else if (code == GLFW_OUT_OF_MEMORY) + strcpy(description, "Out of memory"); + else if (code == GLFW_API_UNAVAILABLE) + strcpy(description, "The requested API is unavailable"); + else if (code == GLFW_VERSION_UNAVAILABLE) + strcpy(description, "The requested API version is unavailable"); + else if (code == GLFW_PLATFORM_ERROR) + strcpy(description, "A platform-specific error occurred"); + else if (code == GLFW_FORMAT_UNAVAILABLE) + strcpy(description, "The requested format is unavailable"); + else if (code == GLFW_NO_WINDOW_CONTEXT) + strcpy(description, "The specified window has no context"); + else + strcpy(description, "ERROR: UNKNOWN GLFW ERROR"); + } if (_glfw.initialized) { diff --git a/src/input.c b/src/input.c index c4f1e3037..429754521 100644 --- a/src/input.c +++ b/src/input.c @@ -509,9 +509,7 @@ GLFWAPI void glfwSetInputMode(GLFWwindow* handle, int mode, int value) _glfwPlatformGetCursorPos(window, &window->virtualCursorPosX, &window->virtualCursorPosY); - - if (_glfwPlatformWindowFocused(window)) - _glfwPlatformSetCursorMode(window, value); + _glfwPlatformSetCursorMode(window, value); } else if (mode == GLFW_STICKY_KEYS) { diff --git a/src/win32_platform.h b/src/win32_platform.h index 607ac13ae..9a669215f 100644 --- a/src/win32_platform.h +++ b/src/win32_platform.h @@ -120,6 +120,8 @@ typedef struct HRGN hRgnBlur; BOOL fTransitionOnMaximized; } DWM_BLURBEHIND; +#else + #include #endif /*Windows Vista*/ #ifndef DPI_ENUMS_DECLARED diff --git a/src/win32_window.c b/src/win32_window.c index 4506c8a72..d467f2ae3 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -235,26 +235,6 @@ static void centerCursor(_GLFWwindow* window) _glfwPlatformSetCursorPos(window, width / 2.0, height / 2.0); } -// Returns whether the cursor is in the client area of the specified window -// -static GLFWbool cursorInClientArea(_GLFWwindow* window) -{ - RECT area; - POINT pos; - - if (!GetCursorPos(&pos)) - return GLFW_FALSE; - - if (WindowFromPoint(pos) != window->win32.handle) - return GLFW_FALSE; - - GetClientRect(window->win32.handle, &area); - ClientToScreen(window->win32.handle, (POINT*) &area.left); - ClientToScreen(window->win32.handle, (POINT*) &area.right); - - return PtInRect(&area, pos); -} - // Updates the cursor image according to its cursor mode // static void updateCursorImage(_GLFWwindow* window) @@ -286,6 +266,67 @@ static void updateClipRect(_GLFWwindow* window) ClipCursor(NULL); } +// Apply disabled cursor mode to a focused window +// +static void disableCursor(_GLFWwindow* window) +{ + const RAWINPUTDEVICE rid = { 0x01, 0x02, 0, window->win32.handle }; + + _glfw.win32.disabledCursorWindow = window; + _glfwPlatformGetCursorPos(window, + &_glfw.win32.restoreCursorPosX, + &_glfw.win32.restoreCursorPosY); + updateCursorImage(window); + centerCursor(window); + updateClipRect(window); + + if (!RegisterRawInputDevices(&rid, 1, sizeof(rid))) + { + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "Win32: Failed to register raw input device"); + } +} + +// Exit disabled cursor mode for the specified window +// +static void enableCursor(_GLFWwindow* window) +{ + const RAWINPUTDEVICE rid = { 0x01, 0x02, RIDEV_REMOVE, NULL }; + + _glfw.win32.disabledCursorWindow = NULL; + updateClipRect(NULL); + _glfwPlatformSetCursorPos(window, + _glfw.win32.restoreCursorPosX, + _glfw.win32.restoreCursorPosY); + updateCursorImage(window); + + if (!RegisterRawInputDevices(&rid, 1, sizeof(rid))) + { + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "Win32: Failed to remove raw input device"); + } +} + +// Returns whether the cursor is in the client area of the specified window +// +static GLFWbool cursorInClientArea(_GLFWwindow* window) +{ + RECT area; + POINT pos; + + if (!GetCursorPos(&pos)) + return GLFW_FALSE; + + if (WindowFromPoint(pos) != window->win32.handle) + return GLFW_FALSE; + + GetClientRect(window->win32.handle, &area); + ClientToScreen(window->win32.handle, (POINT*) &area.left); + ClientToScreen(window->win32.handle, (POINT*) &area.right); + + return PtInRect(&area, pos); +} + // Update native window styles to match attributes // static void updateWindowStyles(const _GLFWwindow* window) @@ -575,7 +616,7 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, if (lParam == 0 && window->win32.frameAction) { if (window->cursorMode == GLFW_CURSOR_DISABLED) - _glfwPlatformSetCursorMode(window, GLFW_CURSOR_DISABLED); + disableCursor(window); window->win32.frameAction = GLFW_FALSE; } @@ -593,7 +634,7 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, break; if (window->cursorMode == GLFW_CURSOR_DISABLED) - _glfwPlatformSetCursorMode(window, GLFW_CURSOR_DISABLED); + disableCursor(window); return 0; } @@ -601,7 +642,7 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, case WM_KILLFOCUS: { if (window->cursorMode == GLFW_CURSOR_DISABLED) - _glfwPlatformSetCursorMode(window, GLFW_CURSOR_NORMAL); + enableCursor(window); if (window->monitor && window->autoIconify) _glfwPlatformIconifyWindow(window); @@ -857,10 +898,10 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, case WM_ENTERSIZEMOVE: case WM_ENTERMENULOOP: { - // HACK: Postpone cursor disabling while the user is moving or - // resizing the window or using the menu + // HACK: Enable the cursor while the user is moving or + // resizing the window or using the window menu if (window->cursorMode == GLFW_CURSOR_DISABLED) - _glfwPlatformSetCursorMode(window, GLFW_CURSOR_NORMAL); + enableCursor(window); break; } @@ -871,7 +912,7 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, // HACK: Disable the cursor once the user is done moving or // resizing the window or using the menu if (window->cursorMode == GLFW_CURSOR_DISABLED) - _glfwPlatformSetCursorMode(window, GLFW_CURSOR_DISABLED); + disableCursor(window); break; } @@ -1772,39 +1813,12 @@ void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode) { if (mode == GLFW_CURSOR_DISABLED) { - const RAWINPUTDEVICE rid = { 0x01, 0x02, 0, window->win32.handle }; - - _glfw.win32.disabledCursorWindow = window; - _glfwPlatformGetCursorPos(window, - &_glfw.win32.restoreCursorPosX, - &_glfw.win32.restoreCursorPosY); - centerCursor(window); - updateClipRect(window); - - if (!RegisterRawInputDevices(&rid, 1, sizeof(rid))) - { - _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, - "Win32: Failed to register raw input device"); - } + if (_glfwPlatformWindowFocused(window)) + disableCursor(window); } else if (_glfw.win32.disabledCursorWindow == window) - { - const RAWINPUTDEVICE rid = { 0x01, 0x02, RIDEV_REMOVE, NULL }; - - _glfw.win32.disabledCursorWindow = NULL; - updateClipRect(NULL); - _glfwPlatformSetCursorPos(window, - _glfw.win32.restoreCursorPosX, - _glfw.win32.restoreCursorPosY); - - if (!RegisterRawInputDevices(&rid, 1, sizeof(rid))) - { - _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, - "Win32: Failed to remove raw input device"); - } - } - - if (cursorInClientArea(window)) + enableCursor(window); + else if (cursorInClientArea(window)) updateCursorImage(window); } diff --git a/src/x11_init.c b/src/x11_init.c index af4fb7ed6..c949916d3 100644 --- a/src/x11_init.c +++ b/src/x11_init.c @@ -479,7 +479,11 @@ static GLFWbool initExtensions(void) &_glfw.x11.vidmode.errorBase); } +#if defined(__CYGWIN__) + _glfw.x11.xi.handle = _glfw_dlopen("libXi-6.so"); +#else _glfw.x11.xi.handle = _glfw_dlopen("libXi.so.6"); +#endif if (_glfw.x11.xi.handle) { _glfw.x11.xi.QueryVersion = (PFN_XIQueryVersion) @@ -505,7 +509,11 @@ static GLFWbool initExtensions(void) } } +#if defined(__CYGWIN__) + _glfw.x11.randr.handle = _glfw_dlopen("libXrandr-2.so"); +#else _glfw.x11.randr.handle = _glfw_dlopen("libXrandr.so.2"); +#endif if (_glfw.x11.randr.handle) { _glfw.x11.randr.AllocGamma = (PFN_XRRAllocGamma) @@ -593,7 +601,11 @@ static GLFWbool initExtensions(void) RROutputChangeNotifyMask); } +#if defined(__CYGWIN__) + _glfw.x11.xcursor.handle = _glfw_dlopen("libXcursor-1.so"); +#else _glfw.x11.xcursor.handle = _glfw_dlopen("libXcursor.so.1"); +#endif if (_glfw.x11.xcursor.handle) { _glfw.x11.xcursor.ImageCreate = (PFN_XcursorImageCreate) @@ -604,7 +616,11 @@ static GLFWbool initExtensions(void) _glfw_dlsym(_glfw.x11.xcursor.handle, "XcursorImageLoadCursor"); } +#if defined(__CYGWIN__) + _glfw.x11.xinerama.handle = _glfw_dlopen("libXinerama-1.so"); +#else _glfw.x11.xinerama.handle = _glfw_dlopen("libXinerama.so.1"); +#endif if (_glfw.x11.xinerama.handle) { _glfw.x11.xinerama.IsActive = (PFN_XineramaIsActive) @@ -644,14 +660,22 @@ static GLFWbool initExtensions(void) } } +#if defined(__CYGWIN__) + _glfw.x11.x11xcb.handle = _glfw_dlopen("libX11-xcb-1.so"); +#else _glfw.x11.x11xcb.handle = _glfw_dlopen("libX11-xcb.so.1"); +#endif if (_glfw.x11.x11xcb.handle) { _glfw.x11.x11xcb.GetXCBConnection = (PFN_XGetXCBConnection) _glfw_dlsym(_glfw.x11.x11xcb.handle, "XGetXCBConnection"); } +#if defined(__CYGWIN__) + _glfw.x11.xrender.handle = _glfw_dlopen("libXrender-1.so"); +#else _glfw.x11.xrender.handle = _glfw_dlopen("libXrender.so.1"); +#endif if (_glfw.x11.xrender.handle) { _glfw.x11.xrender.QueryExtension = (PFN_XRenderQueryExtension) @@ -1024,6 +1048,24 @@ void _glfwPlatformTerminate(void) _glfw.x11.xinerama.handle = NULL; } + if (_glfw.x11.xrender.handle) + { + _glfw_dlclose(_glfw.x11.xrender.handle); + _glfw.x11.xrender.handle = NULL; + } + + if (_glfw.x11.vidmode.handle) + { + _glfw_dlclose(_glfw.x11.vidmode.handle); + _glfw.x11.vidmode.handle = NULL; + } + + if (_glfw.x11.xi.handle) + { + _glfw_dlclose(_glfw.x11.xi.handle); + _glfw.x11.xi.handle = NULL; + } + // NOTE: These need to be unloaded after XCloseDisplay, as they register // cleanup callbacks that get called by that function _glfwTerminateEGL(); diff --git a/src/x11_window.c b/src/x11_window.c index f3014ec9f..fc24f2851 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -571,6 +571,61 @@ static void updateCursorImage(_GLFWwindow* window) } } +// Apply disabled cursor mode to a focused window +// +static void disableCursor(_GLFWwindow* window) +{ + if (_glfw.x11.xi.available) + { + XIEventMask em; + unsigned char mask[XIMaskLen(XI_RawMotion)] = { 0 }; + + em.deviceid = XIAllMasterDevices; + em.mask_len = sizeof(mask); + em.mask = mask; + XISetMask(mask, XI_RawMotion); + + XISelectEvents(_glfw.x11.display, _glfw.x11.root, &em, 1); + } + + _glfw.x11.disabledCursorWindow = window; + _glfwPlatformGetCursorPos(window, + &_glfw.x11.restoreCursorPosX, + &_glfw.x11.restoreCursorPosY); + updateCursorImage(window); + centerCursor(window); + XGrabPointer(_glfw.x11.display, window->x11.handle, True, + ButtonPressMask | ButtonReleaseMask | PointerMotionMask, + GrabModeAsync, GrabModeAsync, + window->x11.handle, + _glfw.x11.hiddenCursorHandle, + CurrentTime); +} + +// Exit disabled cursor mode for the specified window +// +static void enableCursor(_GLFWwindow* window) +{ + if (_glfw.x11.xi.available) + { + XIEventMask em; + unsigned char mask[] = { 0 }; + + em.deviceid = XIAllMasterDevices; + em.mask_len = sizeof(mask); + em.mask = mask; + + XISelectEvents(_glfw.x11.display, _glfw.x11.root, &em, 1); + } + + _glfw.x11.disabledCursorWindow = NULL; + XUngrabPointer(_glfw.x11.display, CurrentTime); + _glfwPlatformSetCursorPos(window, + _glfw.x11.restoreCursorPosX, + _glfw.x11.restoreCursorPosY); + updateCursorImage(window); +} + // Create the X11 window (and its colormap) // static GLFWbool createNativeWindow(_GLFWwindow* window, @@ -1432,7 +1487,7 @@ static void processEvent(XEvent *event) // HACK: This is a workaround for WMs (KWM, Fluxbox) that otherwise // ignore the defined cursor for hidden cursor mode if (window->cursorMode == GLFW_CURSOR_HIDDEN) - _glfwPlatformSetCursorMode(window, GLFW_CURSOR_HIDDEN); + updateCursorImage(window); _glfwInputCursorEnter(window, GLFW_TRUE); return; @@ -1725,7 +1780,7 @@ static void processEvent(XEvent *event) case FocusIn: { if (window->cursorMode == GLFW_CURSOR_DISABLED) - _glfwPlatformSetCursorMode(window, GLFW_CURSOR_DISABLED); + disableCursor(window); if (event->xfocus.mode == NotifyGrab || event->xfocus.mode == NotifyUngrab) @@ -1745,7 +1800,7 @@ static void processEvent(XEvent *event) case FocusOut: { if (window->cursorMode == GLFW_CURSOR_DISABLED) - _glfwPlatformSetCursorMode(window, GLFW_CURSOR_NORMAL); + enableCursor(window); if (event->xfocus.mode == NotifyGrab || event->xfocus.mode == NotifyUngrab) @@ -2708,53 +2763,14 @@ void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode) { if (mode == GLFW_CURSOR_DISABLED) { - if (_glfw.x11.xi.available) - { - XIEventMask em; - unsigned char mask[XIMaskLen(XI_RawMotion)] = { 0 }; - - em.deviceid = XIAllMasterDevices; - em.mask_len = sizeof(mask); - em.mask = mask; - XISetMask(mask, XI_RawMotion); - - XISelectEvents(_glfw.x11.display, _glfw.x11.root, &em, 1); - } - - _glfw.x11.disabledCursorWindow = window; - _glfwPlatformGetCursorPos(window, - &_glfw.x11.restoreCursorPosX, - &_glfw.x11.restoreCursorPosY); - centerCursor(window); - XGrabPointer(_glfw.x11.display, window->x11.handle, True, - ButtonPressMask | ButtonReleaseMask | PointerMotionMask, - GrabModeAsync, GrabModeAsync, - window->x11.handle, - _glfw.x11.hiddenCursorHandle, - CurrentTime); + if (_glfwPlatformWindowFocused(window)) + disableCursor(window); } else if (_glfw.x11.disabledCursorWindow == window) - { - if (_glfw.x11.xi.available) - { - XIEventMask em; - unsigned char mask[] = { 0 }; + enableCursor(window); + else + updateCursorImage(window); - em.deviceid = XIAllMasterDevices; - em.mask_len = sizeof(mask); - em.mask = mask; - - XISelectEvents(_glfw.x11.display, _glfw.x11.root, &em, 1); - } - - _glfw.x11.disabledCursorWindow = NULL; - XUngrabPointer(_glfw.x11.display, CurrentTime); - _glfwPlatformSetCursorPos(window, - _glfw.x11.restoreCursorPosX, - _glfw.x11.restoreCursorPosY); - } - - updateCursorImage(window); XFlush(_glfw.x11.display); }