From 40546161908249b87df452c6fc03bf4ae1ef9f4a Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Fri, 11 Mar 2016 15:18:08 +1000 Subject: [PATCH] Revamp the button macro code The previous API was inconsistent and different to the rest of libratbag's API. Replace with one where a macro is a separate struct, can be initialized and then written to the device with a set_macro() call. The device copies the contents, the macro is otherwise unmodified and can be re-used by the client if need be. Signed-off-by: Peter Hutterer --- src/driver-etekcity.c | 7 +- src/driver-hidpp10.c | 24 +++--- src/driver-hidpp20.c | 23 +++--- src/driver-roccat.c | 9 ++- src/libratbag-private.h | 9 +++ src/libratbag.c | 148 +++++++++++++++++++++++++----------- src/libratbag.h | 161 ++++++++++++++++++++++++++++++---------- src/libratbag.sym | 16 ++-- tools/ratbag-command.c | 16 ++-- tools/shared.c | 12 ++- 10 files changed, 303 insertions(+), 122 deletions(-) diff --git a/src/driver-etekcity.c b/src/driver-etekcity.c index 012ecd58..efd6af51 100644 --- a/src/driver-etekcity.c +++ b/src/driver-etekcity.c @@ -430,6 +430,7 @@ etekcity_read_button(struct ratbag_button *button) { const struct ratbag_button_action *action; struct ratbag_device *device; + struct ratbag_button_macro *m; struct etekcity_macro *macro; struct etekcity_data *drv_data; uint8_t *buf; @@ -464,7 +465,7 @@ etekcity_read_button(struct ratbag_button *button) button->index, button->profile->index, rc < 0 ? strerror(-rc) : "not read enough", rc); } else { - ratbag_button_set_macro(button, macro->name); + m = ratbag_button_macro_new(macro->name); log_raw(device->ratbag, "macro on button %d of profile %d is named '%s', and contains %d events:\n", button->index, button->profile->index, @@ -472,7 +473,7 @@ etekcity_read_button(struct ratbag_button *button) for (j = 0; j < macro->length; j++) { unsigned int keycode = ratbag_hidraw_get_keycode_from_keyboard_usage(device, macro->keys[j].keycode); - ratbag_button_set_macro_event(button, + ratbag_button_macro_set_event(m, j, macro->keys[j].flag & 0x80 ? RATBAG_MACRO_EVENT_KEY_RELEASED : RATBAG_MACRO_EVENT_KEY_PRESSED, keycode); @@ -481,6 +482,8 @@ etekcity_read_button(struct ratbag_button *button) libevdev_event_code_get_name(EV_KEY, keycode), macro->keys[j].flag & 0x80 ? "released" : "pressed"); } + ratbag_button_copy_macro(button, m); + ratbag_button_macro_unref(m); } msleep(10); } diff --git a/src/driver-hidpp10.c b/src/driver-hidpp10.c index 59a6c823..0dfd8afc 100644 --- a/src/driver-hidpp10.c +++ b/src/driver-hidpp10.c @@ -76,6 +76,7 @@ hidpp10drv_read_macro(struct ratbag_button *button, union hidpp10_button *binding) { struct ratbag_device *device = button->profile->device; + struct ratbag_button_macro *m; const char *name; union hidpp10_macro_data *macro; unsigned int i, keycode; @@ -84,13 +85,13 @@ hidpp10drv_read_macro(struct ratbag_button *button, macro = profile->macros[binding->macro.address]; name = binding->macro.address > 1 ? (const char *)profile->macro_names[binding->macro.address - 2] : ""; - ratbag_button_set_macro(button, name); i = 0; + m = ratbag_button_macro_new(name); while (macro && macro->any.type != HIDPP10_MACRO_END && i < MAX_MACRO_EVENTS) { switch (macro->any.type) { case HIDPP10_MACRO_DELAY: - ratbag_button_set_macro_event(button, + ratbag_button_macro_set_event(m, i++, RATBAG_MACRO_EVENT_WAIT, macro->delay.time); @@ -99,11 +100,11 @@ hidpp10drv_read_macro(struct ratbag_button *button, case HIDPP10_MACRO_KEY_PRESS: keycode = ratbag_hidraw_get_keycode_from_keyboard_usage(device, macro->key.key); if (!delay) - ratbag_button_set_macro_event(button, + ratbag_button_macro_set_event(m, i++, RATBAG_MACRO_EVENT_WAIT, 1); - ratbag_button_set_macro_event(button, + ratbag_button_macro_set_event(m, i++, RATBAG_MACRO_EVENT_KEY_PRESSED, keycode); @@ -112,11 +113,11 @@ hidpp10drv_read_macro(struct ratbag_button *button, case HIDPP10_MACRO_KEY_RELEASE: keycode = ratbag_hidraw_get_keycode_from_keyboard_usage(device, macro->key.key); if (!delay) - ratbag_button_set_macro_event(button, + ratbag_button_macro_set_event(m, i++, RATBAG_MACRO_EVENT_WAIT, 1); - ratbag_button_set_macro_event(button, + ratbag_button_macro_set_event(m, i++, RATBAG_MACRO_EVENT_KEY_RELEASED, keycode); @@ -125,11 +126,11 @@ hidpp10drv_read_macro(struct ratbag_button *button, case HIDPP10_MACRO_MOD_PRESS: keycode = hidpp10drv_read_macro_modifier(device, macro); if (!delay) - ratbag_button_set_macro_event(button, + ratbag_button_macro_set_event(m, i++, RATBAG_MACRO_EVENT_WAIT, 1); - ratbag_button_set_macro_event(button, + ratbag_button_macro_set_event(m, i++, RATBAG_MACRO_EVENT_KEY_PRESSED, keycode); @@ -138,11 +139,11 @@ hidpp10drv_read_macro(struct ratbag_button *button, case HIDPP10_MACRO_MOD_RELEASE: keycode = hidpp10drv_read_macro_modifier(device, macro); if (!delay) - ratbag_button_set_macro_event(button, + ratbag_button_macro_set_event(m, i++, RATBAG_MACRO_EVENT_WAIT, 1); - ratbag_button_set_macro_event(button, + ratbag_button_macro_set_event(m, i++, RATBAG_MACRO_EVENT_KEY_RELEASED, keycode); @@ -151,6 +152,9 @@ hidpp10drv_read_macro(struct ratbag_button *button, } macro++; } + + ratbag_button_copy_macro(button, m); + ratbag_button_macro_unref(m); } static void diff --git a/src/driver-hidpp20.c b/src/driver-hidpp20.c index 3598d7c1..ba333cb2 100644 --- a/src/driver-hidpp20.c +++ b/src/driver-hidpp20.c @@ -123,32 +123,34 @@ hidpp20drv_read_macro_8100(struct ratbag_button *button, union hidpp20_button_binding *binding) { struct ratbag_device *device = button->profile->device; + struct ratbag_button_macro *m; union hidpp20_macro_data *macro; unsigned int i, keycode; bool delay = true; macro = profile->macros[binding->macro.page]; - ratbag_button_set_macro(button, "macro"); i = 0; + m = ratbag_button_macro_new("macro"); + while (macro && macro->any.type != HIDPP20_MACRO_END && i < MAX_MACRO_EVENTS) { switch (macro->any.type) { case HIDPP20_MACRO_DELAY: - ratbag_button_set_macro_event(button, - i++, - RATBAG_MACRO_EVENT_WAIT, - macro->delay.time); + ratbag_button_macro_set_event(m, + i++, + RATBAG_MACRO_EVENT_WAIT, + macro->delay.time); delay = true; break; case HIDPP20_MACRO_KEY_PRESS: keycode = hidpp20drv_read_macro_key_8100(device, macro); if (!delay) - ratbag_button_set_macro_event(button, + ratbag_button_macro_set_event(m, i++, RATBAG_MACRO_EVENT_WAIT, 1); - ratbag_button_set_macro_event(button, + ratbag_button_macro_set_event(m, i++, RATBAG_MACRO_EVENT_KEY_PRESSED, keycode); @@ -157,11 +159,11 @@ hidpp20drv_read_macro_8100(struct ratbag_button *button, case HIDPP20_MACRO_KEY_RELEASE: keycode = hidpp20drv_read_macro_key_8100(device, macro); if (!delay) - ratbag_button_set_macro_event(button, + ratbag_button_macro_set_event(m, i++, RATBAG_MACRO_EVENT_WAIT, 1); - ratbag_button_set_macro_event(button, + ratbag_button_macro_set_event(m, i++, RATBAG_MACRO_EVENT_KEY_RELEASED, keycode); @@ -170,6 +172,9 @@ hidpp20drv_read_macro_8100(struct ratbag_button *button, } macro++; } + + ratbag_button_copy_macro(button, m); + ratbag_button_macro_unref(m); } static void diff --git a/src/driver-roccat.c b/src/driver-roccat.c index ef563265..ec702a0e 100644 --- a/src/driver-roccat.c +++ b/src/driver-roccat.c @@ -532,6 +532,7 @@ roccat_read_button(struct ratbag_button *button) ratbag_button_enable_action_type(button, RATBAG_BUTTON_ACTION_TYPE_MACRO); if (action && action->type == RATBAG_BUTTON_ACTION_TYPE_MACRO) { + struct ratbag_button_macro *m = NULL; roccat_set_config_profile(device, button->profile->index, @@ -566,7 +567,7 @@ roccat_read_button(struct ratbag_button *button) goto out_macro; } - ratbag_button_set_macro(button, macro->name); + m = ratbag_button_macro_new(macro->name); log_raw(device->ratbag, "macro on button %d of profile %d is named '%s', and contains %d events:\n", button->index, button->profile->index, @@ -574,7 +575,7 @@ roccat_read_button(struct ratbag_button *button) for (j = 0; j < macro->length; j++) { unsigned int keycode = ratbag_hidraw_get_keycode_from_keyboard_usage(device, macro->keys[j].keycode); - ratbag_button_set_macro_event(button, + ratbag_button_macro_set_event(m, j * 2, macro->keys[j].flag & 0x01 ? RATBAG_MACRO_EVENT_KEY_PRESSED : RATBAG_MACRO_EVENT_KEY_RELEASED, keycode); @@ -582,7 +583,7 @@ roccat_read_button(struct ratbag_button *button) time = macro->keys[j].time; else time = macro->keys[j].flag & 0x01 ? 10 : 50; - ratbag_button_set_macro_event(button, + ratbag_button_macro_set_event(m, j * 2 + 1, RATBAG_MACRO_EVENT_WAIT, time); @@ -592,9 +593,11 @@ roccat_read_button(struct ratbag_button *button) libevdev_event_code_get_name(EV_KEY, keycode), macro->keys[j].flag & 0x80 ? "released" : "pressed"); } + ratbag_button_copy_macro(button, m); } out_macro: msleep(10); + ratbag_button_macro_unref(m); } } diff --git a/src/libratbag-private.h b/src/libratbag-private.h index 2ba4202b..041a8e68 100644 --- a/src/libratbag-private.h +++ b/src/libratbag-private.h @@ -250,6 +250,11 @@ struct ratbag_macro { struct ratbag_macro_event events[MAX_MACRO_EVENTS]; }; +struct ratbag_button_macro { + int refcount; + struct ratbag_macro macro; +}; + struct ratbag_button_action { enum ratbag_button_action_type type; union ratbag_btn_action { @@ -432,5 +437,9 @@ ratbag_assign_driver(struct ratbag_device *device, void ratbag_register_driver(struct ratbag *ratbag, struct ratbag_driver *driver); +void +ratbag_button_copy_macro(struct ratbag_button *button, + const struct ratbag_button_macro *macro); + #endif /* LIBRATBAG_PRIVATE_H */ diff --git a/src/libratbag.c b/src/libratbag.c index d5a319e7..b62038cb 100644 --- a/src/libratbag.c +++ b/src/libratbag.c @@ -1161,8 +1161,25 @@ ratbag_resolution_get_user_data(const struct ratbag_resolution *ratbag_resolutio return ratbag_resolution->userdata; } -LIBRATBAG_EXPORT enum ratbag_error_code -ratbag_button_set_macro(struct ratbag_button *button, const char *name) +LIBRATBAG_EXPORT struct ratbag_button_macro * +ratbag_button_get_macro(struct ratbag_button *button) +{ + struct ratbag_button_macro *macro; + + if (button->action.type != RATBAG_BUTTON_ACTION_TYPE_MACRO) + return NULL; + + macro = ratbag_button_macro_new(button->action.macro->name); + memcpy(macro->macro.events, + button->action.macro->events, + sizeof(macro->macro.events)); + + return macro; +} + +void +ratbag_button_copy_macro(struct ratbag_button *button, + const struct ratbag_button_macro *macro) { if (!button->action.macro) button->action.macro = zalloc(sizeof(struct ratbag_macro)); @@ -1173,25 +1190,37 @@ ratbag_button_set_macro(struct ratbag_button *button, const char *name) } button->action.type = RATBAG_BUTTON_ACTION_TYPE_MACRO; - button->action.macro->name = strdup_safe(name); - - return RATBAG_SUCCESS; + memcpy(button->action.macro->events, + macro->macro.events, + sizeof(macro->macro.events)); + button->action.macro->name = strdup_safe(macro->macro.name); + button->action.macro->group = strdup_safe(macro->macro.group); } LIBRATBAG_EXPORT enum ratbag_error_code -ratbag_button_set_macro_event(struct ratbag_button *button, +ratbag_button_set_macro(struct ratbag_button *button, + const struct ratbag_button_macro *macro) +{ + int rc; + + ratbag_button_copy_macro(button, macro); + + rc = button->profile->device->driver->write_button(button, &button->action); + + return rc == 0 ? RATBAG_SUCCESS : RATBAG_ERROR_DEVICE; +} + +LIBRATBAG_EXPORT enum ratbag_error_code +ratbag_button_macro_set_event(struct ratbag_button_macro *m, unsigned int index, enum ratbag_macro_event_type type, unsigned int data) { - struct ratbag_macro *macro; + struct ratbag_macro *macro = &m->macro; - if (button->action.type != RATBAG_BUTTON_ACTION_TYPE_MACRO || - index >= MAX_MACRO_EVENTS) + if (index >= MAX_MACRO_EVENTS) return RATBAG_ERROR_VALUE; - macro = button->action.macro; - switch (type) { case RATBAG_MACRO_EVENT_KEY_PRESSED: case RATBAG_MACRO_EVENT_KEY_RELEASED: @@ -1212,36 +1241,22 @@ ratbag_button_set_macro_event(struct ratbag_button *button, return 0; } -LIBRATBAG_EXPORT enum ratbag_error_code -ratbag_button_write_macro(struct ratbag_button *button) -{ - int rc; - - rc = button->profile->device->driver->write_button(button, &button->action); - - return rc == 0 ? RATBAG_SUCCESS : RATBAG_ERROR_DEVICE; -} - LIBRATBAG_EXPORT enum ratbag_macro_event_type -ratbag_button_get_macro_event_type(struct ratbag_button *button, unsigned int index) +ratbag_button_macro_get_event_type(struct ratbag_button_macro *macro, unsigned int index) { - if (button->action.type != RATBAG_BUTTON_ACTION_TYPE_MACRO || - index >= MAX_MACRO_EVENTS) + if (index >= MAX_MACRO_EVENTS) return RATBAG_MACRO_EVENT_INVALID; - return button->action.macro->events[index].type; + return macro->macro.events[index].type; } LIBRATBAG_EXPORT int -ratbag_button_get_macro_event_key(struct ratbag_button *button, unsigned int index) +ratbag_button_macro_get_event_key(struct ratbag_button_macro *m, unsigned int index) { - struct ratbag_macro *macro; + struct ratbag_macro *macro = &m->macro; - if (button->action.type != RATBAG_BUTTON_ACTION_TYPE_MACRO || - index >= MAX_MACRO_EVENTS) - return -EINVAL; - - macro = button->action.macro; + if (index >= MAX_MACRO_EVENTS) + return 0; if (macro->events[index].type != RATBAG_MACRO_EVENT_KEY_PRESSED && macro->events[index].type != RATBAG_MACRO_EVENT_KEY_RELEASED) @@ -1251,27 +1266,72 @@ ratbag_button_get_macro_event_key(struct ratbag_button *button, unsigned int ind } LIBRATBAG_EXPORT int -ratbag_button_get_macro_event_timeout(struct ratbag_button *button, unsigned int index) +ratbag_button_macro_get_event_timeout(struct ratbag_button_macro *m, + unsigned int index) { - struct ratbag_macro *macro; + struct ratbag_macro *macro = &m->macro; - if (button->action.type != RATBAG_BUTTON_ACTION_TYPE_MACRO || - index >= MAX_MACRO_EVENTS) - return -EINVAL; - - macro = button->action.macro; + if (index >= MAX_MACRO_EVENTS) + return 0; if (macro->events[index].type != RATBAG_MACRO_EVENT_WAIT) - return -EINVAL; + return 0; return macro->events[index].event.timeout; } -LIBRATBAG_EXPORT const char * -ratbag_button_get_macro_name(struct ratbag_button *button) +LIBRATBAG_EXPORT unsigned int +ratbag_button_macro_get_num_events(struct ratbag_button_macro *macro) { - if (button->action.type != RATBAG_BUTTON_ACTION_TYPE_MACRO) + return MAX_MACRO_EVENTS; +} + +LIBRATBAG_EXPORT const char * +ratbag_button_macro_get_name(struct ratbag_button_macro *macro) +{ + return macro->macro.name; +} + +static void +ratbag_button_macro_destroy(struct ratbag_button_macro *macro) +{ + assert(macro->refcount == 0); + free(macro->macro.name); + free(macro->macro.group); + free(macro); +} + +LIBRATBAG_EXPORT struct ratbag_button_macro * +ratbag_button_macro_ref(struct ratbag_button_macro *macro) +{ + assert(macro->refcount < INT_MAX); + + macro->refcount++; + return macro; +} + +LIBRATBAG_EXPORT struct ratbag_button_macro * +ratbag_button_macro_unref(struct ratbag_button_macro *macro) +{ + if (macro == NULL) return NULL; - return button->action.macro->name; + assert(macro->refcount > 0); + macro->refcount--; + if (macro->refcount == 0) + ratbag_button_macro_destroy(macro); + + return NULL; +} + +LIBRATBAG_EXPORT struct ratbag_button_macro * +ratbag_button_macro_new(const char *name) +{ + struct ratbag_button_macro *macro; + + macro = zalloc(sizeof *macro); + macro->refcount = 1; + macro->macro.name = strdup_safe(name); + + return macro; } diff --git a/src/libratbag.h b/src/libratbag.h index a556b0ca..21f4b122 100644 --- a/src/libratbag.h +++ b/src/libratbag.h @@ -125,6 +125,17 @@ struct ratbag_button; */ struct ratbag_resolution; +/** + * @ingroup button + * @struct ratbag_macro + * + * Represents a macro that can be assigned to a button. + * + * This struct is refcounted, use ratbag_button_macro_ref() and + * ratbag_button_macro_unref(). + */ +struct ratbag_button_macro; + /** * @ingroup base * @@ -1327,101 +1338,175 @@ enum ratbag_macro_event_type { /** * @ingroup button * - * If a button's action is @ref RATBAG_BUTTON_ACTION_TYPE_MACRO, - * this function returns the macro name. + * @param macro A previously initialized ratbag button macro * - * If the button's action type is not @ref RATBAG_BUTTON_ACTION_TYPE_MACRO, - * this function returns NULL. - * - * @param button A previously initialized ratbag button - * - * @return The name of the macro associated to the button. + * @return The name of the macro */ const char * -ratbag_button_get_macro_name(struct ratbag_button *button); +ratbag_button_macro_get_name(struct ratbag_button_macro *macro); /** * @ingroup button * - * If a button's action is @ref RATBAG_BUTTON_ACTION_TYPE_MACRO, - * this function returns the macro event type configured for the event at the + * @param macro A previously initialized ratbag button macro + * + * @return The maximum number of events that can be assigned to this macro + */ +unsigned int +ratbag_button_macro_get_num_events(struct ratbag_button_macro *macro); + +/** + * @ingroup button + * + * Returns the macro event type configured for the event at the * given index. * - * If the button's action type is not @ref RATBAG_BUTTON_ACTION_TYPE_MACRO, - * this function returns @ref RATBAG_MACRO_EVENT_INVALID. + * The behavior of this function for an index equal to or greater than the + * return value of ratbag_button_macro_get_num_events() is undefined. * - * @param button A previously initialized ratbag button + * @param macro A previously initialized ratbag button macro * @param index An index of the event within the macro we are interested in. * * @return The type of the event at the given index */ enum ratbag_macro_event_type -ratbag_button_get_macro_event_type(struct ratbag_button *button, unsigned int index); +ratbag_button_macro_get_event_type(struct ratbag_button_macro *macro, + unsigned int index); /** * @ingroup button * - * If a button's action is @ref RATBAG_BUTTON_ACTION_TYPE_MACRO, and if the - * event stored at the given index is @ref RATBAG_MACRO_EVENT_KEY_PRESSED or - * @ref RATBAG_MACRO_EVENT_KEY_RELEASED, this function returns the key code - * configured for the event at the given index. + * If the event stored at the given index is @ref + * RATBAG_MACRO_EVENT_KEY_PRESSED or @ref RATBAG_MACRO_EVENT_KEY_RELEASED, + * this function returns the key code configured for the event at the given + * index. * - * If the button's action type is not @ref RATBAG_BUTTON_ACTION_TYPE_MACRO, - * or if the event stored at the given index is not - * @ref RATBAG_MACRO_EVENT_KEY_PRESSED or @ref RATBAG_MACRO_EVENT_KEY_RELEASED, - * this function returns -EINVAL. + * The behavior of this function for an index equal to or greater than the + * return value of ratbag_button_macro_get_num_events() is undefined. * - * @param button A previously initialized ratbag button + * @param macro A previously initialized ratbag button macro * @param index An index of the event within the macro we are interested in. * * @return The key of the event at the given index */ int -ratbag_button_get_macro_event_key(struct ratbag_button *button, unsigned int index); +ratbag_button_macro_get_event_key(struct ratbag_button_macro*macro, + unsigned int index); /** * @ingroup button * - * If a button's action is @ref RATBAG_BUTTON_ACTION_TYPE_MACRO, and if the - * event stored at the given index is @ref RATBAG_MACRO_EVENT_WAIT, this - * function returns the timeout configured for the event at the given index. + * If the event stored at the given index is @ref RATBAG_MACRO_EVENT_WAIT, + * this function returns the timeout configured for the event at the given + * index. * - * If the button's action type is not @ref RATBAG_BUTTON_ACTION_TYPE_MACRO, - * or if the event stored at the given index is not - * @ref RATBAG_MACRO_EVENT_WAIT, this function returns -EINVAL. + * The behavior of this function for an index equal to or greater than the + * return value of ratbag_button_macro_get_num_events() is undefined. * - * @param button A previously initialized ratbag button + * @param macro A previously initialized ratbag button macro * @param index An index of the event within the macro we are interested in. * * @return The timeout of the event at the given index */ int -ratbag_button_get_macro_event_timeout(struct ratbag_button *button, unsigned int index); +ratbag_button_macro_get_event_timeout(struct ratbag_button_macro *macro, + unsigned int index); /** * @ingroup button * * Sets the button's action to @ref RATBAG_BUTTON_ACTION_TYPE_MACRO and - * allocates the required memory to store the macro. + * assigns the given macro to this button. + * + * libratbag does not use the macro struct passed in, it extracts the + * required information from the struct. Changes to the macro after a call + * to ratbag_button_set_macro() are not reflected in the device until a + * subsequent call to ratbag_button_set_macro(). + * + * @param button A previously intialized ratbag button + * @param macro A fully initialized macro + * + * @return 0 on success or nonzero otherwise */ enum ratbag_error_code -ratbag_button_set_macro(struct ratbag_button *button, const char *name); +ratbag_button_set_macro(struct ratbag_button *button, + const struct ratbag_button_macro *macro); -enum ratbag_error_code -ratbag_button_write_macro(struct ratbag_button *button); +/** + * @ingroup button + * + * Initialize a new button macro. + * + * The macro is refcounted with an initial value of at least 1. + * Use ratbag_button_macro_unref() to release the macro. + * + * Note that some devices have limited storage for the macro names. + * libratbag silently shortens macro names to the longest string the device + * is capable of storing. + * + * @param name The name to assign to this macro. + * + * @return An "empty" button macro + */ +struct ratbag_button_macro * +ratbag_button_macro_new(const char *name); + +/** + * @ingroup button + * + * If a button's action is @ref RATBAG_BUTTON_ACTION_TYPE_MACRO, + * this function returns the current button macro. The macro is a copy of + * the one used on the device, changes to the macro are not reflected on the + * device until a subsequent call to ratbag_button_set_macro(). + * + * If a button's action is not @ref RATBAG_BUTTON_ACTION_TYPE_MACRO, + * this function returns NULL. + * + * @param button A previously initialized ratbag button + */ +struct ratbag_button_macro * +ratbag_button_get_macro(struct ratbag_button *button); /** * @ingroup button * * Sets the macro's event at the given index to the given type with the * key code or timeout given. + * + * The behavior of this function for an index equal to or greater than the + * return value of ratbag_button_macro_get_num_events() is undefined. */ enum ratbag_error_code -ratbag_button_set_macro_event(struct ratbag_button *button, +ratbag_button_macro_set_event(struct ratbag_button_macro *macro, unsigned int index, enum ratbag_macro_event_type type, unsigned int data); +/** + * @ingroup button + * + * Add a reference to the macro. A macro is destroyed whenever the + * reference count reaches 0. See @ref ratbag_button_macro_unref. + * + * @param macro A previously initialized valid ratbag button macro + * @return The passed ratbag macro + */ +struct ratbag_button_macro * +ratbag_button_macro_ref(struct ratbag_button_macro *macro); + +/** + * @ingroup button + * + * Dereference the ratbag button macro. When the internal refcount reaches + * zero, all resources associated with this object are released. The object + * must be considered invalid once unref is called. + * + * @param macro A previously initialized ratbag button macro + * @return Always NULL + */ +struct ratbag_button_macro * +ratbag_button_macro_unref(struct ratbag_button_macro *macro); + /** * @ingroup button * diff --git a/src/libratbag.sym b/src/libratbag.sym index 6493e194..b076bae8 100644 --- a/src/libratbag.sym +++ b/src/libratbag.sym @@ -8,22 +8,26 @@ global: ratbag_button_get_type; ratbag_button_get_button; ratbag_button_get_key; - ratbag_button_get_macro_event_type; - ratbag_button_get_macro_event_key; - ratbag_button_get_macro_event_timeout; - ratbag_button_get_macro_name; + ratbag_button_get_macro; ratbag_button_get_special; ratbag_button_get_user_data; ratbag_button_has_action_type; + ratbag_button_macro_get_event_key; + ratbag_button_macro_get_event_timeout; + ratbag_button_macro_get_event_type; + ratbag_button_macro_get_name; + ratbag_button_macro_get_num_events; + ratbag_button_macro_new; + ratbag_button_macro_ref; + ratbag_button_macro_set_event; + ratbag_button_macro_unref; ratbag_button_ref; ratbag_button_set_button; ratbag_button_set_key; ratbag_button_set_macro; - ratbag_button_set_macro_event; ratbag_button_set_special; ratbag_button_set_user_data; ratbag_button_unref; - ratbag_button_write_macro; ratbag_device_get_name; ratbag_device_get_num_buttons; ratbag_device_get_num_profiles; diff --git a/tools/ratbag-command.c b/tools/ratbag-command.c index 5c850d68..f780bb42 100644 --- a/tools/ratbag-command.c +++ b/tools/ratbag-command.c @@ -556,6 +556,7 @@ ratbag_cmd_change_button(const struct ratbag_cmd *cmd, struct ratbag_device *device; struct ratbag_button *button = NULL; struct ratbag_profile *profile = NULL; + struct ratbag_button_macro *m = NULL; int button_index; enum ratbag_button_action_type action_type; int rc = ERR_DEVICE; @@ -630,17 +631,18 @@ ratbag_cmd_change_button(const struct ratbag_cmd *cmd, rc = ratbag_button_set_special(button, special); break; case RATBAG_BUTTON_ACTION_TYPE_MACRO: - rc = ratbag_button_set_macro(button, macro.name); + m = ratbag_button_macro_new(macro.name); for (i = 0; i < ARRAY_LENGTH(macro.events); i++) { if (macro.events[i].type == RATBAG_MACRO_EVENT_NONE) break; - ratbag_button_set_macro_event(button, + ratbag_button_macro_set_event(m, i, macro.events[i].type, macro.events[i].data); } - rc = ratbag_button_write_macro(button); + rc = ratbag_button_set_macro(button, m); + ratbag_button_macro_unref(m); break; default: error("well, that shouldn't have happened\n"); @@ -1265,6 +1267,7 @@ ratbag_cmd_button_set_macro(const struct ratbag_cmd *cmd, { struct ratbag_device *device; struct ratbag_button *button; + struct ratbag_button_macro *m; struct macro macro = {0}; int rc; int i; @@ -1289,17 +1292,18 @@ ratbag_cmd_button_set_macro(const struct ratbag_cmd *cmd, return ERR_UNSUPPORTED; button = options->button; - rc = ratbag_button_set_macro(button, macro.name); + m = ratbag_button_macro_new(macro.name); for (i = 0; i < ARRAY_LENGTH(macro.events); i++) { if (macro.events[i].type == RATBAG_MACRO_EVENT_NONE) break; - ratbag_button_set_macro_event(button, + ratbag_button_macro_set_event(m, i, macro.events[i].type, macro.events[i].data); } - rc = ratbag_button_write_macro(button); + rc = ratbag_button_set_macro(button, m); + ratbag_button_macro_unref(m); if (rc != 0) return ERR_DEVICE; diff --git a/tools/shared.c b/tools/shared.c index 20a207fe..4a110e09 100644 --- a/tools/shared.c +++ b/tools/shared.c @@ -174,18 +174,20 @@ static const char *strip_ev_key(int key) char * button_action_macro_to_str(struct ratbag_button *button) { + struct ratbag_button_macro *macro; char str[4096] = {0}; const char *name; int offset; unsigned int i; - name = ratbag_button_get_macro_name(button); + macro = ratbag_button_get_macro(button); + name = ratbag_button_macro_get_name(macro); offset = snprintf(str, sizeof(str), "macro \"%s\":", name ? name : "UNKNOWN"); for (i = 0; i < MAX_MACRO_EVENTS; i++) { - enum ratbag_macro_event_type type = ratbag_button_get_macro_event_type(button, i); - int key = ratbag_button_get_macro_event_key(button, i); - int timeout = ratbag_button_get_macro_event_timeout(button, i); + enum ratbag_macro_event_type type = ratbag_button_macro_get_event_type(macro, i); + int key = ratbag_button_macro_get_event_key(macro, i); + int timeout = ratbag_button_macro_get_event_timeout(macro, i); if (type == RATBAG_MACRO_EVENT_NONE) break; @@ -205,6 +207,8 @@ button_action_macro_to_str(struct ratbag_button *button) } } + ratbag_button_macro_unref(macro); + return strdup_safe(str); }