diff --git a/src/driver-hidpp10.c b/src/driver-hidpp10.c index 30e59592..b732583f 100644 --- a/src/driver-hidpp10.c +++ b/src/driver-hidpp10.c @@ -122,19 +122,33 @@ hidpp10drv_read_profile(struct ratbag_profile *profile, unsigned int index) struct ratbag_device *device = profile->device; struct hidpp10drv_data *drv_data; struct hidpp10_device *hidpp10; - uint16_t xres, yres, refresh; + struct hidpp10_profile p; int rc; + unsigned int i; + uint16_t xres, yres; drv_data = ratbag_get_drv_data(device); hidpp10 = drv_data->dev; + rc = hidpp10_get_profile(hidpp10, index, &p); + if (rc) + return; rc = hidpp10_get_current_resolution(hidpp10, &xres, &yres); - if (rc == 0) - profile->current_dpi = xres; + if (rc) + xres = 0xffff; - rc = hidpp10_get_usb_refresh_rate(hidpp10, &refresh); - if (rc == 0) - profile->report_rate = refresh; + profile->resolution.num_modes = p.num_dpi_modes; + for (i = 0; i < p.num_dpi_modes; i++) { + /* FIXME: we should expose x/y res separately */ + profile->resolution.modes[i].dpi = p.dpi_modes[i].xres; + profile->resolution.modes[i].hz = p.refresh_rate; + profile->resolution.modes[i].is_active = false; + /* FIXME: active != default. p.default_dpi_mode is the + * default, we can only tick the active in the currently + * active profile */ + if (profile->resolution.modes[i].dpi == xres) + profile->resolution.modes[i].is_active = true; + } } static int diff --git a/src/driver-hidpp20.c b/src/driver-hidpp20.c index a828734d..e5903ab8 100644 --- a/src/driver-hidpp20.c +++ b/src/driver-hidpp20.c @@ -297,9 +297,13 @@ hidpp20drv_read_profile(struct ratbag_profile *profile, unsigned int index) struct ratbag_device *device = profile->device; int dpi; + + /* FIXME */ +#if 0 dpi = hidpp20drv_read_resolution_dpi(device); if (dpi > 0) profile->current_dpi = dpi; +#endif hidpp20drv_read_special_key_mouse(device); } diff --git a/src/libratbag-private.h b/src/libratbag-private.h index b152b504..729822a1 100644 --- a/src/libratbag-private.h +++ b/src/libratbag-private.h @@ -26,6 +26,7 @@ #include #include +#include #include "libratbag.h" #include "libratbag-util.h" @@ -178,6 +179,15 @@ struct ratbag_driver { struct list link; }; +#define MAX_RESOLUTIONS 10 +struct ratbag_resolution{ + int refcount; + void *userdata; + unsigned int dpi; /**< resolution on dpi */ + unsigned int hz; /**< report rate in Hz */ + bool is_active; +}; + struct ratbag_profile { int refcount; void *userdata; @@ -188,8 +198,10 @@ struct ratbag_profile { struct list buttons; void *drv_data; void *user_data; - int current_dpi; - int report_rate; + struct { + struct ratbag_resolution modes[MAX_RESOLUTIONS]; + unsigned int num_modes; + } resolution; }; #define BUTTON_ACTION_NONE \ diff --git a/src/libratbag.c b/src/libratbag.c index 8a273635..5acdca1c 100644 --- a/src/libratbag.c +++ b/src/libratbag.c @@ -695,31 +695,95 @@ ratbag_device_set_active_profile(struct ratbag_profile *profile) return rc; } + LIBRATBAG_EXPORT int -ratbag_profile_get_resolution_dpi(const struct ratbag_profile *profile) +ratbag_profile_get_num_resolutions(struct ratbag_profile *profile) { - assert(profile); - return profile->current_dpi; + return profile->resolution.num_modes; +} + +LIBRATBAG_EXPORT struct ratbag_resolution * +ratbag_profile_get_resolution(struct ratbag_profile *profile, unsigned int idx) +{ + struct ratbag_resolution *res; + int max = ratbag_profile_get_num_resolutions(profile); + + if (max < 0 || idx >= (unsigned int)max) + return NULL; + + res = &profile->resolution.modes[idx]; + + return ratbag_resolution_ref(res); +} + +LIBRATBAG_EXPORT struct ratbag_resolution * +ratbag_resolution_ref(struct ratbag_resolution *resolution) +{ + resolution->refcount++; + return resolution; +} + +LIBRATBAG_EXPORT struct ratbag_resolution * +ratbag_resolution_unref(struct ratbag_resolution *resolution) +{ + if (resolution == NULL) + return NULL; + + assert(resolution->refcount > 0); + resolution->refcount--; + if (resolution->refcount > 0) + return resolution; + + /* Resolution is a fixed list of structs, no freeing required */ + + return NULL; } LIBRATBAG_EXPORT int -ratbag_profile_set_resolution_dpi(struct ratbag_profile *profile, int dpi) +ratbag_resolution_set_dpi(struct ratbag_resolution *resolution, + unsigned int dpi) { - if (!ratbag_device_has_capability(profile->device, - RATBAG_CAP_SWITCHABLE_RESOLUTION)) - return -ENOTSUP; - - assert(profile->device->driver->write_resolution_dpi); - return profile->device->driver->write_resolution_dpi(profile, dpi); + resolution->dpi = dpi; + /* FIXME: call into the driver */ + return 0; } LIBRATBAG_EXPORT int -ratbag_profile_get_report_rate_hz(const struct ratbag_profile *profile) +ratbag_resolution_set_report_rate(struct ratbag_resolution *resolution, + unsigned int hz) { - assert(profile); - return profile->report_rate; + resolution->hz = hz; + /* FIXME: call into the driver */ + return 0; } +LIBRATBAG_EXPORT int +ratbag_resolution_get_dpi(struct ratbag_resolution *resolution) +{ + return resolution->dpi; +} + +LIBRATBAG_EXPORT int +ratbag_resolution_get_report_rate(struct ratbag_resolution *resolution) +{ + return resolution->hz; +} + +LIBRATBAG_EXPORT int +ratbag_resolution_is_active(const struct ratbag_resolution *resolution) +{ + return resolution->is_active; +} + +LIBRATBAG_EXPORT int +ratbag_resolution_set_active(struct ratbag_resolution *resolution) +{ + resolution->is_active = true; + /* FIXME: call into the driver */ + return 0; +} + + LIBRATBAG_EXPORT struct ratbag_button* ratbag_profile_get_button_by_index(struct ratbag_profile *profile, unsigned int index) @@ -895,7 +959,6 @@ ratbag_button_unref(struct ratbag_button *button) return NULL; } - #define func_userdata(T) \ LIBRATBAG_EXPORT void \ T##_set_user_data(struct T *ptr, void *userdata) \ @@ -913,3 +976,4 @@ func_userdata(ratbag) func_userdata(ratbag_device) func_userdata(ratbag_profile) func_userdata(ratbag_button) +func_userdata(ratbag_resolution) diff --git a/src/libratbag.h b/src/libratbag.h index cd3f60ed..2a615ddd 100644 --- a/src/libratbag.h +++ b/src/libratbag.h @@ -126,6 +126,18 @@ struct ratbag_profile; */ struct ratbag_button; +/** + * @ingroup resolution + * @struct ratbag_resolution + * + * Represents a resolution setting on the device. Most devices have multiple + * resolutions per profile, one of which is active at a time. + * + * This struct is refcounted, use ratbag_resolution_ref() and + * ratbag_resolution_unref(). + */ +struct ratbag_resolution; + /** * @ingroup base * @struct ratbag_interface @@ -416,6 +428,199 @@ ratbag_device_get_active_profile(struct ratbag_device *ratbag); int ratbag_device_set_active_profile(struct ratbag_profile *profile); +/** + * @ingroup profile + * + * Get the number of @ref ratbag_resolution available in this profile. A + * resolution mode is a tuple of (resolution, report rate), each mode can be + * fetched with ratbag_profile_get_resolution_by_idx(). + * + * The returned value is the maximum number of modes available and thus + * identical for all profiles. However, some of the modes may not be + * configured. + * + * @param profile A previously initialized ratbag profile + * + * @return The number of profiles available. + */ +int +ratbag_profile_get_num_resolutions(struct ratbag_profile *profile); + +/** + * @ingroup profile + * + * Return the resolution in DPI and the report rate in Hz for the resolution + * mode identified by the given index. The index must be between 0 and + * ratbag_profile_get_num_resolution_modes(). + * + * See ratbag_profile_get_num_resolution_modes() for a description of + * resolution_modes. + * + * Profiles available but not currently configured on the device return + * success but set dpi and hz to 0. + * + * The returned struct has a refcount of at least 1, use + * ratbag_resolution_unref() to release the resources associated. + * + * @param profile A previously initialized ratbag profile + * @param idx The index of the resolution mode to get + * + * @return zero on success, non-zero otherwise. On error, dpi and hz are + * unmodified. + */ +struct ratbag_resolution * +ratbag_profile_get_resolution(struct ratbag_profile *profile, unsigned int idx); + +/** + * @ingroup resolution + * + * Add a reference to the resolution. A resolution is destroyed whenever the + * reference count reaches 0. See @ref ratbag_resolution_unref. + * + * @param resolution A previously initialized valid ratbag resolution + * @return The passed ratbag resolution + */ +struct ratbag_resolution * +ratbag_resolution_ref(struct ratbag_resolution *resolution); + +/** + * @ingroup resolution + * + * Dereference the ratbag resolution. After this, the resolution may have been + * destroyed, if the last reference was dereferenced. If so, the resolution is + * invalid and may not be interacted with. + * + * @param resolution A previously initialized ratbag resolution + * @return NULL if context was destroyed otherwise the passed resolution + */ +struct ratbag_resolution * +ratbag_resolution_unref(struct ratbag_resolution *resolution); + +/** + * @ingroup resolution + * + * Set caller-specific data associated with this resolution. libratbag does + * not manage, look at, or modify this data. The caller must ensure the + * data is valid. + * + * @param resolution A previously initialized resolution + * @param userdata Caller-specific data passed to the various callback + * interfaces. + */ +void +ratbag_resolution_set_user_data(struct ratbag_resolution *resolution, void *userdata); + +/** + * @ingroup resolution + * + * Get the caller-specific data associated with this resolution, if any. + * + * @param resolution A previously initialized ratbag resolution + * @return The caller-specific data previously assigned in + * ratbag_resolution_set_user_data(). + */ +void* +ratbag_resolution_get_user_data(const struct ratbag_resolution *resolution); + +/** + * @ingroup resolution + * + * Set the resolution in DPI for the resolution mode. + * + * A value of 0 for dpi disables the mode. + * + * If the resolution mode is the currently active mode and the profile is + * the currently active profile, the change takes effect immediately. + * + * @param resolution A previously initialized ratbag resolution + * @param dpi Set to the resolution in dpi, 0 to disable + * + * @return zero on success, non-zero otherwise + */ +int +ratbag_resolution_set_dpi(struct ratbag_resolution *resolution, + unsigned int dpi); +/** + * @ingroup resolution + * + * Get the resolution in DPI for the resolution mode. + * + * A value of 0 for dpi indicates the mode is disabled. + * + * @param resolution A previously initialized ratbag resolution + * + * @return zero on success, non-zero otherwise + */ +int +ratbag_resolution_get_dpi(struct ratbag_resolution *resolution); + +/** + * @ingroup resolution + * + * Set the the report rate in Hz for the resolution mode. + * + * A value of 0 hz disables the mode. + * + * If the resolution mode is the currently active mode and the profile is + * the currently active profile, the change takes effect immediately. + * + * @param resolution A previously initialized ratbag resolution + * @param hz Set to the report rate in Hz, may be 0 + * + * @return zero on success, non-zero otherwise + */ +int +ratbag_resolution_set_report_rate(struct ratbag_resolution *resolution, + unsigned int hz); + +/** + * @ingroup resolution + * + * Get the the report rate in Hz for the resolution mode. + * + * A value of 0 hz indicates the mode is disabled. + * + * @param resolution A previously initialized ratbag resolution + * + * @return zero on success, non-zero otherwise + */ +int +ratbag_resolution_get_report_rate(struct ratbag_resolution *resolution); + +/** + * @ingroup resolution + * + * Activate the given resolution mode. If the mode is not configured, this + * function returns an error and the result is undefined. + * + * If the profile is the currently active profile, the change takes effect + * immediately. Otherwise, the resolution mode will be the active mode when + * the device switches to the profile next. + * + * @param resolution A previously initialized ratbag resolution + * + * @return zero on success, non-zero otherwise + */ +int +ratbag_resolution_set_active(struct ratbag_resolution *resolution); + +/** + * @ingroup resolution + * + * Check if the resolution mode is the currently active one. + * + * If the profile is the currently active profile, the mode is the one + * currently active. Otherwise, the resolution mode is the one used when + * the device switches to the profile next. + * + * @param resolution A previously initialized ratbag resolution + * + * @return Non-zero if the resolution mode is the active one, zero + * otherwise. + */ +int +ratbag_resolution_is_active(const struct ratbag_resolution *resolution); + /** * @ingroup profile * @@ -423,6 +628,7 @@ ratbag_device_set_active_profile(struct ratbag_profile *profile); * @return The current resolution in dots-per-inch. * @retval 0 The resolution is unknown */ +/* FIXME: remove me */ int ratbag_profile_get_resolution_dpi(const struct ratbag_profile *profile); @@ -439,6 +645,7 @@ ratbag_profile_get_resolution_dpi(const struct ratbag_profile *profile); * * @return 0 on success or -1 on failure */ +/* FIXME: remove me */ int ratbag_profile_set_resolution_dpi(struct ratbag_profile *profile, int dpi); @@ -449,6 +656,7 @@ ratbag_profile_set_resolution_dpi(struct ratbag_profile *profile, int dpi); * @return The current report rate in Hz * @retval 0 The report rate is unknown */ +/* FIXME: remove me */ int ratbag_profile_get_report_rate_hz(const struct ratbag_profile *profile); @@ -465,6 +673,7 @@ ratbag_profile_get_report_rate_hz(const struct ratbag_profile *profile); * * @return 0 on success or -1 on failure */ +/* FIXME: remove me */ int ratbag_profile_set_report_rate_hz(struct ratbag_profile *profile, int hz); diff --git a/src/libratbag.sym b/src/libratbag.sym index 600966f7..272b0d2d 100644 --- a/src/libratbag.sym +++ b/src/libratbag.sym @@ -33,13 +33,22 @@ global: ratbag_log_set_handler; ratbag_log_set_priority; ratbag_profile_get_button_by_index; - ratbag_profile_get_report_rate_hz; - ratbag_profile_get_resolution_dpi; + ratbag_profile_get_num_resolutions; + ratbag_profile_get_resolution; ratbag_profile_get_user_data; - ratbag_profile_set_resolution_dpi; ratbag_profile_ref; ratbag_profile_set_user_data; ratbag_profile_unref; + ratbag_resolution_get_dpi; + ratbag_resolution_get_report_rate; + ratbag_resolution_get_user_data; + ratbag_resolution_is_active; + ratbag_resolution_ref; + ratbag_resolution_set_active; + ratbag_resolution_set_dpi; + ratbag_resolution_set_report_rate; + ratbag_resolution_set_user_data; + ratbag_resolution_unref; ratbag_ref; ratbag_set_user_data; ratbag_unref; diff --git a/tools/ratbag-command.c b/tools/ratbag-command.c index a44746ef..dfe4b37c 100644 --- a/tools/ratbag-command.c +++ b/tools/ratbag-command.c @@ -277,7 +277,7 @@ ratbag_cmd_info(struct ratbag *ratbag, uint32_t flags, int argc, char **argv) struct ratbag_button *button; char *action; int num_profiles, num_buttons; - int i, b; + int i, j, b; int rc = 1; if (argc != 1) { @@ -321,12 +321,20 @@ ratbag_cmd_info(struct ratbag *ratbag, uint32_t flags, int argc, char **argv) int dpi, rate; profile = ratbag_device_get_profile_by_index(device, i); - dpi = ratbag_profile_get_resolution_dpi(profile); - rate = ratbag_profile_get_report_rate_hz(profile); printf(" Profile %d%s\n", i, profile == active_profile ? " (active)" : ""); - printf(" Resolution: %ddpi\n", dpi); - printf(" Report rate: %dhz\n", rate); + printf(" Resolutions:\n"); + for (j = 0; j < ratbag_profile_get_num_resolutions(profile); j++) { + struct ratbag_resolution *res; + + res = ratbag_profile_get_resolution(profile, j); + dpi = ratbag_resolution_get_dpi(res); + rate = ratbag_resolution_get_report_rate(res); + printf(" %d: %ddpi @ %dHz%s\n", i+1, dpi, rate, + ratbag_resolution_is_active(res) ? " (active)" : ""); + + ratbag_resolution_unref(res); + } for (b = 0; b < num_buttons; b++) { enum ratbag_button_type type; @@ -705,6 +713,7 @@ ratbag_cmd_switch_dpi(struct ratbag *ratbag, uint32_t flags, int argc, char **ar struct ratbag_profile *profile = NULL; int rc = 1; int dpi; + int i; if (argc != 2) { usage(); @@ -732,15 +741,23 @@ ratbag_cmd_switch_dpi(struct ratbag *ratbag, uint32_t flags, int argc, char **ar goto out; } - rc = ratbag_profile_set_resolution_dpi(profile, dpi); - if (!rc) - printf("Switched the current resolution profile of '%s' to %d dpi\n", - ratbag_device_get_name(device), - dpi); - else - error("can't seem to be able to change the dpi: %s (%d)\n", - strerror(-rc), - rc); + for (i = 0; i < ratbag_profile_get_num_resolutions(profile); i++) { + struct ratbag_resolution *res; + + res = ratbag_profile_get_resolution(profile, i); + if (ratbag_resolution_is_active(res)) { + rc = ratbag_resolution_set_dpi(res, dpi); + if (!rc) + printf("Switched the current resolution profile of '%s' to %d dpi\n", + ratbag_device_get_name(device), + dpi); + else + error("can't seem to be able to change the dpi: %s (%d)\n", + strerror(-rc), + rc); + } + ratbag_resolution_unref(res); + } out: profile = ratbag_profile_unref(profile);