From 9a8a6bf9b8414470952b008c84515b9516ddc7f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Hoguin?= Date: Thu, 21 Dec 2017 23:32:18 +0100 Subject: Add sdl_cursor along with all its related functions --- c_src/esdl2.h | 15 +++ c_src/esdl2_cursors.c | 96 ++++++++++++++++++ c_src/esdl2_renderers.c | 4 +- c_src/esdl2_windows.c | 4 +- c_src/sdl_cursor.c | 262 ++++++++++++++++++++++++++++++++++++++++++++++++ c_src/sdl_mouse.c | 16 --- c_src/sdl_renderer.c | 2 +- 7 files changed, 376 insertions(+), 23 deletions(-) create mode 100644 c_src/esdl2_cursors.c create mode 100644 c_src/sdl_cursor.c (limited to 'c_src') diff --git a/c_src/esdl2.h b/c_src/esdl2.h index ca9a424..c265110 100644 --- a/c_src/esdl2.h +++ b/c_src/esdl2.h @@ -139,6 +139,7 @@ #define NIF_RES_TYPE(r) SDL_ ## r #define NIF_RESOURCES(R) \ + R(Cursor) \ R(GLContext) \ R(Renderer) \ R(Surface) \ @@ -176,6 +177,14 @@ F(has_sse3, 0) \ F(has_sse41, 0) \ F(has_sse42, 0) \ + /* sdl_cursor */ \ + F(create_cursor, 6) \ + F(create_color_cursor, 3) \ + F(create_system_cursor, 1) \ + F(get_cursor, 0) \ + F(get_default_cursor, 0) \ + F(set_cursor, 1) \ + F(show_cursor, 1) \ /* sdl_events */ \ F(poll_event, 0) \ /* sdl_filesystem */ \ @@ -302,6 +311,12 @@ ERL_NIF_TERM esdl2_renderers_find(ErlNifEnv*, SDL_Renderer*); void esdl2_renderers_remove(SDL_Renderer*); void esdl2_renderers_free(void); +void esdl2_cursors_init(void); +void esdl2_cursors_insert(SDL_Cursor*, obj_Cursor*); +ERL_NIF_TERM esdl2_cursors_find(ErlNifEnv*, SDL_Cursor*); +void esdl2_cursors_remove(SDL_Cursor*); +void esdl2_cursors_free(void); + ErlNifPid* get_callback_process(void); #define sdl_error_tuple(env) \ diff --git a/c_src/esdl2_cursors.c b/c_src/esdl2_cursors.c new file mode 100644 index 0000000..8ce576c --- /dev/null +++ b/c_src/esdl2_cursors.c @@ -0,0 +1,96 @@ +// Copyright (c) 2017, Loïc Hoguin +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +#include "esdl2.h" +#include + +struct esdl2_cursor { + LIST_ENTRY(esdl2_cursor) entries; + + SDL_Cursor* cursor; + obj_Cursor* res; +}; + +static LIST_HEAD(esdl2_cursor_list, esdl2_cursor) cursors; + +void esdl2_cursors_init() +{ + LIST_INIT(&cursors); +} + +void esdl2_cursors_insert(SDL_Cursor* cursor, obj_Cursor* res) +{ + struct esdl2_cursor* item; + + item = malloc(sizeof(struct esdl2_cursor)); + item->cursor = cursor; + item->res = res; + + LIST_INSERT_HEAD(&cursors, item, entries); +} + +static struct esdl2_cursor* esdl2_cursors_find_entry(SDL_Cursor* cursor) +{ + struct esdl2_cursor* head; + + head = LIST_FIRST(&cursors); + while (head != NULL) { + if (head->cursor == cursor) + return head; + + head = LIST_NEXT(head, entries); + } + + return NULL; +} + +ERL_NIF_TERM esdl2_cursors_find(ErlNifEnv* env, SDL_Cursor* cursor) +{ + struct esdl2_cursor* entry; + ERL_NIF_TERM term; + + entry = esdl2_cursors_find_entry(cursor); + + if (entry == NULL) + return atom_undefined; + + term = enif_make_resource(env, entry->res); + + return term; +} + +void esdl2_cursors_remove(SDL_Cursor* cursor) +{ + struct esdl2_cursor* entry; + + entry = esdl2_cursors_find_entry(cursor); + + if (entry == NULL) + return; + + LIST_REMOVE(entry, entries); +} + +void esdl2_cursors_free() +{ + struct esdl2_cursor *head, *next; + + head = LIST_FIRST(&cursors); + while (head != NULL) { + next = LIST_NEXT(head, entries); + free(head); + head = next; + } +} + diff --git a/c_src/esdl2_renderers.c b/c_src/esdl2_renderers.c index 281079c..70ef30d 100644 --- a/c_src/esdl2_renderers.c +++ b/c_src/esdl2_renderers.c @@ -44,9 +44,7 @@ void esdl2_renderers_insert(SDL_Renderer* renderer, obj_Renderer* res, obj_Windo LIST_INSERT_HEAD(&renderers, item, entries); } -struct esdl2_renderer* esdl2_renderers_find_entry(SDL_Renderer* renderer); - -struct esdl2_renderer* esdl2_renderers_find_entry(SDL_Renderer* renderer) +static struct esdl2_renderer* esdl2_renderers_find_entry(SDL_Renderer* renderer) { struct esdl2_renderer* head; diff --git a/c_src/esdl2_windows.c b/c_src/esdl2_windows.c index 8855987..bff9948 100644 --- a/c_src/esdl2_windows.c +++ b/c_src/esdl2_windows.c @@ -40,9 +40,7 @@ void esdl2_windows_insert(SDL_Window* window, obj_Window* res) LIST_INSERT_HEAD(&windows, item, entries); } -struct esdl2_window* esdl2_windows_find_entry(SDL_Window* window); - -struct esdl2_window* esdl2_windows_find_entry(SDL_Window* window) +static struct esdl2_window* esdl2_windows_find_entry(SDL_Window* window) { struct esdl2_window* head; diff --git a/c_src/sdl_cursor.c b/c_src/sdl_cursor.c new file mode 100644 index 0000000..59ad923 --- /dev/null +++ b/c_src/sdl_cursor.c @@ -0,0 +1,262 @@ +// Copyright (c) 2017, Loïc Hoguin +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +#include "esdl2.h" + +#define SYSTEM_CURSOR_ENUM(E) \ + E(arrow, SDL_SYSTEM_CURSOR_ARROW) \ + E(ibeam, SDL_SYSTEM_CURSOR_IBEAM) \ + E(wait, SDL_SYSTEM_CURSOR_WAIT) \ + E(crosshair, SDL_SYSTEM_CURSOR_CROSSHAIR) \ + E(wait_arrow, SDL_SYSTEM_CURSOR_WAITARROW) \ + E(size_nwse, SDL_SYSTEM_CURSOR_SIZENWSE) \ + E(size_nesw, SDL_SYSTEM_CURSOR_SIZENESW) \ + E(size_we, SDL_SYSTEM_CURSOR_SIZEWE) \ + E(size_ns, SDL_SYSTEM_CURSOR_SIZENS) \ + E(size_all, SDL_SYSTEM_CURSOR_SIZEALL) \ + E(no, SDL_SYSTEM_CURSOR_NO) \ + E(hand, SDL_SYSTEM_CURSOR_HAND) + +static NIF_ATOM_TO_ENUM_FUNCTION(atom_to_system_cursor, int, SYSTEM_CURSOR_ENUM) + +void dtor_Cursor(ErlNifEnv* env, void* obj) +{ + SDL_Cursor* cursor = NIF_RES_GET(Cursor, obj); + + SDL_FreeCursor(cursor); + esdl2_cursors_remove(cursor); +} + +// create_cursor + +NIF_CALL_HANDLER(thread_create_cursor) +{ + SDL_Cursor* cursor; + obj_Cursor* res; + ERL_NIF_TERM term; + ErlNifBinary data, mask; + + enif_inspect_binary(args[0], (long)args[1], &data); + enif_inspect_binary(args[0], (long)args[2], &mask); + + cursor = SDL_CreateCursor(data.data, mask.data, + (long)args[3], (long)args[4], (long)args[5], (long)args[6]); + + enif_free_env(args[0]); + + if (!cursor) + return sdl_error_tuple(env); + + NIF_RES_TO_PTR_AND_TERM(Cursor, cursor, res, term); + + esdl2_cursors_insert(cursor, res); + + return enif_make_tuple2(env, + atom_ok, + term + ); +} + +NIF_FUNCTION(create_cursor) +{ + ErlNifEnv* bin_env; + ERL_NIF_TERM data, mask; + int w, h, hot_x, hot_y; + + BADARG_IF(!enif_is_binary(env, argv[0])); + BADARG_IF(!enif_is_binary(env, argv[1])); + BADARG_IF(!enif_get_int(env, argv[2], &w)); + BADARG_IF(!enif_get_int(env, argv[3], &h)); + BADARG_IF(!enif_get_int(env, argv[4], &hot_x)); + BADARG_IF(!enif_get_int(env, argv[5], &hot_y)); + + // We copy the binaries to avoid copying their content. + bin_env = enif_alloc_env(); + data = enif_make_copy(bin_env, argv[0]); + mask = enif_make_copy(bin_env, argv[1]); + + return nif_thread_call(env, thread_create_cursor, 7, + bin_env, data, mask, w, h, hot_x, hot_y); +} + +// create_color_cursor + +NIF_CALL_HANDLER(thread_create_color_cursor) +{ + SDL_Cursor* cursor; + obj_Cursor* res; + ERL_NIF_TERM term; + + cursor = SDL_CreateColorCursor(args[0], (long)args[1], (long)args[2]); + + if (!cursor) + return sdl_error_tuple(env); + + NIF_RES_TO_PTR_AND_TERM(Cursor, cursor, res, term); + + esdl2_cursors_insert(cursor, res); + + return enif_make_tuple2(env, + atom_ok, + term + ); +} + +NIF_FUNCTION(create_color_cursor) +{ + void* surface_res; + int hot_x, hot_y; + + BADARG_IF(!enif_get_resource(env, argv[0], res_Surface, &surface_res)); + BADARG_IF(!enif_get_int(env, argv[1], &hot_x)); + BADARG_IF(!enif_get_int(env, argv[2], &hot_y)); + + return nif_thread_call(env, thread_create_color_cursor, 3, + NIF_RES_GET(Surface, surface_res), hot_x, hot_y); +} + +// create_system_cursor + +NIF_CALL_HANDLER(thread_create_system_cursor) +{ + SDL_Cursor* cursor; + obj_Cursor* res; + ERL_NIF_TERM term; + + cursor = SDL_CreateSystemCursor((long)args[0]); + + if (!cursor) + return sdl_error_tuple(env); + + NIF_RES_TO_PTR_AND_TERM(Cursor, cursor, res, term); + + esdl2_cursors_insert(cursor, res); + + return enif_make_tuple2(env, + atom_ok, + term + ); +} + +NIF_FUNCTION(create_system_cursor) +{ + int id; + + BADARG_IF(!atom_to_system_cursor(env, argv[0], &id)); + + return nif_thread_call(env, thread_create_system_cursor, 1, id); +} + +// get_cursor + +NIF_CALL_HANDLER(thread_get_cursor) +{ + SDL_Cursor* cursor; + obj_Cursor* res; + ERL_NIF_TERM term; + + cursor = SDL_GetCursor(); + + // There is no mouse. + if (!cursor) + return atom_undefined; + + term = esdl2_cursors_find(env, cursor); + + if (!enif_is_identical(term, atom_undefined)) + return term; + + // We don't know this cursor. It's probably a system cursor. + // We should insert it in the list to have the same reference + // for it while it's active. + + NIF_RES_TO_PTR_AND_TERM(Cursor, cursor, res, term); + + esdl2_cursors_insert(cursor, res); + + return term; +} + +NIF_FUNCTION(get_cursor) +{ + return nif_thread_call(env, thread_get_cursor, 0); +} + +// get_default_cursor + +NIF_CALL_HANDLER(thread_get_default_cursor) +{ + SDL_Cursor* cursor; + obj_Cursor* res; + ERL_NIF_TERM term; + + cursor = SDL_GetDefaultCursor(); + + // There is no mouse. + if (!cursor) + return atom_undefined; + + term = esdl2_cursors_find(env, cursor); + + if (!enif_is_identical(term, atom_undefined)) + return term; + + // We don't know this cursor. It's probably a system cursor. + // We should insert it in the list to have the same reference + // for it while it's active. + + NIF_RES_TO_PTR_AND_TERM(Cursor, cursor, res, term); + + esdl2_cursors_insert(cursor, res); + + return term; +} + +NIF_FUNCTION(get_default_cursor) +{ + return nif_thread_call(env, thread_get_default_cursor, 0); +} + +// set_cursor + +NIF_CAST_HANDLER(thread_set_cursor) +{ + SDL_SetCursor(args[0]); +} + +NIF_FUNCTION(set_cursor) +{ + void* cursor_res; + + BADARG_IF(!enif_get_resource(env, argv[0], res_Cursor, &cursor_res)); + + return nif_thread_cast(env, thread_set_cursor, 1, + NIF_RES_GET(Cursor, cursor_res)); +} + +// show_cursor + +NIF_CALL_HANDLER(thread_show_cursor) +{ + return enif_make_int(env, SDL_ShowCursor((long)args[0])); +} + +NIF_FUNCTION(show_cursor) +{ + int toggle; + + BADARG_IF(!enif_get_int(env, argv[0], &toggle)); + + return nif_thread_call(env, thread_show_cursor, 1, toggle); +} diff --git a/c_src/sdl_mouse.c b/c_src/sdl_mouse.c index b74d088..8b36131 100644 --- a/c_src/sdl_mouse.c +++ b/c_src/sdl_mouse.c @@ -14,22 +14,6 @@ #include "esdl2.h" -#define SYSTEM_CURSOR_ENUM(E) \ - E(arrow, SDL_SYSTEM_CURSOR_ARROW) \ - E(ibeam, SDL_SYSTEM_CURSOR_IBEAM) \ - E(wait, SDL_SYSTEM_CURSOR_WAIT) \ - E(crosshair, SDL_SYSTEM_CURSOR_CROSSHAIR) \ - E(wait_arrow, SDL_SYSTEM_CURSOR_WAITARROW) \ - E(size_nwse, SDL_SYSTEM_CURSOR_SIZENWSE) \ - E(size_nesw, SDL_SYSTEM_CURSOR_SIZENESW) \ - E(size_we, SDL_SYSTEM_CURSOR_SIZEWE) \ - E(size_ns, SDL_SYSTEM_CURSOR_SIZENS) \ - E(size_all, SDL_SYSTEM_CURSOR_SIZEALL) \ - E(no, SDL_SYSTEM_CURSOR_NO) \ - E(hand, SDL_SYSTEM_CURSOR_HAND) - -static NIF_ATOM_TO_ENUM_FUNCTION(atom_to_system_cursor, int, SYSTEM_CURSOR_ENUM) - #define MOUSEWHEEL_DIRECTION_ENUM(E) \ E(normal, SDL_MOUSEWHEEL_NORMAL) \ E(flipped, SDL_MOUSEWHEEL_FLIPPED) diff --git a/c_src/sdl_renderer.c b/c_src/sdl_renderer.c index 81e60c4..23b41ca 100644 --- a/c_src/sdl_renderer.c +++ b/c_src/sdl_renderer.c @@ -880,7 +880,7 @@ NIF_FUNCTION(render_set_viewport) NIF_RES_GET(Renderer, renderer_res), x, y, w, h); } -// get_window_grab +// render_target_supported NIF_CALL_HANDLER(thread_render_target_supported) { -- cgit v1.2.3