diff --git a/src/driver-etekcity.c b/src/driver-etekcity.c index eb1a50c6..e3abdd65 100644 --- a/src/driver-etekcity.c +++ b/src/driver-etekcity.c @@ -507,10 +507,12 @@ etekcity_read_profile(struct ratbag_profile *profile, unsigned int index) hz = report_rate; if (!(setting_report->dpi_mask & (1 << i))) { /* the profile is disabled, overwrite it */ - resolution->dpi = 0; + resolution->dpi_x = 0; + resolution->dpi_y = 0; resolution->hz = 0; } - ratbag_resolution_init(profile, i, dpi,hz); + /* FIXME */ + ratbag_resolution_init(profile, i, dpi, dpi, hz); resolution->is_active = (i == setting_report->current_dpi); } @@ -622,7 +624,8 @@ etekcity_write_button(struct ratbag_button *button, } static int -etekcity_write_resolution_dpi(struct ratbag_resolution *resolution, int dpi) +etekcity_write_resolution_dpi(struct ratbag_resolution *resolution, + int dpi_x, int dpi_y) { struct ratbag_profile *profile = resolution->profile; struct ratbag_device *device = profile->device; @@ -632,7 +635,9 @@ etekcity_write_resolution_dpi(struct ratbag_resolution *resolution, int dpi) uint8_t *buf; int rc; - if (dpi < 50 || dpi > 8200 || dpi % 50) + if (dpi_x < 50 || dpi_x > 8200 || dpi_x % 50) + return -EINVAL; + if (dpi_y < 50 || dpi_y > 8200 || dpi_y % 50) return -EINVAL; settings_report = &drv_data->settings[profile->index]; @@ -640,11 +645,10 @@ etekcity_write_resolution_dpi(struct ratbag_resolution *resolution, int dpi) /* retrieve which resolution is asked to be changed */ index = resolution - profile->resolution.modes; - /* FIXME: allow both x and y dpi to be set */ settings_report->x_sensitivity = 0x0a; settings_report->y_sensitivity = 0x0a; - settings_report->xres[index] = dpi / 50; - settings_report->yres[index] = dpi / 50; + settings_report->xres[index] = dpi_x / 50; + settings_report->yres[index] = dpi_y / 50; buf = (uint8_t*)settings_report; etekcity_set_config_profile(device, profile->index, ETEKCITY_CONFIG_SETTINGS); diff --git a/src/driver-hidpp10.c b/src/driver-hidpp10.c index f25a7089..0845c384 100644 --- a/src/driver-hidpp10.c +++ b/src/driver-hidpp10.c @@ -139,10 +139,15 @@ hidpp10drv_read_profile(struct ratbag_profile *profile, unsigned int index) 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 */ - ratbag_resolution_init(profile, i, p.dpi_modes[i].xres, + ratbag_resolution_init(profile, i, + p.dpi_modes[i].xres, + p.dpi_modes[i].yres, p.refresh_rate); - if (profile->is_active && profile->resolution.modes[i].dpi == xres) + ratbag_resolution_set_cap(&profile->resolution.modes[i], + RATBAG_RESOLUTION_CAP_SEPARATE_XY_RESOLUTION); + if (profile->is_active && + profile->resolution.modes[i].dpi_x == xres && + profile->resolution.modes[i].dpi_y == yres) profile->resolution.modes[i].is_active = true; if (i == p.default_dpi_mode) profile->resolution.modes[i].is_default = true; diff --git a/src/driver-hidpp20.c b/src/driver-hidpp20.c index a9899353..5db7dd0b 100644 --- a/src/driver-hidpp20.c +++ b/src/driver-hidpp20.c @@ -208,8 +208,9 @@ hidpp20drv_read_resolution_dpi(struct ratbag_profile *profile) drv_data->num_sensors = MAX_RESOLUTIONS; profile->resolution.num_modes = drv_data->num_sensors; for (i = 0; i < profile->resolution.num_modes; i++) { + int dpi = drv_data->sensors[i].dpi; /* FIXME: retrieve the refresh rate */ - ratbag_resolution_init(profile, i, drv_data->sensors[i].dpi, 0); + ratbag_resolution_init(profile, i, dpi, dpi, 0); /* FIXME: we mark all resolutions as active because * they are from different sensors */ @@ -223,13 +224,15 @@ hidpp20drv_read_resolution_dpi(struct ratbag_profile *profile) } static int -hidpp20drv_write_resolution_dpi(struct ratbag_resolution *resolution, int dpi) +hidpp20drv_write_resolution_dpi(struct ratbag_resolution *resolution, + int dpi_x, int dpi_y) { struct ratbag_profile *profile = resolution->profile; struct ratbag_device *device = profile->device; struct hidpp20drv_data *drv_data = ratbag_get_drv_data(device); struct hidpp20_sensor *sensor; int rc, i; + int dpi = dpi_x; /* dpi_x == dpi_y if we don't have the individual resolution cap */ if (!(drv_data->capabilities & HIDPP_CAP_SWITCHABLE_RESOLUTION_2201)) return -ENOTSUP; diff --git a/src/libratbag-private.h b/src/libratbag-private.h index bbbc9c16..708195c5 100644 --- a/src/libratbag-private.h +++ b/src/libratbag-private.h @@ -27,6 +27,7 @@ #include #include #include +#include #include "libratbag.h" #include "libratbag-util.h" @@ -167,7 +168,8 @@ struct ratbag_driver { * * Mandatory if the driver exports RATBAG_DEVICE_CAP_SWITCHABLE_RESOLUTION. */ - int (*write_resolution_dpi)(struct ratbag_resolution *resolution, int dpi); + int (*write_resolution_dpi)(struct ratbag_resolution *resolution, + int dpi_x, int dpi_y); /* private */ struct list link; @@ -178,10 +180,12 @@ struct ratbag_resolution{ struct ratbag_profile *profile; int refcount; void *userdata; - unsigned int dpi; /**< resolution on dpi */ + unsigned int dpi_x; /**< x resolution in dpi */ + unsigned int dpi_y; /**< y resolution in dpi */ unsigned int hz; /**< report rate in Hz */ bool is_active; bool is_default; + uint32_t capabilities; }; struct ratbag_profile { @@ -309,15 +313,27 @@ ratbag_button_action_match(const struct ratbag_button_action *action, } static inline void -ratbag_resolution_init(struct ratbag_profile *profile, int index, int dpi, int hz) +ratbag_resolution_init(struct ratbag_profile *profile, int index, + int dpi_x, int dpi_y, int hz) { struct ratbag_resolution *res = &profile->resolution.modes[index]; res->profile = profile; - res->dpi = dpi; + res->dpi_x = dpi_x; + res->dpi_y = dpi_y; res->hz = hz; res->is_active = false; res->is_default = false; + res->capabilities = 0; +} + +static inline void +ratbag_resolution_set_cap(struct ratbag_resolution *res, + enum ratbag_resolution_capability cap) +{ + assert(cap <= RATBAG_RESOLUTION_CAP_SEPARATE_XY_RESOLUTION); + + res->capabilities = (1 << cap); } /** diff --git a/src/libratbag.c b/src/libratbag.c index 3925a98f..82dc8a22 100644 --- a/src/libratbag.c +++ b/src/libratbag.c @@ -569,7 +569,7 @@ ratbag_create_profile(struct ratbag_device *device, list_init(&profile->buttons); for (i = 0; i < MAX_RESOLUTIONS; i++) - ratbag_resolution_init(profile, i, 0, 0); + ratbag_resolution_init(profile, i, 0, 0, 0); profile->resolution.num_modes = 1; assert(device->driver->read_profile); @@ -755,15 +755,48 @@ ratbag_resolution_unref(struct ratbag_resolution *resolution) return NULL; } +LIBRATBAG_EXPORT int +ratbag_resolution_has_capability(struct ratbag_resolution *resolution, + enum ratbag_resolution_capability cap) +{ + switch (cap) { + case RATBAG_RESOLUTION_CAP_INDIVIDUAL_REPORT_RATE: + case RATBAG_RESOLUTION_CAP_SEPARATE_XY_RESOLUTION: + break; + default: + return 0; + } + + return !!(resolution->capabilities & (1 << cap)); +} + LIBRATBAG_EXPORT int ratbag_resolution_set_dpi(struct ratbag_resolution *resolution, unsigned int dpi) { struct ratbag_profile *profile = resolution->profile; - resolution->dpi = dpi; + resolution->dpi_x = dpi; + resolution->dpi_y = dpi; assert(profile->device->driver->write_resolution_dpi); - return profile->device->driver->write_resolution_dpi(resolution, dpi); + return profile->device->driver->write_resolution_dpi(resolution, dpi, dpi); +} + +LIBRATBAG_EXPORT int +ratbag_resolution_set_dpi_xy(struct ratbag_resolution *resolution, + unsigned int x, unsigned int y) +{ + struct ratbag_profile *profile = resolution->profile; + + if (!ratbag_resolution_has_capability(resolution, + RATBAG_RESOLUTION_CAP_SEPARATE_XY_RESOLUTION)) + return -1; + + if ((x == 0 && y != 0) || (x != 0 && y == 0)) + return -1; + + assert(profile->device->driver->write_resolution_dpi); + return profile->device->driver->write_resolution_dpi(resolution, x, y); } LIBRATBAG_EXPORT int @@ -778,7 +811,19 @@ ratbag_resolution_set_report_rate(struct ratbag_resolution *resolution, LIBRATBAG_EXPORT int ratbag_resolution_get_dpi(struct ratbag_resolution *resolution) { - return resolution->dpi; + return resolution->dpi_x; +} + +LIBRATBAG_EXPORT int +ratbag_resolution_get_dpi_x(struct ratbag_resolution *resolution) +{ + return resolution->dpi_x; +} + +LIBRATBAG_EXPORT int +ratbag_resolution_get_dpi_y(struct ratbag_resolution *resolution) +{ + return resolution->dpi_y; } LIBRATBAG_EXPORT int diff --git a/src/libratbag.h b/src/libratbag.h index 3cc44ee5..23ace9e8 100644 --- a/src/libratbag.h +++ b/src/libratbag.h @@ -552,10 +552,38 @@ ratbag_resolution_set_user_data(struct ratbag_resolution *resolution, void *user void* ratbag_resolution_get_user_data(const struct ratbag_resolution *resolution); +enum ratbag_resolution_capability { + /** + * The report rate can be set per resolution mode. If this property + * is not available, all resolutions within the same profile have + * the same report rate and changing one changes the others. + */ + RATBAG_RESOLUTION_CAP_INDIVIDUAL_REPORT_RATE = 1, + + /** + * The resolution can be set for x and y separately. + */ + RATBAG_RESOLUTION_CAP_SEPARATE_XY_RESOLUTION, +}; + +/** + * @ingroup resolution + * + * Check if a resolution has a specific capability. + * + * @return non-zero if the capability is available, zero otherwise. + */ +int +ratbag_resolution_has_capability(struct ratbag_resolution *resolution, + enum ratbag_resolution_capability cap); + /** * @ingroup resolution * * Set the resolution in DPI for the resolution mode. + * If the resolution has the @ref + * RATBAG_RESOLUTION_CAP_SEPARATE_XY_RESOLUTION capability, this function + * sets both x and y resolution to the given value. * * A value of 0 for dpi disables the mode. * @@ -570,20 +598,84 @@ ratbag_resolution_get_user_data(const struct ratbag_resolution *resolution); int ratbag_resolution_set_dpi(struct ratbag_resolution *resolution, unsigned int dpi); + +/** + * @ingroup resolution + * + * Set the x and y resolution in DPI for the resolution mode. + * If the resolution does not have the @ref + * RATBAG_RESOLUTION_CAP_SEPARATE_XY_RESOLUTION capability, this function + * returns an error and does nothing. + * + * A value of 0 for both x and y disables the mode. If either value is 0 and + * the other value is non-zero, this function returns an error and does + * nothing. + * + * 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 with the + * @ref RATBAG_RESOLUTION_CAP_SEPARATE_XY_RESOLUTION capability + * @param x The x resolution in dpi + * @param y The y resolution in dpi + * + * @return zero on success, non-zero otherwise + */ +int +ratbag_resolution_set_dpi_xy(struct ratbag_resolution *resolution, + unsigned int x, unsigned int y); + /** * @ingroup resolution * * Get the resolution in DPI for the resolution mode. + * If the resolution has the @ref + * RATBAG_RESOLUTION_CAP_SEPARATE_XY_RESOLUTION capability, this function + * returns the x resolution, see ratbag_resolution_get_dpi_x(). * * 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 + * @return The resolution in dpi */ int ratbag_resolution_get_dpi(struct ratbag_resolution *resolution); +/** + * @ingroup resolution + * + * Get the x resolution in DPI for the resolution mode. If the resolution + * does not have the @ref RATBAG_RESOLUTION_CAP_SEPARATE_XY_RESOLUTION + * capability, this function is identical to ratbag_resolution_get_dpi(). + * + * A value of 0 for dpi indicates the mode is disabled. + * + * @param resolution A previously initialized ratbag resolution with the + * @ref RATBAG_RESOLUTION_CAP_SEPARATE_XY_RESOLUTION capability + * + * @return The resolution in dpi + */ +int +ratbag_resolution_get_dpi_x(struct ratbag_resolution *resolution); + +/** + * @ingroup resolution + * + * Get the y resolution in DPI for the resolution mode. If the resolution + * does not have the @ref RATBAG_RESOLUTION_CAP_SEPARATE_XY_RESOLUTION + * capability, this function is identical to ratbag_resolution_get_dpi(). + * + * A value of 0 for dpi indicates the mode is disabled. + * + * @param resolution A previously initialized ratbag resolution with the + * @ref RATBAG_RESOLUTION_CAP_SEPARATE_XY_RESOLUTION capability + * + * @return The resolution in dpi + */ +int +ratbag_resolution_get_dpi_y(struct ratbag_resolution *resolution); + /** * @ingroup resolution * diff --git a/src/libratbag.sym b/src/libratbag.sym index 4ee29c3c..08d28dda 100644 --- a/src/libratbag.sym +++ b/src/libratbag.sym @@ -40,14 +40,18 @@ global: ratbag_profile_set_active; ratbag_profile_unref; ratbag_resolution_get_dpi; + ratbag_resolution_get_dpi_x; + ratbag_resolution_get_dpi_y; ratbag_resolution_get_report_rate; ratbag_resolution_get_user_data; + ratbag_resolution_has_capability; ratbag_resolution_is_active; ratbag_resolution_is_default; ratbag_resolution_ref; ratbag_resolution_set_active; ratbag_resolution_set_default; ratbag_resolution_set_dpi; + ratbag_resolution_set_dpi_xy; ratbag_resolution_set_report_rate; ratbag_resolution_set_user_data; ratbag_resolution_unref; diff --git a/tools/ratbag-command.c b/tools/ratbag-command.c index fd98fb18..9952ef08 100644 --- a/tools/ratbag-command.c +++ b/tools/ratbag-command.c @@ -332,6 +332,14 @@ ratbag_cmd_info(struct ratbag *ratbag, uint32_t flags, int argc, char **argv) rate = ratbag_resolution_get_report_rate(res); if (dpi == 0) printf(" %d: \n", j); + else if (ratbag_resolution_has_capability(res, + RATBAG_RESOLUTION_CAP_SEPARATE_XY_RESOLUTION)) + printf(" %d: %dx%ddpi @ %dHz%s%s\n", j, + ratbag_resolution_get_dpi_x(res), + ratbag_resolution_get_dpi_y(res), + rate, + ratbag_resolution_is_active(res) ? " (active)" : "", + ratbag_resolution_is_default(res) ? " (default)" : ""); else printf(" %d: %ddpi @ %dHz%s%s\n", j, dpi, rate, ratbag_resolution_is_active(res) ? " (active)" : "",