Added glfwCreateStandardCursor.

This function allows the creation of cursor objects using one of several
standard cursor shapes from the current system cursor theme.
This commit is contained in:
Camilla Berglund 2014-09-02 16:52:16 +02:00
parent 1495134398
commit 2a1375e97c
11 changed files with 246 additions and 8 deletions

View File

@ -63,8 +63,8 @@ GLFW bundles a number of dependencies in the `deps/` directory.
## Changelog ## Changelog
- Added `GLFWcursor` custom system cursor handle - Added `GLFWcursor` custom system cursor handle
- Added `glfwCreateCursor`, `glfwDestroyCursor` and `glfwSetCursor` for - Added `glfwCreateCursor`, `glfwCreateStandardCursor`, `glfwDestroyCursor` and
managing custom system cursors `glfwSetCursor` for managing system cursor images
- Added `GLFWimage` struct for passing 32-bit RGBA images - Added `GLFWimage` struct for passing 32-bit RGBA images
- Added monitor and adapter identifier access to native API - Added monitor and adapter identifier access to native API
- Added `glfwSetDropCallback` and `GLFWdropfun` for receiving dropped files - Added `glfwSetDropCallback` and `GLFWdropfun` for receiving dropped files

View File

@ -343,6 +343,20 @@ When a cursor is destroyed, it is removed from any window where it is set. This
does not affect the cursor modes of those windows. does not affect the cursor modes of those windows.
@subsubsection input_cursor_standard Standard cursor shapes
Cursor objects with platform-specific variants of the
[standard shapes](@ref shapes) can be created with @ref
glfwCreateStandardCursor.
@code
GLFWcursor* cursor = glfwCreateStandardCursor(GLFW_HRESIZE_CURSOR);
@endcode
These cursor objects behave in the exact same way as those created with @ref
glfwCreateCursor except that the platform provides the cursor image data.
@subsection input_cursor_enter Cursor enter/leave events @subsection input_cursor_enter Cursor enter/leave events
If you wish to be notified when the cursor enters or leaves the client area of If you wish to be notified when the cursor enters or leaves the client area of

View File

@ -9,10 +9,9 @@
@subsection news_31_cursor Custom system cursor support @subsection news_31_cursor Custom system cursor support
GLFW now supports creating and setting custom system cursors. They can be GLFW now supports creating and setting both custom and standard system cursors.
created with @ref glfwCreateCursor, set with @ref glfwSetCursor and destroyed They can be created with @ref glfwCreateCursor or @ref glfwCreateStandardCursor,
with @ref glfwDestroyCursor. Custom cursors are only visible in normal cursor set with @ref glfwSetCursor and destroyed with @ref glfwDestroyCursor.
mode.
@subsection news_31_drop File drop event support @subsection news_31_drop File drop event support

View File

