1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

sokol: add mouse cursor support (#15111)

This commit is contained in:
Mehmet Ali 2022-07-18 09:44:48 +03:00 committed by GitHub
parent c1502b3c1f
commit 12d57e8e7b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 344 additions and 37 deletions

24
examples/gg/cursor.v Normal file
View File

@ -0,0 +1,24 @@
module main
import gg
import gx
import sokol.sapp
fn main() {
gg.new_context(
bg_color: gx.white
window_title: 'Cursor'
frame_fn: frame
init_fn: init
).run()
}
fn init(mut ctx gg.Context) {
sapp.set_mouse_cursor(.ibeam)
}
fn frame(mut ctx gg.Context) {
ctx.begin()
ctx.draw_text_def(10, 25, 'Your cursor should be an I shaped beam.')
ctx.end()
}

View File

@ -131,13 +131,13 @@
SUSPENDED | --- | --- | --- | YES | YES | YES | --- | TODO
RESUMED | --- | --- | --- | YES | YES | YES | --- | TODO
QUIT_REQUESTED | YES | YES | YES | --- | --- | --- | TODO | YES
UPDATE_CURSOR | YES | YES | TODO | --- | --- | TODO | --- | TODO
IME | TODO | TODO? | TODO | ??? | TODO | --- | ??? | ???
key repeat flag | YES | YES | YES | --- | --- | YES | TODO | YES
windowed | YES | YES | YES | --- | --- | YES | TODO | YES
fullscreen | YES | YES | YES | YES | YES | YES | TODO | ---
mouse hide | YES | YES | YES | --- | --- | YES | TODO | TODO
mouse hide | YES | YES | YES | --- | --- | YES | TODO | YES
mouse lock | YES | YES | YES | --- | --- | TODO | TODO | YES
set cursor type | YES | YES | YES | --- | --- | YES | TODO | YES
screen keyboard | --- | --- | --- | YES | TODO | TODO | --- | YES
swap interval | YES | YES | YES | YES | TODO | --- | TODO | YES
high-dpi | YES | YES | TODO | YES | YES | YES | TODO | YES
@ -369,6 +369,23 @@
"Really Quit?" dialog box). Note that the cleanup-callback isn't
guaranteed to be called on the web and mobile platforms.
MOUSE CURSOR TYPE AND VISIBILITY
================================
You can show and hide the mouse cursor with
void sapp_show_mouse(bool show)
And to get the current shown status:
bool sapp_mouse_shown(void)
NOTE that hiding the mouse cursor is different and independent from
the MOUSE/POINTER LOCK feature which will also hide the mouse pointer when
active (MOUSE LOCK is described below).
To change the mouse cursor to one of several predefined types, call
the function:
void sapp_set_mouse_cursor(sapp_mouse_cursor cursor)
Setting the default mouse cursor SAPP_MOUSECURSOR_DEFAULT will restore
the standard look.
To get the currently active mouse cursor type, call:
sapp_mouse_cursor sapp_get_mouse_cursor(void)
MOUSE LOCK (AKA POINTER LOCK, AKA MOUSE CAPTURE)
================================================
In normal mouse mode, no mouse movement events are reported when the
@ -970,9 +987,6 @@
- sapp_desc needs a bool whether to initialize depth-stencil surface
- GL context initialization needs more control (at least what GL version to initialize)
- application icon
- the UPDATE_CURSOR event currently behaves differently between Win32 and OSX
(Win32 sends the event each frame when the mouse moves and is inside the window
client area, OSX sends it only once when the mouse enters the client area)
- the Android implementation calls cleanup_cb() and destroys the egl context in onDestroy
at the latest but should do it earlier, in onStop, as an app is "killable" after onStop
on Android Honeycomb and later (it can't be done at the moment as the app may be started
@ -1064,7 +1078,6 @@ typedef enum sapp_event_type {
SAPP_EVENTTYPE_UNFOCUSED,
SAPP_EVENTTYPE_SUSPENDED,
SAPP_EVENTTYPE_RESUMED,
SAPP_EVENTTYPE_UPDATE_CURSOR,
SAPP_EVENTTYPE_QUIT_REQUESTED,
SAPP_EVENTTYPE_CLIPBOARD_PASTED,
SAPP_EVENTTYPE_FILES_DROPPED,
@ -1362,7 +1375,6 @@ typedef struct sapp_desc {
bool fullscreen; // whether the window should be created in fullscreen mode
bool alpha; // whether the framebuffer should have an alpha channel (ignored on some platforms)
const char* window_title; // the window title as UTF-8 encoded string
bool user_cursor; // if true, user is expected to manage cursor image in SAPP_EVENTTYPE_UPDATE_CURSOR
bool enable_clipboard; // enable clipboard access, default is false
int clipboard_size; // max size of clipboard content in bytes
bool enable_dragndrop; // enable file dropping (drag'n'drop), default is false
@ -1413,6 +1425,25 @@ typedef struct sapp_html5_fetch_request {
void* user_data; /* optional userdata pointer */
} sapp_html5_fetch_request;
/*
sapp_mouse_cursor
Predefined cursor image definitions, set with sapp_set_mouse_cursor(sapp_mouse_cursor cursor)
*/
typedef enum sapp_mouse_cursor {
SAPP_MOUSECURSOR_DEFAULT = 0, // equivalent with system default cursor
SAPP_MOUSECURSOR_ARROW,
SAPP_MOUSECURSOR_IBEAM,
SAPP_MOUSECURSOR_CROSSHAIR,
SAPP_MOUSECURSOR_POINTING_HAND,
SAPP_MOUSECURSOR_RESIZE_EW,
SAPP_MOUSECURSOR_RESIZE_NS,
SAPP_MOUSECURSOR_RESIZE_NWSE,
SAPP_MOUSECURSOR_RESIZE_NESW,
SAPP_MOUSECURSOR_RESIZE_ALL,
SAPP_MOUSECURSOR_NOT_ALLOWED,
_SAPP_MOUSECURSOR_NUM,
} sapp_mouse_cursor;
/* user-provided functions */
extern sapp_desc sokol_main(int argc, char* argv[]);
@ -1452,6 +1483,10 @@ SOKOL_APP_API_DECL bool sapp_mouse_shown(void);
SOKOL_APP_API_DECL void sapp_lock_mouse(bool lock);
/* return true if in mouse-pointer-lock mode (this may toggle a few frames later) */
SOKOL_APP_API_DECL bool sapp_mouse_locked(void);
/* set mouse cursor type */
SOKOL_APP_API_DECL void sapp_set_mouse_cursor(sapp_mouse_cursor cursor);
/* get current mouse cursor type */
SOKOL_APP_API_DECL sapp_mouse_cursor sapp_get_mouse_cursor(void);
/* return the userdata pointer optionally provided in sapp_desc */
SOKOL_APP_API_DECL void* sapp_userdata(void);
/* return a copy of the sapp_desc structure */
@ -1796,6 +1831,7 @@ inline void sapp_run(const sapp_desc& desc) { return sapp_run(&desc); }
#include <X11/Xatom.h>
#include <X11/extensions/XInput2.h>
#include <X11/Xcursor/Xcursor.h>
#include <X11/cursorfont.h> /* XC_* font cursors */
#include <X11/Xmd.h> /* CARD32 */
#include <dlfcn.h> /* dlopen, dlsym, dlclose */
#include <limits.h> /* LONG_MAX */
@ -2047,6 +2083,7 @@ typedef struct {
_sapp_macos_app_delegate* app_dlg;
_sapp_macos_window_delegate* win_dlg;
_sapp_macos_view* view;
NSCursor* cursors[_SAPP_MOUSECURSOR_NUM];
#if defined(SOKOL_METAL)
id<MTLDevice> mtl_device;
#endif
@ -2165,6 +2202,7 @@ typedef struct {
HDC dc;
HICON big_icon;
HICON small_icon;
HCURSOR cursors[_SAPP_MOUSECURSOR_NUM];
UINT orig_codepage;
LONG mouse_locked_x, mouse_locked_y;
bool is_win10_or_greater;
@ -2386,6 +2424,7 @@ typedef struct {
Colormap colormap;
Window window;
Cursor hidden_cursor;
Cursor cursors[_SAPP_MOUSECURSOR_NUM];
int window_state;
float dpi;
unsigned char error_code;
@ -2487,6 +2526,7 @@ typedef struct {
bool shown;
bool locked;
bool pos_valid;
sapp_mouse_cursor current_cursor;
} _sapp_mouse_t;
typedef struct {
@ -3094,6 +3134,28 @@ _SOKOL_PRIVATE void _sapp_macos_discard_state(void) {
_SAPP_OBJC_RELEASE(_sapp.macos.window);
}
// undocumented methods for creating cursors (see GLFW 3.4 and imgui_impl_osx.mm)
@interface NSCursor()
+ (id)_windowResizeNorthWestSouthEastCursor;
+ (id)_windowResizeNorthEastSouthWestCursor;
+ (id)_windowResizeNorthSouthCursor;
+ (id)_windowResizeEastWestCursor;
@end
_SOKOL_PRIVATE void _sapp_macos_init_cursors(void) {
_sapp.macos.cursors[SAPP_MOUSECURSOR_DEFAULT] = nil; // not a bug
_sapp.macos.cursors[SAPP_MOUSECURSOR_ARROW] = [NSCursor arrowCursor];
_sapp.macos.cursors[SAPP_MOUSECURSOR_IBEAM] = [NSCursor IBeamCursor];
_sapp.macos.cursors[SAPP_MOUSECURSOR_CROSSHAIR] = [NSCursor crosshairCursor];
_sapp.macos.cursors[SAPP_MOUSECURSOR_POINTING_HAND] = [NSCursor pointingHandCursor];
_sapp.macos.cursors[SAPP_MOUSECURSOR_RESIZE_EW] = [NSCursor respondsToSelector:@selector(_windowResizeEastWestCursor)] ? [NSCursor _windowResizeEastWestCursor] : [NSCursor resizeLeftRightCursor];
_sapp.macos.cursors[SAPP_MOUSECURSOR_RESIZE_NS] = [NSCursor respondsToSelector:@selector(_windowResizeNorthSouthCursor)] ? [NSCursor _windowResizeNorthSouthCursor] : [NSCursor resizeUpDownCursor];
_sapp.macos.cursors[SAPP_MOUSECURSOR_RESIZE_NWSE] = [NSCursor respondsToSelector:@selector(_windowResizeNorthWestSouthEastCursor)] ? [NSCursor _windowResizeNorthWestSouthEastCursor] : [NSCursor closedHandCursor];
_sapp.macos.cursors[SAPP_MOUSECURSOR_RESIZE_NESW] = [NSCursor respondsToSelector:@selector(_windowResizeNorthEastSouthWestCursor)] ? [NSCursor _windowResizeNorthEastSouthWestCursor] : [NSCursor closedHandCursor];
_sapp.macos.cursors[SAPP_MOUSECURSOR_RESIZE_ALL] = [NSCursor closedHandCursor];
_sapp.macos.cursors[SAPP_MOUSECURSOR_NOT_ALLOWED] = [NSCursor operationNotAllowedCursor];
}
_SOKOL_PRIVATE void _sapp_macos_run(const sapp_desc* desc) {
_sapp_init_state(desc);
_sapp_macos_init_keytable();
@ -3296,14 +3358,34 @@ _SOKOL_PRIVATE void _sapp_macos_lock_mouse(bool lock) {
*/
if (_sapp.mouse.locked) {
CGAssociateMouseAndMouseCursorPosition(NO);
CGDisplayHideCursor(kCGDirectMainDisplay);
[NSCursor hide];
}
else {
CGDisplayShowCursor(kCGDirectMainDisplay);
[NSCursor unhide];
CGAssociateMouseAndMouseCursorPosition(YES);
}
}
_SOKOL_PRIVATE void _sapp_macos_update_cursor(sapp_mouse_cursor cursor, bool shown) {
// show/hide cursor only if visibility status has changed (required because show/hide stacks)
if (shown != _sapp.mouse.shown) {
if (shown) {
[NSCursor unhide];
}
else {
[NSCursor hide];
}
}
// update cursor type
SOKOL_ASSERT((cursor >= 0) && (cursor < _SAPP_MOUSECURSOR_NUM));
if (_sapp.macos.cursors[cursor]) {
[_sapp.macos.cursors[cursor] set];
}
else {
[[NSCursor arrowCursor] set];
}
}
_SOKOL_PRIVATE void _sapp_macos_set_icon(const sapp_icon_desc* icon_desc, int num_images) {
NSDockTile* dock_tile = NSApp.dockTile;
const int wanted_width = (int) dock_tile.size.width;
@ -3351,6 +3433,7 @@ _SOKOL_PRIVATE void _sapp_macos_frame(void) {
@implementation _sapp_macos_app_delegate
- (void)applicationDidFinishLaunching:(NSNotification*)aNotification {
_SOKOL_UNUSED(aNotification);
_sapp_macos_init_cursors();
if (_sapp.fullscreen) {
NSRect screen_rect = NSScreen.mainScreen.frame;
_sapp.window_width = screen_rect.size.width;
@ -3911,12 +3994,6 @@ _SOKOL_PRIVATE void _sapp_macos_poll_input_events() {
_sapp_macos_mods(event));
}
}
- (void)cursorUpdate:(NSEvent*)event {
_SOKOL_UNUSED(event);
if (_sapp.desc.user_cursor) {
_sapp_macos_app_event(SAPP_EVENTTYPE_UPDATE_CURSOR);
}
}
@end
#endif /* MacOS */
@ -4599,6 +4676,36 @@ _SOKOL_PRIVATE void _sapp_emsc_update_mouse_lock_state(void) {
}
}
// set mouse cursor type
EM_JS(void, sapp_js_set_cursor, (int cursor_type, int shown), {
if (Module.sapp_emsc_target) {
var cursor;
if (shown === 0) {
cursor = "none";
}
else switch (cursor_type) {
case 0: cursor = "auto"; break; // SAPP_MOUSECURSOR_DEFAULT
case 1: cursor = "default"; break; // SAPP_MOUSECURSOR_ARROW
case 2: cursor = "text"; break; // SAPP_MOUSECURSOR_IBEAM
case 3: cursor = "crosshair"; break; // SAPP_MOUSECURSOR_CROSSHAIR
case 4: cursor = "pointer"; break; // SAPP_MOUSECURSOR_POINTING_HAND
case 5: cursor = "ew-resize"; break; // SAPP_MOUSECURSOR_RESIZE_EW
case 6: cursor = "ns-resize"; break; // SAPP_MOUSECURSOR_RESIZE_NS
case 7: cursor = "nwse-resize"; break; // SAPP_MOUSECURSOR_RESIZE_NWSE
case 8: cursor = "nesw-resize"; break; // SAPP_MOUSECURSOR_RESIZE_NESW
case 9: cursor = "all-scroll"; break; // SAPP_MOUSECURSOR_RESIZE_ALL
case 10: cursor = "not-allowed"; break; // SAPP_MOUSECURSOR_NOT_ALLOWED
default: cursor = "auto"; break;
}
Module.sapp_emsc_target.style.cursor = cursor;
}
});
_SOKOL_PRIVATE void _sapp_emsc_update_cursor(sapp_mouse_cursor cursor, bool shown) {
SOKOL_ASSERT((cursor >= 0) && (cursor < _SAPP_MOUSECURSOR_NUM));
sapp_js_set_cursor((int)cursor, shown ? 1 : 0);
}
/* JS helper functions to update browser tab favicon */
EM_JS(void, sapp_js_clear_favicon, (void), {
var link = document.getElementById('sokol-app-favicon');
@ -6211,9 +6318,73 @@ _SOKOL_PRIVATE void _sapp_win32_toggle_fullscreen(void) {
SetWindowPos(_sapp.win32.hwnd, HWND_TOP, mr.left + rect.left, mr.top + rect.top, win_width, win_height, SWP_SHOWWINDOW | SWP_FRAMECHANGED);
}
_SOKOL_PRIVATE void _sapp_win32_show_mouse(bool visible) {
/* NOTE: this function is only called when the mouse visibility actually changes */
ShowCursor((BOOL)visible);
_SOKOL_PRIVATE void _sapp_win32_init_cursor(sapp_mouse_cursor cursor) {
SOKOL_ASSERT((cursor >= 0) && (cursor < _SAPP_MOUSECURSOR_NUM));
// NOTE: the OCR_* constants are only defined if OEMRESOURCE is defined
// before windows.h is included, but we can't guarantee that because
// the sokol_app.h implementation may be included with other implementations
// in the same compilation unit
int id = 0;
switch (cursor) {
case SAPP_MOUSECURSOR_ARROW: id = 32512; break; // OCR_NORMAL
case SAPP_MOUSECURSOR_IBEAM: id = 32513; break; // OCR_IBEAM
case SAPP_MOUSECURSOR_CROSSHAIR: id = 32515; break; // OCR_CROSS
case SAPP_MOUSECURSOR_POINTING_HAND: id = 32649; break; // OCR_HAND
case SAPP_MOUSECURSOR_RESIZE_EW: id = 32644; break; // OCR_SIZEWE
case SAPP_MOUSECURSOR_RESIZE_NS: id = 32645; break; // OCR_SIZENS
case SAPP_MOUSECURSOR_RESIZE_NWSE: id = 32642; break; // OCR_SIZENWSE
case SAPP_MOUSECURSOR_RESIZE_NESW: id = 32643; break; // OCR_SIZENESW
case SAPP_MOUSECURSOR_RESIZE_ALL: id = 32646; break; // OCR_SIZEALL
case SAPP_MOUSECURSOR_NOT_ALLOWED: id = 32648; break; // OCR_NO
default: break;
}
if (id != 0) {
_sapp.win32.cursors[cursor] = (HCURSOR)LoadImageW(NULL, MAKEINTRESOURCEW(id), IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE|LR_SHARED);
}
// fallback: default cursor
if (0 == _sapp.win32.cursors[cursor]) {
// 32512 => IDC_ARROW
_sapp.win32.cursors[cursor] = LoadCursorW(NULL, MAKEINTRESOURCEW(32512));
}
SOKOL_ASSERT(0 != _sapp.win32.cursors[cursor]);
}
_SOKOL_PRIVATE void _sapp_win32_init_cursors(void) {
for (int i = 0; i < _SAPP_MOUSECURSOR_NUM; i++) {
_sapp_win32_init_cursor((sapp_mouse_cursor)i);
}
}
_SOKOL_PRIVATE bool _sapp_win32_cursor_in_content_area(void) {
POINT pos;
if (!GetCursorPos(&pos)) {
return false;
}
if (WindowFromPoint(pos) != _sapp.win32.hwnd) {
return false;
}
RECT area;
GetClientRect(_sapp.win32.hwnd, &area);
ClientToScreen(_sapp.win32.hwnd, (POINT*)&area.left);
ClientToScreen(_sapp.win32.hwnd, (POINT*)&area.right);
return PtInRect(&area, pos);
}
_SOKOL_PRIVATE void _sapp_win32_update_cursor(sapp_mouse_cursor cursor, bool shown, bool skip_area_test) {
// NOTE: when called from WM_SETCURSOR, the area test would be redundant
if (!skip_area_test) {
if (!_sapp_win32_cursor_in_content_area()) {
return;
}
}
if (!shown) {
SetCursor(NULL);
}
else {
SOKOL_ASSERT((cursor >= 0) && (cursor < _SAPP_MOUSECURSOR_NUM));
SOKOL_ASSERT(0 != _sapp.win32.cursors[cursor]);
SetCursor(_sapp.win32.cursors[cursor]);
}
}
_SOKOL_PRIVATE void _sapp_win32_capture_mouse(uint8_t btn_mask) {
@ -6517,11 +6688,9 @@ _SOKOL_PRIVATE LRESULT CALLBACK _sapp_win32_wndproc(HWND hWnd, UINT uMsg, WPARAM
_sapp_win32_uwp_app_event(SAPP_EVENTTYPE_UNFOCUSED);
break;
case WM_SETCURSOR:
if (_sapp.desc.user_cursor) {
if (LOWORD(lParam) == HTCLIENT) {
_sapp_win32_uwp_app_event(SAPP_EVENTTYPE_UPDATE_CURSOR);
return 1;
}
if (LOWORD(lParam) == HTCLIENT) {
_sapp_win32_update_cursor(_sapp.mouse.current_cursor, _sapp.mouse.shown, true);
return TRUE;
}
break;
case WM_LBUTTONDOWN:
@ -6997,6 +7166,7 @@ _SOKOL_PRIVATE void _sapp_win32_run(const sapp_desc* desc) {
_sapp_win32_uwp_init_keytable();
_sapp_win32_uwp_utf8_to_wide(_sapp.window_title, _sapp.window_title_wide, sizeof(_sapp.window_title_wide));
_sapp_win32_init_dpi();
_sapp_win32_init_cursors();
_sapp_win32_create_window();
sapp_set_icon(&desc->icon);
#if defined(SOKOL_D3D11)
@ -7136,13 +7306,26 @@ _SOKOL_PRIVATE void _sapp_uwp_configure_dpi(float monitor_dpi) {
_sapp.dpi_scale = _sapp.uwp.dpi.content_scale;
}
_SOKOL_PRIVATE void _sapp_uwp_show_mouse(bool visible) {
_SOKOL_PRIVATE void _sapp_uwp_update_cursor(sapp_mouse_cursor cursor, bool shown) {
using namespace winrt::Windows::UI::Core;
/* NOTE: this function is only called when the mouse visibility actually changes */
CoreWindow::GetForCurrentThread().PointerCursor(visible ?
CoreCursor(CoreCursorType::Arrow, 0) :
CoreCursor(nullptr));
CoreCursor uwp_cursor(nullptr);
if (shown) {
switch (cursor) {
case SAPP_MOUSECURSOR_ARROW: uwp_cursor = CoreCursor(CoreCursorType::Arrow, 0); break;
case SAPP_MOUSECURSOR_IBEAM: uwp_cursor = CoreCursor(CoreCursorType::IBeam, 0); break;
case SAPP_MOUSECURSOR_CROSSHAIR: uwp_cursor = CoreCursor(CoreCursorType::Cross, 0); break;
case SAPP_MOUSECURSOR_POINTING_HAND: uwp_cursor = CoreCursor(CoreCursorType::Hand, 0); break;
case SAPP_MOUSECURSOR_RESIZE_EW: uwp_cursor = CoreCursor(CoreCursorType::SizeWestEast, 0); break;
case SAPP_MOUSECURSOR_RESIZE_NS: uwp_cursor = CoreCursor(CoreCursorType::SizeNorthSouth, 0); break;
case SAPP_MOUSECURSOR_RESIZE_NWSE: uwp_cursor = CoreCursor(CoreCursorType::SizeNorthwestSoutheast, 0); break;
case SAPP_MOUSECURSOR_RESIZE_NESW: uwp_cursor = CoreCursor(CoreCursorType::SizeNortheastSouthwest, 0); break;
case SAPP_MOUSECURSOR_RESIZE_ALL: uwp_cursor = CoreCursor(CoreCursorType::SizeAll, 0); break;
case SAPP_MOUSECURSOR_NOT_ALLOWED: uwp_cursor = CoreCursor(CoreCursorType::UniversalNo, 0); break;
default: uwp_cursor = CoreCursor(CoreCursorType::Arrow, 0); break;
}
}
CoreWindow::GetForCurrentThread().PointerCursor(uwp_cursor);
}
_SOKOL_PRIVATE uint32_t _sapp_uwp_mods(winrt::Windows::UI::Core::CoreWindow const& sender_window) {
@ -10022,19 +10205,72 @@ _SOKOL_PRIVATE void _sapp_x11_create_hidden_cursor(void) {
XcursorImageDestroy(img);
}
_SOKOL_PRIVATE void _sapp_x11_create_standard_cursor(sapp_mouse_cursor cursor, const char* name, const char* theme, int size, uint32_t fallback_native) {
SOKOL_ASSERT((cursor >= 0) && (cursor < _SAPP_MOUSECURSOR_NUM));
SOKOL_ASSERT(_sapp.x11.display);
if (theme) {
XcursorImage* img = XcursorLibraryLoadImage(name, theme, size);
if (img) {
_sapp.x11.cursors[cursor] = XcursorImageLoadCursor(_sapp.x11.display, img);
XcursorImageDestroy(img);
}
}
if (0 == _sapp.x11.cursors[cursor]) {
_sapp.x11.cursors[cursor] = XCreateFontCursor(_sapp.x11.display, fallback_native);
}
}
_SOKOL_PRIVATE void _sapp_x11_create_cursors(void) {
SOKOL_ASSERT(_sapp.x11.display);
const char* cursor_theme = XcursorGetTheme(_sapp.x11.display);
const int size = XcursorGetDefaultSize(_sapp.x11.display);
_sapp_x11_create_standard_cursor(SAPP_MOUSECURSOR_ARROW, "default", cursor_theme, size, XC_left_ptr);
_sapp_x11_create_standard_cursor(SAPP_MOUSECURSOR_IBEAM, "text", cursor_theme, size, XC_xterm);
_sapp_x11_create_standard_cursor(SAPP_MOUSECURSOR_CROSSHAIR, "crosshair", cursor_theme, size, XC_crosshair);
_sapp_x11_create_standard_cursor(SAPP_MOUSECURSOR_POINTING_HAND, "pointer", cursor_theme, size, XC_hand2);
_sapp_x11_create_standard_cursor(SAPP_MOUSECURSOR_RESIZE_EW, "ew-resize", cursor_theme, size, XC_sb_h_double_arrow);
_sapp_x11_create_standard_cursor(SAPP_MOUSECURSOR_RESIZE_NS, "ns-resize", cursor_theme, size, XC_sb_v_double_arrow);
_sapp_x11_create_standard_cursor(SAPP_MOUSECURSOR_RESIZE_NWSE, "nwse-resize", cursor_theme, size, 0);
_sapp_x11_create_standard_cursor(SAPP_MOUSECURSOR_RESIZE_NESW, "nesw-resize", cursor_theme, size, 0);
_sapp_x11_create_standard_cursor(SAPP_MOUSECURSOR_RESIZE_ALL, "all-scroll", cursor_theme, size, XC_fleur);
_sapp_x11_create_standard_cursor(SAPP_MOUSECURSOR_NOT_ALLOWED, "no-allowed", cursor_theme, size, 0);
_sapp_x11_create_hidden_cursor();
}
_SOKOL_PRIVATE void _sapp_x11_destroy_cursors(void) {
SOKOL_ASSERT(_sapp.x11.display);
if (_sapp.x11.hidden_cursor) {
XFreeCursor(_sapp.x11.display, _sapp.x11.hidden_cursor);
_sapp.x11.hidden_cursor = 0;
}
for (int i = 0; i < _SAPP_MOUSECURSOR_NUM; i++) {
if (_sapp.x11.cursors[i]) {
XFreeCursor(_sapp.x11.display, _sapp.x11.cursors[i]);
_sapp.x11.cursors[i] = 0;
}
}
}
_SOKOL_PRIVATE void _sapp_x11_toggle_fullscreen(void) {
_sapp.fullscreen = !_sapp.fullscreen;
_sapp_x11_set_fullscreen(_sapp.fullscreen);
_sapp_x11_query_window_size();
}
_SOKOL_PRIVATE void _sapp_x11_show_mouse(bool show) {
if (show) {
XUndefineCursor(_sapp.x11.display, _sapp.x11.window);
_SOKOL_PRIVATE void _sapp_x11_update_cursor(sapp_mouse_cursor cursor, bool shown) {
SOKOL_ASSERT((cursor >= 0) && (cursor < _SAPP_MOUSECURSOR_NUM));
if (shown) {
if (_sapp.x11.cursors[cursor]) {
XDefineCursor(_sapp.x11.display, _sapp.x11.window, _sapp.x11.cursors[cursor]);
}
else {
XUndefineCursor(_sapp.x11.display, _sapp.x11.window);
}
}
else {
XDefineCursor(_sapp.x11.display, _sapp.x11.window, _sapp.x11.hidden_cursor);
}
XFlush(_sapp.x11.display);
}
_SOKOL_PRIVATE void _sapp_x11_lock_mouse(bool lock) {
@ -10927,7 +11163,7 @@ _SOKOL_PRIVATE void _sapp_linux_run(const sapp_desc* desc) {
_sapp_x11_query_system_dpi();
_sapp.dpi_scale = _sapp.x11.dpi / 96.0f;
_sapp_x11_init_extensions();
_sapp_x11_create_hidden_cursor();
_sapp_x11_create_cursors();
_sapp_glx_init();
Visual* visual = 0;
int depth = 0;
@ -10968,6 +11204,7 @@ _SOKOL_PRIVATE void _sapp_linux_run(const sapp_desc* desc) {
_sapp_call_cleanup();
_sapp_glx_destroy_context();
_sapp_x11_destroy_window();
_sapp_x11_destroy_cursors();
XCloseDisplay(_sapp.x11.display);
_sapp_discard_state();
}
@ -11128,13 +11365,15 @@ SOKOL_API_IMPL void sapp_toggle_fullscreen(void) {
SOKOL_API_IMPL void sapp_show_mouse(bool show) {
if (_sapp.mouse.shown != show) {
#if defined(_SAPP_MACOS)
_sapp_macos_show_mouse(show);
_sapp_macos_update_cursor(_sapp.mouse.current_cursor, show);
#elif defined(_SAPP_WIN32)
_sapp_win32_show_mouse(show);
_sapp_win32_update_cursor(_sapp.mouse.current_cursor, show, false);
#elif defined(_SAPP_LINUX)
_sapp_x11_show_mouse(show);
_sapp_x11_update_cursor(_sapp.mouse.current_cursor, show);
#elif defined(_SAPP_UWP)
_sapp_uwp_show_mouse(show);
_sapp_uwp_update_cursor(_sapp.mouse.current_cursor, show);
#elif defined(_SAPP_EMSCRIPTEN)
_sapp_emsc_update_cursor(_sapp.mouse.current_cursor, show);
#endif
_sapp.mouse.shown = show;
}
@ -11162,6 +11401,28 @@ SOKOL_API_IMPL bool sapp_mouse_locked(void) {
return _sapp.mouse.locked;
}
SOKOL_API_IMPL void sapp_set_mouse_cursor(sapp_mouse_cursor cursor) {
SOKOL_ASSERT((cursor >= 0) && (cursor < _SAPP_MOUSECURSOR_NUM));
if (_sapp.mouse.current_cursor != cursor) {
#if defined(_SAPP_MACOS)
_sapp_macos_update_cursor(cursor, _sapp.mouse.shown);
#elif defined(_SAPP_WIN32)
_sapp_win32_update_cursor(cursor, _sapp.mouse.shown, false);
#elif defined(_SAPP_LINUX)
_sapp_x11_update_cursor(cursor, _sapp.mouse.shown);
#elif defined(_SAPP_UWP)
_sapp_uwp_update_cursor(cursor, _sapp.mouse.shown);
#elif defined(_SAPP_EMSCRIPTEN)
_sapp_emsc_update_cursor(cursor, _sapp.mouse.shown);
#endif
_sapp.mouse.current_cursor = cursor;
}
}
SOKOL_API_IMPL sapp_mouse_cursor sapp_get_mouse_cursor(void) {
return _sapp.mouse.current_cursor;
}
SOKOL_API_IMPL void sapp_request_quit(void) {
_sapp.quit_requested = true;
}

View File

@ -36,6 +36,20 @@ pub enum MouseButton {
middle = 2
}
pub enum MouseCursor {
default = C.SAPP_MOUSECURSOR_DEFAULT
arrow = C.SAPP_MOUSECURSOR_ARROW
ibeam = C.SAPP_MOUSECURSOR_IBEAM
crosshair = C.SAPP_MOUSECURSOR_CROSSHAIR
pointing_hand = C.SAPP_MOUSECURSOR_POINTING_HAND
resize_ew = C.SAPP_MOUSECURSOR_RESIZE_EW
resize_ns = C.SAPP_MOUSECURSOR_RESIZE_NS
resize_nwse = C.SAPP_MOUSECURSOR_RESIZE_NWSE
resize_nesw = C.SAPP_MOUSECURSOR_RESIZE_NESW
resize_all = C.SAPP_MOUSECURSOR_RESIZE_ALL
not_allowed = C.SAPP_MOUSECURSOR_NOT_ALLOWED
}
pub enum Modifier {
shift = 1 //(1<<0)
ctrl = 2 //(1<<1)

View File

@ -97,6 +97,12 @@ pub fn show_mouse(visible bool) {
C.sapp_show_mouse(visible)
}
// set mouse cursor
[inline]
pub fn set_mouse_cursor(cursor MouseCursor) {
C.sapp_set_mouse_cursor(cursor)
}
// show or hide the mouse cursor
[inline]
pub fn mouse_shown() bool {

View File

@ -44,6 +44,9 @@ fn C.sapp_show_mouse(visible bool)
// return true if the mouse cursor is shown
fn C.sapp_mouse_shown() bool
// set mouse cursor
fn C.sapp_set_mouse_cursor(cursor MouseCursor)
// lock or unlock the mouse cursor
fn C.sapp_lock_mouse(locked bool)

View File

@ -54,7 +54,6 @@ pub:
fullscreen bool // whether the window should be created in fullscreen mode
alpha bool // whether the framebuffer should have an alpha channel (ignored on some platforms)
window_title &char // the window title as UTF-8 encoded string
user_cursor bool // if true, user is expected to manage cursor image in SAPP_EVENTTYPE_UPDATE_CURSOR
enable_clipboard bool // enable clipboard access, default is false
clipboard_size int // max size of clipboard content in bytes
enable_dragndrop bool // enable file dropping (drag'n'drop), default is false