From b3d07db07621212143040a5693a4b01607b4289e Mon Sep 17 00:00:00 2001 From: Hosang Kim Date: Fri, 9 Dec 2022 16:37:47 +0900 Subject: [PATCH] ecore_wl2: support default cursor configuration @TIZEN_ONLY Change-Id: I7b882596917f049f88e384f3ccabd9c8367c0fe0 --- meson.build | 4 +- src/lib/ecore_wl2/Ecore_Wl2.h | 4 + src/lib/ecore_wl2/ecore_wl2_cursor.c | 340 ++++++++++++++++++++++++++++++++++ src/lib/ecore_wl2/ecore_wl2_input.c | 18 +- src/lib/ecore_wl2/ecore_wl2_private.h | 8 + src/lib/ecore_wl2/meson.build | 7 +- 6 files changed, 375 insertions(+), 6 deletions(-) create mode 100644 src/lib/ecore_wl2/ecore_wl2_cursor.c diff --git a/meson.build b/meson.build index 193d9e4..857c554 100644 --- a/meson.build +++ b/meson.build @@ -325,7 +325,6 @@ subprojects = [ ['ecore_input' ,[] , false, true, false, false, false, false, true, ['eina', 'eo'], []], ['ecore_x' ,['x11'] , false, true, false, false, false, false, true, ['eina', 'efl'], []], ['ecore_fb' ,['fb'] , false, true, false, false, false, false, true, ['eina'], []], - ['ecore_wl2' ,['wl'] , true, true, false, false, true, false, true, ['eina'], ['libdrm']], ['ecore_sdl' ,['sdl'] , false, true, false, false, false, false, true, ['eina'], []], ['ecore_win32' ,[] , false, true, false, false, false, false, true, ['eina'], []], ['ecore_ipc' ,[] , false, true, false, false, false, false, true, ['eina'], []], @@ -336,11 +335,12 @@ subprojects = [ ['ecore_cocoa' ,['cocoa'] , false, true, false, false, false, false, true, ['eina'], []], ['evas' ,[] , true, true, false, false, true, true, true, ['eina', 'efl', 'eo'], ['vg_common', 'libunibreak']], ['efreet' ,[] , false, true, false, false, true, false, true, ['eina', 'efl', 'eo'], []], + ['eio' ,[] , false, true, false, false, true, true, true, ['eina', 'eet'], []], + ['ecore_wl2' ,['wl'] , true, true, false, false, true, false, true, ['eina'], ['libdrm']], ['ecore_input_evas' ,[] , false, true, false, false, false, false, true, ['eina', 'evas'], []], ['ecore_evas' ,[] , true, true, true, false, false, false, true, ['evas', 'ector'], []], ['ecore_imf' ,[] , true, true, false, false, false, false, true, ['eina'], []], ['embryo' ,[] , false, true, true, false, false, false, true, ['eina', 'efl', 'eo'], []], - ['eio' ,[] , false, true, false, false, true, true, true, ['eina', 'eet'], []], ['efreet' ,[] , false, false, true, false, false, false, true, ['eina', 'efl', 'eo'], []], ['ecore_imf_evas' ,[] , false, true, false, false, false, false, true, ['eina', 'efl', 'eo'], []], ['ephysics' ,['physics'] , false, true, false, false, false, false, true, ['eina', 'efl', 'eo'], []], diff --git a/src/lib/ecore_wl2/Ecore_Wl2.h b/src/lib/ecore_wl2/Ecore_Wl2.h index 1e7bf07..1058c21 100644 --- a/src/lib/ecore_wl2/Ecore_Wl2.h +++ b/src/lib/ecore_wl2/Ecore_Wl2.h @@ -2544,6 +2544,10 @@ EAPI void ecore_wl2_sync(void); EAPI unsigned int ecore_wl2_window_resource_id_get(Ecore_Wl2_Window *window); // +// TIZEN_ONLY(20221208): support default cursor configuration +EAPI void ecore_wl2_cursor_config_name_set(const char *name); +// + # undef EAPI # define EAPI diff --git a/src/lib/ecore_wl2/ecore_wl2_cursor.c b/src/lib/ecore_wl2/ecore_wl2_cursor.c new file mode 100644 index 0000000..3f62cb2 --- /dev/null +++ b/src/lib/ecore_wl2/ecore_wl2_cursor.c @@ -0,0 +1,340 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include "ecore_wl2_private.h" + +typedef struct _Cursor_Config Cursor_Config; +struct _Cursor_Config +{ + const char *name; +}; +static Eio_Monitor *_eio_cursor_monitor = NULL; +static Ecore_Event_Handler *_file_created_handler = NULL; +static Ecore_Event_Handler *_file_modified_handler = NULL; +static Eet_Data_Descriptor *_cursor_config_edd = NULL; +static Ecore_Timer *_config_change_delay_timer = NULL; + +Cursor_Config *_cursor_config = NULL; + +#define BASE_DIR "share/.cursor" + +size_t +_config_dir_snprintf(char *dst, + size_t size, + const char *fmt, + ...) +{ + size_t user_dir_len = 0, off = 0; + va_list ap; + char *tmp; + + tmp = eina_vpath_resolve("(:home:)/" BASE_DIR); + + eina_strlcpy(dst, tmp, size); + free(tmp); + + user_dir_len = strlen(dst); + off = user_dir_len + 1; + if (off >= size) return off; + dst[user_dir_len] = '/'; + va_start(ap, fmt); + off = off + vsnprintf(dst + off, size - off, fmt, ap); + va_end(ap); + return off; +} + +static void +_cursor_config_apply(void) +{ + Ecore_Wl2_Display *ewd = NULL; + Ecore_Wl2_Input *input = NULL; + + ewd = ecore_wl2_connected_display_get(NULL); + if (!ewd) return; + input = ecore_wl2_input_default_input_get(ewd); + if (!input) return; + + // Cursor change from configuration is applied only for default cursor + if (!input->cursor.theme_name || eina_streq(input->cursor.theme_name, "default")) + { + if (!input->cursor.name || !eina_streq(input->cursor.name, _cursor_config->name)) + ecore_wl2_input_cursor_from_name_set(input, _cursor_config->name); + } +} + +static void +_cursor_config_free(Cursor_Config *cfg) +{ + eina_stringshare_del(cfg->name); + free(cfg); +} + +static Cursor_Config * +_cursor_config_load(void) +{ + Cursor_Config *cfg = NULL; + Eet_File *ef; + char buf[PATH_MAX]; + + _config_dir_snprintf(buf, sizeof(buf), "config"); + ecore_file_mkpath(buf); + + _config_dir_snprintf(buf, sizeof(buf), "config/cursor.cfg"); + + ef = eet_open(buf, EET_FILE_MODE_READ); + if (ef) + { + cfg = eet_data_read(ef, _cursor_config_edd, "config"); + eet_close(ef); + } + +err: + if (!cfg) + { + cfg = calloc(1, sizeof(Cursor_Config)); + if (!cfg) return NULL; + cfg->name = eina_stringshare_add("left_ptr"); + } + + return cfg; +} + +static Eina_Bool +_config_change_delay_cb(void *data EINA_UNUSED) +{ + _ecore_wl2_cursor_config_reload(); + _cursor_config_apply(); + + _config_change_delay_timer = NULL; + return ECORE_CALLBACK_CANCEL; +} + +static Eina_Bool +_config_file_monitor_cb(void *data EINA_UNUSED, + int type, + void *event) +{ + Eio_Monitor_Event *ev = event; + + const char *file = ecore_file_file_get(ev->filename); + + if (ev->monitor == _eio_cursor_monitor) + { + if ((type == EIO_MONITOR_FILE_CREATED) || (type == EIO_MONITOR_FILE_MODIFIED)) + { + if (!strcmp(file, "cursor.cfg")) + { + if (_config_change_delay_timer) ecore_timer_del(_config_change_delay_timer); + _config_change_delay_timer = ecore_timer_add(0.1, _config_change_delay_cb, NULL); + } + } + } + return ECORE_CALLBACK_PASS_ON; +} +static void +_cursor_desc_init(void) +{ + Eet_Data_Descriptor_Class eddc; + + EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Cursor_Config); + eddc.func.str_direct_alloc = NULL; + eddc.func.str_direct_free = NULL; + + _cursor_config_edd = eet_data_descriptor_file_new(&eddc); + if (!_cursor_config_edd) return; + memset(&eddc, 0, sizeof(eddc)); + EET_DATA_DESCRIPTOR_ADD_BASIC(_cursor_config_edd, Cursor_Config, "name", name, EET_T_STRING); +} + +static void +_cursor_desc_shutdown(void) +{ + if (_cursor_config_edd) + { + eet_data_descriptor_free(_cursor_config_edd); + _cursor_config_edd = NULL; + } +} + +static void +_cursor_monitor_add(void) +{ + char buf[PATH_MAX]; + + _config_dir_snprintf(buf, sizeof(buf), "config"); + ecore_file_mkpath(buf); + + _eio_cursor_monitor = eio_monitor_add(buf); + _file_created_handler = ecore_event_handler_add + (EIO_MONITOR_FILE_CREATED, _config_file_monitor_cb, NULL); + _file_modified_handler = ecore_event_handler_add + (EIO_MONITOR_FILE_MODIFIED, _config_file_monitor_cb, NULL); +} + +void +_ecore_wl2_cursor_config_reload(void) +{ + if (_cursor_config) _cursor_config_free(_cursor_config); + _cursor_config = _cursor_config_load(); +} + +void +_ecore_wl2_cursor_config_init(void) +{ + eet_init(); + eio_init(); + _cursor_desc_init(); + _cursor_monitor_add(); + _cursor_config = _cursor_config_load(); + _cursor_config_apply(); +} + +void +_ecore_wl2_cursor_config_shutdown(void) +{ + if (_file_created_handler) ecore_event_handler_del(_file_created_handler); + _file_created_handler = NULL; + if (_file_modified_handler) ecore_event_handler_del(_file_modified_handler); + _file_modified_handler = NULL; + if (_eio_cursor_monitor) eio_monitor_del(_eio_cursor_monitor); + _eio_cursor_monitor = NULL; + if (_cursor_config) _cursor_config_free(_cursor_config); + _cursor_config = NULL; + if (_config_change_delay_timer) ecore_timer_del(_config_change_delay_timer); + _config_change_delay_timer = NULL; + _cursor_desc_shutdown(); + eio_shutdown(); + eet_shutdown(); +} + +EAPI void +ecore_wl2_cursor_config_name_set(const char* name) +{ + if (!name) return; + eina_stringshare_replace(&(_cursor_config->name), name); + + _ecore_wl2_cursor_config_save(); +} + +const char * +_ecore_wl2_cursor_config_name_get() +{ + return _cursor_config->name; +} + +static const char * +_eet_close_error_get(Eet_File *ef, + char *file) +{ + Eet_Error err; + const char *erstr = NULL; + + err = eet_close(ef); + switch (err) + { + case EET_ERROR_WRITE_ERROR: + erstr = "EET_ERROR_WRITE_ERROR"; + break; + + case EET_ERROR_WRITE_ERROR_FILE_TOO_BIG: + erstr = "EET_ERROR_WRITE_ERROR_FILE_TOO_BIG"; + break; + + case EET_ERROR_WRITE_ERROR_IO_ERROR: + erstr = "EET_ERROR_WRITE_ERROR_IO_ERROR"; + break; + + case EET_ERROR_WRITE_ERROR_OUT_OF_SPACE: + erstr = "EET_ERROR_WRITE_ERROR_OUT_OF_SPACE"; + break; + + case EET_ERROR_WRITE_ERROR_FILE_CLOSED: + erstr = "EET_ERROR_WRITE_ERROR_FILE_CLOSED"; + break; + + default: + break; + } + if (erstr) + { + /* delete any partially-written file */ + ecore_file_unlink(file); + return strdup(erstr); + } + + return NULL; +} + +Eina_Bool +_cursor_config_save(Cursor_Config *cfg) +{ + char buf[PATH_MAX], buf2[PATH_MAX]; + int ok = 0, ret; + const char *err; + Eet_File *ef; + size_t len; + + len = _config_dir_snprintf(buf, sizeof(buf), "config"); + if (len + 1 >= sizeof(buf)) + return EINA_FALSE; + + ok = ecore_file_mkpath(buf); + if (!ok) + { + ERR("Problem accessing user configuration directory: %s", buf); + return EINA_FALSE; + } + + buf[len] = '/'; + len++; + + if (len + sizeof("cursor.cfg") >= sizeof(buf) - len) + return EINA_FALSE; + + memcpy(buf + len, "cursor.cfg", sizeof("cursor.cfg")); + len += sizeof("cursor.cfg") - 1; + + if (len + sizeof(".tmp") >= sizeof(buf)) + return EINA_FALSE; + + memcpy(buf2, buf, len); + memcpy(buf2 + len, ".tmp", sizeof(".tmp")); + + ef = eet_open(buf2, EET_FILE_MODE_WRITE); + if (!ef) + return EINA_FALSE; + + ok = eet_data_write(ef, _cursor_config_edd, "config", cfg, 1); + if (!ok) + goto err; + + err = _eet_close_error_get(ef, buf2); + if (err) + { + ERR("%s", err); + free((void *)err); + goto err; + } + + ret = ecore_file_mv(buf2, buf); + if (!ret) + { + ERR("Error saving configuration file"); + goto err; + } + + return EINA_TRUE; + +err: + ecore_file_unlink(buf2); + return EINA_FALSE; +} + +Eina_Bool +_ecore_wl2_cursor_config_save(void) +{ + return _cursor_config_save(_cursor_config); +} diff --git a/src/lib/ecore_wl2/ecore_wl2_input.c b/src/lib/ecore_wl2/ecore_wl2_input.c index baa04b5..39cb1c0 100644 --- a/src/lib/ecore_wl2/ecore_wl2_input.c +++ b/src/lib/ecore_wl2/ecore_wl2_input.c @@ -1030,6 +1030,7 @@ _pointer_cb_enter(void *data, struct wl_pointer *pointer EINA_UNUSED, unsigned i { Ecore_Wl2_Input *input; Ecore_Wl2_Window *window; + const char *config_cursor_name; input = data; if (!input) return; @@ -1050,6 +1051,18 @@ _pointer_cb_enter(void *data, struct wl_pointer *pointer EINA_UNUSED, unsigned i input->pointer.sx = wl_fixed_to_double(sx); input->pointer.sy = wl_fixed_to_double(sy); + // Cursor change from configuration is applied only for default cursor + if (!input->cursor.theme_name || eina_streq(input->cursor.theme_name, "default")) + { + _ecore_wl2_cursor_config_reload(); + config_cursor_name = _ecore_wl2_cursor_config_name_get(); + if (config_cursor_name) + { + if (!input->cursor.name || !eina_streq(input->cursor.name, config_cursor_name)) + eina_stringshare_replace(&input->cursor.name, config_cursor_name); + } + } + // TIZEN_ONLY(20171207): add functions to set client's custom cursors /* The cursor on the surface is undefined until we set it */ ecore_wl2_input_cursor_from_name_set(input, input->cursor.name); @@ -2357,6 +2370,7 @@ _ecore_wl2_input_add(Ecore_Wl2_Display *display, unsigned int id, unsigned int v /* setup cursor size and theme */ _ecore_wl2_input_cursor_setup(input); + _ecore_wl2_cursor_config_init(); input->wl.seat = wl_registry_bind(display->wl.registry, id, &wl_seat_interface, 4); @@ -2407,6 +2421,8 @@ _ecore_wl2_input_del(Ecore_Wl2_Input *input) if (input->repeat.timer) ecore_timer_del(input->repeat.timer); + _ecore_wl2_cursor_config_shutdown(); + if (input->cursor.name) eina_stringshare_del(input->cursor.name); // TIZEN_ONLY(20200219): cleanup cursor resources when a Ecore_Wl2_Input is destroy _ecore_wl2_input_cursor_cleanup(input); @@ -3858,7 +3874,7 @@ ecore_wl2_input_default_input_get(const Ecore_Wl2_Display *ewd) Ecore_Wl2_Input *input; EINA_SAFETY_ON_NULL_RETURN_VAL(ewd, NULL); - EINA_SAFETY_ON_NULL_RETURN_VAL(ewd->inputs, NULL); + if (!ewd->inputs) return NULL; input = ecore_wl2_display_input_find_by_name(ewd, "seat0"); if (!input) input = ecore_wl2_display_input_find_by_name(ewd, "default"); diff --git a/src/lib/ecore_wl2/ecore_wl2_private.h b/src/lib/ecore_wl2/ecore_wl2_private.h index 4e0ec5f..52b2748 100644 --- a/src/lib/ecore_wl2/ecore_wl2_private.h +++ b/src/lib/ecore_wl2/ecore_wl2_private.h @@ -940,4 +940,12 @@ Eina_Hash *_ecore_wl2_window_hash_get(void); Eina_Bool buffer_fill_zero(tbm_surface_h surface); // +// TIZEN_ONLY(20221208): support default cursor configuration +void _ecore_wl2_cursor_config_init(void); +void _ecore_wl2_cursor_config_shutdown(void); +void _ecore_wl2_cursor_config_reload(void); +const char * _ecore_wl2_cursor_config_name_get(void); +Eina_Bool _ecore_wl2_cursor_config_save(void); +// + #endif diff --git a/src/lib/ecore_wl2/meson.build b/src/lib/ecore_wl2/meson.build index 92abb61..48db951 100644 --- a/src/lib/ecore_wl2/meson.build +++ b/src/lib/ecore_wl2/meson.build @@ -1,5 +1,5 @@ -ecore_wl2_deps = [ecore, ecore_input, buildsystem] -ecore_wl2_pub_deps = [eina, ecore] +ecore_wl2_deps = [ecore, ecore_input, eio, buildsystem] +ecore_wl2_pub_deps = [eina, ecore, ecore_file] ecore_wl2_ext_deps = [dependency('wayland-client'), dependency('wayland-server'), dependency('xkbcommon'), wayland_protocol, libdrm, buildsystem_simple, dl, m] @@ -19,7 +19,8 @@ ecore_wl2_src = files([ 'ecore_wl2.c', 'ecore_wl2_private.h', 'ecore_wl2_buffer.c', - 'ecore_wl2_surface.c' + 'ecore_wl2_surface.c', + 'ecore_wl2_cursor.c' ]) # <----- TIZEN_ONLY(20190109: introduce mesonbuild on tizen env -- 2.7.4