mirror of
				https://github.com/glfw/glfw.git
				synced 2025-10-31 04:32:26 +00:00 
			
		
		
		
	Add more standard cursors
This adds the standard cursors for diagonal and omnidirectional resize/move and operation-not-allowed. It also adds new (better?) names for the horizontal and vertical resize/move and pointing hand cursors. References: - https://developer.apple.com/documentation/appkit/nscursor - https://stackoverflow.com/questions/10733228/ - https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setsystemcursor - https://freedesktop.org/wiki/Specifications/cursor-spec/ - https://tronche.com/gui/x/xlib/appendix/b/ Related to #427.
This commit is contained in:
		
							parent
							
								
									80fde12fda
								
							
						
					
					
						commit
						7dbdd2e6a5
					
				| @ -118,6 +118,11 @@ information on what to include when reporting a bug. | ||||
| 
 | ||||
| ## Changelog | ||||
| 
 | ||||
|  - Added `GLFW_RESIZE_NWSE_CURSOR`, `GLFW_RESIZE_NESW_CURSOR`, | ||||
|    `GLFW_RESIZE_ALL_CURSOR` and `GLFW_NOT_ALLOWED_CURSOR` cursor shapes (#427) | ||||
|  - Added `GLFW_RESIZE_EW_CURSOR` alias for `GLFW_HRESIZE_CURSOR` (#427) | ||||
|  - Added `GLFW_RESIZE_NS_CURSOR` alias for `GLFW_VRESIZE_CURSOR` (#427) | ||||
|  - Added `GLFW_POINTING_HAND_CURSOR` alias for `GLFW_HAND_CURSOR` (#427) | ||||
|  - Disabled tests and examples by default when built as a CMake subdirectory | ||||
|  - Bugfix: The CMake config-file package used an absolute path and was not | ||||
|    relocatable (#1470) | ||||
|  | ||||
| @ -85,6 +85,13 @@ transparent window framebuffers.  If the running X server does not support this | ||||
| extension or there is no running compositing manager, the | ||||
| `GLFW_TRANSPARENT_FRAMEBUFFER` framebuffer hint will have no effect. | ||||
| 
 | ||||
| GLFW uses both the Xcursor extension and the freedesktop cursor conventions to | ||||
| provide an expanded set of standard cursor shapes.  If the running X server does | ||||
| not support this extension or the current cursor theme does not support the | ||||
| conventions, the `GLFW_RESIZE_NWSE_CURSOR`, `GLFW_RESIZE_NESW_CURSOR` and | ||||
| `GLFW_NOT_ALLOWED_CURSOR` shapes will not be available and other shapes may use | ||||
| legacy images. | ||||
| 
 | ||||
| 
 | ||||
| @section compat_wayland Wayland protocols and IPC standards | ||||
| 
 | ||||
|  | ||||
| @ -373,12 +373,15 @@ A cursor with a [standard shape](@ref shapes) from the current system cursor | ||||
| theme can be can be created with @ref glfwCreateStandardCursor. | ||||
| 
 | ||||
| @code | ||||
| GLFWcursor* cursor = glfwCreateStandardCursor(GLFW_HRESIZE_CURSOR); | ||||
| GLFWcursor* url_cursor = glfwCreateStandardCursor(GLFW_POINTING_HAND_CURSOR); | ||||
| @endcode | ||||
| 
 | ||||
| These cursor objects behave in the exact same way as those created with @ref | ||||
| glfwCreateCursor except that the system cursor theme provides the actual image. | ||||
| 
 | ||||
| A few of these shapes are not available everywhere.  If a shape is unavailable, | ||||
| `NULL` is returned.  See @ref glfwCreateStandardCursor for details. | ||||
| 
 | ||||
| 
 | ||||
| @subsubsection cursor_destruction Cursor destruction | ||||
| 
 | ||||
|  | ||||
| @ -9,6 +9,24 @@ | ||||
| 
 | ||||
| @subsection features_34 New features in version 3.4 | ||||
| 
 | ||||
| @subsubsection standard_cursors_34 More standard cursors | ||||
| 
 | ||||
| GLFW now provides the standard cursor shapes @ref GLFW_RESIZE_NWSE_CURSOR and | ||||
| @ref GLFW_RESIZE_NESW_CURSOR for diagonal resizing, @ref GLFW_RESIZE_ALL_CURSOR | ||||
| for omni-directional resizing and @ref GLFW_NOT_ALLOWED_CURSOR for showing an | ||||
| action is not allowed. | ||||
| 
 | ||||
| Unlike the original set, these shapes may not be available everywhere and | ||||
| creation will then fail with the new @ref GLFW_CURSOR_UNAVAILABLE error. | ||||
| 
 | ||||
| The cursors for horizontal and vertical resizing are now referred to as @ref | ||||
| GLFW_RESIZE_EW_CURSOR and @ref GLFW_RESIZE_NS_CURSOR, and the pointing hand | ||||
| cursor is now referred to as @ref GLFW_POINTING_HAND_CURSOR.  The older names | ||||
| are still available. | ||||
| 
 | ||||
| For more information see @ref cursor_standard. | ||||
| 
 | ||||
| 
 | ||||
| @subsubsection features_34_win32_keymenu Support for keyboard access to Windows window menu | ||||
| 
 | ||||
| GLFW now provides the | ||||
| @ -44,6 +62,14 @@ add_subdirectory(path/to/glfw) | ||||
| @subsubsection types_34 New types in version 3.4 | ||||
| @subsubsection constants_34 New constants in version 3.4 | ||||
| 
 | ||||
|  - @ref GLFW_POINTING_HAND_CURSOR | ||||
|  - @ref GLFW_RESIZE_EW_CURSOR | ||||
|  - @ref GLFW_RESIZE_NS_CURSOR | ||||
|  - @ref GLFW_RESIZE_NWSE_CURSOR | ||||
|  - @ref GLFW_RESIZE_NESW_CURSOR | ||||
|  - @ref GLFW_RESIZE_ALL_CURSOR | ||||
|  - @ref GLFW_NOT_ALLOWED_CURSOR | ||||
|  - @ref GLFW_CURSOR_UNAVAILABLE | ||||
|  - @ref GLFW_WIN32_KEYBOARD_MENU | ||||
| 
 | ||||
| 
 | ||||
|  | ||||
| @ -757,6 +757,17 @@ extern "C" { | ||||
|  *  @analysis Application programmer error.  Fix the offending call. | ||||
|  */ | ||||
| #define GLFW_NO_WINDOW_CONTEXT      0x0001000A | ||||
| /*! @brief The specified cursor shape is not available.
 | ||||
|  * | ||||
|  *  The specified standard cursor shape is not available, either because the | ||||
|  *  current system cursor theme does not provide it or because it is not | ||||
|  *  available on the platform. | ||||
|  * | ||||
|  *  @analysis Platform or system settings limitation.  Pick another | ||||
|  *  [standard cursor shape](@ref shapes) or create a | ||||
|  *  [custom cursor](@ref cursor_custom). | ||||
|  */ | ||||
| #define GLFW_CURSOR_UNAVAILABLE     0x0001000B | ||||
| /*! @} */ | ||||
| 
 | ||||
| /*! @addtogroup window
 | ||||
| @ -1039,14 +1050,15 @@ extern "C" { | ||||
| /*! @defgroup shapes Standard cursor shapes
 | ||||
|  *  @brief Standard system cursor shapes. | ||||
|  * | ||||
|  *  See [standard cursor creation](@ref cursor_standard) for how these are used. | ||||
|  *  These are the [standard cursor shapes](@ref cursor_standard) that can be | ||||
|  *  requested from the window system. | ||||
|  * | ||||
|  *  @ingroup input | ||||
|  *  @{ */ | ||||
| 
 | ||||
| /*! @brief The regular arrow cursor shape.
 | ||||
|  * | ||||
|  *  The regular arrow cursor. | ||||
|  *  The regular arrow cursor shape. | ||||
|  */ | ||||
| #define GLFW_ARROW_CURSOR           0x00036001 | ||||
| /*! @brief The text input I-beam cursor shape.
 | ||||
| @ -1054,26 +1066,91 @@ extern "C" { | ||||
|  *  The text input I-beam cursor shape. | ||||
|  */ | ||||
| #define GLFW_IBEAM_CURSOR           0x00036002 | ||||
| /*! @brief The crosshair shape.
 | ||||
| /*! @brief The crosshair cursor shape.
 | ||||
|  * | ||||
|  *  The crosshair shape. | ||||
|  *  The crosshair cursor shape. | ||||
|  */ | ||||
| #define GLFW_CROSSHAIR_CURSOR       0x00036003 | ||||
| /*! @brief The hand shape.
 | ||||
| /*! @brief The pointing hand cursor shape.
 | ||||
|  * | ||||
|  *  The hand shape. | ||||
|  *  The pointing hand cursor shape. | ||||
|  */ | ||||
| #define GLFW_HAND_CURSOR            0x00036004 | ||||
| /*! @brief The horizontal resize arrow shape.
 | ||||
| #define GLFW_POINTING_HAND_CURSOR   0x00036004 | ||||
| /*! @brief The horizontal resize/move arrow shape.
 | ||||
|  * | ||||
|  *  The horizontal resize arrow shape. | ||||
|  *  The horizontal resize/move arrow shape.  This is usually a horizontal | ||||
|  *  double-headed arrow. | ||||
|  */ | ||||
| #define GLFW_HRESIZE_CURSOR         0x00036005 | ||||
| /*! @brief The vertical resize arrow shape.
 | ||||
| #define GLFW_RESIZE_EW_CURSOR       0x00036005 | ||||
| /*! @brief The vertical resize/move arrow shape.
 | ||||
|  * | ||||
|  *  The vertical resize arrow shape. | ||||
|  *  The vertical resize/move shape.  This is usually a vertical double-headed | ||||
|  *  arrow. | ||||
|  */ | ||||
| #define GLFW_VRESIZE_CURSOR         0x00036006 | ||||
| #define GLFW_RESIZE_NS_CURSOR       0x00036006 | ||||
| /*! @brief The top-left to bottom-right diagonal resize/move arrow shape.
 | ||||
|  * | ||||
|  *  The top-left to bottom-right diagonal resize/move shape.  This is usually | ||||
|  *  a diagonal double-headed arrow. | ||||
|  * | ||||
|  *  @note @macos This shape is provided by a private system API and may fail | ||||
|  *  with @ref GLFW_CURSOR_UNAVAILABLE in the future. | ||||
|  * | ||||
|  *  @note @x11 This shape is provided by a newer standard not supported by all | ||||
|  *  cursor themes. | ||||
|  * | ||||
|  *  @note @wayland This shape is provided by a newer standard not supported by | ||||
|  *  all cursor themes. | ||||
|  */ | ||||
| #define GLFW_RESIZE_NWSE_CURSOR     0x00036007 | ||||
| /*! @brief The top-right to bottom-left diagonal resize/move arrow shape.
 | ||||
|  * | ||||
|  *  The top-right to bottom-left diagonal resize/move shape.  This is usually | ||||
|  *  a diagonal double-headed arrow. | ||||
|  * | ||||
|  *  @note @macos This shape is provided by a private system API and may fail | ||||
|  *  with @ref GLFW_CURSOR_UNAVAILABLE in the future. | ||||
|  * | ||||
|  *  @note @x11 This shape is provided by a newer standard not supported by all | ||||
|  *  cursor themes. | ||||
|  * | ||||
|  *  @note @wayland This shape is provided by a newer standard not supported by | ||||
|  *  all cursor themes. | ||||
|  */ | ||||
| #define GLFW_RESIZE_NESW_CURSOR     0x00036008 | ||||
| /*! @brief The omni-directional resize/move cursor shape.
 | ||||
|  * | ||||
|  *  The omni-directional resize cursor/move shape.  This is usually either | ||||
|  *  a combined horizontal and vertical double-headed arrow or a grabbing hand. | ||||
|  */ | ||||
| #define GLFW_RESIZE_ALL_CURSOR      0x00036009 | ||||
| /*! @brief The operation-not-allowed shape.
 | ||||
|  * | ||||
|  *  The operation-not-allowed shape.  This is usually a circle with a diagonal | ||||
|  *  line through it. | ||||
|  * | ||||
|  *  @note @x11 This shape is provided by a newer standard not supported by all | ||||
|  *  cursor themes. | ||||
|  * | ||||
|  *  @note @wayland This shape is provided by a newer standard not supported by | ||||
|  *  all cursor themes. | ||||
|  */ | ||||
| #define GLFW_NOT_ALLOWED_CURSOR     0x0003600A | ||||
| /*! @brief Legacy name for compatibility.
 | ||||
|  * | ||||
|  *  This is an alias for compatibility with earlier versions. | ||||
|  */ | ||||
| #define GLFW_HRESIZE_CURSOR         GLFW_RESIZE_EW_CURSOR | ||||
| /*! @brief Legacy name for compatibility.
 | ||||
|  * | ||||
|  *  This is an alias for compatibility with earlier versions. | ||||
|  */ | ||||
| #define GLFW_VRESIZE_CURSOR         GLFW_RESIZE_NS_CURSOR | ||||
| /*! @brief Legacy name for compatibility.
 | ||||
|  * | ||||
|  *  This is an alias for compatibility with earlier versions. | ||||
|  */ | ||||
| #define GLFW_HAND_CURSOR            GLFW_POINTING_HAND_CURSOR | ||||
| /*! @} */ | ||||
| 
 | ||||
| #define GLFW_CONNECTED              0x00040001 | ||||
| @ -4417,19 +4494,44 @@ 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), that can be set for | ||||
|  *  a window with @ref glfwSetCursor. | ||||
|  *  Returns a cursor with a standard shape, that can be set for a window with | ||||
|  *  @ref glfwSetCursor.  The images for these cursors come from the system | ||||
|  *  cursor theme and their exact appearance will vary between platforms. | ||||
|  * | ||||
|  *  Most of these shapes are guaranteed to exist on every supported platform but | ||||
|  *  a few may not be present.  See the table below for details. | ||||
|  * | ||||
|  *  Cursor shape                   | Windows | macOS | X11    | Wayland | ||||
|  *  ------------------------------ | ------- | ----- | ------ | ------- | ||||
|  *  @ref GLFW_ARROW_CURSOR         | Yes     | Yes   | Yes    | Yes | ||||
|  *  @ref GLFW_IBEAM_CURSOR         | Yes     | Yes   | Yes    | Yes | ||||
|  *  @ref GLFW_CROSSHAIR_CURSOR     | Yes     | Yes   | Yes    | Yes | ||||
|  *  @ref GLFW_POINTING_HAND_CURSOR | Yes     | Yes   | Yes    | Yes | ||||
|  *  @ref GLFW_RESIZE_EW_CURSOR     | Yes     | Yes   | Yes    | Yes | ||||
|  *  @ref GLFW_RESIZE_NS_CURSOR     | Yes     | Yes   | Yes    | Yes | ||||
|  *  @ref GLFW_RESIZE_NWSE_CURSOR   | Yes     | Yes<sup>1</sup> | Maybe<sup>2</sup> | Maybe<sup>2</sup> | ||||
|  *  @ref GLFW_RESIZE_NESW_CURSOR   | Yes     | Yes<sup>1</sup> | Maybe<sup>2</sup> | Maybe<sup>2</sup> | ||||
|  *  @ref GLFW_RESIZE_ALL_CURSOR    | Yes     | Yes   | Yes    | Yes | ||||
|  *  @ref GLFW_NOT_ALLOWED_CURSOR   | Yes     | Yes   | Maybe<sup>2</sup> | Maybe<sup>2</sup> | ||||
|  * | ||||
|  *  1) This uses a private system API and may fail in the future. | ||||
|  * | ||||
|  *  2) This uses a newer standard that not all cursor themes support. | ||||
|  * | ||||
|  *  If the requested shape is not available, this function emits a @ref | ||||
|  *  GLFW_CURSOR_UNAVAILABLE error and returns `NULL`. | ||||
|  * | ||||
|  *  @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. | ||||
|  * | ||||
|  *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref | ||||
|  *  GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. | ||||
|  *  GLFW_INVALID_ENUM, @ref GLFW_CURSOR_UNAVAILABLE and @ref | ||||
|  *  GLFW_PLATFORM_ERROR. | ||||
|  * | ||||
|  *  @thread_safety This function must only be called from the main thread. | ||||
|  * | ||||
|  *  @sa @ref cursor_object | ||||
|  *  @sa @ref cursor_standard | ||||
|  *  @sa @ref glfwCreateCursor | ||||
|  * | ||||
|  *  @since Added in version 3.1. | ||||
|  | ||||
| @ -1603,23 +1603,49 @@ int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape) | ||||
| { | ||||
|     @autoreleasepool { | ||||
| 
 | ||||
|     if (shape == GLFW_ARROW_CURSOR) | ||||
|         cursor->ns.object = [NSCursor arrowCursor]; | ||||
|     else if (shape == GLFW_IBEAM_CURSOR) | ||||
|         cursor->ns.object = [NSCursor IBeamCursor]; | ||||
|     else if (shape == GLFW_CROSSHAIR_CURSOR) | ||||
|         cursor->ns.object = [NSCursor crosshairCursor]; | ||||
|     else if (shape == GLFW_HAND_CURSOR) | ||||
|         cursor->ns.object = [NSCursor pointingHandCursor]; | ||||
|     else if (shape == GLFW_HRESIZE_CURSOR) | ||||
|         cursor->ns.object = [NSCursor resizeLeftRightCursor]; | ||||
|     else if (shape == GLFW_VRESIZE_CURSOR) | ||||
|         cursor->ns.object = [NSCursor resizeUpDownCursor]; | ||||
|     SEL cursorSelector = NULL; | ||||
| 
 | ||||
|     // HACK: Try to use a private message | ||||
|     if (shape == GLFW_RESIZE_EW_CURSOR) | ||||
|         cursorSelector = @selector(_windowResizeEastWestCursor); | ||||
|     else if (shape == GLFW_RESIZE_NS_CURSOR) | ||||
|         cursorSelector = @selector(_windowResizeNorthSouthCursor); | ||||
|     else if (shape == GLFW_RESIZE_NWSE_CURSOR) | ||||
|         cursorSelector = @selector(_windowResizeNorthWestSouthEastCursor); | ||||
|     else if (shape == GLFW_RESIZE_NESW_CURSOR) | ||||
|         cursorSelector = @selector(_windowResizeNorthEastSouthWestCursor); | ||||
| 
 | ||||
|     if (cursorSelector && [NSCursor respondsToSelector:cursorSelector]) | ||||
|     { | ||||
|         id object = [NSCursor performSelector:cursorSelector]; | ||||
|         if ([object isKindOfClass:[NSCursor class]]) | ||||
|             cursor->ns.object = object; | ||||
|     } | ||||
| 
 | ||||
|     if (!cursor->ns.object) | ||||
|     { | ||||
|         _glfwInputError(GLFW_PLATFORM_ERROR, | ||||
|                         "Cocoa: Failed to retrieve standard cursor"); | ||||
|         if (shape == GLFW_ARROW_CURSOR) | ||||
|             cursor->ns.object = [NSCursor arrowCursor]; | ||||
|         else if (shape == GLFW_IBEAM_CURSOR) | ||||
|             cursor->ns.object = [NSCursor IBeamCursor]; | ||||
|         else if (shape == GLFW_CROSSHAIR_CURSOR) | ||||
|             cursor->ns.object = [NSCursor crosshairCursor]; | ||||
|         else if (shape == GLFW_POINTING_HAND_CURSOR) | ||||
|             cursor->ns.object = [NSCursor pointingHandCursor]; | ||||
|         else if (shape == GLFW_RESIZE_EW_CURSOR) | ||||
|             cursor->ns.object = [NSCursor resizeLeftRightCursor]; | ||||
|         else if (shape == GLFW_RESIZE_NS_CURSOR) | ||||
|             cursor->ns.object = [NSCursor resizeUpDownCursor]; | ||||
|         else if (shape == GLFW_RESIZE_ALL_CURSOR) | ||||
|             cursor->ns.object = [NSCursor closedHandCursor]; | ||||
|         else if (shape == GLFW_NOT_ALLOWED_CURSOR) | ||||
|             cursor->ns.object = [NSCursor operationNotAllowedCursor]; | ||||
|     } | ||||
| 
 | ||||
|     if (!cursor->ns.object) | ||||
|     { | ||||
|         _glfwInputError(GLFW_CURSOR_UNAVAILABLE, | ||||
|                         "Cocoa: Standard cursor shape unavailable"); | ||||
|         return GLFW_FALSE; | ||||
|     } | ||||
| 
 | ||||
|  | ||||
| @ -189,6 +189,8 @@ void _glfwInputError(int code, const char* format, ...) | ||||
|             strcpy(description, "The requested format is unavailable"); | ||||
|         else if (code == GLFW_NO_WINDOW_CONTEXT) | ||||
|             strcpy(description, "The specified window has no context"); | ||||
|         else if (code == GLFW_CURSOR_UNAVAILABLE) | ||||
|             strcpy(description, "The specified cursor shape is unavailable"); | ||||
|         else | ||||
|             strcpy(description, "ERROR: UNKNOWN GLFW ERROR"); | ||||
|     } | ||||
|  | ||||
							
								
								
									
										10
									
								
								src/input.c
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								src/input.c
									
									
									
									
									
								
							| @ -757,9 +757,13 @@ GLFWAPI GLFWcursor* glfwCreateStandardCursor(int shape) | ||||
|     if (shape != GLFW_ARROW_CURSOR && | ||||
|         shape != GLFW_IBEAM_CURSOR && | ||||
|         shape != GLFW_CROSSHAIR_CURSOR && | ||||
|         shape != GLFW_HAND_CURSOR && | ||||
|         shape != GLFW_HRESIZE_CURSOR && | ||||
|         shape != GLFW_VRESIZE_CURSOR) | ||||
|         shape != GLFW_POINTING_HAND_CURSOR && | ||||
|         shape != GLFW_RESIZE_EW_CURSOR && | ||||
|         shape != GLFW_RESIZE_NS_CURSOR && | ||||
|         shape != GLFW_RESIZE_NWSE_CURSOR && | ||||
|         shape != GLFW_RESIZE_NESW_CURSOR && | ||||
|         shape != GLFW_RESIZE_ALL_CURSOR && | ||||
|         shape != GLFW_NOT_ALLOWED_CURSOR) | ||||
|     { | ||||
|         _glfwInputError(GLFW_INVALID_ENUM, "Invalid standard cursor 0x%08X", shape); | ||||
|         return NULL; | ||||
|  | ||||
| @ -2068,14 +2068,25 @@ int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape) | ||||
|         id = OCR_IBEAM; | ||||
|     else if (shape == GLFW_CROSSHAIR_CURSOR) | ||||
|         id = OCR_CROSS; | ||||
|     else if (shape == GLFW_HAND_CURSOR) | ||||
|     else if (shape == GLFW_POINTING_HAND_CURSOR) | ||||
|         id = OCR_HAND; | ||||
|     else if (shape == GLFW_HRESIZE_CURSOR) | ||||
|     else if (shape == GLFW_RESIZE_EW_CURSOR) | ||||
|         id = OCR_SIZEWE; | ||||
|     else if (shape == GLFW_VRESIZE_CURSOR) | ||||
|     else if (shape == GLFW_RESIZE_NS_CURSOR) | ||||
|         id = OCR_SIZENS; | ||||
|     else if (shape == GLFW_RESIZE_NWSE_CURSOR) | ||||
|         id = OCR_SIZENWSE; | ||||
|     else if (shape == GLFW_RESIZE_NESW_CURSOR) | ||||
|         id = OCR_SIZENESW; | ||||
|     else if (shape == GLFW_RESIZE_ALL_CURSOR) | ||||
|         id = OCR_SIZEALL; | ||||
|     else if (shape == GLFW_NOT_ALLOWED_CURSOR) | ||||
|         id = OCR_NO; | ||||
|     else | ||||
|     { | ||||
|         _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Unknown standard cursor"); | ||||
|         return GLFW_FALSE; | ||||
|     } | ||||
| 
 | ||||
|     cursor->win32.handle = LoadImageW(NULL, | ||||
|                                       MAKEINTRESOURCEW(id), IMAGE_CURSOR, 0, 0, | ||||
|  | ||||
							
								
								
									
										105
									
								
								src/wl_window.c
									
									
									
									
									
								
							
							
						
						
									
										105
									
								
								src/wl_window.c
									
									
									
									
									
								
							| @ -770,28 +770,6 @@ static void handleEvents(int timeout) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| // Translates a GLFW standard cursor to a theme cursor name
 | ||||
| //
 | ||||
| static char *translateCursorShape(int shape) | ||||
| { | ||||
|     switch (shape) | ||||
|     { | ||||
|         case GLFW_ARROW_CURSOR: | ||||
|             return "left_ptr"; | ||||
|         case GLFW_IBEAM_CURSOR: | ||||
|             return "xterm"; | ||||
|         case GLFW_CROSSHAIR_CURSOR: | ||||
|             return "crosshair"; | ||||
|         case GLFW_HAND_CURSOR: | ||||
|             return "hand2"; | ||||
|         case GLFW_HRESIZE_CURSOR: | ||||
|             return "sb_h_double_arrow"; | ||||
|         case GLFW_VRESIZE_CURSOR: | ||||
|             return "sb_v_double_arrow"; | ||||
|     } | ||||
|     return NULL; | ||||
| } | ||||
| 
 | ||||
| //////////////////////////////////////////////////////////////////////////
 | ||||
| //////                       GLFW platform API                      //////
 | ||||
| //////////////////////////////////////////////////////////////////////////
 | ||||
| @ -1233,26 +1211,79 @@ int _glfwPlatformCreateCursor(_GLFWcursor* cursor, | ||||
| 
 | ||||
| int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape) | ||||
| { | ||||
|     struct wl_cursor* standardCursor; | ||||
|     const char* name = NULL; | ||||
| 
 | ||||
|     standardCursor = wl_cursor_theme_get_cursor(_glfw.wl.cursorTheme, | ||||
|                                                 translateCursorShape(shape)); | ||||
|     if (!standardCursor) | ||||
|     { | ||||
|         _glfwInputError(GLFW_PLATFORM_ERROR, | ||||
|                         "Wayland: Standard cursor \"%s\" not found", | ||||
|                         translateCursorShape(shape)); | ||||
|         return GLFW_FALSE; | ||||
|     } | ||||
|     // Try the XDG names first
 | ||||
|     if (shape == GLFW_ARROW_CURSOR) | ||||
|         name = "default"; | ||||
|     else if (shape == GLFW_IBEAM_CURSOR) | ||||
|         name = "text"; | ||||
|     else if (shape == GLFW_CROSSHAIR_CURSOR) | ||||
|         name = "crosshair"; | ||||
|     else if (shape == GLFW_POINTING_HAND_CURSOR) | ||||
|         name = "pointer"; | ||||
|     else if (shape == GLFW_RESIZE_EW_CURSOR) | ||||
|         name = "ew-resize"; | ||||
|     else if (shape == GLFW_RESIZE_NS_CURSOR) | ||||
|         name = "ns-resize"; | ||||
|     else if (shape == GLFW_RESIZE_NWSE_CURSOR) | ||||
|         name = "nwse-resize"; | ||||
|     else if (shape == GLFW_RESIZE_NESW_CURSOR) | ||||
|         name = "nesw-resize"; | ||||
|     else if (shape == GLFW_RESIZE_ALL_CURSOR) | ||||
|         name = "all-scroll"; | ||||
|     else if (shape == GLFW_NOT_ALLOWED_CURSOR) | ||||
|         name = "not-allowed"; | ||||
| 
 | ||||
|     cursor->wl.cursor = standardCursor; | ||||
|     cursor->wl.currentImage = 0; | ||||
|     cursor->wl.cursor = wl_cursor_theme_get_cursor(_glfw.wl.cursorTheme, name); | ||||
| 
 | ||||
|     if (_glfw.wl.cursorThemeHiDPI) | ||||
|     { | ||||
|         standardCursor = wl_cursor_theme_get_cursor(_glfw.wl.cursorThemeHiDPI, | ||||
|                                                     translateCursorShape(shape)); | ||||
|         cursor->wl.cursorHiDPI = standardCursor; | ||||
|         cursor->wl.cursorHiDPI = | ||||
|             wl_cursor_theme_get_cursor(_glfw.wl.cursorThemeHiDPI, name); | ||||
|     } | ||||
| 
 | ||||
|     if (!cursor->wl.cursor) | ||||
|     { | ||||
|         // Fall back to the core X11 names
 | ||||
|         if (shape == GLFW_ARROW_CURSOR) | ||||
|             name = "left_ptr"; | ||||
|         else if (shape == GLFW_IBEAM_CURSOR) | ||||
|             name = "xterm"; | ||||
|         else if (shape == GLFW_CROSSHAIR_CURSOR) | ||||
|             name = "crosshair"; | ||||
|         else if (shape == GLFW_POINTING_HAND_CURSOR) | ||||
|             name = "hand2"; | ||||
|         else if (shape == GLFW_RESIZE_EW_CURSOR) | ||||
|             name = "sb_h_double_arrow"; | ||||
|         else if (shape == GLFW_RESIZE_NS_CURSOR) | ||||
|             name = "sb_v_double_arrow"; | ||||
|         else if (shape == GLFW_RESIZE_ALL_CURSOR) | ||||
|             name = "fleur"; | ||||
|         else | ||||
|         { | ||||
|             _glfwInputError(GLFW_CURSOR_UNAVAILABLE, | ||||
|                             "Wayland: Standard cursor shape unavailable"); | ||||
|             return GLFW_FALSE; | ||||
|         } | ||||
| 
 | ||||
|         cursor->wl.cursor = wl_cursor_theme_get_cursor(_glfw.wl.cursorTheme, name); | ||||
|         if (!cursor->wl.cursor) | ||||
|         { | ||||
|             _glfwInputError(GLFW_PLATFORM_ERROR, | ||||
|                             "Wayland: Failed to create standard cursor \"%s\"", | ||||
|                             name); | ||||
|             return GLFW_FALSE; | ||||
|         } | ||||
| 
 | ||||
|         if (_glfw.wl.cursorThemeHiDPI) | ||||
|         { | ||||
|             if (!cursor->wl.cursorHiDPI) | ||||
|             { | ||||
|                 cursor->wl.cursorHiDPI = | ||||
|                     wl_cursor_theme_get_cursor(_glfw.wl.cursorThemeHiDPI, name); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return GLFW_TRUE; | ||||
|  | ||||
| @ -615,6 +615,12 @@ static GLFWbool initExtensions(void) | ||||
|             _glfw_dlsym(_glfw.x11.xcursor.handle, "XcursorImageDestroy"); | ||||
|         _glfw.x11.xcursor.ImageLoadCursor = (PFN_XcursorImageLoadCursor) | ||||
|             _glfw_dlsym(_glfw.x11.xcursor.handle, "XcursorImageLoadCursor"); | ||||
|         _glfw.x11.xcursor.GetTheme = (PFN_XcursorGetTheme) | ||||
|             _glfw_dlsym(_glfw.x11.xcursor.handle, "XcursorGetTheme"); | ||||
|         _glfw.x11.xcursor.GetDefaultSize = (PFN_XcursorGetDefaultSize) | ||||
|             _glfw_dlsym(_glfw.x11.xcursor.handle, "XcursorGetDefaultSize"); | ||||
|         _glfw.x11.xcursor.LibraryLoadImage = (PFN_XcursorLibraryLoadImage) | ||||
|             _glfw_dlsym(_glfw.x11.xcursor.handle, "XcursorLibraryLoadImage"); | ||||
|     } | ||||
| 
 | ||||
| #if defined(__CYGWIN__) | ||||
|  | ||||
| @ -85,9 +85,15 @@ typedef int (* PFN_XRRUpdateConfiguration)(XEvent*); | ||||
| typedef XcursorImage* (* PFN_XcursorImageCreate)(int,int); | ||||
| typedef void (* PFN_XcursorImageDestroy)(XcursorImage*); | ||||
| typedef Cursor (* PFN_XcursorImageLoadCursor)(Display*,const XcursorImage*); | ||||
| typedef char* (* PFN_XcursorGetTheme)(Display*); | ||||
| typedef int (* PFN_XcursorGetDefaultSize)(Display*); | ||||
| typedef XcursorImage* (* PFN_XcursorLibraryLoadImage)(const char*,const char*,int); | ||||
| #define XcursorImageCreate _glfw.x11.xcursor.ImageCreate | ||||
| #define XcursorImageDestroy _glfw.x11.xcursor.ImageDestroy | ||||
| #define XcursorImageLoadCursor _glfw.x11.xcursor.ImageLoadCursor | ||||
| #define XcursorGetTheme _glfw.x11.xcursor.GetTheme | ||||
| #define XcursorGetDefaultSize _glfw.x11.xcursor.GetDefaultSize | ||||
| #define XcursorLibraryLoadImage _glfw.x11.xcursor.LibraryLoadImage | ||||
| 
 | ||||
| typedef Bool (* PFN_XineramaIsActive)(Display*); | ||||
| typedef Bool (* PFN_XineramaQueryExtension)(Display*,int*,int*); | ||||
| @ -352,6 +358,9 @@ typedef struct _GLFWlibraryX11 | ||||
|         PFN_XcursorImageCreate ImageCreate; | ||||
|         PFN_XcursorImageDestroy ImageDestroy; | ||||
|         PFN_XcursorImageLoadCursor ImageLoadCursor; | ||||
|         PFN_XcursorGetTheme GetTheme; | ||||
|         PFN_XcursorGetDefaultSize GetDefaultSize; | ||||
|         PFN_XcursorLibraryLoadImage LibraryLoadImage; | ||||
|     } xcursor; | ||||
| 
 | ||||
|     struct { | ||||
|  | ||||
| @ -2823,29 +2823,76 @@ int _glfwPlatformCreateCursor(_GLFWcursor* cursor, | ||||
| 
 | ||||
| int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape) | ||||
| { | ||||
|     int native = 0; | ||||
|     if (_glfw.x11.xcursor.handle) | ||||
|     { | ||||
|         char* theme = XcursorGetTheme(_glfw.x11.display); | ||||
|         if (theme) | ||||
|         { | ||||
|             const int size = XcursorGetDefaultSize(_glfw.x11.display); | ||||
|             const char* name = NULL; | ||||
| 
 | ||||
|     if (shape == GLFW_ARROW_CURSOR) | ||||
|         native = XC_left_ptr; | ||||
|     else if (shape == GLFW_IBEAM_CURSOR) | ||||
|         native = XC_xterm; | ||||
|     else if (shape == GLFW_CROSSHAIR_CURSOR) | ||||
|         native = XC_crosshair; | ||||
|     else if (shape == GLFW_HAND_CURSOR) | ||||
|         native = XC_hand2; | ||||
|     else if (shape == GLFW_HRESIZE_CURSOR) | ||||
|         native = XC_sb_h_double_arrow; | ||||
|     else if (shape == GLFW_VRESIZE_CURSOR) | ||||
|         native = XC_sb_v_double_arrow; | ||||
|     else | ||||
|         return GLFW_FALSE; | ||||
|             if (shape == GLFW_ARROW_CURSOR) | ||||
|                 name = "default"; | ||||
|             else if (shape == GLFW_IBEAM_CURSOR) | ||||
|                 name = "text"; | ||||
|             else if (shape == GLFW_CROSSHAIR_CURSOR) | ||||
|                 name = "crosshair"; | ||||
|             else if (shape == GLFW_POINTING_HAND_CURSOR) | ||||
|                 name = "pointer"; | ||||
|             else if (shape == GLFW_RESIZE_EW_CURSOR) | ||||
|                 name = "ew-resize"; | ||||
|             else if (shape == GLFW_RESIZE_NS_CURSOR) | ||||
|                 name = "ns-resize"; | ||||
|             else if (shape == GLFW_RESIZE_NWSE_CURSOR) | ||||
|                 name = "nwse-resize"; | ||||
|             else if (shape == GLFW_RESIZE_NESW_CURSOR) | ||||
|                 name = "nesw-resize"; | ||||
|             else if (shape == GLFW_RESIZE_ALL_CURSOR) | ||||
|                 name = "all-scroll"; | ||||
|             else if (shape == GLFW_NOT_ALLOWED_CURSOR) | ||||
|                 name = "not-allowed"; | ||||
| 
 | ||||
|             XcursorImage* image = XcursorLibraryLoadImage(name, theme, size); | ||||
|             if (image) | ||||
|             { | ||||
|                 cursor->x11.handle = XcursorImageLoadCursor(_glfw.x11.display, image); | ||||
|                 XcursorImageDestroy(image); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     cursor->x11.handle = XCreateFontCursor(_glfw.x11.display, native); | ||||
|     if (!cursor->x11.handle) | ||||
|     { | ||||
|         _glfwInputError(GLFW_PLATFORM_ERROR, | ||||
|                         "X11: Failed to create standard cursor"); | ||||
|         return GLFW_FALSE; | ||||
|         unsigned int native = 0; | ||||
| 
 | ||||
|         if (shape == GLFW_ARROW_CURSOR) | ||||
|             native = XC_left_ptr; | ||||
|         else if (shape == GLFW_IBEAM_CURSOR) | ||||
|             native = XC_xterm; | ||||
|         else if (shape == GLFW_CROSSHAIR_CURSOR) | ||||
|             native = XC_crosshair; | ||||
|         else if (shape == GLFW_POINTING_HAND_CURSOR) | ||||
|             native = XC_hand2; | ||||
|         else if (shape == GLFW_RESIZE_EW_CURSOR) | ||||
|             native = XC_sb_h_double_arrow; | ||||
|         else if (shape == GLFW_RESIZE_NS_CURSOR) | ||||
|             native = XC_sb_v_double_arrow; | ||||
|         else if (shape == GLFW_RESIZE_ALL_CURSOR) | ||||
|             native = XC_fleur; | ||||
|         else | ||||
|         { | ||||
|             _glfwInputError(GLFW_CURSOR_UNAVAILABLE, | ||||
|                             "X11: Standard cursor shape unavailable"); | ||||
|             return GLFW_FALSE; | ||||
|         } | ||||
| 
 | ||||
|         cursor->x11.handle = XCreateFontCursor(_glfw.x11.display, native); | ||||
|         if (!cursor->x11.handle) | ||||
|         { | ||||
|             _glfwInputError(GLFW_PLATFORM_ERROR, | ||||
|                             "X11: Failed to create standard cursor"); | ||||
|             return GLFW_FALSE; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return GLFW_TRUE; | ||||
|  | ||||
| @ -69,7 +69,7 @@ static int swap_interval = 1; | ||||
| static int wait_events = GLFW_TRUE; | ||||
| static int animate_cursor = GLFW_FALSE; | ||||
| static int track_cursor = GLFW_FALSE; | ||||
| static GLFWcursor* standard_cursors[6]; | ||||
| static GLFWcursor* standard_cursors[10]; | ||||
| static GLFWcursor* tracking_cursor = NULL; | ||||
| 
 | ||||
| static void error_callback(int error, const char* description) | ||||
| @ -271,28 +271,24 @@ static void key_callback(GLFWwindow* window, int key, int scancode, int action, | ||||
|             break; | ||||
| 
 | ||||
|         case GLFW_KEY_1: | ||||
|             glfwSetCursor(window, standard_cursors[0]); | ||||
|             break; | ||||
| 
 | ||||
|         case GLFW_KEY_2: | ||||
|             glfwSetCursor(window, standard_cursors[1]); | ||||
|             break; | ||||
| 
 | ||||
|         case GLFW_KEY_3: | ||||
|             glfwSetCursor(window, standard_cursors[2]); | ||||
|             break; | ||||
| 
 | ||||
|         case GLFW_KEY_4: | ||||
|             glfwSetCursor(window, standard_cursors[3]); | ||||
|             break; | ||||
| 
 | ||||
|         case GLFW_KEY_5: | ||||
|             glfwSetCursor(window, standard_cursors[4]); | ||||
|             break; | ||||
| 
 | ||||
|         case GLFW_KEY_6: | ||||
|             glfwSetCursor(window, standard_cursors[5]); | ||||
|         case GLFW_KEY_7: | ||||
|         case GLFW_KEY_8: | ||||
|         case GLFW_KEY_9: | ||||
|         { | ||||
|             int index = key - GLFW_KEY_1; | ||||
|             if (mods & GLFW_MOD_SHIFT) | ||||
|                 index += 9; | ||||
| 
 | ||||
|             if (index < sizeof(standard_cursors) / sizeof(standard_cursors[0])) | ||||
|                 glfwSetCursor(window, standard_cursors[index]); | ||||
| 
 | ||||
|             break; | ||||
|         } | ||||
| 
 | ||||
|         case GLFW_KEY_F11: | ||||
|         case GLFW_KEY_ENTER: | ||||
| @ -358,17 +354,16 @@ int main(void) | ||||
|             GLFW_ARROW_CURSOR, | ||||
|             GLFW_IBEAM_CURSOR, | ||||
|             GLFW_CROSSHAIR_CURSOR, | ||||
|             GLFW_HAND_CURSOR, | ||||
|             GLFW_HRESIZE_CURSOR, | ||||
|             GLFW_VRESIZE_CURSOR | ||||
|             GLFW_POINTING_HAND_CURSOR, | ||||
|             GLFW_RESIZE_EW_CURSOR, | ||||
|             GLFW_RESIZE_NS_CURSOR, | ||||
|             GLFW_RESIZE_NWSE_CURSOR, | ||||
|             GLFW_RESIZE_NESW_CURSOR, | ||||
|             GLFW_RESIZE_ALL_CURSOR, | ||||
|             GLFW_NOT_ALLOWED_CURSOR | ||||
|         }; | ||||
| 
 | ||||
|         standard_cursors[i] = glfwCreateStandardCursor(shapes[i]); | ||||
|         if (!standard_cursors[i]) | ||||
|         { | ||||
|             glfwTerminate(); | ||||
|             exit(EXIT_FAILURE); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2); | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user