@ -672,6 +672,42 @@ extern "C" {
#define GLFW_RELEASE_BEHAVIOR_FLUSH 0x00035001 #define GLFW_RELEASE_BEHAVIOR_FLUSH 0x00035001
#define GLFW_RELEASE_BEHAVIOR_NONE 0x00035002 #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_CONNECTED 0x00040001
#define GLFW_DISCONNECTED 0x00040002 #define GLFW_DISCONNECTED 0x00040002
@ -2606,7 +2642,7 @@ GLFWAPI void glfwGetCursorPos(GLFWwindow* window, double* xpos, double* ypos);
*/ */
GLFWAPI void glfwSetCursorPos(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 * Creates a new cursor that can be made the system cursor for a window with
* @ref glfwSetCursor. The cursor can be destroyed with @ref * @ref glfwSetCursor. The cursor can be destroyed with @ref
@ -2633,6 +2669,7 @@ GLFWAPI void glfwSetCursorPos(GLFWwindow* window, double xpos, double ypos);
* *
* @sa @ref input_cursor * @sa @ref input_cursor
* @sa glfwDestroyCursor * @sa glfwDestroyCursor
* @sa glfwCreateStandardCursor
* *
* @par History * @par History
* Added in GLFW 3.1. * Added in GLFW 3.1.
@ -2641,6 +2678,31 @@ GLFWAPI void glfwSetCursorPos(GLFWwindow* window, double xpos, double ypos);
*/ */
GLFWAPI GLFWcursor* glfwCreateCursor(const GLFWimage* image, int xhot, int yhot); 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.
*
* @note 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. /*! @brief Destroys a cursor.
* *
* This function destroys a cursor previously created with @ref * This function destroys a cursor previously created with @ref

View File

@ -32,6 +32,29 @@
#include <crt_externs.h> #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 // Center the cursor in the view of the window
// //
static void centerCursor(_GLFWwindow *window) static void centerCursor(_GLFWwindow *window)
@ -1161,6 +1184,19 @@ int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
return GL_TRUE; 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) void _glfwPlatformDestroyCursor(_GLFWcursor* cursor)
{ {
if (cursor->ns.object) if (cursor->ns.object)

View File

@ -382,6 +382,25 @@ GLFWAPI GLFWcursor* glfwCreateCursor(const GLFWimage* image, int xhot, int yhot)
return (GLFWcursor*) cursor; 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) GLFWAPI void glfwDestroyCursor(GLFWcursor* handle)
{ {
_GLFWcursor* cursor = (_GLFWcursor*) handle; _GLFWcursor* cursor = (_GLFWcursor*) handle;

View File

@ -625,6 +625,11 @@ GLFWglproc _glfwPlatformGetProcAddress(const char* procname);
*/ */
int _glfwPlatformCreateCursor(_GLFWcursor* cursor, const GLFWimage* image, int xhot, int yhot); int _glfwPlatformCreateCursor(_GLFWcursor* cursor, const GLFWimage* image, int xhot, int yhot);
/*! @copydoc glfwCreateStandardCursor
* @ingroup platform
*/
int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape);
/*! @copydoc glfwDestroyCursor /*! @copydoc glfwDestroyCursor
* @ingroup platform * @ingroup platform
*/ */

View File

@ -610,6 +610,14 @@ int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
return GL_FALSE; 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) void _glfwPlatformDestroyCursor(_GLFWcursor* cursor)
{ {
_glfwInputError(GLFW_PLATFORM_ERROR, _glfwInputError(GLFW_PLATFORM_ERROR,

View File

@ -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 // Retrieves and translates modifier keys
// //
static int getKeyMods(void) static int getKeyMods(void)
@ -1176,6 +1199,26 @@ int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
return GL_TRUE; 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) void _glfwPlatformDestroyCursor(_GLFWcursor* cursor)
{ {
if (cursor->win32.handle) if (cursor->win32.handle)

View File

@ -422,6 +422,13 @@ int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
return GL_TRUE; return GL_TRUE;
} }
int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape)
{
// TODO
fprintf(stderr, "_glfwPlatformCreateStandardCursor not implemented yet\n");
return GL_FALSE;
}
void _glfwPlatformDestroyCursor(_GLFWcursor* cursor) void _glfwPlatformDestroyCursor(_GLFWcursor* cursor)
{ {
wl_buffer_destroy(cursor->wl.buffer); wl_buffer_destroy(cursor->wl.buffer);

View File

@ -27,6 +27,8 @@
#include "internal.h" #include "internal.h"
#include <X11/cursorfont.h>
#include <sys/select.h> #include <sys/select.h>
#include <string.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; 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 // Translates an X event modifier state mask
// //
static int translateState(int state) static int translateState(int state)
@ -1731,12 +1756,32 @@ int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
int xhot, int yhot) int xhot, int yhot)
{ {
cursor->x11.handle = _glfwCreateCursor(image, xhot, yhot); cursor->x11.handle = _glfwCreateCursor(image, xhot, yhot);
if (cursor->x11.handle == None) if (!cursor->x11.handle)
return GL_FALSE; return GL_FALSE;
return GL_TRUE; 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) void _glfwPlatformDestroyCursor(_GLFWcursor* cursor)
{ {
if (cursor->x11.handle) if (cursor->x11.handle)